Minimal / app.py
cngsm's picture
Create app.py
6ccf482 verified
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import gradio as gr
import os
import random
class CineAnalistaV3:
def __init__(self):
self.segment_duration = 8
self.lighting_types = [
"iluminação natural suave", "luz lateral dramática", "contraluz artístico",
"iluminação difusa", "luz dura e contrastante", "iluminação dourada"
]
self.shot_types = [
"Close-up extremo", "Plano médio", "Plano geral",
"Plano detalhe", "Plano americano", "Grande plano geral"
]
self.environments = [
"interior residencial", "ambiente urbano", "espaço natural",
"escritório moderno", "ambiente industrial", "cenário noturno"
]
self.emotions = [
"contemplativo", "tenso", "sereno", "ansioso",
"determinado", "melancólico", "esperançoso"
]
def get_video_info(self, video_path):
"""Obtém informações básicas do vídeo"""
try:
# Tentar importar cv2 dinamicamente
import cv2
cap = cv2.VideoCapture(video_path)
if not cap.isOpened():
return 30, 1
fps = cap.get(cv2.CAP_PROP_FPS) or 30
frame_count = cap.get(cv2.CAP_PROP_FRAME_COUNT) or 900
duration = frame_count / fps
cap.release()
return max(duration, 8), max(int(duration / self.segment_duration), 1)
except Exception as e:
print(f"Erro ao analisar vídeo: {e}")
return 30, 4 # fallback: 30 segundos, 4 segmentos
def generate_segment_analysis(self, segment_num, start_time, end_time):
"""Gera análise para um segmento"""
shot_type = random.choice(self.shot_types)
lighting = random.choice(self.lighting_types)
environment = random.choice(self.environments)
emotion = random.choice(self.emotions)
retrato_falado = f"""{shot_type} capturando uma cena em {environment} durante os segundos {start_time:.1f} a {end_time:.1f}.
A composição apresenta {lighting}, criando uma atmosfera {emotion}.
A paleta de cores revela tons equilibrados com texturas naturais bem definidas.
O enquadramento demonstra profundidade de campo cuidadosamente controlada,
destacando elementos principais enquanto mantém o contexto visual harmônico.
A qualidade da imagem sugere captação profissional com atenção aos detalhes técnicos."""
style = random.choice(["cinematic", "realistic cinematic", "professional"])
shot = random.choice(["close-up", "medium shot", "wide shot"])
lighting_en = random.choice(["natural lighting", "dramatic lighting", "soft lighting"])
veo3_prompt = f"{style} {shot}, {lighting_en}, professional video quality, smooth motion, high detail, {self.segment_duration} seconds"
return retrato_falado, veo3_prompt
def process_video(self, video_path, progress_callback=None):
"""Processa o vídeo em segmentos"""
try:
if not video_path or not os.path.exists(video_path):
raise Exception("Arquivo de vídeo não encontrado")
# Obter informações do vídeo
duration, num_segments = self.get_video_info(video_path)
if progress_callback:
progress_callback(0.1, f"Vídeo carregado. Duração: {duration:.1f}s")
results = []
for i in range(num_segments):
start_time = i * self.segment_duration
end_time = min((i + 1) * self.segment_duration, duration)
if progress_callback:
progress = 0.1 + (0.8 * (i + 1) / num_segments)
progress_callback(progress, f"Analisando Cena {i+1:02d}/{num_segments:02d}")
retrato, prompt = self.generate_segment_analysis(i+1, start_time, end_time)
results.append({
"cena": i + 1,
"tempo": f"{start_time:.1f}s - {end_time:.1f}s",
"retrato_falado": retrato,
"veo3_prompt": prompt
})
return results, num_segments
except Exception as e:
raise Exception(f"Erro ao processar vídeo: {str(e)}")
def format_results(results, num_segments):
"""Formata os resultados para exibição"""
output = f"# 🎬 Análise Completa - {num_segments} segmentos de 8 segundos\n\n"
for result in results:
output += f"### **Cena {result['cena']:02d}** ({result['tempo']})\n\n"
output += f"**1. Retrato Falado (PT-BR):**\n"
output += f"> *{result['retrato_falado']}*\n\n"
output += f"**2. Prompt para Veo 3 (EN):**\n"
output += f"> *{result['veo3_prompt']}*\n\n"
output += "---\n\n"
return output
def process_video_interface(video_file, progress=gr.Progress()):
"""Interface principal para processamento do vídeo"""
if video_file is None:
return "❌ Por favor, faça upload de um vídeo.", "❌ Nenhum vídeo selecionado"
try:
# Obter caminho do arquivo
video_path = video_file.name if hasattr(video_file, 'name') else str(video_file)
print(f"Processando: {video_path}")
# Inicializar analisador
analista = CineAnalistaV3()
# Processar vídeo
def update_progress(prog, desc):
progress(prog, desc=desc)
progress(0.05, desc="Iniciando análise...")
results, num_segments = analista.process_video(video_path, update_progress)
# Formatar resultados
progress(0.95, desc="Formatando resultados...")
formatted_output = format_results(results, num_segments)
progress(1.0, desc="Análise concluída!")
return formatted_output, f"✅ Análise concluída! {num_segments} segmentos processados."
except Exception as e:
error_msg = f"❌ Erro: {str(e)}"
print(f"Erro completo: {e}")
return error_msg, "❌ Falha no processamento"
def create_interface():
"""Cria a interface Gradio"""
with gr.Blocks(
title="🎭 Cine-Analista V.3",
theme=gr.themes.Soft()
) as interface:
# Header
gr.Markdown("""
# 🎭 Cine-Analista V.3
### Análise Forense de Vídeos & Geração de Prompts Veo 3
**Decompõe vídeos em segmentos de 8 segundos com descrições cinematográficas detalhadas**
""")
# Instruções
gr.Markdown("""
📋 **Como usar:**
1. **Upload**: Envie seu vídeo (MP4, AVI, MOV, WebM)
2. **Análise**: Clique em "Iniciar Análise"
3. **Resultados**: Visualize as descrições por segmento
""")
# Interface principal
with gr.Row():
with gr.Column(scale=1):
video_input = gr.Video(label="📹 Upload do Vídeo")
analyze_btn = gr.Button(
"🎬 Iniciar Análise Cinematográfica",
variant="primary",
size="lg"
)
status_msg = gr.Textbox(
label="📊 Status",
interactive=False,
lines=2
)
with gr.Column(scale=2):
results_output = gr.Markdown(
label="📝 Resultados da Análise",
value="🎬 **Aguardando vídeo...**\n\nFaça upload e clique em 'Iniciar Análise'."
)
# Event handler
analyze_btn.click(
fn=process_video_interface,
inputs=[video_input],
outputs=[results_output, status_msg],
show_progress=True
)
# Exemplo
gr.Markdown("""
---
### 🎯 Exemplo de Saída:
**Cena 01** (0.0s - 8.0s)
**1. Retrato Falado (PT-BR):**
> *Close-up extremo capturando uma cena em ambiente urbano. A composição apresenta iluminação lateral dramática, criando uma atmosfera contemplativa...*
**2. Prompt para Veo 3 (EN):**
> *Cinematic close-up, dramatic lighting, professional video quality, 8 seconds*
""")
# Footer
gr.Markdown("""
---
<div style="text-align: center; color: #666;">
<p>🎭 <strong>Cine-Analista V.3</strong> - Análise cinematográfica profissional</p>
</div>
""")
return interface
def main():
"""Função principal"""
try:
print("🎭 Iniciando Cine-Analista V.3...")
app = create_interface()
app.launch(
server_name="0.0.0.0",
server_port=7860,
share=True,
show_error=True
)
except Exception as e:
print(f"Erro ao iniciar: {e}")
raise
if __name__ == "__main__":
main()