3030
3131class GradioApp (A2AClientMixin ):
3232 _APP_LOGO_PATH = "docs/images/logo.svg"
33+ # https://www.svgrepo.com/svg/529291/user-rounded
34+ _ICON_USER_AVATAR = "docs/images/icon-user-avatar.svg"
35+ # https://www.svgrepo.com/svg/368593/chatbot
36+ _ICON_BOT_AVATAR = "docs/images/icon-bot-avatar.svg"
37+ # https://www.svgrepo.com/svg/496582/send-2
38+ _ICON_BTN_SEND = "docs/images/icon-btn-send.svg"
39+ # https://www.svgrepo.com/svg/499905/delete
40+ _ICON_BTN_DELETE = "docs/images/icon-btn-delete.svg"
3341
3442 _MD_EU_AI_ACT_TRANSPARENCY = """
3543 **European Union AI Act Transparency notice**: By using this app, you are interacting with an artificial intelligence (AI) system.
@@ -45,39 +53,40 @@ def __init__(self):
4553 f"http://{ self ._mhqa_a2a_uvicorn_host } :{ self ._mhqa_a2a_uvicorn_port } "
4654 )
4755
48- def convert_echo_response_to_chat_messages (self , response : MHQAResponse ):
56+ def convert_mhqa_response_to_chat_messages (self , response : MHQAResponse ):
4957 chat_messages = []
5058 chat_messages .append (
5159 gr .ChatMessage (
5260 role = "user" ,
5361 content = response .user_input ,
5462 )
5563 )
56- message_id = (
57- str (uuid4 ())
58- if response .tool_invocations and len (response .tool_invocations ) > 0
59- else None
60- )
61- chat_messages .append (
62- gr .ChatMessage (
63- role = "assistant" ,
64- content = response .agent_output ,
65- metadata = {"id" : message_id } if message_id else None ,
64+ if response .agent_output :
65+ message_id = (
66+ str (uuid4 ())
67+ if response .tool_invocations and len (response .tool_invocations ) > 0
68+ else None
6669 )
67- )
68-
69- for tool_invocation in response .tool_invocations :
7070 chat_messages .append (
7171 gr .ChatMessage (
7272 role = "assistant" ,
73- content = f"Inputs: { tool_invocation .input } \n Outputs: { tool_invocation .output } \n Metadata: { tool_invocation .metadata } " ,
74- metadata = {
75- "parent_id" : message_id ,
76- "title" : f"Tool used: { tool_invocation .name } " ,
77- },
73+ content = response .agent_output ,
74+ metadata = {"id" : message_id } if message_id else None ,
7875 )
7976 )
8077
78+ for tool_invocation in response .tool_invocations :
79+ chat_messages .append (
80+ gr .ChatMessage (
81+ role = "assistant" ,
82+ content = f"Inputs: { tool_invocation .input } \n Outputs: { tool_invocation .output } \n Metadata: { tool_invocation .metadata } " ,
83+ metadata = {
84+ "parent_id" : message_id ,
85+ "title" : f"Tool used: { tool_invocation .name } " ,
86+ },
87+ )
88+ )
89+
8190 return chat_messages
8291
8392 def component_main_content (self ):
@@ -111,9 +120,10 @@ def component_main_content(self):
111120 )
112121 state_selected_chat_id = gr .State (value = None )
113122 btn_chat_delete = gr .Button (
114- "Delete chat" ,
123+ "Delete selected chat" ,
115124 size = "sm" ,
116125 variant = "stop" ,
126+ icon = GradioApp ._ICON_BTN_DELETE ,
117127 interactive = False ,
118128 )
119129 gr .Markdown (GradioApp ._MD_EU_AI_ACT_TRANSPARENCY )
@@ -125,17 +135,23 @@ def component_main_content(self):
125135 chatbot = gr .Chatbot (
126136 type = "messages" ,
127137 label = "Chat history (a new chat will be created if none if selected)" ,
138+ avatar_images = [
139+ GradioApp ._ICON_USER_AVATAR ,
140+ GradioApp ._ICON_BOT_AVATAR ,
141+ ],
128142 )
129143 with gr .Row (equal_height = True ):
130144 txt_input = gr .Textbox (
131145 scale = 3 ,
132146 lines = 4 ,
133147 label = "Your message" ,
134148 info = "Enter your non-trivial question to ask the AI agent." ,
135- placeholder = "Type a message and press Enter, or click the Send button." ,
149+ placeholder = "Type a message and press Shift+ Enter, or click the Send button." ,
136150 show_copy_button = False ,
137151 )
138- btn_echo = gr .Button ("Send" , scale = 1 )
152+ btn_send = gr .Button (
153+ "Send" , size = "lg" , icon = GradioApp ._ICON_BTN_SEND , scale = 1
154+ )
139155 with gr .Column ():
140156 gr .Examples (
141157 label = "Example of input messages" ,
@@ -198,7 +214,7 @@ async def refresh_chat_history_from_agent(chat_id: str) -> list:
198214 chat_history = []
199215 for past_message in validated_response :
200216 chat_history .extend (
201- self .convert_echo_response_to_chat_messages (past_message )
217+ self .convert_mhqa_response_to_chat_messages (past_message )
202218 )
203219 return chat_history
204220
@@ -311,7 +327,7 @@ async def btn_new_chat_clicked(
311327 yield browser_state_chat_histories , new_chat_id , None
312328
313329 @gr .on (
314- triggers = [btn_echo .click , txt_input .submit ],
330+ triggers = [btn_send .click , txt_input .submit ],
315331 inputs = [
316332 txt_input ,
317333 state_selected_chat_id ,
@@ -354,8 +370,17 @@ async def btn_echo_clicked(
354370 ),
355371 )
356372
373+ chat_history .extend (
374+ self .convert_mhqa_response_to_chat_messages (
375+ MHQAResponse (
376+ thread_id = selected_chat_id , user_input = txt_input
377+ )
378+ )
379+ )
380+ last_added_messages = 1
381+
357382 yield (
358- gr . update ( interactive = False ) ,
383+ None ,
359384 browser_state_chat_histories ,
360385 selected_chat_id ,
361386 chat_history ,
@@ -382,11 +407,15 @@ async def btn_echo_clicked(
382407 agent_response = MHQAResponse .model_validate_json (
383408 full_message_content
384409 )
385- chat_history . extend (
386- self .convert_echo_response_to_chat_messages (
410+ new_messages = (
411+ self .convert_mhqa_response_to_chat_messages (
387412 agent_response
388413 )
389414 )
415+ if last_added_messages > 0 :
416+ del chat_history [- last_added_messages :]
417+ chat_history .extend (new_messages )
418+ last_added_messages = len (new_messages )
390419
391420 browser_state_chat_histories [selected_chat_id ] = (
392421 chat_history
@@ -396,7 +425,7 @@ async def btn_echo_clicked(
396425 f"No input message was provided for chat ID { selected_chat_id } ."
397426 )
398427 yield (
399- gr . update ( value = "" , interactive = True ) ,
428+ None ,
400429 browser_state_chat_histories ,
401430 selected_chat_id ,
402431 chat_history ,
@@ -414,7 +443,15 @@ async def btn_echo_clicked(
414443
415444 def construct_ui (self ):
416445 with gr .Blocks (fill_width = True , fill_height = True ) as self .ui :
417- gr .set_static_paths (paths = [GradioApp ._APP_LOGO_PATH ])
446+ gr .set_static_paths (
447+ paths = [
448+ GradioApp ._APP_LOGO_PATH ,
449+ GradioApp ._ICON_USER_AVATAR ,
450+ GradioApp ._ICON_BOT_AVATAR ,
451+ GradioApp ._ICON_BTN_SEND ,
452+ GradioApp ._ICON_BTN_DELETE ,
453+ ]
454+ )
418455 self .component_main_content ()
419456
420457 return self .ui
0 commit comments