Files
live-call-asr-monitor/README.md
2026-07-16 14:18:43 +08:00

259 lines
7.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 实时通话 ASR 事件监控
一个基于 Spring Boot、React 和 AC 自动机的实时通话关键词监控系统。
前端持续提交市民与坐席的 ASR Final 文本,后端按通话维护上下文,匹配当前生效规则,并返回本次新增告警和通话累计结果。
## 主要功能
- 同时处理市民(`citizen`)和坐席(`agent`)文本
-`callId` 维护共享的最近 ASR Final 上下文
- AC 自动机多关键词高效匹配
- 同一通话、同一事件只首次告警
- `callId + seq` 请求幂等
- 页面化规则新增、编辑、启停、删除与热发布
- 新增规则自动生成稳定的事件 ID无需人工填写
- Excel 模板下载、规则导入和当前规则导出
- 历史版本查看与回溯;回溯旧内容时创建新版本
- 通话主动关闭与 TTL 自动清理
- H2 文件数据库持久化规则版本
## 技术栈
| 模块 | 技术 |
| --- | --- |
| 后端 | Java 21、Spring Boot 4、Spring MVC、Spring Data JPA |
| 匹配 | Aho-Corasick 自动机 |
| 数据库 | H2 文件数据库 |
| 前端 | React 19、TypeScript、Vite、Tailwind CSS、Motion |
| Excel | ExcelJS |
## 目录结构
```text
.
├── frontend/ # React 前端
├── src/main/java/com/example/demo/
│ ├── api/ # REST 接口
│ ├── application/ # 监控、规则和会话服务
│ ├── domain/ # 请求、响应和领域模型
│ ├── matcher/ # AC 自动机及匹配器
│ ├── repository/ # 规则版本和会话存储
│ ├── job/ # 过期会话清理
│ └── support/ # 异常、文本标准化等
├── src/main/resources/
│ ├── application.yml # 服务配置
│ └── rules/default-rules.json # 初始规则
└── pom.xml
```
## 本地运行
### 环境要求
- JDK 21
- Node.js 18 或更高版本
- npm
### 1. 启动后端
在项目根目录执行:
```bash
./mvnw spring-boot:run
```
后端默认地址:`http://localhost:8080`
健康检查:
```text
http://localhost:8080/actuator/health
```
### 2. 启动前端
另开一个终端:
```bash
cd frontend
npm install
npm run dev
```
访问:`http://localhost:3000`
开发环境下Vite 会将 `/api` 自动代理到 `http://localhost:8080`
## 打包为单个 Spring Boot JAR
先构建前端并复制静态文件:
```bash
cd frontend
npm install
npm run build
cd ..
cp -R frontend/dist/. src/main/resources/static/
```
再打包和启动后端:
```bash
./mvnw clean package
java -jar target/demo-0.0.1-SNAPSHOT.jar
```
访问:`http://localhost:8080`
## ASR 接口
提交一条 ASR Final
```http
POST /api/v1/asr-events
Content-Type: application/json
```
```json
{
"callId": "call-001",
"seq": 1,
"speaker": "citizen",
"text": "我的顺丰快递一直没有收到",
"final": true
}
```
`speaker` 只支持:
- `citizen`:市民
- `agent`:坐席
同一 `callId` 下,两个角色必须共享一套全局唯一的 `seq`
```text
seq 1 citizen 市民发言
seq 2 agent 坐席发言
seq 3 citizen 市民发言
seq 4 agent 坐席发言
```
响应中的主要字段:
- `newAlerts`:本次新触发、需要前端提醒的事件
- `currentResults`:该通话当前累计命中的事件
- `duplicate`:是否为重复的 `callId + seq`
- `activeRuleVersion`:本次匹配使用的规则版本
通话结束后应主动释放会话:
```http
POST /api/v1/calls/{callId}/close
```
## 算法流程
```mermaid
flowchart TD
A["接收 ASR 请求"] --> B{"final=true?"}
B -- 否 --> C["返回当前结果,不写入上下文"]
B -- 是 --> D{"callId + seq 是否重复?"}
D -- 是 --> E["返回 duplicate=true"]
D -- 否 --> F["写入该通话的共享上下文窗口"]
F --> G["拼接最近 N 条 Final"]
G --> H["文本标准化"]
H --> I["AC 自动机匹配全部关键词"]
I --> J["合并事件并进行通话级去重"]
J --> K["返回 newAlerts 和 currentResults"]
```
### 1. 通话隔离与并发
每个 `callId` 拥有独立会话状态和锁。同一通话按锁串行处理,不同通话可以并行处理。
### 2. 共享上下文窗口
市民和坐席文本进入同一个、按 `seq` 排序的最近 N 条窗口。默认保留 5 条,能够识别被 ASR 切分到相邻 Final 中的关键词。
### 3. 文本标准化
匹配前会进行 Unicode NFKC 标准化、转小写,并移除空白和常见中英文标点。例如:
```text
E M S → ems
顺丰,快递 → 顺丰快递
```
### 4. AC 自动机匹配
所有已启用关键词被一次性构建为不可变 AC 自动机快照。每条匹配文本只需扫描一次即可发现多个关键词,适合规则和关键词数量持续增加的场景。
### 5. 告警去重
匹配结果按业务事件聚合。同一个事件在同一次通话中只进入一次 `newAlerts`,重复命中仍保留在累计状态中,但不会重复提醒。
## 规则管理与版本回溯
规则保存采用完整文档发布,并携带 `baseVersion` 做乐观并发控制。事务提交成功后才切换运行时 AC 自动机快照。
主要接口:
| 方法 | 路径 | 说明 |
| --- | --- | --- |
| GET | `/api/v1/admin/rules` | 获取当前生效规则 |
| PUT | `/api/v1/admin/rules` | 保存并发布新版本 |
| GET | `/api/v1/admin/rules/versions?limit=20` | 获取历史版本 |
| POST | `/api/v1/admin/rules/versions/{version}/restore` | 回溯历史版本 |
回溯不会修改或删除旧记录。例如当前 V8 回溯到 V3系统会复制 V3 的内容并创建新的 V9然后切换 V9 为生效版本。
## 配置
主要配置位于 `src/main/resources/application.yml`
| 配置 | 默认值 | 说明 |
| --- | --- | --- |
| `server.port` | `8080` | HTTP 端口 |
| `monitor.recent-final-window-size` | `5` | 每通话保留的最近 Final 数量 |
| `monitor.max-processed-seqs` | `500` | 幂等序列号历史上限 |
| `monitor.session-ttl` | `PT2H` | 会话空闲过期时间 |
| `monitor.session-cleanup-interval` | `PT10M` | 过期会话清理周期 |
规则数据库默认保存在项目运行目录的 `data/rules.mv.db`
## 扩展性
### 扩展规则
直接通过前端页面或 Excel 导入新增关键词规则,无需修改匹配代码。发布后自动构建新快照并热切换。
### 扩展匹配算法
当前 `matcher``ac-keyword`。可以继续实现正则、语义分类或大模型匹配器,并通过统一的匹配接口进行组合。建议将确定性关键词匹配保持在同步主链路,将耗时模型调用放入异步链路。
### 扩展事件处理
可以在产生 `newAlerts` 后增加消息队列、WebSocket、工单、短信或外部系统通知。建议通过领域事件异步处理避免阻塞 ASR 接口。
### 扩展存储
开发环境使用 H2。生产环境可以迁移到 MySQL 或 PostgreSQLJPA 领域模型和服务层不需要大幅调整。
### 扩展为多实例部署
当前通话上下文保存在单机 JVM 内存。多实例部署时需要选择以下方案之一:
-`callId` 做一致性路由,保证同一通话始终进入同一实例
- 将会话上下文和幂等状态迁移到 Redis 等共享存储
- 使用分布式事件流按 `callId` 分区处理
### 安全与治理
生产环境建议增加管理员认证、规则变更审计、接口限流、数据库迁移工具,以及历史版本保留策略。
## 其他说明
- 前端对话中的关键词高亮是本地视觉提示。
- 真实告警始终以后端 `/api/v1/asr-events` 响应为准。
- 更完整的设计背景见 `asr_event_monitor_confirmed_technical_solution.md`