onenoly11 commited on
Commit
6126277
·
verified ·
1 Parent(s): 760306f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +154 -32
app.py CHANGED
@@ -2,12 +2,15 @@ import os
2
  import gradio as gr
3
  import requests
4
  import random
 
5
  from datetime import datetime
 
6
 
7
- # Your xAI API key
8
  XAI_API_KEY = os.environ.get('XAI_API_KEY')
 
9
 
10
- # Expanded movie database with more genres
11
  MOVIE_TEMPLATES = {
12
  "epic_fantasy": {
13
  "title": "🏰 Epic Fantasy Quest",
@@ -46,18 +49,18 @@ MOVIE_TEMPLATES = {
46
  }
47
  }
48
 
49
- # Top 2025 actors (sourced from box office & buzz)
50
  TOP_ACTORS = [
51
  "Tom Holland", "Dwayne Johnson", "Tom Cruise", "Chris Hemsworth", "Pedro Pascal",
52
  "Robert Downey Jr.", "Will Smith", "Jason Statham", "Rachel Zegler", "Eiza González",
53
  "Monica Barbaro", "Sophie Wilde", "Joseph Quinn", "David Corenswet"
54
  ]
55
 
56
- # MPAA ratings
57
  MPAA_RATINGS = ["G", "PG", "PG-13", "R", "NC-17"]
58
 
59
  def test_connection():
60
- """Test xAI connection with better error handling"""
61
  if not XAI_API_KEY:
62
  return "❌ API key not found in environment", "🔴 Offline"
63
 
@@ -71,9 +74,25 @@ def test_connection():
71
  except Exception as e:
72
  return f"❌ Connection error: {str(e)}", "🔴 Offline"
73
 
74
- def generate_cinematic_story(original_story, sequel_start, selected_actors, extras, story_type="epic_fantasy"):
75
- """Generate a cinematic story with casting, extras, and rating"""
 
 
76
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
  if not original_story or not sequel_start:
78
  return "❌ Please fill in both story fields!"
79
 
@@ -112,7 +131,7 @@ def generate_cinematic_story(original_story, sequel_start, selected_actors, extr
112
  'model': 'grok-beta',
113
  'messages': [{'role': 'user', 'content': prompt}],
114
  'max_tokens': 600,
115
- 'temperature': 0.8 # Bumped for creativity
116
  }
117
 
118
  try:
@@ -136,6 +155,9 @@ def generate_cinematic_story(original_story, sequel_start, selected_actors, extr
136
 
137
  cast_section = f"**CAST HIGHLIGHTS:**\n• Lead: {lead_actor}\n" + "\n".join([f"• Support: {a}" for a in support_actors]) if support_actors else ""
138
 
 
 
 
139
  return f"""
140
  🎬 **PRODUCTION MEMO: {story_type.upper()} SEQUEL** 🎬
141
  **Project ID:** {production_id} | **Rating:** {rating} | **Genre:** {MOVIE_TEMPLATES[story_type]['title']}
@@ -148,15 +170,15 @@ def generate_cinematic_story(original_story, sequel_start, selected_actors, extr
148
  **CAST SHEET:**
149
  {cast_section}
150
 
151
- ✨ Lights, camera, sequel! Export to script? 🚀
152
- """
 
153
 
154
  def _generate_fallback_story(original_story, sequel_start, lead_actor, support_actors, extras, story_type, rating):
155
- """Rich fallback story generation"""
156
  extras_str = f" with twists like {extras}" if extras else ""
157
  support_str = f" alongside {', '.join(support_actors)}" if support_actors else ""
158
 
159
- # Genre-tailored plot
160
  if "fantasy" in story_type:
161
  plot = f"Years after {original_story}, {lead_actor} reprises the scarred warrior-king, facing a cataclysmic rift summoning shadow beasts{support_str}. {extras_str} In blistering battles across fractured realms, {lead_actor} uncovers a betrayal that tests loyalty and reignites old flames. Key scenes: A throne-room ambush, a forbidden portal chase, and an earth-shaking demon duel. Arc: From jaded ruler to unbreakable legend."
162
  elif "sci_fi" in story_type:
@@ -168,10 +190,10 @@ def _generate_fallback_story(original_story, sequel_start, lead_actor, support_a
168
  else: # rom_com
169
  plot = f"Following {original_story}, {lead_actor} navigates love's chaos at a luxury resort{support_str}. {extras_str} Mishaps like mistaken identities and beachside confessions spark hilarity. Key scenes: Awkward speed-dating fiasco, midnight dance mix-up, heartfelt airport dash. Arc: Commitment-phobe to forever optimist."
170
 
171
- return f"**SYNOPSIS:** {plot}\n\n**Why It Works:** High-stakes{ ' + emotional depth' if 'rom' in story_type else ''}, perfect for {rating} crowds. Budget: $150M. Greenlight now!"
172
 
173
  def generate_movie_pitch(selected_actors=None):
174
- """Generate a movie pitch with random cast if none selected"""
175
  if not selected_actors:
176
  selected_actors = random.sample(TOP_ACTORS, 3)
177
 
@@ -186,6 +208,8 @@ def generate_movie_pitch(selected_actors=None):
186
  logline = random.choice(template['examples'])
187
  franchise_potential = '🟢 HIGH' if random.random() > 0.5 else '🟡 MEDIUM'
188
 
 
 
189
  pitch = f"""
190
  🎬 **GREENLIGHT PITCH DECK** 🎬
191
 
@@ -204,27 +228,88 @@ def generate_movie_pitch(selected_actors=None):
204
  • {supports[1] if len(supports) > 1 else 'TBD'}: Emotional anchor
205
 
206
  🟢 **READY FOR DEVELOPMENT?** This one's a box-office beast!
 
207
  """
208
- return pitch
209
 
210
- # Polished Interface
211
- with gr.Blocks(title="IdeaForge Studio v2", theme=gr.themes.Base(primary_hue="amber")) as demo:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
212
 
213
  gr.Markdown("""
214
- # 🎬 **IdeaForge Studio v2**
215
- ### AI-Powered Blockbuster Builder | Cast Stars, Rate It, Pitch It!
216
- *Powered by xAI | Generate sequels & pitches with 2025's top talent.*
217
  """)
218
 
219
- # Status Row
220
  with gr.Row():
221
  with gr.Column(scale=1):
222
- status_btn = gr.Button("📡 Test xAI Connection", variant="secondary")
 
223
  with gr.Column(scale=4):
224
- status_msg = gr.Textbox(label="Connection Log", show_label=False, lines=1)
225
- status_icon = gr.Textbox(label="Status", show_label=False, max_lines=1)
 
 
226
 
227
- # Main Tabs
228
  with gr.Tab("🎞️ Sequel Forge"):
229
  gr.Markdown("### Craft Epic Sequels with Custom Cast")
230
 
@@ -281,14 +366,16 @@ with gr.Blocks(title="IdeaForge Studio v2", theme=gr.themes.Base(primary_hue="am
281
  )
282
 
283
  generate_btn = gr.Button("🎬 Generate Full Sequel!", variant="primary", size="lg")
284
- story_output = gr.Markdown(label="Your Blockbuster Bible", show_label=True)
 
285
 
286
  generate_btn.click(
287
  generate_cinematic_story,
288
  inputs=[original_input, sequel_input, actor_select, extras_input, story_type_dropdown],
289
- outputs=story_output
290
  )
291
 
 
292
  with gr.Tab("💡 Pitch Roulette"):
293
  gr.Markdown("### Instant Greenlight Concepts")
294
 
@@ -305,12 +392,47 @@ with gr.Blocks(title="IdeaForge Studio v2", theme=gr.themes.Base(primary_hue="am
305
  )
306
 
307
  pitch_btn = gr.Button("✨ Generate Pitch Deck!", variant="primary")
308
- pitch_output = gr.Markdown(label="Hot Pitch", show_label=True)
 
309
 
310
- pitch_btn.click(generate_movie_pitch, inputs=[pitch_actor_select], outputs=pitch_output)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
311
 
312
- # Connection
313
- status_btn.click(test_connection, outputs=[status_msg, status_icon])
 
314
 
315
  if __name__ == "__main__":
316
- demo.launch(share=True) # Enable public link for easy sharing
 
2
  import gradio as gr
3
  import requests
4
  import random
5
+ import time
6
  from datetime import datetime
7
+ from typing import Optional
8
 
9
+ # API Keys
10
  XAI_API_KEY = os.environ.get('XAI_API_KEY')
11
+ RUNWAY_API_KEY = os.environ.get('RUNWAY_API_KEY')
12
 
13
+ # Expanded movie database (unchanged)
14
  MOVIE_TEMPLATES = {
15
  "epic_fantasy": {
16
  "title": "🏰 Epic Fantasy Quest",
 
49
  }
50
  }
51
 
52
+ # Top 2025 actors (unchanged)
53
  TOP_ACTORS = [
54
  "Tom Holland", "Dwayne Johnson", "Tom Cruise", "Chris Hemsworth", "Pedro Pascal",
55
  "Robert Downey Jr.", "Will Smith", "Jason Statham", "Rachel Zegler", "Eiza González",
56
  "Monica Barbaro", "Sophie Wilde", "Joseph Quinn", "David Corenswet"
57
  ]
58
 
59
+ # MPAA ratings (unchanged)
60
  MPAA_RATINGS = ["G", "PG", "PG-13", "R", "NC-17"]
61
 
62
  def test_connection():
63
+ """Test xAI connection (unchanged)"""
64
  if not XAI_API_KEY:
65
  return "❌ API key not found in environment", "🔴 Offline"
66
 
 
74
  except Exception as e:
75
  return f"❌ Connection error: {str(e)}", "🔴 Offline"
76
 
77
+ def test_runway_connection():
78
+ """Test Runway ML connection"""
79
+ if not RUNWAY_API_KEY:
80
+ return "❌ Runway API key not found", "🔴 Offline"
81
 
82
+ headers = {'Authorization': f'Bearer {RUNWAY_API_KEY}', 'Content-Type': 'application/json'}
83
+ base_url = 'https://api.runwayml.com/v1'
84
+ try:
85
+ # Simple ping: GET /tasks (or models if available; using a safe endpoint)
86
+ response = requests.get(f"{base_url}/tasks", headers=headers, timeout=10)
87
+ if response.status_code == 200 or response.status_code == 401: # 401 ok for auth test
88
+ return "✅ Runway Connected! Videos incoming... 🎞️", "🟢 Online"
89
+ else:
90
+ return f"❌ Runway Error: {response.status_code}", "🔴 Offline"
91
+ except Exception as e:
92
+ return f"❌ Runway Connection error: {str(e)}", "🔴 Offline"
93
+
94
+ def generate_cinematic_story(original_story, sequel_start, selected_actors, extras, story_type="epic_fantasy"):
95
+ """Generate story (unchanged from v2)"""
96
  if not original_story or not sequel_start:
97
  return "❌ Please fill in both story fields!"
98
 
 
131
  'model': 'grok-beta',
132
  'messages': [{'role': 'user', 'content': prompt}],
133
  'max_tokens': 600,
134
+ 'temperature': 0.8
135
  }
136
 
137
  try:
 
155
 
156
  cast_section = f"**CAST HIGHLIGHTS:**\n• Lead: {lead_actor}\n" + "\n".join([f"• Support: {a}" for a in support_actors]) if support_actors else ""
157
 
158
+ # Return story with trailer prompt extraction (key scene for video)
159
+ trailer_prompt = story.split('Key scenes:')[1].split('.')[0].strip() if 'Key scenes:' in story else f"Epic {story_type} battle featuring {lead_actor}"
160
+
161
  return f"""
162
  🎬 **PRODUCTION MEMO: {story_type.upper()} SEQUEL** 🎬
163
  **Project ID:** {production_id} | **Rating:** {rating} | **Genre:** {MOVIE_TEMPLATES[story_type]['title']}
 
170
  **CAST SHEET:**
171
  {cast_section}
172
 
173
+ ✨ Lights, camera, sequel! Ready for trailer? 🚀
174
+ **Trailer Prompt:** {trailer_prompt}
175
+ """, trailer_prompt
176
 
177
  def _generate_fallback_story(original_story, sequel_start, lead_actor, support_actors, extras, story_type, rating):
178
+ """Fallback (unchanged)"""
179
  extras_str = f" with twists like {extras}" if extras else ""
180
  support_str = f" alongside {', '.join(support_actors)}" if support_actors else ""
181
 
 
182
  if "fantasy" in story_type:
183
  plot = f"Years after {original_story}, {lead_actor} reprises the scarred warrior-king, facing a cataclysmic rift summoning shadow beasts{support_str}. {extras_str} In blistering battles across fractured realms, {lead_actor} uncovers a betrayal that tests loyalty and reignites old flames. Key scenes: A throne-room ambush, a forbidden portal chase, and an earth-shaking demon duel. Arc: From jaded ruler to unbreakable legend."
184
  elif "sci_fi" in story_type:
 
190
  else: # rom_com
191
  plot = f"Following {original_story}, {lead_actor} navigates love's chaos at a luxury resort{support_str}. {extras_str} Mishaps like mistaken identities and beachside confessions spark hilarity. Key scenes: Awkward speed-dating fiasco, midnight dance mix-up, heartfelt airport dash. Arc: Commitment-phobe to forever optimist."
192
 
193
+ return f"**SYNOPSIS:** {plot}\n\n**Why It Works:** High-stakes{ ' + emotional depth' if 'rom' in story_type else ''}, perfect for {rating} crowds. Budget: $150M. Greenlight now!\n**Key scenes:** {plot.split('Key scenes:')[1] if 'Key scenes:' in plot else 'Epic showdown.'}"
194
 
195
  def generate_movie_pitch(selected_actors=None):
196
+ """Pitch (unchanged)"""
197
  if not selected_actors:
198
  selected_actors = random.sample(TOP_ACTORS, 3)
199
 
 
208
  logline = random.choice(template['examples'])
209
  franchise_potential = '🟢 HIGH' if random.random() > 0.5 else '🟡 MEDIUM'
210
 
211
+ trailer_prompt = f"{logline} - cinematic trailer shot with dramatic music."
212
+
213
  pitch = f"""
214
  🎬 **GREENLIGHT PITCH DECK** 🎬
215
 
 
228
  • {supports[1] if len(supports) > 1 else 'TBD'}: Emotional anchor
229
 
230
  🟢 **READY FOR DEVELOPMENT?** This one's a box-office beast!
231
+ **Trailer Prompt:** {trailer_prompt}
232
  """
233
+ return pitch, trailer_prompt
234
 
235
+ def generate_video_trailer(prompt: str, duration: int = 5) -> str:
236
+ """Generate video trailer using Runway ML API"""
237
+ if not RUNWAY_API_KEY:
238
+ # Fallback: Placeholder video URL (e.g., stock trailer)
239
+ return "https://example.com/placeholder-trailer.mp4", "No Runway key—using demo clip. Add RUNWAY_API_KEY for real gen!"
240
+
241
+ headers = {
242
+ 'Authorization': f'Bearer {RUNWAY_API_KEY}',
243
+ 'Content-Type': 'application/json'
244
+ }
245
+ base_url = 'https://api.runwayml.com/v1'
246
+
247
+ # Create task (text-to-video params based on Runway docs)
248
+ create_data = {
249
+ "model": "gen3a_turbo", # Latest text-to-video model (2025)
250
+ "text_prompt": prompt + " | Cinematic trailer style, dramatic lighting, high-energy action, epic music swell.",
251
+ "seconds": duration,
252
+ "aspect_ratio": "16:9",
253
+ "turbo": True, # Faster gen
254
+ "explore_mode": True # More creative
255
+ }
256
+
257
+ try:
258
+ # Start task
259
+ create_resp = requests.post(f"{base_url}/text_to_video", headers=headers, json=create_data, timeout=30)
260
+ create_resp.raise_for_status()
261
+ task_data = create_resp.json()
262
+ task_id = task_data.get('id') or task_data.get('task_id')
263
+ if not task_id:
264
+ raise ValueError("No task ID in response")
265
+
266
+ # Poll for completion (every 10s, up to 5 min)
267
+ status = "processing"
268
+ for _ in range(30): # ~5 min max
269
+ time.sleep(10)
270
+ status_resp = requests.get(f"{base_url}/tasks/{task_id}", headers=headers, timeout=10)
271
+ status_resp.raise_for_status()
272
+ status_data = status_resp.json()
273
+ status = status_data.get('status')
274
+
275
+ if status == 'succeeded':
276
+ # Extract video URL
277
+ output = status_data.get('output', {})
278
+ video_url = output.get('video_url') or output.get('assets', [{}])[0].get('url')
279
+ if video_url:
280
+ return video_url, f"✅ Trailer generated! ({duration}s clip)"
281
+ else:
282
+ raise ValueError("No video URL in output")
283
+ elif status == 'failed':
284
+ error_msg = status_data.get('error', 'Unknown error')
285
+ raise Exception(f"Generation failed: {error_msg}")
286
+
287
+ raise TimeoutError("Generation timed out after 5 min")
288
+
289
+ except Exception as e:
290
+ return None, f"❌ Error: {str(e)}. Check key/credits. Fallback: Imagine epic footage here! 🎞️"
291
+
292
+ # Polished Interface (v3 with Video Tab)
293
+ with gr.Blocks(title="IdeaForge Studio v3", theme=gr.themes.Base(primary_hue="amber")) as demo:
294
 
295
  gr.Markdown("""
296
+ # 🎬 **IdeaForge Studio v3**
297
+ ### AI Blockbusters: Stories, Pitches & Now VIDEO TRAILERS!
298
+ *xAI for text + Runway ML for clips | Oct 2025 Edition.*
299
  """)
300
 
301
+ # Status Row (added Runway test)
302
  with gr.Row():
303
  with gr.Column(scale=1):
304
+ xai_btn = gr.Button("📡 Test xAI", variant="secondary")
305
+ runway_btn = gr.Button("🎞️ Test Runway", variant="secondary")
306
  with gr.Column(scale=4):
307
+ xai_msg = gr.Textbox(label="xAI Log", show_label=False, lines=1)
308
+ xai_icon = gr.Textbox(label="xAI Status", show_label=False, max_lines=1)
309
+ runway_msg = gr.Textbox(label="Runway Log", show_label=False, lines=1)
310
+ runway_icon = gr.Textbox(label="Runway Status", show_label=False, max_lines=1)
311
 
312
+ # Story Tab (updated to return prompt for trailer)
313
  with gr.Tab("🎞️ Sequel Forge"):
314
  gr.Markdown("### Craft Epic Sequels with Custom Cast")
315
 
 
366
  )
367
 
368
  generate_btn = gr.Button("🎬 Generate Full Sequel!", variant="primary", size="lg")
369
+ story_output = gr.Markdown(label="Your Blockbuster Bible")
370
+ trailer_prompt_hidden = gr.Textbox(visible=False) # Hidden for chaining
371
 
372
  generate_btn.click(
373
  generate_cinematic_story,
374
  inputs=[original_input, sequel_input, actor_select, extras_input, story_type_dropdown],
375
+ outputs=[story_output, trailer_prompt_hidden]
376
  )
377
 
378
+ # Pitch Tab (updated to return prompt)
379
  with gr.Tab("💡 Pitch Roulette"):
380
  gr.Markdown("### Instant Greenlight Concepts")
381
 
 
392
  )
393
 
394
  pitch_btn = gr.Button("✨ Generate Pitch Deck!", variant="primary")
395
+ pitch_output = gr.Markdown(label="Hot Pitch")
396
+ pitch_prompt_hidden = gr.Textbox(visible=False)
397
 
398
+ pitch_btn.click(generate_movie_pitch, inputs=[pitch_actor_select], outputs=[pitch_output, pitch_prompt_hidden])
399
+
400
+ # NEW: Video Trailer Tab
401
+ with gr.Tab("🎥 Trailer Forge"):
402
+ gr.Markdown("### AI-Generated Video Trailers via Runway ML")
403
+ gr.Markdown("*Paste a story prompt below—watch it come alive! ~2-5 min gen time.*")
404
+
405
+ trailer_prompt_input = gr.Textbox(
406
+ label="Trailer Prompt",
407
+ placeholder="e.g., King Conan battles ice demons in frozen wastelands, epic sword fight...",
408
+ lines=3,
409
+ value="Cinematic fantasy battle in snowy mountains"
410
+ )
411
+ duration_slider = gr.Slider(5, 10, value=5, step=1, label="Clip Length (seconds)")
412
+ gen_video_btn = gr.Button("🚀 Generate Trailer!", variant="primary")
413
+
414
+ video_output = gr.Video(label="Your AI Trailer", show_download_button=True)
415
+ video_status = gr.Textbox(label="Status", show_label=False, lines=1)
416
+
417
+ # Chain from other tabs? Optional examples
418
+ gr.Examples(
419
+ examples=[
420
+ ["Epic space battle with starships exploding in nebula clouds"],
421
+ ["Romantic comedy meet-cute in rainy Paris streets, slow-motion smiles"],
422
+ ["Horror chase through haunted mansion, flickering lights and shadows"]
423
+ ],
424
+ inputs=trailer_prompt_input
425
+ )
426
+
427
+ gen_video_btn.click(
428
+ generate_video_trailer,
429
+ inputs=[trailer_prompt_input, duration_slider],
430
+ outputs=[video_output, video_status]
431
+ )
432
 
433
+ # Connections
434
+ xai_btn.click(test_connection, outputs=[xai_msg, xai_icon])
435
+ runway_btn.click(test_runway_connection, outputs=[runway_msg, runway_icon])
436
 
437
  if __name__ == "__main__":
438
+ demo.launch(share=True)