Spaces:
Sleeping
Sleeping
| from fastapi import FastAPI | |
| from fastapi.responses import JSONResponse | |
| from fastapi.middleware.cors import CORSMiddleware | |
| from pydantic import BaseModel | |
| import google.generativeai as genai | |
| import uuid | |
| import os | |
| import gradio as gr | |
| import requests | |
| import re | |
| import threading | |
| # ----------------------------------------- | |
| # πΉ Gemini API Configuration | |
| # ----------------------------------------- | |
| genai.configure(api_key=os.getenv("GOOGLE_API_KEY", "AIzaSyAo8pgpGDFSrNM4O0mpNlokpPjKO2Z3vkg")) | |
| # ----------------------------------------- | |
| # πΉ FastAPI App | |
| # ----------------------------------------- | |
| app = FastAPI(title="Dr. HealBot - Medical Consultation API") | |
| # Allow CORS | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=["*"], # Restrict later if needed | |
| allow_credentials=True, | |
| allow_methods=["*"], | |
| allow_headers=["*"], | |
| ) | |
| # ----------------------------------------- | |
| # πΉ Request Schema | |
| # ----------------------------------------- | |
| class ChatRequest(BaseModel): | |
| message: str | |
| session_id: str | None = None | |
| # ----------------------------------------- | |
| # πΉ Chat Memory | |
| # ----------------------------------------- | |
| chat_histories = {} | |
| # ----------------------------------------- | |
| # πΉ Doctor System Prompt | |
| # ----------------------------------------- | |
| DOCTOR_SYSTEM_PROMPT = """ | |
| You are Dr. HealBot, a calm, knowledgeable, and empathetic virtual doctor. | |
| GOAL: | |
| Hold a natural, focused conversation with the patient to understand their health issue and offer helpful preliminary medical guidance. | |
| 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. | |
| π« RESTRICTIONS: | |
| - You must ONLY provide information related to medical, health, or wellness topics. | |
| - If the user asks anything (e.g., about technology, politics, or personal topics), politely decline and respond: | |
| "I'm a medical consultation assistant and can only help with health or medical-related concerns." | |
| - Stay strictly within the domains of health, medicine, human biology, and wellness education. | |
| CONVERSATION LOGIC: | |
| - Ask only relevant and concise medical questions necessary for diagnosing the illness. | |
| - Each question should help clarify symptoms or narrow possible causes. | |
| - Stop asking once enough information is collected for a basic assessment. | |
| - Then, provide a structured, friendly, and visually clear medical response using headings, emojis, and bullet points. | |
| - Automatically detect if the user is asking a **general medical question** (e.g., "What is diabetes?", "How does blood pressure work?", "Explain antibiotics"). | |
| - In such cases, switch to **Instructor Mode**: | |
| - Give a clear, educational, and structured explanation. | |
| - Use short paragraphs or bullet points. | |
| - Maintain a professional but approachable tone. | |
| - Conclude with a brief practical takeaway or health tip if appropriate. | |
| - If the user is describing symptoms or a health issue, continue in **Doctor Mode**: | |
| FINAL RESPONSE FORMAT: | |
| When giving your full assessment, use this markdown-styled format: | |
| π©Ί Based on what you've told me... | |
| Brief summary of what the patient described. | |
| π‘ Possible Causes (Preliminary) | |
| - List 1β2 possible conditions using phrases like "It could be" or "This sounds like". | |
| - Include a disclaimer that this is not a confirmed diagnosis. | |
| π₯ Lifestyle & Home Care Tips | |
| - 2β3 practical suggestions (rest, hydration, warm compress, balanced diet, etc.) | |
| β When to See a Real Doctor | |
| - 2β3 warning signs or conditions when urgent medical care is needed. | |
| π Follow-Up Advice | |
| - Brief recommendation for self-care or follow-up timing (e.g., "If not improving in 3 days, visit a clinic.") | |
| TONE & STYLE: | |
| - Speak like a real, caring doctor β short, clear, and empathetic (1β2 sentences per reply). | |
| - Use plain language, no jargon. | |
| - Only one question per turn unless clarification is essential. | |
| - Keep tone warm, calm, and professional. | |
| - Early messages: short questions only. | |
| - Final message: structured output with emojis and headings. | |
| IMPORTANT: | |
| - Never provide any information . | |
| - Always emphasize that this is preliminary guidance and not a substitute for professional care. | |
| - Never make definitive diagnoses; use phrases like "it sounds like" or "it could be". | |
| - If symptoms seem serious, always recommend urgent medical attention. | |
| CONVERSATION FLOW: | |
| 1. Begin by asking the purpose of the visit: | |
| 2. Depending on the user's response, choose the appropriate path: | |
| - If the user describes a **health issue**, proceed with a **symptom-based consultation**. | |
| - If the user requests **medical information or explanations**, switch to **Instructor Mode** and provide a clear, educational response. | |
| 3. For Symptom-Based Consultation: | |
| a. Ask about the **main symptom** (e.g., "Can you describe your main concern?") | |
| b. Ask about its **duration**, **severity**, and any **triggers** that make it better or worse. | |
| c. Ask about any **accompanying symptoms** (e.g., fever, nausea, fatigue, etc.). | |
| d. Ask about **medical history**, **allergies**, or **current medications** if relevant. | |
| e. Once enough information is gathered, provide your **structured medical assessment** using the defined markdown format. | |
| 4. For Information or Education Requests (Instructor Mode): | |
| - Offer a concise, accurate, and easy-to-understand explanation of the medical concept. | |
| - Use examples, analogies, or bullet points to make complex ideas simple. | |
| 5. Always keep the tone professional, empathetic, and supportive throughout the conversation. | |
| """ | |
| # ----------------------------------------- | |
| # πΉ FastAPI Endpoint | |
| # ----------------------------------------- | |
| async def chat(request: ChatRequest): | |
| try: | |
| session_id = request.session_id or str(uuid.uuid4()) | |
| if session_id not in chat_histories: | |
| chat_histories[session_id] = [{"role": "user", "text": DOCTOR_SYSTEM_PROMPT}] | |
| user_message = request.message.strip() | |
| chat_histories[session_id].append({"role": "user", "text": user_message}) | |
| contents = [] | |
| for msg in chat_histories[session_id]: | |
| role = "user" if msg["role"] == "user" else "model" | |
| contents.append({"role": role, "parts": [{"text": msg["text"]}]}) | |
| model = genai.GenerativeModel("gemini-2.5-flash") | |
| response = model.generate_content(contents) | |
| reply_text = response.text.strip() | |
| chat_histories[session_id].append({"role": "model", "text": reply_text}) | |
| return JSONResponse({ | |
| "reply": reply_text, | |
| "session_id": session_id | |
| }) | |
| except Exception as e: | |
| return JSONResponse({"error": str(e)}, status_code=500) | |
| def root(): | |
| return {"message": "Dr. HealBot API is running and ready for consultation!"} | |
| # ----------------------------------------- | |
| # πΉ Gradio Chat Interface | |
| # ----------------------------------------- | |
| API_URL = "http://127.0.0.1:8000/chat" | |
| session_id = None | |
| def clean_text(text): | |
| """Remove emojis from output.""" | |
| emoji_pattern = re.compile( | |
| "[" | |
| u"\U0001F600-\U0001F64F" | |
| u"\U0001F300-\U0001F5FF" | |
| u"\U0001F680-\U0001F6FF" | |
| u"\U0001F1E0-\U0001F1FF" | |
| u"\U00002500-\U00002BEF" | |
| u"\U00002702-\U000027B0" | |
| u"\U000024C2-\U0001F251" | |
| "]+", flags=re.UNICODE) | |
| return emoji_pattern.sub(r'', text) | |
| def chat_with_bot(message, history): | |
| """Send message to FastAPI backend and return response.""" | |
| global session_id | |
| try: | |
| payload = {"message": message, "session_id": session_id} | |
| res = requests.post(API_URL, json=payload) | |
| data = res.json() | |
| if "session_id" in data: | |
| session_id = data["session_id"] | |
| reply = clean_text(data.get("reply", "Error: No response")) | |
| except Exception as e: | |
| reply = f"Error: {e}" | |
| history.append((message, reply)) | |
| return history, history | |
| def launch_gradio(): | |
| """Run Gradio interface.""" | |
| with gr.Blocks(title="Dr. HealBot (Markdown Chat)") as demo: | |
| gr.Markdown("## π©Ί Dr. HealBot\nA Medical Consultation Chatbot (Markdown Supported, Emoji-Free)\n") | |
| chatbot = gr.Chatbot(show_label=False, height=500, bubble_full_width=False, show_copy_button=True) | |
| msg = gr.Textbox(placeholder="Type your health query...", label="Message") | |
| clear = gr.Button("Clear Chat") | |
| msg.submit(chat_with_bot, [msg, chatbot], [chatbot, chatbot]) | |
| clear.click(lambda: None, None, chatbot, queue=False) | |
| demo.launch(server_name="0.0.0.0", server_port=7860) | |
| # ----------------------------------------- | |
| # πΉ Run Both FastAPI + Gradio Together | |
| # ----------------------------------------- | |
| if __name__ == "__main__": | |
| import uvicorn | |
| threading.Thread(target=lambda: uvicorn.run(app, host="0.0.0.0", port=8000, reload=False), daemon=True).start() | |
| launch_gradio() | |