panda992 commited on
Commit
220b14b
Β·
1 Parent(s): 58512a3
Files changed (2) hide show
  1. README.md +40 -65
  2. app.py +24 -7
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. It uses a state-of-the-art, two-stage process to first understand a user's needs through conversation and then use powerful tools to find an evidence-based answer.
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
- - πŸ’¬ **Conversational & Stateful**: Instead of a simple Q&A, MediAgent engages in a multi-turn dialogue to gather necessary details, ensuring the final answer is relevant and comprehensive.
23
- - πŸ‘€ **Role-Based Adaptation**: The AI tailors its language and questions based on the selected user role: **Patient** (simple, empathetic language), **Doctor** (technical, concise), or **Health Worker** (procedural, clear).
24
- - πŸ› οΈ **Agentic Tool Use**: After gathering enough information, the agent actively chooses the best tool for your question from its specialized toolkit:
25
- - `search_pubmed`: For technical and clinical research.
26
- - `search_web`: For general health and symptom information.
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
- ## πŸ§ͺ Example Conversation (Patient Role)
36
-
37
- > **You:** I have a headache.
38
- >
39
- > **MediAgent AI:** I'm sorry to hear that. How long have you had this headache?
40
- >
41
- > **You:** For about two days, and it's pretty severe.
42
- >
43
- > **MediAgent AI:** To confirm, you are experiencing a **severe** headache that has lasted for **about two days**. Is that correct?
44
- >
45
- > **You:** Yes.
46
- >
47
- > **MediAgent AI:** (Now using its tools) Based on information from reputable medical sources, a severe headache lasting two days can be associated with several conditions... It's important to monitor for other symptoms such as... [Provides detailed, sourced information].
48
- >
49
- > ---
50
- > _Disclaimer: This is an AI-generated answer and not a substitute for professional medical advice..._
 
 
 
51
 
52
  ---
53
 
54
- ## πŸ› οΈ Architecture Overview
55
-
56
- MediAgent AI uses an advanced two-stage architecture that separates conversational management from tool-based reasoning.
57
-
58
- ```plaintext
59
- User Input + Role + State
60
- β”‚
61
- β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
62
- β”‚ Gradio Chat UI on HF Spaces β”‚
63
- β”‚ (Maintains Conversation State) β”‚
64
- β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
65
- β”‚ (API Call to Modal with full context)
66
- β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β†“β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
67
- β”‚ Modal Serverless Backend β”‚
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", "health_worker"],
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(