try: import spaces has_spaces = True except ImportError: has_spaces = False import asyncio import gradio as gr from fastapi.middleware.cors import CORSMiddleware from backend.app.api.v1.router import api_router from backend.app.ml.manager import model_manager from backend.app.core.database import init_db # 1. ZeroGPU worker function def _run_ner(text: str): if not text or not text.strip(): return "Please provide clinical text." try: service = model_manager.get_ner_service() results = service.model.predict(text) if not results: return "No biomedical entities detected." return "\n".join( f"• [{e.label}] {e.text} (Confidence: {round((e.confidence or 1.0)*100, 1)}%)" for e in results ) except Exception as e: return f"Inference notice: {e}" if has_spaces: @spaces.GPU def predict_ner(text: str): return _run_ner(text) else: def predict_ner(text: str): return _run_ner(text) # 2. Gradio Interface — this IS the app ZeroGPU launches, so it must be the # thing that actually calls .launch() below. with gr.Blocks(title="SanjeevaniAI Healthcare Intelligence") as demo: gr.Markdown("# 🏥 SanjeevaniAI — Healthcare Intelligence Engine") gr.Markdown( "Backend REST API Engine powered by **FastAPI** on Hugging Face **ZeroGPU**.\n\n" "- **Health Status**: `/api/v1/health`\n" "- **NER Analysis**: `/api/v1/ner/analyze`" ) with gr.Row(): inp = gr.Textbox( label="Test Clinical Text", value="Metformin 500mg prescribed for type 2 diabetes mellitus and hypertension.", ) out = gr.Textbox(label="ZeroGPU Extracted Biomedical Entities") btn = gr.Button("⚡ Run ZeroGPU Clinical NER", variant="primary") btn.click(fn=predict_ner, inputs=inp, outputs=out) async def _startup(): await init_db() try: model_manager.initialize() except Exception as e: print(f"ML Model initialization: {e}") def main(): # prevent_thread_lock=True makes launch() return instead of blocking, # so we can attach to the REAL, live app object it just built. # Anything attached to demo.app BEFORE this call gets discarded — # launch() rebuilds the app internally to apply ssr_mode etc. demo.launch( server_name="0.0.0.0", server_port=7860, ssr_mode=False, prevent_thread_lock=True, ) # --- Everything below runs against the app that's actually serving traffic --- demo.app.include_router(api_router, prefix="/api/v1") # Defensive reset: guarantees add_middleware never raises # "Cannot add middleware after an application has started", # even if a request theoretically slipped in during the gap above. demo.app.middleware_stack = None demo.app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) asyncio.run(_startup()) # Keep the process alive — launch() no longer blocks on its own, # so without this the script exits and the server dies immediately. demo.block_thread() if __name__ == "__main__": main()