david-oplatka
commited on
Commit
•
757fbed
1
Parent(s):
86fb75b
Reorganize Files
Browse files- .env +11 -0
- Dockerfile +11 -11
- __pycache__/agent.cpython-310.pyc +0 -0
- __pycache__/chatbox.cpython-310.pyc +0 -0
- __pycache__/chatui.cpython-310.pyc +0 -0
- __pycache__/footer.cpython-310.pyc +0 -0
- __pycache__/header.cpython-310.pyc +0 -0
- __pycache__/utils.cpython-310.pyc +0 -0
- app.py +37 -611
- app2.py +733 -0
- app_full.py +714 -0
- chatbox.py +71 -0
- chatui.py +219 -0
- footer.py +127 -0
- header.py +152 -0
- requirements.txt +1 -1
- utils.py +3 -0
.env
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
VECTARA_CUSTOMER_ID="1526022105"
|
2 |
+
VECTARA_API_KEY="zqt_WvU_2ZD8owebGIuCtv_aWivgVyPGiH3pyF57bg"
|
3 |
+
VECTARA_CORPUS_ID="279"
|
4 |
+
VECTARA_AGENT_TYPE="OPENAI"
|
5 |
+
VECTARA_AGENT_MAIN_LLM_PROVIDER="OPENAI"
|
6 |
+
VECTARA_AGENT_TOOL_LLM_PROVIDER="OPENAI"
|
7 |
+
OPENAI_API_KEY="sk-proj-ecGoQqchQtEztxM1oeTfT3BlbkFJ0sDJUagzIEUlW7JSK9tf"
|
8 |
+
QUERY_EXAMPLES="Please explain the current eminent domain policies in Alaska; What are the elements of permitting requirements and notice?; What is adverse possession? What are the elements of adverse possession in Alaska?"
|
9 |
+
DEMO_NAME="Legal Assistant"
|
10 |
+
SHORT_DESCRIPTION="This demo can help you prepare for a court case by providing you information about past court cases in Alaska."
|
11 |
+
EXTRA_INFO="You can ask about specific topics or rulings and get related case info, including the official case document and other cases cited in the final opinion. You can also ask the assistant to critique your argument to enhance your preparation."
|
Dockerfile
CHANGED
@@ -1,14 +1,14 @@
|
|
1 |
-
ARG VECTARA_CUSTOMER_ID
|
2 |
-
ARG VECTARA_API_KEY
|
3 |
-
ARG VECTARA_CORPUS_ID
|
4 |
-
ARG VECTARA_AGENT_TYPE
|
5 |
-
ARG VECTARA_AGENT_MAIN_LLM_PROVIDER
|
6 |
-
ARG VECTARA_AGENT_TOOL_LLM_PROVIDE
|
7 |
-
ARG OPENAI_API_KEY
|
8 |
-
ARG QUERY_EXAMPLES
|
9 |
-
ARG DEMO_NAME
|
10 |
-
ARG SHORT_DESCRIPTION
|
11 |
-
ARG EXTRA_INFO
|
12 |
|
13 |
FROM python:3.10
|
14 |
|
|
|
1 |
+
# ARG VECTARA_CUSTOMER_ID
|
2 |
+
# ARG VECTARA_API_KEY
|
3 |
+
# ARG VECTARA_CORPUS_ID
|
4 |
+
# ARG VECTARA_AGENT_TYPE
|
5 |
+
# ARG VECTARA_AGENT_MAIN_LLM_PROVIDER
|
6 |
+
# ARG VECTARA_AGENT_TOOL_LLM_PROVIDE
|
7 |
+
# ARG OPENAI_API_KEY
|
8 |
+
# ARG QUERY_EXAMPLES
|
9 |
+
# ARG DEMO_NAME
|
10 |
+
# ARG SHORT_DESCRIPTION
|
11 |
+
# ARG EXTRA_INFO
|
12 |
|
13 |
FROM python:3.10
|
14 |
|
__pycache__/agent.cpython-310.pyc
ADDED
Binary file (10.3 kB). View file
|
|
__pycache__/chatbox.cpython-310.pyc
ADDED
Binary file (1.44 kB). View file
|
|
__pycache__/chatui.cpython-310.pyc
ADDED
Binary file (4.76 kB). View file
|
|
__pycache__/footer.cpython-310.pyc
ADDED
Binary file (1.85 kB). View file
|
|
__pycache__/header.cpython-310.pyc
ADDED
Binary file (2.33 kB). View file
|
|
__pycache__/utils.cpython-310.pyc
ADDED
Binary file (195 Bytes). View file
|
|
app.py
CHANGED
@@ -1,39 +1,27 @@
|
|
1 |
import asyncio
|
2 |
import threading
|
3 |
-
from markdown_it import MarkdownIt
|
4 |
-
from mdit_py_plugins import front_matter
|
5 |
|
6 |
-
from reactpy import component, html, hooks, use_effect,
|
7 |
from reactpy.backend.starlette import configure
|
8 |
from starlette.applications import Starlette
|
9 |
from vectara_agentic.agent import AgentStatusType
|
10 |
from agent import initialize_agent, get_agent_config
|
11 |
|
12 |
-
|
|
|
|
|
|
|
|
|
13 |
|
14 |
@component
|
15 |
def App():
|
16 |
-
|
17 |
-
# Used for showing/hiding logs
|
18 |
show_logs, set_show_logs = hooks.use_state(False)
|
19 |
-
|
20 |
-
# Determining when the "Show Logs" button should appear
|
21 |
show_logs_button, set_show_logs_button = hooks.use_state(False)
|
22 |
-
|
23 |
-
# Used for resetting chat bot with "Start Over" button.
|
24 |
first_turn, set_first_turn = hooks.use_state(True)
|
25 |
-
|
26 |
-
# Tracks the state of whether the header is collapsed or exapnded
|
27 |
-
more_info, set_more_info = hooks.use_state(False)
|
28 |
-
|
29 |
-
# Tracks the state of whether the footer is collapsed or expanded
|
30 |
-
collapsed, set_collapse = hooks.use_state(False)
|
31 |
-
|
32 |
-
# Record of Chat Messages
|
33 |
messages, set_messages = hooks.use_state([])
|
34 |
-
|
35 |
message, set_message = hooks.use_state("")
|
36 |
-
input_value, set_input_value = hooks.use_state("")
|
37 |
|
38 |
def use_agent_logger():
|
39 |
agent_log_entries, set_agent_log_entries = hooks.use_state([])
|
@@ -46,6 +34,7 @@ def App():
|
|
46 |
|
47 |
return agent_log_entries, add_log_entry, reset_log_entries
|
48 |
|
|
|
49 |
log_entries, add_log_entry, reset_log_entries = use_agent_logger()
|
50 |
|
51 |
def update_func(status_type: AgentStatusType, msg: str):
|
@@ -53,16 +42,11 @@ def App():
|
|
53 |
output = f"{status_type.value} - {msg}"
|
54 |
add_log_entry(output)
|
55 |
|
|
|
56 |
cfg, _ = hooks.use_state(get_agent_config())
|
57 |
agent, _ = hooks.use_state(initialize_agent(cfg, update_func))
|
58 |
|
59 |
-
|
60 |
-
set_more_info(not more_info)
|
61 |
-
|
62 |
-
def toggle_footer(event=None):
|
63 |
-
set_collapse(not collapsed)
|
64 |
-
|
65 |
-
# Clears all messages and resets chat interface
|
66 |
def start_over(event=None):
|
67 |
set_messages([])
|
68 |
set_first_turn(True)
|
@@ -70,7 +54,6 @@ def App():
|
|
70 |
def display_message(new_messages):
|
71 |
if first_turn:
|
72 |
set_first_turn(False)
|
73 |
-
|
74 |
set_messages(messages + list(new_messages))
|
75 |
|
76 |
async def chat_response(user_message):
|
@@ -89,17 +72,14 @@ def App():
|
|
89 |
set_show_logs_button(True)
|
90 |
|
91 |
def send_message(event=None):
|
92 |
-
print(f"DEBUG: SEND MESSAGE CALLED FOR MESSAGE {message}")
|
93 |
if message.strip():
|
94 |
sent_message = message
|
95 |
set_message("")
|
96 |
-
set_input_value("")
|
97 |
set_show_logs_button(False)
|
98 |
set_show_logs(False)
|
99 |
reset_log_entries()
|
100 |
display_message([{"user": "human", "message": sent_message}])
|
101 |
display_message([{"user": "bot", "message": wait_message}])
|
102 |
-
|
103 |
asyncio.create_task(send_message_async(sent_message))
|
104 |
|
105 |
def send_example(ex_prompt):
|
@@ -112,576 +92,13 @@ def App():
|
|
112 |
|
113 |
asyncio.create_task(send_message_async(sent_message))
|
114 |
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
# def handle_key_down(event):
|
120 |
-
# if event['key'] == 'Enter':
|
121 |
-
# send_message()
|
122 |
-
|
123 |
-
|
124 |
-
def handle_input(event):
|
125 |
-
new_value = event['target']['value']
|
126 |
-
set_input_value(new_value)
|
127 |
-
|
128 |
-
def handle_key_down(event):
|
129 |
-
if event['key'] == 'Enter':
|
130 |
-
send_message()
|
131 |
-
|
132 |
-
use_effect(lambda: set_message(input_value), [input_value])
|
133 |
-
|
134 |
-
@component
|
135 |
-
def Header(demo_name: str, short_description: str, extra_info: str):
|
136 |
-
return html.header(
|
137 |
-
{
|
138 |
-
"style": {
|
139 |
-
"backgroundColor": "#FFFFFF",
|
140 |
-
"display": "flex",
|
141 |
-
"justifyContent": "space-between",
|
142 |
-
"alignItems": "center",
|
143 |
-
}
|
144 |
-
},
|
145 |
-
html.div(
|
146 |
-
{
|
147 |
-
"style": {
|
148 |
-
"display": "flex",
|
149 |
-
"alignItems": "center",
|
150 |
-
"flex": 2,
|
151 |
-
"textAlign": "left",
|
152 |
-
"padding": "10px",
|
153 |
-
}
|
154 |
-
},
|
155 |
-
html.img(
|
156 |
-
{
|
157 |
-
"src": "https://avatars.githubusercontent.com/u/108304503?s=200&v=4",
|
158 |
-
"style": {
|
159 |
-
"height": "30px",
|
160 |
-
"marginRight": "15px",
|
161 |
-
"marginLeft": "5px",
|
162 |
-
"transform": "translateY(-2px)",
|
163 |
-
}
|
164 |
-
}
|
165 |
-
),
|
166 |
-
html.p(
|
167 |
-
{
|
168 |
-
"style": {
|
169 |
-
"fontSize": "25px",
|
170 |
-
"fontFamily": "Georgia, 'Times New Roman', Times, serif",
|
171 |
-
}
|
172 |
-
},
|
173 |
-
f"{demo_name}"
|
174 |
-
),
|
175 |
-
),
|
176 |
-
html.div(
|
177 |
-
{
|
178 |
-
"style": {
|
179 |
-
"flex": 5,
|
180 |
-
"textAlign": "center",
|
181 |
-
"padding": "10px 0px 15px 0px",
|
182 |
-
"fontFamily": "Lato",
|
183 |
-
"position": "relative",
|
184 |
-
}
|
185 |
-
},
|
186 |
-
html.h3(f"Welcome to the {demo_name} Demo"),
|
187 |
-
html.p(
|
188 |
-
short_description,
|
189 |
-
html.button(
|
190 |
-
{
|
191 |
-
"style": {
|
192 |
-
"display": "inline" if not more_info else "none",
|
193 |
-
"backgroundColor": "#FFFFFF",
|
194 |
-
"color": "#757575",
|
195 |
-
"fontSize": "13px",
|
196 |
-
"cursor": "pointer",
|
197 |
-
"border": "none",
|
198 |
-
"padding": "0px 0px 0px 5px",
|
199 |
-
},
|
200 |
-
"type": "button",
|
201 |
-
"onClick": toggle_header,
|
202 |
-
},
|
203 |
-
html.u(
|
204 |
-
{
|
205 |
-
"style": {
|
206 |
-
"flex": 2,
|
207 |
-
"textAlign": "right",
|
208 |
-
"padding": "10px",
|
209 |
-
}
|
210 |
-
},
|
211 |
-
"Learn More"
|
212 |
-
)
|
213 |
-
),
|
214 |
-
f" {extra_info}" if more_info else ""
|
215 |
-
),
|
216 |
-
html.button(
|
217 |
-
{
|
218 |
-
"style": {
|
219 |
-
"display": "block" if more_info else "none",
|
220 |
-
"background": "none",
|
221 |
-
"border": "none",
|
222 |
-
"color": "#757575",
|
223 |
-
"cursor": "pointer",
|
224 |
-
"position": "absolute",
|
225 |
-
"left": "50%",
|
226 |
-
"transform": "translateX(-50%)",
|
227 |
-
"bottom": "1px",
|
228 |
-
},
|
229 |
-
"type": "button",
|
230 |
-
"on_click": toggle_header,
|
231 |
-
},
|
232 |
-
svg.svg(
|
233 |
-
{
|
234 |
-
"width": "20",
|
235 |
-
"height": "20",
|
236 |
-
"viewBox": "0 0 20 20",
|
237 |
-
"fill": "none",
|
238 |
-
"stroke": "black",
|
239 |
-
"strokeWidth": "2",
|
240 |
-
"strokeLinecap": "round",
|
241 |
-
"strokeLinejoin": "round",
|
242 |
-
},
|
243 |
-
svg.path(
|
244 |
-
{
|
245 |
-
"d": "M12 19V5M5 12l7-7 7 7",
|
246 |
-
"stroke": "currentColor",
|
247 |
-
}
|
248 |
-
)
|
249 |
-
)
|
250 |
-
)
|
251 |
-
),
|
252 |
-
html.div(
|
253 |
-
{
|
254 |
-
"style": {
|
255 |
-
"flex": 2,
|
256 |
-
"textAlign": "right",
|
257 |
-
"padding": "10px",
|
258 |
-
}
|
259 |
-
},
|
260 |
-
html.button(
|
261 |
-
{
|
262 |
-
"style": {
|
263 |
-
"backgroundColor": "#FFFFFF",
|
264 |
-
"color": "#757575",
|
265 |
-
"fontSize": "14px",
|
266 |
-
"cursor": "pointer",
|
267 |
-
"border": "1px solid #e2dfdf",
|
268 |
-
"borderRadius": "5px",
|
269 |
-
"padding": "6px 20px",
|
270 |
-
"marginRight": "15px",
|
271 |
-
},
|
272 |
-
"type": "button",
|
273 |
-
"onClick": start_over,
|
274 |
-
},
|
275 |
-
"Start Over?"
|
276 |
-
)
|
277 |
-
)
|
278 |
-
)
|
279 |
-
|
280 |
-
def markdown_to_html(markdown_text):
|
281 |
-
md = (
|
282 |
-
MarkdownIt("commonmark", {"breaks": True, "html": True})
|
283 |
-
.use(front_matter.front_matter_plugin)
|
284 |
-
)
|
285 |
-
return md.render(markdown_text)
|
286 |
-
|
287 |
-
@component
|
288 |
-
def MarkdownRenderer(content):
|
289 |
-
html_content = markdown_to_html(content)
|
290 |
-
return html.div(
|
291 |
-
{
|
292 |
-
"style": {
|
293 |
-
"fontFamily": "Arial",
|
294 |
-
"color": "#49454F",
|
295 |
-
"fontSize": "14px",
|
296 |
-
},
|
297 |
-
"dangerouslySetInnerHTML": {"__html": html_content}
|
298 |
-
}
|
299 |
-
)
|
300 |
-
|
301 |
-
@component
|
302 |
-
def ExamplePrompts():
|
303 |
-
example_questions = [example.strip() for example in cfg['examples'].split(";")] if cfg.examples else []
|
304 |
-
|
305 |
-
def create_prompt_button(question):
|
306 |
-
return html.button(
|
307 |
-
{
|
308 |
-
"style": {
|
309 |
-
"backgroundColor": "#FFFFFF",
|
310 |
-
"borderWidth": "1px",
|
311 |
-
"borderColor": "#65558F",
|
312 |
-
"borderRadius": "20px",
|
313 |
-
"padding": "5px 7px",
|
314 |
-
"margin": "5px",
|
315 |
-
"cursor": "pointer",
|
316 |
-
"color": "#21005D",
|
317 |
-
"fontSize": "13px",
|
318 |
-
},
|
319 |
-
"type": "button",
|
320 |
-
"onClick": lambda _: send_example(question),
|
321 |
-
},
|
322 |
-
question
|
323 |
-
)
|
324 |
-
|
325 |
-
if first_turn:
|
326 |
-
return html.div(
|
327 |
-
{
|
328 |
-
"style": {
|
329 |
-
"display": "flex",
|
330 |
-
"transform": "translate(4%, 100%)",
|
331 |
-
"flexDirection": "column",
|
332 |
-
"justifyContent": "center",
|
333 |
-
"width": "90%",
|
334 |
-
}
|
335 |
-
},
|
336 |
-
html.p(
|
337 |
-
{
|
338 |
-
"style": {
|
339 |
-
"fontSize": "16px",
|
340 |
-
"fontFamily": "Arial",
|
341 |
-
"color": "#49454F",
|
342 |
-
"marginBottom": "5px",
|
343 |
-
"transform": "translateX(3%)",
|
344 |
-
"textAlign": "left",
|
345 |
-
}
|
346 |
-
},
|
347 |
-
"Queries to try:"
|
348 |
-
),
|
349 |
-
html.div(
|
350 |
-
{
|
351 |
-
"style": {
|
352 |
-
"display": "flex",
|
353 |
-
"flexWrap": "wrap",
|
354 |
-
"justifyContent": "center",
|
355 |
-
}
|
356 |
-
},
|
357 |
-
*[create_prompt_button(q) for q in example_questions]
|
358 |
-
)
|
359 |
-
)
|
360 |
-
|
361 |
-
return None
|
362 |
-
|
363 |
-
@component
|
364 |
-
def ChatBox():
|
365 |
-
return html.div(
|
366 |
-
{
|
367 |
-
"style": {
|
368 |
-
"position": "fixed",
|
369 |
-
"bottom": "70px" if collapsed else "140px",
|
370 |
-
"left": "50%",
|
371 |
-
"transform": "translateX(-50%)",
|
372 |
-
"width": "80%",
|
373 |
-
"display": "flex",
|
374 |
-
"alignItems": "center",
|
375 |
-
"backgroundColor": "#FFFFFF",
|
376 |
-
"borderRadius": "50px",
|
377 |
-
"zIndex": "1000",
|
378 |
-
}
|
379 |
-
},
|
380 |
-
html.input(
|
381 |
-
{
|
382 |
-
"type": "text",
|
383 |
-
"value": message,
|
384 |
-
"placeholder": "Your Message",
|
385 |
-
"onInput": handle_input,
|
386 |
-
"onKeyDown": handle_key_down,
|
387 |
-
"style": {
|
388 |
-
"width": "100%",
|
389 |
-
"padding": "10px 50px 10px 20px",
|
390 |
-
"border": "none",
|
391 |
-
"borderRadius": "50px",
|
392 |
-
"color": "#65558F",
|
393 |
-
}
|
394 |
-
}
|
395 |
-
),
|
396 |
-
html.button(
|
397 |
-
{
|
398 |
-
"type": "button",
|
399 |
-
"onClick": send_message,
|
400 |
-
"style": {
|
401 |
-
"position": "absolute",
|
402 |
-
"right": "8px",
|
403 |
-
"top": "50%",
|
404 |
-
"transform":"translateY(-50%)",
|
405 |
-
"background": "none",
|
406 |
-
"border": "none",
|
407 |
-
"cursor": "pointer",
|
408 |
-
"padding": "8px",
|
409 |
-
"display": "flex",
|
410 |
-
"alignItems": "center",
|
411 |
-
"justifyContent": "center",
|
412 |
-
}
|
413 |
-
},
|
414 |
-
svg.svg(
|
415 |
-
{
|
416 |
-
"xmlns": "http://www.w3.org/2000/svg",
|
417 |
-
"width": "20",
|
418 |
-
"height": "20",
|
419 |
-
"fill": "none",
|
420 |
-
"stroke": "currentColor",
|
421 |
-
"stroke-linecap": "round",
|
422 |
-
"stroke-linejoin": "round",
|
423 |
-
"stroke-width": "2",
|
424 |
-
"viewBox": "0 0 24 24",
|
425 |
-
"class": "feather feather-send",
|
426 |
-
},
|
427 |
-
svg.path({"d": "M22 2 11 13"}),
|
428 |
-
svg.path({"d": "M22 2 15 22 11 13 2 9z"})
|
429 |
-
)
|
430 |
-
)
|
431 |
-
)
|
432 |
-
|
433 |
-
|
434 |
-
@component
|
435 |
-
def ChatMessage(user, message):
|
436 |
-
|
437 |
-
return html.div(
|
438 |
-
{
|
439 |
-
"style": {
|
440 |
-
"display": "flex",
|
441 |
-
"width": "75%",
|
442 |
-
"transform": "translateX(20%)",
|
443 |
-
"justifyContent": "flex-end" if user == "human" else "flex-start",
|
444 |
-
"margin": "20px 0px 10px 0px"
|
445 |
-
}
|
446 |
-
},
|
447 |
-
html.div(
|
448 |
-
{
|
449 |
-
"style": {
|
450 |
-
"maxWidth": "50%",
|
451 |
-
"padding": "0px 15px 0px 10px",
|
452 |
-
"borderRadius": "15px",
|
453 |
-
"backgroundColor": "#E8DEF8" if user == "human" else "#ECE6F0",
|
454 |
-
"color": "#000000",
|
455 |
-
}
|
456 |
-
},
|
457 |
-
MarkdownRenderer(message)
|
458 |
-
)
|
459 |
-
)
|
460 |
-
|
461 |
-
@component
|
462 |
-
def Logs():
|
463 |
-
if (len(messages) > 0) and (len(log_entries) > 0) and (messages[-1]["message"] != wait_message) and (show_logs_button):
|
464 |
-
if not show_logs:
|
465 |
-
return html.div(
|
466 |
-
{
|
467 |
-
"style": {
|
468 |
-
"display": "flex",
|
469 |
-
"transform": "translateX(75%)",
|
470 |
-
"width": "20%",
|
471 |
-
"margin": "0px",
|
472 |
-
}
|
473 |
-
},
|
474 |
-
html.button(
|
475 |
-
{
|
476 |
-
"style": {
|
477 |
-
"position": "flex",
|
478 |
-
"background": "none",
|
479 |
-
"color": "#757575",
|
480 |
-
"border": "none",
|
481 |
-
"cursor": "pointer",
|
482 |
-
"fontFamily": "Arial",
|
483 |
-
"fontSize": "14px",
|
484 |
-
},
|
485 |
-
"type": "button",
|
486 |
-
"onClick": lambda _: set_show_logs(True)
|
487 |
-
},
|
488 |
-
"Show Logs"
|
489 |
-
)
|
490 |
-
)
|
491 |
-
else:
|
492 |
-
return html.div(
|
493 |
-
{
|
494 |
-
"style": {
|
495 |
-
"display": "flex",
|
496 |
-
"transform": "translateX(20%)",
|
497 |
-
"border": "2px solid #e2dfdf",
|
498 |
-
"borderRadius": "10px",
|
499 |
-
"width": "75%",
|
500 |
-
}
|
501 |
-
},
|
502 |
-
html.div(
|
503 |
-
[
|
504 |
-
html.p(
|
505 |
-
{
|
506 |
-
"style": {
|
507 |
-
"fontSize": "14px",
|
508 |
-
"marginLeft": "10px",
|
509 |
-
}
|
510 |
-
},
|
511 |
-
entry
|
512 |
-
) for entry in log_entries
|
513 |
-
],
|
514 |
-
html.button(
|
515 |
-
{
|
516 |
-
"style": {
|
517 |
-
"position": "flex",
|
518 |
-
"background": "none",
|
519 |
-
"color": "#757575",
|
520 |
-
"border": "none",
|
521 |
-
"cursor": "pointer",
|
522 |
-
"fontFamily": "Arial",
|
523 |
-
"fontSize": "14px",
|
524 |
-
"marginBottom": "10px",
|
525 |
-
"marginLeft": "5px",
|
526 |
-
},
|
527 |
-
"type": "button",
|
528 |
-
"onClick": lambda _: set_show_logs(False)
|
529 |
-
},
|
530 |
-
"Hide Logs"
|
531 |
-
)
|
532 |
-
)
|
533 |
-
)
|
534 |
|
535 |
-
|
536 |
-
|
537 |
-
@component
|
538 |
-
def ChatUI():
|
539 |
-
|
540 |
-
def render_chat_content():
|
541 |
-
if first_turn:
|
542 |
-
return ExamplePrompts()
|
543 |
-
else:
|
544 |
-
return [ChatMessage(msg["user"], msg["message"]) for msg in messages]
|
545 |
-
|
546 |
-
return html.div(
|
547 |
-
{
|
548 |
-
"style": {
|
549 |
-
"display": "flex",
|
550 |
-
"flexDirection": "column",
|
551 |
-
"padding": "10px",
|
552 |
-
"backgroundColor": "#F4F1F4",
|
553 |
-
"overflowY": "auto",
|
554 |
-
"height": f"calc(100vh - {265 if collapsed else 335}px)",
|
555 |
-
"marginBottom": "15px",
|
556 |
-
"paddingBottom": "15px",
|
557 |
-
},
|
558 |
-
},
|
559 |
-
render_chat_content(),
|
560 |
-
Logs()
|
561 |
-
)
|
562 |
-
|
563 |
-
|
564 |
-
@component
|
565 |
-
def Footer():
|
566 |
-
|
567 |
-
if collapsed:
|
568 |
-
return html.footer(
|
569 |
-
{
|
570 |
-
"style": {
|
571 |
-
"backgroundColor": "#FFFFFF",
|
572 |
-
"position": "fixed",
|
573 |
-
"bottom": 0,
|
574 |
-
"width": "100%",
|
575 |
-
"height": "50px",
|
576 |
-
}
|
577 |
-
},
|
578 |
-
html.button(
|
579 |
-
{
|
580 |
-
"style": {
|
581 |
-
"background": "none",
|
582 |
-
"border": "none",
|
583 |
-
"color": "#757575",
|
584 |
-
"cursor": "pointer",
|
585 |
-
"position": "absolute",
|
586 |
-
"bottom": "5px",
|
587 |
-
"right": "10px",
|
588 |
-
},
|
589 |
-
"type": "button",
|
590 |
-
"on_click": toggle_footer,
|
591 |
-
},
|
592 |
-
svg.svg(
|
593 |
-
{
|
594 |
-
"xmlns": "http://www.w3.org/2000/svg",
|
595 |
-
"width": "24",
|
596 |
-
"height": "24",
|
597 |
-
"fill": "none",
|
598 |
-
"stroke": "currentColor",
|
599 |
-
"stroke-linecap": "round",
|
600 |
-
"stroke-linejoin": "round",
|
601 |
-
"stroke-width": "3",
|
602 |
-
"viewBox": "0 0 24 24",
|
603 |
-
},
|
604 |
-
svg.path({"d": "M19 14l-7-7-7 7"})
|
605 |
-
)
|
606 |
-
)
|
607 |
-
)
|
608 |
-
|
609 |
-
else:
|
610 |
-
return html.footer(
|
611 |
-
{
|
612 |
-
"style": {
|
613 |
-
"backgroundColor": "#FFFFFF",
|
614 |
-
"position": "fixed",
|
615 |
-
"bottom": 0,
|
616 |
-
"width": "100%",
|
617 |
-
}
|
618 |
-
},
|
619 |
-
html.div(
|
620 |
-
{
|
621 |
-
"style": {
|
622 |
-
"backgroundColor": "#FFFFFF",
|
623 |
-
"padding": "0px 20px 0px 50px",
|
624 |
-
"position": "relative",
|
625 |
-
"display": "block",
|
626 |
-
}
|
627 |
-
},
|
628 |
-
html.button(
|
629 |
-
{
|
630 |
-
"style": {
|
631 |
-
"position": "absolute",
|
632 |
-
"right": "10px",
|
633 |
-
"background": "none",
|
634 |
-
"border": "none",
|
635 |
-
"color": "#757575",
|
636 |
-
"cursor": "pointer",
|
637 |
-
},
|
638 |
-
"type": "button",
|
639 |
-
"on_click": toggle_footer,
|
640 |
-
},
|
641 |
-
svg.svg(
|
642 |
-
{
|
643 |
-
"xmlns": "http://www.w3.org/2000/svg",
|
644 |
-
"width": "24",
|
645 |
-
"height": "24",
|
646 |
-
"fill": "none",
|
647 |
-
"stroke": "currentColor",
|
648 |
-
"stroke-linecap": "round",
|
649 |
-
"stroke-linejoin": "round",
|
650 |
-
"stroke-width": "3",
|
651 |
-
"viewBox": "0 0 24 24",
|
652 |
-
},
|
653 |
-
svg.path({"d": "M18 6L6 18"}),
|
654 |
-
svg.path({"d": "M6 6l12 12"})
|
655 |
-
)
|
656 |
-
),
|
657 |
-
html.p(
|
658 |
-
{
|
659 |
-
"style": {
|
660 |
-
"fontSize": "20px",
|
661 |
-
"color": "#4b4851"
|
662 |
-
}
|
663 |
-
},
|
664 |
-
"How this works?",
|
665 |
-
),
|
666 |
-
html.p(
|
667 |
-
{
|
668 |
-
"style": {
|
669 |
-
"color": "#757575",
|
670 |
-
}
|
671 |
-
},
|
672 |
-
"This app was built with ",
|
673 |
-
html.a(
|
674 |
-
{
|
675 |
-
"href": "https://vectara.com/",
|
676 |
-
"target": "_blank",
|
677 |
-
},
|
678 |
-
"Vectara",
|
679 |
-
),
|
680 |
-
html.br(),
|
681 |
-
"It demonstrates the use of Agentic-RAG functionality with Vectara",
|
682 |
-
)
|
683 |
-
)
|
684 |
-
)
|
685 |
|
686 |
return html.div(
|
687 |
{
|
@@ -698,29 +115,38 @@ def App():
|
|
698 |
}
|
699 |
},
|
700 |
html.head(
|
701 |
-
html.style(
|
|
|
702 |
body {
|
703 |
margin: 0;
|
704 |
padding: 0;
|
705 |
}
|
706 |
-
|
|
|
707 |
),
|
708 |
Header(
|
709 |
demo_name=cfg['demo_name'],
|
710 |
short_description=cfg['short_description'],
|
711 |
-
extra_info=cfg['extra_info']
|
|
|
712 |
),
|
713 |
-
ChatUI(
|
714 |
-
|
715 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
716 |
)
|
717 |
|
718 |
app = Starlette()
|
719 |
-
|
720 |
configure(app, App)
|
721 |
|
722 |
-
# Should only need for local testing
|
723 |
-
|
724 |
# if __name__ == "__main__":
|
725 |
-
#
|
726 |
-
# uvicorn.run(app, host="0.0.0.0", port=8000)
|
|
|
1 |
import asyncio
|
2 |
import threading
|
|
|
|
|
3 |
|
4 |
+
from reactpy import component, html, hooks, use_effect, run
|
5 |
from reactpy.backend.starlette import configure
|
6 |
from starlette.applications import Starlette
|
7 |
from vectara_agentic.agent import AgentStatusType
|
8 |
from agent import initialize_agent, get_agent_config
|
9 |
|
10 |
+
from header import Header
|
11 |
+
from footer import Footer
|
12 |
+
from chatbox import ChatBox
|
13 |
+
from chatui import ChatUI
|
14 |
+
from utils import wait_message
|
15 |
|
16 |
@component
|
17 |
def App():
|
18 |
+
# State hooks
|
|
|
19 |
show_logs, set_show_logs = hooks.use_state(False)
|
|
|
|
|
20 |
show_logs_button, set_show_logs_button = hooks.use_state(False)
|
21 |
+
collapsed, set_collapsed = hooks.use_state(False) # Whether or not the footer is collapsed
|
|
|
22 |
first_turn, set_first_turn = hooks.use_state(True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
23 |
messages, set_messages = hooks.use_state([])
|
|
|
24 |
message, set_message = hooks.use_state("")
|
|
|
25 |
|
26 |
def use_agent_logger():
|
27 |
agent_log_entries, set_agent_log_entries = hooks.use_state([])
|
|
|
34 |
|
35 |
return agent_log_entries, add_log_entry, reset_log_entries
|
36 |
|
37 |
+
# Logger setup
|
38 |
log_entries, add_log_entry, reset_log_entries = use_agent_logger()
|
39 |
|
40 |
def update_func(status_type: AgentStatusType, msg: str):
|
|
|
42 |
output = f"{status_type.value} - {msg}"
|
43 |
add_log_entry(output)
|
44 |
|
45 |
+
# Agent setup
|
46 |
cfg, _ = hooks.use_state(get_agent_config())
|
47 |
agent, _ = hooks.use_state(initialize_agent(cfg, update_func))
|
48 |
|
49 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
50 |
def start_over(event=None):
|
51 |
set_messages([])
|
52 |
set_first_turn(True)
|
|
|
54 |
def display_message(new_messages):
|
55 |
if first_turn:
|
56 |
set_first_turn(False)
|
|
|
57 |
set_messages(messages + list(new_messages))
|
58 |
|
59 |
async def chat_response(user_message):
|
|
|
72 |
set_show_logs_button(True)
|
73 |
|
74 |
def send_message(event=None):
|
|
|
75 |
if message.strip():
|
76 |
sent_message = message
|
77 |
set_message("")
|
|
|
78 |
set_show_logs_button(False)
|
79 |
set_show_logs(False)
|
80 |
reset_log_entries()
|
81 |
display_message([{"user": "human", "message": sent_message}])
|
82 |
display_message([{"user": "bot", "message": wait_message}])
|
|
|
83 |
asyncio.create_task(send_message_async(sent_message))
|
84 |
|
85 |
def send_example(ex_prompt):
|
|
|
92 |
|
93 |
asyncio.create_task(send_message_async(sent_message))
|
94 |
|
95 |
+
async def handle_key_down(event):
|
96 |
+
if event['key'] == 'Enter' and message.strip():
|
97 |
+
await send_message()
|
98 |
+
set_message("")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
99 |
|
100 |
+
def handle_input_change(event):
|
101 |
+
set_message(event['target']['value'])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
102 |
|
103 |
return html.div(
|
104 |
{
|
|
|
115 |
}
|
116 |
},
|
117 |
html.head(
|
118 |
+
html.style(
|
119 |
+
"""
|
120 |
body {
|
121 |
margin: 0;
|
122 |
padding: 0;
|
123 |
}
|
124 |
+
"""
|
125 |
+
)
|
126 |
),
|
127 |
Header(
|
128 |
demo_name=cfg['demo_name'],
|
129 |
short_description=cfg['short_description'],
|
130 |
+
extra_info=cfg['extra_info'],
|
131 |
+
start_over=start_over
|
132 |
),
|
133 |
+
ChatUI(
|
134 |
+
messages=messages,
|
135 |
+
first_turn=first_turn,
|
136 |
+
examples=cfg['examples'],
|
137 |
+
send_example=send_example,
|
138 |
+
log_entries=log_entries,
|
139 |
+
show_logs=show_logs,
|
140 |
+
set_show_logs=set_show_logs,
|
141 |
+
show_logs_button=show_logs_button,
|
142 |
+
collapsed=collapsed
|
143 |
+
),
|
144 |
+
ChatBox(message, handle_input_change, handle_key_down, send_message, collapsed),
|
145 |
+
Footer(collapsed, set_collapsed),
|
146 |
)
|
147 |
|
148 |
app = Starlette()
|
|
|
149 |
configure(app, App)
|
150 |
|
|
|
|
|
151 |
# if __name__ == "__main__":
|
152 |
+
# run(App)
|
|
app2.py
ADDED
@@ -0,0 +1,733 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import asyncio
|
2 |
+
import threading
|
3 |
+
from markdown_it import MarkdownIt
|
4 |
+
from mdit_py_plugins import front_matter
|
5 |
+
|
6 |
+
from reactpy import component, html, hooks, use_effect, svg, run # DELETE run FOR DEPLOYMENT
|
7 |
+
from reactpy.backend.starlette import configure
|
8 |
+
from starlette.applications import Starlette
|
9 |
+
from vectara_agentic.agent import AgentStatusType
|
10 |
+
from agent import initialize_agent, get_agent_config
|
11 |
+
|
12 |
+
wait_message = "Please wait. Assistant at work..."
|
13 |
+
|
14 |
+
@component
|
15 |
+
def App():
|
16 |
+
|
17 |
+
# Used for showing/hiding logs
|
18 |
+
show_logs, set_show_logs = hooks.use_state(False)
|
19 |
+
|
20 |
+
# Determining when the "Show Logs" button should appear
|
21 |
+
show_logs_button, set_show_logs_button = hooks.use_state(False)
|
22 |
+
|
23 |
+
# Used for resetting chat bot with "Start Over" button.
|
24 |
+
first_turn, set_first_turn = hooks.use_state(True)
|
25 |
+
|
26 |
+
# Tracks the state of whether the header is collapsed or exapnded
|
27 |
+
more_info, set_more_info = hooks.use_state(False)
|
28 |
+
|
29 |
+
# Tracks the state of whether the footer is collapsed or expanded
|
30 |
+
collapsed, set_collapse = hooks.use_state(False)
|
31 |
+
|
32 |
+
# Record of Chat Messages
|
33 |
+
messages, set_messages = hooks.use_state([])
|
34 |
+
|
35 |
+
message, set_message = hooks.use_state("")
|
36 |
+
# input_value, set_input_value = hooks.use_state("")
|
37 |
+
|
38 |
+
def use_agent_logger():
|
39 |
+
agent_log_entries, set_agent_log_entries = hooks.use_state([])
|
40 |
+
|
41 |
+
def reset_log_entries():
|
42 |
+
set_agent_log_entries([])
|
43 |
+
|
44 |
+
def add_log_entry(new_log_entry):
|
45 |
+
set_agent_log_entries(lambda previous_entries: previous_entries + [new_log_entry])
|
46 |
+
|
47 |
+
return agent_log_entries, add_log_entry, reset_log_entries
|
48 |
+
|
49 |
+
log_entries, add_log_entry, reset_log_entries = use_agent_logger()
|
50 |
+
|
51 |
+
def update_func(status_type: AgentStatusType, msg: str):
|
52 |
+
if status_type != AgentStatusType.AGENT_UPDATE:
|
53 |
+
output = f"{status_type.value} - {msg}"
|
54 |
+
add_log_entry(output)
|
55 |
+
|
56 |
+
cfg, _ = hooks.use_state(get_agent_config())
|
57 |
+
agent, _ = hooks.use_state(initialize_agent(cfg, update_func))
|
58 |
+
|
59 |
+
def toggle_header(event=None):
|
60 |
+
set_more_info(not more_info)
|
61 |
+
|
62 |
+
def toggle_footer(event=None):
|
63 |
+
set_collapse(not collapsed)
|
64 |
+
|
65 |
+
# Clears all messages and resets chat interface
|
66 |
+
def start_over(event=None):
|
67 |
+
set_messages([])
|
68 |
+
set_first_turn(True)
|
69 |
+
|
70 |
+
def display_message(new_messages):
|
71 |
+
if first_turn:
|
72 |
+
set_first_turn(False)
|
73 |
+
|
74 |
+
set_messages(messages + list(new_messages))
|
75 |
+
|
76 |
+
async def chat_response(user_message):
|
77 |
+
response = await asyncio.to_thread(agent.chat, user_message)
|
78 |
+
return response
|
79 |
+
|
80 |
+
async def send_message_async(sent_message):
|
81 |
+
response = await chat_response(sent_message)
|
82 |
+
set_messages(messages[:-1])
|
83 |
+
display_message(
|
84 |
+
[
|
85 |
+
{"user": "human", "message": sent_message},
|
86 |
+
{"user": "bot", "message": response},
|
87 |
+
]
|
88 |
+
)
|
89 |
+
set_show_logs_button(True)
|
90 |
+
|
91 |
+
def send_message(event=None):
|
92 |
+
print(f"DEBUG: SEND MESSAGE CALLED FOR MESSAGE {message}")
|
93 |
+
if message.strip():
|
94 |
+
sent_message = message
|
95 |
+
set_message("")
|
96 |
+
# set_input_value("")
|
97 |
+
set_show_logs_button(False)
|
98 |
+
set_show_logs(False)
|
99 |
+
reset_log_entries()
|
100 |
+
display_message([{"user": "human", "message": sent_message}])
|
101 |
+
display_message([{"user": "bot", "message": wait_message}])
|
102 |
+
|
103 |
+
asyncio.create_task(send_message_async(sent_message))
|
104 |
+
|
105 |
+
def send_example(ex_prompt):
|
106 |
+
if ex_prompt.strip():
|
107 |
+
sent_message = ex_prompt
|
108 |
+
set_message("")
|
109 |
+
reset_log_entries()
|
110 |
+
display_message([{"user": "human", "message": sent_message}])
|
111 |
+
display_message([{"user": "bot", "message": wait_message}])
|
112 |
+
|
113 |
+
asyncio.create_task(send_message_async(sent_message))
|
114 |
+
|
115 |
+
# # New Code Suggestion from Claude
|
116 |
+
# def handle_input(event):
|
117 |
+
# set_message(event['target']['value'])
|
118 |
+
|
119 |
+
# def handle_key_down(event):
|
120 |
+
# if event['key'] == 'Enter':
|
121 |
+
# send_message()
|
122 |
+
|
123 |
+
|
124 |
+
# def handle_input(event):
|
125 |
+
# new_value = event['target']['value']
|
126 |
+
# set_input_value(new_value)
|
127 |
+
|
128 |
+
# def handle_key_down(event):
|
129 |
+
# if event['key'] == 'Enter':
|
130 |
+
# send_message()
|
131 |
+
|
132 |
+
# use_effect(lambda: set_message(input_value), [input_value])
|
133 |
+
|
134 |
+
async def handle_key_down(event):
|
135 |
+
if event['key'] == 'Enter' and message.strip():
|
136 |
+
await send_message()
|
137 |
+
set_message("")
|
138 |
+
|
139 |
+
def handle_input_change(event):
|
140 |
+
set_message(event['target']['value'])
|
141 |
+
|
142 |
+
@component
|
143 |
+
def Header(demo_name: str, short_description: str, extra_info: str):
|
144 |
+
return html.header(
|
145 |
+
{
|
146 |
+
"style": {
|
147 |
+
"backgroundColor": "#FFFFFF",
|
148 |
+
"display": "flex",
|
149 |
+
"justifyContent": "space-between",
|
150 |
+
"alignItems": "center",
|
151 |
+
}
|
152 |
+
},
|
153 |
+
html.div(
|
154 |
+
{
|
155 |
+
"style": {
|
156 |
+
"display": "flex",
|
157 |
+
"alignItems": "center",
|
158 |
+
"flex": 2,
|
159 |
+
"textAlign": "left",
|
160 |
+
"padding": "10px",
|
161 |
+
}
|
162 |
+
},
|
163 |
+
html.img(
|
164 |
+
{
|
165 |
+
"src": "https://avatars.githubusercontent.com/u/108304503?s=200&v=4",
|
166 |
+
"style": {
|
167 |
+
"height": "30px",
|
168 |
+
"marginRight": "15px",
|
169 |
+
"marginLeft": "5px",
|
170 |
+
"transform": "translateY(-2px)",
|
171 |
+
}
|
172 |
+
}
|
173 |
+
),
|
174 |
+
html.p(
|
175 |
+
{
|
176 |
+
"style": {
|
177 |
+
"fontSize": "25px",
|
178 |
+
"fontFamily": "Georgia, 'Times New Roman', Times, serif",
|
179 |
+
}
|
180 |
+
},
|
181 |
+
f"{demo_name}"
|
182 |
+
),
|
183 |
+
),
|
184 |
+
html.div(
|
185 |
+
{
|
186 |
+
"style": {
|
187 |
+
"flex": 5,
|
188 |
+
"textAlign": "center",
|
189 |
+
"padding": "10px 0px 15px 0px",
|
190 |
+
"fontFamily": "Lato",
|
191 |
+
"position": "relative",
|
192 |
+
}
|
193 |
+
},
|
194 |
+
html.h3(f"Welcome to the {demo_name} Demo"),
|
195 |
+
html.p(
|
196 |
+
short_description,
|
197 |
+
html.button(
|
198 |
+
{
|
199 |
+
"style": {
|
200 |
+
"display": "inline" if not more_info else "none",
|
201 |
+
"backgroundColor": "#FFFFFF",
|
202 |
+
"color": "#757575",
|
203 |
+
"fontSize": "13px",
|
204 |
+
"cursor": "pointer",
|
205 |
+
"border": "none",
|
206 |
+
"padding": "0px 0px 0px 5px",
|
207 |
+
},
|
208 |
+
"type": "button",
|
209 |
+
"onClick": toggle_header,
|
210 |
+
},
|
211 |
+
html.u(
|
212 |
+
{
|
213 |
+
"style": {
|
214 |
+
"flex": 2,
|
215 |
+
"textAlign": "right",
|
216 |
+
"padding": "10px",
|
217 |
+
}
|
218 |
+
},
|
219 |
+
"Learn More"
|
220 |
+
)
|
221 |
+
),
|
222 |
+
f" {extra_info}" if more_info else ""
|
223 |
+
),
|
224 |
+
html.button(
|
225 |
+
{
|
226 |
+
"style": {
|
227 |
+
"display": "block" if more_info else "none",
|
228 |
+
"background": "none",
|
229 |
+
"border": "none",
|
230 |
+
"color": "#757575",
|
231 |
+
"cursor": "pointer",
|
232 |
+
"position": "absolute",
|
233 |
+
"left": "50%",
|
234 |
+
"transform": "translateX(-50%)",
|
235 |
+
"bottom": "1px",
|
236 |
+
},
|
237 |
+
"type": "button",
|
238 |
+
"on_click": toggle_header,
|
239 |
+
},
|
240 |
+
svg.svg(
|
241 |
+
{
|
242 |
+
"width": "20",
|
243 |
+
"height": "20",
|
244 |
+
"viewBox": "0 0 20 20",
|
245 |
+
"fill": "none",
|
246 |
+
"stroke": "black",
|
247 |
+
"strokeWidth": "2",
|
248 |
+
"strokeLinecap": "round",
|
249 |
+
"strokeLinejoin": "round",
|
250 |
+
},
|
251 |
+
svg.path(
|
252 |
+
{
|
253 |
+
"d": "M12 19V5M5 12l7-7 7 7",
|
254 |
+
"stroke": "currentColor",
|
255 |
+
}
|
256 |
+
)
|
257 |
+
)
|
258 |
+
)
|
259 |
+
),
|
260 |
+
html.div(
|
261 |
+
{
|
262 |
+
"style": {
|
263 |
+
"flex": 2,
|
264 |
+
"textAlign": "right",
|
265 |
+
"padding": "10px",
|
266 |
+
}
|
267 |
+
},
|
268 |
+
html.button(
|
269 |
+
{
|
270 |
+
"style": {
|
271 |
+
"backgroundColor": "#FFFFFF",
|
272 |
+
"color": "#757575",
|
273 |
+
"fontSize": "14px",
|
274 |
+
"cursor": "pointer",
|
275 |
+
"border": "1px solid #e2dfdf",
|
276 |
+
"borderRadius": "5px",
|
277 |
+
"padding": "6px 20px",
|
278 |
+
"marginRight": "15px",
|
279 |
+
},
|
280 |
+
"type": "button",
|
281 |
+
"onClick": start_over,
|
282 |
+
},
|
283 |
+
"Start Over?"
|
284 |
+
)
|
285 |
+
)
|
286 |
+
)
|
287 |
+
|
288 |
+
def markdown_to_html(markdown_text):
|
289 |
+
md = (
|
290 |
+
MarkdownIt("commonmark", {"breaks": True, "html": True})
|
291 |
+
.use(front_matter.front_matter_plugin)
|
292 |
+
)
|
293 |
+
return md.render(markdown_text)
|
294 |
+
|
295 |
+
@component
|
296 |
+
def MarkdownRenderer(content):
|
297 |
+
html_content = markdown_to_html(content)
|
298 |
+
return html.div(
|
299 |
+
{
|
300 |
+
"style": {
|
301 |
+
"fontFamily": "Arial",
|
302 |
+
"color": "#49454F",
|
303 |
+
"fontSize": "14px",
|
304 |
+
},
|
305 |
+
"dangerouslySetInnerHTML": {"__html": html_content}
|
306 |
+
}
|
307 |
+
)
|
308 |
+
|
309 |
+
@component
|
310 |
+
def ExamplePrompts():
|
311 |
+
example_questions = [example.strip() for example in cfg['examples'].split(";")] if cfg.examples else []
|
312 |
+
|
313 |
+
def create_prompt_button(question):
|
314 |
+
return html.button(
|
315 |
+
{
|
316 |
+
"style": {
|
317 |
+
"backgroundColor": "#FFFFFF",
|
318 |
+
"borderWidth": "1px",
|
319 |
+
"borderColor": "#65558F",
|
320 |
+
"borderRadius": "20px",
|
321 |
+
"padding": "5px 7px",
|
322 |
+
"margin": "5px",
|
323 |
+
"cursor": "pointer",
|
324 |
+
"color": "#21005D",
|
325 |
+
"fontSize": "13px",
|
326 |
+
},
|
327 |
+
"type": "button",
|
328 |
+
"onClick": lambda _: send_example(question),
|
329 |
+
},
|
330 |
+
question
|
331 |
+
)
|
332 |
+
|
333 |
+
if first_turn:
|
334 |
+
return html.div(
|
335 |
+
{
|
336 |
+
"style": {
|
337 |
+
"display": "flex",
|
338 |
+
"transform": "translate(4%, 100%)",
|
339 |
+
"flexDirection": "column",
|
340 |
+
"justifyContent": "center",
|
341 |
+
"width": "90%",
|
342 |
+
}
|
343 |
+
},
|
344 |
+
html.p(
|
345 |
+
{
|
346 |
+
"style": {
|
347 |
+
"fontSize": "16px",
|
348 |
+
"fontFamily": "Arial",
|
349 |
+
"color": "#49454F",
|
350 |
+
"marginBottom": "5px",
|
351 |
+
"transform": "translateX(3%)",
|
352 |
+
"textAlign": "left",
|
353 |
+
}
|
354 |
+
},
|
355 |
+
"Queries to try:"
|
356 |
+
),
|
357 |
+
html.div(
|
358 |
+
{
|
359 |
+
"style": {
|
360 |
+
"display": "flex",
|
361 |
+
"flexWrap": "wrap",
|
362 |
+
"justifyContent": "center",
|
363 |
+
}
|
364 |
+
},
|
365 |
+
*[create_prompt_button(q) for q in example_questions]
|
366 |
+
)
|
367 |
+
)
|
368 |
+
|
369 |
+
return None
|
370 |
+
|
371 |
+
@component
|
372 |
+
def ChatBox():
|
373 |
+
return html.div(
|
374 |
+
{
|
375 |
+
"style": {
|
376 |
+
"position": "fixed",
|
377 |
+
"bottom": "70px" if collapsed else "140px",
|
378 |
+
"left": "50%",
|
379 |
+
"transform": "translateX(-50%)",
|
380 |
+
"width": "80%",
|
381 |
+
"display": "flex",
|
382 |
+
"alignItems": "center",
|
383 |
+
"backgroundColor": "#FFFFFF",
|
384 |
+
"borderRadius": "50px",
|
385 |
+
"zIndex": "1000",
|
386 |
+
}
|
387 |
+
},
|
388 |
+
html.input(
|
389 |
+
{
|
390 |
+
"type": "text",
|
391 |
+
"value": message,
|
392 |
+
"placeholder": "Your Message",
|
393 |
+
"onChange": handle_input_change,
|
394 |
+
"onKeyDown": handle_key_down,
|
395 |
+
"style": {
|
396 |
+
"width": "100%",
|
397 |
+
"padding": "10px 50px 10px 20px",
|
398 |
+
"border": "none",
|
399 |
+
"borderRadius": "50px",
|
400 |
+
"color": "#65558F",
|
401 |
+
}
|
402 |
+
}
|
403 |
+
),
|
404 |
+
html.button(
|
405 |
+
{
|
406 |
+
"type": "button",
|
407 |
+
"onClick": send_message,
|
408 |
+
"style": {
|
409 |
+
"position": "absolute",
|
410 |
+
"right": "8px",
|
411 |
+
"top": "50%",
|
412 |
+
"transform":"translateY(-50%)",
|
413 |
+
"background": "none",
|
414 |
+
"border": "none",
|
415 |
+
"cursor": "pointer",
|
416 |
+
"padding": "8px",
|
417 |
+
"display": "flex",
|
418 |
+
"alignItems": "center",
|
419 |
+
"justifyContent": "center",
|
420 |
+
}
|
421 |
+
},
|
422 |
+
svg.svg(
|
423 |
+
{
|
424 |
+
"xmlns": "http://www.w3.org/2000/svg",
|
425 |
+
"width": "20",
|
426 |
+
"height": "20",
|
427 |
+
"fill": "none",
|
428 |
+
"stroke": "currentColor",
|
429 |
+
"stroke-linecap": "round",
|
430 |
+
"stroke-linejoin": "round",
|
431 |
+
"stroke-width": "2",
|
432 |
+
"viewBox": "0 0 24 24",
|
433 |
+
"class": "feather feather-send",
|
434 |
+
},
|
435 |
+
svg.path({"d": "M22 2 11 13"}),
|
436 |
+
svg.path({"d": "M22 2 15 22 11 13 2 9z"})
|
437 |
+
)
|
438 |
+
)
|
439 |
+
)
|
440 |
+
|
441 |
+
|
442 |
+
@component
|
443 |
+
def ChatMessage(user, message):
|
444 |
+
|
445 |
+
return html.div(
|
446 |
+
{
|
447 |
+
"style": {
|
448 |
+
"display": "flex",
|
449 |
+
"width": "75%",
|
450 |
+
"transform": "translateX(20%)",
|
451 |
+
"justifyContent": "flex-end" if user == "human" else "flex-start",
|
452 |
+
"margin": "20px 0px 10px 0px"
|
453 |
+
}
|
454 |
+
},
|
455 |
+
html.div(
|
456 |
+
{
|
457 |
+
"style": {
|
458 |
+
"maxWidth": "50%",
|
459 |
+
"padding": "0px 15px 0px 10px",
|
460 |
+
"borderRadius": "15px",
|
461 |
+
"backgroundColor": "#E8DEF8" if user == "human" else "#ECE6F0",
|
462 |
+
"color": "#000000",
|
463 |
+
}
|
464 |
+
},
|
465 |
+
MarkdownRenderer(message)
|
466 |
+
)
|
467 |
+
)
|
468 |
+
|
469 |
+
@component
|
470 |
+
def Logs():
|
471 |
+
if (len(messages) > 0) and (len(log_entries) > 0) and (messages[-1]["message"] != wait_message) and (show_logs_button):
|
472 |
+
if not show_logs:
|
473 |
+
return html.div(
|
474 |
+
{
|
475 |
+
"style": {
|
476 |
+
"display": "flex",
|
477 |
+
"transform": "translateX(75%)",
|
478 |
+
"width": "20%",
|
479 |
+
"margin": "0px",
|
480 |
+
}
|
481 |
+
},
|
482 |
+
html.button(
|
483 |
+
{
|
484 |
+
"style": {
|
485 |
+
"position": "flex",
|
486 |
+
"background": "none",
|
487 |
+
"color": "#757575",
|
488 |
+
"border": "none",
|
489 |
+
"cursor": "pointer",
|
490 |
+
"fontFamily": "Arial",
|
491 |
+
"fontSize": "14px",
|
492 |
+
},
|
493 |
+
"type": "button",
|
494 |
+
"onClick": lambda _: set_show_logs(True)
|
495 |
+
},
|
496 |
+
"Show Logs"
|
497 |
+
)
|
498 |
+
)
|
499 |
+
else:
|
500 |
+
return html.div(
|
501 |
+
{
|
502 |
+
"style": {
|
503 |
+
"display": "flex",
|
504 |
+
"transform": "translateX(20%)",
|
505 |
+
"border": "2px solid #e2dfdf",
|
506 |
+
"borderRadius": "10px",
|
507 |
+
"width": "75%",
|
508 |
+
}
|
509 |
+
},
|
510 |
+
html.div(
|
511 |
+
[
|
512 |
+
html.p(
|
513 |
+
{
|
514 |
+
"style": {
|
515 |
+
"fontSize": "14px",
|
516 |
+
"marginLeft": "10px",
|
517 |
+
}
|
518 |
+
},
|
519 |
+
entry
|
520 |
+
) for entry in log_entries
|
521 |
+
],
|
522 |
+
html.button(
|
523 |
+
{
|
524 |
+
"style": {
|
525 |
+
"position": "flex",
|
526 |
+
"background": "none",
|
527 |
+
"color": "#757575",
|
528 |
+
"border": "none",
|
529 |
+
"cursor": "pointer",
|
530 |
+
"fontFamily": "Arial",
|
531 |
+
"fontSize": "14px",
|
532 |
+
"marginBottom": "10px",
|
533 |
+
"marginLeft": "5px",
|
534 |
+
},
|
535 |
+
"type": "button",
|
536 |
+
"onClick": lambda _: set_show_logs(False)
|
537 |
+
},
|
538 |
+
"Hide Logs"
|
539 |
+
)
|
540 |
+
)
|
541 |
+
)
|
542 |
+
|
543 |
+
return None
|
544 |
+
|
545 |
+
@component
|
546 |
+
def ChatUI():
|
547 |
+
|
548 |
+
def render_chat_content():
|
549 |
+
if first_turn:
|
550 |
+
return ExamplePrompts()
|
551 |
+
else:
|
552 |
+
return [ChatMessage(msg["user"], msg["message"]) for msg in messages]
|
553 |
+
|
554 |
+
return html.div(
|
555 |
+
{
|
556 |
+
"style": {
|
557 |
+
"display": "flex",
|
558 |
+
"flexDirection": "column",
|
559 |
+
"padding": "10px",
|
560 |
+
"backgroundColor": "#F4F1F4",
|
561 |
+
"overflowY": "auto",
|
562 |
+
"height": f"calc(100vh - {265 if collapsed else 335}px)",
|
563 |
+
"marginBottom": "15px",
|
564 |
+
"paddingBottom": "15px",
|
565 |
+
},
|
566 |
+
},
|
567 |
+
render_chat_content(),
|
568 |
+
Logs()
|
569 |
+
)
|
570 |
+
|
571 |
+
|
572 |
+
@component
|
573 |
+
def Footer():
|
574 |
+
|
575 |
+
if collapsed:
|
576 |
+
return html.footer(
|
577 |
+
{
|
578 |
+
"style": {
|
579 |
+
"backgroundColor": "#FFFFFF",
|
580 |
+
"position": "fixed",
|
581 |
+
"bottom": 0,
|
582 |
+
"width": "100%",
|
583 |
+
"height": "50px",
|
584 |
+
}
|
585 |
+
},
|
586 |
+
html.button(
|
587 |
+
{
|
588 |
+
"style": {
|
589 |
+
"background": "none",
|
590 |
+
"border": "none",
|
591 |
+
"color": "#757575",
|
592 |
+
"cursor": "pointer",
|
593 |
+
"position": "absolute",
|
594 |
+
"bottom": "5px",
|
595 |
+
"right": "10px",
|
596 |
+
},
|
597 |
+
"type": "button",
|
598 |
+
"on_click": toggle_footer,
|
599 |
+
},
|
600 |
+
svg.svg(
|
601 |
+
{
|
602 |
+
"xmlns": "http://www.w3.org/2000/svg",
|
603 |
+
"width": "24",
|
604 |
+
"height": "24",
|
605 |
+
"fill": "none",
|
606 |
+
"stroke": "currentColor",
|
607 |
+
"stroke-linecap": "round",
|
608 |
+
"stroke-linejoin": "round",
|
609 |
+
"stroke-width": "3",
|
610 |
+
"viewBox": "0 0 24 24",
|
611 |
+
},
|
612 |
+
svg.path({"d": "M19 14l-7-7-7 7"})
|
613 |
+
)
|
614 |
+
)
|
615 |
+
)
|
616 |
+
|
617 |
+
else:
|
618 |
+
return html.footer(
|
619 |
+
{
|
620 |
+
"style": {
|
621 |
+
"backgroundColor": "#FFFFFF",
|
622 |
+
"position": "fixed",
|
623 |
+
"bottom": 0,
|
624 |
+
"width": "100%",
|
625 |
+
}
|
626 |
+
},
|
627 |
+
html.div(
|
628 |
+
{
|
629 |
+
"style": {
|
630 |
+
"backgroundColor": "#FFFFFF",
|
631 |
+
"padding": "0px 20px 0px 50px",
|
632 |
+
"position": "relative",
|
633 |
+
"display": "block",
|
634 |
+
}
|
635 |
+
},
|
636 |
+
html.button(
|
637 |
+
{
|
638 |
+
"style": {
|
639 |
+
"position": "absolute",
|
640 |
+
"right": "10px",
|
641 |
+
"background": "none",
|
642 |
+
"border": "none",
|
643 |
+
"color": "#757575",
|
644 |
+
"cursor": "pointer",
|
645 |
+
},
|
646 |
+
"type": "button",
|
647 |
+
"on_click": toggle_footer,
|
648 |
+
},
|
649 |
+
svg.svg(
|
650 |
+
{
|
651 |
+
"xmlns": "http://www.w3.org/2000/svg",
|
652 |
+
"width": "24",
|
653 |
+
"height": "24",
|
654 |
+
"fill": "none",
|
655 |
+
"stroke": "currentColor",
|
656 |
+
"stroke-linecap": "round",
|
657 |
+
"stroke-linejoin": "round",
|
658 |
+
"stroke-width": "3",
|
659 |
+
"viewBox": "0 0 24 24",
|
660 |
+
},
|
661 |
+
svg.path({"d": "M18 6L6 18"}),
|
662 |
+
svg.path({"d": "M6 6l12 12"})
|
663 |
+
)
|
664 |
+
),
|
665 |
+
html.p(
|
666 |
+
{
|
667 |
+
"style": {
|
668 |
+
"fontSize": "20px",
|
669 |
+
"color": "#4b4851"
|
670 |
+
}
|
671 |
+
},
|
672 |
+
"How this works?",
|
673 |
+
),
|
674 |
+
html.p(
|
675 |
+
{
|
676 |
+
"style": {
|
677 |
+
"color": "#757575",
|
678 |
+
}
|
679 |
+
},
|
680 |
+
"This app was built with ",
|
681 |
+
html.a(
|
682 |
+
{
|
683 |
+
"href": "https://vectara.com/",
|
684 |
+
"target": "_blank",
|
685 |
+
},
|
686 |
+
"Vectara",
|
687 |
+
),
|
688 |
+
html.br(),
|
689 |
+
"It demonstrates the use of Agentic-RAG functionality with Vectara",
|
690 |
+
)
|
691 |
+
)
|
692 |
+
)
|
693 |
+
|
694 |
+
return html.div(
|
695 |
+
{
|
696 |
+
"style": {
|
697 |
+
"backgroundColor": "#F4F1F4",
|
698 |
+
"margin": "0",
|
699 |
+
"padding": "0",
|
700 |
+
"minHeight": "100vh",
|
701 |
+
"display": "flex",
|
702 |
+
"boxSizing": "border-box",
|
703 |
+
"flexDirection": "column",
|
704 |
+
"overflowX": "hidden",
|
705 |
+
"position": "relative",
|
706 |
+
}
|
707 |
+
},
|
708 |
+
html.head(
|
709 |
+
html.style("""
|
710 |
+
body {
|
711 |
+
margin: 0;
|
712 |
+
padding: 0;
|
713 |
+
}
|
714 |
+
""")
|
715 |
+
),
|
716 |
+
Header(
|
717 |
+
demo_name=cfg['demo_name'],
|
718 |
+
short_description=cfg['short_description'],
|
719 |
+
extra_info=cfg['extra_info']
|
720 |
+
),
|
721 |
+
ChatUI(),
|
722 |
+
ChatBox(),
|
723 |
+
Footer(),
|
724 |
+
)
|
725 |
+
|
726 |
+
# app = Starlette()
|
727 |
+
|
728 |
+
# configure(app, App)
|
729 |
+
|
730 |
+
# Should only need for local testing
|
731 |
+
|
732 |
+
if __name__ == "__main__":
|
733 |
+
run(App)
|
app_full.py
ADDED
@@ -0,0 +1,714 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import asyncio
|
2 |
+
import threading
|
3 |
+
from markdown_it import MarkdownIt
|
4 |
+
from mdit_py_plugins import front_matter
|
5 |
+
|
6 |
+
from reactpy import component, html, hooks, use_effect, svg, run # DELETE run FOR DEPLOYMENT
|
7 |
+
from reactpy.backend.starlette import configure
|
8 |
+
from starlette.applications import Starlette
|
9 |
+
from vectara_agentic.agent import AgentStatusType
|
10 |
+
from agent import initialize_agent, get_agent_config
|
11 |
+
|
12 |
+
wait_message = "Please wait. Assistant at work..."
|
13 |
+
|
14 |
+
@component
|
15 |
+
def App():
|
16 |
+
|
17 |
+
# Used for showing/hiding logs
|
18 |
+
show_logs, set_show_logs = hooks.use_state(False)
|
19 |
+
|
20 |
+
# Determining when the "Show Logs" button should appear
|
21 |
+
show_logs_button, set_show_logs_button = hooks.use_state(False)
|
22 |
+
|
23 |
+
# Used for resetting chat bot with "Start Over" button.
|
24 |
+
first_turn, set_first_turn = hooks.use_state(True)
|
25 |
+
|
26 |
+
# Tracks the state of whether the header is collapsed or exapnded
|
27 |
+
more_info, set_more_info = hooks.use_state(False)
|
28 |
+
|
29 |
+
# Tracks the state of whether the footer is collapsed or expanded
|
30 |
+
collapsed, set_collapse = hooks.use_state(False)
|
31 |
+
|
32 |
+
# Record of Chat Messages
|
33 |
+
messages, set_messages = hooks.use_state([])
|
34 |
+
|
35 |
+
message, set_message = hooks.use_state("")
|
36 |
+
# input_value, set_input_value = hooks.use_state("")
|
37 |
+
|
38 |
+
def use_agent_logger():
|
39 |
+
agent_log_entries, set_agent_log_entries = hooks.use_state([])
|
40 |
+
|
41 |
+
def reset_log_entries():
|
42 |
+
set_agent_log_entries([])
|
43 |
+
|
44 |
+
def add_log_entry(new_log_entry):
|
45 |
+
set_agent_log_entries(lambda previous_entries: previous_entries + [new_log_entry])
|
46 |
+
|
47 |
+
return agent_log_entries, add_log_entry, reset_log_entries
|
48 |
+
|
49 |
+
log_entries, add_log_entry, reset_log_entries = use_agent_logger()
|
50 |
+
|
51 |
+
def update_func(status_type: AgentStatusType, msg: str):
|
52 |
+
if status_type != AgentStatusType.AGENT_UPDATE:
|
53 |
+
output = f"{status_type.value} - {msg}"
|
54 |
+
add_log_entry(output)
|
55 |
+
|
56 |
+
cfg, _ = hooks.use_state(get_agent_config())
|
57 |
+
agent, _ = hooks.use_state(initialize_agent(cfg, update_func))
|
58 |
+
|
59 |
+
def toggle_header(event=None):
|
60 |
+
set_more_info(not more_info)
|
61 |
+
|
62 |
+
def toggle_footer(event=None):
|
63 |
+
set_collapse(not collapsed)
|
64 |
+
|
65 |
+
# Clears all messages and resets chat interface
|
66 |
+
def start_over(event=None):
|
67 |
+
set_messages([])
|
68 |
+
set_first_turn(True)
|
69 |
+
|
70 |
+
def display_message(new_messages):
|
71 |
+
if first_turn:
|
72 |
+
set_first_turn(False)
|
73 |
+
|
74 |
+
set_messages(messages + list(new_messages))
|
75 |
+
|
76 |
+
async def chat_response(user_message):
|
77 |
+
response = await asyncio.to_thread(agent.chat, user_message)
|
78 |
+
return response
|
79 |
+
|
80 |
+
async def send_message_async(sent_message):
|
81 |
+
response = await chat_response(sent_message)
|
82 |
+
set_messages(messages[:-1])
|
83 |
+
display_message(
|
84 |
+
[
|
85 |
+
{"user": "human", "message": sent_message},
|
86 |
+
{"user": "bot", "message": response},
|
87 |
+
]
|
88 |
+
)
|
89 |
+
set_show_logs_button(True)
|
90 |
+
|
91 |
+
def send_message(event=None):
|
92 |
+
print(f"DEBUG: SEND MESSAGE CALLED FOR MESSAGE {message}")
|
93 |
+
if message.strip():
|
94 |
+
sent_message = message
|
95 |
+
set_message("")
|
96 |
+
# set_input_value("")
|
97 |
+
set_show_logs_button(False)
|
98 |
+
set_show_logs(False)
|
99 |
+
reset_log_entries()
|
100 |
+
display_message([{"user": "human", "message": sent_message}])
|
101 |
+
display_message([{"user": "bot", "message": wait_message}])
|
102 |
+
|
103 |
+
asyncio.create_task(send_message_async(sent_message))
|
104 |
+
|
105 |
+
def send_example(ex_prompt):
|
106 |
+
if ex_prompt.strip():
|
107 |
+
sent_message = ex_prompt
|
108 |
+
set_message("")
|
109 |
+
reset_log_entries()
|
110 |
+
display_message([{"user": "human", "message": sent_message}])
|
111 |
+
display_message([{"user": "bot", "message": wait_message}])
|
112 |
+
|
113 |
+
asyncio.create_task(send_message_async(sent_message))
|
114 |
+
|
115 |
+
async def handle_key_down(event):
|
116 |
+
if event['key'] == 'Enter' and message.strip():
|
117 |
+
await send_message()
|
118 |
+
set_message("")
|
119 |
+
|
120 |
+
def handle_input_change(event):
|
121 |
+
set_message(event['target']['value'])
|
122 |
+
|
123 |
+
@component
|
124 |
+
def Header(demo_name: str, short_description: str, extra_info: str):
|
125 |
+
return html.header(
|
126 |
+
{
|
127 |
+
"style": {
|
128 |
+
"backgroundColor": "#FFFFFF",
|
129 |
+
"display": "flex",
|
130 |
+
"justifyContent": "space-between",
|
131 |
+
"alignItems": "center",
|
132 |
+
}
|
133 |
+
},
|
134 |
+
html.div(
|
135 |
+
{
|
136 |
+
"style": {
|
137 |
+
"display": "flex",
|
138 |
+
"alignItems": "center",
|
139 |
+
"flex": 2,
|
140 |
+
"textAlign": "left",
|
141 |
+
"padding": "10px",
|
142 |
+
}
|
143 |
+
},
|
144 |
+
html.img(
|
145 |
+
{
|
146 |
+
"src": "https://avatars.githubusercontent.com/u/108304503?s=200&v=4",
|
147 |
+
"style": {
|
148 |
+
"height": "30px",
|
149 |
+
"marginRight": "15px",
|
150 |
+
"marginLeft": "5px",
|
151 |
+
"transform": "translateY(-2px)",
|
152 |
+
}
|
153 |
+
}
|
154 |
+
),
|
155 |
+
html.p(
|
156 |
+
{
|
157 |
+
"style": {
|
158 |
+
"fontSize": "25px",
|
159 |
+
"fontFamily": "Georgia, 'Times New Roman', Times, serif",
|
160 |
+
}
|
161 |
+
},
|
162 |
+
f"{demo_name}"
|
163 |
+
),
|
164 |
+
),
|
165 |
+
html.div(
|
166 |
+
{
|
167 |
+
"style": {
|
168 |
+
"flex": 5,
|
169 |
+
"textAlign": "center",
|
170 |
+
"padding": "10px 0px 15px 0px",
|
171 |
+
"fontFamily": "Lato",
|
172 |
+
"position": "relative",
|
173 |
+
}
|
174 |
+
},
|
175 |
+
html.h3(f"Welcome to the {demo_name} Demo"),
|
176 |
+
html.p(
|
177 |
+
short_description,
|
178 |
+
html.button(
|
179 |
+
{
|
180 |
+
"style": {
|
181 |
+
"display": "inline" if not more_info else "none",
|
182 |
+
"backgroundColor": "#FFFFFF",
|
183 |
+
"color": "#757575",
|
184 |
+
"fontSize": "13px",
|
185 |
+
"cursor": "pointer",
|
186 |
+
"border": "none",
|
187 |
+
"padding": "0px 0px 0px 5px",
|
188 |
+
},
|
189 |
+
"type": "button",
|
190 |
+
"onClick": toggle_header,
|
191 |
+
},
|
192 |
+
html.u(
|
193 |
+
{
|
194 |
+
"style": {
|
195 |
+
"flex": 2,
|
196 |
+
"textAlign": "right",
|
197 |
+
"padding": "10px",
|
198 |
+
}
|
199 |
+
},
|
200 |
+
"Learn More"
|
201 |
+
)
|
202 |
+
),
|
203 |
+
f" {extra_info}" if more_info else ""
|
204 |
+
),
|
205 |
+
html.button(
|
206 |
+
{
|
207 |
+
"style": {
|
208 |
+
"display": "block" if more_info else "none",
|
209 |
+
"background": "none",
|
210 |
+
"border": "none",
|
211 |
+
"color": "#757575",
|
212 |
+
"cursor": "pointer",
|
213 |
+
"position": "absolute",
|
214 |
+
"left": "50%",
|
215 |
+
"transform": "translateX(-50%)",
|
216 |
+
"bottom": "1px",
|
217 |
+
},
|
218 |
+
"type": "button",
|
219 |
+
"on_click": toggle_header,
|
220 |
+
},
|
221 |
+
svg.svg(
|
222 |
+
{
|
223 |
+
"width": "20",
|
224 |
+
"height": "20",
|
225 |
+
"viewBox": "0 0 20 20",
|
226 |
+
"fill": "none",
|
227 |
+
"stroke": "black",
|
228 |
+
"strokeWidth": "2",
|
229 |
+
"strokeLinecap": "round",
|
230 |
+
"strokeLinejoin": "round",
|
231 |
+
},
|
232 |
+
svg.path(
|
233 |
+
{
|
234 |
+
"d": "M12 19V5M5 12l7-7 7 7",
|
235 |
+
"stroke": "currentColor",
|
236 |
+
}
|
237 |
+
)
|
238 |
+
)
|
239 |
+
)
|
240 |
+
),
|
241 |
+
html.div(
|
242 |
+
{
|
243 |
+
"style": {
|
244 |
+
"flex": 2,
|
245 |
+
"textAlign": "right",
|
246 |
+
"padding": "10px",
|
247 |
+
}
|
248 |
+
},
|
249 |
+
html.button(
|
250 |
+
{
|
251 |
+
"style": {
|
252 |
+
"backgroundColor": "#FFFFFF",
|
253 |
+
"color": "#757575",
|
254 |
+
"fontSize": "14px",
|
255 |
+
"cursor": "pointer",
|
256 |
+
"border": "1px solid #e2dfdf",
|
257 |
+
"borderRadius": "5px",
|
258 |
+
"padding": "6px 20px",
|
259 |
+
"marginRight": "15px",
|
260 |
+
},
|
261 |
+
"type": "button",
|
262 |
+
"onClick": start_over,
|
263 |
+
},
|
264 |
+
"Start Over?"
|
265 |
+
)
|
266 |
+
)
|
267 |
+
)
|
268 |
+
|
269 |
+
def markdown_to_html(markdown_text):
|
270 |
+
md = (
|
271 |
+
MarkdownIt("commonmark", {"breaks": True, "html": True})
|
272 |
+
.use(front_matter.front_matter_plugin)
|
273 |
+
)
|
274 |
+
return md.render(markdown_text)
|
275 |
+
|
276 |
+
@component
|
277 |
+
def MarkdownRenderer(content):
|
278 |
+
html_content = markdown_to_html(content)
|
279 |
+
return html.div(
|
280 |
+
{
|
281 |
+
"style": {
|
282 |
+
"fontFamily": "Arial",
|
283 |
+
"color": "#49454F",
|
284 |
+
"fontSize": "14px",
|
285 |
+
},
|
286 |
+
"dangerouslySetInnerHTML": {"__html": html_content}
|
287 |
+
}
|
288 |
+
)
|
289 |
+
|
290 |
+
@component
|
291 |
+
def ExamplePrompts():
|
292 |
+
example_questions = [example.strip() for example in cfg['examples'].split(";")] if cfg.examples else []
|
293 |
+
|
294 |
+
def create_prompt_button(question):
|
295 |
+
return html.button(
|
296 |
+
{
|
297 |
+
"style": {
|
298 |
+
"backgroundColor": "#FFFFFF",
|
299 |
+
"borderWidth": "1px",
|
300 |
+
"borderColor": "#65558F",
|
301 |
+
"borderRadius": "20px",
|
302 |
+
"padding": "5px 7px",
|
303 |
+
"margin": "5px",
|
304 |
+
"cursor": "pointer",
|
305 |
+
"color": "#21005D",
|
306 |
+
"fontSize": "13px",
|
307 |
+
},
|
308 |
+
"type": "button",
|
309 |
+
"onClick": lambda _: send_example(question),
|
310 |
+
},
|
311 |
+
question
|
312 |
+
)
|
313 |
+
|
314 |
+
if first_turn:
|
315 |
+
return html.div(
|
316 |
+
{
|
317 |
+
"style": {
|
318 |
+
"display": "flex",
|
319 |
+
"transform": "translate(4%, 100%)",
|
320 |
+
"flexDirection": "column",
|
321 |
+
"justifyContent": "center",
|
322 |
+
"width": "90%",
|
323 |
+
}
|
324 |
+
},
|
325 |
+
html.p(
|
326 |
+
{
|
327 |
+
"style": {
|
328 |
+
"fontSize": "16px",
|
329 |
+
"fontFamily": "Arial",
|
330 |
+
"color": "#49454F",
|
331 |
+
"marginBottom": "5px",
|
332 |
+
"transform": "translateX(3%)",
|
333 |
+
"textAlign": "left",
|
334 |
+
}
|
335 |
+
},
|
336 |
+
"Queries to try:"
|
337 |
+
),
|
338 |
+
html.div(
|
339 |
+
{
|
340 |
+
"style": {
|
341 |
+
"display": "flex",
|
342 |
+
"flexWrap": "wrap",
|
343 |
+
"justifyContent": "center",
|
344 |
+
}
|
345 |
+
},
|
346 |
+
*[create_prompt_button(q) for q in example_questions]
|
347 |
+
)
|
348 |
+
)
|
349 |
+
|
350 |
+
return None
|
351 |
+
|
352 |
+
@component
|
353 |
+
def ChatBox():
|
354 |
+
return html.div(
|
355 |
+
{
|
356 |
+
"style": {
|
357 |
+
"position": "fixed",
|
358 |
+
"bottom": "70px" if collapsed else "140px",
|
359 |
+
"left": "50%",
|
360 |
+
"transform": "translateX(-50%)",
|
361 |
+
"width": "80%",
|
362 |
+
"display": "flex",
|
363 |
+
"alignItems": "center",
|
364 |
+
"backgroundColor": "#FFFFFF",
|
365 |
+
"borderRadius": "50px",
|
366 |
+
"zIndex": "1000",
|
367 |
+
}
|
368 |
+
},
|
369 |
+
html.input(
|
370 |
+
{
|
371 |
+
"type": "text",
|
372 |
+
"value": message,
|
373 |
+
"placeholder": "Your Message",
|
374 |
+
"onChange": handle_input_change,
|
375 |
+
"onKeyDown": handle_key_down,
|
376 |
+
"style": {
|
377 |
+
"width": "100%",
|
378 |
+
"padding": "10px 50px 10px 20px",
|
379 |
+
"border": "none",
|
380 |
+
"borderRadius": "50px",
|
381 |
+
"color": "#65558F",
|
382 |
+
}
|
383 |
+
}
|
384 |
+
),
|
385 |
+
html.button(
|
386 |
+
{
|
387 |
+
"type": "button",
|
388 |
+
"onClick": send_message,
|
389 |
+
"style": {
|
390 |
+
"position": "absolute",
|
391 |
+
"right": "8px",
|
392 |
+
"top": "50%",
|
393 |
+
"transform":"translateY(-50%)",
|
394 |
+
"background": "none",
|
395 |
+
"border": "none",
|
396 |
+
"cursor": "pointer",
|
397 |
+
"padding": "8px",
|
398 |
+
"display": "flex",
|
399 |
+
"alignItems": "center",
|
400 |
+
"justifyContent": "center",
|
401 |
+
}
|
402 |
+
},
|
403 |
+
svg.svg(
|
404 |
+
{
|
405 |
+
"xmlns": "http://www.w3.org/2000/svg",
|
406 |
+
"width": "20",
|
407 |
+
"height": "20",
|
408 |
+
"fill": "none",
|
409 |
+
"stroke": "currentColor",
|
410 |
+
"stroke-linecap": "round",
|
411 |
+
"stroke-linejoin": "round",
|
412 |
+
"stroke-width": "2",
|
413 |
+
"viewBox": "0 0 24 24",
|
414 |
+
"class": "feather feather-send",
|
415 |
+
},
|
416 |
+
svg.path({"d": "M22 2 11 13"}),
|
417 |
+
svg.path({"d": "M22 2 15 22 11 13 2 9z"})
|
418 |
+
)
|
419 |
+
)
|
420 |
+
)
|
421 |
+
|
422 |
+
|
423 |
+
@component
|
424 |
+
def ChatMessage(user, message):
|
425 |
+
|
426 |
+
return html.div(
|
427 |
+
{
|
428 |
+
"style": {
|
429 |
+
"display": "flex",
|
430 |
+
"width": "75%",
|
431 |
+
"transform": "translateX(20%)",
|
432 |
+
"justifyContent": "flex-end" if user == "human" else "flex-start",
|
433 |
+
"margin": "20px 0px 10px 0px"
|
434 |
+
}
|
435 |
+
},
|
436 |
+
html.div(
|
437 |
+
{
|
438 |
+
"style": {
|
439 |
+
"maxWidth": "50%",
|
440 |
+
"padding": "0px 15px 0px 10px",
|
441 |
+
"borderRadius": "15px",
|
442 |
+
"backgroundColor": "#E8DEF8" if user == "human" else "#ECE6F0",
|
443 |
+
"color": "#000000",
|
444 |
+
}
|
445 |
+
},
|
446 |
+
MarkdownRenderer(message)
|
447 |
+
)
|
448 |
+
)
|
449 |
+
|
450 |
+
@component
|
451 |
+
def Logs():
|
452 |
+
if (len(messages) > 0) and (len(log_entries) > 0) and (messages[-1]["message"] != wait_message) and (show_logs_button):
|
453 |
+
if not show_logs:
|
454 |
+
return html.div(
|
455 |
+
{
|
456 |
+
"style": {
|
457 |
+
"display": "flex",
|
458 |
+
"transform": "translateX(75%)",
|
459 |
+
"width": "20%",
|
460 |
+
"margin": "0px",
|
461 |
+
}
|
462 |
+
},
|
463 |
+
html.button(
|
464 |
+
{
|
465 |
+
"style": {
|
466 |
+
"position": "flex",
|
467 |
+
"background": "none",
|
468 |
+
"color": "#757575",
|
469 |
+
"border": "none",
|
470 |
+
"cursor": "pointer",
|
471 |
+
"fontFamily": "Arial",
|
472 |
+
"fontSize": "14px",
|
473 |
+
},
|
474 |
+
"type": "button",
|
475 |
+
"onClick": lambda _: set_show_logs(True)
|
476 |
+
},
|
477 |
+
"Show Logs"
|
478 |
+
)
|
479 |
+
)
|
480 |
+
else:
|
481 |
+
return html.div(
|
482 |
+
{
|
483 |
+
"style": {
|
484 |
+
"display": "flex",
|
485 |
+
"transform": "translateX(20%)",
|
486 |
+
"border": "2px solid #e2dfdf",
|
487 |
+
"borderRadius": "10px",
|
488 |
+
"width": "75%",
|
489 |
+
}
|
490 |
+
},
|
491 |
+
html.div(
|
492 |
+
[
|
493 |
+
html.p(
|
494 |
+
{
|
495 |
+
"style": {
|
496 |
+
"fontSize": "14px",
|
497 |
+
"marginLeft": "10px",
|
498 |
+
}
|
499 |
+
},
|
500 |
+
entry
|
501 |
+
) for entry in log_entries
|
502 |
+
],
|
503 |
+
html.button(
|
504 |
+
{
|
505 |
+
"style": {
|
506 |
+
"position": "flex",
|
507 |
+
"background": "none",
|
508 |
+
"color": "#757575",
|
509 |
+
"border": "none",
|
510 |
+
"cursor": "pointer",
|
511 |
+
"fontFamily": "Arial",
|
512 |
+
"fontSize": "14px",
|
513 |
+
"marginBottom": "10px",
|
514 |
+
"marginLeft": "5px",
|
515 |
+
},
|
516 |
+
"type": "button",
|
517 |
+
"onClick": lambda _: set_show_logs(False)
|
518 |
+
},
|
519 |
+
"Hide Logs"
|
520 |
+
)
|
521 |
+
)
|
522 |
+
)
|
523 |
+
|
524 |
+
return None
|
525 |
+
|
526 |
+
@component
|
527 |
+
def ChatUI():
|
528 |
+
|
529 |
+
def render_chat_content():
|
530 |
+
if first_turn:
|
531 |
+
return ExamplePrompts()
|
532 |
+
else:
|
533 |
+
return [ChatMessage(msg["user"], msg["message"]) for msg in messages]
|
534 |
+
|
535 |
+
return html.div(
|
536 |
+
{
|
537 |
+
"style": {
|
538 |
+
"display": "flex",
|
539 |
+
"flexDirection": "column",
|
540 |
+
"padding": "10px",
|
541 |
+
"backgroundColor": "#F4F1F4",
|
542 |
+
"overflowY": "auto",
|
543 |
+
"height": f"calc(100vh - {265 if collapsed else 335}px)",
|
544 |
+
"marginBottom": "15px",
|
545 |
+
"paddingBottom": "15px",
|
546 |
+
},
|
547 |
+
},
|
548 |
+
render_chat_content(),
|
549 |
+
Logs()
|
550 |
+
)
|
551 |
+
|
552 |
+
|
553 |
+
@component
|
554 |
+
def Footer():
|
555 |
+
|
556 |
+
if collapsed:
|
557 |
+
return html.footer(
|
558 |
+
{
|
559 |
+
"style": {
|
560 |
+
"backgroundColor": "#FFFFFF",
|
561 |
+
"position": "fixed",
|
562 |
+
"bottom": 0,
|
563 |
+
"width": "100%",
|
564 |
+
"height": "50px",
|
565 |
+
}
|
566 |
+
},
|
567 |
+
html.button(
|
568 |
+
{
|
569 |
+
"style": {
|
570 |
+
"background": "none",
|
571 |
+
"border": "none",
|
572 |
+
"color": "#757575",
|
573 |
+
"cursor": "pointer",
|
574 |
+
"position": "absolute",
|
575 |
+
"bottom": "5px",
|
576 |
+
"right": "10px",
|
577 |
+
},
|
578 |
+
"type": "button",
|
579 |
+
"on_click": toggle_footer,
|
580 |
+
},
|
581 |
+
svg.svg(
|
582 |
+
{
|
583 |
+
"xmlns": "http://www.w3.org/2000/svg",
|
584 |
+
"width": "24",
|
585 |
+
"height": "24",
|
586 |
+
"fill": "none",
|
587 |
+
"stroke": "currentColor",
|
588 |
+
"stroke-linecap": "round",
|
589 |
+
"stroke-linejoin": "round",
|
590 |
+
"stroke-width": "3",
|
591 |
+
"viewBox": "0 0 24 24",
|
592 |
+
},
|
593 |
+
svg.path({"d": "M19 14l-7-7-7 7"})
|
594 |
+
)
|
595 |
+
)
|
596 |
+
)
|
597 |
+
|
598 |
+
else:
|
599 |
+
return html.footer(
|
600 |
+
{
|
601 |
+
"style": {
|
602 |
+
"backgroundColor": "#FFFFFF",
|
603 |
+
"position": "fixed",
|
604 |
+
"bottom": 0,
|
605 |
+
"width": "100%",
|
606 |
+
}
|
607 |
+
},
|
608 |
+
html.div(
|
609 |
+
{
|
610 |
+
"style": {
|
611 |
+
"backgroundColor": "#FFFFFF",
|
612 |
+
"padding": "0px 20px 0px 50px",
|
613 |
+
"position": "relative",
|
614 |
+
"display": "block",
|
615 |
+
}
|
616 |
+
},
|
617 |
+
html.button(
|
618 |
+
{
|
619 |
+
"style": {
|
620 |
+
"position": "absolute",
|
621 |
+
"right": "10px",
|
622 |
+
"background": "none",
|
623 |
+
"border": "none",
|
624 |
+
"color": "#757575",
|
625 |
+
"cursor": "pointer",
|
626 |
+
},
|
627 |
+
"type": "button",
|
628 |
+
"on_click": toggle_footer,
|
629 |
+
},
|
630 |
+
svg.svg(
|
631 |
+
{
|
632 |
+
"xmlns": "http://www.w3.org/2000/svg",
|
633 |
+
"width": "24",
|
634 |
+
"height": "24",
|
635 |
+
"fill": "none",
|
636 |
+
"stroke": "currentColor",
|
637 |
+
"stroke-linecap": "round",
|
638 |
+
"stroke-linejoin": "round",
|
639 |
+
"stroke-width": "3",
|
640 |
+
"viewBox": "0 0 24 24",
|
641 |
+
},
|
642 |
+
svg.path({"d": "M18 6L6 18"}),
|
643 |
+
svg.path({"d": "M6 6l12 12"})
|
644 |
+
)
|
645 |
+
),
|
646 |
+
html.p(
|
647 |
+
{
|
648 |
+
"style": {
|
649 |
+
"fontSize": "20px",
|
650 |
+
"color": "#4b4851"
|
651 |
+
}
|
652 |
+
},
|
653 |
+
"How this works?",
|
654 |
+
),
|
655 |
+
html.p(
|
656 |
+
{
|
657 |
+
"style": {
|
658 |
+
"color": "#757575",
|
659 |
+
}
|
660 |
+
},
|
661 |
+
"This app was built with ",
|
662 |
+
html.a(
|
663 |
+
{
|
664 |
+
"href": "https://vectara.com/",
|
665 |
+
"target": "_blank",
|
666 |
+
},
|
667 |
+
"Vectara",
|
668 |
+
),
|
669 |
+
html.br(),
|
670 |
+
"It demonstrates the use of Agentic-RAG functionality with Vectara",
|
671 |
+
)
|
672 |
+
)
|
673 |
+
)
|
674 |
+
|
675 |
+
return html.div(
|
676 |
+
{
|
677 |
+
"style": {
|
678 |
+
"backgroundColor": "#F4F1F4",
|
679 |
+
"margin": "0",
|
680 |
+
"padding": "0",
|
681 |
+
"minHeight": "100vh",
|
682 |
+
"display": "flex",
|
683 |
+
"boxSizing": "border-box",
|
684 |
+
"flexDirection": "column",
|
685 |
+
"overflowX": "hidden",
|
686 |
+
"position": "relative",
|
687 |
+
}
|
688 |
+
},
|
689 |
+
html.head(
|
690 |
+
html.style("""
|
691 |
+
body {
|
692 |
+
margin: 0;
|
693 |
+
padding: 0;
|
694 |
+
}
|
695 |
+
""")
|
696 |
+
),
|
697 |
+
Header(
|
698 |
+
demo_name=cfg['demo_name'],
|
699 |
+
short_description=cfg['short_description'],
|
700 |
+
extra_info=cfg['extra_info']
|
701 |
+
),
|
702 |
+
ChatUI(),
|
703 |
+
ChatBox(),
|
704 |
+
Footer(),
|
705 |
+
)
|
706 |
+
|
707 |
+
# app = Starlette()
|
708 |
+
|
709 |
+
# configure(app, App)
|
710 |
+
|
711 |
+
# Should only need for local testing
|
712 |
+
|
713 |
+
if __name__ == "__main__":
|
714 |
+
run(App)
|
chatbox.py
ADDED
@@ -0,0 +1,71 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from reactpy import component, html, svg
|
2 |
+
|
3 |
+
@component
|
4 |
+
def ChatBox(message, handle_input_change, handle_key_down, send_message, collapsed):
|
5 |
+
return html.div(
|
6 |
+
{
|
7 |
+
"style": {
|
8 |
+
"position": "fixed",
|
9 |
+
"bottom": "70px" if collapsed else "140px",
|
10 |
+
"left": "50%",
|
11 |
+
"transform": "translateX(-50%)",
|
12 |
+
"width": "80%",
|
13 |
+
"display": "flex",
|
14 |
+
"alignItems": "center",
|
15 |
+
"backgroundColor": "#FFFFFF",
|
16 |
+
"borderRadius": "50px",
|
17 |
+
"zIndex": "1000",
|
18 |
+
}
|
19 |
+
},
|
20 |
+
html.input(
|
21 |
+
{
|
22 |
+
"type": "text",
|
23 |
+
"value": message,
|
24 |
+
"placeholder": "Your Message",
|
25 |
+
"onChange": handle_input_change,
|
26 |
+
"onKeyDown": handle_key_down,
|
27 |
+
"style": {
|
28 |
+
"width": "100%",
|
29 |
+
"padding": "10px 50px 10px 20px",
|
30 |
+
"border": "none",
|
31 |
+
"borderRadius": "50px",
|
32 |
+
"color": "#65558F",
|
33 |
+
}
|
34 |
+
}
|
35 |
+
),
|
36 |
+
html.button(
|
37 |
+
{
|
38 |
+
"type": "button",
|
39 |
+
"onClick": send_message,
|
40 |
+
"style": {
|
41 |
+
"position": "absolute",
|
42 |
+
"right": "8px",
|
43 |
+
"top": "50%",
|
44 |
+
"transform":"translateY(-50%)",
|
45 |
+
"background": "none",
|
46 |
+
"border": "none",
|
47 |
+
"cursor": "pointer",
|
48 |
+
"padding": "8px",
|
49 |
+
"display": "flex",
|
50 |
+
"alignItems": "center",
|
51 |
+
"justifyContent": "center",
|
52 |
+
}
|
53 |
+
},
|
54 |
+
svg.svg(
|
55 |
+
{
|
56 |
+
"xmlns": "http://www.w3.org/2000/svg",
|
57 |
+
"width": "20",
|
58 |
+
"height": "20",
|
59 |
+
"fill": "none",
|
60 |
+
"stroke": "currentColor",
|
61 |
+
"stroke-linecap": "round",
|
62 |
+
"stroke-linejoin": "round",
|
63 |
+
"stroke-width": "2",
|
64 |
+
"viewBox": "0 0 24 24",
|
65 |
+
"class": "feather feather-send",
|
66 |
+
},
|
67 |
+
svg.path({"d": "M22 2 11 13"}),
|
68 |
+
svg.path({"d": "M22 2 15 22 11 13 2 9z"})
|
69 |
+
)
|
70 |
+
)
|
71 |
+
)
|
chatui.py
ADDED
@@ -0,0 +1,219 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from markdown_it import MarkdownIt
|
2 |
+
from mdit_py_plugins import front_matter
|
3 |
+
|
4 |
+
from reactpy import component, html
|
5 |
+
|
6 |
+
from utils import wait_message
|
7 |
+
|
8 |
+
|
9 |
+
def markdown_to_html(markdown_text):
|
10 |
+
md = (
|
11 |
+
MarkdownIt("commonmark", {"breaks": True, "html": True})
|
12 |
+
.use(front_matter.front_matter_plugin)
|
13 |
+
)
|
14 |
+
return md.render(markdown_text)
|
15 |
+
|
16 |
+
@component
|
17 |
+
def MarkdownRenderer(content):
|
18 |
+
html_content = markdown_to_html(content)
|
19 |
+
return html.div(
|
20 |
+
{
|
21 |
+
"style": {
|
22 |
+
"fontFamily": "Arial",
|
23 |
+
"color": "#49454F",
|
24 |
+
"fontSize": "14px",
|
25 |
+
},
|
26 |
+
"dangerouslySetInnerHTML": {"__html": html_content}
|
27 |
+
}
|
28 |
+
)
|
29 |
+
|
30 |
+
@component
|
31 |
+
def ExamplePrompts(examples, send_example, first_turn):
|
32 |
+
example_questions = [example.strip() for example in examples.split(";")] if examples else []
|
33 |
+
|
34 |
+
def create_prompt_button(question):
|
35 |
+
return html.button(
|
36 |
+
{
|
37 |
+
"style": {
|
38 |
+
"backgroundColor": "#FFFFFF",
|
39 |
+
"borderWidth": "1px",
|
40 |
+
"borderColor": "#65558F",
|
41 |
+
"borderRadius": "20px",
|
42 |
+
"padding": "5px 7px",
|
43 |
+
"margin": "5px",
|
44 |
+
"cursor": "pointer",
|
45 |
+
"color": "#21005D",
|
46 |
+
"fontSize": "13px",
|
47 |
+
},
|
48 |
+
"type": "button",
|
49 |
+
"onClick": lambda _: send_example(question),
|
50 |
+
},
|
51 |
+
question
|
52 |
+
)
|
53 |
+
|
54 |
+
if first_turn:
|
55 |
+
return html.div(
|
56 |
+
{
|
57 |
+
"style": {
|
58 |
+
"display": "flex",
|
59 |
+
"transform": "translate(4%, 100%)",
|
60 |
+
"flexDirection": "column",
|
61 |
+
"justifyContent": "center",
|
62 |
+
"width": "90%",
|
63 |
+
}
|
64 |
+
},
|
65 |
+
html.p(
|
66 |
+
{
|
67 |
+
"style": {
|
68 |
+
"fontSize": "16px",
|
69 |
+
"fontFamily": "Arial",
|
70 |
+
"color": "#49454F",
|
71 |
+
"marginBottom": "5px",
|
72 |
+
"transform": "translateX(3%)",
|
73 |
+
"textAlign": "left",
|
74 |
+
}
|
75 |
+
},
|
76 |
+
"Queries to try:"
|
77 |
+
),
|
78 |
+
html.div(
|
79 |
+
{
|
80 |
+
"style": {
|
81 |
+
"display": "flex",
|
82 |
+
"flexWrap": "wrap",
|
83 |
+
"justifyContent": "center",
|
84 |
+
}
|
85 |
+
},
|
86 |
+
*[create_prompt_button(q) for q in example_questions]
|
87 |
+
)
|
88 |
+
)
|
89 |
+
|
90 |
+
return None
|
91 |
+
|
92 |
+
@component
|
93 |
+
def ChatMessage(user, message):
|
94 |
+
|
95 |
+
return html.div(
|
96 |
+
{
|
97 |
+
"style": {
|
98 |
+
"display": "flex",
|
99 |
+
"width": "75%",
|
100 |
+
"transform": "translateX(20%)",
|
101 |
+
"justifyContent": "flex-end" if user == "human" else "flex-start",
|
102 |
+
"margin": "20px 0px 10px 0px"
|
103 |
+
}
|
104 |
+
},
|
105 |
+
html.div(
|
106 |
+
{
|
107 |
+
"style": {
|
108 |
+
"maxWidth": "50%",
|
109 |
+
"padding": "0px 15px 0px 10px",
|
110 |
+
"borderRadius": "15px",
|
111 |
+
"backgroundColor": "#E8DEF8" if user == "human" else "#ECE6F0",
|
112 |
+
"color": "#000000",
|
113 |
+
}
|
114 |
+
},
|
115 |
+
MarkdownRenderer(message)
|
116 |
+
)
|
117 |
+
)
|
118 |
+
|
119 |
+
@component
|
120 |
+
def Logs(messages, log_entries, show_logs, set_show_logs, show_logs_button):
|
121 |
+
if (len(messages) > 0) and (len(log_entries) > 0) and (messages[-1]["message"] != wait_message) and (show_logs_button):
|
122 |
+
if not show_logs:
|
123 |
+
return html.div(
|
124 |
+
{
|
125 |
+
"style": {
|
126 |
+
"display": "flex",
|
127 |
+
"transform": "translateX(75%)",
|
128 |
+
"width": "20%",
|
129 |
+
"margin": "0px",
|
130 |
+
}
|
131 |
+
},
|
132 |
+
html.button(
|
133 |
+
{
|
134 |
+
"style": {
|
135 |
+
"position": "flex",
|
136 |
+
"background": "none",
|
137 |
+
"color": "#757575",
|
138 |
+
"border": "none",
|
139 |
+
"cursor": "pointer",
|
140 |
+
"fontFamily": "Arial",
|
141 |
+
"fontSize": "14px",
|
142 |
+
},
|
143 |
+
"type": "button",
|
144 |
+
"onClick": lambda _: set_show_logs(True)
|
145 |
+
},
|
146 |
+
"Show Logs"
|
147 |
+
)
|
148 |
+
)
|
149 |
+
else:
|
150 |
+
return html.div(
|
151 |
+
{
|
152 |
+
"style": {
|
153 |
+
"display": "flex",
|
154 |
+
"transform": "translateX(20%)",
|
155 |
+
"border": "2px solid #e2dfdf",
|
156 |
+
"borderRadius": "10px",
|
157 |
+
"width": "75%",
|
158 |
+
}
|
159 |
+
},
|
160 |
+
html.div(
|
161 |
+
[
|
162 |
+
html.p(
|
163 |
+
{
|
164 |
+
"style": {
|
165 |
+
"fontSize": "14px",
|
166 |
+
"marginLeft": "10px",
|
167 |
+
}
|
168 |
+
},
|
169 |
+
entry
|
170 |
+
) for entry in log_entries
|
171 |
+
],
|
172 |
+
html.button(
|
173 |
+
{
|
174 |
+
"style": {
|
175 |
+
"position": "flex",
|
176 |
+
"background": "none",
|
177 |
+
"color": "#757575",
|
178 |
+
"border": "none",
|
179 |
+
"cursor": "pointer",
|
180 |
+
"fontFamily": "Arial",
|
181 |
+
"fontSize": "14px",
|
182 |
+
"marginBottom": "10px",
|
183 |
+
"marginLeft": "5px",
|
184 |
+
},
|
185 |
+
"type": "button",
|
186 |
+
"onClick": lambda _: set_show_logs(False)
|
187 |
+
},
|
188 |
+
"Hide Logs"
|
189 |
+
)
|
190 |
+
)
|
191 |
+
)
|
192 |
+
|
193 |
+
return None
|
194 |
+
|
195 |
+
@component
|
196 |
+
def ChatUI(messages, first_turn, examples, send_example, log_entries, show_logs, set_show_logs, show_logs_button, collapsed):
|
197 |
+
|
198 |
+
def render_chat_content():
|
199 |
+
if first_turn:
|
200 |
+
return ExamplePrompts(examples, send_example, first_turn)
|
201 |
+
else:
|
202 |
+
return [ChatMessage(msg["user"], msg["message"]) for msg in messages]
|
203 |
+
|
204 |
+
return html.div(
|
205 |
+
{
|
206 |
+
"style": {
|
207 |
+
"display": "flex",
|
208 |
+
"flexDirection": "column",
|
209 |
+
"padding": "10px",
|
210 |
+
"backgroundColor": "#F4F1F4",
|
211 |
+
"overflowY": "auto",
|
212 |
+
"height": f"calc(100vh - {265 if collapsed else 335}px)",
|
213 |
+
"marginBottom": "15px",
|
214 |
+
"paddingBottom": "15px",
|
215 |
+
},
|
216 |
+
},
|
217 |
+
render_chat_content(),
|
218 |
+
Logs(messages, log_entries, show_logs, set_show_logs, show_logs_button)
|
219 |
+
)
|
footer.py
ADDED
@@ -0,0 +1,127 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from reactpy import component, html, svg, hooks
|
2 |
+
|
3 |
+
@component
|
4 |
+
def Footer(collapsed, set_collapsed):
|
5 |
+
|
6 |
+
# def toggle_footer(event=None):
|
7 |
+
# set_collapse(not collapsed)
|
8 |
+
|
9 |
+
if collapsed:
|
10 |
+
return html.footer(
|
11 |
+
{
|
12 |
+
"style": {
|
13 |
+
"backgroundColor": "#FFFFFF",
|
14 |
+
"position": "fixed",
|
15 |
+
"bottom": 0,
|
16 |
+
"width": "100%",
|
17 |
+
"height": "50px",
|
18 |
+
}
|
19 |
+
},
|
20 |
+
html.button(
|
21 |
+
{
|
22 |
+
"style": {
|
23 |
+
"background": "none",
|
24 |
+
"border": "none",
|
25 |
+
"color": "#757575",
|
26 |
+
"cursor": "pointer",
|
27 |
+
"position": "absolute",
|
28 |
+
"bottom": "5px",
|
29 |
+
"right": "10px",
|
30 |
+
},
|
31 |
+
"type": "button",
|
32 |
+
"on_click": lambda _: set_collapsed(False)
|
33 |
+
# "on_click": toggle_footer,
|
34 |
+
},
|
35 |
+
svg.svg(
|
36 |
+
{
|
37 |
+
"xmlns": "http://www.w3.org/2000/svg",
|
38 |
+
"width": "24",
|
39 |
+
"height": "24",
|
40 |
+
"fill": "none",
|
41 |
+
"stroke": "currentColor",
|
42 |
+
"stroke-linecap": "round",
|
43 |
+
"stroke-linejoin": "round",
|
44 |
+
"stroke-width": "3",
|
45 |
+
"viewBox": "0 0 24 24",
|
46 |
+
},
|
47 |
+
svg.path({"d": "M19 14l-7-7-7 7"})
|
48 |
+
)
|
49 |
+
)
|
50 |
+
)
|
51 |
+
else:
|
52 |
+
return html.footer(
|
53 |
+
{
|
54 |
+
"style": {
|
55 |
+
"backgroundColor": "#FFFFFF",
|
56 |
+
"position": "fixed",
|
57 |
+
"bottom": 0,
|
58 |
+
"width": "100%",
|
59 |
+
}
|
60 |
+
},
|
61 |
+
html.div(
|
62 |
+
{
|
63 |
+
"style": {
|
64 |
+
"backgroundColor": "#FFFFFF",
|
65 |
+
"padding": "0px 20px 0px 50px",
|
66 |
+
"position": "relative",
|
67 |
+
"display": "block",
|
68 |
+
}
|
69 |
+
},
|
70 |
+
html.button(
|
71 |
+
{
|
72 |
+
"style": {
|
73 |
+
"position": "absolute",
|
74 |
+
"right": "10px",
|
75 |
+
"background": "none",
|
76 |
+
"border": "none",
|
77 |
+
"color": "#757575",
|
78 |
+
"cursor": "pointer",
|
79 |
+
},
|
80 |
+
"type": "button",
|
81 |
+
"on_click": lambda _: set_collapsed(True)
|
82 |
+
# "on_click": toggle_footer,
|
83 |
+
},
|
84 |
+
svg.svg(
|
85 |
+
{
|
86 |
+
"xmlns": "http://www.w3.org/2000/svg",
|
87 |
+
"width": "24",
|
88 |
+
"height": "24",
|
89 |
+
"fill": "none",
|
90 |
+
"stroke": "currentColor",
|
91 |
+
"stroke-linecap": "round",
|
92 |
+
"stroke-linejoin": "round",
|
93 |
+
"stroke-width": "3",
|
94 |
+
"viewBox": "0 0 24 24",
|
95 |
+
},
|
96 |
+
svg.path({"d": "M18 6L6 18"}),
|
97 |
+
svg.path({"d": "M6 6l12 12"})
|
98 |
+
)
|
99 |
+
),
|
100 |
+
html.p(
|
101 |
+
{
|
102 |
+
"style": {
|
103 |
+
"fontSize": "20px",
|
104 |
+
"color": "#4b4851"
|
105 |
+
}
|
106 |
+
},
|
107 |
+
"How this works?",
|
108 |
+
),
|
109 |
+
html.p(
|
110 |
+
{
|
111 |
+
"style": {
|
112 |
+
"color": "#757575",
|
113 |
+
}
|
114 |
+
},
|
115 |
+
"This app was built with ",
|
116 |
+
html.a(
|
117 |
+
{
|
118 |
+
"href": "https://vectara.com/",
|
119 |
+
"target": "_blank",
|
120 |
+
},
|
121 |
+
"Vectara",
|
122 |
+
),
|
123 |
+
html.br(),
|
124 |
+
"It demonstrates the use of Agentic-RAG functionality with Vectara",
|
125 |
+
)
|
126 |
+
)
|
127 |
+
)
|
header.py
ADDED
@@ -0,0 +1,152 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from reactpy import component, html, svg, hooks
|
2 |
+
|
3 |
+
@component
|
4 |
+
def Header(demo_name: str, short_description: str, extra_info: str, start_over):
|
5 |
+
more_info, set_more_info = hooks.use_state(False)
|
6 |
+
|
7 |
+
def toggle_header(event=None):
|
8 |
+
set_more_info(not more_info)
|
9 |
+
|
10 |
+
return html.header(
|
11 |
+
{
|
12 |
+
"style": {
|
13 |
+
"backgroundColor": "#FFFFFF",
|
14 |
+
"display": "flex",
|
15 |
+
"justifyContent": "space-between",
|
16 |
+
"alignItems": "center",
|
17 |
+
}
|
18 |
+
},
|
19 |
+
html.div(
|
20 |
+
{
|
21 |
+
"style": {
|
22 |
+
"display": "flex",
|
23 |
+
"alignItems": "center",
|
24 |
+
"flex": 2,
|
25 |
+
"textAlign": "left",
|
26 |
+
"padding": "10px",
|
27 |
+
}
|
28 |
+
},
|
29 |
+
html.img(
|
30 |
+
{
|
31 |
+
"src": "https://avatars.githubusercontent.com/u/108304503?s=200&v=4",
|
32 |
+
"style": {
|
33 |
+
"height": "30px",
|
34 |
+
"marginRight": "15px",
|
35 |
+
"marginLeft": "5px",
|
36 |
+
"transform": "translateY(-2px)",
|
37 |
+
}
|
38 |
+
}
|
39 |
+
),
|
40 |
+
html.p(
|
41 |
+
{
|
42 |
+
"style": {
|
43 |
+
"fontSize": "25px",
|
44 |
+
"fontFamily": "Georgia, 'Times New Roman', Times, serif",
|
45 |
+
}
|
46 |
+
},
|
47 |
+
f"{demo_name}"
|
48 |
+
),
|
49 |
+
),
|
50 |
+
html.div(
|
51 |
+
{
|
52 |
+
"style": {
|
53 |
+
"flex": 5,
|
54 |
+
"textAlign": "center",
|
55 |
+
"padding": "10px 0px 15px 0px",
|
56 |
+
"fontFamily": "Lato",
|
57 |
+
"position": "relative",
|
58 |
+
}
|
59 |
+
},
|
60 |
+
html.h3(f"Welcome to the {demo_name} Demo"),
|
61 |
+
html.p(
|
62 |
+
short_description,
|
63 |
+
html.button(
|
64 |
+
{
|
65 |
+
"style": {
|
66 |
+
"display": "inline" if not more_info else "none",
|
67 |
+
"backgroundColor": "#FFFFFF",
|
68 |
+
"color": "#757575",
|
69 |
+
"fontSize": "13px",
|
70 |
+
"cursor": "pointer",
|
71 |
+
"border": "none",
|
72 |
+
"padding": "0px 0px 0px 5px",
|
73 |
+
},
|
74 |
+
"type": "button",
|
75 |
+
"onClick": toggle_header,
|
76 |
+
},
|
77 |
+
html.u(
|
78 |
+
{
|
79 |
+
"style": {
|
80 |
+
"flex": 2,
|
81 |
+
"textAlign": "right",
|
82 |
+
"padding": "10px",
|
83 |
+
}
|
84 |
+
},
|
85 |
+
"Learn More"
|
86 |
+
)
|
87 |
+
),
|
88 |
+
f" {extra_info}" if more_info else ""
|
89 |
+
),
|
90 |
+
html.button(
|
91 |
+
{
|
92 |
+
"style": {
|
93 |
+
"display": "block" if more_info else "none",
|
94 |
+
"background": "none",
|
95 |
+
"border": "none",
|
96 |
+
"color": "#757575",
|
97 |
+
"cursor": "pointer",
|
98 |
+
"position": "absolute",
|
99 |
+
"left": "50%",
|
100 |
+
"transform": "translateX(-50%)",
|
101 |
+
"bottom": "1px",
|
102 |
+
},
|
103 |
+
"type": "button",
|
104 |
+
"on_click": toggle_header,
|
105 |
+
},
|
106 |
+
svg.svg(
|
107 |
+
{
|
108 |
+
"width": "20",
|
109 |
+
"height": "20",
|
110 |
+
"viewBox": "0 0 20 20",
|
111 |
+
"fill": "none",
|
112 |
+
"stroke": "black",
|
113 |
+
"strokeWidth": "2",
|
114 |
+
"strokeLinecap": "round",
|
115 |
+
"strokeLinejoin": "round",
|
116 |
+
},
|
117 |
+
svg.path(
|
118 |
+
{
|
119 |
+
"d": "M12 19V5M5 12l7-7 7 7",
|
120 |
+
"stroke": "currentColor",
|
121 |
+
}
|
122 |
+
)
|
123 |
+
)
|
124 |
+
)
|
125 |
+
),
|
126 |
+
html.div(
|
127 |
+
{
|
128 |
+
"style": {
|
129 |
+
"flex": 2,
|
130 |
+
"textAlign": "right",
|
131 |
+
"padding": "10px",
|
132 |
+
}
|
133 |
+
},
|
134 |
+
html.button(
|
135 |
+
{
|
136 |
+
"style": {
|
137 |
+
"backgroundColor": "#FFFFFF",
|
138 |
+
"color": "#757575",
|
139 |
+
"fontSize": "14px",
|
140 |
+
"cursor": "pointer",
|
141 |
+
"border": "1px solid #e2dfdf",
|
142 |
+
"borderRadius": "5px",
|
143 |
+
"padding": "6px 20px",
|
144 |
+
"marginRight": "15px",
|
145 |
+
},
|
146 |
+
"type": "button",
|
147 |
+
"onClick": start_over,
|
148 |
+
},
|
149 |
+
"Start Over?"
|
150 |
+
)
|
151 |
+
)
|
152 |
+
)
|
requirements.txt
CHANGED
@@ -5,6 +5,6 @@ python-dotenv==1.0.1
|
|
5 |
uuid==1.30
|
6 |
langdetect==1.0.9
|
7 |
langcodes==3.4.0
|
8 |
-
vectara-agentic==0.1.
|
9 |
markdown-it-py==3.0.0
|
10 |
mdit-py-plugins==0.4.1
|
|
|
5 |
uuid==1.30
|
6 |
langdetect==1.0.9
|
7 |
langcodes==3.4.0
|
8 |
+
vectara-agentic==0.1.7
|
9 |
markdown-it-py==3.0.0
|
10 |
mdit-py-plugins==0.4.1
|
utils.py
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
|
3 |
+
wait_message = "Please wait. Assistant at work..."
|