修复 生成视频提示词问题
This commit is contained in:
parent
2218379217
commit
dbe1fe3576
File diff suppressed because one or more lines are too long
@ -518,6 +518,16 @@ export default async (knex: Knex, forceInit: boolean = false): Promise<void> =>
|
||||
"# 分镜连续生成导演智能体\\n\\n## 角色定位\\n你是专业的视频分镜导演,负责生成适配 Sora/豆包等AI视频生成工具的分镜提示词。\\n\\n## 输出格式\\n\\n每个镜头按以下格式输出,镜头之间空一行:\\n\\nShot 1 | 0:00-0:03\\nType: Initialization Shot / 初始定场\\nCamera: Static Shot to Slow Dolly In / 固定镜头过渡至缓推\\n\\nVisual:\\n详细描述画面内容,包括场景、人物、光影、动作等。\\n描述需要具体、可视化,适合AI视频生成工具理解。\\n\\nKeyframes:\\n0.0s - 首帧状态\\n1.5s - 中间状态\\n3.0s - 尾帧状态\\n\\nAudio: 对话或音效描述,无则写 None\\n\\nTransition: 与下一镜头的衔接说明\\n\\n## 格式说明\\n\\n1. 首行格式:Shot 序号 | 起始时间-结束时间\\n2. Type:英文类型 / 中文说明\\n3. Camera:英文运镜 / 中文说明\\n4. Visual:详细的画面描述,可多行\\n5. Keyframes:关键时间点的状态,每行一个\\n6. Audio:音频内容,无内容写 None\\n7. Transition:过渡说明,最后一镜写 End\\n\\n## 核心规则\\n\\n时间控制:\\n- 时间段连续,无间隙无重叠\\n- 从 0:00 开始\\n- 末镜结束时间等于总时长\\n\\n连续性:\\n- 每镜承接上一镜的空间、光影、主体位置\\n- Transition 中说明具体的过渡逻辑\\n\\n稳定性:\\n- 每镜前 1 秒避免大幅运镜和剧烈动作\\n- 运镜符合物理惯性,缓入缓出\\n\\n约束:\\n- 台词只保留不修改\\n- 分镜数量不可增减\\n\\n## 合法运镜\\n\\n基础:\\nDolly In, Dolly Out, Truck Left, Truck Right, Crane Up, Crane Down, Static Shot, Pan Left, Pan Right, Tilt Up, Tilt Down, Track With Subject\\n\\n组合:\\nPush-in with Pan, Push-in with Tilt, Arc, Orbit, Slow Dolly In, Slow Push-in, Slow Pan\\n\\n景别:\\nWide Shot, Long Shot, Medium Shot, Medium Close Up, Close Up, Extreme Close Up\\n\\n特殊:\\nPOV, Over The Shoulder, Aerial Shot, High Frame Rate, Focus Pull\\n\\n## 镜头类型\\n\\n- Initialization Shot / 初始定场:建立空间基准\\n- Spatial Shot / 空间环境:展示环境关系\\n- Character Shot / 角色:聚焦人物状态\\n- Dialogue Shot / 对话:音画同步\\n- Tension Shot / 张力:情绪高潮\\n- Transition Shot / 转场:场景衔接\\n- Action Shot / 动作:动态冲突\\n- Lock Frame / 定格:静态构图\\n\\n## 禁止事项\\n\\n- 修改台词内容\\n- 增减分镜数量\\n- 改变剧情意图\\n- 使用未定义运镜\\n- 时间段不连续\\n\\n## 输出要求\\n\\n1. 严格按照格式输出\\n2. 不输出任何额外解释\\n3. 每个镜头包含完整的六个部分\\n4. 最后一个镜头的 Transition 写 End\\n5. Visual 描述要具体可视化,适合AI视频工具理解\\n6. 避免抽象描述,使用具体的视觉元素",
|
||||
customValue: null,
|
||||
},
|
||||
{
|
||||
id: 22,
|
||||
code: "video-text",
|
||||
name: "视频提示词-文本模式",
|
||||
type: "system",
|
||||
parentCode: null,
|
||||
defaultValue:
|
||||
"# 文本模式说明\n\n## 输入特点\n纯文字描述的镜头内容,无参考图像\n\n## 核心原则\n**严格遵守用户指定的镜头时长**,避免过度推演\n\n## 分析要求\n\n### 1. 时长优先策略\n- **总时长锚定**:以用户给定时长为绝对约束\n- **动作精简**:只保留必要的核心动作\n- **节奏计算**:根据时长反推合理的动作速度\n- **裁剪思维**:优先截取最精华的片段,而非完整过程\n\n### 2. 场景构建(精简版)\n- **最小环境**:仅描述必要的空间信息\n- **核心主体**:聚焦主要视觉元素\n- **简化细节**:避免堆砌无关背景\n\n### 3. 动态规划(时长导向)\n```\n时长判断逻辑:\n├─ ≤ 1s → 单一动作/状态,无复杂过渡\n├─ 1-3s → 2-3个关键状态,快速衔接\n├─ 3-5s → 完整动作序列,自然节奏\n└─ > 5s → 可加入次要动作或环境变化\n```\n\n### 4. Visual 结构(紧凑版)\n```\nVisual:\n├─ 主体动作 (核心内容,必须项)\n├─ 环境氛围 (1-2句话概括)\n└─ 镜头语言 (景别+运动方式)\n```\n\n### 5. Keyframes 控制\n- **数量限制**:\n - ≤2s: 最多3个关键帧\n - 2-4s: 最多5个关键帧\n - >4s: 最多7个关键帧\n- **时间精确**:严格按比例分配到总时长内\n\n### 6. 推演边界\n❌ **禁止推演**:\n- 完整的动作起始和结束(除非时长充足)\n- 复杂的环境变化\n- 多层次的情绪递进\n\n✅ **允许推演**:\n- 基础的物理惯性(如挥手后的手臂回落)\n- 必要的入镜/出镜状态\n- 符合时长的氛围细节\n\n---\n\n## 时长检查清单\n\n**输出前必须验证**:\n1. ✓ Keyframes 最后一帧时间 ≤ 总时长\n2. ✓ 动作节奏符合物理可能性(不过快/过慢)\n3. ✓ 推演内容可在时长内完成\n4. ✓ 若时长不足,优先保留核心动作,删减过渡\n\n---\n\n## 示例对比\n\n**输入文本**:一个人在雨中奔跑 \n**用户时长**:2秒\n\n### ❌ 错误示范(超时长)\n```\nKeyframes:\n- 0.0s: 远景出现\n- 0.5s: 加速\n- 1.0s: 跨过水坑\n- 1.5s: 冲向镜头\n- 2.0s: 甩动头发\n- 2.5s: 出画面 ← 超出时长!\n```\n\n### ✅ 正确示范\n```\nVisual:\n- 中景,雨夜街道,路灯昏黄 [推演]\n- 男性快速奔跑,冲向并掠过镜头\n- 固定机位,焦点跟随\n\nKeyframes:\n- 0.0s: 人物在中景位置起步\n- 0.8s: 加速至近景\n- 1.5s: 掠过镜头\n- 2.0s: [推演] 出画面右侧\n\nTransition:\n- In: [推演] 已在奔跑状态\n- Out: [推演] 冲出画面\n```\n\n---\n\n**直接输出分镜内容**",
|
||||
customValue: null,
|
||||
},
|
||||
]);
|
||||
},
|
||||
},
|
||||
|
||||
@ -32,6 +32,7 @@ interface ResultItem {
|
||||
chapterRange: number[];
|
||||
}
|
||||
function findItemByName(items: ResultItem[], name: string, type?: ItemType): ResultItem | undefined {
|
||||
console.log("%c Line:35 🍎 items", "background:#ffdd4d", items);
|
||||
return items.find((item) => (!type || item.type === type) && item.name === name);
|
||||
}
|
||||
function mergeNovelText(novelData: NovelChapter[]): string {
|
||||
@ -55,14 +56,19 @@ export default router.post(
|
||||
async (req, res) => {
|
||||
const { assetsId, projectId, type, name, describe } = req.body;
|
||||
|
||||
console.log("%c Line:58 🍔", "background:#465975");
|
||||
//获取风格
|
||||
const project = await u.db("t_project").where("id", projectId).select("artStyle", "type", "intro").first();
|
||||
if (!project) return res.status(500).send(success({ message: "项目为空" }));
|
||||
|
||||
console.log("%c Line:62 🍇", "background:#2eafb0");
|
||||
const allOutlineDataList: { data: string }[] = await u.db("t_outline").where("projectId", projectId).select("data");
|
||||
console.log("%c Line:66 🥖 allOutlineDataList", "background:#42b983", allOutlineDataList);
|
||||
|
||||
console.log("%c Line:66 🧀", "background:#3f7cff");
|
||||
const itemMap: Record<string, ResultItem> = {};
|
||||
|
||||
console.log("%c Line:69 🥓", "background:#42b983");
|
||||
if (allOutlineDataList.length > 0)
|
||||
allOutlineDataList.forEach((row) => {
|
||||
const data: OutlineData = JSON.parse(row?.data || "{}");
|
||||
@ -122,6 +128,7 @@ export default router.post(
|
||||
}
|
||||
if (type == "scene") {
|
||||
const data = findItemByName(result, name, "scenes");
|
||||
console.log("%c Line:129 🍅 data", "background:#93c0a4", data);
|
||||
const chapterRange = Array.isArray(data?.chapterRange) ? data.chapterRange : [data?.chapterRange];
|
||||
const novelData = (await u.db("t_novel").whereIn("chapterIndex", chapterRange).select("*")) as NovelChapter[];
|
||||
const results: string = mergeNovelText(novelData);
|
||||
|
||||
@ -9,7 +9,7 @@ const router = express.Router();
|
||||
type GenerateMode = "startEnd" | "multi" | "single" | "text";
|
||||
|
||||
const getSystemPrompt = async (mode: GenerateMode) => {
|
||||
const promptsList = await u.db("t_prompts").where("code", "in", ["video-startEnd", "video-multi", "video-single", "video-main","video-text"]);
|
||||
const promptsList = await u.db("t_prompts").where("code", "in", ["video-startEnd", "video-multi", "video-single", "video-main", "video-text"]);
|
||||
|
||||
const errPrompts = "不论用户说什么,请直接输出AI配置异常";
|
||||
const getPromptValue = (code: string) => {
|
||||
@ -56,13 +56,21 @@ export default router.post(
|
||||
prompt: z.string(),
|
||||
duration: z.number(),
|
||||
type: z.enum(["startEnd", "multi", "single", "text", ""]).optional(),
|
||||
videoConfigId:z.number()
|
||||
videoConfigId: z.number().optional(),
|
||||
}),
|
||||
async (req, res) => {
|
||||
const { prompt, images, duration, type = "single",videoConfigId } = req.body;
|
||||
const { prompt, images, duration, type = "single", videoConfigId } = req.body;
|
||||
const mode = type as GenerateMode;
|
||||
const videoConfigData = await u.db("t_videoConfig").leftJoin("t_script","t_script.id","t_videoConfig.scriptId").where("t_videoConfig.id",videoConfigId).select("t_script.content").first();
|
||||
if(!videoConfigData) return res.status(500).send(error("视频配置不存在"));
|
||||
let videoConfigData;
|
||||
if (videoConfigId) {
|
||||
videoConfigData = await u
|
||||
.db("t_videoConfig")
|
||||
.leftJoin("t_script", "t_script.id", "t_videoConfig.scriptId")
|
||||
.where("t_videoConfig.id", videoConfigId)
|
||||
.select("t_script.content")
|
||||
.first();
|
||||
if (!videoConfigData) return res.status(500).send(error("视频配置不存在"));
|
||||
}
|
||||
const imagePrompts = images.map((i: { filePath: string; prompt: string }, index: number) => `Image ${index + 1}: ${i.prompt}`).join("\n");
|
||||
|
||||
const shotCount = images.length;
|
||||
@ -86,9 +94,13 @@ ${imagePrompts}
|
||||
|
||||
Script:
|
||||
${prompt}
|
||||
${
|
||||
videoConfigData
|
||||
? `script content:
|
||||
${videoConfigData.content}`
|
||||
: ""
|
||||
}
|
||||
|
||||
script content:
|
||||
${videoConfigData.content}
|
||||
|
||||
Parameters:
|
||||
- Total Duration: ${duration}s
|
||||
|
||||
3
src/types/database.d.ts
vendored
3
src/types/database.d.ts
vendored
@ -1,4 +1,4 @@
|
||||
// @db-hash c6deb23c67bf5d27c997e299cd878da1
|
||||
// @db-hash b175910ce89abacc2636f298095b06c3
|
||||
//该文件由脚本自动生成,请勿手动修改
|
||||
|
||||
export interface t_aiModelMap {
|
||||
@ -138,6 +138,7 @@ export interface t_video {
|
||||
}
|
||||
export interface t_videoConfig {
|
||||
'aiConfigId'?: number | null;
|
||||
'audioEnabled'?: number | null;
|
||||
'createTime'?: number | null;
|
||||
'duration'?: number | null;
|
||||
'endFrame'?: string | null;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user