import "dotenv/config"; import { writeFile } from "node:fs/promises"; import { setTimeout as sleep } from "node:timers/promises"; import { prisma } from "../lib/prisma"; import { prepareAudio } from "../lib/stt/audio"; import { downloadTranscript, getAsrConfig, queryTranscription, submitTranscription, } from "../lib/stt/dashscope"; async function main() { const videoId = process.argv[2]; if (!videoId || !/^[A-Za-z0-9_-]+$/.test(videoId)) throw new Error("用法:npx tsx scripts/stt-smoke.ts <视频 ID>"); getAsrConfig(); const video = await prisma.video.findUniqueOrThrow({ where: { aweme_id: videoId }, select: { duration_ms: true }, }); console.log( JSON.stringify({ videoId, durationSeconds: video.duration_ms / 1000, phase: "extracting_audio", }), ); const audioURL = await prepareAudio(videoId); const resultPath = `/tmp/douyin-asr-${videoId}.json`; if (!audioURL) { await writeFile( resultPath, JSON.stringify({ videoId, transcript: [] }, null, 2), ); console.log( JSON.stringify({ phase: "complete", transcript: [], resultPath }), ); return; } const taskId = await submitTranscription(audioURL); await writeFile( resultPath, JSON.stringify({ videoId, taskId, status: "submitted" }, null, 2), ); console.log(JSON.stringify({ phase: "submitted", taskId })); for (let attempt = 0; attempt < 90; attempt++) { await sleep(10_000); const task = await queryTranscription(taskId); if (task.status === "SUCCEEDED") { const transcript = await downloadTranscript(task.resultURL); await writeFile( resultPath, JSON.stringify({ videoId, taskId, transcript }, null, 2), ); console.log( JSON.stringify({ phase: "complete", transcript, resultPath }), ); return; } if (attempt % 6 === 0) console.log(JSON.stringify({ phase: task.status })); } throw new Error( `15 分钟内未完成,任务 ID 已保存在 ${resultPath},请查询原任务而非重复提交`, ); } main() .catch((error) => { // Do not print arbitrary SDK/network errors: they may contain signed URLs. console.error( error instanceof Error && !error.name.startsWith("Prisma") ? error.message : "读取视频或转写失败", ); process.exitCode = 1; }) .finally(() => prisma.$disconnect());