Fastwhisper Processor
这是一个基于 faster-whisper 的 Modal 转录处理器。
第一版只做语音转文字,不做翻译。它从 Cloudflare R2 下载音频或视频文件,转录成结构化 JSON,再把结果写回 R2。
当前 MVP 能力
- 通过
sourceKey从 R2 读取源音视频文件。 - 支持 FFmpeg 可解码的常见格式,例如 mp4、m4a、wav、mp3、mov、webm、aac、ogg、flac。
- 使用
faster-whisper执行原语言转录。 - 上传转录 JSON 到 R2。
- 可选接收
jobId作为当前 Modal 任务 ID;不传则生成modal-<uuid>。 - 可选接收
jobId、stepKey、stepName/name,并向 Job Hub 上报当前 step 进度。 - 可选传入
webhookUrl,回调进度和完成状态。
默认输出位置:
transcripts/{jobId}/transcript.json
第一版只输出 JSON 文件,不额外输出 txt、srt 或 vtt。
目录与入口
所有命令建议从 modal-processor 项目根目录执行:
cd ~/projects/modal-processor
source .venv/bin/activate
当前 app 入口文件:
apps/fastwhisper/modal_app.py
必需的 Modal Secret
复用现有 R2 secret,名称必须是:
video-to-short-r2
里面需要包含这些环境变量:
R2_ACCOUNT_ID=...
R2_ACCESS_KEY_ID=...
R2_SECRET_ACCESS_KEY=...
R2_BUCKET=...
安装依赖
pip install -r requirements.txt
本地触发测试
这个命令是在本地终端触发 Modal 远端任务。真正的转录发生在 Modal 远端容器里,不是在本机。
modal run apps/fastwhisper/modal_app.py \
--source-key youtube_video/youtube-video-1779260797732.m4a \
--job-id transcribe-test-001
显式指定输出位置:
modal run apps/fastwhisper/modal_app.py \
--source-key uploads/source.mp4 \
--job-id transcribe-test-001 \
--output-key transcripts/transcribe-test-001/transcript.json
指定源语言和模型大小:
modal run apps/fastwhisper/modal_app.py \
--source-key uploads/source.mp4 \
--source-language zh \
--model-size small
成功时输出里会包含类似内容:
'status': 'completed'
'outputKey': 'transcripts/transcribe-test-001/transcript.json'
部署
modal deploy apps/fastwhisper/modal_app.py
部署成功后,Modal 会输出 transcribe_media 函数对应的 .modal.run URL,形式类似:
https://<workspace>--fastwhisper-processor-transcribe-media.modal.run
外部 HTTP 调用
部署后,可以通过 POST JSON 调用这个 endpoint:
curl -X POST "https://zhengkinson--fastwhisper-processor-transcribe-media.modal.run" \
-H "Content-Type: application/json" \
-d '{
"sourceKey": "uploads/source.mp4",
"outputKey": "transcripts/source/transcript.json",
"sourceLanguage": "zh",
"modelSize": "small"
}'
预期会立刻返回:
{"accepted": true, "jobId": "modal-..."}
注意:这个返回只表示 Modal 已接收任务。返回里的 jobId 是当前 Modal 转录任务 ID:如果请求传了 jobId,会返回传入值;如果没传,则由 Modal endpoint 生成。
jobId 是可选字段,表示当前 Modal 任务 ID;如果请求同时传入 jobId、stepKey 和 stepName/name,处理器会通过 Job Hub step 接口上报进度。缺少任一字段时,不进行 Job Hub 更新。job_id、step_key、step_name 兼容下划线写法。处理失败且 Job Hub 字段完整时,处理器会上报 status=failed、失败原因 message 和 failJob=true。
Webhook 格式
如果请求里传了 webhookUrl,处理器会回调进度和最终结果。旧字段 callbackUrl 会被兼容识别为 webhookUrl。
请求示例:
{
"sourceKey": "uploads/source.mp4",
"outputKey": "transcripts/source/transcript.json",
"jobId": "job-123",
"stepKey": "transcribe",
"stepName": "转写音视频",
"jobProgressStart": 20,
"jobProgressEnd": 70,
"webhookUrl": "https://your-app.com/api/processor/webhook",
"sourceLanguage": "zh",
"modelSize": "small"
}
进度 webhook 示例:
{
"jobId": "job-123",
"stepKey": "transcribe",
"stepName": "转写音视频",
"sourceKey": "uploads/source.mp4",
"outputKey": "transcripts/source/transcript.json",
"modelSize": "small",
"sourceLanguage": "zh",
"status": "processing",
"stage": "transcribing",
"progress": 40,
"message": "Transcribing source media with faster-whisper."
}
完成 webhook 示例:
{
"jobId": "job-123",
"stepKey": "transcribe",
"stepName": "转写音视频",
"sourceKey": "uploads/source.mp4",
"outputKey": "transcripts/source/transcript.json",
"modelSize": "small",
"sourceLanguage": "zh",
"status": "completed",
"stage": "completed",
"progress": 100,
"message": "Audio transcription completed successfully.",
"language": "zh",
"languageProbability": 0.98,
"durationSeconds": 123.45
}
R2 输出 JSON 格式
R2 中的 outputKey 会保存完整转录结果:
segments 是经过句子级后处理的片段,不是 faster-whisper 原始时间块。处理器会优先按 . ? ! 。?! 断句,并在原始时间块内按字符位置近似估算句子边界时间。
{
"jobId": "job-123",
"stepKey": "transcribe",
"stepName": "转写音视频",
"sourceKey": "uploads/source.mp4",
"outputKey": "transcripts/source/transcript.json",
"modelSize": "small",
"sourceLanguage": "zh",
"status": "completed",
"language": "zh",
"languageProbability": 0.98,
"durationSeconds": 123.45,
"text": "完整转录文本...",
"segments": [
{
"id": 0,
"index": 0,
"segmentKey": "seg_0123456789abcdef0123456789abcdef",
"start": 0.0,
"end": 4.2,
"startMs": 0,
"endMs": 4200,
"text": "第一段文本"
}
],
"model": {
"name": "faster-whisper",
"size": "small"
}
}
参数说明
sourceKey
必填。R2 上的源音视频对象路径。
outputKey
选填。R2 上的转录 JSON 输出路径。默认 transcripts/{jobId}/transcript.json。
sourceLanguage
选填。源文件语言,例如 zh、en。不传时由 Whisper 自动识别。
modelSize
选填。默认 small。可按 Modal 容器资源和准确率需求调整为 base、small、medium 等。
常见错误
Missing required field: sourceKey
请求里没有传 R2 源文件路径。
NoSuchKey
传入的 sourceKey 在当前 R2 bucket 里不存在。
Missing required environment variable: R2_ACCOUNT_ID
Modal secret 存在,但里面缺少必要字段。
AccessDenied
R2 S3 access key 不正确,或者没有当前 bucket 的读写权限。
Web endpoint Functions require FastAPI
镜像缺少 FastAPI。执行 pip install -r requirements.txt 后重新部署。