fix: use cloud local asr fallback

This commit is contained in:
2026-05-19 14:23:20 +08:00
parent 68ab3dab96
commit 980d252815
6 changed files with 40 additions and 11 deletions

View File

@@ -25,6 +25,7 @@
- 生产启动:`docker compose -f docker-compose.prod.yml --env-file deploy/.env.production up -d --build`
- 生产架构:`web` 容器用 Nginx 承载 Next 静态导出;`/login/``/_next/``/assets/``/skg-logo-black.svg``/oasis-source/` 等登录页必需静态资源公开访问;未登录访问工作台跳转 `/login/``/api/` 通过 Nginx `auth_request` 校验 FastAPI 会话 Cookie 后反代到 `skg-marketing-api:4291`Traefik 通过 `coolify` 外部网络接入 80/443
- Web 验收必须以生产 Docker 形态为准:前端是 `next export` 静态产物 + Nginx不是 `next dev` / `next start`。任何 Web 改动部署后必须运行 `./scripts/verify-prod-docker.sh`,确认 `/login/``/_next/``/api/health`、本地 API 地址泄漏和 API 镜像 `.env` 污染检查通过;不能只用本地 `npm run build` 作为上线依据。
- 当前音频解析:`https://ai.skg.com/azure/v1``gpt-4o-transcribe` 当前返回 `DeploymentNotFound`,且官方 Azure OpenAI transcription 路径探测也未返回可用部署;生产临时复制本地成功策略,直接使用容器内 `faster-whisper tiny.en` 真实转写,关闭 Gemini 多模态音频兜底。拿到真实 Azure ASR deployment 名后再恢复 `ASR_REMOTE_ENABLED=true`
- 持久化目录:服务器 `./data/jobs` 挂载到后端 `/data/jobs`;全局资源中心持久化在 `./data/asset_library``./data/prompt_library``./data/_trash`
- TikTok 下载登录态:公开视频默认不带 cookies 直接下载,生产环境变量必须显式保持 `YTDLP_COOKIES_FILE=``YTDLP_COOKIES_FROM_BROWSER=` 为空,防止容器读取不存在的浏览器 cookies。只有 TikTok 明确要求登录态时,才使用服务器私有 cookies 文件 `./secrets/tiktok_cookies.txt` 挂载到 API 容器 `/run/secrets/tiktok_cookies.txt` 并配置 `YTDLP_COOKIES_FILE=/run/secrets/tiktok_cookies.txt``yt-dlp` 会在任务结束时回写 cookies因此不要把该挂载设为只读不要使用云端浏览器读取方案也不要把 cookies 入库。生产容器严禁使用 `YTDLP_COOKIES_FROM_BROWSER=chrome`
- 登录凭证:用户名写下方快捷登录;密码明文备份只放服务器 `/root/skg-marketing-studio-login.txt`,生产环境变量 `WEB_AUTH_PASSWORD` / `WEB_AUTH_SESSION_SECRET` 只放服务器 `deploy/.env.production`
@@ -55,13 +56,14 @@
## 环境变量
- `LLM_BASE_URL` / `LLM_API_KEY`OpenAI 兼容网关,用于翻译、文案改写、音频分析等文本/多模态理解模型调用
- `ASR_BASE_URL` / `ASR_API_KEY`OpenAI Audio Transcriptions 兼容网关,用于上传 `audio.wav` 做真实转写;未配置 `ASR_API_KEY` 时复用 `LLM_API_KEY`,生产默认指向 `https://ai.skg.com/azure/v1`
- `ASR_MODEL`OpenAI Audio Transcriptions 音频转写模型;生产微软通道默认用 Azure OpenAI 部署名 `gpt-4o-transcribe`,如果 Azure 侧实际部署名不同必须同步改这里
- `ASR_REMOTE_ENABLED`:是否启用远端 OpenAI Audio Transcriptions微软 ASR 验收时必须为 `true`
- `ASR_LOCAL_FALLBACK_ENABLED`:是否允许远端 ASR 失败后落到本机 / 容器内 ASR生产微软 ASR 验收设为 `false`避免静默使用 `faster-whisper`
- `ASR_MODEL`OpenAI Audio Transcriptions 音频转写模型;微软通道使用 Azure OpenAI 部署名 `gpt-4o-transcribe`,如果 Azure 侧实际部署名不同必须同步改这里
- `ASR_LANGUAGE`:远端 ASR 的输入语言提示,默认 `en`;微软官方说明指定 ISO-639-1 语言可改善准确率和延迟。
- `ASR_REMOTE_ENABLED`:是否启用远端 OpenAI Audio Transcriptions微软 ASR 验收时必须为 `true`。当前生产因 `https://ai.skg.com/azure/v1``gpt-4o-transcribe` 返回 `DeploymentNotFound`,临时设为 `false`直接走容器内 `faster-whisper`,等真实 Azure deployment 名补齐后再恢复。
- `ASR_LOCAL_FALLBACK_ENABLED`:是否允许远端 ASR 失败后落到本机 / 容器内 ASR当前生产为 `true`,复制本地成功路径的“本机真实转写”策略,云端用 CPU 版 `faster-whisper` 替代本机 Mac 的 `mlx_whisper`
- `ASR_AUDIO_FALLBACK_ENABLED`:是否允许远端和本机 ASR 失败后落到多模态音频兜底;生产微软 ASR 验收设为 `false`,避免静默使用 Gemini 音频
- `FASTER_WHISPER_MODEL` / `FASTER_WHISPER_DEVICE` / `FASTER_WHISPER_COMPUTE_TYPE`:容器内本地 ASR 兜底,仅在 `ASR_LOCAL_FALLBACK_ENABLED=true` 时启用
- `ASR_FALLBACK_MODEL`:多模态音频兜底模型,仅在 `ASR_AUDIO_FALLBACK_ENABLED=true` 时用于兜底或音频画像,默认 `gemini-2.5-flash`;如果模型不能真实听到音频或返回疑似逐秒假字幕,后端必须拒绝写入时间轴
- `ASR_TIMEOUT_SECONDS`:远端 ASR / 音频分析单次请求超时,生产微软 ASR 默认 180 秒,避免 60 秒左右音频被 45 秒客户端超时提前中断
- `ASR_TIMEOUT_SECONDS`:远端 ASR / 翻译 / 音频分析单次请求超时;当前生产本地转写模式设为 45 秒,微软 ASR 重新启用时可按素材长度提高。
- `LOCAL_ASR_BIN` / `LOCAL_ASR_MODEL` / `LOCAL_ASR_TIMEOUT_SECONDS`:本机 ASR 兜底,默认使用 `/opt/homebrew/bin/mlx_whisper` + `mlx-community/whisper-tiny`,用于当前 SKG 网关 `/audio/transcriptions` 不可用时生成真实逐句时间轴
- `TRANSLATE_MODEL`:字幕翻译模型,默认 `gemini-2.5-flash`
- `GPT_TEXT_MODEL`GPT 文本 / 视觉默认模型,默认 `gpt-4o`;用于兜底修正旧 Gemini 覆盖值

View File

@@ -61,6 +61,7 @@ LLM_API_KEY = os.getenv("LLM_API_KEY", "").strip()
ASR_BASE_URL = os.getenv("ASR_BASE_URL", LLM_BASE_URL).strip()
ASR_API_KEY = (os.getenv("ASR_API_KEY") or LLM_API_KEY).strip()
ASR_MODEL = os.getenv("ASR_MODEL", "whisper-1")
ASR_LANGUAGE = os.getenv("ASR_LANGUAGE", "en").strip()
ASR_REMOTE_ENABLED = os.getenv("ASR_REMOTE_ENABLED", "true").strip().lower() not in {"0", "false", "no", "off"}
ASR_LOCAL_FALLBACK_ENABLED = os.getenv("ASR_LOCAL_FALLBACK_ENABLED", "true").strip().lower() not in {"0", "false", "no", "off"}
ASR_AUDIO_FALLBACK_ENABLED = os.getenv("ASR_AUDIO_FALLBACK_ENABLED", "true").strip().lower() not in {"0", "false", "no", "off"}
@@ -2875,6 +2876,7 @@ def _transcribe_sync(wav: Path) -> list[dict]:
model=ASR_MODEL,
response_format="verbose_json",
timestamp_granularities=["segment"],
**({"language": ASR_LANGUAGE} if ASR_LANGUAGE else {}),
)
raw = resp.model_dump() if hasattr(resp, "model_dump") else resp
segments = raw.get("segments") or []
@@ -2917,7 +2919,7 @@ def _translate_sync(segments: list[dict]) -> list[str]:
+ json.dumps(payload, ensure_ascii=False)
)
try:
resp = llm().chat.completions.create(
resp = llm().with_options(timeout=ASR_TIMEOUT_SECONDS).chat.completions.create(
model=TRANSLATE_MODEL,
messages=[{"role": "user", "content": prompt}],
response_format={"type": "json_object"},
@@ -4007,6 +4009,7 @@ def health() -> dict:
"voice_base_url": AZURE_OPENAI_BASE_URL,
"models": {
"asr": ASR_MODEL,
"asr_language": ASR_LANGUAGE,
"asr_base_url": ASR_BASE_URL or LLM_BASE_URL or "openai-default",
"asr_remote_enabled": ASR_REMOTE_ENABLED,
"asr_local_fallback_enabled": ASR_LOCAL_FALLBACK_ENABLED,

View File

@@ -21,14 +21,16 @@ LLM_BASE_URL=https://ai.skg.com/ezlink/v1
LLM_API_KEY=
# Model routing
# Azure ASR can be re-enabled once the real deployment name exists.
ASR_BASE_URL=https://ai.skg.com/azure/v1
ASR_API_KEY=
ASR_MODEL=gpt-4o-transcribe
ASR_REMOTE_ENABLED=true
ASR_LOCAL_FALLBACK_ENABLED=false
ASR_LANGUAGE=en
ASR_REMOTE_ENABLED=false
ASR_LOCAL_FALLBACK_ENABLED=true
ASR_AUDIO_FALLBACK_ENABLED=false
ASR_FALLBACK_MODEL=gemini-2.5-flash
ASR_TIMEOUT_SECONDS=180
ASR_TIMEOUT_SECONDS=45
FASTER_WHISPER_MODEL=tiny.en
FASTER_WHISPER_DEVICE=cpu
FASTER_WHISPER_COMPUTE_TYPE=int8

View File

@@ -963,14 +963,14 @@ ProductRefStateItem {
</thead>
<tbody>
<tr><td>网页登录</td><td><code>POST /auth/login</code><code>GET /auth/check</code><code>POST /auth/logout</code></td><td><code>web/app/login/page.tsx</code>、Nginx <code>auth_request</code></td><td>登录页提交账号密码到 <code>/api/auth/login</code>,后端设置 HttpOnly 会话 Cookie生产 Nginx 对工作台和 <code>/api/</code><code>/auth/check</code> 做统一校验,未登录页面跳 <code>/login/</code>API 返回 JSON 401。</td></tr>
<tr><td>运行配置 / 模型标注</td><td><code>GET /health</code></td><td><code>getRuntimeHealth</code><code>ModelTrace</code></td><td>返回 <code>models</code>ASR、<code>asr_base_url</code><code>asr_remote_enabled</code><code>asr_local_fallback_enabled</code><code>asr_audio_fallback_enabled</code><code>faster_whisper</code>、本机 ASR、ASR fallback、翻译、GPT 改写、GPT 画面理解、产品视角识别 <code>product_view</code>、GPT 图像模型、主体 6 视图 GPT 图像模型、Azure OpenAI TTS、视频别名和 Seedance 服务商。当前 <code>REWRITE_MODEL</code><code>AUDIO_REWRITE_MODEL</code><code>VISION_MODEL</code> 默认使用 <code>gpt-4o</code>;如果旧环境变量仍写 <code>gemini-*</code>,后端会归一化回 <code>GPT_TEXT_MODEL</code> / <code>REWRITE_MODEL</code>。语音只走 Azure OpenAI TTS<code>models.voice_tts_paths</code> 会回传当前尝试的语音路径,方便区分路径错误和语音服务不可用。前端所有当前主路径里会调用模型的按钮旁显示模型名,点击弹出小窗口查看模型链路和输入输出逻辑;不返回 API Key 或敏感凭证。</td></tr>
<tr><td>运行配置 / 模型标注</td><td><code>GET /health</code></td><td><code>getRuntimeHealth</code><code>ModelTrace</code></td><td>返回 <code>models</code>ASR、<code>asr_language</code><code>asr_base_url</code><code>asr_remote_enabled</code><code>asr_local_fallback_enabled</code><code>asr_audio_fallback_enabled</code><code>faster_whisper</code>、本机 ASR、ASR fallback、翻译、GPT 改写、GPT 画面理解、产品视角识别 <code>product_view</code>、GPT 图像模型、主体 6 视图 GPT 图像模型、Azure OpenAI TTS、视频别名和 Seedance 服务商。当前 <code>REWRITE_MODEL</code><code>AUDIO_REWRITE_MODEL</code><code>VISION_MODEL</code> 默认使用 <code>gpt-4o</code>;如果旧环境变量仍写 <code>gemini-*</code>,后端会归一化回 <code>GPT_TEXT_MODEL</code> / <code>REWRITE_MODEL</code>。语音只走 Azure OpenAI TTS<code>models.voice_tts_paths</code> 会回传当前尝试的语音路径,方便区分路径错误和语音服务不可用。前端所有当前主路径里会调用模型的按钮旁显示模型名,点击弹出小窗口查看模型链路和输入输出逻辑;不返回 API Key 或敏感凭证。</td></tr>
<tr><td>历史列表</td><td><code>GET /jobs</code></td><td><code>listJobs</code></td><td>所有 job 精简列表id/url/status/thumbnail/mtime…按 state.json mtime 倒序。前端 URL 无 <code>?job=</code> 时拉它回填全部历史;带 <code>limit</code> 可截断。</td></tr>
<tr><td>创建任务</td><td><code>POST /jobs</code></td><td><code>createJob</code></td><td>提交 TK 链接,后台开始下载;前端“开始”队列会在 downloaded 后自动触发音频解析。下载阶段默认不带 cookies生产环境必须显式保持 <code>YTDLP_COOKIES_FILE=</code><code>YTDLP_COOKIES_FROM_BROWSER=</code> 为空,避免容器内误读被打进镜像的开发 <code>api/.env</code>。只有 TikTok 明确要求登录态时,才把宿主机 <code>./secrets/tiktok_cookies.txt</code> 挂载进容器并设置 <code>YTDLP_COOKIES_FILE=/run/secrets/tiktok_cookies.txt</code>。生产容器没有 Chrome cookies 数据库,不能配置 <code>YTDLP_COOKIES_FROM_BROWSER=chrome</code></td></tr>
<tr><td>重试下载</td><td><code>POST /jobs/{id}/download/retry</code></td><td><code>retryJobDownload</code></td><td>用于 TK 链接下载失败且没有 <code>video_url</code> 的素材;清空错误、重新进入下载状态,并在后台再次执行 <code>pipeline_download</code>。上传视频不能重下载,需要重新上传文件。</td></tr>
<tr><td>上传视频</td><td><code>POST /jobs/upload</code></td><td><code>uploadJob</code></td><td>保存 source.mp4然后同样进入下载完成状态当前上传后也加入第一步队列下载完成后自动解析音频。</td></tr>
<tr><td>删除输入视频</td><td><code>DELETE /jobs/{id}</code></td><td><code>deleteJob</code></td><td>从任务队列、URL 和磁盘 <code>jobs/&lt;id&gt;</code> 目录移除整个 job包括源视频、关键帧、元素提取图和生成视频。</td></tr>
<tr><td>解析视频</td><td><code>POST /jobs/{id}/analyze?frames=&amp;target=&amp;mode=&amp;quality=</code></td><td><code>analyzeJob</code></td><td>抽参考帧能力。当前开始流程会在视频下载完成后自动调用一次,默认 <code>frames=12</code><code>target=motion</code><code>quality=accurate</code><code>mode=replace</code>,形成全局动作/节奏参考帧池;原版视频旁的“抽参考 12 帧”也会用同一参数显式重跑。<code>target</code> 仍支持透明骨架人、综合、清晰主体、转场变化、表情瞬间、动作峰值。</td></tr>
<tr><td>音频文案轨</td><td><code>POST /jobs/{id}/transcribe</code></td><td><code>triggerTranscribe</code></td><td>若尚未拆轨,先从 <code>source.mp4</code> 提取 <code>audio.wav</code> 并回填 <code>source_audio_url</code>;远端启用时把 <code>audio.wav</code> 上传到 <code>ASR_BASE_URL</code> 的 OpenAI Audio Transcriptions 兼容接口,用 <code>ASR_MODEL</code> 提取原始文案。生产微软 ASR 验收时 <code>ASR_BASE_URL=https://ai.skg.com/azure/v1</code><code>ASR_REMOTE_ENABLED=true</code><code>ASR_LOCAL_FALLBACK_ENABLED=false</code><code>ASR_AUDIO_FALLBACK_ENABLED=false</code>Azure 失败会明确失败,不会静默切到 <code>faster-whisper</code> 或 Gemini。只有显式开启兜底开关时远端不可用才会走容器内 CPU 版 <code>faster-whisper</code> 或多模态音频兜底。后端会拒绝重复文本、逐秒假字幕或覆盖率过低的结果,不再把不可听的多模态输出写进时间轴。中文翻译由 <code>TRANSLATE_MODEL</code> 按 ASR 段落补齐,失败时保留原文时间轴且中文可为空。再用 <code>ASR_FALLBACK_MODEL</code> 读取 <code>audio.wav</code> 和已有转写时间轴,多模态音频分析讲话人、语速节奏、停顿、背景音乐/环境声/音效,写入 <code>speaker_profile</code><code>rhythm_profile</code><code>background_audio_profile</code>;若模型分析失败,则用转写段落、时长和语速做本地估算兜底。当前第一步不默认生成 SKG 新口播和 Azure OpenAI 配音。</td></tr>
<tr><td>音频文案轨</td><td><code>POST /jobs/{id}/transcribe</code></td><td><code>triggerTranscribe</code></td><td>若尚未拆轨,先从 <code>source.mp4</code> 提取 <code>audio.wav</code> 并回填 <code>source_audio_url</code>;远端启用时把 <code>audio.wav</code> 上传到 <code>ASR_BASE_URL</code> 的 OpenAI Audio Transcriptions 兼容接口,用 <code>ASR_MODEL</code> 提取原始文案,并传 <code>ASR_LANGUAGE=en</code> 降低英文素材延迟。微软官方路径包括 <code>/openai/deployments/{deployment}/audio/transcriptions?api-version=...</code><code>/openai/v1/audio/transcriptions?api-version=preview</code>;当前 SKG 网关探测这些路径均未返回可用 ASR<code>gpt-4o-transcribe</code> 返回 <code>DeploymentNotFound</code>。当前生产因此复制本地成功策略:<code>ASR_REMOTE_ENABLED=false</code><code>ASR_LOCAL_FALLBACK_ENABLED=true</code>直接走容器内 CPU 版 <code>faster-whisper</code> 生成真实逐句时间轴;<code>ASR_AUDIO_FALLBACK_ENABLED=false</code>,避免 Gemini 多模态假字幕。后端会拒绝重复文本、逐秒假字幕或覆盖率过低的结果。中文翻译由 <code>TRANSLATE_MODEL</code> 按 ASR 段落补齐,失败时保留原文时间轴且中文可为空。再用 <code>ASR_FALLBACK_MODEL</code> 读取 <code>audio.wav</code> 和已有转写时间轴,多模态音频分析讲话人、语速节奏、停顿、背景音乐/环境声/音效,写入 <code>speaker_profile</code><code>rhythm_profile</code><code>background_audio_profile</code>;若模型分析失败,则用转写段落、时长和语速做本地估算兜底。当前第一步不默认生成 SKG 新口播和 Azure OpenAI 配音。</td></tr>
<tr><td>分镜脚本改写</td><td><code>POST /jobs/{id}/script/rewrite</code></td><td><code>rewriteStoryboardScript</code></td><td>根据原英文参考文案、当前英文新口播、英文 role enum、时间段和作者想法改写英文口播作者想法若含中文后端会先经 <code>_ensure_english</code> 兜底翻译。<code>mode=segment</code> 只改一段;<code>mode=all</code> 一次改完整片,要求整片前后连贯。后端按 <code>AUDIO_REWRITE_MODEL</code><code>ASR_FALLBACK_MODEL</code><code>TRANSLATE_MODEL</code> 依次尝试,全部失败时用英文本地模板保留可编辑文案。接口返回 <code>items[index,text,text_zh]</code>,其中 <code>text</code> 是写入模型链路的英文主值,<code>text_zh</code> 只供团队审稿镜像显示;点击保存规划后写入 <code>StoryboardScene.action</code></td></tr>
<tr><td>原始音频文件</td><td><code>GET /jobs/{id}/audio.wav</code></td><td><code>sourceAudioUrl</code></td><td>返回拆轨得到的 wav当前主界面不再渲染底部吸附音频条右侧复刻工作表会读取该文件生成参考图式横向响度波形并和原视频、逐句时间轴联动波形标题栏显示当前播放秒数、总时长和鼠标指针停点秒数。</td></tr>
<tr><td>改写配音文件</td><td><code>GET /jobs/{id}/audio-script.mp3</code></td><td><code>apiAssetUrl(job.audio_script.voice_url)</code></td><td>后续新配音阶段保留的 TTS 产物;服务端固定走 <code>VOICE_PROVIDER=azure_openai</code>,通过 <code>AZURE_OPENAI_BASE_URL</code> 的 OpenAI 协议生成 mp3并按 <code>AZURE_TTS_PATHS</code> 依次尝试 <code>/audio/speech</code><code>/v1/audio/speech</code> 等路径。当前第一步不默认生成该文件。</td></tr>
@@ -1108,6 +1108,19 @@ ProductRefStateItem {
<h2>变更记录</h2>
<p>这个记录不是 git log 的替代品。它记录“产品理解发生了什么变化、影响了哪些源码、你以后描述需求时该怎么说”。后续每次改功能都要补一条。</p>
<div class="changelog">
<article class="change">
<header>
<h3>2026-05-19 · 云端音频解析复制本地真实转写路径</h3>
<span class="tag blue">API</span>
<span class="tag cyan">Audio</span>
<span class="tag red">Deploy</span>
</header>
<div class="body">
<p><strong>问题:</strong>本地音频解析成功时实际链路是远端失败后落到 <code>mlx_whisper</code>,而生产强制 <code>ASR_BASE_URL=https://ai.skg.com/azure/v1</code> + <code>ASR_MODEL=gpt-4o-transcribe</code> 且关闭本地兜底。生产探测官方 Azure OpenAI 音频路径 <code>/openai/v1/audio/transcriptions?api-version=preview</code><code>/openai/deployments/{deployment}/audio/transcriptions?api-version=...</code> 仍不可用,当前部署名返回 <code>DeploymentNotFound</code></p>
<p><strong>改动:</strong>远端 ASR 请求新增 <code>ASR_LANGUAGE</code>,默认 <code>en</code>,用于按官方建议降低英文素材延迟;翻译请求也套用 <code>ASR_TIMEOUT_SECONDS</code>。生产配置临时改成 <code>ASR_REMOTE_ENABLED=false</code><code>ASR_LOCAL_FALLBACK_ENABLED=true</code><code>ASR_AUDIO_FALLBACK_ENABLED=false</code>,云端用容器内 <code>faster-whisper tiny.en</code> 复制本地“真实本机转写”路径。</p>
<p><strong>影响:</strong>音频解析不再卡在不存在的 Azure deployment当前云端 CPU 实测同一失败 job 的 <code>audio.wav</code> 可在约 13.6 秒转出 17 段。等 SKG 网关提供真实 Azure ASR deployment 后,再把 <code>ASR_REMOTE_ENABLED=true</code> 并恢复对应部署名。</p>
</div>
</article>
<article class="change">
<header>
<h3>2026-05-19 · 删除抽帧状态文案改为参考帧</h3>

View File

@@ -859,11 +859,14 @@ function resolveVideoModelLabel(models: RuntimeModels | undefined, model: string
}
function audioModelTrace(models?: RuntimeModels): ModelTraceSpec {
const remoteState = models?.asr_remote_enabled === false ? "已关闭" : "启用"
const localState = models?.asr_local_fallback_enabled === false ? "关闭" : "启用"
const localModel = models?.faster_whisper ? `faster-whisper ${models.faster_whisper}` : modelValue(models?.local_asr)
return {
title: "音频解析",
model: modelList([models?.asr, models?.translate, models?.asr_fallback]),
chain: [
`ASR 转写:优先 ${modelValue(models?.asr)};失败后尝试本机 ${modelValue(models?.local_asr)};仍失败才回退 ${modelValue(models?.asr_fallback)},并拒绝假字幕/重复时间轴`,
`ASR 转写:远端 ${remoteState},模型 ${modelValue(models?.asr)}${models?.asr_language ? `,语言 ${models.asr_language}` : ""};本机转写 ${localState},使用 ${localModel};多模态兜底${models?.asr_audio_fallback_enabled === false ? "关闭" : ` ${modelValue(models?.asr_fallback)}`},并拒绝假字幕/重复时间轴`,
`字幕翻译:${modelValue(models?.translate)} 按 ASR 段落输出中文;失败时保留原文时间轴,中文可为空`,
`讲话人 / 节奏 / 背景音:${modelValue(models?.asr_fallback)} 读取 audio.wav + 转写时间轴做多模态分析;失败时用本地时长/段落估算兜底`,
],

View File

@@ -254,6 +254,12 @@ export interface GeneratedVideo {
export interface RuntimeModels {
asr?: string
asr_language?: string
asr_base_url?: string
asr_remote_enabled?: boolean
asr_local_fallback_enabled?: boolean
asr_audio_fallback_enabled?: boolean
faster_whisper?: string
local_asr?: string
asr_fallback?: string
translate?: string