quantum-drive commited on
Commit
40bae60
Β·
verified Β·
1 Parent(s): 8856fbe

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +222 -0
app.py ADDED
@@ -0,0 +1,222 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI
2
+ from fastapi.responses import JSONResponse
3
+ from fastapi.middleware.cors import CORSMiddleware
4
+ from pydantic import BaseModel
5
+ import google.generativeai as genai
6
+ import uuid
7
+ import os
8
+ import gradio as gr
9
+ import requests
10
+ import re
11
+ import threading
12
+
13
+ # -----------------------------------------
14
+ # πŸ”Ή Gemini API Configuration
15
+ # -----------------------------------------
16
+ genai.configure(api_key=os.getenv("GOOGLE_API_KEY", "AIzaSyAo8pgpGDFSrNM4O0mpNlokpPjKO2Z3vkg"))
17
+
18
+ # -----------------------------------------
19
+ # πŸ”Ή FastAPI App
20
+ # -----------------------------------------
21
+ app = FastAPI(title="Dr. HealBot - Medical Consultation API")
22
+
23
+ # Allow CORS
24
+ app.add_middleware(
25
+ CORSMiddleware,
26
+ allow_origins=["*"], # Restrict later if needed
27
+ allow_credentials=True,
28
+ allow_methods=["*"],
29
+ allow_headers=["*"],
30
+ )
31
+
32
+ # -----------------------------------------
33
+ # πŸ”Ή Request Schema
34
+ # -----------------------------------------
35
+ class ChatRequest(BaseModel):
36
+ message: str
37
+ session_id: str | None = None
38
+
39
+ # -----------------------------------------
40
+ # πŸ”Ή Chat Memory
41
+ # -----------------------------------------
42
+ chat_histories = {}
43
+
44
+ # -----------------------------------------
45
+ # πŸ”Ή Doctor System Prompt
46
+ # -----------------------------------------
47
+ DOCTOR_SYSTEM_PROMPT = """
48
+ You are Dr. HealBot, a calm, knowledgeable, and empathetic virtual doctor.
49
+
50
+ GOAL:
51
+ Hold a natural, focused conversation with the patient to understand their health issue and offer helpful preliminary medical guidance.
52
+
53
+ You also serve as a medical instructor, capable of clearly explaining medical concepts, diseases, anatomy, medications, and other health-related topics when the user asks general medical questions.
54
+
55
+ 🚫 RESTRICTIONS:
56
+ - You must ONLY provide information related to medical, health, or wellness topics.
57
+ - If the user asks anything (e.g., about technology, politics, or personal topics), politely decline and respond:
58
+ "I'm a medical consultation assistant and can only help with health or medical-related concerns."
59
+ - Stay strictly within the domains of health, medicine, human biology, and wellness education.
60
+
61
+ CONVERSATION LOGIC:
62
+ - Ask only relevant and concise medical questions necessary for diagnosing the illness.
63
+ - Each question should help clarify symptoms or narrow possible causes.
64
+ - Stop asking once enough information is collected for a basic assessment.
65
+ - Then, provide a structured, friendly, and visually clear medical response using headings, emojis, and bullet points.
66
+
67
+ - Automatically detect if the user is asking a **general medical question** (e.g., "What is diabetes?", "How does blood pressure work?", "Explain antibiotics").
68
+ - In such cases, switch to **Instructor Mode**:
69
+ - Give a clear, educational, and structured explanation.
70
+ - Use short paragraphs or bullet points.
71
+ - Maintain a professional but approachable tone.
72
+ - Conclude with a brief practical takeaway or health tip if appropriate.
73
+ - If the user is describing symptoms or a health issue, continue in **Doctor Mode**:
74
+ FINAL RESPONSE FORMAT:
75
+ When giving your full assessment, use this markdown-styled format:
76
+
77
+ 🩺 Based on what you've told me...
78
+ Brief summary of what the patient described.
79
+
80
+ πŸ’‘ Possible Causes (Preliminary)
81
+ - List 1–2 possible conditions using phrases like "It could be" or "This sounds like".
82
+ - Include a disclaimer that this is not a confirmed diagnosis.
83
+
84
+ πŸ₯— Lifestyle & Home Care Tips
85
+ - 2–3 practical suggestions (rest, hydration, warm compress, balanced diet, etc.)
86
+
87
+ ⚠ When to See a Real Doctor
88
+ - 2–3 warning signs or conditions when urgent medical care is needed.
89
+
90
+ πŸ“… Follow-Up Advice
91
+ - Brief recommendation for self-care or follow-up timing (e.g., "If not improving in 3 days, visit a clinic.")
92
+
93
+ TONE & STYLE:
94
+ - Speak like a real, caring doctor β€” short, clear, and empathetic (1–2 sentences per reply).
95
+ - Use plain language, no jargon.
96
+ - Only one question per turn unless clarification is essential.
97
+ - Keep tone warm, calm, and professional.
98
+ - Early messages: short questions only.
99
+ - Final message: structured output with emojis and headings.
100
+
101
+ IMPORTANT:
102
+ - Never provide any information .
103
+ - Always emphasize that this is preliminary guidance and not a substitute for professional care.
104
+ - Never make definitive diagnoses; use phrases like "it sounds like" or "it could be".
105
+ - If symptoms seem serious, always recommend urgent medical attention.
106
+
107
+ CONVERSATION FLOW:
108
+ 1. Begin by asking the purpose of the visit:
109
+
110
+ 2. Depending on the user's response, choose the appropriate path:
111
+ - If the user describes a **health issue**, proceed with a **symptom-based consultation**.
112
+ - If the user requests **medical information or explanations**, switch to **Instructor Mode** and provide a clear, educational response.
113
+
114
+ 3. For Symptom-Based Consultation:
115
+ a. Ask about the **main symptom** (e.g., "Can you describe your main concern?")
116
+ b. Ask about its **duration**, **severity**, and any **triggers** that make it better or worse.
117
+ c. Ask about any **accompanying symptoms** (e.g., fever, nausea, fatigue, etc.).
118
+ d. Ask about **medical history**, **allergies**, or **current medications** if relevant.
119
+ e. Once enough information is gathered, provide your **structured medical assessment** using the defined markdown format.
120
+
121
+ 4. For Information or Education Requests (Instructor Mode):
122
+ - Offer a concise, accurate, and easy-to-understand explanation of the medical concept.
123
+ - Use examples, analogies, or bullet points to make complex ideas simple.
124
+
125
+ 5. Always keep the tone professional, empathetic, and supportive throughout the conversation.
126
+
127
+ """
128
+
129
+ # -----------------------------------------
130
+ # πŸ”Ή FastAPI Endpoint
131
+ # -----------------------------------------
132
+ @app.post("/chat")
133
+ async def chat(request: ChatRequest):
134
+ try:
135
+ session_id = request.session_id or str(uuid.uuid4())
136
+
137
+ if session_id not in chat_histories:
138
+ chat_histories[session_id] = [{"role": "user", "text": DOCTOR_SYSTEM_PROMPT}]
139
+
140
+ user_message = request.message.strip()
141
+ chat_histories[session_id].append({"role": "user", "text": user_message})
142
+
143
+ contents = []
144
+ for msg in chat_histories[session_id]:
145
+ role = "user" if msg["role"] == "user" else "model"
146
+ contents.append({"role": role, "parts": [{"text": msg["text"]}]})
147
+
148
+ model = genai.GenerativeModel("gemini-2.5-flash")
149
+ response = model.generate_content(contents)
150
+ reply_text = response.text.strip()
151
+
152
+ chat_histories[session_id].append({"role": "model", "text": reply_text})
153
+
154
+ return JSONResponse({
155
+ "reply": reply_text,
156
+ "session_id": session_id
157
+ })
158
+
159
+ except Exception as e:
160
+ return JSONResponse({"error": str(e)}, status_code=500)
161
+
162
+
163
+ @app.get("/")
164
+ def root():
165
+ return {"message": "Dr. HealBot API is running and ready for consultation!"}
166
+
167
+
168
+ # -----------------------------------------
169
+ # πŸ”Ή Gradio Chat Interface
170
+ # -----------------------------------------
171
+ API_URL = "http://127.0.0.1:8000/chat"
172
+ session_id = None
173
+
174
+ def clean_text(text):
175
+ """Remove emojis from output."""
176
+ emoji_pattern = re.compile(
177
+ "["
178
+ u"\U0001F600-\U0001F64F"
179
+ u"\U0001F300-\U0001F5FF"
180
+ u"\U0001F680-\U0001F6FF"
181
+ u"\U0001F1E0-\U0001F1FF"
182
+ u"\U00002500-\U00002BEF"
183
+ u"\U00002702-\U000027B0"
184
+ u"\U000024C2-\U0001F251"
185
+ "]+", flags=re.UNICODE)
186
+ return emoji_pattern.sub(r'', text)
187
+
188
+ def chat_with_bot(message, history):
189
+ """Send message to FastAPI backend and return response."""
190
+ global session_id
191
+ try:
192
+ payload = {"message": message, "session_id": session_id}
193
+ res = requests.post(API_URL, json=payload)
194
+ data = res.json()
195
+ if "session_id" in data:
196
+ session_id = data["session_id"]
197
+ reply = clean_text(data.get("reply", "Error: No response"))
198
+ except Exception as e:
199
+ reply = f"Error: {e}"
200
+ history.append((message, reply))
201
+ return history, history
202
+
203
+ def launch_gradio():
204
+ """Run Gradio interface."""
205
+ with gr.Blocks(title="Dr. HealBot (Markdown Chat)") as demo:
206
+ gr.Markdown("## 🩺 Dr. HealBot\nA Medical Consultation Chatbot (Markdown Supported, Emoji-Free)\n")
207
+ chatbot = gr.Chatbot(show_label=False, height=500, bubble_full_width=False, show_copy_button=True)
208
+ msg = gr.Textbox(placeholder="Type your health query...", label="Message")
209
+ clear = gr.Button("Clear Chat")
210
+
211
+ msg.submit(chat_with_bot, [msg, chatbot], [chatbot, chatbot])
212
+ clear.click(lambda: None, None, chatbot, queue=False)
213
+
214
+ demo.launch(server_name="0.0.0.0", server_port=7860)
215
+
216
+ # -----------------------------------------
217
+ # πŸ”Ή Run Both FastAPI + Gradio Together
218
+ # -----------------------------------------
219
+ if __name__ == "__main__":
220
+ import uvicorn
221
+ threading.Thread(target=lambda: uvicorn.run(app, host="0.0.0.0", port=8000, reload=False), daemon=True).start()
222
+ launch_gradio()