feat: 将视频转写重构为纯文字异步语音识别
This commit is contained in:
@@ -34,3 +34,73 @@ You can check out [the Next.js GitHub repository](https://github.com/vercel/next
|
||||
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
|
||||
|
||||
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
|
||||
|
||||
## 视频文字转写(DashScope ASR)
|
||||
|
||||
仅使用 `qwen3-asr-flash-filetrans` 做文字识别,不使用通用模型理解、分类、总结或润色。新视频保存后入队;历史文字保留,后台可单条重转或批量补转。关闭页面不影响已入队任务。
|
||||
|
||||
处理流程:从 MinIO 将原视频流式下载到临时文件 → ffprobe 检查音轨及实际时长 → ffmpeg 提取整段 **16 kHz 单声道、64 kbps MP3** → 上传至 MinIO → 将 **音频 URL** 提交到 DashScope → 后台取回文字。没有分块、视频上传到模型或二次模型调用。无音轨直接保存空文字;ASR 空结果显示“未识别到文字”。
|
||||
|
||||
### 配置与启动
|
||||
|
||||
参考 `.env.example`。模型配置统一为:
|
||||
|
||||
```dotenv
|
||||
DASHSCOPE_API_KEY=你的百炼Key
|
||||
DASHSCOPE_BASE_URL=https://dashscope.aliyuncs.com/api/v1
|
||||
DASHSCOPE_ASR_MODEL=qwen3-asr-flash-filetrans
|
||||
```
|
||||
|
||||
这是 DashScope **原生 API** 地址,不是 `/compatible-mode/v1`。Key 和端点地域必须匹配。也可使用北京业务空间域名的 `/api/v1` 地址。旧 `OPENAI_*`、`QWEN_*` 和转写模块的全局代理配置不再使用;已有 Omni 的百炼 Key 可用于 ASR,仍需账号开通相应模型权限。
|
||||
|
||||
需要 ffmpeg、ffprobe(可通过 `FFMPEG_PATH`、`FFPROBE_PATH` 指定)。`MINIO_ENDPOINT`/端口/SSL 必须是运行机器可鉴权读写的 S3 API;`MINIO_PUBLIC_DOMAIN` 必须让 DashScope 能下载所上传的音频。执行器不修改 Bucket 策略。音频存储于 `transcription-audio/<视频ID>/<时间戳>.mp3`;独立对象防止手动重试覆盖仍在使用的音频。可为该前缀配置不少于 7 天的生命周期,视频原文件不受影响。本地视频临时文件在成功或失败后都会清理。
|
||||
|
||||
```bash
|
||||
npm ci
|
||||
npx prisma generate
|
||||
npm run dev
|
||||
# 另一个终端(开发与生产均需执行器)
|
||||
npm run stt:worker
|
||||
```
|
||||
|
||||
生产使用 `pm2 startOrReload pm2.config.cjs --env production --update-env`,配置同时包含 `DouyinArchive` 和 `DouyinArchive-ASR`。全局最多两个处理中任务,每 10 秒查一次供应商状态。任务保存在 PostgreSQL,不需要 Redis。未配置 Key 不阻止网站启动,转写会显示配置错误。
|
||||
|
||||
### 数据库迁移与发布顺序
|
||||
|
||||
1. 备份现有数据库,保存旧版本用于回退。
|
||||
2. 在停止服务前安装依赖、生成 Prisma Client 并运行 `npm run build`。
|
||||
3. 停止旧网站及旧后台执行器,运行 `npx prisma migrate deploy`。
|
||||
4. 用上述 PM2 命令启动新网站和 ASR 执行器,检查两者日志;确认转写与搜索后再完成发布验收。
|
||||
|
||||
迁移保留 `VideoTranscript` 的历史文字、关联和时间字段;删除 `speech_detected`、`language`、`audio_type`、`non_speech_summary`,以及部分部署存在的 `content_tags`。不自动补转或重转历史视频。新建 `TranscriptionTask` 保存状态、任务 ID、租约和重试信息。重转成功时原子替换文字,失败保留旧文字。
|
||||
|
||||
迁移会替换已知的旧全文检索触发器,并维护 `transcript_zh_tsv` 与 GIN 索引。**已有 `public.zhcfg` 中文分词配置会保留**;新库没有该配置时创建 `simple` 回退配置,它不提供中文分词。新部署若需要与旧库相同的中文搜索效果,先安装同样的中文分词扩展和 `zhcfg`;后续调整分词配置后应重新计算现有索引字段。不要在迁移后直接回滚到依赖旧字段的应用;需要回退时恢复数据库备份和旧应用版本。
|
||||
|
||||
### 接口和任务行为
|
||||
|
||||
- `POST /api/stt`,JSON `{ "awemeId": "视频ID" }`:首次转写或手动重转;处理中重复点击复用当前任务。
|
||||
- `GET /api/stt?awemeId=视频ID`:只读取 `{ status, error, transcript }`,不触发转写。`transcript` 为 `string[] | null`;`null` 表示没有完成记录,`[]` 表示完成但没有文字。
|
||||
- `POST /api/stt/batch`:一次将所有没有完成记录、且未在排队或处理中的视频加入数据库队列,失败记录可补转,历史完成记录不重转。
|
||||
- 状态为 `PENDING`(尚未入队)、`QUEUED`、`PROCESSING`、`SUCCEEDED`、`FAILED`。后台显示各状态数量、错误和重试按钮。
|
||||
|
||||
音频限制为 12 小时、2 GB,超限失败而非截断。执行器重启后复用已有供应商任务 ID;租约到期可恢复领取。提交前写入标记,提交阶段崩溃或超时无法确认任务 ID 时,标为失败并要求核对百炼任务后手动重试,避免盲目重复付费。查询和结果下载的网络错误/429/5xx 按 10 秒至 5 分钟退避重试;鉴权和明确的供应商失败不自动重提。超过 24 小时的任务标为失败。
|
||||
|
||||
### 验证
|
||||
|
||||
```bash
|
||||
npm run test:stt
|
||||
# 必须是独立本地库 douyin_asr_test;此测试会重建该库的 public schema
|
||||
TEST_DATABASE_URL=postgresql://你的本地用户名@127.0.0.1:5432/douyin_asr_test npm run test:stt:integration
|
||||
npx tsc --noEmit
|
||||
npm run build
|
||||
```
|
||||
|
||||
部署后可用管理页测试短视频、超过 5 分钟的视频、无发言/无音轨视频。检查新归档自动入队、关页面继续处理、重启续查、失败保留旧文字及文字搜索。
|
||||
|
||||
也可对已归档的视频独立实测(会上传音频、调用付费 ASR;**不修改数据库里的原转写**):
|
||||
|
||||
```bash
|
||||
npx tsx scripts/stt-smoke.ts 7682010237578136858
|
||||
```
|
||||
|
||||
脚本将供应商任务 ID 和结果保存在 `/tmp/douyin-asr-<视频ID>.json`。已有未完成任务时应查询原任务,不要重复提交。
|
||||
|
||||
Reference in New Issue
Block a user