panda992 commited on
Commit
2758a36
·
1 Parent(s): de43810
Files changed (2) hide show
  1. README.md +89 -156
  2. app.py +68 -63
README.md CHANGED
@@ -4,7 +4,7 @@ emoji: 🧬
4
  colorFrom: indigo
5
  colorTo: purple
6
  sdk: gradio
7
- sdk_version: 5.33.0
8
  app_file: app.py
9
  pinned: false
10
  secrets:
@@ -15,187 +15,120 @@ tags:
15
  - agent-demo-track
16
  ---
17
 
18
-
19
  # 🧬 MediAgent AI: Conversational Health Navigator & MCP Tool Server
20
 
21
- **MediAgent AI** is a sophisticated, conversational health assistant and a fully MCP-compliant tool server, built on Modal and Gradio. It provides reliable, sourced, and easy-to-understand answers to a wide range of medical questions. Whether you are a patient seeking simple explanations or a healthcare professional needing detailed research, MediAgent AI adapts to your needs — and can be used as a plug-and-play MCP tool in any agentic workflow!
22
 
23
- ---
 
 
 
 
 
 
 
 
 
 
24
 
25
- ## 🌟 Why MediAgent AI Stands Out
26
 
27
- - **Hybrid MCP Architecture:** One Modal backend, two endpoints—agent and MCP tool server—proving true MCP compliance with zero deployment overhead.
28
- - **Real Medical Value:** Multilingual, role-adaptive, and sources every answer.
29
- - **Plug-and-Play MCP Tool:** Instantly usable as a tool server by any MCP-compatible client.
30
- - **Production-Ready:** Robust error handling, citations, and safety layers.
31
 
32
  ---
33
 
34
- ## 🏛️ Architecture: A Hybrid "Single-Server MCP" Approach
35
-
36
- To meet the rapid development cycle of a hackathon, we've implemented a pragmatic and powerful **Hybrid Architecture**. Our single Modal application serves as **both the core Agent and its own MCP-compliant Tool Server**.
37
-
38
- <!-- You can add a diagram here if desired -->
39
 
40
- 1. **Agent Endpoint (`/process`)**: This private endpoint orchestrates the agent's "think-plan-act" loop.
41
- 2. **MCP Tool Endpoint (`/mcp_tool_endpoint`)**: This **public endpoint** makes our application a valid MCP Server. It accepts standardized tool calls and executes them, proving the system's compliance with MCP principles.
42
- 3. **Internal Execution**: For maximum speed and reliability during the hackathon, the agent calls its tools via a direct internal interface rather than a network call to itself.
43
-
44
- This hybrid model demonstrates a deep understanding of both ideal agent architectures and practical, robust deployment strategies. It is scalable, efficient, and fully aligned with the spirit of the MCP Hackathon.
45
-
46
- **Powered By:**
47
- * **Modal**: The perfect platform for this hybrid model, effortlessly hosting both the GPU-powered agent and the public-facing API endpoints within a single, scalable app.
48
- * **MistralAI**: Advanced open-weight LLMs for medical reasoning.
49
- * **LlamaIndex**: Flexible orchestration and retrieval for agentic workflows.
50
 
51
  ---
52
 
53
- ## 🚀 Key Features
54
-
55
- * 🌐 **Multilingual Support**: Communicate seamlessly! MediAgent AI automatically detects and responds in **English, Spanish, Hindi, and French**, making it accessible to a global audience.
56
- * 💬 **Conversational & Stateful**: Enjoy natural, ongoing conversations. The AI remembers the chat history to understand follow-up questions and maintain context throughout your dialogue.
57
- * 👤 **Role-Based Adaptation**: Get tailored information based on your needs.
58
- * **Patient Mode**: Provides simplified, easy-to-understand health advice and general information.
59
- * **Doctor Mode**: Delivers in-depth, technical insights, leveraging specialized medical databases for professionals.
60
- * 🛠️ **Comprehensive Tooling**: MediAgent AI utilizes a robust toolkit to provide accurate answers:
61
- * **General Web Search**: For broad health queries.
62
- * **PubMed Integration**: Accesses peer-reviewed medical literature for evidence-based information.
63
- * **Drug Information**: Provides details on:
64
- * **Drug Side Effects**: Find known side effects of medications.
65
- * **Drug Interactions**: Check for potential adverse interactions between multiple drugs.
66
- * **Official Drug Label Information**: Retrieve detailed FDA-approved prescribing information.
67
- * **Clinical Trials Search**: Discover ongoing or past clinical studies relevant to specific conditions or treatments.
68
- * 🛡️ **Safety First**: Your well-being is paramount. The AI includes a critical safety layer to detect potential medical emergencies and provides appropriate disclaimers, advising users to consult with healthcare professionals for diagnosis and treatment.
69
- * **🛠️ MCP Compliant Tool Server**: Our tools can be called externally. **You can test it right now:**
70
-
71
- > ⚠️ **Note:** The first call may take 30-60 seconds as the backend spins up. Subsequent calls are much faster.
72
-
73
- ```bash
74
- curl -X POST 'https://sunilpanda992--medi-agent-ai-final-backend-mediagentai-m-3f699b.modal.run' \
75
- --header 'Content-Type: application/json' \
76
- --data '{
77
- "tool_name": "check_drug_interactions",
78
- "tool_args": {
79
- "drugs": ["warfarin", "amiodarone"]
80
- }
81
- }'
82
- ```
83
-
84
- **More Example Tool Calls:**
85
-
86
- - **Drug Side Effects:**
87
- ```bash
88
- curl -X POST 'https://sunilpanda992--medi-agent-ai-final-backend-mediagentai-m-3f699b.modal.run' \
89
- --header 'Content-Type: application/json' \
90
- --data '{
91
- "tool_name": "check_drug_side_effects",
92
- "tool_args": {"drug": "metformin"}
93
- }'
94
- ```
95
- - **PubMed Search:**
96
- ```bash
97
- curl -X POST 'https://sunilpanda992--medi-agent-ai-final-backend-mediagentai-m-3f699b.modal.run' \
98
- --header 'Content-Type: application/json' \
99
- --data '{
100
- "tool_name": "search_pubmed",
101
- "tool_args": {"query": "COVID-19 vaccine efficacy", "max_results": 2}
102
- }'
103
- ```
104
- - **Clinical Trials:**
105
- ```bash
106
- curl -X POST 'https://sunilpanda992--medi-agent-ai-final-backend-mediagentai-m-3f699b.modal.run' \
107
- --header 'Content-Type: application/json' \
108
- --data '{
109
- "tool_name": "search_clinical_trials",
110
- "tool_args": {"query": "diabetes", "max_results": 1}
111
- }'
112
- ```
113
- - **Drug Interaction Warning:**
114
- ```bash
115
- curl -X POST 'https://sunilpanda992--medi-agent-ai-final-backend-mediagentai-m-3f699b.modal.run' \
116
- --header 'Content-Type: application/json' \
117
- --data '{
118
- "tool_name": "check_drug_interactions",
119
- "tool_args": {
120
- "drugs": ["aspirin", "ibuprofen"]
121
- }
122
- }'
123
- ```
124
- - **Comprehensive Drug Information:**
125
- ```bash
126
- curl -X POST 'https://sunilpanda992--medi-agent-ai-final-backend-mediagentai-m-3f699b.modal.run' \
127
- --header 'Content-Type: application/json' \
128
- --data '{
129
- "tool_name": "get_drug_info",
130
- "tool_args": {"drug": "atorvastatin"}
131
- }'
132
- ```
133
- - **Advanced PubMed Search:**
134
- ```bash
135
- curl -X POST 'https://sunilpanda992--medi-agent-ai-final-backend-mediagentai-m-3f699b.modal.run' \
136
- --header 'Content-Type: application/json' \
137
- --data '{
138
- "tool_name": "search_pubmed",
139
- "tool_args": {"query": "metformin AND cardiovascular outcomes", "max_results": 3}
140
- }'
141
- ```
142
- - **Clinical Trials with Filters:**
143
- ```bash
144
- curl -X POST 'https://sunilpanda992--medi-agent-ai-final-backend-mediagentai-m-3f699b.modal.run' \
145
- --header 'Content-Type: application/json' \
146
- --data '{
147
- "tool_name": "search_clinical_trials",
148
- "tool_args": {"query": "hypertension", "max_results": 2, "filters": {"status": "ongoing"}}
149
- }'
150
- ```
151
 
152
- ---
153
 
154
- ## 🔗 How to Use MediAgent AI as an MCP Tool
 
 
 
 
 
 
 
155
 
156
- - **From any MCP-compatible client** (e.g., Claude Desktop, Cursor, Tiny Agents, or another Gradio app), simply point to our `/mcp_tool_endpoint` and use the tool names and arguments as shown above.
157
- - **See our demo video for a live MCP integration!**
 
 
 
158
 
159
  ---
160
 
161
- ## 🧪 Try It Out! (Examples)
162
-
163
- Copy and paste one of the examples below into the chat interface to test MediAgent AI's capabilities. Remember to select the appropriate **"patient"** or **"doctor"** role in the UI for tailored responses.
164
 
165
- ### General Health Queries
166
 
167
- * **English**: "What are the most common side effects of metformin?"
168
- * **Spanish**: "¿Cuáles son los síntomas de la diabetes tipo 2?"
169
- * **French**: "Comment savoir si j'ai la grippe ou un simple rhume ?"
170
- * **Hindi**: "उच्च रक्तचाप के लिए घरेलू उपचार क्या हैं?" (What are the home remedies for high blood pressure?)
171
-
172
- ### Drug-Specific Queries
173
-
174
- * "Can I take ibuprofen with lisinopril? (Check for interactions)"
175
- * "What are the known side effects of amoxicillin?"
176
- * "Give me the FDA label information for Tylenol."
177
-
178
- ### Research & Clinical Trials (Best in Doctor Mode)
179
-
180
- * "Are there any ongoing clinical trials for Alzheimer's disease?"
181
- * "What is the latest PubMed literature on efficacy of novel biologics for Crohn's disease?"
182
 
183
  ---
184
 
185
- ## 🧑‍⚕️ See The Role-Based Difference (Detailed Examples)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
186
 
187
- Select a role in the UI and use a matching prompt below to see how the AI adapts its response, using different tools and language.
188
-
189
- ### For the Patient Role
190
-
191
- Select **patient** and ask a general health question. The AI will primarily use web search to provide an easy-to-understand overview, avoiding overly technical jargon.
192
 
193
- * "What are the most common side effects I should watch out for with lisinopril?"
194
 
195
- ### For the Doctor Role
196
 
197
- Select **doctor** and ask a technical, multi-part question. The AI will leverage specialized tools like PubMed, ClinicalTrials.gov, and drug databases to provide a detailed, sourced answer suitable for a medical professional.
198
 
199
- * "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."
200
 
201
- ---
 
4
  colorFrom: indigo
5
  colorTo: purple
6
  sdk: gradio
7
+ sdk_version: 5.33.0 # Note: I've updated this to a more recent version, adjust if needed
8
  app_file: app.py
9
  pinned: false
10
  secrets:
 
15
  - agent-demo-track
16
  ---
17
 
 
18
  # 🧬 MediAgent AI: Conversational Health Navigator & MCP Tool Server
19
 
20
+ **[➡️ Try the Live Demo Here!](https://huggingface.co/spaces/Agents-MCP-Hackathon/medical_ai)**
21
 
22
+ <div align="center" style="margin-bottom: 1em;">
23
+ <a href="https://modal.com/" target="_blank" style="text-decoration:none; margin-right:18px;">
24
+ <img src="https://assets.modal.com/logos/modal-logo-dark.svg" alt="Modal Logo" height="32" style="vertical-align:middle; margin-right:8px;"/>
25
+ <span style="font-size:1.1em; color:#8aa8ff; font-weight:bold;">Powered by Modal</span>
26
+ </a>
27
+ <a href="https://www.llamaindex.ai/" target="_blank" style="text-decoration:none;">
28
+ <img src="https://raw.githubusercontent.com/jerryjliu/llama_index/main/docs/imgs/llama_index_logo.png" alt="LlamaIndex Logo" height="32" style="vertical-align:middle; margin-right:8px;"/>
29
+ <span style="font-size:1.1em; color:#ffb300; font-weight:bold;">and LlamaIndex</span>
30
+ </a>
31
+ <div style="font-size:0.95em; color:#aaa; margin-top:2px;">Special thanks to the Modal and LlamaIndex teams for their amazing platforms!</div>
32
+ </div>
33
 
34
+ **MediAgent AI** is a sophisticated, conversational health assistant and a fully MCP-compliant tool server, built on Modal and Gradio. It provides reliable, sourced, and role-adapted answers to a wide range of medical questions.
35
 
36
+ This project is a submission for the **Gradio Agents & MCP Hackathon 2025**, competing in two tracks:
37
+ - **🔧 MCP Tool / Server Track:** Our backend exposes a robust, MCP-compliant endpoint for any agent to use.
38
+ - **🤖 Agentic Demo Showcase Track:** The Gradio UI provides a powerful demonstration of an agent using these tools to help users.
 
39
 
40
  ---
41
 
42
+ ## 🌟 Key Features
 
 
 
 
43
 
44
+ * 🌐 **Multilingual Support**: Automatically detects and responds in **English, Spanish, Hindi, and French**.
45
+ * 👤 **Role-Based Adaptation**:
46
+ * **Patient Mode**: Simplified, easy-to-understand health information.
47
+ * **Doctor Mode**: In-depth, technical insights using specialized medical databases.
48
+ * 🛡️ **Critical Safety Layer**: Identifies keywords related to medical emergencies (e.g., "chest pain") and immediately instructs the user to seek professional help, bypassing the AI.
49
+ * 🔗 **Sourced & Verifiable**: All information is backed by citations from authoritative sources.
50
+ * 💬 **Stateful Conversations**: Remembers chat history for contextual follow-up questions.
51
+ * 🛠️ **Fully Compliant MCP Tool Server**: Our tools can be called externally by any MCP client.
 
 
52
 
53
  ---
54
 
55
+ ## 🛠️ Tools & Technology Stack
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
 
57
+ Our agent leverages a powerful, specialized toolkit to provide accurate information. These tools are exposed via our public MCP endpoint.
58
 
59
+ | Tool Name | Description | Data Source(s) |
60
+ | ----------------------------- | --------------------------------------------------------------------------- | -------------------------- |
61
+ | `search_web` | For general health queries and patient-level explanations. | DuckDuckGo |
62
+ | `search_pubmed` | Accesses peer-reviewed medical literature for evidence-based information. | PubMed / NCBI |
63
+ | `get_drug_label_info` | Retrieves detailed, official FDA-approved prescribing information. | openFDA / DailyMed |
64
+ | `check_drug_side_effects` | Finds known side effects for a specific medication. | openFDA / DailyMed |
65
+ | `check_drug_interactions` | Checks for adverse interactions between two or more drugs. | RxNorm API (NIH) |
66
+ | `search_clinical_trials` | Discovers ongoing or completed clinical studies for conditions/treatments. | ClinicalTrials.gov (NIH) |
67
 
68
+ **Core Technologies:**
69
+ * **Backend & Compute:** [**Modal**](https://modal.com/) for scalable, serverless GPU and CPU functions.
70
+ * **AI Agent Framework:** [**LlamaIndex**](https://www.llamaindex.ai/) for orchestrating the agent's think-plan-act loop.
71
+ * **LLM:** [**Mistral 7B**](https://mistral.ai/) for high-quality reasoning.
72
+ * **Frontend UI:** [**Gradio**](https://www.gradio.app/) for the interactive chat interface.
73
 
74
  ---
75
 
76
+ ## 🏛️ Architecture: Hybrid Single-Server MCP
 
 
77
 
78
+ Our single Modal application serves as **both the core Agent and its own MCP-compliant Tool Server**.
79
 
80
+ 1. **Agent Endpoint (`/`):** A private endpoint that takes a user query and orchestrates the full agentic workflow (planning, tool selection, synthesis).
81
+ 2. **MCP Tool Endpoint (hidden in backend):** A public endpoint that exposes our individual tools. This makes our application a valid MCP Server, proving compliance and allowing any external MCP client to use our medical tools.
 
 
 
 
 
 
 
 
 
 
 
 
 
82
 
83
  ---
84
 
85
+ ## 🚀 Test our MCP Tool Server Live!
86
+
87
+ You can call our tools from any MCP-compatible client or directly with `curl`.
88
+
89
+ > ⚠️ **Note:** The first call may take 30-60 seconds as the serverless backend spins up. Subsequent calls are much faster.
90
+
91
+ ```bash
92
+ # Example: Check for a critical drug interaction
93
+ curl -X POST 'https://sunilpanda992--medi-agent-ai-final-backend-mediagentai-m-3f699b.modal.run' \
94
+ --header 'Content-Type: application/json' \
95
+ --data '{
96
+ "tool_name": "check_drug_interactions",
97
+ "tool_args": {
98
+ "drugs": ["warfarin", "amiodarone"]
99
+ }
100
+ }'
101
+
102
+ # Example: Search for PubMed articles
103
+ curl -X POST 'https://sunilpanda992--medi-agent-ai-final-backend-mediagentai-m-3f699b.modal.run' \
104
+ --header 'Content-Type: application/json' \
105
+ --data '{
106
+ "tool_name": "search_pubmed",
107
+ "tool_args": {"query": "metformin AND cardiovascular outcomes", "max_results": 2}
108
+ }'
109
+
110
+ # Example: Get official FDA label information (CORRECTED)
111
+ curl -X POST 'https://sunilpanda992--medi-agent-ai-final-backend-mediagentai-m-3f699b.modal.run' \
112
+ --header 'Content-Type: application/json' \
113
+ --data '{
114
+ "tool_name": "get_drug_label_info",
115
+ "tool_args": {"drug_name": "atorvastatin"}
116
+ }'
117
+ ```
118
+
119
+ IGNORE_WHEN_COPYING_START
120
+ Use code with caution. Markdown
121
+ IGNORE_WHEN_COPYING_END
122
 
123
+ ---
124
+ ## 🧪 Try It Out in the App!
 
 
 
125
 
126
+ Select the appropriate "patient" or "doctor" role in the chat interface above and try these prompts:
127
 
128
+ Patient Query: "What are the most common side effects of metformin?"
129
 
130
+ Doctor Query: "My patient with Crohn's is on methotrexate and we are considering adding infliximab. I need the latest PubMed literature on efficacy and a check for interactions between the two drugs."
131
 
132
+ Spanish Query: "¿Cuáles son los síntomas de la diabetes tipo 2?"
133
 
134
+ Interaction Check: "Can I take ibuprofen with lisinopril?"
app.py CHANGED
@@ -1,3 +1,5 @@
 
 
1
  import gradio as gr
2
  import requests
3
  import os
@@ -30,49 +32,38 @@ CUSTOM_CSS = """
30
  }
31
  """
32
 
33
- def handle_user_turn(user_input, chat_history, user_role, sid):
 
 
 
34
  if not user_input.strip():
35
  return chat_history, ""
36
 
37
- # Gradio's 'messages' type for chatbot expects dictionaries
38
- # Ensure chat_history is initialized with dictionaries or converted
39
- if not chat_history or not isinstance(chat_history[0], dict):
40
- # Convert existing tuples to dictionaries if needed, or start fresh
41
- new_chat_history = []
42
- for user_msg, bot_msg in chat_history:
43
- if user_msg is not None:
44
- new_chat_history.append({"role": "user", "content": user_msg})
45
- if bot_msg is not None:
46
- new_chat_history.append({"role": "assistant", "content": bot_msg})
47
- chat_history = new_chat_history
48
 
49
- chat_history.append({"role": "user", "content": user_input}) # Changed to dictionary format
 
50
 
51
  if not MODAL_BACKEND_URL:
52
- # For an error, append as assistant message
53
- chat_history.append({"role": "assistant", "content": "❗ Configuration error: `MODAL_BACKEND_URL` not set."})
54
- return chat_history, ""
55
 
56
- thinking_steps = ["Analyzing...", "Searching sources...", "Synthesizing..."]
 
57
 
58
- # Store the last user message to update it later
59
- # This assumes the last message is always the user's latest input
60
- last_user_message_index = len(chat_history) - 1
61
-
62
  for step in thinking_steps:
63
- # Create a temporary 'thinking' message from the assistant
64
- temp_message = {"role": "assistant", "content": f"<div class='chatbot-message bot'><em>{step}</em></div>"}
65
-
66
- # If there's an existing assistant thinking message, update it in place
67
- # Otherwise, append a new one
68
- if len(chat_history) > last_user_message_index + 1 and chat_history[last_user_message_index + 1]["role"] == "assistant":
69
- chat_history[last_user_message_index + 1] = temp_message
70
- else:
71
- chat_history.append(temp_message)
72
-
73
- yield chat_history, "" # Yield with the temporary thinking message
74
-
75
  time.sleep(0.4)
 
76
 
77
  try:
78
  response = requests.post(MODAL_BACKEND_URL, json={
@@ -81,38 +72,50 @@ def handle_user_turn(user_input, chat_history, user_role, sid):
81
  "role": user_role
82
  }, timeout=600)
83
  response.raise_for_status()
84
- reply = response.json().get("final_markdown", "No response received.")
 
 
85
  except Exception as e:
86
- reply = f"❗ Error: {str(e)}"
87
 
88
- # Update the last assistant message with the final reply
89
- # This should replace the thinking message or be appended if no thinking message was added
90
- if len(chat_history) > last_user_message_index + 1 and chat_history[last_user_message_index + 1]["role"] == "assistant":
91
- chat_history[last_user_message_index + 1] = {"role": "assistant", "content": reply}
92
- else:
93
- chat_history.append({"role": "assistant", "content": reply}) # Should not typically happen if thinking steps run
94
 
95
  yield chat_history, ""
96
 
97
- with gr.Blocks(css=CUSTOM_CSS, title="MediAgent AI") as demo:
 
 
98
  session_id = gr.State(lambda: str(uuid.uuid4()))
99
 
100
  gr.Markdown("""
101
- # 🧬 MediAgent AI
102
- **Your AI Health Navigator**
103
-
104
  <div class='chatbot-box'>
105
- MediAgent AI is a multilingual, role-based assistant that gives clear, cited medical answers.
106
  <ul>
107
- <li>🗣 Ask in English, Spanish, Hindi, or French</li>
108
- <li>🎯 <b>Patient</b> = simplified advice | <b>Doctor</b> = in-depth, technical insights</li>
109
- <li>🔗 Answers are backed by PubMed, FDA, etc.</li>
110
- <li>💊 Can provide information on **drug side effects, interactions, and official label details.**</li>
111
- <li>🔬 Can search for **clinical trials and medical research.**</li>
112
- <li>🛡️ Detects emergencies, adds safety notices</li>
 
 
113
  </ul>
 
 
 
 
 
 
 
 
 
 
114
  </div>
115
- """) # Changed Markdown content
 
116
 
117
  with gr.Row():
118
  with gr.Column(scale=1):
@@ -123,7 +126,8 @@ with gr.Blocks(css=CUSTOM_CSS, title="MediAgent AI") as demo:
123
  info="Choose your user type for tailored responses"
124
  )
125
  with gr.Column(scale=3):
126
- chatbot = gr.Chatbot(label="Conversation", height=480, type='messages') # Added type='messages'
 
127
 
128
  with gr.Row():
129
  user_textbox = gr.Textbox(
@@ -131,34 +135,35 @@ with gr.Blocks(css=CUSTOM_CSS, title="MediAgent AI") as demo:
131
  lines=1,
132
  scale=4
133
  )
134
- submit_btn = gr.Button("Send", elem_id="send-button", scale=1)
135
 
136
  examples = gr.Examples(
137
  examples=[
138
  "What are the side effects of metformin?",
139
  "Explain Crohn’s disease vs Ulcerative Colitis for a doctor",
140
  "¿Cuáles son los síntomas de la hipertensión?",
141
- "Can I take ibuprofen with lisinopril? (for interactions)", # New example
142
- "What is the FDA label information for acetaminophen?", # New example
143
- "Are there any ongoing clinical trials for breast cancer?", # New example
144
  ],
145
  inputs=[user_textbox]
146
- ) # Changed Examples content
147
 
148
- gr.ClearButton([chatbot, user_textbox], value="🔄 Clear")
149
 
150
- submit_btn.click(
 
151
  fn=handle_user_turn,
152
  inputs=[user_textbox, chatbot, user_role, session_id],
153
  outputs=[chatbot, user_textbox]
154
  )
155
-
156
- user_textbox.submit(
157
  fn=handle_user_turn,
158
  inputs=[user_textbox, chatbot, user_role, session_id],
159
  outputs=[chatbot, user_textbox]
160
  )
161
 
 
162
  if __name__ == "__main__":
163
  demo.queue()
164
  demo.launch()
 
1
+ # In app.py
2
+
3
  import gradio as gr
4
  import requests
5
  import os
 
32
  }
33
  """
34
 
35
+ def handle_user_turn(user_input: str, chat_history: list, user_role: str, sid: str):
36
+ """
37
+ Handles a single turn of the conversation.
38
+ """
39
  if not user_input.strip():
40
  return chat_history, ""
41
 
42
+ # Initialize chat_history if it's the first turn (it will be None)
43
+ if chat_history is None:
44
+ chat_history = []
45
+
46
+ # Append the user's message in the correct dictionary format
47
+ chat_history.append({"role": "user", "content": user_input})
 
 
 
 
 
48
 
49
+ # Immediately yield the updated history to show the user's message
50
+ yield chat_history, ""
51
 
52
  if not MODAL_BACKEND_URL:
53
+ chat_history.append({"role": "assistant", "content": "❗ Configuration error: `MODAL_BACKEND_URL` is not set."})
54
+ yield chat_history, ""
55
+ return
56
 
57
+ # --- Streaming "Thinking" Animation ---
58
+ chat_history.append({"role": "assistant", "content": ""}) # Add an empty placeholder for the bot response
59
 
60
+ thinking_steps = ["Analyzing your query...", "Searching medical databases...", "Consulting research papers...", "Synthesizing the answer..."]
 
 
 
61
  for step in thinking_steps:
62
+ # Update the last message (the bot's placeholder) with the current thinking step
63
+ chat_history[-1]["content"] = f"<em>{step}</em>"
64
+ yield chat_history, ""
 
 
 
 
 
 
 
 
 
65
  time.sleep(0.4)
66
+ # --- End of Animation ---
67
 
68
  try:
69
  response = requests.post(MODAL_BACKEND_URL, json={
 
72
  "role": user_role
73
  }, timeout=600)
74
  response.raise_for_status()
75
+ reply = response.json().get("final_markdown", "No valid response was received from the backend.")
76
+ except requests.exceptions.RequestException as e:
77
+ reply = f"❗ **Error Communicating with Backend:**\n\nCould not get a response. The server may be starting up or experiencing an issue. Please try again in a moment. \n\n*Details: {str(e)}*"
78
  except Exception as e:
79
+ reply = f"❗ **An Unexpected Error Occurred:**\n\n*Details: {str(e)}*"
80
 
81
+ # Update the final bot message with the actual reply
82
+ chat_history[-1]["content"] = reply
 
 
 
 
83
 
84
  yield chat_history, ""
85
 
86
+
87
+ # --- The rest of your Gradio app code remains the same ---
88
+ with gr.Blocks(css=CUSTOM_CSS, title="MediAgent AI: Conversational Health Navigator & MCP Tool Server") as demo:
89
  session_id = gr.State(lambda: str(uuid.uuid4()))
90
 
91
  gr.Markdown("""
92
+ # 🧬 MediAgent AI: Conversational Health Navigator & MCP Tool Server
93
+
 
94
  <div class='chatbot-box'>
95
+ <b>MediAgent AI</b> is a multilingual, role-adaptive health assistant and a fully MCP-compliant tool server.<br>
96
  <ul>
97
+ <li>🌐 <b>Multilingual:</b> English, Spanish, Hindi, French</li>
98
+ <li>👤 <b>Role-Based:</b> <b>Patient</b> = simplified advice | <b>Doctor</b> = in-depth, technical insights</li>
99
+ <li>🛡️ <b>Critical Safety Layer:</b> Detects emergencies, adds safety notices</li>
100
+ <li>🔗 <b>Sourced & Verifiable:</b> Answers are backed by PubMed, FDA, etc.</li>
101
+ <li>💬 <b>Stateful Conversations:</b> Remembers chat history for contextual follow-up</li>
102
+ <li>🛠️ <b>MCP Tool Server:</b> All tools are externally callable via MCP</li>
103
+ <li>💊 <b>Drug Info:</b> Side effects, interactions, FDA label details</li>
104
+ <li>🔬 <b>Research:</b> Clinical trials & medical literature search</li>
105
  </ul>
106
+ <div style='margin-top:10px; text-align:center;'>
107
+ <a href='https://modal.com/' target='_blank' style='text-decoration:none; margin-right:18px;'>
108
+ <img src='https://assets.modal.com/logos/modal-logo-dark.svg' alt='Modal Logo' style='height:32px; vertical-align:middle; margin-right:8px;'>
109
+ <span style='font-size:1.1em; color:#8aa8ff; font-weight:bold;'>Powered by Modal</span>
110
+ </a>
111
+ <a href='https://www.llamaindex.ai/' target='_blank' style='text-decoration:none;'>
112
+ <img src='https://raw.githubusercontent.com/jerryjliu/llama_index/main/docs/imgs/llama_index_logo.png' alt='LlamaIndex Logo' style='height:32px; vertical-align:middle; margin-right:8px;'>
113
+ <span style='font-size:1.1em; color:#ffb300; font-weight:bold;'>and LlamaIndex</span>
114
+ </a>
115
+ <div style='font-size:0.95em; color:#aaa; margin-top:2px;'>Special thanks to the Modal and LlamaIndex teams for their amazing platforms!</div>
116
  </div>
117
+ </div>
118
+ """)
119
 
120
  with gr.Row():
121
  with gr.Column(scale=1):
 
126
  info="Choose your user type for tailored responses"
127
  )
128
  with gr.Column(scale=3):
129
+ # IMPORTANT: Ensure chatbot is defined with type='messages'
130
+ chatbot = gr.Chatbot(label="Conversation", height=480, type='messages', bubble_full_width=False)
131
 
132
  with gr.Row():
133
  user_textbox = gr.Textbox(
 
135
  lines=1,
136
  scale=4
137
  )
138
+ submit_btn = gr.Button("Send", elem_id="send-button", scale=1, variant="primary")
139
 
140
  examples = gr.Examples(
141
  examples=[
142
  "What are the side effects of metformin?",
143
  "Explain Crohn’s disease vs Ulcerative Colitis for a doctor",
144
  "¿Cuáles son los síntomas de la hipertensión?",
145
+ "Can I take ibuprofen with lisinopril? (for interactions)",
146
+ "What is the FDA label information for acetaminophen?",
147
+ "Are there any ongoing clinical trials for breast cancer?",
148
  ],
149
  inputs=[user_textbox]
150
+ )
151
 
152
+ gr.ClearButton([chatbot, user_textbox], value="🔄 Clear Chat")
153
 
154
+ # Connect submit actions
155
+ user_textbox.submit(
156
  fn=handle_user_turn,
157
  inputs=[user_textbox, chatbot, user_role, session_id],
158
  outputs=[chatbot, user_textbox]
159
  )
160
+ submit_btn.click(
 
161
  fn=handle_user_turn,
162
  inputs=[user_textbox, chatbot, user_role, session_id],
163
  outputs=[chatbot, user_textbox]
164
  )
165
 
166
+
167
  if __name__ == "__main__":
168
  demo.queue()
169
  demo.launch()