Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| from rag_dspy import MedicalRAG | |
| rag_chain = MedicalRAG() | |
| sample_questions = [ | |
| "What are the most common symptoms of lupus?", | |
| "How is type 2 diabetes usually managed in adults?", | |
| "What are the first-line medications for treating hypertension?", | |
| ] | |
| def qa_bot(user_question, history, min_year, max_year, specialty): | |
| history = history or [] | |
| if not user_question.strip(): | |
| return history, history | |
| history.append({"role": "user", "content": user_question}) | |
| result = rag_chain.forward(user_question, min_year, max_year, specialty) | |
| answer = result.final_answer | |
| history.append({"role": "assistant", "content": answer}) | |
| return history, history | |
| css = """ | |
| html, body, #root, .gradio-container { | |
| margin: 0 !important; | |
| padding: 0 !important; | |
| } | |
| body { | |
| background: #f5f7fa !important; | |
| font-family: 'Segoe UI', 'Roboto', 'Helvetica Neue', Arial, sans-serif !important; | |
| color: #212529 !important; | |
| margin: 0; | |
| padding: 0; | |
| } | |
| #main-row { | |
| display: flex; | |
| flex-direction: row; | |
| width: 100vw; | |
| min-height: 100vh; | |
| box-sizing: border-box; | |
| gap: 0; | |
| } | |
| #readme-col { | |
| flex: 1 1 0; | |
| background: #f5f7fa; | |
| padding: 0 0 0 0; | |
| border-right: 1px solid #e3e7ef; | |
| height: 108vh; | |
| overflow-y: auto; | |
| box-sizing: border-box; | |
| } | |
| #readme-markdown { | |
| border-radius: 5px; | |
| box-shadow: 0 4px 24px rgba(60, 80, 120, 0.07), 0 1.5px 4px rgba(60, 80, 120, 0.05); | |
| padding: 32px 32px 24px 32px; | |
| margin: 0; | |
| border: none; | |
| overflow-y: auto; | |
| box-sizing: border-box; | |
| flex: 1; | |
| } | |
| #main-card { | |
| background: #fff !important; | |
| border-radius: 5px; | |
| box-shadow: 0 4px 24px rgba(60, 80, 120, 0.07), 0 1.5px 4px rgba(60, 80, 120, 0.05); | |
| padding: 32px 32px 24px 32px; | |
| margin: 0; | |
| border: none; | |
| overflow-y: auto; | |
| box-sizing: border-box; | |
| flex: 1; | |
| } | |
| #chatbot { | |
| background: #f9fbfd !important; | |
| border-radius: 5px !important; | |
| box-shadow: 0 2px 8px rgba(60, 80, 120, 0.06); | |
| margin-bottom: 18px !important; | |
| border: 1px solid #e3e7ef !important; | |
| padding: 16px !important; | |
| color: #212529 !important; | |
| } | |
| .suggestion-btn { | |
| margin: 0 12px 18px 0 !important; | |
| background: #eaf4ff !important; | |
| color: #2563eb !important; | |
| border-radius: 10px !important; | |
| font-weight: 500 !important; | |
| font-size: 1rem !important; | |
| border: 1.5px solid #bcdfff !important; | |
| transition: background 0.2s, color 0.2s, border-color 0.2s; | |
| } | |
| .suggestion-btn:hover { | |
| background: #d2eaff !important; | |
| color: #174ea6 !important; | |
| border-color: #2563eb !important; | |
| } | |
| #medical-title { | |
| text-align: center; | |
| color: #2563eb; | |
| font-size: 2.3rem; | |
| font-weight: 700; | |
| margin-bottom: 18px; | |
| letter-spacing: 1px; | |
| } | |
| #user-input { | |
| border-radius: 10px !important; | |
| border: 1.5px solid #bcdfff !important; | |
| padding: 10px 16px !important; | |
| font-size: 1.1rem !important; | |
| background: #fff !important; | |
| color: #212529 !important; | |
| } | |
| #user-input::placeholder { | |
| color: #8ca0b3 !important; | |
| opacity: 1 !important; | |
| } | |
| #submit-btn { | |
| background: linear-gradient(90deg, #2563eb 0%, #38bdf8 100%) !important; | |
| color: #fff !important; | |
| border-radius: 10px !important; | |
| font-size: 1.3rem !important; | |
| min-width: 56px; | |
| min-height: 44px; | |
| border: none !important; | |
| box-shadow: 0 2px 8px rgba(60, 80, 120, 0.07); | |
| transition: background 0.2s; | |
| } | |
| #submit-btn:hover { | |
| background: linear-gradient(90deg, #174ea6 0%, #0ea5e9 100%) !important; | |
| color: #fff !important; | |
| } | |
| @media (max-width: 900px) { | |
| #main-row { | |
| flex-direction: column; | |
| width: 100vw; | |
| } | |
| #readme-col, #main-card { | |
| min-width: 0 !important; | |
| max-width: 100vw !important; | |
| border-radius: 0 !important; | |
| height: auto !important; | |
| } | |
| #readme-markdown { | |
| padding: 24px 12px 16px 12px; | |
| } | |
| } | |
| @media (max-width: 600px) { | |
| #main-row { | |
| flex-direction: column; | |
| width: 100vw; | |
| } | |
| #readme-col, #main-card { | |
| min-width: 0 !important; | |
| max-width: 100vw !important; | |
| border-radius: 0 !important; | |
| height: auto !important; | |
| } | |
| #readme-markdown { | |
| padding: 14px 6px 10px 6px; | |
| font-size: 0.98rem; | |
| } | |
| #main-card { | |
| padding: 16px 6px 10px 6px !important; | |
| } | |
| } | |
| """ | |
| readme_content = """ | |
| # Medical QA Chatbot | |
| This is a Chain-of-Thought powered medical chatbot that: | |
| - Retrieves answers from a Qdrant Cloud vector DB | |
| - Uses Stanford DSPy to reason step-by-step | |
| - Supports filtering by year and specialty | |
| - Uses dense + ColBERT multivectors for retrieval | |
| --- | |
| ## How to Use | |
| - Add your `OPENAI_API_KEY` to `.env` | |
| - Add your `QDRANT_API_KEY` to `.env` | |
| - Add your `QDRANT_CLOUD_URL` to `.env` | |
| - Make sure `qdrant-client` points to your | |
| Qdrant Cloud instance in `rag_dspy.py` | |
| - Run `python app.py` | |
| ## Sample Questions | |
| ### General Medical Knowledge | |
| - What are the most common symptoms of lupus? | |
| - How is type 2 diabetes usually managed in adults? | |
| - What is the difference between viral and bacterial pneumonia? | |
| ### Treatment & Medication | |
| - What are the first-line medications for treating hypertension? | |
| - How does metformin work to lower blood sugar? | |
| """ | |
| def suggestion_click(q, history, min_year, max_year, specialty): | |
| return qa_bot(q, history, min_year, max_year, specialty) | |
| with gr.Blocks(theme=gr.themes.Monochrome(), css=css) as demo: | |
| with gr.Row(elem_id="main-row"): | |
| with gr.Column(elem_id="main-card"): | |
| chatbot = gr.Chatbot(label="", elem_id="chatbot", type="messages", height=300) | |
| state = gr.State([]) | |
| specialty_options = [ | |
| "Rheumatology", "Psychiatry", "Pulmonology & Respiratory Medicine", "Nephrology", "Public Health & Epidemiology", | |
| "Medical Research & Methodology", "Pharmacy & Pharmacology", "Hematology", "Oncology", "Medical Ethics & Law", | |
| "Medical Technology & Informatics", "Infectious Disease", "Basic Medical Sciences", "Allergology", "Geriatrics", | |
| "Cardiology", "Gastroenterology & Hepatology", "General Surgery", "General Pediatrics", "Endocrinology & Metabolism", | |
| "Vascular Surgery", "Radiology & Imaging", "Obstetrics & Gynecology", "Orthopedic Surgery", "Neurology", | |
| "Family Medicine & Primary Care", "Psychology & Behavioral Health", "Otorhinolaryngology (ENT)", "General Internal Medicine", | |
| "Anesthesiology", "Physical & Rehabilitation Medicine", "Medical Education", "Healthcare Administration & Management", | |
| "Non-Medical Sciences & Disciplines", "Dermatology", "Critical Care & Intensive Care", "Urology", "Complementary & Alternative Medicine", | |
| "Cardiothoracic Surgery", "Neurosurgery", "Pediatric Subspecialties", "Occupational & Environmental Health", "Ophthalmology", | |
| "Emergency Medicine", "Dental & Oral Medicine", "Biomedical Engineering", "Pathology & Laboratory Medicine", "Transplant Surgery", | |
| "Preventive Medicine", "Genetics", "Nursing", "Allied Health Professions", "Plastic & Reconstructive Surgery", "Others", | |
| "Toxicology", "General Medicine" | |
| ] | |
| specialty_dropdown = gr.Dropdown(choices=specialty_options, value="General Medicine", label="Specialty", scale=2, elem_id="specialty-dropdown") | |
| with gr.Row(): | |
| min_year_slider = gr.Slider(minimum=1793, maximum=2021, value=1990, step=1, label="Min Year", scale=2, elem_id="min-year-slider") | |
| max_year_slider = gr.Slider(minimum=1793, maximum=2021, value=2021, step=1, label="Max Year", scale=2, elem_id="max-year-slider") | |
| with gr.Row(): | |
| user_input = gr.Textbox(placeholder="Type a medical question...", show_label=False, lines=1, scale=8, elem_id="user-input") | |
| submit_btn = gr.Button(value="➤", scale=1, elem_id="submit-btn") | |
| with gr.Row(): | |
| suggestion_buttons = [] | |
| for i, q in enumerate(sample_questions): | |
| btn = gr.Button(q, elem_id=f"suggestion-{i}", elem_classes=["suggestion-btn"]) | |
| suggestion_buttons.append(btn) | |
| submit_btn.click(qa_bot, inputs=[user_input, state, min_year_slider, max_year_slider, specialty_dropdown], outputs=[chatbot, state]) | |
| user_input.submit(qa_bot, inputs=[user_input, state, min_year_slider, max_year_slider, specialty_dropdown], outputs=[chatbot, state]) | |
| for btn, q in zip(suggestion_buttons, sample_questions): | |
| btn.click(suggestion_click, inputs=[gr.State(q), state, min_year_slider, max_year_slider, specialty_dropdown], outputs=[chatbot, state]) | |
| with gr.Column(elem_id="readme-col"): | |
| gr.Markdown(readme_content, elem_id="readme-markdown") | |
| if __name__ == "__main__": | |
| demo.launch() | |