Files
eaiadminandClaude Code b4c8ea38d1 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>
2026-09-26 23:36:00 +08:00

44 lines
2.6 KiB
Bash
Raw Permalink 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.
# 本地语音转写服务(eai_agentplatform-asr.service)的环境变量样例。
#
# 装机:sudo cp deploy/asr.env /opt/eai_agentplatform-asr/asr.env
# 端口不在这里配 —— 它写在 unit 的 ExecStart 上(--port 8090),
# 与后端 config/ai_config.json 里 audio_route_local_whisper.base_url 的 8090
# 是同一个值。改端口要同时改这两处,否则后端起不来时界面会显示
# 「本地路由不健康」,而真实原因是对不上端口。
# 这里注释掉的那行只是记录这个耦合,别指望它生效:
# ASR_PORT=8090
# 计算精度。8G 显存要和 llama-server 共用,float16 会 OOM(原型机实测,
# 见 bugs_and_errors.md E06)。int8_float16 是这台机器的可用档位。
ASR_COMPUTE_TYPE=int8_float16
# 模型目录**不在这里配**:serve.py 按 `脚本所在目录/models` 找,也就是
# /opt/eai_agentplatform-asr/models(软链或实体目录都行,见 DELIVERY.md 第 1 节)。
# 把模型放到别处就得改 asr_core.py,不如把目录放对。
# 家目录指到 cache/,**必须有这一行**。
#
# 原型机上服务以 eaiadmin 跑,~ 可写,所以从没暴露过;装成服务后两件事同时变:
# unit 里 ProtectHome=true 挡住 /home,而系统账号 eai_agentplatform 的家目录
# (/home/eai_agentplatform)压根不存在。pyannote 起步时要写
# ~/.pyannote/database.yml,于是每次转写都以 PermissionError 收场 ——
# 而报错发生在说话人分离那一段,看起来像模型坏了,其实是没地方写配置。
#
# 指到 cache/ 是因为 unit 的 ReadWritePaths 只放开了这一个目录;
# 顺带让 torch / matplotlib 之类的 dotfile 也落在同一个可写位置。
# 换目录要连 unit 的 ReadWritePaths 一起改。
HOME=/opt/eai_agentplatform-asr/cache
# 离线开关。权重全部是本地文件(faster-whisper 直接读目录、pyannote 的
# config.yaml 已改写成本地文件路径),正常情况下一个网络请求都不发。
# 这两个开关是安全网:万一哪条分支想回 huggingface.co,本机到那边是**不通**的,
# 表现会是挂起几分钟而不是报错 —— 加上开关,它立刻失败,日志里一眼能看出来。
HF_HOME=/opt/eai_agentplatform-asr/cache/huggingface
HF_HUB_OFFLINE=1
TRANSFORMERS_OFFLINE=1
# 故意没有 PYTORCH_CUDA_ALLOC_CONF 之类的分配器开关:这台机器的显存配置
# (int8_float16 + 转写前后释放模型)是实测调出来的,见 bugs_and_errors.md E06。
# 没在这台机器上验过的旋钮不要加进来 —— 加错了表现是 OOM,
# 而 OOM 看起来又像「模型太大」,很容易往错误的方向查。