Skip to content

Commit 207fc85

Browse files
committed
feat: add traffic-vlm-analysis skill for city CCTV
7 analysis modes with tailored VLM prompt templates: - traffic_accident, crowd_anomaly, suspicious_behavior - wrong_way, road_obstruction, fire_smoke, full_scan Features: - Sensitivity levels (low/medium/high) adjusting VLM strictness - Language support: English, Burmese, or bilingual output - Camera location context injection into prompts - YOLO pre-filter: only sends frames to VLM when trigger objects detected - Frame throttle (configurable FPS) to manage VLM token cost - Full Aegis JSONL stdin/stdout protocol compliance - Zero extra Python dependencies (stdlib urllib only) - Standalone test script for prompt validation per mode - deploy.sh with prompt module sanity check Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DXvYppU6bAHzS9R8HbTHdN
1 parent e686009 commit 207fc85

6 files changed

Lines changed: 752 additions & 0 deletions

File tree

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
---
2+
name: traffic-vlm-analysis
3+
description: "Traffic & public safety VLM analysis — accident, anomaly, and crowd detection using vision-language models"
4+
version: 1.0.0
5+
category: analysis
6+
runtime: python
7+
entry: scripts/analyze.py
8+
install: pip
9+
10+
requirements:
11+
python: ">=3.9"
12+
platforms: ["linux", "macos", "windows"]
13+
14+
parameters:
15+
- name: analysis_mode
16+
label: "Analysis Mode"
17+
type: select
18+
options:
19+
- "traffic_accident"
20+
- "crowd_anomaly"
21+
- "suspicious_behavior"
22+
- "wrong_way"
23+
- "road_obstruction"
24+
- "fire_smoke"
25+
- "full_scan"
26+
default: "full_scan"
27+
description: "Focus the VLM on a specific threat type, or run all checks at once"
28+
group: Analysis
29+
30+
- name: sensitivity
31+
label: "Sensitivity"
32+
type: select
33+
options: ["low", "medium", "high"]
34+
default: "medium"
35+
description: "low = only obvious incidents | high = flag edge cases and near-misses"
36+
group: Analysis
37+
38+
- name: fps
39+
label: "Processing FPS"
40+
type: select
41+
options: [0.1, 0.2, 0.5, 1, 2]
42+
default: 0.5
43+
description: "Frames per second sent to VLM — VLM is slower than YOLO, keep low"
44+
group: Performance
45+
46+
- name: min_confidence
47+
label: "Min Confidence to Report"
48+
type: number
49+
min: 0.1
50+
max: 1.0
51+
default: 0.6
52+
description: "Suppress incidents below this confidence score"
53+
group: Analysis
54+
55+
- name: yolo_prefilter
56+
label: "YOLO Pre-filter"
57+
type: boolean
58+
default: true
59+
description: "Only send frames to VLM when YOLO detects relevant objects (saves VLM tokens)"
60+
group: Performance
61+
62+
- name: camera_location
63+
label: "Camera Location Description"
64+
type: string
65+
default: ""
66+
description: "e.g. 'Intersection of Main St and 5th Ave, downtown' — injected into VLM prompt for context"
67+
group: Analysis
68+
69+
- name: language
70+
label: "Report Language"
71+
type: select
72+
options: ["english", "burmese", "both"]
73+
default: "english"
74+
description: "Language for incident descriptions in VLM output"
75+
group: Analysis
76+
77+
capabilities:
78+
live_detection:
79+
script: scripts/analyze.py
80+
description: "Real-time VLM scene analysis for traffic and public safety"
81+
---
82+
83+
# Traffic VLM Analysis
84+
85+
Real-time traffic and public safety scene analysis using Vision-Language Models (VLMs). Runs on top of the Aegis camera frame pipeline and outputs structured incident events.
86+
87+
## What It Detects
88+
89+
| Mode | Examples |
90+
|------|---------|
91+
| `traffic_accident` | Collisions, overturned vehicles, post-crash debris |
92+
| `crowd_anomaly` | Stampedes, unusually dense crowds, dispersal events |
93+
| `suspicious_behavior` | Loitering, package abandonment, erratic movement |
94+
| `wrong_way` | Vehicles driving against traffic |
95+
| `road_obstruction` | Stopped vehicles blocking lanes, fallen objects |
96+
| `fire_smoke` | Visible flames, smoke plumes from vehicles or structures |
97+
| `full_scan` | All of the above in one pass |
98+
99+
## Sensitivity Levels
100+
101+
| Level | Behavior |
102+
|-------|---------|
103+
| `low` | Only clear, confirmed incidents (fewer false positives) |
104+
| `medium` | Balanced — flags near-misses and developing situations |
105+
| `high` | Flags edge cases, unusual patterns, and potential precursors |
106+
107+
## VLM Compatibility
108+
109+
Works with any OpenAI-compatible vision endpoint:
110+
- **Local:** Qwen-VL, LLaVA, DeepSeek-VL, SmolVLM (via llama-server or Ollama)
111+
- **Cloud:** GPT-4o Vision, Claude Sonnet (vision), Gemini Pro Vision
112+
113+
## Protocol
114+
115+
### Aegis → Skill (stdin)
116+
```jsonl
117+
{"event": "frame", "frame_id": 42, "camera_id": "cam_001", "frame_path": "/tmp/frame.jpg", "timestamp": "2026-07-01T10:30:00Z", "width": 1920, "height": 1080}
118+
```
119+
120+
### Skill → Aegis (stdout)
121+
```jsonl
122+
{"event": "ready", "model": "qwen-vl", "mode": "full_scan", "sensitivity": "medium", "fps": 0.5}
123+
124+
{"event": "analysis", "frame_id": 42, "camera_id": "cam_001", "timestamp": "...",
125+
"incident_detected": true,
126+
"incident_type": "traffic_accident",
127+
"severity": "high",
128+
"confidence": 0.91,
129+
"description": "Two-vehicle collision detected at intersection. One vehicle has crossed the center line. Airbags may have deployed.",
130+
"objects": ["car", "truck"],
131+
"suggested_action": "Dispatch emergency services",
132+
"skipped_reason": null}
133+
134+
{"event": "analysis", "frame_id": 43, "camera_id": "cam_001", "timestamp": "...",
135+
"incident_detected": false, "skipped_reason": "no_trigger_objects"}
136+
137+
{"event": "error", "message": "VLM endpoint unreachable", "retriable": true}
138+
```
139+
140+
### Stop Command
141+
```jsonl
142+
{"command": "stop"}
143+
```
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
"""
2+
Traffic VLM prompt templates.
3+
4+
Each prompt is a system message instructing the VLM to return a specific JSON schema.
5+
The `build()` function assembles the final system + user messages for a given mode.
6+
"""
7+
8+
# ---------------------------------------------------------------------------
9+
# Shared JSON schema instruction (appended to every system prompt)
10+
# ---------------------------------------------------------------------------
11+
_SCHEMA = """
12+
Respond ONLY with a valid JSON object. No markdown, no extra text.
13+
Schema:
14+
{
15+
"incident_detected": <bool>,
16+
"incident_type": <one of: "traffic_accident"|"crowd_anomaly"|"suspicious_behavior"|"wrong_way"|"road_obstruction"|"fire_smoke"|"other"|null>,
17+
"severity": <"low"|"medium"|"high"|"critical"|null>,
18+
"confidence": <float 0.0-1.0>,
19+
"description": <string, 1-3 sentences, factual>,
20+
"objects": <list of detected relevant objects, e.g. ["car","truck","person"]>,
21+
"suggested_action": <string or null>
22+
}
23+
If no incident is detected, set incident_detected=false and all other fields to null.
24+
"""
25+
26+
# ---------------------------------------------------------------------------
27+
# Sensitivity preambles
28+
# ---------------------------------------------------------------------------
29+
_SENSITIVITY = {
30+
"low": (
31+
"Report ONLY clear, confirmed incidents that are already happening. "
32+
"Do not flag near-misses, ambiguous situations, or normal traffic congestion."
33+
),
34+
"medium": (
35+
"Report confirmed incidents AND developing situations (near-misses, vehicles slowing abnormally, "
36+
"crowds beginning to gather). Use your judgment on ambiguous cases."
37+
),
38+
"high": (
39+
"Report any unusual pattern, near-miss, potential precursor to an incident, "
40+
"or behavior that deviates from normal traffic flow. Err on the side of flagging."
41+
),
42+
}
43+
44+
# ---------------------------------------------------------------------------
45+
# Mode-specific system prompts
46+
# ---------------------------------------------------------------------------
47+
_MODE_PROMPTS = {
48+
"traffic_accident": """You are a traffic accident detection AI monitoring a city CCTV camera.
49+
Analyze the frame for:
50+
- Vehicle collisions (rear-end, side-impact, head-on)
51+
- Overturned or heavily damaged vehicles
52+
- Vehicles stopped in unusual positions after impact
53+
- Post-crash debris on the road
54+
- Pedestrians injured or struck by vehicles
55+
- Motorcycles or bicycles involved in crashes
56+
Ignore: normal traffic stops, parked cars, minor fender-benders with no safety impact.""",
57+
58+
"crowd_anomaly": """You are a crowd safety AI monitoring a city CCTV camera.
59+
Analyze the frame for:
60+
- Stampedes or crowds moving in panic
61+
- Abnormally dense crowd concentration (crush risk)
62+
- Sudden crowd dispersal (possible fight or threat nearby)
63+
- People falling or being trampled
64+
- Blocked emergency access routes
65+
- Crowd gathering around an incident
66+
Ignore: normal pedestrian traffic, bus stops, markets with expected density.""",
67+
68+
"suspicious_behavior": """You are a public safety AI monitoring a city CCTV camera.
69+
Analyze the frame for:
70+
- Individuals loitering in restricted or unusual areas for extended periods
71+
- Abandoned bags, packages, or objects left unattended
72+
- Erratic or aggressive movement between individuals
73+
- Individuals surveilling or photographing infrastructure suspiciously
74+
- Groups confronting or surrounding another person
75+
- Individuals climbing fences, walls, or restricted structures
76+
Ignore: people waiting normally, street vendors, delivery personnel.""",
77+
78+
"wrong_way": """You are a wrong-way vehicle detection AI monitoring a city CCTV camera.
79+
Analyze the frame for:
80+
- Vehicles driving against the flow of traffic
81+
- Vehicles entering one-way streets in the wrong direction
82+
- Vehicles reversing on highways or main roads
83+
- Vehicles driving on sidewalks or pedestrian areas
84+
Use lane markings, traffic signals, and the direction of other vehicles as reference.
85+
Ignore: emergency vehicles, reversing in parking areas.""",
86+
87+
"road_obstruction": """You are a road obstruction detection AI monitoring a city CCTV camera.
88+
Analyze the frame for:
89+
- Vehicles stopped and blocking one or more lanes
90+
- Fallen cargo, debris, or objects on the road
91+
- Construction equipment or materials blocking traffic
92+
- Broken-down vehicles in live traffic lanes
93+
- Flooding or road damage blocking passage
94+
- Pedestrians or animals on the road in dangerous positions
95+
Ignore: normal traffic queues, vehicles stopped at red lights.""",
96+
97+
"fire_smoke": """You are a fire and smoke detection AI monitoring a city CCTV camera.
98+
Analyze the frame for:
99+
- Visible flames from vehicles, buildings, or roadside objects
100+
- Smoke plumes (black, grey, or white) from any source
101+
- Burning debris on the road
102+
- Smoke rising from underground (manhole fires)
103+
- Vehicles on fire or smoldering
104+
Report even small fires or initial smoke as they can escalate rapidly.""",
105+
106+
"full_scan": """You are a comprehensive city traffic and public safety AI monitoring a CCTV camera.
107+
In a single pass, analyze the frame for ANY of the following:
108+
1. TRAFFIC ACCIDENTS — collisions, overturned vehicles, injured pedestrians
109+
2. CROWD ANOMALIES — stampedes, dangerous density, panic dispersal
110+
3. SUSPICIOUS BEHAVIOR — loitering, abandoned objects, confrontations
111+
4. WRONG-WAY VEHICLES — driving against traffic or on restricted areas
112+
5. ROAD OBSTRUCTIONS — blocked lanes, debris, breakdowns
113+
6. FIRE & SMOKE — flames or smoke from any source
114+
Report the MOST SEVERE incident if multiple are present.
115+
Classify the incident_type accurately based on the primary threat.""",
116+
}
117+
118+
119+
def build(
120+
mode: str,
121+
sensitivity: str,
122+
camera_location: str = "",
123+
language: str = "english",
124+
) -> tuple[str, str]:
125+
"""
126+
Build (system_prompt, user_message) for a given analysis mode.
127+
128+
Returns:
129+
system_prompt: Full system instruction with schema
130+
user_message: Frame-specific user turn
131+
"""
132+
base = _MODE_PROMPTS.get(mode, _MODE_PROMPTS["full_scan"])
133+
sens = _SENSITIVITY.get(sensitivity, _SENSITIVITY["medium"])
134+
135+
location_ctx = f"\nCamera location: {camera_location}" if camera_location else ""
136+
137+
lang_instruction = ""
138+
if language == "burmese":
139+
lang_instruction = "\nWrite the 'description' and 'suggested_action' fields in Burmese (Myanmar language)."
140+
elif language == "both":
141+
lang_instruction = "\nWrite the 'description' field as: English description first, then '|' separator, then Burmese translation."
142+
143+
system_prompt = f"{base}\n\nSensitivity level: {sens}{location_ctx}{lang_instruction}\n\n{_SCHEMA}"
144+
145+
user_message = "Analyze this camera frame and return the JSON response."
146+
147+
return system_prompt, user_message
148+
149+
150+
def get_available_modes() -> list[str]:
151+
return list(_MODE_PROMPTS.keys())
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#!/bin/bash
2+
# Deploy script for traffic-vlm-analysis skill.
3+
# No special dependencies — VLM is called over HTTP.
4+
set -e
5+
6+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
7+
8+
echo "[traffic-vlm-analysis] Deploy check..."
9+
python3 -c "import sys, json, base64, urllib.request, pathlib; print(' stdlib OK')"
10+
python3 -c "
11+
import sys
12+
sys.path.insert(0, '$SCRIPT_DIR/assets/prompts')
13+
from prompts import get_available_modes
14+
print(f' prompts OK — {len(get_available_modes())} modes: {get_available_modes()}')
15+
"
16+
echo "[traffic-vlm-analysis] Ready."
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# No extra dependencies — uses only Python stdlib (urllib, base64, json, signal)
2+
# The VLM runs externally via HTTP (Aegis gateway or local llama-server)

0 commit comments

Comments
 (0)