This commit is contained in:
2026-06-30 15:02:20 +08:00
commit 3948b5a48a
306 changed files with 77275 additions and 0 deletions
+104
View File
@@ -0,0 +1,104 @@
const response = require('../response');
const path = require('path');
function routes(db, log, cfg) {
function getStoragePath() {
const loadConfig = require('../config').loadConfig;
const c = (cfg && cfg.storage) ? cfg : loadConfig();
return path.isAbsolute(c.storage?.local_path)
? c.storage.local_path
: path.join(process.cwd(), c.storage?.local_path || './data/storage');
}
return {
/** 为单条分镜生成 TTS:对白 → audio_local_path;旁白 → narration_audio_local_pathbody.tts_kind === 'narration' */
extract: async (req, res) => {
const { storyboard_id, text, tts_kind } = req.body || {};
if (!text && !storyboard_id) return response.badRequest(res, '请提供 storyboard_id 或 text');
const kind = String(tts_kind || 'dialogue').toLowerCase() === 'narration' ? 'narration' : 'dialogue';
let ttsText = text;
if (kind === 'narration') {
if ((!ttsText || !String(ttsText).trim()) && storyboard_id) {
const row = db.prepare('SELECT narration FROM storyboards WHERE id = ? AND deleted_at IS NULL').get(Number(storyboard_id));
ttsText = row?.narration;
}
if (!ttsText || !String(ttsText).trim()) {
return response.badRequest(res, '分镜解说旁白为空,无法合成语音');
}
} else {
if ((!ttsText || !String(ttsText).trim()) && storyboard_id) {
const row = db.prepare('SELECT dialogue FROM storyboards WHERE id = ? AND deleted_at IS NULL').get(Number(storyboard_id));
ttsText = row?.dialogue;
}
if (!ttsText || !String(ttsText).trim()) {
return response.badRequest(res, '分镜对白为空,无法合成语音');
}
}
try {
const ttsService = require('../services/ttsService');
const result = await ttsService.synthesize(db, log, {
text: ttsText,
storyboard_id: storyboard_id || null,
storage_base: getStoragePath(),
});
if (storyboard_id && result.local_path) {
const now = new Date().toISOString();
try {
if (kind === 'narration') {
db.prepare('UPDATE storyboards SET narration_audio_local_path = ?, updated_at = ? WHERE id = ?').run(
result.local_path, now, Number(storyboard_id)
);
} else {
db.prepare('UPDATE storyboards SET audio_local_path = ?, updated_at = ? WHERE id = ?').run(
result.local_path, now, Number(storyboard_id)
);
}
} catch (_) {}
}
response.success(res, { local_path: result.local_path, url: result.local_path ? '/static/' + result.local_path : '', tts_kind: kind });
} catch (err) {
log.error('audio extract', { error: err.message });
response.internalError(res, err.message);
}
},
/** 批量为多条分镜生成 TTS */
extractBatch: async (req, res) => {
const { storyboard_ids } = req.body || {};
if (!Array.isArray(storyboard_ids) || storyboard_ids.length === 0) {
return response.badRequest(res, 'storyboard_ids 不能为空');
}
const results = [];
const storagePath = getStoragePath();
for (const sbId of storyboard_ids) {
const row = db.prepare('SELECT id, dialogue FROM storyboards WHERE id = ? AND deleted_at IS NULL').get(Number(sbId));
if (!row || !row.dialogue?.trim()) {
results.push({ storyboard_id: sbId, error: '对白为空' });
continue;
}
try {
const ttsService = require('../services/ttsService');
const result = await ttsService.synthesize(db, log, {
text: row.dialogue,
storyboard_id: row.id,
storage_base: storagePath,
});
if (result.local_path) {
const now = new Date().toISOString();
try {
db.prepare('UPDATE storyboards SET audio_local_path = ?, updated_at = ? WHERE id = ?').run(
result.local_path, now, row.id
);
} catch (_) {}
}
results.push({ storyboard_id: sbId, local_path: result.local_path });
} catch (err) {
results.push({ storyboard_id: sbId, error: err.message });
}
}
response.success(res, results);
},
};
}
module.exports = routes;