|
|
|
|
|
|
|
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: |
|
|
|
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 |
|
|
|
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") |
|
|
|
|
|
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: |
|
|
|
video_path = video_file.name if hasattr(video_file, 'name') else str(video_file) |
|
|
|
print(f"Processando: {video_path}") |
|
|
|
|
|
analista = CineAnalistaV3() |
|
|
|
|
|
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) |
|
|
|
|
|
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: |
|
|
|
|
|
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** |
|
""") |
|
|
|
|
|
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 |
|
""") |
|
|
|
|
|
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'." |
|
) |
|
|
|
|
|
analyze_btn.click( |
|
fn=process_video_interface, |
|
inputs=[video_input], |
|
outputs=[results_output, status_msg], |
|
show_progress=True |
|
) |
|
|
|
|
|
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* |
|
""") |
|
|
|
|
|
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() |