feat(transcriber): 可配置 whisper 模型 + 名称映射(自定义 HF repo / 本地路径)

此前 fast-whisper 把「size → Systran/faster-whisper-{size}」的约定隐式散落在
加载/下载/检测三处,用户想用命名不符该约定的模型(社区微调版、或自己下到本地
的模型)接不上。本功能把映射显式化 + 可配置(对齐已有的 MLX_MODEL_MAP 模式)。

后端:
- 新增 app/transcriber/whisper_models.py 注册表:内置映射 + 用户自定义
  (config/whisper_models.json 持久化,Docker 下随 config 卷保留);resolve
  优先级 自定义 > 内置 > 直通(含 / 的 repo_id / 已存在本地目录)。
- whisper.py / config.py 的加载、下载、完整性检测统一走 resolve;HF cache 目录从
  任意 repo_id 推导(models--{org}--{name})不再写死 Systran;本地路径跳过下载,
  _purge_cache 绝不删用户本地模型。
- 新增 /whisper_models 增删查 API;/transcriber_config 返回内置+自定义列表;
  下载校验放开到「已登记/可解析」的模型。

前端:transcriber.tsx 新增「自定义模型」卡片(增删 + 下载状态),模型下拉自动含自定义。

Docker:自定义 HF 模型下到 /app/backend/models(v2.3.3 models 卷已持久化);本地模型
走挂载目录 + 配置路径,UI 已提示挂载。

测试:tests/test_whisper_models.py 13 个单测全过;并在 v2.3.3 镜像真实后端环境做了
import 链 + resolve + 真实模型检测的集成冒烟,均通过。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
huangjianwu
2026-05-22 15:09:06 +08:00
parent 717df2af7b
commit 58d992f28f
6 changed files with 565 additions and 27 deletions

View File

@@ -5,6 +5,10 @@ export interface TranscriberConfig {
whisper_model_size: string
available_types: { value: string; label: string }[]
whisper_model_sizes: string[]
/** 内置模型映射size → HF repo_id */
whisper_builtin_models?: Record<string, string>
/** 用户自定义模型映射:名称 → HF repo_id 或本地路径 */
whisper_custom_models?: Record<string, string>
mlx_whisper_available: boolean
}
@@ -41,3 +45,23 @@ export const downloadModel = async (data: {
}) => {
return await request.post('/transcriber_download', data)
}
export interface WhisperModelsResponse {
builtin: Record<string, string>
custom: Record<string, string>
}
/** 列出内置 + 自定义 whisper 模型映射 */
export const listWhisperModels = async (): Promise<WhisperModelsResponse> => {
return await request.get('/whisper_models')
}
/** 新增自定义模型映射(名称 → HF repo_id 或本地路径) */
export const addWhisperModel = async (data: { name: string; target: string }) => {
return await request.post('/whisper_models', data)
}
/** 删除自定义模型映射(不会删除已下载的模型文件) */
export const deleteWhisperModel = async (name: string) => {
return await request.delete(`/whisper_models/${encodeURIComponent(name)}`)
}