Architecture
The agent pipeline runs in parallel tracks:Speech-to-Text (STT)
Implementation:app/agents/stt_client.py
Deepgram Integration
DispatchAI uses Deepgram Nova-2 for real-time transcription:Callback System
Transcripts update in real-time via callbacks: Partial transcripts (interim results):app/api/ws/handler.py:328-341, app/main.py:467
Emotion Detection
Implementation:app/agents/emotion.py
Emotion analysis combines acoustic distress with text sentiment.
Provider Options
Choose viaEMOTION_PROVIDER environment variable:
1. Heuristic (Default)
When to use: No API key available or need instant results Method: Rule-based keyword matching + distress score- Add keywords to
life_threatening,neg_keywords,pos_keywords - Adjust distress thresholds (lines 42-48)
- Modify intensity boost factors (lines 76-77, 98)
app/agents/emotion.py:27-116
2. Deepgram Sentiment
When to use: Already using Deepgram for STT, want accurate sentiment Method: Deepgram Text Intelligence API- Adjust crisis keyword list (lines 172-185)
- Modify fusion thresholds (lines 204-238)
app/agents/emotion.py:119-251
3. OpenAI LLM
When to use: Highest accuracy, don’t mind API cost Method: GPT-4o-mini structured classification- Edit system prompt (lines 264-272)
- Change model via
OPENAI_MODEL_EMOTIONenv var - Adjust temperature (line 291)
app/agents/emotion.py:254-331
Emotion Labels
All providers output one of these labels:| Label | Intensity Range | Description |
|---|---|---|
CALM | 0.0 - 0.15 | Normal conversation, no stress |
RELIEVED | 0.15 - 0.3 | Positive emotions, gratitude |
TENSE | 0.15 - 0.3 | Mild stress, concern |
DISTRESSED | 0.3 - 0.7 | Elevated stress, fear |
HIGHLY_DISTRESSED | 0.7 - 1.0 | Extreme stress, panic |
Service Classification
Implementation:app/agents/service_classify.py
Classifies calls into emergency service categories with semantic tags.
Categories
- EMS: Heart attack, overdose, trauma, breathing problems
- FIRE: Structure fire, gas leak, smoke, explosion
- POLICE: Active shooter, assault, burglary, domestic violence
- OTHER: Noise complaint, lost pet, non-emergency
Classification Logic
Uses keyword detection with contextual rules:app/agents/service_classify.py:8-1192
Semantic Tags
Over 60 tags across four domains: Medical (EMS):ACTIVE_SHOOTER- Gunshot woundsSTABBING- Knife/blade injuriesMAJOR_BLEEDING- Severe hemorrhageNOT_BREATHING- Respiratory arrestCARDIAC_ARREST- No pulse/heartbeatOVERDOSE- Drug/poison ingestionUNCONSCIOUS- Unresponsive patientSTROKE- Neurological emergencySEIZURE- Convulsions
FIRE- Structure fireSMOKE- Smoke detectedGAS_LEAK- Natural gas/propaneEXPLOSION- Blast/detonationHAZMAT- Chemical spill
VIOLENCE- Physical altercationASSAULT- Attacking someoneDOMESTIC_VIOLENCE- Partner abuseWEAPON_INVOLVED- Gun/knife presentROBBERY- Armed robberyBURGLARY- Breaking and enteringSUICIDAL- Suicide threat
VEHICLE_ACCIDENT- Car crashTRAPPED- Stuck in elevator/buildingEMOTIONAL_DISTRESS- Mental healthNOISE_COMPLAINT- Non-emergency
Customizing Keywords
Add your own detection rules:app/agents/service_classify.py
Negation Detection
Avoids false positives from negative statements:- ✅ “He’s bleeding” →
BLEEDINGtag - ❌ “He’s not bleeding” → No tag
app/agents/service_classify.py:45-71
ASR Error Normalization
Common speech-to-text mistakes are fixed:app/agents/service_classify.py:1195-1235
Summary Generation
Implementation:app/agents/summary.py
Creates dispatcher-friendly 1-2 sentence summaries.
OpenAI Mode
“Caller reports an active shooter at a shopping mall. Multiple victims with gunshot wounds. Police and EMS needed urgently.”File:
app/agents/summary.py:41-83
Heuristic Fallback
When no API key is available:“There’s someone in my house with a gun and I’m hiding in the closet…”File:
app/agents/summary.py:14-38
Risk Scoring
Implementation:app/main.py:224-321
Combines multiple signals into a unified risk assessment.
Scoring Algorithm
Risk Levels
| Level | Score Range | Description | Example |
|---|---|---|---|
CRITICAL | 0.7 - 1.0 | Life-threatening, immediate response | Active shooter, cardiac arrest |
ELEVATED | 0.4 - 0.7 | Serious emergency, urgent response | Assault, breathing difficulty |
NORMAL | 0.15 - 0.4 | Standard emergency, timely response | Minor injury, property crime |
LOW | 0.0 - 0.15 | Non-emergency, routine response | Noise complaint, lost item |
Customizing Risk Thresholds
Adjust score thresholds incompute_risk_level():
app/main.py:224-321
Priority Ranking
Implementation:app/ranking/ranking.py
Converts risk levels into queue priorities.
app/ranking/ranking.py, app/main.py:741-750
Testing Agents
Unit Tests
Manual Testing
Use the call replay script:Live Testing
Make a test call and check real-time processing:- Start dev server:
./scripts/dev_start.sh - Call your Telnyx number
- Speak test scenario: “Help, there’s a fire in my kitchen!”
- Monitor logs:
Performance Tuning
Latency Optimization
Use faster STT:.env
Accuracy Optimization
Use best providers:.env
service_classify.py with domain-specific terms.
Tune thresholds:
Adjust risk score thresholds based on historical data.
Next Steps
API Reference
Explore REST endpoints and data schemas
Quickstart
Build your first integration