I'll complete the AI Movie Generator system.
Here's the continuation and
completion:
# Scene editor form fields
ctk.CTkLabel(form_frame, text="Scene Title:").pack(anchor="w",
pady=2)
self.scene_title_entry = ctk.CTkEntry(form_frame,
placeholder_text="Scene title")
self.scene_title_entry.pack(fill="x", pady=2)
ctk.CTkLabel(form_frame, text="Location:").pack(anchor="w",
pady=2)
self.scene_location_entry = ctk.CTkEntry(form_frame,
placeholder_text="INT./EXT. Location")
self.scene_location_entry.pack(fill="x", pady=2)
ctk.CTkLabel(form_frame, text="Time of Day:").pack(anchor="w",
pady=2)
self.scene_time_combo = ctk.CTkComboBox(form_frame,
values=["Day", "Night", "Dawn", "Dusk"])
self.scene_time_combo.pack(fill="x", pady=2)
ctk.CTkLabel(form_frame, text="Mood:").pack(anchor="w",
pady=2)
self.scene_mood_combo = ctk.CTkComboBox(
form_frame,
values=["neutral", "happy", "sad", "tense", "mysterious",
"romantic", "action"]
)
self.scene_mood_combo.pack(fill="x", pady=2)
ctk.CTkLabel(form_frame, text="Duration
(seconds):").pack(anchor="w", pady=2)
self.scene_duration_entry = ctk.CTkEntry(form_frame,
placeholder_text="5.0")
self.scene_duration_entry.pack(fill="x", pady=2)
ctk.CTkLabel(form_frame, text="Characters:").pack(anchor="w",
pady=2)
self.scene_characters_entry = ctk.CTkEntry(form_frame,
placeholder_text="Character1, Character2")
self.scene_characters_entry.pack(fill="x", pady=2)
ctk.CTkLabel(form_frame, text="Action:").pack(anchor="w",
pady=2)
self.scene_action_textbox = ctk.CTkTextbox(form_frame,
height=80)
self.scene_action_textbox.pack(fill="x", pady=2)
ctk.CTkLabel(form_frame, text="Dialogue:").pack(anchor="w",
pady=2)
self.scene_dialogue_textbox = ctk.CTkTextbox(form_frame,
height=100)
self.scene_dialogue_textbox.pack(fill="x", pady=2)
# Scene actions
scene_actions_frame = ctk.CTkFrame(form_frame)
scene_actions_frame.pack(fill="x", pady=10)
self.update_scene_btn = ctk.CTkButton(
scene_actions_frame,
text="Update Scene",
command=self._update_scene
)
self.update_scene_btn.pack(side="left", padx=5)
self.delete_scene_btn = ctk.CTkButton(
scene_actions_frame,
text="Delete Scene",
command=self._delete_scene,
fg_color=Config.ERROR_COLOR
)
self.delete_scene_btn.pack(side="right", padx=5)
# Selected scene tracking
self.selected_scene_id = None
def _create_generation_tab(self):
"""Create the movie generation tab"""
generation_tab = self.tabview.add("Generation")
# Generation controls
controls_frame = ctk.CTkFrame(generation_tab)
controls_frame.pack(fill="x", padx=10, pady=10)
ctk.CTkLabel(
controls_frame,
text="Movie Generation",
font=ctk.CTkFont(size=18, weight="bold")
).pack(pady=10)
# Generation options
options_frame = ctk.CTkFrame(controls_frame)
options_frame.pack(fill="x", padx=10, pady=10)
# Image generation settings
image_frame = ctk.CTkFrame(options_frame)
image_frame.pack(side="left", fill="both", expand=True,
padx=5, pady=5)
ctk.CTkLabel(image_frame, text="Image Generation",
font=ctk.CTkFont(weight="bold")).pack(pady=5)
self.image_style_combo = ctk.CTkComboBox(
image_frame,
values=["cinematic", "realistic", "artistic", "animated",
"noir", "fantasy"]
)
self.image_style_combo.pack(pady=2)
self.generate_images_var = ctk.BooleanVar(value=True)
ctk.CTkCheckBox(
image_frame,
text="Generate Images",
variable=self.generate_images_var
).pack(pady=2)
# Audio generation settings
audio_frame = ctk.CTkFrame(options_frame)
audio_frame.pack(side="right", fill="both", expand=True,
padx=5, pady=5)
ctk.CTkLabel(audio_frame, text="Audio Generation",
font=ctk.CTkFont(weight="bold")).pack(pady=5)
self.voice_id_entry = ctk.CTkEntry(audio_frame,
placeholder_text="Voice ID (optional)")
self.voice_id_entry.pack(pady=2)
self.generate_audio_var = ctk.BooleanVar(value=True)
ctk.CTkCheckBox(
audio_frame,
text="Generate Audio",
variable=self.generate_audio_var
).pack(pady=2)
self.background_music_var = ctk.BooleanVar(value=True)
ctk.CTkCheckBox(
audio_frame,
text="Background Music",
variable=self.background_music_var
).pack(pady=2)
# Progress section
progress_frame = ctk.CTkFrame(generation_tab)
progress_frame.pack(fill="both", expand=True, padx=10,
pady=10)
ctk.CTkLabel(
progress_frame,
text="Generation Progress",
font=ctk.CTkFont(size=16, weight="bold")
).pack(pady=5)
# Progress bar
self.progress_bar = ctk.CTkProgressBar(progress_frame)
self.progress_bar.pack(fill="x", padx=20, pady=10)
self.progress_bar.set(0)
# Progress text
self.progress_label = ctk.CTkLabel(progress_frame, text="Ready
to generate")
self.progress_label.pack(pady=5)
# Progress details
self.progress_details = ctk.CTkTextbox(progress_frame,
height=200)
self.progress_details.pack(fill="both", expand=True, padx=20,
pady=10)
# Generation controls
gen_controls_frame = ctk.CTkFrame(progress_frame)
gen_controls_frame.pack(fill="x", padx=20, pady=10)
self.start_generation_btn = ctk.CTkButton(
gen_controls_frame,
text="🎬 Start Generation",
command=self._start_movie_generation,
height=40,
font=ctk.CTkFont(size=14, weight="bold"),
fg_color=Config.SUCCESS_COLOR
)
self.start_generation_btn.pack(side="left", padx=5)
self.stop_generation_btn = ctk.CTkButton(
gen_controls_frame,
text=" Stop Generation",
command=self._stop_movie_generation,
height=40,
fg_color=Config.ERROR_COLOR,
state="disabled"
)
self.stop_generation_btn.pack(side="left", padx=5)
self.open_output_btn = ctk.CTkButton(
gen_controls_frame,
text="📁 Open Output Folder",
command=self._open_output_folder,
height=40
)
self.open_output_btn.pack(side="right", padx=5)
def _create_projects_tab(self):
"""Create the projects management tab"""
projects_tab = self.tabview.add("Projects")
# Projects list
list_frame = ctk.CTkFrame(projects_tab)
list_frame.pack(side="left", fill="both", expand=True,
padx=10, pady=10)
ctk.CTkLabel(
list_frame,
text="Projects",
font=ctk.CTkFont(size=16, weight="bold")
).pack(pady=5)
# Projects scrollable frame
self.projects_scrollable = ctk.CTkScrollableFrame(list_frame,
height=400)
self.projects_scrollable.pack(fill="both", expand=True,
padx=10, pady=10)
# Project actions
project_actions_frame = ctk.CTkFrame(list_frame)
project_actions_frame.pack(fill="x", padx=10, pady=5)
self.refresh_projects_btn = ctk.CTkButton(
project_actions_frame,
text="🔄 Refresh",
command=self._refresh_projects_list
)
self.refresh_projects_btn.pack(side="left", padx=5)
self.new_project_btn2 = ctk.CTkButton(
project_actions_frame,
text="➕ New Project",
command=self._new_project
)
self.new_project_btn2.pack(side="right", padx=5)
# Project details
details_frame = ctk.CTkFrame(projects_tab)
details_frame.pack(side="right", fill="both", expand=True,
padx=10, pady=10)
ctk.CTkLabel(
details_frame,
text="Project Details",
font=ctk.CTkFont(size=16, weight="bold")
).pack(pady=5)
self.project_details_textbox = ctk.CTkTextbox(details_frame,
height=300)
self.project_details_textbox.pack(fill="both", expand=True,
padx=10, pady=10)
# Load projects on startup
self._refresh_projects_list()
def _create_settings_tab(self):
"""Create the settings tab"""
settings_tab = self.tabview.add("Settings")
# API Keys section
api_frame = ctk.CTkFrame(settings_tab)
api_frame.pack(fill="x", padx=10, pady=10)
ctk.CTkLabel(
api_frame,
text="API Keys Configuration",
font=ctk.CTkFont(size=16, weight="bold")
).pack(pady=10)
# OpenAI API Key
openai_frame = ctk.CTkFrame(api_frame)
openai_frame.pack(fill="x", padx=10, pady=5)
ctk.CTkLabel(openai_frame, text="OpenAI API Key:",
width=120).pack(side="left", padx=5)
self.openai_key_entry = ctk.CTkEntry(
openai_frame,
placeholder_text="sk-...",
show="*"
)
self.openai_key_entry.pack(side="left", fill="x", expand=True,
padx=5)
# Gemini API Key
gemini_frame = ctk.CTkFrame(api_frame)
gemini_frame.pack(fill="x", padx=10, pady=5)
ctk.CTkLabel(gemini_frame, text="Gemini API Key:",
width=120).pack(side="left", padx=5)
self.gemini_key_entry = ctk.CTkEntry(
gemini_frame,
placeholder_text="AI...",
show="*"
)
self.gemini_key_entry.pack(side="left", fill="x", expand=True,
padx=5)
# Stability AI API Key
stability_frame = ctk.CTkFrame(api_frame)
stability_frame.pack(fill="x", padx=10, pady=5)
ctk.CTkLabel(stability_frame, text="Stability AI Key:",
width=120).pack(side="left", padx=5)
self.stability_key_entry = ctk.CTkEntry(
stability_frame,
placeholder_text="sk-...",
show="*"
)
self.stability_key_entry.pack(side="left", fill="x",
expand=True, padx=5)
# ElevenLabs API Key
elevenlabs_frame = ctk.CTkFrame(api_frame)
elevenlabs_frame.pack(fill="x", padx=10, pady=5)
ctk.CTkLabel(elevenlabs_frame, text="ElevenLabs Key:",
width=120).pack(side="left", padx=5)
self.elevenlabs_key_entry = ctk.CTkEntry(
elevenlabs_frame,
placeholder_text="...",
show="*"
)
self.elevenlabs_key_entry.pack(side="left", fill="x",
expand=True, padx=5)
# Save API keys button
self.save_api_keys_btn = ctk.CTkButton(
api_frame,
text="💾 Save API Keys",
command=self._save_api_keys
)
self.save_api_keys_btn.pack(pady=10)
# Video settings
video_frame = ctk.CTkFrame(settings_tab)
video_frame.pack(fill="x", padx=10, pady=10)
ctk.CTkLabel(
video_frame,
text="Video Settings",
font=ctk.CTkFont(size=16, weight="bold")
).pack(pady=10)
# Resolution
res_frame = ctk.CTkFrame(video_frame)
res_frame.pack(fill="x", padx=10, pady=5)
ctk.CTkLabel(res_frame, text="Resolution:",
width=120).pack(side="left", padx=5)
self.resolution_combo = ctk.CTkComboBox(
res_frame,
values=["1920x1080", "1280x720", "854x480", "640x360"]
)
self.resolution_combo.pack(side="left", padx=5)
# FPS
fps_frame = ctk.CTkFrame(video_frame)
fps_frame.pack(fill="x", padx=10, pady=5)
ctk.CTkLabel(fps_frame, text="FPS:",
width=120).pack(side="left", padx=5)
self.fps_combo = ctk.CTkComboBox(
fps_frame,
values=["24", "30", "60"]
)
self.fps_combo.pack(side="left", padx=5)
# Bitrate
bitrate_frame = ctk.CTkFrame(video_frame)
bitrate_frame.pack(fill="x", padx=10, pady=5)
ctk.CTkLabel(bitrate_frame, text="Bitrate:",
width=120).pack(side="left", padx=5)
self.bitrate_entry = ctk.CTkEntry(bitrate_frame,
placeholder_text="5000k")
self.bitrate_entry.pack(side="left", padx=5)
# About section
about_frame = ctk.CTkFrame(settings_tab)
about_frame.pack(fill="both", expand=True, padx=10, pady=10)
ctk.CTkLabel(
about_frame,
text="About AI Movie Generator",
font=ctk.CTkFont(size=16, weight="bold")
).pack(pady=10)
about_text = """
AI Movie Generator v2.0
A comprehensive AI-powered movie generation system that
creates
complete movies from scripts using multiple AI services.
Technologies Used:
• OpenAI GPT for script generation
• Google Gemini for scene analysis
• Stability AI for image generation
• ElevenLabs for voice synthesis
• MoviePy for video compilation
• CustomTkinter for modern GUI
Created with ❤️by AI Movie Generator Team
"""
ctk.CTkLabel(
about_frame,
text=about_text,
font=ctk.CTkFont(size=12),
justify="left"
).pack(pady=20, padx=20)
# Load saved settings
self._load_settings()
def _create_status_bar(self):
"""Create the status bar"""
self.status_frame = ctk.CTkFrame(self.root, height=30,
corner_radius=0)
self.status_frame.grid(row=1, column=0, columnspan=2,
sticky="ew")
self.status_label = ctk.CTkLabel(
self.status_frame,
text="Ready",
font=ctk.CTkFont(size=12)
)
self.status_label.pack(side="left", padx=10, pady=5)
self.status_progress = ctk.CTkProgressBar(self.status_frame,
width=200, height=15)
self.status_progress.pack(side="right", padx=10, pady=7)
self.status_progress.set(0)
def _setup_progress_monitoring(self):
"""Setup progress monitoring system"""
def check_progress():
try:
while True:
update = self.progress_queue.get_nowait()
self._update_progress(update)
except queue.Empty:
pass
# Schedule next check
self.root.after(100, check_progress)
# Start progress monitoring
self.root.after(100, check_progress)
# ===== EVENT HANDLERS =====
def _show_home_tab(self):
"""Show home tab"""
self.tabview.set("Home")
def _show_script_tab(self):
"""Show script tab"""
self.tabview.set("Script")
def _show_scenes_tab(self):
"""Show scenes tab"""
self.tabview.set("Scenes")
self._refresh_scenes_list()
def _show_generation_tab(self):
"""Show generation tab"""
self.tabview.set("Generation")
def _show_projects_tab(self):
"""Show projects tab"""
self.tabview.set("Projects")
self._refresh_projects_list()
def _show_settings_tab(self):
"""Show settings tab"""
self.tabview.set("Settings")
def _new_project(self):
"""Create a new project"""
try:
# Get project details from user
dialog = ProjectDialog(self.root, "New Project")
if dialog.result:
title, genre, duration = dialog.result
self.current_project = MovieProject(
title=title,
genre=genre,
duration_minutes=int(duration)
)
self._update_project_info()
self._update_status("New project created")
# Clear existing content
self.script_textbox.delete("1.0", "end")
self._refresh_scenes_list()
logger.info(f"Created new project: {title}")
except Exception as e:
logger.error(f"Error creating new project: {e}")
messagebox.showerror("Error", f"Failed to create new
project: {e}")
def _save_project(self):
"""Save current project"""
try:
if not self.current_project:
messagebox.showwarning("Warning", "No project to
save")
return
# Update project with current data
self.current_project.script =
self.script_textbox.get("1.0", "end-1c")
if
self.project_manager.save_project(self.current_project):
self._update_status("Project saved successfully")
messagebox.showinfo("Success", "Project saved
successfully")
else:
messagebox.showerror("Error", "Failed to save
project")
except Exception as e:
logger.error(f"Error saving project: {e}")
messagebox.showerror("Error", f"Failed to save project:
{e}")
def _load_project(self, project_id: str):
"""Load a project"""
try:
project = self.project_manager.load_project(project_id)
if project:
self.current_project = project
# Update UI with project data
self.script_textbox.delete("1.0", "end")
self.script_textbox.insert("1.0", project.script)
self.title_entry.delete(0, "end")
self.title_entry.insert(0, project.title)
self.genre_combo.set(project.genre)
self.duration_entry.delete(0, "end")
self.duration_entry.insert(0,
str(project.duration_minutes))
self._update_project_info()
self._refresh_scenes_list()
self._update_status(f"Loaded project:
{project.title}")
logger.info(f"Loaded project: {project.title}")
else:
messagebox.showerror("Error", "Failed to load
project")
except Exception as e:
logger.error(f"Error loading project: {e}")
messagebox.showerror("Error", f"Failed to load project:
{e}")
def _generate_script(self):
"""Generate script using AI"""
try:
prompt = self.prompt_entry.get().strip()
genre = self.genre_combo.get()
duration = int(self.duration_entry.get() or "5")
if not prompt:
messagebox.showwarning("Warning", "Please enter a
script prompt")
return
self._update_status("Generating script...")
self.generate_script_btn.configure(state="disabled",
text="Generating...")
def generate():
try:
script = self.ai_service.generate_script(prompt,
genre, duration)
# Update UI in main thread
self.root.after(0, lambda:
self._on_script_generated(script))
except Exception as e:
self.root.after(0, lambda:
self._on_script_error(str(e)))
# Run generation in background thread
threading.Thread(target=generate, daemon=True).start()
except ValueError:
messagebox.showerror("Error", "Please enter a valid
duration")
except Exception as e:
logger.error(f"Error generating script: {e}")
messagebox.showerror("Error", f"Failed to generate script:
{e}")
def _on_script_generated(self, script: str):
"""Handle script generation completion"""
self.script_textbox.delete("1.0", "end")
self.script_textbox.insert("1.0", script)
self.generate_script_btn.configure(state="normal", text="🤖
Generate Script")
self._update_status("Script generated successfully")
# Update current project
if self.current_project:
self.current_project.script = script
def _on_script_error(self, error: str):
"""Handle script generation error"""
self.generate_script_btn.configure(state="normal", text="🤖
Generate Script")
self._update_status("Script generation failed")
messagebox.showerror("Error", f"Script generation failed:
{error}")
def _load_script_file(self):
"""Load script from file"""
try:
file_path = filedialog.askopenfilename(
title="Load Script",
filetypes=[("Text files", "*.txt"), ("All files",
"*.*")]
)
if file_path:
with open(file_path, 'r', encoding='utf-8') as f:
script = f.read()
self.script_textbox.delete("1.0", "end")
self.script_textbox.insert("1.0", script)
if self.current_project:
self.current_project.script = script
self._update_status(f"Loaded script from
{os.path.basename(file_path)}")
except Exception as e:
logger.error(f"Error loading script file: {e}")
messagebox.showerror("Error", f"Failed to load script:
{e}")
def _save_script_file(self):
"""Save script to file"""
try:
file_path = filedialog.asksaveasfilename(
title="Save Script",
defaultextension=".txt",
filetypes=[("Text files", "*.txt"), ("All files",
"*.*")]
)
if file_path:
script = self.script_textbox.get("1.0", "end-1c")
with open(file_path, 'w', encoding='utf-8') as f:
f.write(script)
self._update_status(f"Saved script to
{os.path.basename(file_path)}")
except Exception as e:
logger.error(f"Error saving script file: {e}")
messagebox.showerror("Error", f"Failed to save script:
{e}")
def _analyze_script(self):
"""Analyze script and extract scenes"""
try:
script = self.script_textbox.get("1.0", "end-1c").strip()
if not script:
messagebox.showwarning("Warning", "Please enter or
generate a script first")
return
self._update_status("Analyzing script...")
self.analyze_script_btn.configure(state="disabled",
text="Analyzing...")
def analyze():
try:
scenes =
self.ai_service.analyze_script_with_gemini(script)
# Update UI in main thread
self.root.after(0, lambda:
self._on_script_analyzed(scenes))
except Exception as e:
self.root.after(0, lambda:
self._on_analysis_error(str(e)))
# Run analysis in background thread
threading.Thread(target=analyze, daemon=True).start()
except Exception as e:
logger.error(f"Error analyzing script: {e}")
messagebox.showerror("Error", f"Failed to analyze script:
{e}")
def _on_script_analyzed(self, scenes: List[Scene]):
"""Handle script analysis completion"""
if self.current_project:
self.current_project.scenes = scenes
self.analyze_script_btn.configure(state="normal", text="🔍
Analyze Scenes")
self._update_status(f"Script analyzed - {len(scenes)} scenes
found")
self._refresh_scenes_list()
# Switch to scenes tab
self.tabview.set("Scenes")
def _on_analysis_error(self, error: str):
"""Handle script analysis error"""
self.analyze_script_btn.configure(state="normal", text="🔍
Analyze Scenes")
self._update_status("Script analysis failed")
messagebox.showerror("Error", f"Script analysis failed:
{error}")
def _refresh_scenes_list(self):
"""Refresh the scenes list display"""
try:
# Clear existing scene widgets
for widget in self.scenes_scrollable.winfo_children():
widget.destroy()
if not self.current_project or not
self.current_project.scenes:
ctk.CTkLabel(
self.scenes_scrollable,
text="No scenes available\nAnalyze script to
generate scenes",
font=ctk.CTkFont(size=14)
).pack(pady=20)
return
# Create scene widgets
for scene in self.current_project.scenes:
scene_frame = ctk.CTkFrame(self.scenes_scrollable)
scene_frame.pack(fill="x", padx=5, pady=5)
# Scene header
header_frame = ctk.CTkFrame(scene_frame)
header_frame.pack(fill="x", padx=5, pady=5)
scene_title = ctk.CTkLabel(
header_frame,
text=f"Scene {scene.id}: {scene.title}",
font=ctk.CTkFont(size=14, weight="bold")
)
scene_title.pack(side="left", padx=5)
edit_btn = ctk.CTkButton(
header_frame,
text="Edit",
width=60,
height=25,
command=lambda s=scene: self._edit_scene(s)
)
edit_btn.pack(side="right", padx=5)
# Scene details
details_text = f"📍 {scene.location} | ⏰
{scene.time_of_day} | 🎭 {scene.mood} | {scene.duration}s"
ctk.CTkLabel(
scene_frame,
text=details_text,
font=ctk.CTkFont(size=12)
).pack(anchor="w", padx=10, pady=2)
# Scene action preview
if scene.action:
action_preview = scene.action[:100] + "..." if
len(scene.action) > 100 else scene.action
ctk.CTkLabel(
scene_frame,
text=f"Action: {action_preview}",
font=ctk.CTkFont(size=11),
text_color="gray"
).pack(anchor="w", padx=10, pady=1)
except Exception as e:
logger.error(f"Error refreshing scenes list: {e}")
def _edit_scene(self, scene: Scene):
"""Edit a scene"""
try:
self.selected_scene_id = scene.id
# Populate scene editor form
self.scene_title_entry.delete(0, "end")
self.scene_title_entry.insert(0, scene.title)
self.scene_location_entry.delete(0, "end")
self.scene_location_entry.insert(0, scene.location)
self.scene_time_combo.set(scene.time_of_day)
self.scene_mood_combo.set(scene.mood)
self.scene_duration_entry.delete(0, "end")
self.scene_duration_entry.insert(0, str(scene.duration))
self.scene_characters