整体架构
AI Voice Platform 的核心运行链路由 5 个相互独立的服务/模块 组成,各自职责单一、协议清晰,可以单机起,也可以分布式部署。在这条媒体主链路之外,还有两个面向运营、与媒体路径解耦的子系统——管理控制台与智能外呼,见本页「管理面与外呼面」。
1 | ┌────────────────────────────┐ |
组件职责矩阵
| 组件 | 角色 | 进程 | 主要协议 | 默认端口 |
|---|---|---|---|---|
| FreeSWITCH | 软交换、媒体处理、ESL | 第三方 | SIP / RTP / ESL | 5060 / RTP / 8021 |
| mod_audio_fork | 把通话音频从 FreeSWITCH 桥接出去 | FS 内 | WebSocket(子协议 audio.drachtio.org) |
跟随上游 |
| callflow-esl | 业务编排:ESL 入站 + HTTP 外呼 API | Bun | ESL TCP / HTTP | 9911 / 9912 |
| sherpa-asr-online-server | 流式 ASR + VAD | C++ | WebSocket | 10096 |
| sherpa-tts-server | 离线 TTS + wav 缓存与下载 | C++ | HTTP | 9080 |
四条主数据流
1. 呼入流程(用户拨进来)
1 | SIP INVITE |
2. 呼出流程(业务发起外呼)
1 | HTTP POST /outbound-calls (callflow-esl) |
3. 实时识别流程(hear / callHear)
1 | business: ctx.hear({...}) |
callHear 是 hear 的”长连接”版本——整通通话保持 audio_fork,业务通过 onResult / onFinal 回调驱动。
4. TTS 播报流程(speak)
apps/callflow-esl/config.json 的 tts.streamingEnabled 决定走哪条链路:
普通链路(streamingEnabled=false):
1 | business: ctx.speak({ kind: "tts", text: "..." }) |
流式链路(streamingEnabled=true):
1 | business: ctx.speak({ kind: "tts", text: "..." }) |
文本+speakerId+speed 相同的合成会命中文件级缓存,第二次请求直接返回已有 wavUrl,零合成开销。
管理面与外呼面
除上面的媒体主链路外,仓库还提供两个面向运营、与通话媒体路径解耦的子系统:
| 组件 | 角色 | 进程 | 协议 | 默认端口 |
|---|---|---|---|---|
| callflow-server | 管理台 API:运行时配置 / FreeSWITCH 数据视图 / TTS 试听代理 | Bun | HTTP | 9913 |
| callflow-webpage | 管理控制台前端(看板 / 表浏览 / 配置 / 音色试听) | Quasar | HTTP(dev) | 19913 |
| callout-server | 外呼任务 API:活动 / 名单 / 批次调度 / 角色鉴权 / 坐席 / 转人工会议 / 策略 / 回铃音 + 嘟声检测 / 线路号码池 | Bun | HTTP + inbound ESL | 9920 |
| callout-webpage | 外呼管理前端 | Quasar | HTTP(dev) | 19920 |
| emotion-analysis-server | 通话后情绪分析(文本 BERT + 音频 wav2vec2),由 callout 后台调用 | C++ | HTTP | 9090 |
- 管理控制台(callflow-server + callflow-webpage)把运行时 TTS / 录音配置写进
callflow-esl 同一套callflowschema,再通过POST /runtime-configs/reload通知
callflow-esl 热重载;同时只读浏览 FreeSWITCH 数据库、管理号码 → 业务路由、试听 TTS
音色。详见 管理控制台。 - 智能外呼(callout-server + callout-webpage)直接连 FreeSWITCH inbound ESL 批量
originate,接通后复用同一套 dialplan socket 把通话送回 callflow-esl 执行业务:
1 | callout-webpage → callout-server |
调度、并发、工作时段、重试、回铃音 + 嘟声检测、角色鉴权、坐席工作台、转人工会议
(盲转 / 协商转 / 主管监听·插话)、外呼策略与 DNC,以及通话后情绪分析(后台 worker
调用 情绪分析服务 的 POST /analyze)详见 智能外呼。
端口与协议矩阵
| 源 | 目标 | 协议 | 端口 | 用途 |
|---|---|---|---|---|
| SIP UAC | FreeSWITCH | SIP/UDP | 5060 | 呼入 |
| FreeSWITCH | callflow-esl | TCP | 9911 | outbound ESL(dialplan socket) |
| callflow-esl | FreeSWITCH | TCP | 8021 | inbound ESL(originate) |
| 调用方 | callflow-esl | HTTP | 9912 | POST /outbound-calls |
| FreeSWITCH (mod_audio_fork) | ASR Server | WebSocket | 10096 | /audio 路径,子协议 audio.drachtio.org |
| callflow-esl | TTS Server | HTTP | 9080 | POST /tts |
| FreeSWITCH | TTS Server | HTTP | 9080 | GET /wav/<file> 播放 |
| 任意 | ASR Server | HTTP | 10096 | GET /health |
| callflow-esl | PostgreSQL | TCP | 5432 | 业务路由与运行时配置 |
| 浏览器 | callflow-server | HTTP | 9913 | 管理控制台 API |
| callflow-server | PostgreSQL / FreeSWITCH DB | TCP | 5432 | 运行时配置 + FS 数据视图 |
| 浏览器 | callout-server | HTTP | 9920 | 外呼管理 API |
| callout-server | FreeSWITCH | TCP | 8021 | inbound ESL(批量 originate) |
| callout-server | emotion-analysis-server | HTTP | 9090 | 通话后情绪分析 POST /analyze(可选) |
ASR 与 TTS 服务没有鉴权。生产环境务必置于内网或加反代鉴权层,参见 部署。
业务编排分层
callflow-esl 内部分三层,自上而下:
1 | ┌───────────────────────────────────────────────┐ |
业务层只看 CallContext,不直接碰 ESL 命令;Runtime 层负责把抽象命令翻译成 ESL execute / sendmsg / event 订阅;ESL 层负责协议序列化。
资源解耦
各组件之间无强耦合,可灵活替换:
| 想换什么 | 怎么做 |
|---|---|
| ASR 引擎 | 实现兼容 mod_audio_fork 子协议的 WebSocket 服务即可(参见 ASR 服务 协议章节) |
| TTS 引擎 | 实现 POST /tts 返回 { wavUrl } 的 HTTP 服务即可 |
| 业务编排 | 直接用裸 ESL 自行实现;或在 callflow-esl 里新增业务函数 |
| 模型 | 替换 models/ 下对应目录与配置中的路径,无需改代码 |
| 软交换 | 任何支持媒体桥接到 WebSocket 的 PBX;本项目以 FreeSWITCH 为最小验证集 |