pratheek-c/RapidResponse
GitHub: pratheek-c/RapidResponse
基于 AWS Nova Sonic 的市政级 911 智能接警调度平台,实现实时语音分诊、事件分类和人机协同调度。
Stars: 0 | Forks: 0
# RapidResponse.ai
[](https://github.com/your-org/rapidresponse)
[](LICENSE)
[](https://bun.sh)
[](https://aws.amazon.com/bedrock/)
## 概述
RapidResponse.ai 是一个市政级 911 紧急响应平台,AI 语音代理 (AWS Bedrock Nova Sonic 2) 通过 Web 界面自主处理打入的紧急电话。该代理对呼叫者进行分类,通过 RAG 遵循协议驱动的问题询问,按类型和优先级对事件进行分类,并实时向人工调度员显示可操作的数据。
**核心功能:**
- 通过 WebSocket 进行实时双向语音通话 —— 呼叫者可使用任意浏览器进行语音通话
- AWS Nova Sonic 2 (Bedrock) 完全自主处理呼叫者交互
- 实时转录按话语逐条保存至 libSQL (Turso)
- 紧急协议 (MPDS 风格) 以向量形式存储在 LanceDB 中;每次通话均通过 RAG 进行查询
- 事件分类:类型 (医疗 / 火灾 / 执法 / 危险品 / 其他) 和优先级 1–5
- LanceDB 中的 S2 几何索引,用于快速查询呼叫者位置邻近度
- 原始音频录音存储在 AWS S3 中
- React/TypeScript 调度员仪表板,包含实时事件源、单位追踪器和完整通话回放
## 架构
```
┌─────────────────────────────────────────────────────────────────┐
│ Caller (Browser) │
│ Web app — microphone → AudioWorklet │
└──────────────────────────┬──────────────────────────────────────┘
│ WebSocket (PCM audio stream)
▼
┌─────────────────────────────────────────────────────────────────┐
│ RapidResponse.ai Backend │
│ Bun + TypeScript monolith │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ WebSocket Call Handler │ │
│ │ - Streams audio to AWS Bedrock Nova Sonic 2 │ │
│ │ - Receives AI audio response, streams back to caller │ │
│ │ - Extracts transcript turns in real time │ │
│ └────────────┬──────────────────────┬──────────────────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────────────┐ ┌──────────────────────────────┐ │
│ │ Nova Sonic Agent │ │ Incident Service │ │
│ │ - System prompt │ │ - Create/update incident │ │
│ │ - Tool use: │ │ - Classify type + priority │ │
│ │ classify_incident│ │ - Assign units │ │
│ │ get_protocol │ │ - Push SSE to dashboard │ │
│ │ dispatch_unit │ └──────────────────────────────┘ │
│ └─────────────────────┘ │
│ │
│ ┌──────────────┐ ┌────────────────┐ ┌─────────────────┐ │
│ │ libSQL │ │ LanceDB │ │ AWS S3 │ │
│ │ (Turso) │ │ + S2 Geometry │ │ Audio storage │ │
│ │ incidents │ │ protocols │ │ recordings/ │ │
│ │ transcripts │ │ incidents │ │ {incident_id}/ │ │
│ │ units │ │ locations │ │ *.webm │ │
│ │ dispatches │ │ │ │ │ │
│ └──────────────┘ └────────────────┘ └─────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ REST API (Express-style) │ │
│ │ GET/POST /incidents GET/POST /units POST /dispatch │ │
│ │ GET /incidents/:id/transcript GET /protocols │ │
│ └──────────────────────────────────────────────────────────┘ │
└──────────────────────────┬──────────────────────────────────────┘
│ REST + SSE
▼
┌─────────────────────────────────────────────────────────────────┐
│ Dispatcher Dashboard (React / TS) │
│ - Live incident board (SSE) │
│ - Call transcript panel + audio playback │
│ - Unit map tracker │
│ - Manual dispatch controls │
└─────────────────────────────────────────────────────────────────┘
```
## 技术栈
| 层级 | 技术 | 用途 |
|---|---|---|
| Runtime | [Bun](https://bun.sh) | 快速 TypeScript 后端运行时 |
| 语言 | TypeScript (strict) | 全栈类型安全 |
| 语音 AI | AWS Bedrock Nova Sonic 2 | 双向语音代理 |
| 嵌入 | AWS Bedrock Titan Embeddings v2 | 协议 + 事件向量化 |
| 向量数据库 | [LanceDB](https://lancedb.com) + S2 | 协议 RAG,位置邻近度搜索 |
| 关系型数据库 | [libSQL / Turso](https://turso.tech) | 事件、转录、单位、调度 |
| 音频存储 | AWS S3 | 原始通话录音 |
| 前端 | React 18 + TypeScript + Vite | 调度员仪表板 |
| HTTP/WS 服务器 | Bun native HTTP + `ws` | WebSocket 通话处理 + REST API |
| 部署 | AWS ECS (Fargate) + ALB | 容器化后端 |
## 项目结构
```
rapidresponse/
├── package.json # Root — Bun workspace config
├── bunfig.toml # Bun configuration
├── .env.example # All required environment variables
├── README.md
├── AGENTS.md # AI agent / OpenCode context
├── .opencode/
│ └── skills/ # OpenCode skill definitions
│ ├── ingest-protocols.md
│ ├── seed-db.md
│ ├── run-migrations.md
│ ├── build-docker.md
│ └── deploy-ecs.md
│
├── backend/
│ ├── package.json
│ ├── tsconfig.json
│ ├── src/
│ │ ├── index.ts # Entry point — starts Bun server
│ │ ├── server.ts # HTTP server, WebSocket upgrade, SSE
│ │ ├── agents/
│ │ │ └── novaAgent.ts # Nova Sonic bidirectional stream handler
│ │ ├── services/
│ │ │ ├── transcriptionService.ts # Save transcript turns to libSQL
│ │ │ ├── incidentService.ts # Incident CRUD + classification
│ │ │ ├── dispatchService.ts # Unit assignment logic
│ │ │ ├── storageService.ts # S3 audio upload/download
│ │ │ └── ragService.ts # LanceDB vector search
│ │ ├── db/
│ │ │ ├── libsql.ts # Turso client, schema types
│ │ │ ├── migrations/ # SQL migration files (numbered)
│ │ │ │ ├── 001_initial.sql
│ │ │ │ └── 002_add_indexes.sql
│ │ │ └── lancedb.ts # LanceDB init, collection schemas
│ │ ├── routes/
│ │ │ ├── incidents.ts # GET/POST /incidents
│ │ │ ├── units.ts # GET/POST /units
│ │ │ ├── dispatch.ts # POST /dispatch
│ │ │ ├── protocols.ts # GET /protocols
│ │ │ └── recordings.ts # GET /recordings/:incidentId
│ │ └── types/
│ │ └── index.ts # Shared TypeScript types
│ ├── protocols/ # Upload emergency protocol docs here
│ │ └── .gitkeep
│ └── scripts/
│ ├── ingest.ts # bun run ingest:protocols
│ ├── seed.ts # bun run db:seed
│ └── migrate.ts # bun run db:migrate
│
└── frontend/
├── package.json
├── tsconfig.json
├── vite.config.ts
├── index.html
└── src/
├── main.tsx
├── App.tsx
├── components/
│ ├── IncidentBoard.tsx # Live active incidents list
│ ├── IncidentCard.tsx # Single incident card with priority badge
│ ├── CallPanel.tsx # Transcript viewer + audio playback
│ ├── UnitTracker.tsx # Unit status map/table
│ ├── PriorityBadge.tsx # Color-coded priority 1–5 badge
│ ├── CallerView.tsx # Browser UI for caller — mic + status
│ └── DispatchControls.tsx # Assign unit to incident
├── hooks/
│ ├── useIncidentFeed.ts # SSE subscription to live incidents
│ ├── useCallSession.ts # WebSocket audio session management
│ └── useUnits.ts # Units polling/state
└── types/
└── index.ts # Frontend TypeScript types
```
## 前置条件
- [Bun](https://bun.sh) >= 1.1.0
- 启用了 Bedrock 访问权限的 AWS 账户 (在您的区域启用了 Nova Sonic 2 + Titan Embeddings v2)
- [Turso CLI](https://docs.turso.tech/cli/installation) 和一个 Turso 数据库
- 用于存储录音的 AWS S3 存储桶
- Docker (用于部署)
## 环境变量
将 `.env.example` 复制到 `.env` 并填写所有值。
```
cp .env.example .env
```
| 变量 | 服务 | 描述 |
|---|---|---|
| `AWS_REGION` | AWS | 启用 Bedrock 的区域 (例如 `us-east-1`) |
| `AWS_ACCESS_KEY_ID` | AWS | 具有 Bedrock + S3 权限的 IAM 访问密钥 |
| `AWS_SECRET_ACCESS_KEY` | AWS | IAM 密钥 |
| `BEDROCK_NOVA_SONIC_MODEL_ID` | Bedrock | Nova Sonic 模型 ID (例如 `amazon.nova-sonic-v2:0`) |
| `BEDROCK_TITAN_EMBED_MODEL_ID` | Bedrock | Titan Embeddings 模型 ID |
| `TURSO_DATABASE_URL` | libSQL | Turso 数据库 URL (`libsql://...`) |
| `TURSO_AUTH_TOKEN` | libSQL | Turso 认证令牌 |
| `S3_BUCKET_NAME` | S3 | 音频录音的存储桶名称 |
| `S3_RECORDINGS_PREFIX` | S3 | 对象键前缀 (默认: `recordings/`) |
| `LANCEDB_PATH` | LanceDB | LanceDB 数据目录的本地路径 (默认: `./data/lancedb`) |
| `PORT` | 服务器 | HTTP 服务器端口 (默认: `3000`) |
| `FRONTEND_URL` | 服务器 | 仪表板允许的 CORS 源 |
## 设置与安装
### 1. 安装依赖
```
bun install
```
这会同时安装根工作区、`backend/` 和 `frontend/` 的依赖。
### 2. 初始化数据库
```
bun run db:migrate
```
按顺序针对您的 Turso 数据库运行 `backend/src/db/migrations/` 中的所有 SQL 迁移。
### 3. 初始化 LanceDB 集合
LanceDB 集合在首次启动时自动创建。无需手动设置。
### 4. 导入紧急协议文档
将您的协议文档 (PDF、TXT 或 Markdown) 放置在 `backend/protocols/` 中,然后运行:
```
bun run ingest:protocols
```
这将切分文档,通过 Bedrock Titan 生成嵌入,并将其更新插入到 LanceDB 的 `protocols` 集合中。
### 5. (可选) 填充测试数据
```
bun run db:seed
```
使用样本事件、单位和调度记录填充 libSQL,以便进行本地开发。
## 本地运行
同时运行后端和前端:
```
bun run dev
```
或者分别运行:
```
# 仅 Backend
bun run dev:backend
# 仅 Frontend
bun run dev:frontend
```
| 服务 | URL |
|---|---|
| 后端 HTTP + WebSocket | `http://localhost:3000` |
| 调度员仪表板 | `http://localhost:5173` |
| 呼叫者 Web 应用 | `http://localhost:5173/call` |
## 脚本参考
所有脚本均从项目根目录运行。
| 脚本 | 描述 |
|---|---|
| `bun run dev` | 以监视模式启动后端 + 前端 |
| `bun run dev:backend` | 仅以监视模式启动后端 |
| `bun run dev:frontend` | 启动前端 (Vite 开发服务器) |
| `bun run build` | 构建生产环境的后端和前端 |
| `bun run build:backend` | 编译后端 TypeScript |
| `bun run build:frontend` | Vite 生产环境构建 |
| `bun run db:migrate` | 运行所有待处理的 SQL 迁移 |
| `bun run db:status` | 显示迁移状态 |
| `bun run db:seed` | 用开发测试数据填充数据库 |
| `bun run ingest:protocols` | 将协议文档导入 LanceDB |
| `bun run test` | 使用 Bun 测试运行器运行所有测试 |
| `bun run test:backend` | 仅运行后端测试 |
| `bun run lint` | 运行 TypeScript 编译器检查 (无输出) |
## API 参考
### WebSocket —— 通话会话
**端点:** `ws://host/call`
呼叫者的浏览器打开一个 WebSocket 连接。音频以二进制帧 (PCM 16-bit, 16kHz, mono) 形式流式传输。服务器以相同格式的二进制帧流式传回 AI 音频响应。
| 方向 | 格式 | 描述 |
|---|---|---|
| 客户端 → 服务器 | Binary (PCM) | 麦克风音频块 |
| 客户端 → 服务器 | JSON 文本 | `{ type: "call_start", location: "...", callerId: "..." }` |
| 客户端 → 服务器 | JSON 文本 | `{ type: "call_end" }` |
| 服务器 → 客户端 | Binary (PCM) | Nova Sonic 音频响应 |
| 服务器 → 客户端 | JSON 文本 | `{ type: "transcript", speaker: "caller\|ai", text: "...", timestamp: "..." }` |
| 服务器 → 客户端 | JSON 文本 | `{ type: "incident_created", incidentId: "...", priority: 1-5, classification: "..." }` |
### REST API
#### 事件
| 方法 | 路径 | 描述 |
|---|---|---|
| `GET` | `/incidents` | 列出所有事件 (查询: `?status=active`) |
| `GET` | `/incidents/:id` | 获取单个事件的完整详情 |
| `GET` | `/incidents/:id/transcript` | 获取事件的完整记录 |
| `POST` | `/incidents` | 手动创建事件 |
| `PATCH` | `/incidents/:id` | 更新事件状态或优先级 |
#### 单位
| 方法 | 路径 | 描述 |
|---|---|---|
| `GET` | `/units` | 列出所有单位及其当前状态 |
| `POST` | `/units` | 注册一个新单位 |
| `PATCH` | `/units/:id` | 更新单位状态或位置 |
#### 调度
| 方法 | 路径 | 描述 |
|---|---|---|
| `POST` | `/dispatch` | 将单位分配给事件 `{ incidentId, unitId }` |
| `PATCH` | `/dispatch/:id/arrive` | 标记单位已到达现场 |
| `PATCH` | `/dispatch/:id/clear` | 将单位从事件中解除 |
#### 协议
| 方法 | 路径 | 描述 |
|---|---|---|
| `GET` | `/protocols` | 列出所有已导入的协议文档 |
| `GET` | `/protocols/search?q=...` | 通过查询进行协议向量搜索 |
#### 录音
| 方法 | 路径 | 描述 |
|---|---|---|
| `GET` | `/recordings/:incidentId` | 列出某个事件的 S3 音频文件 |
| `GET` | `/recordings/:incidentId/url` | 获取用于播放的预签名 S3 URL |
### Server-Sent Events
**端点:** `GET /events`
调度员仪表板订阅此 SSE 流以获取实时更新。
| 事件 | 负载 |
|---|---|
| `incident_created` | 完整事件对象 |
| `incident_updated` | `{ id, changes }` |
| `unit_updated` | 完整单位对象 |
| `transcript_turn` | `{ incidentId, speaker, text, timestamp }` |
## 数据模型
### libSQL (Turso) —— 结构化数据
```
-- Active and historical incidents
CREATE TABLE incidents (
id TEXT PRIMARY KEY,
caller_id TEXT,
type TEXT NOT NULL, -- medical | fire | law | hazmat | other
priority INTEGER NOT NULL, -- 1 (critical) to 5 (low)
status TEXT NOT NULL, -- active | dispatched | resolved | closed
location TEXT, -- Free-text address extracted by AI
lat REAL,
lng REAL,
s2_cell_id TEXT, -- S2 cell token for LanceDB proximity
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);
-- Per-utterance transcript log
CREATE TABLE transcriptions (
id TEXT PRIMARY KEY,
incident_id TEXT NOT NULL REFERENCES incidents(id),
speaker TEXT NOT NULL, -- caller | ai
text TEXT NOT NULL,
timestamp TEXT NOT NULL
);
-- Emergency response units
CREATE TABLE units (
id TEXT PRIMARY KEY,
name TEXT NOT NULL, -- e.g. "Engine 7", "Unit 42"
type TEXT NOT NULL, -- police | fire | ems | hazmat
status TEXT NOT NULL, -- available | dispatched | on_scene | off_duty
lat REAL,
lng REAL,
updated_at TEXT NOT NULL
);
-- Dispatch assignments
CREATE TABLE dispatches (
id TEXT PRIMARY KEY,
incident_id TEXT NOT NULL REFERENCES incidents(id),
unit_id TEXT NOT NULL REFERENCES units(id),
dispatched_at TEXT NOT NULL,
arrived_at TEXT,
cleared_at TEXT
);
```
### LanceDB —— 向量集合
| 集合 | 模式 | 用途 |
|---|---|---|
| `protocols` | `id, source_file, section, chunk_text, embedding, metadata` | 紧急协议 RAG |
| `incidents_history` | `id, summary, type, priority, embedding, s2_cell_id` | 历史事件模式匹配 |
| `locations` | `id, address, lat, lng, s2_cell_id, embedding` | 地理空间邻近度搜索 |
### S3 —— 对象布局
```
s3://{S3_BUCKET_NAME}/
└── recordings/
└── {incident_id}/
├── audio_{timestamp}.webm # Raw caller audio chunk
└── transcript.json # Final transcript export
```
## 部署
### 前置条件
- 已安装 Docker 并通过 AWS ECR 认证
- 已配置部署凭证的 AWS CLI
- 已创建的 ECS 集群、任务定义和服务
- 存储在 AWS Secrets Manager 或 ECS 任务定义中的环境变量
### 步骤
1. **构建并推送 Docker 镜像:**
bun run docker:build
bun run docker:push
2. **注册新的 ECS 任务定义修订版** (更新任务定义 JSON 中的镜像 URI,然后):
aws ecs register-task-definition --cli-input-json file://infra/task-definition.json
3. **强制执行新的 ECS 部署:**
aws ecs update-service \
--cluster rapidresponse-cluster \
--service rapidresponse-backend \
--force-new-deployment
4. **监控部署:**
aws ecs wait services-stable \
--cluster rapidresponse-cluster \
--services rapidresponse-backend
### 所需 IAM 权限
ECS 任务角色必须具有:
```
{
"bedrock:InvokeModel",
"bedrock:InvokeModelWithResponseStream",
"s3:PutObject",
"s3:GetObject",
"s3:ListBucket"
}
```
## 贡献
### 分支命名
```
feature/short-description
fix/short-description
chore/short-description
```
### 提交风格
遵循 [Conventional Commits](https://www.conventionalcommits.org/):
```
feat: add unit proximity dispatch logic
fix: handle Nova Sonic stream disconnect gracefully
chore: update protocol ingestion chunk size
```
### PR 检查清单
- [ ] `bun run lint` 通过 (无 TypeScript 错误)
- [ ] `bun run test` 通过
- [ ] 新环境变量已添加到 `.env.example`
- [ ] 新数据库列有对应的迁移文件
- [ ] 新协议字段已记录在 AGENTS.md 中
## 许可证
MIT —— 详见 [LICENSE](LICENSE)
标签:911紧急调度, AI语音代理, AWS Nova Sonic, AWS S3, Bedrock, Bun运行时, IP 地址批量处理, LanceDB, libSQL, MPDS协议, RAG技术, React仪表盘, S2几何索引, Turso, TypeScript, WebSocket通信, 事件分类, 云原生架构, 公共安全, 危险品处理, 双向通话, 向量数据库, 安全插件, 实时语音分诊, 实时转录, 应急响应系统, 执法调度, 智慧政务, 消防调度, 紧急医疗服务, 自动语音识别