| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127 |
- function registerWhisperRoutes(app, deps) {
- const {
- exec,
- fs,
- path,
- projectRoot,
- whisperDir,
- readManifest,
- writeManifest,
- resolveVideoPath,
- } = deps;
- app.post('/api/whisper/transcribe', async (req, res) => {
- const { videoId, language = 'Chinese', model = 'base' } = req.body;
- if (!videoId) {
- return res.status(400).json({ error: '缺少 videoId 参数' });
- }
- const manifest = readManifest();
- const video = manifest.find(v => v.id === videoId);
- if (!video) {
- return res.status(404).json({ error: `未找到视频: ${videoId}` });
- }
- const videoPath = resolveVideoPath(video.filename);
- if (!fs.existsSync(videoPath)) {
- return res.status(404).json({ error: `视频文件不存在: ${video.filename}` });
- }
- const baseName = video.filename.replace(/\.[^.]+$/, '');
- const outputDir = path.join(whisperDir, baseName);
- if (!fs.existsSync(outputDir)) {
- fs.mkdirSync(outputDir, { recursive: true });
- }
- console.log(`🎙️ 开始 Whisper 转录: ${video.filename}`);
- console.log(` 模型: ${model}, 语言: ${language}`);
- console.log(` 输出目录: ${outputDir}`);
- const cmd = `whisper "${videoPath}" --model ${model} --language ${language} --output_dir "${outputDir}"`;
- try {
- await new Promise((resolve, reject) => {
- const process = exec(cmd, {
- cwd: projectRoot,
- timeout: 10 * 60 * 1000,
- maxBuffer: 10 * 1024 * 1024,
- });
- let stdout = '';
- let stderr = '';
- process.stdout.on('data', (data) => {
- stdout += data;
- console.log(` [whisper] ${data.toString().trim()}`);
- });
- process.stderr.on('data', (data) => {
- stderr += data;
- });
- process.on('close', (code) => {
- if (code === 0) {
- resolve({ stdout, stderr });
- } else {
- reject(new Error(`Whisper 退出码: ${code}\n${stderr}`));
- }
- });
- process.on('error', (err) => {
- reject(new Error(`无法启动 Whisper: ${err.message}`));
- });
- });
- const txtFile = path.join(outputDir, `${baseName}.txt`);
- const srtFile = path.join(outputDir, `${baseName}.srt`);
- const transcript = fs.existsSync(txtFile) ? fs.readFileSync(txtFile, 'utf-8') : '';
- const srt = fs.existsSync(srtFile) ? fs.readFileSync(srtFile, 'utf-8') : '';
- if (!transcript) {
- return res.status(500).json({ error: 'Whisper 执行完成但未生成文字稿' });
- }
- const whisperPaths = {
- transcript: `Whisper/${baseName}/${baseName}.txt`,
- srt: `Whisper/${baseName}/${baseName}.srt`,
- };
- const jsonFile = path.join(outputDir, `${baseName}.json`);
- if (fs.existsSync(jsonFile)) whisperPaths.segments = `Whisper/${baseName}/${baseName}.json`;
- video.whisper = whisperPaths;
- writeManifest(manifest);
- console.log(`✅ Whisper 转录完成: ${baseName}`);
- res.json({
- success: true,
- videoId: video.id,
- transcript,
- srt,
- whisper: whisperPaths,
- outputDir: `Whisper/${baseName}`,
- });
- } catch (err) {
- console.error('❌ Whisper 转录失败:', err.message);
- res.status(500).json({
- error: `Whisper 转录失败: ${err.message}`,
- hint: '请确保已安装 Whisper: pip install openai-whisper',
- });
- }
- });
- app.get('/api/whisper/status', (req, res) => {
- exec('whisper --help', { timeout: 5000 }, (err) => {
- if (err) {
- res.json({ available: false, message: '未检测到 Whisper,请执行: pip install openai-whisper' });
- } else {
- res.json({ available: true, message: 'Whisper 已安装' });
- }
- });
- });
- }
- module.exports = { registerWhisperRoutes };
|