外观
开发测试手册(Windows 11)
本手册面向在 Windows 11 上进行日常开发与测试的场景。约定:除 FreeSWITCH 安装在虚拟机 外,本仓库的全部服务(ONNX C++ 服务、Bun 后端、Quasar 前端、NLU)都在本机 Win11 上启动运行, 以便快速联调。生产上线请改用 deployment-debian12.md。
阅读顺序:环境准备 → 依赖服务 → 虚拟机 FreeSWITCH 与网络约定 → 构建 C++ → 启动 → 冒烟测试 → 自动化测试(typecheck / bun test)→ 收尾关闭。
1. 拓扑与网络约定
text
┌──────────────── Windows 11 开发机 ───────────────┐ ┌──── 虚拟机 ────┐
│ ONNX: ASR 10096 / TTS 9080 / Emotion 9090 │ │ FreeSWITCH │
│ NLU 9930 callflow-esl 9911/9912 │◀──────▶│ 1.10.x │
│ callflow-server 9913 callout-server 9920 │ 局域网 │ mod_audio_fork│
│ callflow-webpage 19913 callout-webpage 19920 │ │ ESL 8021 │
│ PostgreSQL 5432 Redis 6379 Ollama 11434 │ └────────────────┘
└──────────────────────────────────────────────────┘关键约束:FreeSWITCH 与开发机之间必须双向可达。
- 本机 → 虚拟机:
callflow-esl/callout-server的freeswitch.host:8021(inbound ESL)、 以及录音静态访问地址要指向虚拟机 IP。 - 虚拟机 → 本机:FreeSWITCH 需回连开发机的
- outbound socket:
callbackHost:callbackPort(默认9911) - ASR 推流:
audioFork.wsUrl(默认ws://<开发机IP>:10096/audio) - TTS 播放:
sherpa-tts-server的publicBaseUrl/ 返回的 wav/mp3 URL
- outbound socket:
因此配置里不能用 127.0.0.1 作为回连地址。建议把虚拟机网卡设为桥接模式(或 NAT + 端口转发),让开发机与虚拟机在同一网段,然后把上述三处地址统一填成开发机的局域网 IP (ipconfig 查看)。Windows 防火墙需放通 9911 / 10096 / 9080(以及 TTS 短文件名静态端口)。
校验:在虚拟机上
curl http://<开发机IP>:10096/health与curl http://<开发机IP>:9080/health能通,才说明回连链路可用。
2. 环境准备(一次性)
2.1 必备工具
- Bun 1.x —— 所有 TS/前端服务的运行时。
bun --version验证。 - Visual Studio 2022(含 "使用 C++ 的桌面开发" 工作负载)+ CMake —— 构建 ONNX C++ 服务。
- PowerShell(仓库脚本默认 shell,使用
$null/$env:VAR/ 反引号续行)。 - ffmpeg 在
PATH中(流式 TTS 需要),或在 TTS 配置里指定mp3.encoderPath。
2.2 依赖服务(本机安装)
| 服务 | 默认地址 | 用途 | Win11 获取方式 |
|---|---|---|---|
| PostgreSQL | localhost:5432 | callflow / callout 两套 schema | 官方安装包或 Docker Desktop |
| Redis | 127.0.0.1:6379 | 外呼分布式锁与状态 | Docker Desktop / Memurai / WSL |
| Ollama | 127.0.0.1:11434 | NLU 后端模型 | Windows 版 Ollama |
准备步骤:
- PostgreSQL:创建库
freeswitch(与默认连接串postgres://postgres:postgres@localhost:5432/freeswitch一致),用户/密码可按需改并同步到各config.json。callflow-esl 与 callout-server 使用同一实例上的callflow/callout两个 schema。 - Redis:启动后确保密码与
apps/callout-server/config.json、apps/callflow-esl/config.json的redis段一致(默认密码redis)。 - Ollama:
ollama pull qwen3.5:2b(与apps/llm-nlu-server/config.json的llm.model一致),ollama serve后curl http://127.0.0.1:11434/api/tags验证。
2.3 安装依赖与建表
powershell
bun install # 安装全部 workspace 依赖
bun run --cwd apps/callflow-esl db:push # 同步 callflow schema
bun run --cwd apps/callout-server db:push # 同步 callout schemadb:push 直接把 Drizzle schema 推到数据库,不保留迁移目录。首次建表后, 启动 callflow-esl 会把内置业务的 code/desc 写入 callflow.call_businesses。
3. 配置本机联调地址
编辑以下文件,把回连相关地址改成开发机局域网 IP、FreeSWITCH 相关地址改成虚拟机 IP:
apps/callflow-esl/config.jsonfreeswitch.host→ 虚拟机 IP,port8021(inbound ESL)freeswitch.callbackHost→ 开发机 IP,callbackPort9911audioFork.wsUrl→ws://<开发机IP>:10096/audiodatabase.url/redis→ 本机 PostgreSQL / Redis
apps/callout-server/config.jsonfreeswitch(inbound ESL)、callflowEsl.baseUrl(默认http://127.0.0.1:9912本机即可)media.freeswitchRecordingBaseUrl→ 虚拟机上录音静态服务地址
apps/llm-nlu-server/config.json→llm.ollamaUrl默认本机11434即可
不要把改后的机器专属 IP / 明文密码提交回仓库(见 CLAUDE.md 与
contributing-docs.md)。本机联调建议用未跟踪的本地覆盖或环境变量注入。
4. 构建 ONNX C++ 服务(Win11)
bun run dev:asr/tts/emotion 只从 target/win_x64/ 拉起已编译产物,产物不存在会直接退出, 所以首次必须先构建:
powershell
cd onnx-platform\sherpa-asr-online-server; .\build.ps1
cd ..\sherpa-tts-server; .\build.ps1
cd ..\emotion-analysis-server; .\build.ps1build.ps1 用 CMake + VS 2022 生成到 build\win_x64\,并把可执行文件安装到 target\win_x64\。
5. 启动服务
一次性启动(推荐日常开发)
powershell
bun run dev默认进程范围和标签以服务目录为准。C++ 三个服务必须已构建。 Ctrl+C 一次性退出全部子进程。
单服务启动(排障 / 只调某一块)
powershell
bun run dev:asr # 也有 dev:tts dev:emotion dev:llm-nlu dev:llm-chat
bun run dev:callflow-esl
bun run dev:callflow-server
bun run dev:callout-server
bun run dev:callflow-webpage
bun run dev:callout-webpage云端兼容网关不在
bun run dev默认组内,按需bun run dev:aliyun-speech(10097/9081)、bun run dev:azure-speech(10098/9082)。
6. 启动后冒烟测试
按依赖顺序验证,避免上游未就绪造成下游误判:
powershell
# 1. C++ 三件套健康
Invoke-WebRequest http://127.0.0.1:10096/health # ASR
Invoke-WebRequest http://127.0.0.1:9080/health # TTS
Invoke-WebRequest http://127.0.0.1:9090/health # Emotion
# 2. NLU
Invoke-WebRequest http://127.0.0.1:9930/health
Invoke-WebRequest http://127.0.0.1:9930/api/v1/nlu/capabilities
# 3. Chat(capabilities 启用 token 时需附带 X-Callout-Internal-Token)
Invoke-WebRequest http://127.0.0.1:9931/health
# 4. TTS 合成(确认能返回 wavUrl,且虚拟机 FreeSWITCH 能访问该 URL)
Invoke-WebRequest -Method Post http://127.0.0.1:9080/tts -ContentType 'application/json' -Body '{"text":"测试"}'
# 5. 管理台 / 外呼后端
Invoke-WebRequest http://127.0.0.1:9913/health
Invoke-WebRequest http://127.0.0.1:9920/health
Invoke-WebRequest http://127.0.0.1:9920/api/media/config
# 5. 前端可达
Invoke-WebRequest http://127.0.0.1:19913
Invoke-WebRequest http://127.0.0.1:19920端到端一通电话(联通性最终验证):从虚拟机 FreeSWITCH 侧发起一次呼叫路由到 callflow-esl (dialplan socket <开发机IP>:9911 async full,或走 POST http://127.0.0.1:9912/outbound-calls), 观察 callflow-esl 日志出现握手、业务命中、ASR transcription、TTS 播放。链路任何一环断, 对照第 1 节网络约定与 troubleshooting.md 排查。
7. 自动化测试(改代码后的最低验证)
本仓库没有统一测试运行器,typecheck 是所有 TS 改动的基线门槛:
powershell
bun run typecheck # 一次性检查 6 个核心 TS/Vue 应用(两个语音网关不在内,改到时单独 typecheck)触及运行时 / 业务逻辑且有 *.test.ts 覆盖时,追加单元测试:
powershell
bun test --cwd apps/callflow-esl # 跑该 app 全部 *.test.ts
bun test --cwd apps/callout-server
bun run --cwd apps/callflow-esl typecheck # 单 app 的 tsc --noEmit
bun test apps/callflow-esl/src/xxx.test.ts # 单文件
bun test -t "关键字" # 按用例名过滤前端(Quasar/Vue3)另有:
powershell
bun run --cwd apps/callflow-webpage lint
bun run --cwd apps/callflow-webpage typecheck # vue-tsc --noEmit改动 Drizzle schema 后需 bun run --cwd apps/<app> db:generate 与 db:push 再重启对应服务。 新增 callflow-esl 业务的完整步骤见 apps/callflow-esl/README.md 与 apps/callflow-esl/docs/business-development.md。
8. 收尾:关闭本机实例(仓库硬性约定)
测试结束必须关闭本机手动启动的服务,避免端口/资源残留:
powershell
# bun run dev 单终端:Ctrl+C 即可
# 拆分启动的补充清理:
Get-Process | Where-Object { $_.ProcessName -in @('sherpa_asr_online_server','sherpa_tts_server','emotion_analysis_server','node','bun') } | Format-Table Id,ProcessName
netstat -ano | Select-String '10096|9080|9090|9930|9931|9911|9912|9913|9920|19913|19920'9. 常见问题速查
| 现象 | 首查项 |
|---|---|
dev:asr/tts/emotion 秒退 | target/win_x64/ 无产物,先 build.ps1 |
| FreeSWITCH 呼入不进 callflow-esl | callbackHost 写成 127.0.0.1;应为开发机局域网 IP,且虚拟机可达 |
| 无 ASR 结果 | 虚拟机访问不到 audioFork.wsUrl;检查开发机防火墙 10096 |
| TTS 不播放 | FreeSWITCH 访问不到 TTS 返回的 URL;publicBaseUrl 用回环地址 |
| NLU 报错 | Ollama 未启动或未 pull 对应模型 |
| 建表/连库失败 | PostgreSQL 未建 freeswitch 库,或连接串与 config.json 不一致 |
| 外呼调度不动 | Redis 未启动或密码不符 |
更细的模块级排障见 troubleshooting.md 与各模块 README。