Spaces:
Running
Running
Update
Browse files
README.md
CHANGED
@@ -13,79 +13,54 @@ secrets:
|
|
13 |
|
14 |
# 𧬠MediAgent AI: Your Conversational Health Navigator
|
15 |
|
16 |
-
**MediAgent AI** is a sophisticated, conversational health assistant designed to provide reliable, sourced, and easy-to-understand answers to a wide range of medical questions.
|
17 |
|
18 |
This application is built with a decoupled architecture: a modern Gradio UI hosted on Hugging Face Spaces and a powerful, serverless GPU backend running on [Modal](https://modal.com).
|
19 |
|
20 |
## π Key Features
|
21 |
|
22 |
-
-
|
23 |
-
-
|
24 |
-
-
|
25 |
-
|
26 |
-
|
27 |
-
- `check_drug_interactions`: To check for interactions between multiple drugs via the openFDA API.
|
28 |
-
- `check_drug_side_effects`: To find adverse reactions for a specific drug via the openFDA API.
|
29 |
-
- π‘οΈ **Advanced Safety Layers**: Features critical safety prompts that instruct the AI on how to handle potential emergencies and always provide disclaimers.
|
30 |
-
- π§ **Two-Stage Reasoning Engine**: Powered by **`google/gemma-2-2b-it`** and LlamaIndex, the system first uses a `StructuredOutputManager` to gather information conversationally, then deploys a `ReActAgent` to think, act, and observe in a loop to find the final answer.
|
31 |
-
- β¨ **Modern Chat UI**: A clean, responsive chat interface built with [Gradio](https://www.gradio.app) that supports natural, multi-turn conversations.
|
32 |
|
33 |
---
|
34 |
|
35 |
-
## π§ͺ
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
|
|
|
|
|
|
51 |
|
52 |
---
|
53 |
|
54 |
-
##
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
β
|
70 |
-
1. π‘οΈ Safety & Pre-processing
|
71 |
-
β
|
72 |
-
βββββββββββΊ 2. π£οΈ StructuredOutputManager (Conversational Loop)
|
73 |
-
β a. Is task ready? (e.g., has user confirmed summary?)
|
74 |
-
β b. If NO: Use LLM to generate a clarifying question or summary.
|
75 |
-
β c. Send response back to UI and wait for next user input.
|
76 |
-
β |
|
77 |
-
βββββββββββββββββββββββββββββββββ
|
78 |
-
β (If YES, proceed to next stage)
|
79 |
-
β
|
80 |
-
3. π€ LlamaIndex ReAct Agent (Tool-Using Loop)
|
81 |
-
a. π€ Thought: "User confirmed headache for 2 days. I should use search_web."
|
82 |
-
b. π¬ Action: Executes tool (`search_web('severe headache 2 days')`)
|
83 |
-
c. π Observation: Receives data back from the tool (e.g., search results)
|
84 |
-
(Loop continues until the agent has a complete answer)
|
85 |
-
β
|
86 |
-
4. π Final Answer Synthesis
|
87 |
-
(Agent composes a complete answer based on tool output)
|
88 |
-
β
|
89 |
-
βββββββββββββββββββββββββββββββ
|
90 |
-
β Final Answer Displayed in UI β
|
91 |
-
βββββββββββββββββββββββββββββββ
|
|
|
13 |
|
14 |
# 𧬠MediAgent AI: Your Conversational Health Navigator
|
15 |
|
16 |
+
**MediAgent AI** is a sophisticated, conversational health assistant designed to provide reliable, sourced, and easy-to-understand answers to a wide range of medical questions.
|
17 |
|
18 |
This application is built with a decoupled architecture: a modern Gradio UI hosted on Hugging Face Spaces and a powerful, serverless GPU backend running on [Modal](https://modal.com).
|
19 |
|
20 |
## π Key Features
|
21 |
|
22 |
+
- π **Multilingual Support**: Automatically detects and responds in English, French, Spanish, and Hindi.
|
23 |
+
- π¬ **Conversational & Stateful**: Remembers the chat history to understand follow-up questions.
|
24 |
+
- π€ **Role-Based Adaptation**: Tailors its language and the tools it uses based on whether you select **Patient** or **Doctor**.
|
25 |
+
- π οΈ **Multi-Tool Capability**: Uses a powerful toolkit to search the web, PubMed, clinical trials, and drug databases to find the best answer.
|
26 |
+
- π‘οΈ **Safety First**: Includes a critical safety layer to detect potential emergencies and provide appropriate disclaimers.
|
|
|
|
|
|
|
|
|
|
|
27 |
|
28 |
---
|
29 |
|
30 |
+
## π§ͺ Try It In Your Language!
|
31 |
+
|
32 |
+
Copy and paste one of the examples below to test the AI's multilingual capabilities.
|
33 |
+
|
34 |
+
### English
|
35 |
+
|
36 |
+
What are the most common side effects of metformin?
|
37 |
+
|
38 |
+
### Spanish
|
39 |
+
|
40 |
+
CuΓ‘les son los sΓntomas de la diabetes tipo 2?
|
41 |
+
|
42 |
+
### French
|
43 |
+
|
44 |
+
Comment savoir si j'ai la grippe ou un simple rhume ?
|
45 |
+
|
46 |
+
### Hindi
|
47 |
+
|
48 |
+
ΰ€ΰ€ΰ₯ΰ€ ΰ€°ΰ€ΰ₯ΰ€€ΰ€ΰ€Ύΰ€ͺ ΰ€ΰ₯ ΰ€²ΰ€Ώΰ€ ΰ€ΰ€°ΰ₯ΰ€²ΰ₯ ΰ€ΰ€ͺΰ€ΰ€Ύΰ€° ΰ€ΰ₯ΰ€―ΰ€Ύ ΰ€Ήΰ₯ΰ€?
|
49 |
|
50 |
---
|
51 |
|
52 |
+
## π§ββοΈ See The Role-Based Difference
|
53 |
+
|
54 |
+
Select a role in the UI and use a matching prompt below to see how the AI adapts its response.
|
55 |
+
|
56 |
+
### For the Patient Role
|
57 |
+
|
58 |
+
Select **patient** and ask a general health question. The AI will use web search to provide an easy-to-understand overview.
|
59 |
+
|
60 |
+
What are the most common side effects I should watch out for with lisinopril?
|
61 |
+
|
62 |
+
### For the Doctor Role
|
63 |
+
|
64 |
+
Select **doctor** and ask a technical, multi-part question. The AI will use specialized tools like PubMed and ClinicalTrials.gov to provide a detailed, sourced answer.
|
65 |
+
|
66 |
+
My patient with Crohn's is on methotrexate and we are considering adding infliximab. I need the latest PubMed literature on efficacy, a check for interactions between the two drugs, and a list of ongoing clinical trials for novel biologics in IBD.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
app.py
CHANGED
@@ -99,13 +99,27 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"), cs
|
|
99 |
</div>
|
100 |
""")
|
101 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
102 |
with gr.Group(elem_id="role-selector"):
|
103 |
user_role = gr.Radio(
|
104 |
-
["patient", "doctor"
|
105 |
label="π€ Select Your Role",
|
106 |
value="patient",
|
107 |
-
info="The AI will adapt its communication style based on your role."
|
|
|
|
|
108 |
)
|
|
|
109 |
|
110 |
chatbot = gr.Chatbot(
|
111 |
label="Conversation",
|
@@ -123,6 +137,7 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"), cs
|
|
123 |
container=False,
|
124 |
)
|
125 |
submit_btn = gr.Button("Send", variant="primary", scale=1, min_width=150, elem_id="send-button")
|
|
|
126 |
|
127 |
with gr.Row():
|
128 |
clear_btn = gr.ClearButton(
|
@@ -131,24 +146,26 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"), cs
|
|
131 |
)
|
132 |
|
133 |
def handle_user_turn(user_input, chat_history, user_role_selection, current_state, sid):
|
|
|
|
|
|
|
|
|
134 |
if not user_input.strip():
|
|
|
135 |
yield {chatbot: chat_history, conversation_state: current_state, user_textbox: user_input}
|
136 |
return
|
137 |
-
|
138 |
user_message_html = f"<div class='message user'>{user_input}</div>"
|
139 |
chat_history.append((user_message_html, None))
|
140 |
yield {chatbot: chat_history, user_textbox: ""}
|
141 |
-
|
142 |
if not MODAL_BACKEND_URL:
|
143 |
error_message = "### β Configuration Error\n**Reason**: `MODAL_BACKEND_URL` environment variable is not set."
|
144 |
error_message_html = f"<div class='message bot'>{error_message}</div>"
|
145 |
chat_history[-1] = (user_message_html, error_message_html)
|
|
|
146 |
yield {chatbot: chat_history}
|
147 |
return
|
148 |
-
|
149 |
headers = {"Content-Type": "application/json"}
|
150 |
payload = {"user_input": user_input, "session_id": sid, "role": user_role_selection}
|
151 |
-
|
152 |
try:
|
153 |
response = requests.post(MODAL_BACKEND_URL, headers=headers, json=payload, timeout=300)
|
154 |
response.raise_for_status()
|
@@ -156,9 +173,9 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"), cs
|
|
156 |
bot_response_text = backend_response.get("final_markdown", "Sorry, I received an empty response.")
|
157 |
except requests.exceptions.RequestException as e:
|
158 |
bot_response_text = f"### β Network Error\n**Reason**: Could not connect to the backend.\n**Details**: {str(e)}"
|
159 |
-
|
160 |
bot_message_html = f"<div class='message bot'>{bot_response_text}</div>"
|
161 |
chat_history[-1] = (user_message_html, bot_message_html)
|
|
|
162 |
yield {chatbot: chat_history, conversation_state: current_state}
|
163 |
|
164 |
submit_btn.click(
|
|
|
99 |
</div>
|
100 |
""")
|
101 |
|
102 |
+
with gr.Row():
|
103 |
+
gr.Markdown("""
|
104 |
+
<b>π‘ Example Prompts:</b>
|
105 |
+
<ul>
|
106 |
+
<li><button onclick=\"document.querySelector('textarea').value='What are the most common side effects of metformin?';\">English: What are the most common side effects of metformin?</button></li>
|
107 |
+
<li><button onclick=\"document.querySelector('textarea').value='CuΓ‘les son los sΓntomas de la diabetes tipo 2?';\">Spanish: CuΓ‘les son los sΓntomas de la diabetes tipo 2?</button></li>
|
108 |
+
<li><button onclick=\"document.querySelector('textarea').value='Comment savoir si j\'ai la grippe ou un simple rhume ?';\">French: Comment savoir si j'ai la grippe ou un simple rhume ?</button></li>
|
109 |
+
<li><button onclick=\"document.querySelector('textarea').value='ΰ€ΰ€ΰ₯ΰ€ ΰ€°ΰ€ΰ₯ΰ€€ΰ€ΰ€Ύΰ€ͺ ΰ€ΰ₯ ΰ€²ΰ€Ώΰ€ ΰ€ΰ€°ΰ₯ΰ€²ΰ₯ ΰ€ΰ€ͺΰ€ΰ€Ύΰ€° ΰ€ΰ₯ΰ€―ΰ€Ύ ΰ€Ήΰ₯ΰ€?';\">Hindi: ΰ€ΰ€ΰ₯ΰ€ ΰ€°ΰ€ΰ₯ΰ€€ΰ€ΰ€Ύΰ€ͺ ΰ€ΰ₯ ΰ€²ΰ€Ώΰ€ ΰ€ΰ€°ΰ₯ΰ€²ΰ₯ ΰ€ΰ€ͺΰ€ΰ€Ύΰ€° ΰ€ΰ₯ΰ€―ΰ€Ύ ΰ€Ήΰ₯ΰ€?</button></li>
|
110 |
+
</ul>
|
111 |
+
""")
|
112 |
+
|
113 |
with gr.Group(elem_id="role-selector"):
|
114 |
user_role = gr.Radio(
|
115 |
+
["patient", "doctor"],
|
116 |
label="π€ Select Your Role",
|
117 |
value="patient",
|
118 |
+
info="The AI will adapt its tools and communication style based on your role.",
|
119 |
+
elem_id="user-role-radio",
|
120 |
+
show_label=True
|
121 |
)
|
122 |
+
gr.Markdown("<span title='Choose your role to tailor the AI response. Patients get simple answers, doctors get technical details.' style='cursor: help;'>βΉοΈ</span>")
|
123 |
|
124 |
chatbot = gr.Chatbot(
|
125 |
label="Conversation",
|
|
|
137 |
container=False,
|
138 |
)
|
139 |
submit_btn = gr.Button("Send", variant="primary", scale=1, min_width=150, elem_id="send-button")
|
140 |
+
loading_spinner = gr.Markdown("<span id='loading-spinner' style='display:none;'>β³ <em>Thinking...</em></span>")
|
141 |
|
142 |
with gr.Row():
|
143 |
clear_btn = gr.ClearButton(
|
|
|
146 |
)
|
147 |
|
148 |
def handle_user_turn(user_input, chat_history, user_role_selection, current_state, sid):
|
149 |
+
import time
|
150 |
+
from gradio import processing
|
151 |
+
# Show spinner
|
152 |
+
gr.update(elem_id="loading-spinner", value="<span id='loading-spinner' style='display:block;'>β³ <em>Thinking...</em></span>")
|
153 |
if not user_input.strip():
|
154 |
+
gr.update(elem_id="loading-spinner", value="<span id='loading-spinner' style='display:none;'></span>")
|
155 |
yield {chatbot: chat_history, conversation_state: current_state, user_textbox: user_input}
|
156 |
return
|
|
|
157 |
user_message_html = f"<div class='message user'>{user_input}</div>"
|
158 |
chat_history.append((user_message_html, None))
|
159 |
yield {chatbot: chat_history, user_textbox: ""}
|
|
|
160 |
if not MODAL_BACKEND_URL:
|
161 |
error_message = "### β Configuration Error\n**Reason**: `MODAL_BACKEND_URL` environment variable is not set."
|
162 |
error_message_html = f"<div class='message bot'>{error_message}</div>"
|
163 |
chat_history[-1] = (user_message_html, error_message_html)
|
164 |
+
gr.update(elem_id="loading-spinner", value="<span id='loading-spinner' style='display:none;'></span>")
|
165 |
yield {chatbot: chat_history}
|
166 |
return
|
|
|
167 |
headers = {"Content-Type": "application/json"}
|
168 |
payload = {"user_input": user_input, "session_id": sid, "role": user_role_selection}
|
|
|
169 |
try:
|
170 |
response = requests.post(MODAL_BACKEND_URL, headers=headers, json=payload, timeout=300)
|
171 |
response.raise_for_status()
|
|
|
173 |
bot_response_text = backend_response.get("final_markdown", "Sorry, I received an empty response.")
|
174 |
except requests.exceptions.RequestException as e:
|
175 |
bot_response_text = f"### β Network Error\n**Reason**: Could not connect to the backend.\n**Details**: {str(e)}"
|
|
|
176 |
bot_message_html = f"<div class='message bot'>{bot_response_text}</div>"
|
177 |
chat_history[-1] = (user_message_html, bot_message_html)
|
178 |
+
gr.update(elem_id="loading-spinner", value="<span id='loading-spinner' style='display:none;'></span>")
|
179 |
yield {chatbot: chat_history, conversation_state: current_state}
|
180 |
|
181 |
submit_btn.click(
|