| """ |
| AI-Powered Disaster Triage from Images |
| ---------------------------------------- |
| Gradio front-end. Run locally with: python app.py |
| Deploys as-is to a Hugging Face Space (ZeroGPU-compatible, see README). |
| """ |
| try: |
| import spaces |
| GPU_DECORATOR = spaces.GPU |
| except ImportError: |
| def GPU_DECORATOR(fn): |
| return fn |
|
|
| import json |
| import tempfile |
| import os |
|
|
| import gradio as gr |
|
|
|
|
|
|
| |
| |
| |
| |
| |
| |
|
|
|
|
| @GPU_DECORATOR |
| def analyze_image(image_path): |
| |
| from src.pipeline import run_triage |
|
|
| if image_path is None: |
| return None, "Please upload an image first.", "{}" |
|
|
| annotated_rgb, result = run_triage(image_path) |
| report_md = result.to_markdown() |
| report_json = json.dumps(result.__dict__, indent=2) |
|
|
| return annotated_rgb, report_md, report_json |
|
|
| def download_report(image_path, report_md): |
| if not report_md: |
| return None |
| fd, path = tempfile.mkstemp(suffix=".md", prefix="triage_report_") |
| with os.fdopen(fd, "w") as f: |
| f.write("# Disaster Triage Report\n\n" + report_md) |
| return path |
|
|
|
|
| CSS = """ |
| #risk-panel { font-size: 1.05rem; } |
| footer { visibility: hidden } |
| """ |
|
|
| with gr.Blocks(title="AI Disaster Triage", css=CSS, theme=gr.themes.Soft()) as demo: |
| gr.Markdown( |
| """ |
| # π¨ AI-Powered Disaster Triage from Images |
| Upload a photo from a citizen, drone, CCTV feed, or rescue team. |
| The system detects objects (YOLO11), reasons about the scene like a |
| triage officer (Qwen2.5-VL), and returns a risk score + recommended |
| response β not just a list of detected objects. |
| """ |
| ) |
|
|
| with gr.Row(): |
| with gr.Column(scale=1): |
| image_input = gr.Image(type="filepath", label="Disaster Image", height=380) |
| analyze_btn = gr.Button("π Analyze Scene", variant="primary") |
| gr.Markdown("*Tip: drone/CCTV/citizen photos of floods, collapses, blocked roads work best.*") |
|
|
| with gr.Column(scale=1): |
| annotated_output = gr.Image(label="Annotated Scene (YOLO11 + Risk Badge)", height=380) |
|
|
| with gr.Row(): |
| with gr.Column(scale=2): |
| report_output = gr.Markdown(label="Triage Report", elem_id="risk-panel") |
| download_btn = gr.Button("β¬οΈ Download Report (.md)") |
| file_output = gr.File(label="Report file", visible=True) |
| with gr.Column(scale=1): |
| json_output = gr.Code(label="Raw structured output (JSON)", language="json") |
|
|
| analyze_btn.click( |
| fn=analyze_image, |
| inputs=[image_input], |
| outputs=[annotated_output, report_output, json_output], |
| ) |
| download_btn.click( |
| fn=download_report, |
| inputs=[image_input, report_output], |
| outputs=[file_output], |
| ) |
|
|
| if __name__ == "__main__": |
| demo.launch(share=True) |
|
|