Files
video-create/.claude/skills/video-from-script/scripts/lib/cmd-create-account.js
sion123 7d526d2b60 feat(video-pipeline): 重构多阶段生成管线并集成 CosyVoice TTS
- 重写 `phase-images`:改为并发 3 张并行生成,每个 item 完成立即写入 manifest,支持 MJ task ID 恢复
- 重写 `phase-videos`:先恢复已有 task ID 再提交新任务(并发 3),支持中断恢复
- 迁移 TTS 引擎:从 Qwen-TTS HTTP 接口切换为 CosyVoice WebSocket 接口,支持音色/语气参数透传
- 精简账号系统:移除 `styles/` 目录、`taskId` 过滤和 `--id` 正则校验,`references` 改为顶层字段
- 调整 `slugify`:限制中文字符 5 个、其他 10 个,避免文件名过长
- 更新文档:`manifest-schema.md` 中 `narration` 改为完整原文案,`account-creation.md` 新增 TTS 配置项
- 配置更新:默认 TTS 模型切换为 `cosyvoice-v3.5-plus`,新增 `localAudio` 参数
2026-05-01 00:44:18 +08:00

90 lines
3.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Command: create-account — 一键创建账号
*
* 创建目录结构 → 复制参考图 → 上传 OSS → 生成 account.json
* prompt 文件通过 Agent Q&A 流程生成(见 account-creation.md
*/
const fs = require('fs')
const path = require('path')
const { ensureDir, log, ACCOUNTS_DIR } = require('./pipeline-utils')
async function createAccount(args) {
const { id, name, desc, format, imageModel, videoModel, references, ttsVoice, ttsInstruction } = args
if (!id) { console.error('错误: 必须指定 --id <账号ID>'); process.exit(1) }
if (!name) { console.error('错误: 必须指定 --name <账号名>'); process.exit(1) }
const accountDir = path.join(ACCOUNTS_DIR, id)
if (fs.existsSync(accountDir)) { console.error(`错误: 账号已存在: ${accountDir}`); process.exit(1) }
ensureDir(accountDir)
ensureDir(path.join(accountDir, 'prompts'))
ensureDir(path.join(accountDir, 'references'))
// 复制参考图到 references/ 并上传 OSS
const refs = (references || '').split(',').filter(Boolean)
const uploadedRefs = []
if (refs.length > 0) {
const { uploadFile } = require('../oss-upload')
for (const refPath of refs) {
const absPath = path.resolve(refPath)
if (!fs.existsSync(absPath)) { console.error(`参考图不存在: ${absPath}`); continue }
const fileName = path.basename(absPath)
const destPath = path.join(accountDir, 'references', fileName)
fs.copyFileSync(absPath, destPath)
try {
const { url } = await uploadFile(destPath)
uploadedRefs.push({ file: fileName, url })
log('account', `参考图 ${fileName} → OK`)
} catch (err) {
uploadedRefs.push({ file: fileName })
log('account', `参考图 ${fileName} 上传失败: ${err.message}(仅保存本地)`)
}
}
}
// 生成 account.json
const accountConfig = {
id,
name,
description: desc || '',
defaultFormat: format || '9:16',
imageModel: imageModel || 'gemini',
videoModel: videoModel || '',
batchSize: 30,
ttsVoice: ttsVoice || '',
ttsInstruction: ttsInstruction || '',
storyboardPrompt: 'prompts/分镜.md',
imageStylePrompt: 'prompts/图片提示词.md',
videoStylePrompt: 'prompts/视频提示词.md',
references: uploadedRefs,
capcut: {
effects: [],
filter: '',
subtitleStyle: {
fontSize: 36,
color: '#FFFFFF',
highlightColor: '#FF6B35',
bold: true,
},
defaultBGM: '',
},
}
const accountPath = path.join(accountDir, 'account.json')
fs.writeFileSync(accountPath, JSON.stringify(accountConfig, null, 2), 'utf-8')
console.log(`\n账号已创建: ${accountDir}`)
console.log(` ID: ${id}`)
console.log(` 名称: ${name}`)
console.log(` 模型: ${accountConfig.imageModel} + ${accountConfig.videoModel || '(未指定)'}`)
console.log(` 参考图: ${uploadedRefs.length} 张(${uploadedRefs.filter(r => r.url).length} 已上传)`)
console.log(`\n下一步: 通过 Agent Q&A 流程生成 prompts/*.md或手动创建\n`)
return accountPath
}
module.exports = { createAccount }