generated from fahricansecer/boilerplate-be
@@ -687,11 +687,10 @@ SCENE STRUCTURE & CONTINUITY
|
||||
═══════════════════════════════════
|
||||
|
||||
• 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).
|
||||
• For a 60-second video, you must generate 10 to 15 scenes.
|
||||
• Scene 1 (HOOK): 3-5 seconds — instant attention
|
||||
• Middle scenes: 4-6 seconds each — continuous visual flow
|
||||
• Final scene (CLOSER): 3-5 seconds — memorable conclusion
|
||||
• 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.
|
||||
• Scene 1 (HOOK): ~5 seconds — instant attention
|
||||
• Middle scenes: ~5 seconds each — continuous visual flow
|
||||
• Final scene (CLOSER): ~5 seconds — memorable conclusion
|
||||
• Total duration: within ±2 seconds of targetDuration
|
||||
• 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 enrichedScript = this.enrichVisualPrompts(
|
||||
humanizedScript,
|
||||
@@ -1082,6 +1081,7 @@ REQUIREMENTS:
|
||||
|
||||
// Aspect ratio → kompozisyon yönlendirmesi
|
||||
const aspectRatioGuide = this.getAspectRatioGuide(input.aspectRatio);
|
||||
const exactSceneCount = Math.floor(input.targetDurationSeconds / 5);
|
||||
|
||||
let prompt =
|
||||
`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` +
|
||||
`- Video style: ${input.videoStyle} — STRICTLY follow the Visual DNA Map for this style\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` +
|
||||
`- 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` +
|
||||
@@ -1113,7 +1113,7 @@ REQUIREMENTS:
|
||||
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 += `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`;
|
||||
|
||||
if (input.seoKeywords?.length) {
|
||||
@@ -1925,7 +1925,7 @@ REQUIREMENTS:
|
||||
return dnaMap[videoStyle] || dnaMap['CINEMATIC'];
|
||||
}
|
||||
|
||||
private parseAndValidateScript(rawText: string): GeneratedScript {
|
||||
private parseAndValidateScript(rawText: string, targetDurationSeconds?: number): GeneratedScript {
|
||||
let parsed: GeneratedScript;
|
||||
try {
|
||||
let cleanText = rawText.trim();
|
||||
@@ -1979,7 +1979,18 @@ REQUIREMENTS:
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
Reference in New Issue
Block a user