115 lines
8.3 KiB
Markdown
115 lines
8.3 KiB
Markdown
# 多模态管线与模型运行
|
||
|
||
更新日期:2026-09-04。阶段 F 实现位于 `feat/multimodal-pipeline`,接口以 `/openapi.json` 为准。
|
||
|
||
## 安装
|
||
|
||
API 保留 `backend/.venv`,模型依赖安装到独立的 `backend/.venv-models`。在项目根目录执行:
|
||
|
||
```powershell
|
||
# 默认 CPU
|
||
./backend/scripts/install-model-runtime.ps1
|
||
# CUDA 显式选装,不安装或修改 NVIDIA 驱动
|
||
./backend/scripts/install-model-runtime.ps1 -Device cuda
|
||
```
|
||
|
||
脚本固定 torch/torchaudio 2.9.1,分别选择 CPU / cu128 wheel;其他已验证依赖由 `model-requirements.lock` 锁定。不要求 vLLM、FlashAttention。`APP_MODEL_PYTHON` 可指定模型解释器。
|
||
|
||
设置 → 模型提供商 → 本地模型提供下载、续传、删除、设备与预算配置。推理不自动下载;“已下载并校验”不代表设备已通过推理验证,最近实际设备与诊断单独显示。
|
||
|
||
默认 CPU、2 线程、8 GiB 内存预算。独立子进程按需加载,每任务结束释放,取消/超时终止并回收进程。单模型串行执行,排队中的交互向量请求优先于转写,不抢占运行中任务。请求 CUDA 但不可用时回退 CPU,记录原因。任务冻结运行配置。当前要求单 API worker,不支持跨进程调度。
|
||
|
||
## 模型与许可
|
||
|
||
| 能力 | 模型 | 固定 revision | 权重许可 |
|
||
| --- | --- | --- | --- |
|
||
| 默认 Embedding | hotchpotch/bekko-embedding-v1-a8m | c721113d59a1d91b447450324f51c4b3332c924a | MIT |
|
||
| 可选 Embedding | ibm-granite/granite-embedding-97m-multilingual-r2 | 835ad14087e140460703cf0fae09f97d469d65c2 | Apache-2.0 |
|
||
| 转写、语言识别 | Qwen/Qwen3-ASR-0.6B | 5eb144179a02acc5e5ba31e748d22b0cf3e303b0 | Apache-2.0 |
|
||
| 声纹相似度 | iic/speech_eres2netv2_sv_zh-cn_16k-common | 3317286545c587ae682dbc166831d9448780eebb | Apache-2.0 |
|
||
|
||
来源:[Bekko](https://huggingface.co/hotchpotch/bekko-embedding-v1-a8m)、[Granite](https://huggingface.co/ibm-granite/granite-embedding-97m-multilingual-r2)、[Qwen3-ASR](https://huggingface.co/Qwen/Qwen3-ASR-0.6B)、[ERes2NetV2](https://modelscope.cn/models/iic/speech_eres2netv2_sv_zh-cn_16k-common)。下载固定 revision;HF LFS / ModelScope 校验 SHA-256,HF 普通文件校验 Git blob hash。中断保留 .partial,使用 Range 续传;校验失败、磁盘不足和中断分别记录。
|
||
|
||
## 媒体接口
|
||
|
||
| 方法与路径 | 行为 |
|
||
| --- | --- |
|
||
| POST /api/media/attachments?filename=... | 二进制上传,宿主分配 ID,25 MiB 上限 |
|
||
| GET /api/media/attachments/{id} | 受控读取,支持播放器 Range |
|
||
| POST /api/media/transcriptions | 202/queued;local_only、diarization、terminology、idempotency_key |
|
||
| GET /api/media/transcriptions | 按状态分页查询 |
|
||
| GET /api/media/transcriptions/{id} | 状态、分段、原文、修订、进度 |
|
||
| GET /api/media/transcriptions/{id}/events | SSE;after / Last-Event-ID 回放 |
|
||
| POST /api/media/transcriptions/{id}/cancel | 取消排队或运行任务 |
|
||
| POST /api/media/transcriptions/{id}/retry | 新 attempt,保留 previous_job_id |
|
||
| PATCH /api/media/transcriptions/{id} | revision 乐观锁校对、重命名 |
|
||
| GET /api/media/transcriptions/{id}/revisions | 历史修订 |
|
||
| POST /api/media/transcriptions/{id}/notes | Knowledge 写入;任务/修订/选项幂等 |
|
||
| POST /api/media/speaker-matches | 两附件声纹比对,支持 local_only |
|
||
| GET /api/media/attachments/{id}/cleanup-impact | 清理影响与保留笔记 |
|
||
| DELETE /api/media/attachments/{id} | 清理附件、转写正文、修订及术语 |
|
||
|
||
任务、模型快照、事件和修订写入 SQLite。重启把未完成任务标为 TRANSCRIPTION_INTERRUPTED,不自动重新上传。幂等摘要包含内容、选项、模型和提供商配置;同键不同输入返回 409。
|
||
|
||
API 优先,无配置或无效结果时本地回退。local_only 禁止远程模型。纯文本附件和既有 sidecar 可导入,但已有真实音频时不使用旁边文本冒充识别。
|
||
|
||
PyAV 提取音轨至 16 kHz 单声道,最长 1 小时,禁止解码器网络协议。能量分段后交给 Qwen3-ASR,返回片段边界,不宣称逐字对齐。ERes2NetV2 提取片段声纹并按相似度聚类;短片段、同段多人、重叠发言需要人工校对。缺失能力返回 DIARIZATION_UNAVAILABLE;未启用逐字对齐返回 WORD_TIMESTAMPS_UNAVAILABLE。
|
||
|
||
术语是识别后的替换规则,保留原始文本和来源。重命名只修改显示名,稳定 ID 不变。笔记包含音频与时间跳转链接;重复导出不覆盖用户编辑。清理保留已导出笔记,音频链接失效,已清理任务不可重试。重建索引保留转写与笔记关联。
|
||
|
||
## 向量空间
|
||
|
||
生产使用真实模型;HashEmbeddingProvider 仅供测试注入。本地/API 向量都写入按模型空间隔离的 routed_block_vectors;不同模型、revision、接口或维度不混用。旧 128 维测试索引不用于真实查询。
|
||
|
||
模型不可用时仍可保存 Markdown/FTS;语义查询返回索引未就绪,混合查询可使用全文检索。切换模型后重建全部索引。Benchmark 验证当前空间完整覆盖。
|
||
|
||
## Token 用量
|
||
|
||
GET /api/usage 使用带时区的 start/end(左闭右开),支持 provider_id、model、source。页面提供今日、7 天、30 天、自定义时段。
|
||
|
||
按实际 attempt 保存 request_id、Agent run_id、模型、来源、时间、原始数值与归一化计数。覆盖 Chat、流式、Agent、Embedding、媒体及本地推理。累计快照取最大值并 upsert;回放不新增请求,真实重试有新 attempt。流中断保留已收到计数。
|
||
|
||
输入缓存按供应商口径归一化,推理不重复加入输出;缓存命中率按完整输入口径加权。缺失为 null,显示每项覆盖数。本地 Embedding 使用真实 tokenizer,其他本地能力不编造 Token。写入失败不影响回复;原始 usage 仅保留数值白名单。本应用观测值不是厂商账单。
|
||
|
||
## 自定义请求 JSON
|
||
|
||
request_overrides 每项含 capability、model(空表示全部)、stream(null 表示全部模式)、body。通用规则先于模型规则,同层显式流式规则优先。对象递归合并、数组替换、标量覆盖、null 保持实际值;删除键恢复继承。
|
||
|
||
```json
|
||
{
|
||
"capability": "chat",
|
||
"model": "special-model",
|
||
"stream": true,
|
||
"body": {
|
||
"stream_options": { "include_usage": true },
|
||
"enable_thinking": false
|
||
}
|
||
}
|
||
```
|
||
|
||
model、消息、系统提示、工具、媒体文件、stream 由宿主管理,冲突拒绝。禁止 body 注入凭据、Header、URL,无模板求值。媒体独立匹配规则,嵌套扩展作为 JSON 文本 multipart 字段,不接收聊天规则。是否支持某扩展由供应商决定。
|
||
|
||
POST /api/providers/request-preview 不联网,隐藏正文/文件且不包含凭据。表单有格式化、校验、删除规则、预览;Provider version 检测保存冲突,适配器冻结配置。原有连接测试只验证模型列表连通性,不等于厂商推理接受扩展字段。
|
||
|
||
## 验证记录
|
||
|
||
2026-09-04,Windows / Python 3.12 / torch 2.9.1+cpu:后端 472 项、前端 93 项测试通过,类型检查和生产构建通过,仍有既有大 bundle 警告。Edge 真实 API 页面、播放器时长/定位、模型与用量卡片无页面异常。
|
||
|
||
真实模型完成音频 → 转写 → 片段声纹 → 笔记 → 语义检索闭环。示例来自固定 ModelScope revision;权重和音频不提交仓库。
|
||
|
||
| 实测 | 结果 |
|
||
| --- | --- |
|
||
| Bekko 中文小样本 | 384 维;相关相似度 0.495、无关 0.083 |
|
||
| Qwen3-ASR 短中文音频 | 加载约 11.1 秒、推理约 6.3 秒、峰值约 5.4 GiB |
|
||
| ERes2NetV2 | 同音频 1.000,不同示例说话人 0.090,片段聚类完成 |
|
||
| 笔记闭环 | 重复导出同 note_id,语义检索找回同笔记 |
|
||
|
||
这是功能冒烟,不是代表性课程语料完整质量评估。CUDA 实机、Granite 对照、逐字强制对齐及重叠语音质量未验证。每任务释放模型有加载成本;长音频准确率、阈值与吞吐需要目标机器专项验收。
|
||
|
||
```powershell
|
||
cd backend
|
||
.venv/Scripts/python scripts/local-model-smoke.py bekko --download
|
||
.venv/Scripts/python scripts/local-model-smoke.py qwen3-asr --download --audio C:/path/to/speech.wav
|
||
.venv/Scripts/python scripts/local-model-smoke.py eres2netv2 --download --audio C:/path/to/speech.wav --reference C:/path/to/reference.wav
|
||
```
|