Update app.py
Browse files
app.py
CHANGED
|
@@ -7,24 +7,55 @@ from datetime import datetime
|
|
| 7 |
# Your xAI API key
|
| 8 |
XAI_API_KEY = os.environ.get('XAI_API_KEY')
|
| 9 |
|
| 10 |
-
#
|
| 11 |
MOVIE_TEMPLATES = {
|
| 12 |
"epic_fantasy": {
|
| 13 |
"title": "π° Epic Fantasy Quest",
|
| 14 |
"examples": [
|
| 15 |
"A hobbit's quest to destroy a powerful ring",
|
| 16 |
-
"A young wizard's journey to defeat a dark lord",
|
| 17 |
]
|
| 18 |
},
|
| 19 |
"sci_fi_adventure": {
|
| 20 |
-
"title": "π Sci-Fi Space Opera",
|
| 21 |
"examples": [
|
| 22 |
"A starship crew exploring unknown galaxies",
|
| 23 |
"First contact with an alien civilization"
|
| 24 |
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 25 |
}
|
| 26 |
}
|
| 27 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 28 |
def test_connection():
|
| 29 |
"""Test xAI connection with better error handling"""
|
| 30 |
if not XAI_API_KEY:
|
|
@@ -40,32 +71,48 @@ def test_connection():
|
|
| 40 |
except Exception as e:
|
| 41 |
return f"β Connection error: {str(e)}", "π΄ Offline"
|
| 42 |
|
| 43 |
-
def generate_cinematic_story(original_story, sequel_start, story_type="epic_fantasy"):
|
| 44 |
-
"""Generate a cinematic story with
|
| 45 |
|
| 46 |
if not original_story or not sequel_start:
|
| 47 |
return "β Please fill in both story fields!"
|
| 48 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 49 |
headers = {
|
| 50 |
'Authorization': f'Bearer {XAI_API_KEY}',
|
| 51 |
'Content-Type': 'application/json'
|
| 52 |
}
|
| 53 |
|
| 54 |
-
#
|
|
|
|
|
|
|
|
|
|
| 55 |
prompt = f"""
|
| 56 |
-
Create a movie sequel
|
| 57 |
|
| 58 |
Original: {original_story}
|
| 59 |
Sequel starts: {sequel_start}
|
|
|
|
| 60 |
|
| 61 |
-
Write an engaging sequel
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 62 |
"""
|
| 63 |
|
| 64 |
data = {
|
| 65 |
'model': 'grok-beta',
|
| 66 |
'messages': [{'role': 'user', 'content': prompt}],
|
| 67 |
-
'max_tokens':
|
| 68 |
-
'temperature': 0.
|
| 69 |
}
|
| 70 |
|
| 71 |
try:
|
|
@@ -73,138 +120,197 @@ def generate_cinematic_story(original_story, sequel_start, story_type="epic_fant
|
|
| 73 |
'https://api.x.ai/v1/chat/completions',
|
| 74 |
headers=headers,
|
| 75 |
json=data,
|
| 76 |
-
timeout=30
|
| 77 |
)
|
| 78 |
|
| 79 |
if response.status_code == 200:
|
| 80 |
result = response.json()
|
| 81 |
story = result['choices'][0]['message']['content']
|
|
|
|
|
|
|
| 82 |
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
**
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 89 |
|
| 90 |
{story}
|
| 91 |
|
| 92 |
---
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
else:
|
| 96 |
-
return f"""
|
| 97 |
-
π¬ **PRODUCTION UPDATE** π¬
|
| 98 |
-
**Status:** π‘ IN DEVELOPMENT
|
| 99 |
-
|
| 100 |
-
While our AI director sets up the epic scenes, here's your Conan sequel concept:
|
| 101 |
|
| 102 |
-
|
| 103 |
-
|
| 104 |
-
Years after becoming king, Conan (Arnold Schwarzenegger) faces an ancient ice demon from the north. The frozen threat forces the aging barbarian to wield his sword once more in an epic battle for Aquilonia.
|
| 105 |
-
|
| 106 |
-
**Key Scenes:**
|
| 107 |
-
β’ Conan's council debate about the supernatural threat
|
| 108 |
-
β’ Journey through frozen wastelands
|
| 109 |
-
β’ Epic battle with ice creatures
|
| 110 |
-
β’ Final confrontation with the ice demon
|
| 111 |
-
|
| 112 |
-
**Character Arc:** Older, wiser Conan learns that true strength comes from wisdom, not just muscle.
|
| 113 |
-
"""
|
| 114 |
-
|
| 115 |
-
except Exception as e:
|
| 116 |
-
return f"""
|
| 117 |
-
π¬ **CREATIVE DEVELOPMENT** π¬
|
| 118 |
-
**Status:** π‘ CONCEPT PHASE
|
| 119 |
-
|
| 120 |
-
**CONAN RETURNS: FROZEN LEGACY**
|
| 121 |
|
| 122 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 123 |
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
|
| 127 |
-
|
| 128 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 129 |
|
| 130 |
-
|
| 131 |
-
|
| 132 |
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
template = MOVIE_TEMPLATES[selected_genre]
|
| 139 |
-
|
| 140 |
-
pitch = f"""
|
| 141 |
-
π¬ **GREENLIGHT OPPORTUNITY** π¬
|
| 142 |
|
| 143 |
-
**
|
| 144 |
-
|
| 145 |
-
|
| 146 |
-
|
| 147 |
|
| 148 |
-
**
|
| 149 |
-
|
| 150 |
-
|
| 151 |
-
"""
|
| 152 |
-
return pitch
|
| 153 |
-
except:
|
| 154 |
-
return "π¬ New movie concept ready for development!"
|
| 155 |
|
| 156 |
-
#
|
| 157 |
-
with gr.Blocks(title="IdeaForge Studio", theme=gr.themes.
|
| 158 |
|
| 159 |
-
gr.Markdown("
|
| 160 |
-
|
|
|
|
|
|
|
|
|
|
| 161 |
|
| 162 |
-
# Status
|
| 163 |
with gr.Row():
|
| 164 |
-
|
| 165 |
-
|
|
|
|
|
|
|
|
|
|
| 166 |
|
| 167 |
# Main Tabs
|
| 168 |
-
with gr.Tab("ποΈ
|
| 169 |
-
gr.Markdown("###
|
| 170 |
|
| 171 |
-
|
| 172 |
-
|
| 173 |
-
|
| 174 |
-
|
| 175 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 176 |
|
| 177 |
-
|
| 178 |
-
|
| 179 |
-
|
| 180 |
-
|
|
|
|
|
|
|
|
|
|
| 181 |
)
|
|
|
|
|
|
|
|
|
|
| 182 |
|
| 183 |
-
|
| 184 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 185 |
|
| 186 |
-
|
| 187 |
-
|
| 188 |
-
return [
|
| 189 |
-
"Conan the Barbarian seeks revenge against Thulsa Doom for destroying his village",
|
| 190 |
-
"Years later, King Conan faces an ancient ice demon awakening in the frozen north"
|
| 191 |
-
]
|
| 192 |
|
| 193 |
-
|
| 194 |
-
conan_example,
|
| 195 |
-
outputs=[original_input, sequel_input]
|
| 196 |
-
)
|
| 197 |
-
|
| 198 |
-
generate_btn.click(generate_cinematic_story, [original_input, sequel_input], story_output)
|
| 199 |
-
|
| 200 |
-
with gr.Tab("π‘ Quick Pitches"):
|
| 201 |
-
gr.Markdown("### Instant Movie Concepts")
|
| 202 |
-
pitch_btn = gr.Button("π² Generate Pitch")
|
| 203 |
-
pitch_output = gr.Textbox(label="Pitch Deck", lines=6, show_copy_button=True)
|
| 204 |
-
pitch_btn.click(generate_movie_pitch, outputs=pitch_output)
|
| 205 |
|
| 206 |
-
# Connection
|
| 207 |
-
status_btn.click(test_connection, outputs=
|
| 208 |
|
| 209 |
if __name__ == "__main__":
|
| 210 |
-
demo.launch()
|
|
|
|
| 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",
|
| 14 |
"examples": [
|
| 15 |
"A hobbit's quest to destroy a powerful ring",
|
| 16 |
+
"A young wizard's journey to defeat a dark lord",
|
| 17 |
]
|
| 18 |
},
|
| 19 |
"sci_fi_adventure": {
|
| 20 |
+
"title": "π Sci-Fi Space Opera",
|
| 21 |
"examples": [
|
| 22 |
"A starship crew exploring unknown galaxies",
|
| 23 |
"First contact with an alien civilization"
|
| 24 |
]
|
| 25 |
+
},
|
| 26 |
+
"action_thriller": {
|
| 27 |
+
"title": "π₯ High-Octane Action",
|
| 28 |
+
"examples": [
|
| 29 |
+
"A rogue agent's global chase against a shadow cabal",
|
| 30 |
+
"Undercover cop vs. cartel kingpin in neon-lit streets"
|
| 31 |
+
]
|
| 32 |
+
},
|
| 33 |
+
"horror_mystery": {
|
| 34 |
+
"title": "π» Chilling Horror",
|
| 35 |
+
"examples": [
|
| 36 |
+
"A haunted house awakens ancient curses",
|
| 37 |
+
"Small-town vanishings reveal a cult's dark secret"
|
| 38 |
+
]
|
| 39 |
+
},
|
| 40 |
+
"rom_com": {
|
| 41 |
+
"title": "β€οΈ Romantic Comedy",
|
| 42 |
+
"examples": [
|
| 43 |
+
"Fake dating turns real amid wedding chaos",
|
| 44 |
+
"Rival chefs spark love in a culinary showdown"
|
| 45 |
+
]
|
| 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:
|
|
|
|
| 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 |
|
| 80 |
+
# Cast lead/support
|
| 81 |
+
lead_actor = random.choice(selected_actors) if selected_actors else random.choice(TOP_ACTORS)
|
| 82 |
+
support_actors = [a for a in selected_actors if a != lead_actor][:2]
|
| 83 |
+
|
| 84 |
+
# Random rating based on genre
|
| 85 |
+
rating = random.choice(["PG-13", "R"] if "horror" in story_type or "action" in story_type else MPAA_RATINGS)
|
| 86 |
+
|
| 87 |
headers = {
|
| 88 |
'Authorization': f'Bearer {XAI_API_KEY}',
|
| 89 |
'Content-Type': 'application/json'
|
| 90 |
}
|
| 91 |
|
| 92 |
+
# Enhanced prompt with actors, extras, genre
|
| 93 |
+
extras_str = f" Include these elements: {extras}." if extras else ""
|
| 94 |
+
actors_str = f" Cast {lead_actor} as the lead hero. Feature {', '.join(support_actors)} in supporting roles.{extras_str}"
|
| 95 |
+
|
| 96 |
prompt = f"""
|
| 97 |
+
Create a blockbuster movie sequel in the {story_type} genre (MPAA rating: {rating}):
|
| 98 |
|
| 99 |
Original: {original_story}
|
| 100 |
Sequel starts: {sequel_start}
|
| 101 |
+
{actors_str}
|
| 102 |
|
| 103 |
+
Write an engaging, cinematic sequel synopsis (300-400 words) with:
|
| 104 |
+
- Strong character arcs for the lead ({lead_actor})
|
| 105 |
+
- Key scenes: 3-5 high-stakes action/emotional beats
|
| 106 |
+
- Plot twists from extras
|
| 107 |
+
- Blockbuster ending hook
|
| 108 |
+
Keep it vivid, dialogue-snappy, and ready for the big screen!
|
| 109 |
"""
|
| 110 |
|
| 111 |
data = {
|
| 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:
|
|
|
|
| 120 |
'https://api.x.ai/v1/chat/completions',
|
| 121 |
headers=headers,
|
| 122 |
json=data,
|
| 123 |
+
timeout=30
|
| 124 |
)
|
| 125 |
|
| 126 |
if response.status_code == 200:
|
| 127 |
result = response.json()
|
| 128 |
story = result['choices'][0]['message']['content']
|
| 129 |
+
else:
|
| 130 |
+
story = _generate_fallback_story(original_story, sequel_start, lead_actor, support_actors, extras, story_type, rating)
|
| 131 |
|
| 132 |
+
except Exception as e:
|
| 133 |
+
story = _generate_fallback_story(original_story, sequel_start, lead_actor, support_actors, extras, story_type, rating)
|
| 134 |
+
|
| 135 |
+
production_id = f"PROD-{random.randint(10000,99999)}-{datetime.now().strftime('%m%d')}"
|
| 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']}
|
| 142 |
+
|
| 143 |
+
**{lead_actor}'s LEGEND CONTINUES...**
|
| 144 |
|
| 145 |
{story}
|
| 146 |
|
| 147 |
---
|
| 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:
|
| 163 |
+
plot = f"Post-{original_story}, {lead_actor} commands a ragtag fleet against an AI overlord devouring stars{support_str}. {extras_str} Quantum jumps and zero-G dogfights ensue, revealing a personal clone conspiracy. Key scenes: Black hole evasion, holographic interrogations, epic wormhole assault. Arc: Doubtful captain to galaxy's defiant savior."
|
| 164 |
+
elif "action" in story_type:
|
| 165 |
+
plot = f"After {original_story}, {lead_actor} hunts a rogue syndicate in rain-slicked megacities{support_str}. {extras_str} Explosive set-pieces include subway heists and rooftop pursuits. Key scenes: Double-cross diner shootout, armored convoy takedown, skyline finale. Arc: Lone wolf to team-forged avenger."
|
| 166 |
+
elif "horror" in story_type:
|
| 167 |
+
plot = f"Haunted by {original_story}, {lead_actor} investigates viral nightmares plaguing the world{support_str}. {extras_str} Creeping dread builds to possessions and ritual showdowns. Key scenes: Foggy asylum lockdown, mirror-world traps, blood-moon ritual. Arc: Skeptic to harbinger of the damned."
|
| 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 |
+
|
| 178 |
+
genres = list(MOVIE_TEMPLATES.keys())
|
| 179 |
+
selected_genre = random.choice(genres)
|
| 180 |
+
template = MOVIE_TEMPLATES[selected_genre]
|
| 181 |
+
|
| 182 |
+
lead = selected_actors[0]
|
| 183 |
+
supports = selected_actors[1:]
|
| 184 |
+
rating = random.choice(MPAA_RATINGS)
|
| 185 |
+
|
| 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 |
|
| 192 |
+
**GENRE:** {template['title']} | **RATING:** {rating}
|
| 193 |
+
**LOGLINE:** {logline} β Starring {lead} as the unbreakable hero, with {', '.join(supports)} lighting up the ensemble.
|
| 194 |
|
| 195 |
+
**BUDGET:** ${random.randint(80,250)}M
|
| 196 |
+
**TIMELINE:** {random.randint(18,36)} months to cameras
|
| 197 |
+
**TARGET AUDIENCE:** {random.randint(13,35)}+ thrill-seekers/romantics
|
| 198 |
+
**FRANCHISE POTENTIAL:** {franchise_potential}
|
| 199 |
+
**HOOK:** Explosive opener + twisty mid-act + unforgettable finale. Dir. rec: Taika Waititi for {selected_genre}.
|
|
|
|
|
|
|
|
|
|
|
|
|
| 200 |
|
| 201 |
+
**QUICK CAST NOTES:**
|
| 202 |
+
β’ {lead}: Lead (raw charisma + action chops)
|
| 203 |
+
β’ {supports[0] if supports else 'TBD'}: Comic relief/foil
|
| 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 |
|
| 231 |
+
with gr.Row():
|
| 232 |
+
with gr.Column(scale=1):
|
| 233 |
+
original_input = gr.Textbox(
|
| 234 |
+
label="Original Movie Logline",
|
| 235 |
+
placeholder="e.g., Conan slays Thulsa Doom in barbaric revenge...",
|
| 236 |
+
lines=2
|
| 237 |
+
)
|
| 238 |
+
sequel_input = gr.Textbox(
|
| 239 |
+
label="Sequel Kickoff",
|
| 240 |
+
placeholder="e.g., As King, Conan battles an ice demon's curse...",
|
| 241 |
+
lines=2
|
| 242 |
+
)
|
| 243 |
+
story_type_dropdown = gr.Dropdown(
|
| 244 |
+
choices=list(MOVIE_TEMPLATES.keys()),
|
| 245 |
+
value="epic_fantasy",
|
| 246 |
+
label="Genre Vibes"
|
| 247 |
+
)
|
| 248 |
+
extras_input = gr.Textbox(
|
| 249 |
+
label="Add Twists/Elements",
|
| 250 |
+
placeholder="e.g., time-travel betrayal, zombie allies",
|
| 251 |
+
lines=1
|
| 252 |
+
)
|
| 253 |
+
actor_select = gr.CheckboxGroup(
|
| 254 |
+
choices=TOP_ACTORS,
|
| 255 |
+
label="Cast Your Stars (pick 1-3)",
|
| 256 |
+
value=[TOP_ACTORS[0]],
|
| 257 |
+
interactive=True
|
| 258 |
+
)
|
| 259 |
+
|
| 260 |
+
with gr.Column(scale=1):
|
| 261 |
+
gr.Markdown("### Quick Load")
|
| 262 |
+
gr.Button("π‘οΈ Conan Classic").click(
|
| 263 |
+
lambda: ([
|
| 264 |
+
"Conan the Barbarian seeks revenge against Thulsa Doom for destroying his village",
|
| 265 |
+
"Years later, King Conan faces an ancient ice demon awakening in the frozen north",
|
| 266 |
+
"epic_fantasy",
|
| 267 |
+
"magical artifacts, betrayal by advisor",
|
| 268 |
+
["Dwayne Johnson", "Pedro Pascal"]
|
| 269 |
+
]),
|
| 270 |
+
outputs=[original_input, sequel_input, story_type_dropdown, extras_input, actor_select]
|
| 271 |
+
)
|
| 272 |
+
gr.Button("π Star Wars Vibes").click(
|
| 273 |
+
lambda: ([
|
| 274 |
+
"A farm boy joins rebels to destroy the Death Star",
|
| 275 |
+
"Post-victory, the hero uncovers a Sith family secret",
|
| 276 |
+
"sci_fi_adventure",
|
| 277 |
+
"force ghost mentors, twin reveal",
|
| 278 |
+
["Tom Holland", "Joseph Quinn"]
|
| 279 |
+
]),
|
| 280 |
+
outputs=[original_input, sequel_input, story_type_dropdown, extras_input, actor_select]
|
| 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 |
|
| 295 |
+
with gr.Row():
|
| 296 |
+
pitch_actor_select = gr.CheckboxGroup(
|
| 297 |
+
choices=TOP_ACTORS,
|
| 298 |
+
label="Dream Cast (optional)",
|
| 299 |
+
value=[],
|
| 300 |
+
interactive=True
|
| 301 |
+
)
|
| 302 |
+
gr.Button("π² Roll Random Cast", variant="secondary").click(
|
| 303 |
+
lambda: random.sample(TOP_ACTORS, random.randint(1,3)),
|
| 304 |
+
outputs=pitch_actor_select
|
| 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
|