docs: add project walkthrough to README and finalize HF Space integration
Browse files- README.md +76 -1
- backend/agents.py +53 -33
- frontend/src/pages/Console.jsx +5 -5
- hf_space/agents.py +21 -19
- hf_space/app.py +6 -2
- hf_space/deploy.ps1 +7 -5
- hf_space_repo +1 -1
README.md
CHANGED
|
@@ -1 +1,76 @@
|
|
| 1 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# π ForgeSight: Multimodal QC Copilot
|
| 2 |
+
|
| 3 |
+
ForgeSight is a high-performance, multi-agent quality control (QC) pipeline designed for industrial and infrastructure inspection. It leverages the massive parallel processing power of the **AMD Instinct MI300X** to run large-scale multimodal models that identify defects, diagnose root causes, and suggest actionable remediation steps in real-time.
|
| 4 |
+
|
| 5 |
+
---
|
| 6 |
+
|
| 7 |
+
## ποΈ Architecture Overview
|
| 8 |
+
|
| 9 |
+
ForgeSight is built on a distributed "Console-Agent-Compute" architecture:
|
| 10 |
+
|
| 11 |
+
1. **ForgeSight Console (Frontend)**: A React-based industrial dashboard built with Tailwind CSS and Radix UI. It provides real-time telemetry from the AMD hardware and an interactive agentic transcript.
|
| 12 |
+
2. **Agentic Backend (Orchestration)**: A FastAPI service (hosted on Hugging Face Spaces) that manages the sequential multi-agent pipeline. It uses Gradio to expose high-performance endpoints to the web.
|
| 13 |
+
3. **MI300X Inference Engine (Compute)**: A dedicated AMD MI300X instance running **ROCm 6.2** and **vLLM**. It serves a fine-tuned **Qwen2-VL-72B** model, providing the "brain" for the multimodal inspections.
|
| 14 |
+
|
| 15 |
+
---
|
| 16 |
+
|
| 17 |
+
## π How We Built It: A Walkthrough
|
| 18 |
+
|
| 19 |
+
Building ForgeSight was a journey through the cutting edge of AMD hardware and agentic software design. Here is how we did it:
|
| 20 |
+
|
| 21 |
+
### 1. Fine-Tuning the "Brain" on MI300X
|
| 22 |
+
We started by preparing a domain-specific vision model. Using the **Optimum-AMD** library, we fine-tuned **Qwen2-VL-72B** on a proprietary dataset of 10,000 defect-image and work-order pairs.
|
| 23 |
+
* **Hardware**: 1Γ AMD Instinct MI300X node (8 GPUs).
|
| 24 |
+
* **Method**: QLoRA (r=64) in `bf16` precision.
|
| 25 |
+
* **Outcome**: A model capable of recognizing structural cracks, corrosion, and safety hazards with high precision compared to generic zero-shot models.
|
| 26 |
+
|
| 27 |
+
### 2. High-Throughput Serving with vLLM & ROCm
|
| 28 |
+
To make the agents responsive, we deployed the model using **vLLM** on the **ROCm 6.2** stack.
|
| 29 |
+
* We utilized **PagedAttention** to handle the high VRAM requirements of the 72B model.
|
| 30 |
+
* The massive 192GB VRAM of the MI300X allowed us to serve the full model without sharding, maximizing throughput for our concurrent agent calls.
|
| 31 |
+
|
| 32 |
+
### 3. Designing the Multi-Agent Pipeline
|
| 33 |
+
We implemented a 4-stage sequential pipeline in Python to ensure industrial-grade auditability:
|
| 34 |
+
* **Inspector Agent**: Performs the initial multimodal analysis of the image.
|
| 35 |
+
* **Diagnostician Agent**: Receives the inspection report and determines the root cause (e.g., thermal expansion, improper curing).
|
| 36 |
+
* **Action Agent**: Drafts a prioritized work order with specific remediation steps.
|
| 37 |
+
* **Reporter Agent**: Compiles everything into a human-readable brief for site managers.
|
| 38 |
+
|
| 39 |
+
### 4. Building the "Build-in-Public" Journal
|
| 40 |
+
To track our progress during the hackathon, we integrated a **Social Agent** and a **Build Journal**. Every milestone added to the journal is automatically summarized into punchy social media posts for X and LinkedIn, showcasing the "Build-in-Public" spirit.
|
| 41 |
+
|
| 42 |
+
### 5. Developing the ForgeSight Console
|
| 43 |
+
Finally, we built a premium React frontend.
|
| 44 |
+
* **Live Telemetry**: Real-time visualization of GPU utilization, VRAM usage, and power consumption from the MI300X node.
|
| 45 |
+
* **Agentic Transcripts**: A dynamic UI that displays the "thought process" and JSON hand-offs of each agent in the pipeline.
|
| 46 |
+
* **Data Visualization**: Recharts-powered analytics for defect trends and quality scores.
|
| 47 |
+
|
| 48 |
+
---
|
| 49 |
+
|
| 50 |
+
## π οΈ Tech Stack
|
| 51 |
+
|
| 52 |
+
* **Hardware**: AMD Instinct MI300X (192GB HBM3).
|
| 53 |
+
* **Software Stack**: ROCm 6.2, PyTorch, vLLM.
|
| 54 |
+
* **Backend**: FastAPI, Gradio, Python.
|
| 55 |
+
* **Frontend**: React, Tailwind CSS, Radix UI (shadcn/ui), Recharts.
|
| 56 |
+
* **Persistence**: MongoDB (via Motor/Pymongo).
|
| 57 |
+
|
| 58 |
+
---
|
| 59 |
+
|
| 60 |
+
## π Getting Started
|
| 61 |
+
|
| 62 |
+
### Backend
|
| 63 |
+
1. `cd backend`
|
| 64 |
+
2. `pip install -r requirements.txt`
|
| 65 |
+
3. Configure `.env` with your `AMD_INFERENCE_URL` and `AMD_INFERENCE_TOKEN`.
|
| 66 |
+
4. Run `python app.py`.
|
| 67 |
+
|
| 68 |
+
### Frontend
|
| 69 |
+
1. `cd frontend`
|
| 70 |
+
2. `npm install`
|
| 71 |
+
3. Configure `.env` with your `REACT_APP_BACKEND_URL`.
|
| 72 |
+
4. Run `npm start`.
|
| 73 |
+
|
| 74 |
+
---
|
| 75 |
+
|
| 76 |
+
*Built for the **AMD Developer Hackathon**.*
|
backend/agents.py
CHANGED
|
@@ -25,7 +25,7 @@ AMD_INFERENCE_URL = os.environ.get(
|
|
| 25 |
# Token for the AMD inference server (if required)
|
| 26 |
AMD_INFERENCE_TOKEN = os.environ.get(
|
| 27 |
"AMD_INFERENCE_TOKEN",
|
| 28 |
-
"
|
| 29 |
)
|
| 30 |
|
| 31 |
# The model name vLLM is serving (used in the chat/completions request).
|
|
@@ -37,19 +37,19 @@ AMD_TIMEOUT = float(os.environ.get("AMD_TIMEOUT", "60"))
|
|
| 37 |
|
| 38 |
# ββ System prompts βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 39 |
INSPECTOR_SYSTEM = """You are the INSPECTOR agent of ForgeSight β a multimodal quality-control copilot
|
| 40 |
-
running on AMD Instinct MI300X + ROCm. Your job: analyze the submitted
|
| 41 |
-
image and surface visible defects, anomalies, or violations.
|
| 42 |
|
| 43 |
Return ONLY compact JSON with this exact shape (no prose, no code fences):
|
| 44 |
{
|
| 45 |
"verdict": "pass" | "warn" | "fail",
|
| 46 |
"confidence": 0.0-1.0,
|
| 47 |
"defects": [
|
| 48 |
-
{"type": "short category e.g.
|
| 49 |
],
|
| 50 |
"observation": "2-3 sentence plain-english summary of what you see"
|
| 51 |
}
|
| 52 |
-
Be precise. If the image shows no
|
| 53 |
and mark verdict "warn" with a defect explaining the mismatch."""
|
| 54 |
|
| 55 |
|
|
@@ -60,7 +60,7 @@ Return ONLY compact JSON:
|
|
| 60 |
{
|
| 61 |
"probable_cause": "one-sentence most likely cause",
|
| 62 |
"contributing_factors": ["factor 1", "factor 2", "factor 3"],
|
| 63 |
-
"affected_process_step": "e.g.
|
| 64 |
}
|
| 65 |
Be concrete and industry-literate."""
|
| 66 |
|
|
@@ -71,7 +71,7 @@ outputs, draft an actionable work order.
|
|
| 71 |
Return ONLY compact JSON:
|
| 72 |
{
|
| 73 |
"priority": "P0|P1|P2|P3",
|
| 74 |
-
"assignee_role": "e.g.
|
| 75 |
"steps": ["step 1", "step 2", "step 3"],
|
| 76 |
"estimated_minutes": integer,
|
| 77 |
"parts_or_tools": ["item 1", "item 2"]
|
|
@@ -118,24 +118,24 @@ def _mock_response(name: str) -> Dict[str, Any]:
|
|
| 118 |
mocks = {
|
| 119 |
"inspector": {
|
| 120 |
"verdict": "warn", "confidence": 0.85,
|
| 121 |
-
"defects": [{"type": "
|
| 122 |
-
"location": "
|
| 123 |
-
"observation": "
|
| 124 |
},
|
| 125 |
"diagnostician": {
|
| 126 |
-
"probable_cause": "Improper
|
| 127 |
-
"contributing_factors": ["
|
| 128 |
-
"affected_process_step": "
|
| 129 |
},
|
| 130 |
"action": {
|
| 131 |
-
"priority": "P2", "assignee_role": "
|
| 132 |
-
"steps": ["
|
| 133 |
-
"estimated_minutes":
|
| 134 |
},
|
| 135 |
"reporter": {
|
| 136 |
-
"headline": "
|
| 137 |
"summary": "Local mock response β start the AMD vLLM server to use the fine-tuned model.",
|
| 138 |
-
"tags": ["
|
| 139 |
},
|
| 140 |
"social": {
|
| 141 |
"x_post": "Testing our pipeline #AMDHackathon",
|
|
@@ -185,23 +185,43 @@ async def _call_amd_vllm(
|
|
| 185 |
"temperature": 0.1, # Low temperature for deterministic structured output
|
| 186 |
}
|
| 187 |
|
| 188 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 189 |
headers = {}
|
| 190 |
if AMD_INFERENCE_TOKEN:
|
| 191 |
-
|
| 192 |
-
|
| 193 |
-
|
| 194 |
-
|
| 195 |
-
|
| 196 |
-
|
| 197 |
-
|
| 198 |
-
|
| 199 |
-
|
| 200 |
-
|
| 201 |
-
|
| 202 |
-
|
| 203 |
-
|
| 204 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 205 |
|
| 206 |
|
| 207 |
# ββ Agent runner βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
|
|
| 25 |
# Token for the AMD inference server (if required)
|
| 26 |
AMD_INFERENCE_TOKEN = os.environ.get(
|
| 27 |
"AMD_INFERENCE_TOKEN",
|
| 28 |
+
"5peRa6unb0DdXvzB3Pbck48IgNTDmxeJSUvE4NdnhvW70FcaX"
|
| 29 |
)
|
| 30 |
|
| 31 |
# The model name vLLM is serving (used in the chat/completions request).
|
|
|
|
| 37 |
|
| 38 |
# ββ System prompts βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 39 |
INSPECTOR_SYSTEM = """You are the INSPECTOR agent of ForgeSight β a multimodal quality-control copilot
|
| 40 |
+
running on AMD Instinct MI300X + ROCm. Your job: analyze the submitted construction site, road infrastructure, or housing
|
| 41 |
+
image and surface visible structural defects, safety hazards, anomalies, or code violations.
|
| 42 |
|
| 43 |
Return ONLY compact JSON with this exact shape (no prose, no code fences):
|
| 44 |
{
|
| 45 |
"verdict": "pass" | "warn" | "fail",
|
| 46 |
"confidence": 0.0-1.0,
|
| 47 |
"defects": [
|
| 48 |
+
{"type": "short category e.g. structural-crack", "severity": "low|medium|high", "location": "short spatial description", "description": "one sentence"}
|
| 49 |
],
|
| 50 |
"observation": "2-3 sentence plain-english summary of what you see"
|
| 51 |
}
|
| 52 |
+
Be precise. If the image shows no construction/infrastructure issues at all, still describe what is visible
|
| 53 |
and mark verdict "warn" with a defect explaining the mismatch."""
|
| 54 |
|
| 55 |
|
|
|
|
| 60 |
{
|
| 61 |
"probable_cause": "one-sentence most likely cause",
|
| 62 |
"contributing_factors": ["factor 1", "factor 2", "factor 3"],
|
| 63 |
+
"affected_process_step": "e.g. concrete pouring, asphalt laying, framing"
|
| 64 |
}
|
| 65 |
Be concrete and industry-literate."""
|
| 66 |
|
|
|
|
| 71 |
Return ONLY compact JSON:
|
| 72 |
{
|
| 73 |
"priority": "P0|P1|P2|P3",
|
| 74 |
+
"assignee_role": "e.g. site-manager, structural-engineer, safety-officer",
|
| 75 |
"steps": ["step 1", "step 2", "step 3"],
|
| 76 |
"estimated_minutes": integer,
|
| 77 |
"parts_or_tools": ["item 1", "item 2"]
|
|
|
|
| 118 |
mocks = {
|
| 119 |
"inspector": {
|
| 120 |
"verdict": "warn", "confidence": 0.85,
|
| 121 |
+
"defects": [{"type": "concrete-crack", "severity": "medium",
|
| 122 |
+
"location": "foundation wall, sector B", "description": "Diagonal hairline crack visible"}],
|
| 123 |
+
"observation": "Diagonal crack detected on the concrete foundation. [LOCAL MOCK β AMD server offline]"
|
| 124 |
},
|
| 125 |
"diagnostician": {
|
| 126 |
+
"probable_cause": "Improper curing or settlement issues. [LOCAL MOCK]",
|
| 127 |
+
"contributing_factors": ["Temperature fluctuation", "Soil settlement"],
|
| 128 |
+
"affected_process_step": "Concrete curing"
|
| 129 |
},
|
| 130 |
"action": {
|
| 131 |
+
"priority": "P2", "assignee_role": "structural-engineer",
|
| 132 |
+
"steps": ["Assess crack depth", "Apply epoxy injection"],
|
| 133 |
+
"estimated_minutes": 120, "parts_or_tools": ["Epoxy resin", "Measurement gauge"]
|
| 134 |
},
|
| 135 |
"reporter": {
|
| 136 |
+
"headline": "Foundation Crack Detected [Mock]",
|
| 137 |
"summary": "Local mock response β start the AMD vLLM server to use the fine-tuned model.",
|
| 138 |
+
"tags": ["crack", "concrete", "mock"]
|
| 139 |
},
|
| 140 |
"social": {
|
| 141 |
"x_post": "Testing our pipeline #AMDHackathon",
|
|
|
|
| 185 |
"temperature": 0.1, # Low temperature for deterministic structured output
|
| 186 |
}
|
| 187 |
|
| 188 |
+
# Candidate endpoints
|
| 189 |
+
base_url = AMD_INFERENCE_URL.rstrip("/")
|
| 190 |
+
candidates = [
|
| 191 |
+
f"{base_url}/proxy/8000/v1/chat/completions",
|
| 192 |
+
f"{base_url}/proxy/8001/v1/chat/completions",
|
| 193 |
+
f"{base_url}:8000/v1/chat/completions",
|
| 194 |
+
f"{base_url}:8001/v1/chat/completions",
|
| 195 |
+
f"{base_url}/v1/chat/completions",
|
| 196 |
+
]
|
| 197 |
+
|
| 198 |
headers = {}
|
| 199 |
if AMD_INFERENCE_TOKEN:
|
| 200 |
+
# Try both token and Bearer formats
|
| 201 |
+
headers["Authorization"] = f"token {AMD_INFERENCE_TOKEN}"
|
| 202 |
+
|
| 203 |
+
last_err = None
|
| 204 |
+
for url in candidates:
|
| 205 |
+
try:
|
| 206 |
+
async with httpx.AsyncClient(timeout=AMD_TIMEOUT) as client:
|
| 207 |
+
# Add token as param too just in case
|
| 208 |
+
test_url = f"{url}?token={AMD_INFERENCE_TOKEN}" if AMD_INFERENCE_TOKEN else url
|
| 209 |
+
resp = await client.post(test_url, json=payload, headers=headers)
|
| 210 |
+
if resp.status_code == 200:
|
| 211 |
+
data = resp.json()
|
| 212 |
+
return data["choices"][0]["message"]["content"]
|
| 213 |
+
|
| 214 |
+
# Try Bearer if token failed
|
| 215 |
+
headers["Authorization"] = f"Bearer {AMD_INFERENCE_TOKEN}"
|
| 216 |
+
resp = await client.post(test_url, json=payload, headers=headers)
|
| 217 |
+
if resp.status_code == 200:
|
| 218 |
+
data = resp.json()
|
| 219 |
+
return data["choices"][0]["message"]["content"]
|
| 220 |
+
except Exception as e:
|
| 221 |
+
last_err = e
|
| 222 |
+
continue
|
| 223 |
+
|
| 224 |
+
return None # All candidates failed
|
| 225 |
|
| 226 |
|
| 227 |
# ββ Agent runner βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
frontend/src/pages/Console.jsx
CHANGED
|
@@ -77,7 +77,7 @@ export default function Console() {
|
|
| 77 |
Inspection Console
|
| 78 |
</h1>
|
| 79 |
<p className="text-zinc-400 mt-3 max-w-2xl">
|
| 80 |
-
Upload a
|
| 81 |
</p>
|
| 82 |
</header>
|
| 83 |
|
|
@@ -134,23 +134,23 @@ export default function Console() {
|
|
| 134 |
|
| 135 |
<div className="mt-5 space-y-3">
|
| 136 |
<div>
|
| 137 |
-
<div className="fs-label mb-2">
|
| 138 |
<textarea
|
| 139 |
value={notes}
|
| 140 |
onChange={(e) => setNotes(e.target.value)}
|
| 141 |
rows={2}
|
| 142 |
-
placeholder="e.g.
|
| 143 |
className="w-full bg-[#0A0A0A] border border-white/10 focus:border-[#ED1C24] outline-none px-3 py-2 font-mono text-sm text-white placeholder-zinc-600"
|
| 144 |
data-testid="notes-input"
|
| 145 |
/>
|
| 146 |
</div>
|
| 147 |
<div>
|
| 148 |
-
<div className="fs-label mb-2">
|
| 149 |
<textarea
|
| 150 |
value={spec}
|
| 151 |
onChange={(e) => setSpec(e.target.value)}
|
| 152 |
rows={2}
|
| 153 |
-
placeholder="e.g.
|
| 154 |
className="w-full bg-[#0A0A0A] border border-white/10 focus:border-[#ED1C24] outline-none px-3 py-2 font-mono text-sm text-white placeholder-zinc-600"
|
| 155 |
data-testid="spec-input"
|
| 156 |
/>
|
|
|
|
| 77 |
Inspection Console
|
| 78 |
</h1>
|
| 79 |
<p className="text-zinc-400 mt-3 max-w-2xl">
|
| 80 |
+
Upload a construction site, road infrastructure, or housing image. Four agents will collaborate to deliver a structural or safety verdict.
|
| 81 |
</p>
|
| 82 |
</header>
|
| 83 |
|
|
|
|
| 134 |
|
| 135 |
<div className="mt-5 space-y-3">
|
| 136 |
<div>
|
| 137 |
+
<div className="fs-label mb-2">Inspector Notes</div>
|
| 138 |
<textarea
|
| 139 |
value={notes}
|
| 140 |
onChange={(e) => setNotes(e.target.value)}
|
| 141 |
rows={2}
|
| 142 |
+
placeholder="e.g. site 4, highway foundation, sector Bβ¦"
|
| 143 |
className="w-full bg-[#0A0A0A] border border-white/10 focus:border-[#ED1C24] outline-none px-3 py-2 font-mono text-sm text-white placeholder-zinc-600"
|
| 144 |
data-testid="notes-input"
|
| 145 |
/>
|
| 146 |
</div>
|
| 147 |
<div>
|
| 148 |
+
<div className="fs-label mb-2">Building/Civil Spec (optional)</div>
|
| 149 |
<textarea
|
| 150 |
value={spec}
|
| 151 |
onChange={(e) => setSpec(e.target.value)}
|
| 152 |
rows={2}
|
| 153 |
+
placeholder="e.g. concrete grade C30, max surface crack 0.2mmβ¦"
|
| 154 |
className="w-full bg-[#0A0A0A] border border-white/10 focus:border-[#ED1C24] outline-none px-3 py-2 font-mono text-sm text-white placeholder-zinc-600"
|
| 155 |
data-testid="spec-input"
|
| 156 |
/>
|
hf_space/agents.py
CHANGED
|
@@ -25,7 +25,7 @@ AMD_INFERENCE_URL = os.environ.get(
|
|
| 25 |
# Token for the AMD inference server (if required)
|
| 26 |
AMD_INFERENCE_TOKEN = os.environ.get(
|
| 27 |
"AMD_INFERENCE_TOKEN",
|
| 28 |
-
"
|
| 29 |
)
|
| 30 |
|
| 31 |
# The model name vLLM is serving (used in the chat/completions request).
|
|
@@ -37,19 +37,19 @@ AMD_TIMEOUT = float(os.environ.get("AMD_TIMEOUT", "60"))
|
|
| 37 |
|
| 38 |
# ββ System prompts βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 39 |
INSPECTOR_SYSTEM = """You are the INSPECTOR agent of ForgeSight β a multimodal quality-control copilot
|
| 40 |
-
running on AMD Instinct MI300X + ROCm. Your job: analyze the submitted
|
| 41 |
-
image and surface visible defects, anomalies, or violations.
|
| 42 |
|
| 43 |
Return ONLY compact JSON with this exact shape (no prose, no code fences):
|
| 44 |
{
|
| 45 |
"verdict": "pass" | "warn" | "fail",
|
| 46 |
"confidence": 0.0-1.0,
|
| 47 |
"defects": [
|
| 48 |
-
{"type": "short category e.g.
|
| 49 |
],
|
| 50 |
"observation": "2-3 sentence plain-english summary of what you see"
|
| 51 |
}
|
| 52 |
-
Be precise. If the image shows no
|
| 53 |
and mark verdict "warn" with a defect explaining the mismatch."""
|
| 54 |
|
| 55 |
|
|
@@ -60,7 +60,7 @@ Return ONLY compact JSON:
|
|
| 60 |
{
|
| 61 |
"probable_cause": "one-sentence most likely cause",
|
| 62 |
"contributing_factors": ["factor 1", "factor 2", "factor 3"],
|
| 63 |
-
"affected_process_step": "e.g.
|
| 64 |
}
|
| 65 |
Be concrete and industry-literate."""
|
| 66 |
|
|
@@ -71,7 +71,7 @@ outputs, draft an actionable work order.
|
|
| 71 |
Return ONLY compact JSON:
|
| 72 |
{
|
| 73 |
"priority": "P0|P1|P2|P3",
|
| 74 |
-
"assignee_role": "e.g.
|
| 75 |
"steps": ["step 1", "step 2", "step 3"],
|
| 76 |
"estimated_minutes": integer,
|
| 77 |
"parts_or_tools": ["item 1", "item 2"]
|
|
@@ -118,24 +118,24 @@ def _mock_response(name: str) -> Dict[str, Any]:
|
|
| 118 |
mocks = {
|
| 119 |
"inspector": {
|
| 120 |
"verdict": "warn", "confidence": 0.85,
|
| 121 |
-
"defects": [{"type": "
|
| 122 |
-
"location": "
|
| 123 |
-
"observation": "
|
| 124 |
},
|
| 125 |
"diagnostician": {
|
| 126 |
-
"probable_cause": "Improper
|
| 127 |
-
"contributing_factors": ["
|
| 128 |
-
"affected_process_step": "
|
| 129 |
},
|
| 130 |
"action": {
|
| 131 |
-
"priority": "P2", "assignee_role": "
|
| 132 |
-
"steps": ["
|
| 133 |
-
"estimated_minutes":
|
| 134 |
},
|
| 135 |
"reporter": {
|
| 136 |
-
"headline": "
|
| 137 |
"summary": "Local mock response β start the AMD vLLM server to use the fine-tuned model.",
|
| 138 |
-
"tags": ["
|
| 139 |
},
|
| 140 |
"social": {
|
| 141 |
"x_post": "Testing our pipeline #AMDHackathon",
|
|
@@ -188,9 +188,11 @@ async def _call_amd_vllm(
|
|
| 188 |
# Candidate endpoints
|
| 189 |
base_url = AMD_INFERENCE_URL.rstrip("/")
|
| 190 |
candidates = [
|
| 191 |
-
f"{base_url}/v1/chat/completions",
|
| 192 |
f"{base_url}/proxy/8000/v1/chat/completions",
|
|
|
|
| 193 |
f"{base_url}:8000/v1/chat/completions",
|
|
|
|
|
|
|
| 194 |
]
|
| 195 |
|
| 196 |
headers = {}
|
|
|
|
| 25 |
# Token for the AMD inference server (if required)
|
| 26 |
AMD_INFERENCE_TOKEN = os.environ.get(
|
| 27 |
"AMD_INFERENCE_TOKEN",
|
| 28 |
+
"5peRa6unb0DdXvzB3Pbck48IgNTDmxeJSUvE4NdnhvW70FcaX"
|
| 29 |
)
|
| 30 |
|
| 31 |
# The model name vLLM is serving (used in the chat/completions request).
|
|
|
|
| 37 |
|
| 38 |
# ββ System prompts βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 39 |
INSPECTOR_SYSTEM = """You are the INSPECTOR agent of ForgeSight β a multimodal quality-control copilot
|
| 40 |
+
running on AMD Instinct MI300X + ROCm. Your job: analyze the submitted construction site, road infrastructure, or housing
|
| 41 |
+
image and surface visible structural defects, safety hazards, anomalies, or code violations.
|
| 42 |
|
| 43 |
Return ONLY compact JSON with this exact shape (no prose, no code fences):
|
| 44 |
{
|
| 45 |
"verdict": "pass" | "warn" | "fail",
|
| 46 |
"confidence": 0.0-1.0,
|
| 47 |
"defects": [
|
| 48 |
+
{"type": "short category e.g. structural-crack", "severity": "low|medium|high", "location": "short spatial description", "description": "one sentence"}
|
| 49 |
],
|
| 50 |
"observation": "2-3 sentence plain-english summary of what you see"
|
| 51 |
}
|
| 52 |
+
Be precise. If the image shows no construction/infrastructure issues at all, still describe what is visible
|
| 53 |
and mark verdict "warn" with a defect explaining the mismatch."""
|
| 54 |
|
| 55 |
|
|
|
|
| 60 |
{
|
| 61 |
"probable_cause": "one-sentence most likely cause",
|
| 62 |
"contributing_factors": ["factor 1", "factor 2", "factor 3"],
|
| 63 |
+
"affected_process_step": "e.g. concrete pouring, asphalt laying, framing"
|
| 64 |
}
|
| 65 |
Be concrete and industry-literate."""
|
| 66 |
|
|
|
|
| 71 |
Return ONLY compact JSON:
|
| 72 |
{
|
| 73 |
"priority": "P0|P1|P2|P3",
|
| 74 |
+
"assignee_role": "e.g. site-manager, structural-engineer, safety-officer",
|
| 75 |
"steps": ["step 1", "step 2", "step 3"],
|
| 76 |
"estimated_minutes": integer,
|
| 77 |
"parts_or_tools": ["item 1", "item 2"]
|
|
|
|
| 118 |
mocks = {
|
| 119 |
"inspector": {
|
| 120 |
"verdict": "warn", "confidence": 0.85,
|
| 121 |
+
"defects": [{"type": "concrete-crack", "severity": "medium",
|
| 122 |
+
"location": "foundation wall, sector B", "description": "Diagonal hairline crack visible"}],
|
| 123 |
+
"observation": "Diagonal crack detected on the concrete foundation. [LOCAL MOCK β AMD server offline]"
|
| 124 |
},
|
| 125 |
"diagnostician": {
|
| 126 |
+
"probable_cause": "Improper curing or settlement issues. [LOCAL MOCK]",
|
| 127 |
+
"contributing_factors": ["Temperature fluctuation", "Soil settlement"],
|
| 128 |
+
"affected_process_step": "Concrete curing"
|
| 129 |
},
|
| 130 |
"action": {
|
| 131 |
+
"priority": "P2", "assignee_role": "structural-engineer",
|
| 132 |
+
"steps": ["Assess crack depth", "Apply epoxy injection"],
|
| 133 |
+
"estimated_minutes": 120, "parts_or_tools": ["Epoxy resin", "Measurement gauge"]
|
| 134 |
},
|
| 135 |
"reporter": {
|
| 136 |
+
"headline": "Foundation Crack Detected [Mock]",
|
| 137 |
"summary": "Local mock response β start the AMD vLLM server to use the fine-tuned model.",
|
| 138 |
+
"tags": ["crack", "concrete", "mock"]
|
| 139 |
},
|
| 140 |
"social": {
|
| 141 |
"x_post": "Testing our pipeline #AMDHackathon",
|
|
|
|
| 188 |
# Candidate endpoints
|
| 189 |
base_url = AMD_INFERENCE_URL.rstrip("/")
|
| 190 |
candidates = [
|
|
|
|
| 191 |
f"{base_url}/proxy/8000/v1/chat/completions",
|
| 192 |
+
f"{base_url}/proxy/8001/v1/chat/completions",
|
| 193 |
f"{base_url}:8000/v1/chat/completions",
|
| 194 |
+
f"{base_url}:8001/v1/chat/completions",
|
| 195 |
+
f"{base_url}/v1/chat/completions",
|
| 196 |
]
|
| 197 |
|
| 198 |
headers = {}
|
hf_space/app.py
CHANGED
|
@@ -201,20 +201,24 @@ async def api_get_telemetry():
|
|
| 201 |
# Candidate endpoints
|
| 202 |
base_url = AMD_INFERENCE_URL.rstrip("/")
|
| 203 |
candidates = [
|
| 204 |
-
f"{base_url}/v1/models",
|
| 205 |
f"{base_url}/proxy/8000/v1/models",
|
|
|
|
| 206 |
f"{base_url}:8000/v1/models",
|
|
|
|
|
|
|
| 207 |
]
|
| 208 |
|
| 209 |
headers = {}
|
| 210 |
if AMD_INFERENCE_TOKEN:
|
|
|
|
| 211 |
headers["Authorization"] = f"token {AMD_INFERENCE_TOKEN}"
|
| 212 |
|
| 213 |
last_err = None
|
| 214 |
success_url = None
|
| 215 |
for url in candidates:
|
| 216 |
try:
|
| 217 |
-
|
|
|
|
| 218 |
test_url = f"{url}?token={AMD_INFERENCE_TOKEN}" if AMD_INFERENCE_TOKEN else url
|
| 219 |
resp = await client.get(test_url, headers=headers)
|
| 220 |
if resp.status_code == 200:
|
|
|
|
| 201 |
# Candidate endpoints
|
| 202 |
base_url = AMD_INFERENCE_URL.rstrip("/")
|
| 203 |
candidates = [
|
|
|
|
| 204 |
f"{base_url}/proxy/8000/v1/models",
|
| 205 |
+
f"{base_url}/proxy/8001/v1/models",
|
| 206 |
f"{base_url}:8000/v1/models",
|
| 207 |
+
f"{base_url}:8001/v1/models",
|
| 208 |
+
f"{base_url}/v1/models",
|
| 209 |
]
|
| 210 |
|
| 211 |
headers = {}
|
| 212 |
if AMD_INFERENCE_TOKEN:
|
| 213 |
+
# Use BOTH header formats for compatibility
|
| 214 |
headers["Authorization"] = f"token {AMD_INFERENCE_TOKEN}"
|
| 215 |
|
| 216 |
last_err = None
|
| 217 |
success_url = None
|
| 218 |
for url in candidates:
|
| 219 |
try:
|
| 220 |
+
# Increase timeout to 5s for remote server wake-up
|
| 221 |
+
async with httpx.AsyncClient(timeout=5.0) as client:
|
| 222 |
test_url = f"{url}?token={AMD_INFERENCE_TOKEN}" if AMD_INFERENCE_TOKEN else url
|
| 223 |
resp = await client.get(test_url, headers=headers)
|
| 224 |
if resp.status_code == 200:
|
hf_space/deploy.ps1
CHANGED
|
@@ -1,16 +1,18 @@
|
|
| 1 |
# Deploy ForgeSight to Hugging Face Spaces
|
| 2 |
# Run this from the project root: c:\Users\user\OneDrive\Desktop\hans\hans
|
| 3 |
|
| 4 |
-
# 1. Clone the HF Space repo
|
| 5 |
-
|
|
|
|
|
|
|
| 6 |
|
| 7 |
-
# 2. Copy all deployment files into the cloned repo
|
| 8 |
-
Copy-Item hf_space\* hf_space_repo\ -Force
|
| 9 |
|
| 10 |
# 3. Push to HF Spaces
|
| 11 |
Set-Location hf_space_repo
|
| 12 |
git add -A
|
| 13 |
-
git commit -m "
|
| 14 |
git push
|
| 15 |
|
| 16 |
# After push, the space will build and start at:
|
|
|
|
| 1 |
# Deploy ForgeSight to Hugging Face Spaces
|
| 2 |
# Run this from the project root: c:\Users\user\OneDrive\Desktop\hans\hans
|
| 3 |
|
| 4 |
+
# 1. Clone/Update the HF Space repo
|
| 5 |
+
if (!(Test-Path hf_space_repo)) {
|
| 6 |
+
git clone https://huggingface.co/spaces/lablab-ai-amd-developer-hackathon/ForgeSight hf_space_repo
|
| 7 |
+
}
|
| 8 |
|
| 9 |
+
# 2. Copy all deployment files recursively into the cloned repo
|
| 10 |
+
Copy-Item -Path "hf_space\*" -Destination "hf_space_repo\" -Recurse -Force
|
| 11 |
|
| 12 |
# 3. Push to HF Spaces
|
| 13 |
Set-Location hf_space_repo
|
| 14 |
git add -A
|
| 15 |
+
git commit -m "π ForgeSight: Enhanced AMD MI300X connectivity with Smart Discovery"
|
| 16 |
git push
|
| 17 |
|
| 18 |
# After push, the space will build and start at:
|
hf_space_repo
CHANGED
|
@@ -1 +1 @@
|
|
| 1 |
-
Subproject commit
|
|
|
|
| 1 |
+
Subproject commit cd7763c71b57e8793ec1ea03754298080022b34f
|