mgbam commited on
Commit
ae86660
Β·
verified Β·
1 Parent(s): bf873b0

Update core/prompt_engineering.py

Browse files
Files changed (1) hide show
  1. core/prompt_engineering.py +252 -237
core/prompt_engineering.py CHANGED
@@ -5,291 +5,306 @@ def create_cinematic_treatment_prompt(user_idea, genre, mood, num_scenes=3, crea
5
  """
6
  Generates a prompt for Gemini to create a full cinematic treatment, including
7
  proactive suggestions for visual style, camera, sound, thematic elements,
8
- and whether a scene is better as an image or a short video clip.
9
- creative_guidance: "standard", "more_artistic", "experimental_narrative"
10
  """
11
- guidance_detail = {
12
- "standard": "Provide solid, genre-appropriate suggestions. Recommend 'image' for most asset types unless strong motion is implied.",
13
- "more_artistic": "Lean into more artistic, unconventional, and visually striking suggestions for style and camera. Suggest unique color palettes or lighting. Consider where a 'video_clip' might offer more impact.",
14
- "experimental_narrative": "Feel free to suggest a minor unexpected narrative twist or a symbolic visual motif. If a scene has significant implied motion or transformation, recommend 'video_clip'."
15
- }[creative_guidance]
 
16
 
17
- # Updated list of fields to request from Gemini
18
  return f"""
19
- You are an AI Creative Director and Master Storyteller, collaborating on a cinematic concept.
20
- Base Idea: "{user_idea}"
21
- Genre: "{genre}"
22
- Mood: "{mood}"
23
- Number of Key Scenes: {num_scenes}
24
- Creative Guidance Level: {creative_guidance} ({guidance_detail})
25
-
26
- Task: Develop a rich cinematic treatment. For EACH of the {num_scenes} key scenes, provide the following 16 fields EXACTLY as named:
27
- 1. `scene_number` (int): Sequential.
28
- 2. `scene_title` (str): A short, evocative title (e.g., "The Neon Rains of Sector 7").
29
- 3. `emotional_beat` (str): The core emotion or feeling this scene should evoke (e.g., "Tension and Suspense", "Hopeful Discovery", "Tragic Realization").
30
- 4. `setting_description` (str): Vivid, sensory details (sight, sound, atmosphere). Where are we? What makes it unique? (40-60 words).
31
- 5. `characters_involved` (list of str): Names of characters central to this scene. If non-speaking or an entity (e.g., "Scavenger Drone"), list them.
32
- 6. `character_focus_moment` (str): For primary character(s), describe a key internal thought, expression, or micro-action revealing their state or arc. If no specific character focus, describe the general atmosphere's impact.
33
- 7. `key_plot_beat` (str): Critical plot development or character action (1-2 sentences). Suitable for brief video overlay.
34
- 8. `suggested_dialogue_hook` (str): One potent line of dialogue. (If no dialogue, state "Silent scene" or describe key non-verbal communication).
35
- 9. `PROACTIVE_visual_style_감독` (str): Your detailed suggestion for this scene's visual style. Specific art movements, film references, color theory, lighting (e.g., "Dutch angles, chiaroscuro, desaturated palette with cyan highlights, Tarkovsky-esque cyberpunk").
36
- 10. `PROACTIVE_camera_work_감독` (str): Your suggestion for impactful camera work. Describe a specific shot or short sequence (e.g., "Slow dolly zoom into protagonist's eyes, whip pan to reveal threat").
37
- 11. `PROACTIVE_sound_design_감독` (str): Key ambient sounds, SFX, and musical mood/instrumentation (e.g., "Ambient: City hum, dripping water. SFX: Glitching spark. Music: Ominous synth pads, detuned piano motif").
38
- 12. `suggested_asset_type_감독` (str): Your recommendation for the primary visual asset for this scene: "image" (for a still) or "video_clip" (for a short ~3-7 second generated video). Default to "image" unless strong motion is described or implied.
39
- 13. `video_clip_motion_description_감독` (str): If `suggested_asset_type_감독` is "video_clip", describe the primary motion in the scene (e.g., "Protagonist slowly turns to face the camera", "Raindrops striking neon puddles, camera pans up", "Spaceship flies past from left to right"). Otherwise, "N/A".
40
- 14. `video_clip_duration_estimate_secs_감독` (int): If `suggested_asset_type_감독` is "video_clip", provide an estimated duration in seconds (e.g., 3, 5, 7). Otherwise, 0.
41
- 15. `image_generation_keywords_감독` (str): A concise list of 5-8 powerful keywords extracted from all above details (setting, characters, action, style, camera, motion if video), for generating a visual asset (image OR video). Focus on nouns, strong adjectives, artistic styles, and key motion verbs if applicable. (e.g., "cyberpunk alleyway, neon rain, lone figure Jax, glowing data streams, high contrast shadows, cinematic low-angle, slow pan").
42
- 16. `pexels_search_query_감독` (str): A concise, effective search query (2-4 words) for Pexels for a background or atmospheric shot (e.g., "rainy neon city," "vast desert landscape," "dark server room").
43
-
44
- If `creative_guidance` is "experimental_narrative", for ONLY ONE scene, you may subtly alter `key_plot_beat` or add a symbolic element to `setting_description` for an unexpected twist. If so, add `director_note` (str) to THAT SCENE ONLY, explaining the choice.
45
-
46
- Output ONLY a valid JSON list of these scene objects. Ensure all field names are exactly as specified (감독 denotes your proactive directorial input).
47
- Example for one scene object (ensure all 16 fields are present for every scene, plus optional director_note):
 
 
 
 
48
  {{
49
  "scene_number": 1,
50
- "scene_title": "Sun-Bleached Mirage",
51
- "emotional_beat": "Desperate Survival",
52
- "setting_description": "Relentless sun on endless rust-colored dunes, shimmering with heat haze. Skeletal remains of colossal, forgotten machinery litter the landscape. Air heavy with dust and decay.",
53
- "characters_involved": ["Anya"],
54
- "character_focus_moment": "Anya's sunburnt hand reaches for her nearly empty water canteen. Doubt flickers, then masked by determination.",
55
- "key_plot_beat": "Anya navigates treacherous dunes, guided by a tattered map, avoiding mechanical scavengers.",
56
- "suggested_dialogue_hook": "(Anya, raspy whisper) 'Almost... just a little further.'",
57
- "PROACTIVE_visual_style_감독": "Widescreen anamorphic, sun-bleached desaturated palette, metallic glints. HDR, harsh sun, deep shadows. 'Mad Max: Fury Road' meets 'Dune (2021)'. Visible heat distortion.",
58
- "PROACTIVE_camera_work_감독": "Extreme long shot of Anya in vast desert, then gritty close-up on her face. Slow, deliberate tracking.",
59
- "PROACTIVE_sound_design_감독": "Ambient: Howling wind, distant creaks. SFX: Sand crunch, strained breathing. Music: Sparse, atmospheric synth drones, percussive hits.",
60
  "suggested_asset_type_감독": "image",
61
  "video_clip_motion_description_감독": "N/A",
62
  "video_clip_duration_estimate_secs_감독": 0,
63
- "image_generation_keywords_감독": "post-apocalyptic desert, lone wanderer Anya, rust dunes, colossal wrecks, heat haze, cinematic widescreen, sun-bleached, determined expression",
64
- "pexels_search_query_감독": "vast desert sun"
65
  }}
66
  """
67
 
68
  def construct_dalle_prompt(scene_data, character_definitions=None, global_style_additions=""):
69
  """
70
- Constructs the final DALL-E prompt for an IMAGE, using keywords from Gemini's treatment,
71
- injecting character details, and global style preferences.
72
  """
73
- scene_title = scene_data.get('scene_title', 'A dramatic moment')
74
- # Use the more generic keyword field, suitable for images
75
- base_keywords = scene_data.get('image_generation_keywords_감독', 'cinematic scene, highly detailed')
76
- setting_desc_context = scene_data.get('setting_description', '')
77
- action_desc_context = scene_data.get('key_plot_beat', '')
78
- director_visual_style = scene_data.get('PROACTIVE_visual_style_감독', '')
79
- director_camera = scene_data.get('PROACTIVE_camera_work_감독', '')
80
- emotional_beat_context = scene_data.get('emotional_beat', scene_title)
81
-
82
- current_scene_character_details = []
83
- characters_involved_in_scene = scene_data.get('characters_involved', [])
84
- if characters_involved_in_scene:
85
- for char_name_from_scene in characters_involved_in_scene:
86
- char_name_clean = char_name_from_scene.strip()
87
- char_lookup_key = char_name_clean.lower()
88
- if character_definitions and char_lookup_key in character_definitions:
89
- char_visual_desc = character_definitions[char_lookup_key]
90
- current_scene_character_details.append(f"{char_name_clean} (depicted as: {char_visual_desc})")
91
  else:
92
- current_scene_character_details.append(char_name_clean)
93
-
94
- character_narrative = ""
95
- if current_scene_character_details:
96
- if len(current_scene_character_details) == 1:
97
- character_narrative = f"The scene focuses on {current_scene_character_details[0]}."
98
- else:
99
- character_narrative = f"The scene prominently features {', '.join(current_scene_character_details[:-1])} and {current_scene_character_details[-1]}."
100
 
101
- final_style_directive = director_visual_style
102
  if global_style_additions:
103
- final_style_directive = f"{director_visual_style}. Additional global style notes: {global_style_additions}."
104
-
105
- prompt = (
106
- f"Create an ultra-detailed, photorealistic, and intensely cinematic still image (digital painting or high-fidelity concept art). "
107
- f"The image must visually embody the scene titled: '{scene_title}'. "
108
- f"Core visual elements and keywords: {base_keywords}. "
109
- f"{character_narrative} "
110
- f"Contextual narrative for the visual: The setting is '{setting_desc_context}'. The key moment is '{action_desc_context}'. "
111
- f"Artistic Direction -- Overall Visual Style and Mood: {final_style_directive}. "
112
- f"Cinematography -- Camera Framing and Perspective for a still image: {director_camera}. " # Emphasize still image context
113
- f"Emotional Impact: Convey a strong sense of '{emotional_beat_context}'. "
114
- f"Technical Execution: Render with extreme detail, sophisticated lighting (e.g., dramatic rim lighting, soft diffused light, harsh contrasts), rich textures, palpable atmospheric effects (e.g., mist, dust, lens flares, rain). "
115
- f"The final image should be of exceptional quality, suitable for a major film production's visual development. "
116
- f"Ensure all specified characters are distinct and adhere to their descriptions if provided. Still image, no motion implied unless essential to the pose."
117
- )
118
- return " ".join(prompt.split()) # Normalize whitespace
 
 
 
 
119
 
120
 
121
- def construct_text_to_video_prompt(scene_data, character_definitions=None, global_style_additions="", seed_image_path=None):
 
122
  """
123
- Constructs a prompt for a text-to-video (or image-to-video) generation model
124
- like Runway Gen-1/Gen-2.
 
125
  """
126
- scene_title = scene_data.get('scene_title', 'A dynamic scene')
127
- # Keywords can be used for styling and core elements
128
- base_keywords = scene_data.get('image_generation_keywords_감독', 'cinematic video clip')
129
- setting_desc = scene_data.get('setting_description', '')
130
- plot_beat = scene_data.get('key_plot_beat', '')
131
- motion_desc = scene_data.get('video_clip_motion_description_감독', 'subtle ambient motion')
132
- visual_style = scene_data.get('PROACTIVE_visual_style_감독', '')
133
- camera_work = scene_data.get('PROACTIVE_camera_work_감독', 'dynamic camera movement')
134
- emotional_beat = scene_data.get('emotional_beat', scene_title)
135
-
136
- current_scene_character_details = []
137
- characters_involved = scene_data.get('characters_involved', [])
138
- if characters_involved:
139
- for char_name in characters_involved:
140
- char_lookup_key = char_name.strip().lower()
141
- if character_definitions and char_lookup_key in character_definitions:
142
- current_scene_character_details.append(f"{char_name.strip()} (as: {character_definitions[char_lookup_key]})")
143
- else:
144
- current_scene_character_details.append(char_name.strip())
145
 
146
- character_narrative = ""
147
- if current_scene_character_details:
148
- character_narrative = f"Characters involved: {', '.join(current_scene_character_details)}. Their appearance and actions should be central."
 
 
 
 
 
 
 
 
 
 
149
 
150
- final_style_directive = visual_style
151
- if global_style_additions:
152
- final_style_directive = f"{visual_style}. Global style notes: {global_style_additions}."
153
-
154
- prompt_parts = [
155
- f"Generate a highly cinematic video clip for a scene titled '{scene_title}'.",
156
- f"Setting: {setting_desc}.",
157
- f"Key moment: {plot_beat}.",
158
- character_narrative if character_narrative else "Focus on the environment and atmosphere if no specific characters are detailed.",
159
- f"Primary Motion: {motion_desc}. This motion should be the central dynamic element of the clip.",
160
- f"Visual Style & Mood: {final_style_directive}. Infuse with a strong sense of '{emotional_beat}'.",
161
- f"Cinematography: Implement camera work described as '{camera_work}'. If specific shots like 'dolly zoom' or 'tracking shot' are mentioned, execute them clearly.",
162
- f"Core visual keywords for styling and content: {base_keywords}.",
163
- "The video should be photorealistic, with extreme detail, sophisticated lighting, rich textures, and palpable atmospheric effects.",
164
- "Ensure high fidelity and smooth motion. The clip should feel like a shot from a major film production."
165
- ]
166
 
167
- if seed_image_path:
168
- prompt_parts.append(f"Use the provided seed image at '{seed_image_path}' to guide the visual style, composition, and content of the video, while incorporating the described motion.")
169
- else:
170
- prompt_parts.append("Generate the video from text description only, creating all visual elements based on the prompt.")
 
 
 
171
 
172
- return " ".join(" ".join(prompt_parts).split()) # Normalize whitespace
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
173
 
174
 
175
  def create_narration_script_prompt_enhanced(story_scenes_data, overall_mood, overall_genre, voice_style="cinematic_trailer"):
176
- scenes_summary = []
177
- for i, scene in enumerate(story_scenes_data):
178
- scenes_summary.append(
179
- f"Scene {scene.get('scene_number', i+1)} (Title: '{scene.get('scene_title','Untitled')}', Beat: '{scene.get('emotional_beat','N/A')}', Asset: {scene.get('suggested_asset_type_감독','image')}):\n"
180
- f" Setting: {scene.get('setting_description','')}\n"
181
- f" Plot Beat: {scene.get('key_plot_beat','')}\n"
182
- f" Character Focus: {scene.get('character_focus_moment','(general atmosphere)')}\n"
183
- f" Dialogue Hook: {scene.get('suggested_dialogue_hook','(none)')}\n"
184
- f" Director's Sound Hint: {scene.get('PROACTIVE_sound_design_감독','')}"
 
 
 
185
  )
186
- full_summary_text = "\n\n".join(scenes_summary)
187
 
188
- voice_style_description = {
189
- "cinematic_trailer": "deep, resonant, slightly epic, building anticipation, and authoritative.",
190
- "documentary_neutral": "clear, informative, objective, and well-paced.",
191
- "introspective_character": f"reflective, personal, possibly first-person, echoing the thoughts of a key character."
192
- }[voice_style]
 
193
 
194
  prompt = f"""
195
- You are an award-winning voiceover scriptwriter for a cinematic animatic.
196
- The animatic uses a mix of still images and short video clips, based on these scene treatments:
197
 
198
  --- SCENE TREATMENTS ---
199
- {full_summary_text}
200
  --- END SCENE TREATMENTS ---
201
 
202
- Overall Genre: {overall_genre}
203
- Overall Mood: {overall_mood}
204
- Desired Voiceover Style: {voice_style} (Characteristics: {voice_style_description})
 
205
 
206
- Your narration script should:
207
- - Weave a cohesive narrative through all scenes.
208
- - Enhance emotional impact, drawing from 'emotional_beat', 'character_focus_moment', and 'sound_hint'.
209
- - Be concise: 1-3 impactful sentences per scene. Total for {len(story_scenes_data)} scenes: approx {len(story_scenes_data) * 15}-{len(story_scenes_data) * 25} words.
210
- - Transcend simple description; offer insight, build tension/emotion, evoke thematic depth.
211
- - If 'introspective_character', write from one prominent character's perspective.
212
- - The output MUST be ONLY the narration script text, ready for text-to-speech. No scene numbers, titles, or directives like "(Voiceover)".
 
213
 
214
- Example (different story):
215
- "Dust motes danced in the lone shaft of light. Each step echoed, a countdown. The air grew colder, heavy with ozone and ancient despair..."
216
 
217
- Craft your narration.
218
  """
219
- return " ".join(prompt.split())
220
 
221
 
222
- def create_scene_regeneration_prompt(original_scene_data, user_feedback, full_story_context=None):
223
- context_str = f"Original scene (Scene Number {original_scene_data.get('scene_number')} - Title: {original_scene_data.get('scene_title')}):\n{json.dumps(original_scene_data, indent=2)}\n\n"
224
- if full_story_context:
225
- context_str += f"Full story context for reference (abbreviated):\n"
226
- for i, scene_ctx in enumerate(full_story_context):
227
- context_str += f" Scene {scene_ctx.get('scene_number', i+1)} Title: {scene_ctx.get('scene_title', 'Untitled')}, Plot: {scene_ctx.get('key_plot_beat', '')[:50]}...\n"
 
 
 
 
 
228
  context_str += "\n"
229
 
230
-
231
  return f"""
232
- You are an AI Script Supervisor and Creative Consultant.
233
- {context_str}
234
- User Feedback for this scene: "{user_feedback}"
235
 
236
- Regenerate ONLY the JSON object for this single scene, incorporating the feedback.
237
- Maintain the exact 16 field structure:
238
- (scene_number, scene_title, emotional_beat, setting_description, characters_involved, character_focus_moment, key_plot_beat, suggested_dialogue_hook, PROACTIVE_visual_style_감독, PROACTIVE_camera_work_감독, PROACTIVE_sound_design_감독, suggested_asset_type_감독, video_clip_motion_description_감독, video_clip_duration_estimate_secs_감독, image_generation_keywords_감독, pexels_search_query_감독).
239
-
240
- Key considerations:
241
- - 'scene_number' MUST NOT change.
242
- - 'key_plot_beat' should be a concise descriptive sentence (max 15-20 words).
243
- - 'image_generation_keywords_감독' should be updated to reflect any visual changes.
244
- - 'pexels_search_query_감독' should also be updated if the setting or mood changes significantly.
245
- - If feedback implies changes to motion or asset type, update 'suggested_asset_type_감독', 'video_clip_motion_description_감독', and 'video_clip_duration_estimate_secs_감독' accordingly. For 'video_clip_motion_description_감독', if type is 'image', set to "N/A". For 'video_clip_duration_estimate_secs_감독', if type is 'image', set to 0.
246
- - If the user's feedback implies experimental narrative changes and the original scene had a `director_note`, you may update or remove it. If introducing a new experimental twist, add/update the `director_note` field.
247
-
248
- Output only the single, updated JSON object for this scene.
 
249
  """
250
 
251
- def create_visual_regeneration_prompt(original_dalle_prompt, user_feedback, scene_data, character_definitions=None, global_style_additions=""):
252
  """
253
- Creates a prompt for Gemini to refine an existing DALL-E prompt for an IMAGE.
254
  """
255
- characters_involved_in_scene = scene_data.get('characters_involved', [])
256
- current_scene_character_details = []
257
- if characters_involved_in_scene:
258
- for char_name_from_scene in characters_involved_in_scene:
259
- char_name_clean = char_name_from_scene.strip(); char_lookup_key = char_name_clean.lower()
260
- if character_definitions and char_lookup_key in character_definitions:
261
- current_scene_character_details.append(f"{char_name_clean} (described as: {character_definitions[char_lookup_key]})")
262
- else: current_scene_character_details.append(char_name_clean)
263
- characters_narrative = f" Characters to feature: {', '.join(current_scene_character_details) if current_scene_character_details else 'None specifically detailed'}."
264
-
265
- full_prompt_for_gemini = f"""
266
- You are an AI Art Director specializing in refining DALL-E 3 prompts for cinematic STILL IMAGES.
267
- The goal is to update an image prompt based on user feedback.
268
-
269
- Scene Context:
270
- - Title: "{scene_data.get('scene_title', '')}"
271
- - Setting: "{scene_data.get('setting_description', '')}"
272
- - Key Plot Beat: "{scene_data.get('key_plot_beat', '')}"
273
- - {characters_narrative}
274
- - Director's Suggested Visual Style: "{scene_data.get('PROACTIVE_visual_style_감독', '')}"
275
- - Director's Suggested Camera: "{scene_data.get('PROACTIVE_camera_work_감독', '')}"
276
- - Current Global Style Additions: "{global_style_additions}"
277
-
278
- The PREVIOUS DALL-E 3 prompt (that generated the image the user wants to change) was:
279
- "{original_dalle_prompt}"
280
-
281
- User Feedback on the visual generated by the previous prompt:
282
- "{user_feedback}"
283
-
284
- Your Task: Generate a NEW, revised DALL-E 3 prompt specifically for a STILL IMAGE.
285
- This new prompt must incorporate the user's feedback to achieve the desired visual changes.
286
- It should remain ultra-detailed, photorealistic, and highly cinematic.
287
- The prompt should guide DALL-E 3 to create a stunning still image suitable for a film's concept art.
288
- Maintain core scene elements (setting, characters, plot beat) unless feedback explicitly asks to change them.
289
- Translate feedback into concrete visual descriptions for a static image (lighting, color, composition, character appearance/pose, atmosphere).
290
- Reinforce character descriptions from the context if they are relevant to the feedback.
291
- The prompt should be a single block of text.
292
-
293
- Output ONLY the new, revised DALL-E 3 prompt string. Do not add any other text before or after the prompt.
 
294
  """
295
- return " ".join(full_prompt_for_gemini.split())
 
5
  """
6
  Generates a prompt for Gemini to create a full cinematic treatment, including
7
  proactive suggestions for visual style, camera, sound, thematic elements,
8
+ and whether a scene is better as an image or a short video clip for AI generation.
9
+ Creative Guidance options: "standard", "more_artistic", "experimental_narrative".
10
  """
11
+ guidance_map = {
12
+ "standard": "Provide solid, genre-appropriate suggestions. Recommend 'image' for most asset types unless strong, specific motion is essential to the scene's core impact.",
13
+ "more_artistic": "Emphasize artistic, unconventional, and visually striking suggestions for style and camera. Suggest unique color palettes or lighting. Be more liberal in recommending 'video_clip' if it can enhance the artistic vision with distinct motion.",
14
+ "experimental_narrative": "Feel free to suggest a minor unexpected narrative twist or a symbolic visual motif within one of the scenes. If a scene has significant implied motion, transformation, or a reveal best shown dynamically, recommend 'video_clip'."
15
+ }
16
+ guidance_description = guidance_map.get(creative_guidance, guidance_map["standard"])
17
 
 
18
  return f"""
19
+ You are an AI Creative Director and Master Storyteller, tasked with developing a cinematic concept.
20
+ Your response MUST be a valid JSON list of scene objects only.
21
+
22
+ Project Details:
23
+ - Core Idea: "{user_idea}"
24
+ - Genre: "{genre}"
25
+ - Overall Mood: "{mood}"
26
+ - Number of Key Scenes: {num_scenes}
27
+ - Creative Direction Style: {creative_guidance} ({guidance_description})
28
+
29
+ For EACH of the {num_scenes} key scenes, provide exactly the following 16 fields:
30
+ 1. `scene_number` (int): Sequential number (1, 2, ...).
31
+ 2. `scene_title` (str): Short, evocative title (e.g., "The Crimson Dawn", "Whispers in the Wires").
32
+ 3. `emotional_beat` (str): The primary emotion or feeling this scene should evoke (e.g., "Rising Tension", "Brief Respite", "Shocking Revelation").
33
+ 4. `setting_description` (str): Vivid sensory details (sight, sound, atmosphere, time of day). Concisely establish where and when (40-70 words).
34
+ 5. `characters_involved` (list of str): Names of characters central to this scene. List non-speaking entities if key (e.g., "Security Drone").
35
+ 6. `character_focus_moment` (str): A key internal thought, subtle expression, or micro-action for the primary character(s) that reveals their state or advances their arc. If no specific character focus, describe the general atmospheric impact or a key object's significance.
36
+ 7. `key_plot_beat` (str): The most critical plot development or character action in this scene (1-2 concise sentences). This should be suitable for a brief video overlay if needed.
37
+ 8. `suggested_dialogue_hook` (str): One potent line of dialogue capturing the scene's essence or a character's voice. If silent, state "Silent scene" or describe key non-verbal communication.
38
+ 9. `PROACTIVE_visual_style_감독` (str): Your detailed, proactive suggestion for this scene's visual style. Be specific: art movements, film references (e.g., "Blade Runner 2049"), color palettes, lighting techniques (e.g., "Chiaroscuro lighting with predominantly cool blues and teals, punctuated by a single warm amber light source. Neo-noir aesthetic with a touch of gothic architecture.").
39
+ 10. `PROACTIVE_camera_work_감독` (str): Your proactive suggestion for impactful camera work. Describe a specific shot, angle, or short sequence (e.g., "Low-angle tracking shot following the character's feet, then tilting up to a dramatic reveal.", "Slow, unsettling push-in on the antagonist's unblinking eye.").
40
+ 11. `PROACTIVE_sound_design_감독` (str): Key ambient sounds, specific SFX, and a suggestion for the musical mood/instrumentation (e.g., "Ambient: Distant, echoing drips and metallic groans. SFX: A sudden, sharp electronic static burst. Music: Brooding, minimalist synth score with a recurring, dissonant motif.").
41
+ 12. `suggested_asset_type_감독` (str): Your recommendation for the primary visual asset for this scene: "image" (for a still concept art) or "video_clip" (for a short ~3-7 second AI-generated video, e.g., Runway Gen-4). Default to "image" unless distinct, describable motion is central to the scene's impact.
42
+ 13. `video_clip_motion_description_감독` (str): If `suggested_asset_type_감독` is "video_clip", provide a concise (1-3 sentences) description of the primary motion to be generated (e.g., "The subject slowly turns their head to look directly at the camera. A subtle breeze ruffles their hair.", "Steam rises from a street vent as the camera slowly pans upwards."). Otherwise, "N/A". This description is key for text-to-video AI.
43
+ 14. `video_clip_duration_estimate_secs_감독` (int): If `suggested_asset_type_감독` is "video_clip", estimate duration in seconds (typically 3-7 seconds, or 5/10 for Gen-4). Otherwise, 0.
44
+ 15. `image_generation_keywords_감독` (str): A concise list of 5-8 powerful keywords extracted from all above details, suitable for AI image generation (e.g., DALL-E). Focus on nouns, strong adjectives, artistic styles. If a video, include keywords that might inform the *initial frame* or *style* if the video AI uses a seed image. (e.g., "cyberpunk cityscape, neon rain, lone figure silhouette, glowing advertisements, high contrast, cinematic lighting, atmospheric perspective").
45
+ 16. `pexels_search_query_감독` (str): A concise, effective search query (2-4 words) for Pexels to find a relevant background or atmospheric stock photo/video (e.g., "rainy neon street," "vast desert sunset," "moody forest path").
46
+
47
+ Special Instruction for "experimental_narrative" Guidance:
48
+ If `creative_guidance` is "experimental_narrative", for ONLY ONE of the scenes, you may subtly alter `key_plot_beat` or add a symbolic element to `setting_description` to introduce an unexpected narrative twist or thematic layer. If you do this, add an additional field `director_note` (str) to THAT SCENE'S JSON OBJECT ONLY, briefly explaining your creative choice for the experimental element.
49
+
50
+ Ensure your entire response is a single, valid JSON list of objects. Each object must contain all 16 specified fields (plus the optional `director_note` if applicable).
51
+ Example of one scene object (ensure all 16 fields are present for every scene, values are illustrative):
52
  {{
53
  "scene_number": 1,
54
+ "scene_title": "First Light on Xylos",
55
+ "emotional_beat": "Awe and Trepidation",
56
+ "setting_description": "The twin suns of Xylos cast long, eerie shadows across a crystalline landscape. Jagged, purple rock formations pierce a sky the color of bruised plums. A faint, alien hum resonates through the thin air.",
57
+ "characters_involved": ["Captain Eva Rostova", "Exploration Drone Unit 7"],
58
+ "character_focus_moment": "Eva touches her helmet, her reflection showing wide eyes scanning the alien vista. A single, hesitant breath escapes her lips, misting in the cold.",
59
+ "key_plot_beat": "Eva takes the first human steps onto Xylos, her drone scouting ahead, as an unknown energy signature is detected nearby.",
60
+ "suggested_dialogue_hook": "Eva (comms, hushed): 'Ground control, Xylos actual. The eagles have landed... and it's breathtakingly strange.'",
61
+ "PROACTIVE_visual_style_감독": "Cinematic sci-fi realism. Style of 'Arrival' meets 'Prometheus'. Sharp focus, deep depth of field, lens flares from the twin suns. Palette dominated by cool purples, blues, and metallic greys, with warm highlights from Eva's suit lights.",
62
+ "PROACTIVE_camera_work_감독": "Initial sweeping wide shot establishing the alien landscape. Followed by a tight, over-the-shoulder shot as Eva steps from the lander, then a POV from the drone.",
63
+ "PROACTIVE_sound_design_감독": "Ambient: Low, resonant alien hum, wind whistling through crystals. SFX: Eva's suit servos, drone whirring. Music: Ethereal, slightly unsettling orchestral score with high strings and deep bass tones.",
64
  "suggested_asset_type_감독": "image",
65
  "video_clip_motion_description_감독": "N/A",
66
  "video_clip_duration_estimate_secs_감독": 0,
67
+ "image_generation_keywords_감독": "alien planet Xylos, crystalline landscape, twin suns, female astronaut Eva, exploration drone, sci-fi realism, cinematic lighting, purple sky, awe-inspiring",
68
+ "pexels_search_query_감독": "alien landscape purple"
69
  }}
70
  """
71
 
72
  def construct_dalle_prompt(scene_data, character_definitions=None, global_style_additions=""):
73
  """
74
+ Constructs a detailed DALL-E prompt for generating a STILL IMAGE.
 
75
  """
76
+ scene_title = scene_data.get('scene_title', 'A dramatic cinematic moment')
77
+ base_keywords = scene_data.get('image_generation_keywords_감독', 'cinematic, highly detailed, photorealistic')
78
+ setting_desc = scene_data.get('setting_description', 'A visually rich environment.')
79
+ plot_beat = scene_data.get('key_plot_beat', 'A key action or event is happening.')
80
+ visual_style_directive = scene_data.get('PROACTIVE_visual_style_감독', 'Default cinematic visual style.')
81
+ camera_perspective = scene_data.get('PROACTIVE_camera_work_감독', 'Dynamic camera angle.')
82
+ emotional_tone = scene_data.get('emotional_beat', scene_title)
83
+
84
+ character_details_list = []
85
+ characters_in_scene = scene_data.get('characters_involved', [])
86
+ if characters_in_scene:
87
+ for char_name_raw in characters_in_scene:
88
+ char_name_norm = char_name_raw.strip()
89
+ char_key = char_name_norm.lower()
90
+ if character_definitions and char_key in character_definitions:
91
+ char_desc_text = character_definitions[char_key]
92
+ character_details_list.append(f"{char_name_norm} (described as: {char_desc_text})")
 
93
  else:
94
+ character_details_list.append(char_name_norm)
95
+
96
+ character_narrative_str = ""
97
+ if character_details_list:
98
+ if len(character_details_list) == 1: character_narrative_str = f"The scene prominently features {character_details_list[0]}."
99
+ else: character_narrative_str = f"The scene features {', '.join(character_details_list[:-1])} and {character_details_list[-1]}."
 
 
100
 
101
+ combined_style_directive = visual_style_directive
102
  if global_style_additions:
103
+ combined_style_directive = f"{visual_style_directive}. Additional overarching style notes: {global_style_additions}."
104
+
105
+ # DALL-E 3 benefits from more descriptive, conversational prompts.
106
+ prompt_elements = [
107
+ f"Create an ultra-detailed, photorealistic, and intensely cinematic digital painting or concept art still image.",
108
+ f"Scene Title: '{scene_title}'.",
109
+ f"Core Elements & Keywords: {base_keywords}.",
110
+ character_narrative_str,
111
+ f"Setting Description: {setting_desc}.",
112
+ f"Key Moment / Plot Beat: {plot_beat}.",
113
+ f"Artistic & Visual Style: {combined_style_directive}.",
114
+ f"Cinematography (for a still image): {camera_perspective}. Consider composition, lighting, and perspective described.",
115
+ f"Emotional Tone to Convey: {emotional_tone}.",
116
+ f"Technical Execution: Achieve extreme detail, sophisticated and purposeful lighting that sculpts forms and defines mood (e.g., dramatic rim lighting, volumetric light, soft diffused light, harsh contrasts), rich and believable textures, and palpable atmospheric effects (e.g., mist, dust, lens flares, rain, heat haze).",
117
+ f"The final image should be of exceptional quality, suitable for a major film production's visual development phase or as a keyframe concept art.",
118
+ f"Ensure any specified characters are distinct and adhere to their provided descriptions. This is a still image, focus on a powerful, frozen moment."
119
+ ]
120
+
121
+ final_prompt_str = " ".join(filter(None, prompt_elements)) # Join non-empty parts
122
+ return " ".join(final_prompt_str.split()) # Normalize whitespace
123
 
124
 
125
+ # <<< THIS IS THE FUNCTION YOUR app.py IS TRYING TO IMPORT >>>
126
+ def construct_text_to_video_prompt_for_gen4(scene_data, global_style_additions=""):
127
  """
128
+ Constructs a text prompt specifically for Runway Gen-4 (image-to-video),
129
+ focusing on MOTION as per their guidelines. The input image for Gen-4
130
+ will provide the scene, characters, and base visual style.
131
  """
132
+ motion_description = scene_data.get('video_clip_motion_description_감독', 'Subtle ambient motion and atmospheric effects.')
133
+ # PROACTIVE_camera_work_감독 might describe a static shot or actual camera motion.
134
+ # We only want to include it if it implies *camera movement*.
135
+ camera_work_suggestion = scene_data.get('PROACTIVE_camera_work_감독', '')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
136
 
137
+ # Keywords for camera motion to look for
138
+ camera_motion_keywords = ["pan", "tilt", "dolly", "zoom", "track", "handheld", "crane", "aerial", "rotate", "orbit", "follow", "move", "travel"]
139
+
140
+ camera_motion_instruction = ""
141
+ if camera_work_suggestion:
142
+ # Check if any motion keyword is present in the camera work suggestion
143
+ if any(keyword in camera_work_suggestion.lower() for keyword in camera_motion_keywords):
144
+ camera_motion_instruction = f"Camera: {camera_work_suggestion}."
145
+ else:
146
+ # If no explicit motion, but camera work is described, it might imply a static shot style
147
+ # For Gen-4, we might omit static camera descriptions unless they add to "style".
148
+ # logger.debug(f"Camera work '{camera_work_suggestion}' seems static, omitting from motion prompt.")
149
+ pass
150
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
151
 
152
+ # Refer to subjects generally as per Runway Gen-4 guide ("the subject", "they", "it")
153
+ # The `motion_description` from Gemini should ideally already do this.
154
+ # We avoid re-describing characters here.
155
+
156
+ prompt_parts = [motion_description]
157
+ if camera_motion_instruction:
158
+ prompt_parts.append(camera_motion_instruction)
159
 
160
+ # Add relevant global style additions if they imply motion style (e.g., "smooth animation", "live-action speed")
161
+ # or general aesthetic that complements the motion.
162
+ # Be careful not to add static visual descriptions here.
163
+ if global_style_additions:
164
+ # Filter global styles for motion-relevant terms if possible, or use sparingly
165
+ # For now, we'll include it as is, assuming it's curated for motion.
166
+ prompt_parts.append(f"Style: {global_style_additions}.")
167
+
168
+ final_prompt = " ".join(prompt_parts).strip()
169
+
170
+ # Runway Gen-4 promptText is <= 1000 characters.
171
+ # Ensure conciseness and focus.
172
+ # "Don't underestimate the power of simplicity in your text prompt" - Runway Guide
173
+ # "Use positive phrasing and avoid negative prompts" - Runway Guide
174
+
175
+ normalized_prompt = " ".join(final_prompt.split()) # Normalize whitespace
176
+ return normalized_prompt[:1000] # Truncate if necessary
177
 
178
 
179
  def create_narration_script_prompt_enhanced(story_scenes_data, overall_mood, overall_genre, voice_style="cinematic_trailer"):
180
+ """
181
+ Generates a prompt for Gemini to write a voiceover narration script.
182
+ """
183
+ scenes_summary_list = []
184
+ for i, scene_item in enumerate(story_scenes_data):
185
+ scenes_summary_list.append(
186
+ f"Scene {scene_item.get('scene_number', i+1)} (Title: '{scene_item.get('scene_title','Untitled Scene')}', Beat: '{scene_item.get('emotional_beat','N/A')}', Asset Type: {scene_item.get('suggested_asset_type_감독','image')}):\n"
187
+ f" Setting: {scene_item.get('setting_description','Not specified.')}\n"
188
+ f" Plot Beat: {scene_item.get('key_plot_beat','Not specified.')}\n"
189
+ f" Character Focus: {scene_item.get('character_focus_moment','General atmosphere or unspecified.')}\n"
190
+ f" Dialogue Hook: {scene_item.get('suggested_dialogue_hook','(No dialogue specified)')}\n"
191
+ f" Director's Sound Hint: {scene_item.get('PROACTIVE_sound_design_감독','Not specified.')}"
192
  )
193
+ full_summary_of_scenes = "\n\n".join(scenes_summary_list)
194
 
195
+ voice_style_details_map = {
196
+ "cinematic_trailer": "deep, resonant, authoritative, perhaps slightly epic, building anticipation.",
197
+ "documentary_neutral": "clear, informative, objective, calm, and well-paced.",
198
+ "introspective_character": f"reflective, personal, possibly first-person (choose a key character from the scenes if appropriate, or use a more omniscient but internal tone), echoing internal thoughts and observations."
199
+ }
200
+ voice_style_description_text = voice_style_details_map.get(voice_style, voice_style_details_map["cinematic_trailer"])
201
 
202
  prompt = f"""
203
+ You are an acclaimed voiceover scriptwriter crafting narration for a cinematic animatic.
204
+ The animatic is composed of AI-generated still images and short video clips, based on the following scene treatments:
205
 
206
  --- SCENE TREATMENTS ---
207
+ {full_summary_of_scenes}
208
  --- END SCENE TREATMENTS ---
209
 
210
+ Overall Story Details:
211
+ - Genre: {overall_genre}
212
+ - Mood: {overall_mood}
213
+ - Desired Voiceover Style: {voice_style} (Characteristics: {voice_style_description_text})
214
 
215
+ Your Task: Write a compelling and concise narration script.
216
+ - The script must weave a cohesive narrative thread that connects all provided scenes.
217
+ - It should enhance the emotional impact and atmosphere, drawing inspiration from each scene's 'emotional_beat', 'character_focus_moment', and 'PROACTIVE_sound_design_감독' hints.
218
+ - Aim for 1-3 impactful sentences per scene. For {len(story_scenes_data)} scenes, the total script length should be approximately {len(story_scenes_data) * 15} to {len(story_scenes_data) * 30} words. Brevity is key.
219
+ - The narration should transcend simple description of on-screen action. Instead, offer insight, build tension or emotion, or evoke thematic depth.
220
+ - If the voice style is 'introspective_character', adopt the perspective of a key character if one is apparent and consistently featured, or maintain a more omniscient internal monologue tone that reflects the story's core emotional journey.
221
+ - The final output MUST be ONLY the narration script text itself, ready for text-to-speech.
222
+ - Do NOT include scene numbers, scene titles, character names in parentheses, or any directives like "(Voiceover)", "Narrator:", "SFX:", etc.
223
 
224
+ Example of desired output format (for a different story):
225
+ "In the shadowed alleys, hope was a contraband currency. Echoes of a forgotten promise led Kaelan deeper into the neon labyrinth, each step a gamble against time. The city's digital heartbeat pulsed with secrets, some best left undisturbed..."
226
 
227
+ Craft your narration now.
228
  """
229
+ return " ".join(prompt.split()) # Normalize whitespace
230
 
231
 
232
+ def create_scene_regeneration_prompt(original_scene_data_dict, user_provided_feedback, full_story_context_list=None):
233
+ """
234
+ Generates a prompt for Gemini to regenerate a single scene's JSON object based on feedback.
235
+ """
236
+ original_scene_json_str = json.dumps(original_scene_data_dict, indent=2)
237
+ context_str = f"Original scene data (Scene Number {original_scene_data_dict.get('scene_number')} - Title: '{original_scene_data_dict.get('scene_title')}' ):\n{original_scene_json_str}\n\n"
238
+
239
+ if full_story_context_list:
240
+ context_str += f"Full story context (abbreviated for reference):\n"
241
+ for i_ctx, scene_ctx_item in enumerate(full_story_context_list):
242
+ context_str += f" Scene {scene_ctx_item.get('scene_number', i_ctx+1)} Title: '{scene_ctx_item.get('scene_title', 'Untitled')}', Plot Beat: '{scene_ctx_item.get('key_plot_beat', '')[:60]}...'\n"
243
  context_str += "\n"
244
 
 
245
  return f"""
246
+ You are an AI Script Supervisor and Creative Consultant, refining a cinematic scene treatment.
247
+ Your response MUST be a single, valid JSON object for the revised scene.
 
248
 
249
+ {context_str}
250
+ User Feedback for improving this specific scene: "{user_provided_feedback}"
251
+
252
+ Task: Regenerate ONLY the JSON object for this single scene, incorporating the user's feedback.
253
+ - Adhere strictly to the original 16 field structure: (scene_number, scene_title, emotional_beat, setting_description, characters_involved, character_focus_moment, key_plot_beat, suggested_dialogue_hook, PROACTIVE_visual_style_감독, PROACTIVE_camera_work_감독, PROACTIVE_sound_design_감독, suggested_asset_type_감독, video_clip_motion_description_감독, video_clip_duration_estimate_secs_감독, image_generation_keywords_감독, pexels_search_query_감독).
254
+ - The 'scene_number' field MUST NOT change.
255
+ - Update fields like 'setting_description', 'key_plot_beat', 'PROACTIVE_visual_style_감독', 'video_clip_motion_description_감독', etc., as implied by the feedback.
256
+ - 'image_generation_keywords_감독' and 'pexels_search_query_감독' MUST be updated if visual elements change.
257
+ - If feedback implies a change in asset type (image vs. video_clip), update 'suggested_asset_type_감독'.
258
+ - If new type is 'image', 'video_clip_motion_description_감독' should be "N/A" and 'video_clip_duration_estimate_secs_감독' should be 0.
259
+ - If new type is 'video_clip', ensure 'video_clip_motion_description_감독' is descriptive and 'video_clip_duration_estimate_secs_감독' is appropriate (e.g., 3-7 seconds).
260
+ - If the feedback suggests experimental narrative changes and the original scene had a `director_note`, you may update or remove that note. If introducing a new experimental element based on feedback, add or update the `director_note` field.
261
+
262
+ Output ONLY the single, complete, and valid JSON object for the revised scene.
263
  """
264
 
265
+ def create_visual_regeneration_prompt(original_dalle_image_prompt, user_provided_feedback, scene_data_dict, character_definitions_map=None, global_style_additions_str=""):
266
  """
267
+ Generates a prompt for Gemini to refine an existing DALL-E prompt for a STILL IMAGE.
268
  """
269
+ characters_in_scene_list = scene_data_dict.get('characters_involved', [])
270
+ character_details_for_prompt = []
271
+ if characters_in_scene_list:
272
+ for char_name_item in characters_in_scene_list:
273
+ clean_char_name = char_name_item.strip(); lookup_key_char = clean_char_name.lower()
274
+ if character_definitions_map and lookup_key_char in character_definitions_map:
275
+ character_details_for_prompt.append(f"{clean_char_name} (described as: {character_definitions_map[lookup_key_char]})")
276
+ else: character_details_for_prompt.append(clean_char_name)
277
+ characters_narrative_for_prompt = f" Characters to potentially feature or consider: {', '.join(character_details_for_prompt) if character_details_for_prompt else 'None specifically detailed in character definitions.'}."
278
+
279
+ full_prompt_for_gemini_refinement = f"""
280
+ You are an AI Art Director specializing in iteratively refining DALL-E 3 prompts for cinematic STILL IMAGES.
281
+ Your goal is to produce a new DALL-E 3 prompt string that incorporates user feedback to achieve a better visual.
282
+ Your response MUST be ONLY the new DALL-E 3 prompt string.
283
+
284
+ Context for the Scene (do not repeat this verbatim in the DALL-E prompt unless relevant to the feedback):
285
+ - Scene Title: "{scene_data_dict.get('scene_title', 'N/A')}"
286
+ - Setting: "{scene_data_dict.get('setting_description', 'N/A')}"
287
+ - Key Plot Beat: "{scene_data_dict.get('key_plot_beat', 'N/A')}"
288
+ - {characters_narrative_for_prompt}
289
+ - Director's Suggested Visual Style for Scene: "{scene_data_dict.get('PROACTIVE_visual_style_감독', 'N/A')}"
290
+ - Director's Suggested Camera for Scene: "{scene_data_dict.get('PROACTIVE_camera_work_감독', 'N/A')}"
291
+ - Current Global Style Additions: "{global_style_additions_str if global_style_additions_str else 'None'}"
292
+
293
+ The PREVIOUS DALL-E 3 prompt (which generated the image the user wants to change) was:
294
+ "{original_dalle_image_prompt}"
295
+
296
+ User Feedback on the visual generated by the PREVIOUS prompt:
297
+ "{user_provided_feedback}"
298
+
299
+ Your Task: Generate a NEW, revised DALL-E 3 prompt string for a STILL IMAGE.
300
+ - This new prompt MUST directly address and incorporate the user's feedback to achieve the desired visual changes.
301
+ - It should maintain or enhance the ultra-detailed, photorealistic, and intensely cinematic qualities.
302
+ - The prompt must guide DALL-E 3 to create a stunning still image suitable for high-end film concept art.
303
+ - Maintain core, unchanged scene elements (setting, characters, plot beat) unless the feedback explicitly requests changes to them.
304
+ - Translate abstract feedback into concrete visual descriptions: specify lighting, color, composition, character appearance/pose/expression, atmosphere, textures, etc., as needed to fulfill the feedback.
305
+ - If characters are mentioned in feedback, ensure their descriptions (if available in context) are reinforced or modified in the new prompt.
306
+ - The output prompt should be a single, coherent block of text, optimized for DALL-E 3.
307
+
308
+ Output ONLY the new, revised DALL-E 3 prompt string. Do not include any other explanatory text, preambles, or apologies.
309
  """
310
+ return " ".join(full_prompt_for_gemini_refinement.split()) # Normalize whitespace