SpotMaster_v1.0 / app.py
Marek4321's picture
Update app.py
ca4db0c verified
# @title app.py
import os
import gradio as gr
import asyncio
from pathlib import Path
from typing import Optional, List, Tuple
from core.shooting_board import ShootingBoardGenerator
from core.audio_gen import AudioGenerator
from core.video_gen import VideoGenerator
from core.video_editor import VideoEditor
from utils.logger import SpotMakerLogger
from utils.jwt_handler import JWTHandler
class SpotMakerApp:
def __init__(self):
self.logger = SpotMakerLogger()
self.jwt_handler = JWTHandler()
self.output_dir = Path("output")
self.output_dir.mkdir(exist_ok=True)
def create_interface(self) -> gr.Blocks:
with gr.Blocks(title="SpotMaker - Generator Reklam Video") as interface:
gr.Markdown(
"""
# 🎥 SpotMaker - Generator Reklam Video // by www.Heuristica.pl
Wprowadź swój klucz API i opisz koncepcję reklamy.
"""
)
with gr.Row():
with gr.Column():
# Konfiguracja API
api_key = gr.Textbox(
label="Klucz API Hailuo",
placeholder="Wklej swój klucz API...",
type="password"
)
# Koncepcja
concept = gr.Textbox(
label="Opis koncepcji",
placeholder="Wprowadź krótki opis koncepcji reklamowej...",
lines=5
)
file_input = gr.File(
label="Załącz dodatkowy opis (opcjonalnie)",
file_types=["txt", "docx"]
)
with gr.Row():
start_btn = gr.Button("▶️ Generuj spot", variant="primary")
clear_btn = gr.Button("🗑️ Wyczyść")
with gr.Column():
# Status i logi
progress = gr.Slider(
minimum=0,
maximum=100,
value=0,
label="Postęp",
interactive=False
)
status = gr.Markdown("Gotowy do rozpoczęcia")
logs = gr.TextArea(
value="",
label="Szczegółowe logi",
interactive=False,
lines=15,
autoscroll=True,
show_copy_button=True,
max_lines=100
)
# Funkcja do aktualizacji logów
def add_log(msg: str, current_logs: str) -> str:
"""Dodaje nową linię do logów z timestampem."""
if not current_logs:
return msg
return f"{current_logs}\n{msg}"
# Tworzenie listy do przechowywania callback'ów aktualizacji logów
log_updates = []
with gr.Row(visible=False) as result_row:
# Wyniki
video_output = gr.Video(label="Wygenerowany spot")
with gr.Column():
video_info = gr.Markdown("")
download_btn = gr.Button("⬇️ Pobierz spot")
def validate_api_key(api_key: str) -> str:
"""Sprawdza poprawność klucza API i wyświetla GroupID."""
if not api_key:
return "❌ Wprowadź klucz API"
group_id = self.jwt_handler.extract_group_id(api_key)
if not group_id:
return "❌ Nieprawidłowy klucz API"
return f"✅ GroupID: {group_id}"
def update_state(value: float, message: str) -> dict:
"""Aktualizuje stan interfejsu."""
self.logger.update_progress("app", value, message)
return {
progress: value,
status: message,
logs: self.logger.get_module_status("app")
}
def generate(api_key: str, concept: str, file_input: Optional[str]) -> dict:
"""Główna funkcja generująca spot."""
try:
# Walidacja API
group_id = self.jwt_handler.extract_group_id(api_key)
if not group_id:
return {
progress: 0,
status: "❌ Błąd: Nieprawidłowy klucz API",
logs: "Sprawdź czy klucz API jest poprawny",
result_row: gr.Row(visible=False),
video_output: None,
video_info: "",
download_btn: gr.Button(visible=False)
}
# Walidacja koncepcji
if not concept or len(concept.strip()) < 10:
return {
progress: 0,
status: "❌ Błąd: Zbyt krótki opis",
logs: "Wprowadź dłuższy opis koncepcji (min. 10 znaków)",
result_row: gr.Row(visible=False),
video_output: None,
video_info: "",
download_btn: gr.Button(visible=False)
}
# Create event loop
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
# Update progress
update_state(20, "Generuję scenariusz...")
# Create generators
shooting_board = ShootingBoardGenerator(api_key, self.logger)
audio_gen = AudioGenerator(api_key, group_id, "generated_audio", self.logger)
video_gen = VideoGenerator(api_key, "generated_videos", self.logger)
video_editor = VideoEditor("final_spot", self.logger)
# 1. Generate shooting board
scenario = loop.run_until_complete(shooting_board.generate(concept))
update_state(40, "Generuję ścieżkę audio...")
# 2. Generate audio
audio_result = loop.run_until_complete(audio_gen.generate_voice_over(scenario['voice_over']))
audio_path, audio_duration = audio_result
update_state(60, "Generuję klipy video...")
# 3. Generate video clips
video_paths = loop.run_until_complete(video_gen.generate_clips(scenario['key_frames']))
update_state(80, "Montuję finalny spot...")
# 4. Edit final video
final_path = loop.run_until_complete(video_editor.create_spot(video_paths, audio_path, audio_duration))
# Close loop
loop.close()
# Success
update_state(100, "Zakończono!")
return {
progress: 100,
status: "✅ Generowanie zakończone!",
logs: self.logger.get_module_status("app"),
video_output: final_path,
video_info: f"""### Szczegóły spotu:
- Długość: {audio_duration:.2f}s
- Liczba ujęć: {len(video_paths)}""",
result_row: gr.Row(visible=True),
download_btn: gr.Button(visible=True)
}
# 4. Edit final video
final_path = video_editor.create_spot(video_paths, audio_path, audio_duration)
# Success
update_state(100, "Zakończono!")
return {
progress: 100,
status: "✅ Generowanie zakończone!",
logs: self.logger.get_module_status("app"),
video_output: final_path,
video_info: f"""### Szczegóły spotu:
- Długość: {audio_duration:.2f}s
- Liczba ujęć: {len(video_paths)}""",
result_row: gr.Row(visible=True)
}
except Exception as e:
error_msg = self.logger.format_error("app", e)
return {
progress: 0,
status: "❌ Wystąpił błąd",
logs: f"Szczegóły błędu:\n{error_msg}",
result_row: gr.Row(visible=False),
video_output: None,
video_info: ""
}
def clear() -> dict:
"""Czyści interfejs."""
return {
api_key: "",
concept: "",
file_input: None,
progress: 0,
status: "Gotowy do rozpoczęcia",
logs: "",
video_output: None,
video_info: "",
result_row: gr.Row(visible=False)
}
# Podpięcie zdarzeń
api_key.change(validate_api_key, api_key, status)
start_btn.click(
fn=generate,
inputs=[api_key, concept, file_input],
outputs=[progress, status, logs, video_output, video_info,
result_row, download_btn]
)
clear_btn.click(
fn=clear,
outputs=[api_key, concept, file_input, progress, status,
logs, video_output, video_info, result_row, download_btn]
)
return interface
if __name__ == "__main__":
app = SpotMakerApp()
interface = app.create_interface()
interface.queue()
interface.launch(
server_name="0.0.0.0",
server_port=7860,
show_api=False,
share=False
)