generated from fahricansecer/boilerplate-be
+1069
File diff suppressed because it is too large
Load Diff
@@ -687,11 +687,10 @@ SCENE STRUCTURE & CONTINUITY
|
|||||||
═══════════════════════════════════
|
═══════════════════════════════════
|
||||||
|
|
||||||
• AI video generators produce best results in 4-6 second bursts.
|
• AI video generators produce best results in 4-6 second bursts.
|
||||||
• You MUST generate enough scenes to cover the targetDuration (targetDuration / 5 = approximate scene count).
|
• You MUST generate EXACTLY the number of scenes requested in the user prompt (targetDuration / 5). DO NOT default to 5 scenes unless explicitly asked for.
|
||||||
• For a 60-second video, you must generate 10 to 15 scenes.
|
• Scene 1 (HOOK): ~5 seconds — instant attention
|
||||||
• Scene 1 (HOOK): 3-5 seconds — instant attention
|
• Middle scenes: ~5 seconds each — continuous visual flow
|
||||||
• Middle scenes: 4-6 seconds each — continuous visual flow
|
• Final scene (CLOSER): ~5 seconds — memorable conclusion
|
||||||
• Final scene (CLOSER): 3-5 seconds — memorable conclusion
|
|
||||||
• Total duration: within ±2 seconds of targetDuration
|
• Total duration: within ±2 seconds of targetDuration
|
||||||
• CONTINUITY: Ensure consecutive visual prompts maintain strict subject, lighting, and camera movement continuity so they blend seamlessly.
|
• CONTINUITY: Ensure consecutive visual prompts maintain strict subject, lighting, and camera movement continuity so they blend seamlessly.
|
||||||
|
|
||||||
@@ -879,7 +878,7 @@ export class VideoAiService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const script = this.parseAndValidateScript(rawText);
|
const script = this.parseAndValidateScript(rawText, input.targetDurationSeconds);
|
||||||
const humanizedScript = this.applyHumanizerPass(script);
|
const humanizedScript = this.applyHumanizerPass(script);
|
||||||
const enrichedScript = this.enrichVisualPrompts(
|
const enrichedScript = this.enrichVisualPrompts(
|
||||||
humanizedScript,
|
humanizedScript,
|
||||||
@@ -1082,6 +1081,7 @@ REQUIREMENTS:
|
|||||||
|
|
||||||
// Aspect ratio → kompozisyon yönlendirmesi
|
// Aspect ratio → kompozisyon yönlendirmesi
|
||||||
const aspectRatioGuide = this.getAspectRatioGuide(input.aspectRatio);
|
const aspectRatioGuide = this.getAspectRatioGuide(input.aspectRatio);
|
||||||
|
const exactSceneCount = Math.floor(input.targetDurationSeconds / 5);
|
||||||
|
|
||||||
let prompt =
|
let prompt =
|
||||||
`Create a YouTube Shorts video script about: "${input.topic}"\n\n` +
|
`Create a YouTube Shorts video script about: "${input.topic}"\n\n` +
|
||||||
@@ -1091,7 +1091,7 @@ REQUIREMENTS:
|
|||||||
`- Visual prompts: ALWAYS in English (for AI image/video generation)\n` +
|
`- Visual prompts: ALWAYS in English (for AI image/video generation)\n` +
|
||||||
`- Video style: ${input.videoStyle} — STRICTLY follow the Visual DNA Map for this style\n` +
|
`- Video style: ${input.videoStyle} — STRICTLY follow the Visual DNA Map for this style\n` +
|
||||||
`- Aspect ratio: ${input.aspectRatio || 'PORTRAIT_9_16'} — ${aspectRatioGuide}\n` +
|
`- Aspect ratio: ${input.aspectRatio || 'PORTRAIT_9_16'} — ${aspectRatioGuide}\n` +
|
||||||
`- SCENE MATH: Each scene must represent 4-6 seconds of video. Total scenes = Target duration / 5.\n` +
|
`- SCENE MATH (CRITICAL): You MUST generate EXACTLY ${exactSceneCount} scenes in the "scenes" array. You are creating a ${input.targetDurationSeconds} second video. Each scene is ~5 seconds. Do NOT generate 5 scenes unless the video is 25 seconds. You MUST output exactly ${exactSceneCount} scenes! Do NOT stop early. Pace your story so it spans EXACTLY ${exactSceneCount} scenes and DO NOT conclude the story until the final scene.\n` +
|
||||||
`- NARRATION PACING: Strict limit of 2 words per second. For a ${input.targetDurationSeconds}s video, write exactly ~${input.targetDurationSeconds * 2} words total across all scenes.\n` +
|
`- NARRATION PACING: Strict limit of 2 words per second. For a ${input.targetDurationSeconds}s video, write exactly ~${input.targetDurationSeconds * 2} words total across all scenes.\n` +
|
||||||
`- CONTINUITY: Consecutive scenes MUST logically flow into each other. Use matching camera angles, consistent lighting, and coherent subject transitions so the video clips stitch together perfectly.\n` +
|
`- CONTINUITY: Consecutive scenes MUST logically flow into each other. Use matching camera angles, consistent lighting, and coherent subject transitions so the video clips stitch together perfectly.\n` +
|
||||||
`- Make it viral-worthy, visually stunning, and intellectually captivating\n` +
|
`- Make it viral-worthy, visually stunning, and intellectually captivating\n` +
|
||||||
@@ -1113,7 +1113,7 @@ REQUIREMENTS:
|
|||||||
prompt += `5. FINISHING: DOF, film stock, color grade, texture, post-processing\n`;
|
prompt += `5. FINISHING: DOF, film stock, color grade, texture, post-processing\n`;
|
||||||
prompt += `Each visualPrompt MUST end with "Avoid: [list of things to avoid]"\n`;
|
prompt += `Each visualPrompt MUST end with "Avoid: [list of things to avoid]"\n`;
|
||||||
prompt += `Scene 1 establishes the visual world — all subsequent scenes maintain continuity.\n`;
|
prompt += `Scene 1 establishes the visual world — all subsequent scenes maintain continuity.\n`;
|
||||||
prompt += `Scene 1 minimum: 80 words | Other scenes minimum: 50 words\n`;
|
prompt += `IMPORTANT FOR LONG VIDEOS: To avoid hitting length limits, keep visual prompts for scenes 2 to ${exactSceneCount} VERY CONCISE (15-20 words max), focusing only on what changes. You MUST finish all ${exactSceneCount} scenes!\n`;
|
||||||
prompt += `═══════════════════════════════════════════\n`;
|
prompt += `═══════════════════════════════════════════\n`;
|
||||||
|
|
||||||
if (input.seoKeywords?.length) {
|
if (input.seoKeywords?.length) {
|
||||||
@@ -1925,7 +1925,7 @@ REQUIREMENTS:
|
|||||||
return dnaMap[videoStyle] || dnaMap['CINEMATIC'];
|
return dnaMap[videoStyle] || dnaMap['CINEMATIC'];
|
||||||
}
|
}
|
||||||
|
|
||||||
private parseAndValidateScript(rawText: string): GeneratedScript {
|
private parseAndValidateScript(rawText: string, targetDurationSeconds?: number): GeneratedScript {
|
||||||
let parsed: GeneratedScript;
|
let parsed: GeneratedScript;
|
||||||
try {
|
try {
|
||||||
let cleanText = rawText.trim();
|
let cleanText = rawText.trim();
|
||||||
@@ -1979,7 +1979,18 @@ REQUIREMENTS:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (parsed.scenes.length < 2) {
|
if (parsed.scenes.length < 2) {
|
||||||
throw new InternalServerErrorException('AI en az 2 sahne üretmelidir.');
|
throw new InternalServerErrorException('AI en az 2 sahne üretmelidir. Lütfen tekrar deneyin.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetDurationSeconds) {
|
||||||
|
const expectedScenes = Math.floor(targetDurationSeconds / 5);
|
||||||
|
// Give 10% margin for Gemini being slightly off, e.g. 24 scenes expected -> min 21 scenes.
|
||||||
|
const minScenes = Math.max(2, Math.floor(expectedScenes * 0.9));
|
||||||
|
if (parsed.scenes.length < minScenes) {
|
||||||
|
throw new InternalServerErrorException(
|
||||||
|
`AI yeterli sahne üretemedi (Beklenen: ~${expectedScenes}, Üretilen: ${parsed.scenes.length}). Bu genellikle uzun videolarda modelin kesilmesinden kaynaklanır. Lütfen "Yeniden Üret" butonuna basın.`
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const scene of parsed.scenes) {
|
for (const scene of parsed.scenes) {
|
||||||
|
|||||||
Reference in New Issue
Block a user