Real-time emergency incident monitoring and visualization for Austin and Travis County, Texas. This application combines public incident data with live radio dispatch audio to provide comprehensive situational awareness for fire, medical, and traffic incidents.
- Real-time Incident Tracking - Live updates from Austin Open Data Portal and Broadcastify radio calls
- Interactive Map - MapLibre GL-powered map with incident markers, clustering, and user location tracking
- Live Dispatch Audio - Integration with Broadcastify Calls API for live radio communications
- AI-Powered Transcript Processing - Deepgram transcribes audio, GPT-4o-mini extracts structured data (addresses, units, call types)
- Smart Geocoding - Intelligent address parsing with multiple fallback providers to handle transcription errors
- Concurrent Processing - Parallel batch transcription (20 requests at once) for ultra-fast incident loading
- Split-Panel Interface - Resizable sidebar with incident list and full-screen map view
- Advanced Filtering - Filter by status, date range, agency, and search terms
- Dark/Light Theme - Automatic theme detection with manual toggle
- Audio Playback - Built-in player for dispatch call recordings
- Incident Banners - Animated notifications for new incidents
- Incident Replay - Re-inject past incidents to review and test alerts
- Resolution Time Estimation - AI-powered predictions for incident resolution based on type and severity
- Unit Tracking - Automatic extraction of responding units (Engine 5, Medic 12, etc.)
- Channel Identification - Parse radio channels and tactical frequencies
- Address Normalization - Handle common OCR/transcription errors in dispatch audio
- Priority Sorting - High-priority incidents processed first for faster display
Frontend
- Next.js 15 - React framework with App Router
- React 19 - UI library
- TypeScript 5 - Type safety
- Tailwind CSS 4 - Utility-first styling
- shadcn/ui - Component library
- MapLibre GL - Interactive maps
- Turbopack - Fast bundler
Backend
- Supabase - PostgreSQL database, Edge Functions, Realtime subscriptions
- Next.js API Routes - Serverless functions
- Server-Sent Events (SSE) - Real-time streaming
- Deepgram API - Speech-to-text transcription (Nova-2 model)
- OpenAI API - GPT-4o-mini for transcript parsing
- jsonwebtoken - JWT authentication for Broadcastify
- pg_cron - Background job scheduling
Data Sources
- Austin Open Data Portal - Fire/rescue/traffic incidents
- Broadcastify Calls API - Live radio dispatch audio
- Nominatim - Primary geocoding service
- Maps.co - Fallback geocoding with dual-key support
- Node.js 20+ and pnpm 9+
- Supabase account (free tier is sufficient)
- Supabase CLI (
npm install -g supabase) - Broadcastify API credentials (API Key ID, Secret, App ID)
- Deepgram API key (free tier: 45,000 minutes/month)
- OpenAI API key (for GPT-4o-mini transcript parsing)
- Broadcastify account (username/password for authenticated API access)
git clone https://github.com/yourusername/austin-fire-map.git
cd austin-fire-mappnpm install# Login to Supabase
supabase login
# Link to your project (or create new one)
supabase link --project-ref YOUR_PROJECT_REF
# Run database migrations
supabase db pushSee SUPABASE_DEPLOYMENT.md for detailed setup instructions.
Create a .env.local file in the project root:
# Supabase Configuration
# Obtain from: https://supabase.com/dashboard/project/_/settings/api
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_anon_key
SUPABASE_SERVICE_ROLE_KEY=your_service_role_key
# Broadcastify API Credentials
# Obtain from: https://www.broadcastify.com/developer
BROADCASTIFY_API_KEY_ID=your_api_key_id
BROADCASTIFY_API_KEY_SECRET=your_api_key_secret
BROADCASTIFY_APP_ID=your_app_id
# Deepgram API Key (Free tier available)
# Obtain from: https://console.deepgram.com/
DEEPGRAM_API_KEY=your_deepgram_api_key
# OpenAI API Key (for transcript parsing)
# Obtain from: https://platform.openai.com/api-keys
OPENAI_API_KEY=sk-your-openai-api-key
# Optional: Geocoding API Keys (for fallback geocoding)
GEOCODING_API_KEY=your_mapsco_api_key
GEOCODING_API_KEY_2=your_mapsco_api_key_2pnpm run devOpen http://localhost:3000 to view the application.
| Command | Description |
|---|---|
pnpm run dev |
Start development server with Turbopack hot reload |
pnpm run build |
Create production build |
pnpm run start |
Start production server (requires build first) |
pnpm run lint |
Run ESLint code quality checks |
- View Map - Incidents appear as colored markers (red=fire, blue=medical, yellow=traffic)
- Filter Incidents - Use sidebar filters for status, date range, or search
- Click Marker - View detailed incident information
- Play Audio - Click audio button to hear dispatch call recording
- Track Location - Enable location tracking to see your position
Click the settings icon to configure:
- Data Source - Toggle between Austin Open Data and Broadcastify Calls
- Auto-refresh Interval - Set polling frequency (15s to 5min)
- Show Banner - Enable/disable new incident notifications
- Active Groups - Select which radio channels to monitor
For testing or review:
- Open incident details in sidebar
- Click "Replay" button
- Incident will be re-injected as new with banner animation
βββββββββββββββββββββββββββββββββββββββββββββββββββ
β Supabase Infrastructure β
β β
β ββββββββββββββββββββββββββββββββββββββββββββ β
β β pg_cron (runs every 60 seconds) β β
β β β β β
β β Edge Function: process-calls β β
β ββββββββββββββββββββββββββββββββββββββββββββ β
β β β
βββββββββββββββββββββββ¬ββββββββββββββββββββββββββββ
β
ββββββββββββββΌβββββββββββββ
β β
βΌ βΌ
βββββββββββββββββββ βββββββββββββββββββ
β Broadcastify β β Next.js API β
β Calls API β β Route (SSE) β
ββββββββββ¬βββββββββ ββββββββββ¬βββββββββ
β β
βββΊ JWT Auth β
βββΊ Fetch Live Calls β
β β
βΌ βΌ
βββββββββββββββββββ βββββββββββββββββββ
β Deepgram API ββββββββ€ Process Audio β
β (Transcription) β β & Transcripts β
ββββββββββ¬βββββββββ ββββββββββ¬βββββββββ
β β
βββΊ Parallel Processing β
β (20 concurrent) β
β β
βΌ βΌ
βββββββββββββββββββ βββββββββββββββββββ
β OpenAI API ββββββββ€ Parse Data: β
β (GPT-4o-mini) β β - Call types β
ββββββββββ¬βββββββββ β - Units β
β β - Addresses β
β βββββββββββββββββββ
βΌ
βββββββββββββββββββ
β Geocoding β
β (Multi-source) β
ββββββββββ¬βββββββββ
β
βββΊ Nominatim (primary)
βββΊ Maps.co (fallback)
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββ
β Supabase PostgreSQL β
β β
β ββββββββββββββββββββββββββββββββββββββββββββ β
β β incidents table (with PostGIS) β β
β β worker_state table (track position) β β
β ββββββββββββββββββββββββββββββββββββββββββββ β
β β β
β ββββββββββββββββββββββββββββββββββββββββββββ β
β β Realtime (WebSocket subscriptions) β β
β ββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββ¬ββββββββββββββββββββββββββββ
β
βΌ
ββββββββββββββββββββββββββ
β Next.js Frontend β
β - Map rendering β
β - Filtering β
β - Realtime updates β
ββββββββββββββββββββββββββ
austin-fire-map/
βββ src/
β βββ app/
β β βββ page.tsx # Main application page
β β βββ layout.tsx # Root layout with theme provider
β β βββ api/
β β βββ broadcastify/
β β βββ live-calls/
β β βββ route.ts # SSE endpoint with parallel processing
β βββ components/
β β βββ IncidentMap.tsx # MapLibre GL map component
β β βββ IncidentsList.tsx # Sidebar with filtering
β β βββ CallBanner.tsx # New incident notifications
β β βββ SettingsDialog.tsx # Configuration UI
β β βββ LoadingScreen.tsx # Initial load animation
β β βββ ThemeToggle.tsx # Dark/light mode switcher
β β βββ ui/ # shadcn/ui components
β βββ lib/
β β βββ api.ts # useFireIncidents hook
β β βββ dispatch-parser.ts # GPT-4o-mini parsing logic
β β βββ broadcastify-jwt.ts # JWT token generation
β β βββ supabase.ts # Supabase client
β β βββ settings.ts # Settings persistence
β β βββ utils.ts # Utility functions
β βββ types/
β βββ incident.ts # Incident data types
β βββ broadcastify.ts # API response types
βββ supabase/
β βββ functions/
β β βββ process-calls/ # Edge Function for background processing
β β β βββ index.ts # Main function handler
β β β βββ deno.json # Deno configuration
β β βββ _shared/ # Shared utilities
β β βββ broadcastify-jwt.ts # JWT generation
β β βββ dispatch-parser.ts # Transcript parsing
β βββ migrations/
β β βββ 001_initial_schema.sql # Tables, indexes, RLS policies
β β βββ 002_setup_cron.sql # pg_cron job configuration
β βββ config.toml # Supabase project configuration
βββ public/ # Static assets
βββ .env.local # Environment variables (create this)
βββ package.json # Dependencies
βββ tsconfig.json # TypeScript configuration
βββ tailwind.config.js # Tailwind CSS configuration
βββ SUPABASE_DEPLOYMENT.md # Deployment guide
Austin/Travis County radio channels (configured in settings):
- Fire Dispatch A1:
2-3416 - Fire Dispatch A2:
2-3417 - Fire Dispatch A3:
2-3418 - Medical Dispatch M1:
2-3419 - Medical Dispatch M2:
2-3420
The application uses a two-stage AI pipeline:
-
Deepgram Nova-2 - Converts MP3 audio to text
- Real-time speed (~10x faster than Whisper)
- Smart formatting and punctuation
- Processes directly from URL (no download needed)
- Batch processing: 20 concurrent requests
-
OpenAI GPT-4o-mini - Extracts structured data from transcript
- Call types with proper title case
- Unit identification (Engine 5, Medic 12)
- Address parsing with error correction
- Channel extraction (F-TAC-203)
- Address variant generation for geocoding
Multi-provider fallback with rate limiting:
- Nominatim - Primary free service (1 req/sec)
- Maps.co Key 1 - First fallback (1 req/sec)
- Maps.co Key 2 - Second fallback (1 req/sec)
Each provider tries all address variants before moving to next provider.
- Broadcastify API: Maximum 1 request per 5 seconds (enforced by API)
- Deepgram API: 100 concurrent requests (using batch size of 20)
- Client Polling: Configurable interval (default 30 seconds)
- OpenAI API: Standard quota limits
- Nominatim: 1 request per second (enforced by client)
See CLAUDE.md for detailed development patterns including:
- Adding new incident fields
- Modifying dispatch parsing logic
- Changing map behavior
- Extending filter capabilities
Use test credentials provided in Broadcastify API docs:
# Standard User
Username: spook42069
Password: df7a0nqagl
# Premium Subscriber
Username: motion42069
Password: ef7a0n5a5mlTest JWT generation:
pnpm tsx src/lib/test-jwt.tsDebug SSE Connection:
# Terminal 1: Start dev server with logging
pnpm run dev
# Terminal 2: Monitor SSE endpoint
curl -N http://localhost:3000/api/broadcastify/live-calls?stream=1&init=1Test Geocoding:
// In browser console
fetch('/api/geocode?address=100 Main St, Austin, TX')
.then(r => r.json())
.then(console.log)Clear Local Storage:
// In browser console
localStorage.clear()
location.reload()Deploy the Edge Function and database:
# Deploy Edge Function
supabase functions deploy process-calls
# Configure Edge Function secrets
supabase secrets set BROADCASTIFY_API_KEY_ID=your_key
# ... (see SUPABASE_DEPLOYMENT.md for complete list)Then set up the cron job in the Supabase SQL Editor (see SUPABASE_DEPLOYMENT.md).
- Push code to GitHub
- Import project in Vercel Dashboard
- Add environment variables in project settings:
- Supabase URL and keys (3 variables)
- Broadcastify credentials (3 variables)
- Deepgram API key
- OpenAI API key
- Optional: Maps.co geocoding keys
- Deploy
For detailed instructions, see SUPABASE_DEPLOYMENT.md.
- SSE Connections: Browser limit of 6 concurrent EventSource connections
- Map Tiles: Consider MapTiler or Mapbox for production tile serving
- Geocoding: Multi-provider fallback reduces dependency on single service
- Transcription: Deepgram free tier provides 45k minutes/month
- Parsing: OpenAI GPT-4o-mini costs ~$0.0001 per call
- Batch Processing: 20 concurrent requests = 10-15x faster initial loads
For typical usage (monitoring 1-2 channels):
- Supabase: FREE (500MB database, 500k Edge Function invocations/month)
- Deepgram: FREE (45k min/month tier covers ~1500 incidents/day)
- OpenAI: ~$3-5/month (GPT-4o-mini parsing)
- Nominatim: FREE (community service)
- Maps.co: FREE tier or $10/month for higher limits
- Vercel: FREE (Hobby tier sufficient)
Total: $0-15/month depending on traffic and geocoding needs
The cron job running every 60 seconds = 43,200 invocations/month, well within Supabase's free tier.
MIT License - See LICENSE file for details
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
For issues and questions:
- Open an issue on GitHub
- Check
CLAUDE.mdfor architecture details - Review Broadcastify API documentation
- City of Austin - Open Data Portal
- Broadcastify/RadioReference - Live radio call data
- Deepgram - Fast, accurate speech-to-text transcription
- OpenAI - GPT-4o-mini for intelligent transcript parsing
- Austin Fire Department - Emergency response data
Built with β€οΈ for Austin/Travis County emergency services