feat(asr): 降级兜底——分离路由全挂时退到无分离路由,只交付逐字稿
回退链从「一条主路由 + 一串替补」改成两级:先把同能力(有说话人分离)的路由 试完,全挂才降级到不分离的路由。降级是**本次事实**而不是配置事实,写进第 2 步 产物(capability_degraded / capability_zh),第 3 步与第 5/6 步据此判为不可用。 - transcribe.go:Result 加 CapabilityDegraded,判据 chain[0] 能分离而实际这条 不能;与 HasSpeakers 分开记(后者可能是「配了却没输出」那种异常) - audio_handlers.go:闸门从「读路由声明的能力」改成「读稿子里实际有没有标签」 (audioTranscriptSpeakerKeys),与第 3 步共用同一句 SpeakerKeysOf;本次没分离 → 哨兵错误 errAudioSpeakersUnavailableThisRun,不再放行去写一份看不出残缺的纪要 - 闸门**不看** capability_degraded:改动前落库的老产物没有这个字段,看它就 fail-open - 第 1 步「转写要求」提前把降级的后果说清;第 2 步产物带完整措辞与「⚠」日志 - 前端两处(SpecialistPanel.vue / audioSkill.js)判断顺序改为先读实际结果 has_speakers、再退回声明 speakers —— 顺序反了会在降级那一次照旧显示第 3 步 - ai_config.json:补 3 条云端无分离路由与各自的回退链 验证:三处变异(产物 key 拼错、标记写死 true、闸门 fail-closed)都验过会红; 新增两个用例文件走真实 gin 路由 + 真实鉴权中间件,断言拦下来的**理由**而不只是 「拦下来了」;go test ./... 全绿、gofmt 干净、前端构建通过。 同期把本地 ASR 装成 systemd 常驻服务(deploy/install_asr_local.sh 七步全过, 开机自启,实测 26.7 分钟录音 → 3.1 分钟)。装的过程挖出两个只在服务化时才暴露的坑: - E12 转写堵住事件循环 → 探活超时 → 本地被判不健康 → auto 静默退云端、音频出网, 全程没有任何报错。修法 run_in_threadpool(deploy/asr/serve.py) - E13 服务账号的 ~ 不可写,pyannote 写不了 ~/.pyannote/database.yml,每次转写 500。 修法 asr.env 加 HOME=<cache 目录>(该目录在 unit 的 ReadWritePaths 里) 顺带收口一处交付缺口:服务源码原先只有 ~/asr-poc 一份,而 DELIVERY.md 的清理计划 要 rm -rf 它 —— 那会让唯一副本变成 /opt 下 root 所有、不在任何版本库里的文件。 现在 deploy/asr/ 是唯一事实源,装机脚本与文档同步改。 已知偏离 / 未做(记在案): - 界面那句「本次没有说话人分离,后续步骤不可用」只验到后端接口层,没有造出真实 降级场景渲染出来看过 - deploy/asr/ 的引入改变了装机来源:原型目录 $SRC_DIR 从此只提供 venv 与模型, 服务代码一律从仓库取 Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
# 本地语音转写服务(eai_agentplatform-asr)
|
||||
|
||||
> 这份文件是给**运维/交付工程师**看的,装完机器后遇到「转写失败」时先读它。
|
||||
> 服务的 systemd 单元里 `Documentation=` 指向本文件。
|
||||
|
||||
---
|
||||
|
||||
## 它是什么
|
||||
|
||||
一个只监听回环地址的 Python 服务,提供 OpenAI 兼容的转写端点:
|
||||
|
||||
| 端点 | 用途 |
|
||||
|---|---|
|
||||
| `POST /v1/audio/transcriptions` | 转写(含说话人分离) |
|
||||
| `GET /v1/models` | 健康探测用的探针端点 |
|
||||
|
||||
- **监听**:`127.0.0.1:8090` —— 只回环,不在局域网上暴露
|
||||
- **模型**:faster-whisper large-v3 + pyannote 3.1
|
||||
- **为什么要它**:把客户会议录音的转写留在本机。平台默认语音路由指向它,
|
||||
音频不出本机;它不可用时平台才回退云端,并在界面上标注「音频已离开本机」。
|
||||
|
||||
---
|
||||
|
||||
## 怎么确认它是好的
|
||||
|
||||
```bash
|
||||
systemctl status eai_agentplatform-asr # active (running)
|
||||
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8090/v1/models # 期望 200
|
||||
journalctl -u eai_agentplatform-asr -n 50 --no-pager
|
||||
```
|
||||
|
||||
平台侧从**后台 → AI 路由 → 语音**看 `本地` 那条的 `healthy` 是否为真;
|
||||
或直接打后端接口:
|
||||
|
||||
```bash
|
||||
curl -s -H "Authorization: Bearer <token>" http://127.0.0.1:8080/api/ai/routes/audio
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 它挂了会怎样(重要)
|
||||
|
||||
**不会报错给用户,而是静默回退云端。** 这正是需要有人盯着它的原因:
|
||||
|
||||
1. `audio_route_auto` 探测到本地不健康 → 改选 `fallback_routes` 里的云端路由;
|
||||
2. 转写照常成功,但**录音已经出了本机**;
|
||||
3. 界面在转写结果上标注「音频已离开本机」——这是唯一的用户可见信号。
|
||||
|
||||
所以:**如果这台机器的定位是「音频不许出本机」,本服务必须一直 active。**
|
||||
单元里 `Restart=always` 就是这个意思;不要改成 `on-failure`。
|
||||
|
||||
---
|
||||
|
||||
## 排障顺序
|
||||
|
||||
| 症状 | 先看这里 |
|
||||
|---|---|
|
||||
| 服务起不来 | `journalctl -u eai_agentplatform-asr -n 100` |
|
||||
| CUDA OOM | 显存被别的进程占了(本机 llama-server 常态占约 5G,卡总共 8G)。见 `bugs_and_errors.md` E06 |
|
||||
| 加载模型挂住不报错 | 是否有分支想回 `huggingface.co`。本机到那边不通,`HF_HUB_OFFLINE=1` / `TRANSFORMERS_OFFLINE=1` 会让它立刻失败而不是挂起 |
|
||||
| 平台显示本地不健康但服务是好的 | 端口对不上。端口写在 unit 的 `ExecStart --port` 与后端 `config/ai_config.json` 的 `audio_route_local_whisper.base_url` 两处,改一处没用 |
|
||||
| 平台显示本地不健康,且刚重启过服务 | 平台每 30 分钟探一次。后台点一次保存/重载会立刻重探(`POST /api/ai/reload`) |
|
||||
|
||||
---
|
||||
|
||||
## 装 / 卸
|
||||
|
||||
装:`sudo bash deploy/install_asr_local.sh`(见 `DELIVERY.md` 第 2.5 节)
|
||||
|
||||
卸(会删掉 13.5 GB 的 venv 与模型,先确认目标机不再需要本地转写):
|
||||
|
||||
```bash
|
||||
sudo systemctl disable --now eai_agentplatform-asr
|
||||
sudo rm -rf /opt/eai_agentplatform-asr
|
||||
sudo rm -f /etc/systemd/system/eai_agentplatform-asr.service
|
||||
sudo systemctl daemon-reload
|
||||
```
|
||||
|
||||
卸完记得把后台的**默认语音路由**切到云端,否则 `audio_route_auto` 会一直
|
||||
在一条永远不健康的本地路由上打转,每次都白等一轮探测超时。
|
||||
Reference in New Issue
Block a user