main
Backend Deploy 🚀 / build-and-deploy (push) Has been cancelled

This commit is contained in:
Harun CAN
2026-05-01 01:12:09 +02:00
parent 589e773ad6
commit 2d6f068363
2 changed files with 1090 additions and 10 deletions
+1069
View File
File diff suppressed because it is too large Load Diff
+21 -10
View File
@@ -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) {