Spaces:
Sleeping
Sleeping
| """Step 5 — Gradio chat UI for the Medical RAG Chatbot. | |
| Run locally: | |
| python app.py | |
| Then open the printed local URL in your browser. This same file is the | |
| entry point HuggingFace Spaces looks for, so it deploys with no changes. | |
| """ | |
| from __future__ import annotations | |
| import gradio as gr | |
| from src.rag_pipeline import RAGChatbot | |
| DISCLAIMER = ( | |
| "⚠️ **Research demo only — not medical advice.** " | |
| "Answers are generated from a small set of documents and may be incomplete " | |
| "or wrong. Always consult a qualified ophthalmologist." | |
| ) | |
| EXAMPLE_QUESTIONS = [ | |
| "What is diabetic retinopathy?", | |
| "How is the severity of diabetic retinopathy graded?", | |
| "What deep learning methods are used to detect diabetic retinopathy?", | |
| "Why is early screening for diabetic retinopathy important?", | |
| ] | |
| def ensure_vector_store() -> None: | |
| """Build the ChromaDB index on first run if it doesn't exist yet. | |
| This makes the app self-contained on HuggingFace Spaces: if the vector | |
| store is missing, it downloads the source PDFs (when needed) and ingests | |
| them automatically, so the Space works without a manual build step. | |
| """ | |
| from src.config import CHROMA_DIR, DATA_DIR | |
| if CHROMA_DIR.exists(): | |
| return # already built — nothing to do | |
| print("No vector store found — building it now (first-run setup) ...") | |
| # If there are no source PDFs yet, try to fetch the defaults. | |
| if not list(DATA_DIR.glob("*.pdf")): | |
| try: | |
| from src.download_sources import main as download_main | |
| download_main() | |
| except Exception as exc: # noqa: BLE001 | |
| print(f" (could not auto-download sources: {exc})") | |
| # Build the index from whatever PDFs are present. | |
| from src.ingest import main as ingest_main | |
| ingest_main() | |
| # Load the pipeline once at startup. If something is missing (no docs or no key), | |
| # show the error in the UI instead of crashing silently. | |
| _load_error: str | None = None | |
| bot: RAGChatbot | None = None | |
| try: | |
| ensure_vector_store() | |
| bot = RAGChatbot() | |
| except Exception as exc: # noqa: BLE001 | |
| _load_error = str(exc) | |
| def _format_sources(sources) -> str: | |
| if not sources: | |
| return "" | |
| seen = [] | |
| for d in sources: | |
| src = d.metadata.get("source", "unknown") | |
| page = d.metadata.get("page", "?") | |
| label = f"{src} (p.{page})" | |
| if label not in seen: | |
| seen.append(label) | |
| return "\n\n**Sources used:** " + "; ".join(seen) | |
| def respond(message: str, history): | |
| """Gradio chat callback.""" | |
| if _load_error: | |
| return f"⚠️ Setup incomplete: {_load_error}" | |
| if not message.strip(): | |
| return "Please type a question about diabetic retinopathy." | |
| resp = bot.ask(message) | |
| return resp.answer + _format_sources(resp.sources) | |
| with gr.Blocks(title="Medical RAG Chatbot") as demo: | |
| gr.Markdown("# 🩺 Medical RAG Chatbot — Diabetic Retinopathy") | |
| gr.Markdown( | |
| "Ask questions about diabetic retinopathy. Answers are grounded in " | |
| "open-access research papers using Retrieval-Augmented Generation " | |
| "(LangChain · ChromaDB · sentence-transformers · Llama 3.3 70B on Groq)." | |
| ) | |
| gr.Markdown(DISCLAIMER) | |
| gr.ChatInterface( | |
| fn=respond, | |
| examples=EXAMPLE_QUESTIONS, | |
| ) | |
| if __name__ == "__main__": | |
| demo.launch() | |