57 lines
5.5 KiB
Markdown
57 lines
5.5 KiB
Markdown
# Meeting ASR
|
||
|
||
独立的会议/通话录音转写与整理 Web 应用(`asrservice` + `asrpipe`)。支持本地 GPU 声纹服务(`qwen3cam`)与云端多模型语音识别(`soniox`、`gemini`、`openai`、`grok`),可通过 Arcane 部署到本地 VM(`tools-pve`)或外网 VPS。
|
||
|
||
## 核心架构
|
||
|
||
1. **Web 控制与审核面(`asrservice.web`)**
|
||
- 极简零构建服务端渲染 HTML + 原生 JS(深浅色自适应)。
|
||
- 上传录音时可按任务切换 ASR 引擎(`qwen3cam` / `soniox` / `gemini` / `openai` / `grok`)。
|
||
- 任务详情页内置支持 HTTP Range 的音频播放器、失败一键切换模型重试、草稿与纪要 Markdown 在线编辑。
|
||
- `/review/` 提供低置信度词语、关系确认与说话人身份确认(本地 `qwen3cam` 自动注册声纹至 `:10099`,线上多说话人模型直接更新草稿与词库而不依赖 `:10099`)。
|
||
- `/lexicon` 提供热词、同音纠错、人物关系管理与 Obsidian 词库一键同步。
|
||
- `/settings` 展示引擎是否就绪。网关地址和 API 密钥只显示「已配置 / 未配置」,页面不回显内网地址或密钥片段。
|
||
- 浏览器界面默认关闭。必须设置 `ASR_WEB_PASSWORD` 后才能上传、审核和改配置。未设置口令时页面只提示需要配置该变量,不会整站可写。`ASR_WEB_ALLOW_ANON=1` 仅用于跑在本机且不可被其他主机访问的调试进程。状态变更还要带 CSRF 令牌。`/api/v1/*` 继续使用 `ASR_AGENT_TOKEN`。
|
||
|
||
2. **后台消费与修订队列(`asrservice.worker`)**
|
||
- 监控 `ASR_DATA_DIR/inbox`(容器内 `/data/inbox`)并认领 `intake.db` 任务。旧的 `meeting-watch.py` 仍监听 `recordings/inbox` 并桥接到 vault `.asr-inbox`。两者共用 `ASR_STATE_DIR/consumer.lock`,第二个进程直接退出,避免同一盘录音被消费两次。
|
||
- 调用统一多引擎层 `asrpipe.providers.transcribe_audio()` 生成带结构化注释头的原始转写。
|
||
- 执行 `asr-refine draft`:结合 SQLite 词库、Obsidian Vault(`People/`、`Companies/`、`Projects/`、`minutes/`、`_glossary.md`)与 Hindsight(`personal-context`)进行分段去口语化、保真检查与会议纪要生成。
|
||
- 监控 `state/revision-queue/` 处理 Web 审核提交的修订重跑请求,确认通过后发布正式纪要至 Obsidian 并可选执行 Git 自动提交推送。
|
||
|
||
3. **语音识别(ASR)与大模型网关边界**
|
||
- **LLM 后处理**:彻底移除 ZenMux,统一通过 **LiteLLM**(内网 `http://192.168.50.49:4000/v1` / 外网 `https://api.opfo.xyz/v1`)调用:
|
||
- `ASR_CLEAN_MODEL` / `ASR_KEYWORD_MODEL`:默认 `aistudio/gemini-flash-lite-latest`
|
||
- `ASR_DRAFT_MODEL`:默认 `codex/gpt-sol-latest`
|
||
- **ASR 引擎**:
|
||
- `qwen3cam`(内网默认):对接局域网 GPU `Qwen3-ASR 1.7B + CAM++`(`http://192.168.50.100:10099/asr`),支持声纹特征比对与增量注册。
|
||
- `soniox`(线上高精度首选):因 LiteLLM 同步 `/v1/audio/transcriptions` 不支持 Soniox 异步 Files API、结构化 `context` 热词注入与逐词 `speaker` 分离且有 180s 超时限制,由 `asrpipe.providers` 通过 `SONIOX_API_KEY` 直连 Soniox `stt-async-v5`(自动注入 SQLite 词库热词与任务背景,完成后自动清理云端临时音频)。
|
||
- `gemini`:通过 LiteLLM 统一网关调用 `aistudio/gemini-3.5-transcribe`(长音频自动 `ffmpeg` 切片)。
|
||
- `openai`:通过 LiteLLM 统一网关调用 `openai/gpt-4o-transcribe-diarize`(支持 `diarized_json` 角色分离与 >23MB 自动压缩切片)。
|
||
- `grok`:通过 `XAI_API_KEY` 调用 xAI `grok-voice-transcribe-2.0`(支持多说话人分离)。
|
||
|
||
## 目录结构
|
||
|
||
- `asrpipe/`:核心转写引擎适配(`providers.py`)、词库召回(`lexicon.py`)、分段去口语化(`segment.py`、`refine.py`)、审核流(`review.py`)与 Obsidian/Hindsight 集成。
|
||
- `asrservice/`:容器化 Web 服务(`web.py`)、后台 Worker(`worker.py`)、SQLite 任务状态机(`db.py`)、Webhook 通知(`notify.py`)与健康检查(`healthcheck.py`)。
|
||
- `recordings/bin/`:录音监听与 CLI 转写脚本(兼容 `MEETING_ASR_BACKEND` 多引擎调度)。
|
||
- `termbank/`:专业词库源数据。
|
||
- `tests/`:核心管线、多引擎契约与 Web 服务单元测试。
|
||
- `Dockerfile` & `compose.yaml`:面向 Arcane 部署的单镜像双角色(`asr-web` + `asr-worker`)容器编排。
|
||
|
||
## 本地开发与测试
|
||
|
||
```bash
|
||
python3 -m venv .venv
|
||
.venv/bin/pip install -e .
|
||
ASR_NOTIFY=0 ASR_GIT_SYNC=0 .venv/bin/python -m unittest discover -s tests -v
|
||
```
|
||
|
||
## Arcane 部署(内网 VM / 外网 VPS)
|
||
|
||
1. 复制 `.env.example` 为 `.env`,按环境配置:
|
||
- **内网 VM(`tools-pve`)**:`MEETING_ASR_BACKEND=qwen3cam`(同时可配 `SONIOX_API_KEY` 等以便在 Web UI 按需切换)、`LITELLM_BASE_URL=http://192.168.50.49:4000/v1`、`HINDSIGHT_URL=http://192.168.50.47:8888`。
|
||
- **外网 VPS**:`MEETING_ASR_BACKEND=soniox`(或 `gemini` / `openai` / `grok`)、`LITELLM_BASE_URL=https://api.opfo.xyz/v1`,并且必须设置 `ASR_WEB_PASSWORD`。代码不会按部署位置自动加锁。HTTPS 站点再设 `ASR_WEB_COOKIE_SECURE=1`。
|
||
2. `ASR_GIT_SYNC` 与 `ASR_NOTIFY` 缺省为关。要推送 vault 或发通知时显式设为 `1`,并配置 `ASR_NOTIFY_BACKEND`。
|
||
3. 使用 `compose.yaml` 启动 `asr-web`(默认 `:8788`)与 `asr-worker`。`deploy/systemd/` 是现网单元快照,路径仍指向旧工作目录,不要原样安装到本仓库。
|