Spaces:
Sleeping
Sleeping
Deploy ReliefLens AI Gradio Space
Browse files- README.md +18 -7
- app.py +171 -0
- requirements.txt +2 -0
README.md
CHANGED
|
@@ -1,13 +1,24 @@
|
|
| 1 |
---
|
| 2 |
-
title: ReliefLens
|
| 3 |
-
emoji:
|
| 4 |
colorFrom: blue
|
| 5 |
colorTo: red
|
| 6 |
sdk: gradio
|
| 7 |
-
|
| 8 |
-
python_version: '3.13'
|
| 9 |
-
app_file: app.py
|
| 10 |
-
pinned: false
|
| 11 |
---
|
| 12 |
|
| 13 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
---
|
| 2 |
+
title: ReliefLens AI
|
| 3 |
+
emoji: 🚨
|
| 4 |
colorFrom: blue
|
| 5 |
colorTo: red
|
| 6 |
sdk: gradio
|
| 7 |
+
python_version: "3.10"
|
|
|
|
|
|
|
|
|
|
| 8 |
---
|
| 9 |
|
| 10 |
+
# ReliefLens AI
|
| 11 |
+
|
| 12 |
+
ReliefLens AI is a multimodal, human-in-the-loop disaster triage system built for the AMD Developer Hackathon.
|
| 13 |
+
|
| 14 |
+
This Hugging Face Space is the public demo frontend.
|
| 15 |
+
|
| 16 |
+
The backend runs on AMD Developer Cloud using ROCm / MI300X infrastructure.
|
| 17 |
+
|
| 18 |
+
## Demo mode
|
| 19 |
+
|
| 20 |
+
This demo uses synthetic disaster-response data for safety.
|
| 21 |
+
|
| 22 |
+
## Safety
|
| 23 |
+
|
| 24 |
+
ReliefLens AI is not connected to emergency services and must not be used for real-world dispatch decisions.
|
app.py
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import json
|
| 3 |
+
import requests
|
| 4 |
+
import gradio as gr
|
| 5 |
+
|
| 6 |
+
BACKEND_PUBLIC_URL = os.getenv("BACKEND_PUBLIC_URL", "http://134.199.203.136:8080").rstrip("/")
|
| 7 |
+
AMD_LLM_MODEL = os.getenv("AMD_LLM_MODEL", "Qwen/Qwen2.5-7B-Instruct")
|
| 8 |
+
DEMO_MODE = os.getenv("DEMO_MODE", "true")
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
def backend_get(path: str):
|
| 12 |
+
url = f"{BACKEND_PUBLIC_URL}{path}"
|
| 13 |
+
try:
|
| 14 |
+
response = requests.get(url, timeout=25)
|
| 15 |
+
response.raise_for_status()
|
| 16 |
+
try:
|
| 17 |
+
return response.json()
|
| 18 |
+
except Exception:
|
| 19 |
+
return {"raw": response.text[:3000]}
|
| 20 |
+
except Exception as exc:
|
| 21 |
+
return {
|
| 22 |
+
"error": str(exc),
|
| 23 |
+
"url": url,
|
| 24 |
+
"hint": "Check that the AMD backend is running and reachable."
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def backend_post(path: str, payload: dict):
|
| 29 |
+
url = f"{BACKEND_PUBLIC_URL}{path}"
|
| 30 |
+
try:
|
| 31 |
+
response = requests.post(url, json=payload, timeout=90)
|
| 32 |
+
response.raise_for_status()
|
| 33 |
+
try:
|
| 34 |
+
return response.json()
|
| 35 |
+
except Exception:
|
| 36 |
+
return {"raw": response.text[:5000]}
|
| 37 |
+
except Exception as exc:
|
| 38 |
+
return {
|
| 39 |
+
"error": str(exc),
|
| 40 |
+
"url": url,
|
| 41 |
+
"hint": "Check the backend route in /docs. If this route does not exist, use the fallback demo."
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
def check_backend():
|
| 46 |
+
health = backend_get("/health")
|
| 47 |
+
amd = backend_get("/api/amd/performance")
|
| 48 |
+
|
| 49 |
+
return json.dumps(
|
| 50 |
+
{
|
| 51 |
+
"backend_url": BACKEND_PUBLIC_URL,
|
| 52 |
+
"health": health,
|
| 53 |
+
"amd_performance": amd,
|
| 54 |
+
"model": AMD_LLM_MODEL,
|
| 55 |
+
"demo_mode": DEMO_MODE,
|
| 56 |
+
},
|
| 57 |
+
indent=2,
|
| 58 |
+
ensure_ascii=False,
|
| 59 |
+
)
|
| 60 |
+
|
| 61 |
+
|
| 62 |
+
def run_santa_ana_demo():
|
| 63 |
+
payload = {
|
| 64 |
+
"scenario": "santa_ana",
|
| 65 |
+
"demo_mode": True,
|
| 66 |
+
"model": AMD_LLM_MODEL,
|
| 67 |
+
}
|
| 68 |
+
|
| 69 |
+
result = backend_post("/api/demo/run", payload)
|
| 70 |
+
return json.dumps(result, indent=2, ensure_ascii=False)
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
def run_fallback_demo():
|
| 74 |
+
result = {
|
| 75 |
+
"status": "fallback_demo",
|
| 76 |
+
"message": "Synthetic fallback demo. AMD backend may be offline or demo route may be unavailable.",
|
| 77 |
+
"scenario": "Santa Ana wildfire synthetic demo",
|
| 78 |
+
"signals": [
|
| 79 |
+
{
|
| 80 |
+
"type": "text",
|
| 81 |
+
"content": "Smoke visible near hillside. Two families requesting evacuation assistance.",
|
| 82 |
+
"priority_hint": "high"
|
| 83 |
+
},
|
| 84 |
+
{
|
| 85 |
+
"type": "image_report",
|
| 86 |
+
"content": "Simulated image evidence: smoke plume near residential area.",
|
| 87 |
+
"priority_hint": "medium"
|
| 88 |
+
},
|
| 89 |
+
{
|
| 90 |
+
"type": "csv_location",
|
| 91 |
+
"content": "Lat/lon cluster indicates repeated alerts from the same area.",
|
| 92 |
+
"priority_hint": "high"
|
| 93 |
+
}
|
| 94 |
+
],
|
| 95 |
+
"consolidated_incident": {
|
| 96 |
+
"incident_type": "wildfire",
|
| 97 |
+
"priority": "P1",
|
| 98 |
+
"location": "Santa Ana synthetic demo area",
|
| 99 |
+
"evidence_count": 3
|
| 100 |
+
},
|
| 101 |
+
"recommended_resources": [
|
| 102 |
+
"evacuation support",
|
| 103 |
+
"medical triage unit",
|
| 104 |
+
"fire response team",
|
| 105 |
+
"public alert message"
|
| 106 |
+
],
|
| 107 |
+
"dispatch_message": "P1 wildfire risk near residential area. Dispatch evacuation support and fire response. Monitor wind direction and confirm affected households.",
|
| 108 |
+
"amd_note": "Full backend is expected to run on AMD Developer Cloud. This fallback does not claim live GPU inference."
|
| 109 |
+
}
|
| 110 |
+
|
| 111 |
+
return json.dumps(result, indent=2, ensure_ascii=False)
|
| 112 |
+
|
| 113 |
+
|
| 114 |
+
with gr.Blocks(title="ReliefLens AI") as demo:
|
| 115 |
+
gr.Markdown(
|
| 116 |
+
"""
|
| 117 |
+
# 🚨 ReliefLens AI
|
| 118 |
+
|
| 119 |
+
**Agentic disaster-response triage powered by AMD Developer Cloud.**
|
| 120 |
+
|
| 121 |
+
ReliefLens AI turns chaotic multimodal field reports into structured incidents,
|
| 122 |
+
priority labels, evidence links, resource recommendations, and dispatch-ready messages.
|
| 123 |
+
|
| 124 |
+
This public Space calls a FastAPI backend deployed on AMD Developer Cloud.
|
| 125 |
+
"""
|
| 126 |
+
)
|
| 127 |
+
|
| 128 |
+
with gr.Row():
|
| 129 |
+
gr.Textbox(value=BACKEND_PUBLIC_URL, label="AMD Backend URL", interactive=False)
|
| 130 |
+
gr.Textbox(value=AMD_LLM_MODEL, label="Target model", interactive=False)
|
| 131 |
+
|
| 132 |
+
with gr.Tab("1. AMD Backend Status"):
|
| 133 |
+
gr.Markdown("Check whether the AMD Cloud backend is reachable.")
|
| 134 |
+
status_btn = gr.Button("Check Backend")
|
| 135 |
+
status_output = gr.Code(label="Backend status", language="json")
|
| 136 |
+
status_btn.click(fn=check_backend, outputs=status_output)
|
| 137 |
+
|
| 138 |
+
with gr.Tab("2. Santa Ana Demo"):
|
| 139 |
+
gr.Markdown(
|
| 140 |
+
"""
|
| 141 |
+
Runs the synthetic Santa Ana crisis-response scenario through the AMD backend.
|
| 142 |
+
|
| 143 |
+
If the backend endpoint is not available yet, use the fallback tab.
|
| 144 |
+
"""
|
| 145 |
+
)
|
| 146 |
+
run_btn = gr.Button("Run Santa Ana Demo via AMD Backend")
|
| 147 |
+
run_output = gr.Code(label="Demo output", language="json")
|
| 148 |
+
run_btn.click(fn=run_santa_ana_demo, outputs=run_output)
|
| 149 |
+
|
| 150 |
+
with gr.Tab("3. Offline Fallback Demo"):
|
| 151 |
+
gr.Markdown("Safe local fallback for judges if the AMD VM is offline.")
|
| 152 |
+
fallback_btn = gr.Button("Run Fallback Demo")
|
| 153 |
+
fallback_output = gr.Code(label="Fallback output", language="json")
|
| 154 |
+
fallback_btn.click(fn=run_fallback_demo, outputs=fallback_output)
|
| 155 |
+
|
| 156 |
+
with gr.Tab("4. Safety / Limitations"):
|
| 157 |
+
gr.Markdown(
|
| 158 |
+
"""
|
| 159 |
+
## Safety and limitations
|
| 160 |
+
|
| 161 |
+
- This demo uses synthetic disaster-response data.
|
| 162 |
+
- It is not connected to emergency services.
|
| 163 |
+
- It should not be used for real-world emergency dispatch.
|
| 164 |
+
- AMD Cloud validation should be shown with `rocm-smi`, backend status, and performance telemetry.
|
| 165 |
+
- If the AMD VM is destroyed to save credits, the fallback demo remains available.
|
| 166 |
+
"""
|
| 167 |
+
)
|
| 168 |
+
|
| 169 |
+
|
| 170 |
+
if __name__ == "__main__":
|
| 171 |
+
demo.launch()
|
requirements.txt
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
gradio
|
| 2 |
+
requests
|