File size: 3,242 Bytes
4bab068
 
 
 
 
 
cc740a6
 
 
 
 
 
4bab068
 
 
 
 
 
 
cc740a6
4bab068
 
 
 
 
 
 
 
 
 
 
cc740a6
 
 
4bab068
 
 
 
 
 
 
cc740a6
4bab068
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e847d84
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
"""
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



# ---------------------------------------------------------------------------
# Optional: Hugging Face ZeroGPU support.
# On a normal local NVIDIA GPU, `spaces` isn't installed and this no-ops.
# On HF Spaces (ZeroGPU hardware), this decorator grants a GPU burst for the
# duration of the function call — required for Spaces' free GPU tier.
# ---------------------------------------------------------------------------


@GPU_DECORATOR
def analyze_image(image_path):
    # Import AFTER spaces has initialized
    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)