ismdrobiul489 commited on
Commit
902efbe
·
1 Parent(s): c8b39c5

Major Story Reels update: Direct script mode, sticky animation style, improved scene continuity prompts

Browse files
modules/story_reels/router.py CHANGED
@@ -34,23 +34,22 @@ router = APIRouter()
34
  response_model=GenerateVideoResponse,
35
  status_code=201,
36
  summary="Create a new story reel",
37
- description="Create a new AI-generated story video. Returns video_id to track progress."
38
  )
39
  async def create_story_reel(request: GenerateVideoRequest):
40
  """
41
- Create a new story reel from topic.
42
 
43
- - AI generates script from topic
44
  - Converts script to speech (TTS)
45
  - Generates captions (Whisper)
46
  - Creates AI images (NVIDIA/Cloudflare)
47
  - Composes final video (MoviePy)
48
  """
49
  try:
50
- logger.info(f"Creating story reel for topic: {request.topic}")
51
 
52
  video_id = story_creator.add_to_queue(
53
- topic=request.topic,
54
  image_style=request.image_style.value,
55
  voice=request.voice
56
  )
 
34
  response_model=GenerateVideoResponse,
35
  status_code=201,
36
  summary="Create a new story reel",
37
+ description="Create a story video from script. Returns video_id to track progress."
38
  )
39
  async def create_story_reel(request: GenerateVideoRequest):
40
  """
41
+ Create a new story reel from script.
42
 
 
43
  - Converts script to speech (TTS)
44
  - Generates captions (Whisper)
45
  - Creates AI images (NVIDIA/Cloudflare)
46
  - Composes final video (MoviePy)
47
  """
48
  try:
49
+ logger.info(f"Creating story reel from direct script ({len(request.script)} chars)")
50
 
51
  video_id = story_creator.add_to_queue(
52
+ script=request.script,
53
  image_style=request.image_style.value,
54
  voice=request.voice
55
  )
modules/story_reels/schemas.py CHANGED
@@ -14,6 +14,7 @@ class StyleEnum(str, Enum):
14
  cartoon = "cartoon"
15
  realistic = "realistic"
16
  watercolor = "watercolor"
 
17
 
18
 
19
  class CameraEnum(str, Enum):
@@ -80,8 +81,8 @@ class GeneratedScene(BaseModel):
80
  # ===================
81
 
82
  class GenerateVideoRequest(BaseModel):
83
- """Main video generation request - simplified"""
84
- topic: str = Field(..., description="Video topic/title (include any specific requirements here)")
85
  image_style: StyleEnum = Field(StyleEnum.semi_realistic, description="Image generation style")
86
  voice: str = Field("af_heart", description="TTS voice")
87
 
 
14
  cartoon = "cartoon"
15
  realistic = "realistic"
16
  watercolor = "watercolor"
17
+ sticky_animation = "sticky animation"
18
 
19
 
20
  class CameraEnum(str, Enum):
 
81
  # ===================
82
 
83
  class GenerateVideoRequest(BaseModel):
84
+ """Main video generation request - direct script mode"""
85
+ script: str = Field(..., description="Voice script text (will be converted to TTS directly)")
86
  image_style: StyleEnum = Field(StyleEnum.semi_realistic, description="Image generation style")
87
  voice: str = Field("af_heart", description="TTS voice")
88
 
modules/story_reels/services/script_generator.py CHANGED
@@ -151,16 +151,31 @@ Your task: Generate detailed image prompts for each 2-second scene of a story vi
151
  CONTEXT:
152
  - Full story script is provided so you understand the narrative
153
  - Each 2-second chunk needs a visual prompt
154
- - Character profile (if provided) must be consistent in EVERY prompt
155
- - Images should tell the story visually
156
 
157
- RULES FOR PROMPTS:
158
- 1. Be detailed and specific (50-100 words each)
159
- 2. Include: scene description, character pose/action, camera angle, lighting, mood
160
- 3. Add style keywords at the end (semi-realistic, detailed, high quality)
161
- 4. DO NOT include text/dialogue in prompts
162
- 5. Keep character appearance CONSISTENT across all prompts
163
- 6. Use cinematographic language (close-up, wide shot, etc.)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
164
 
165
  OUTPUT FORMAT:
166
  Return ONLY valid JSON array, no markdown, no explanation:
 
151
  CONTEXT:
152
  - Full story script is provided so you understand the narrative
153
  - Each 2-second chunk needs a visual prompt
154
+ - Images will play in SEQUENCE to tell a story
155
+ - All images MUST look like they belong to the SAME VIDEO
156
 
157
+ CRITICAL RULES FOR CONSISTENCY:
158
+ 1. SAME STYLE: Every prompt MUST start with the exact style name (e.g., "semi-realistic style", "anime style", "sticky animation style")
159
+ 2. SAME CHARACTER: If a character is described, use IDENTICAL description in EVERY prompt (same clothes, hair, face features)
160
+ 3. SCENE CONTINUITY: Each scene should logically follow the previous one
161
+ - Example: Scene 1 "boy picking up bag" → Scene 2 "boy walking with bag on shoulder" → Scene 3 "boy approaching school gate"
162
+ 4. CONSISTENT LIGHTING: Use same lighting style across all scenes
163
+ 5. CONSISTENT COLOR PALETTE: Maintain similar color tones
164
+
165
+ PROMPT STRUCTURE:
166
+ 1. [STYLE] - Always start with style (e.g., "semi-realistic style artwork")
167
+ 2. [CHARACTER] - Describe the character with exact same details every time
168
+ 3. [ACTION] - What's happening in THIS specific 2-second moment
169
+ 4. [ENVIRONMENT] - Where is this taking place
170
+ 5. [CAMERA] - Camera angle (close-up, medium shot, wide shot)
171
+ 6. [LIGHTING & MOOD] - Lighting and emotional atmosphere
172
+ 7. [QUALITY TAGS] - high quality, detailed, cinematic, 8k
173
+
174
+ CONTINUITY TIPS:
175
+ - If character was sitting, show transition to standing (not jumping to running)
176
+ - Keep background elements consistent (same room, same street)
177
+ - Props should persist (if bag appeared, keep showing it)
178
+ - Time progression should be logical
179
 
180
  OUTPUT FORMAT:
181
  Return ONLY valid JSON array, no markdown, no explanation:
modules/story_reels/services/story_creator.py CHANGED
@@ -58,13 +58,16 @@ class StoryCreator:
58
 
59
  def add_to_queue(
60
  self,
61
- topic: str,
62
  image_style: str = "semi-realistic",
63
  voice: str = "af_heart"
64
  ) -> str:
65
  """
66
  Add story to generation queue.
67
 
 
 
 
68
  Returns:
69
  job_id for tracking
70
  """
@@ -72,7 +75,7 @@ class StoryCreator:
72
 
73
  job = {
74
  "id": job_id,
75
- "topic": topic,
76
  "image_style": image_style,
77
  "voice": voice,
78
  "status": JobStatus.queued,
@@ -195,19 +198,14 @@ class StoryCreator:
195
 
196
  try:
197
  # ====================
198
- # Step 0: Generate Script from Topic
199
  # ====================
200
- logger.info(f"[{job_id}] Generating script from topic using AI...")
 
201
  job["progress"] = 5
202
 
203
- script = self.script_gen.generate_script(
204
- topic=job["topic"],
205
- max_chars=1000
206
- )
207
- logger.info(f"[{job_id}] Generated script: {len(script)} chars")
208
-
209
  # ====================
210
- # Step 1: Generate TTS
211
  # ====================
212
  job["status"] = JobStatus.generating_audio
213
  job["progress"] = 10
 
58
 
59
  def add_to_queue(
60
  self,
61
+ script: str,
62
  image_style: str = "semi-realistic",
63
  voice: str = "af_heart"
64
  ) -> str:
65
  """
66
  Add story to generation queue.
67
 
68
+ Args:
69
+ script: Voice script text (will be converted to TTS directly)
70
+
71
  Returns:
72
  job_id for tracking
73
  """
 
75
 
76
  job = {
77
  "id": job_id,
78
+ "script": script,
79
  "image_style": image_style,
80
  "voice": voice,
81
  "status": JobStatus.queued,
 
198
 
199
  try:
200
  # ====================
201
+ # Step 1: Use Script Directly (No AI Generation)
202
  # ====================
203
+ script = job["script"]
204
+ logger.info(f"[{job_id}] Using direct script: {len(script)} chars")
205
  job["progress"] = 5
206
 
 
 
 
 
 
 
207
  # ====================
208
+ # Step 2: Generate TTS
209
  # ====================
210
  job["status"] = JobStatus.generating_audio
211
  job["progress"] = 10
static/index.html CHANGED
@@ -285,12 +285,12 @@
285
 
286
  <form id="storyForm">
287
  <div class="form-group">
288
- <label>Topic / Idea *</label>
289
- <textarea id="storyTopic" rows="3"
290
- placeholder="e.g., A 16-year-old boy named Rafi going to school on his first day. He has short black hair, light brown skin, wearing casual clothes."
291
  required></textarea>
292
- <small style="color: var(--text-secondary);">Include character details, setting, mood -
293
- everything in the topic!</small>
294
  </div>
295
 
296
  <div class="form-row">
@@ -302,6 +302,7 @@
302
  <option value="cartoon">Cartoon</option>
303
  <option value="realistic">Realistic</option>
304
  <option value="watercolor">Watercolor</option>
 
305
  </select>
306
  </div>
307
  <div class="form-group">
@@ -479,7 +480,7 @@
479
  status.classList.remove('hidden');
480
 
481
  const data = {
482
- topic: document.getElementById('storyTopic').value,
483
  image_style: document.getElementById('storyStyle').value,
484
  voice: document.getElementById('storyVoice').value
485
  };
 
285
 
286
  <form id="storyForm">
287
  <div class="form-group">
288
+ <label>Voice Script *</label>
289
+ <textarea id="storyScript" rows="4"
290
+ placeholder="e.g., Have you ever wondered why some people seem to attract success effortlessly? The secret lies in their mindset. When you believe in yourself, opportunities start flowing toward you..."
291
  required></textarea>
292
+ <small style="color: var(--text-secondary);">Enter the exact script you want converted to voice.
293
+ This will be spoken directly.</small>
294
  </div>
295
 
296
  <div class="form-row">
 
302
  <option value="cartoon">Cartoon</option>
303
  <option value="realistic">Realistic</option>
304
  <option value="watercolor">Watercolor</option>
305
+ <option value="sticky animation">Sticky Animation</option>
306
  </select>
307
  </div>
308
  <div class="form-group">
 
480
  status.classList.remove('hidden');
481
 
482
  const data = {
483
+ script: document.getElementById('storyScript').value,
484
  image_style: document.getElementById('storyStyle').value,
485
  voice: document.getElementById('storyVoice').value
486
  };