mgbam commited on
Commit
de2fdbb
Β·
verified Β·
1 Parent(s): 287c9ca

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +124 -0
app.py CHANGED
@@ -0,0 +1,124 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app.py
2
+ import streamlit as st
3
+ from core.gemini_handler import GeminiHandler
4
+ from core.visual_engine import VisualEngine
5
+ from core.prompt_engineering import create_story_breakdown_prompt, create_image_prompt_from_scene
6
+ import os
7
+
8
+ # --- Configuration & Initialization ---
9
+ st.set_page_config(page_title="CineGen AI", layout="wide")
10
+
11
+ # Load API Key from Streamlit secrets
12
+ try:
13
+ GEMINI_API_KEY = st.secrets["GEMINI_API_KEY"]
14
+ except KeyError:
15
+ st.error("GEMINI_API_KEY not found in secrets. Please add it to your Streamlit Cloud secrets.")
16
+ st.stop()
17
+
18
+ gemini = GeminiHandler(api_key=GEMINI_API_KEY)
19
+ visualizer = VisualEngine(output_dir="temp_generated_media") # Use a temp dir for HF Spaces
20
+
21
+ # --- UI Elements ---
22
+ st.title("🎬 CineGen AI: Your Pocket AI Film Studio")
23
+ st.markdown("Let's turn your ideas into cinematic visuals!")
24
+
25
+ with st.sidebar:
26
+ st.header("🎨 Creative Controls")
27
+ user_idea = st.text_area("Enter your core idea/story prompt:", "A lone astronaut discovers a glowing alien artifact on Mars, a sense of wonder and slight dread.", height=100)
28
+ genre = st.selectbox("Select Genre:", ["Sci-Fi", "Fantasy", "Thriller", "Drama", "Comedy"], index=0)
29
+ mood = st.selectbox("Select Mood:", ["Suspenseful", "Mysterious", "Epic", "Uplifting", "Dark"], index=0)
30
+ generate_button = st.button("✨ Generate Cinematic Concept", type="primary")
31
+
32
+ # --- Session State for Storing Results ---
33
+ if 'story_scenes' not in st.session_state:
34
+ st.session_state.story_scenes = None
35
+ if 'image_prompts' not in st.session_state:
36
+ st.session_state.image_prompts = []
37
+ if 'generated_images_paths' not in st.session_state:
38
+ st.session_state.generated_images_paths = []
39
+ if 'video_path' not in st.session_state:
40
+ st.session_state.video_path = None
41
+
42
+ # --- Main Logic ---
43
+ if generate_button and user_idea:
44
+ st.session_state.story_scenes = None # Reset previous results
45
+ st.session_state.image_prompts = []
46
+ st.session_state.generated_images_paths = []
47
+ st.session_state.video_path = None
48
+
49
+ with st.spinner("Phase 1: Gemini is drafting the script and scene breakdown... πŸ“œ"):
50
+ story_prompt = create_story_breakdown_prompt(user_idea, genre, mood)
51
+ st.session_state.story_scenes = gemini.generate_story_breakdown(story_prompt)
52
+
53
+ if st.session_state.story_scenes:
54
+ st.toast("Script and scene breakdown complete!", icon="βœ…")
55
+
56
+ with st.spinner("Phase 2: Gemini is crafting visual prompts for keyframes... πŸ–ΌοΈ"):
57
+ for i, scene in enumerate(st.session_state.story_scenes):
58
+ scene_desc_for_image = f"Scene {scene.get('scene_number', i+1)}: {scene.get('key_action', 'N/A')}. Setting: {scene.get('setting_description', 'N/A')}"
59
+ img_gen_prompt_text = create_image_prompt_from_scene(scene_desc_for_image, scene.get('visual_style_suggestion', 'cinematic'))
60
+
61
+ # Get the actual image description from Gemini
62
+ # For this demo, we'll use the scene's key_action and setting as the "description" for the placeholder
63
+ # In a real app, Gemini would generate a detailed image prompt here.
64
+ # image_description_from_gemini = gemini.generate_image_prompt(img_gen_prompt_text)
65
+ # For simplicity, we use parts of the scene data directly for the placeholder image text
66
+ image_description_for_placeholder = f"Scene {scene.get('scene_number', i+1)}: {scene.get('key_action', 'N/A')}\nStyle: {scene.get('visual_style_suggestion', 'cinematic')}"
67
+
68
+ if image_description_for_placeholder: # was image_description_from_gemini
69
+ st.session_state.image_prompts.append(image_description_for_placeholder)
70
+ # Simulate image generation by creating a placeholder
71
+ img_path = visualizer.create_placeholder_image(
72
+ image_description_for_placeholder, # use the generated desc
73
+ f"scene_{scene.get('scene_number', i+1)}_placeholder.png"
74
+ )
75
+ st.session_state.generated_images_paths.append(img_path)
76
+ else:
77
+ st.warning(f"Could not generate image prompt/description for Scene {scene.get('scene_number', i+1)}.")
78
+ st.toast("Visual prompts and placeholder images generated!", icon="πŸ–ΌοΈ")
79
+
80
+ if st.session_state.generated_images_paths:
81
+ with st.spinner("Phase 3: Assembling the cinematic video... 🎞️"):
82
+ st.session_state.video_path = visualizer.create_video_from_images(
83
+ st.session_state.generated_images_paths,
84
+ output_filename="cinegen_output.mp4",
85
+ duration_per_image=3 # Show each image for 3 seconds
86
+ )
87
+ st.toast("Video assembled!", icon="🎬")
88
+ st.balloons()
89
+ else:
90
+ st.error("No images were generated, cannot create video.")
91
+ else:
92
+ st.error("Failed to generate story breakdown from Gemini. Please check logs or try a different prompt.")
93
+
94
+ # --- Display Results ---
95
+ if st.session_state.story_scenes:
96
+ st.header("πŸ“ Generated Story Breakdown")
97
+ for i, scene in enumerate(st.session_state.story_scenes):
98
+ with st.expander(f"Scene {scene.get('scene_number', i+1)}: {scene.get('key_action', 'N/A')[:50]}...", expanded=i==0):
99
+ st.markdown(f"**Setting:** {scene.get('setting_description', 'N/A')}")
100
+ st.markdown(f"**Characters:** {', '.join(scene.get('characters_involved', []))}")
101
+ st.markdown(f"**Key Action:** {scene.get('key_action', 'N/A')}")
102
+ st.markdown(f"**Visual Style Suggestion:** {scene.get('visual_style_suggestion', 'N/A')}")
103
+ st.markdown(f"**Camera Angle Suggestion:** {scene.get('camera_angle_suggestion', 'N/A')}")
104
+
105
+ if i < len(st.session_state.image_prompts):
106
+ st.markdown(f"**Image Concept (Placeholder Text):**")
107
+ st.code(st.session_state.image_prompts[i])
108
+ if i < len(st.session_state.generated_images_paths):
109
+ st.image(st.session_state.generated_images_paths[i], caption=f"Visual Concept for Scene {scene.get('scene_number', i+1)}")
110
+
111
+
112
+ if st.session_state.video_path and os.path.exists(st.session_state.video_path):
113
+ st.header("🎬 Generated Cinematic Concept Video")
114
+ video_file = open(st.session_state.video_path, 'rb')
115
+ video_bytes = video_file.read()
116
+ st.video(video_bytes)
117
+ st.markdown(f"Download your video: [{os.path.basename(st.session_state.video_path)}]({st.session_state.video_path})") # This download might not work directly on Spaces due to pathing, but video will play.
118
+ # For download on Spaces, you might need to serve it differently or provide a direct link if Spaces keeps it.
119
+ # A simpler way for Spaces is to just let the user right-click the video player and save.
120
+ else:
121
+ if generate_button and not st.session_state.video_path and st.session_state.generated_images_paths:
122
+ st.warning("Video generation might have failed or no images were available.")
123
+ elif not generate_button :
124
+ st.info("Enter your idea and click 'Generate Cinematic Concept' to begin!")