Spaces:
Build error
Build error
| # app.py | |
| # | |
| # Copyright (C) August 4, 2025 Carlos Rodrigues dos Santos | |
| # | |
| # Versão 9.5.0 (Full Planner3D Architecture UI) | |
| # Esta versão implementa a UI completa para a nova arquitetura da Etapa 2, | |
| # com um chat e galeria dedicados, gerenciados pelo Planner3D. | |
| import gradio as gr | |
| import yaml | |
| import logging | |
| import os | |
| import sys | |
| import shutil | |
| import time | |
| # --- 1. IMPORTAÇÃO DO FRAMEWORK E CONFIGURAÇÃO --- | |
| import aduc_framework | |
| from aduc_framework.types import PreProductionParams, ProductionParams | |
| # ... (Configuração de Logging e Inicialização do Framework - sem alterações) ... | |
| LOG_FILE_PATH = "aduc_log.txt" | |
| if os.path.exists(LOG_FILE_PATH): os.remove(LOG_FILE_PATH) | |
| log_format = '%(asctime)s - %(levelname)s - [%(name)s:%(funcName)s] - %(message)s' | |
| root_logger = logging.getLogger() | |
| root_logger.setLevel(logging.INFO) | |
| root_logger.handlers.clear() | |
| stream_handler = logging.StreamHandler(sys.stdout) | |
| stream_handler.setFormatter(logging.Formatter(log_format)) | |
| root_logger.addHandler(stream_handler) | |
| file_handler = logging.FileHandler(LOG_FILE_PATH, mode='w', encoding='utf-8') | |
| file_handler.setFormatter(logging.Formatter(log_format)) | |
| root_logger.addHandler(file_handler) | |
| logger = logging.getLogger(__name__) | |
| try: | |
| with open("config.yaml", 'r') as f: config = yaml.safe_load(f) | |
| WORKSPACE_DIR = config['application']['workspace_dir'] | |
| aduc = aduc_framework.create_aduc_instance(workspace_dir=WORKSPACE_DIR) | |
| logger.info("Interface Gradio inicializada e conectada ao Aduc Framework.") | |
| except Exception as e: | |
| logger.critical(f"ERRO CRÍTICO durante a inicialização: {e}", exc_info=True) | |
| with gr.Blocks() as demo_error: | |
| gr.Markdown("# ERRO CRÍTICO NA INICIALIZAÇÃO") | |
| gr.Markdown("Não foi possível iniciar o Aduc Framework.") | |
| gr.Textbox(value=str(e), label="Detalhes do Erro", lines=10) | |
| demo_error.launch() | |
| exit() | |
| # --- 2. FUNÇÕES WRAPPER (UI <-> FRAMEWORK) --- | |
| def run_pre_production_wrapper(prompt, num_scenes, ref_files, resolution_str, duration_per_fragment, fast_mode): | |
| """Wrapper para a Etapa 1 (Pré-Produção - Roteiro).""" | |
| if not ref_files: raise gr.Error("Por favor, forneça pelo menos uma imagem de referência.") | |
| target_resolution = int(resolution_str.split('x')[0]) | |
| ref_paths = [aduc.process_image_for_story(f.name, target_resolution, f"ref_processed_{i}.png") for i, f in enumerate(ref_files)] | |
| params = PreProductionParams( | |
| prompt=prompt, num_scenes=int(num_scenes), ref_paths=ref_paths, | |
| resolution=target_resolution, duration_per_fragment=duration_per_fragment, fast_mode=fast_mode | |
| ) | |
| chatbot_display_history, fully_displayed_message_count, final_dna = [], 0, {} | |
| for update in aduc.task_pre_production(params): | |
| backend_chat_dna = update.get("chat_dna", []) | |
| dna_snapshot = update.get("dna_snapshot", gr.skip()) | |
| if update.get("status") == "complete": final_dna = update.get("dna", {}) | |
| while len(backend_chat_dna) > fully_displayed_message_count: | |
| new_message_obj = backend_chat_dna[fully_displayed_message_count] | |
| role = f"**{new_message_obj.get('role', 'Sistema')}**" | |
| content_to_type = new_message_obj.get('content', '') | |
| chatbot_display_history.append([role, ""]) | |
| full_typed_message = "" | |
| for char in content_to_type: | |
| full_typed_message += char | |
| chatbot_display_history[-1][1] = full_typed_message + "▌" | |
| yield { chat_history_chatbot: chatbot_display_history, dna_display: dna_snapshot } | |
| time.sleep(0.02) | |
| chatbot_display_history[-1][1] = full_typed_message | |
| yield { chat_history_chatbot: chatbot_display_history, dna_display: dna_snapshot } | |
| fully_displayed_message_count += 1 | |
| if "Llama, preciso da sua ajuda" in content_to_type: | |
| chatbot_display_history.append([f"**Llama (IA Criativa)**", "..."]) | |
| yield { chat_history_chatbot: chatbot_display_history, dna_display: dna_snapshot } | |
| time.sleep(1.5) | |
| chatbot_display_history.pop() | |
| yield { chat_history_chatbot: chatbot_display_history, dna_display: dna_snapshot } | |
| yield { | |
| chat_history_chatbot: chatbot_display_history, | |
| dna_display: final_dna, | |
| step2_accordion: gr.update(visible=True, open=True) | |
| } | |
| def run_keyframe_generation_wrapper(current_state_dict): | |
| """Wrapper para a Etapa 2. Consome os pacotes do Planner3D e dramatiza a UI.""" | |
| chatbot_display_history = [] | |
| fully_displayed_message_count = 0 | |
| final_dna = current_state_dict | |
| for update_package in aduc.task_generate_keyframes(current_state_dict): | |
| backend_chat_history = update_package.get("chat", []) | |
| gallery_paths = update_package.get("gallery", []) | |
| final_dna = update_package.get("dna", final_dna) | |
| while len(backend_chat_history) > fully_displayed_message_count: | |
| role, content_to_type = backend_chat_history[fully_displayed_message_count] | |
| chatbot_display_history.append([role, ""]) | |
| full_typed_message = "" | |
| for char in content_to_type: | |
| full_typed_message += char | |
| chatbot_display_history[-1][1] = full_typed_message + "▌" | |
| yield { | |
| keyframe_chat_chatbot: chatbot_display_history, | |
| keyframe_gallery: gr.update(value=gallery_paths), | |
| generation_state_holder: final_dna | |
| } | |
| time.sleep(0.02) | |
| chatbot_display_history[-1][1] = full_typed_message | |
| yield { | |
| keyframe_chat_chatbot: chatbot_display_history, | |
| keyframe_gallery: gr.update(value=gallery_paths), | |
| generation_state_holder: final_dna | |
| } | |
| fully_displayed_message_count += 1 | |
| if update_package.get("status") == "keyframes_complete": | |
| yield { | |
| keyframe_chat_chatbot: chatbot_display_history, | |
| keyframe_gallery: gr.update(value=gallery_paths), | |
| step3_accordion: gr.update(visible=True, open=True), | |
| generation_state_holder: final_dna | |
| } | |
| return | |
| # --- 3. DEFINIÇÃO DA UI --- | |
| with gr.Blocks(css="style.css") as demo: | |
| generation_state_holder = gr.State(value={}) | |
| gr.Markdown("<h1>ADUC-SDR 🎬 - A Sala de Roteiristas de IA</h1>") | |
| with gr.Accordion("Etapa 1: Planejamento do Roteiro", open=True): | |
| prompt_input = gr.Textbox(label="Ideia Geral do Filme", value="Um leão majestoso caminha pela savana e ruge para o sol poente.") | |
| with gr.Row(): | |
| resolution_selector = gr.Radio(["512x512", "768x768"], value="512x512", label="Resolução Base") | |
| num_scenes_slider = gr.Slider(minimum=2, maximum=5, value=3, step=1, label="Número de Cenas") | |
| duration_per_fragment_slider = gr.Slider(label="Duração de cada Ato (s)", minimum=2.0, maximum=10.0, value=5.0, step=0.1) | |
| ref_image_input = gr.File(label="Imagens de Referência", file_count="multiple", file_types=["image"]) | |
| fast_mode_checkbox = gr.Checkbox(label="Modo Rápido", value=False) | |
| start_planning_button = gr.Button("📝 Iniciar Planejamento (Etapa 1)", variant="primary") | |
| with gr.Accordion("🧠 Diário do Planejador de Roteiro (Ao Vivo)", open=False) as planning_log_accordion: | |
| with gr.Row(): | |
| chat_history_chatbot = gr.Chatbot(label="Conversa da Equipe de Roteiro", height=500, scale=1) | |
| dna_display = gr.JSON(label="DNA da Produção (em construção)", scale=1) | |
| with gr.Accordion("Etapa 2: Geração de Keyframes (Cenas-Chave)", open=False, visible=False) as step2_accordion: | |
| start_keyframe_button = gr.Button("🖼️ Gerar Keyframes (Etapa 2)", variant="primary") | |
| keyframe_chat_chatbot = gr.Chatbot(label="Conversa do Arquiteto Visual e Pintor", bubble_full_width=False, height=300) | |
| keyframe_gallery = gr.Gallery(label="Keyframes Gerados (em tempo real)", object_fit="contain", height="auto") | |
| with gr.Accordion("Etapa 3: Produção do Vídeo Original", open=False, visible=False) as step3_accordion: | |
| produce_original_button = gr.Button("🎬 Produzir Vídeo (Etapa 3)", variant="primary") | |
| with gr.Accordion("🎞️ Resultado Final", open=True): | |
| final_video_output = gr.Video(label="Filme Concluído", interactive=False) | |
| # --- 4. CONEXÕES DE EVENTOS --- | |
| start_planning_button.click( | |
| fn=lambda: gr.update(open=True), outputs=[planning_log_accordion] | |
| ).then( | |
| fn=run_pre_production_wrapper, | |
| inputs=[prompt_input, num_scenes_slider, ref_image_input, resolution_selector, duration_per_fragment_slider, fast_mode_checkbox], | |
| outputs=[chat_history_chatbot, dna_display, step2_accordion] | |
| ) | |
| dna_display.change(fn=lambda data: data, inputs=dna_display, outputs=generation_state_holder) | |
| start_keyframe_button.click( | |
| fn=run_keyframe_generation_wrapper, | |
| inputs=[generation_state_holder], | |
| outputs=[keyframe_chat_chatbot, keyframe_gallery, step3_accordion, generation_state_holder] | |
| ) | |
| # --- 5. INICIALIZAÇÃO DA APLICAÇÃO --- | |
| if __name__ == "__main__": | |
| if os.path.exists(WORKSPACE_DIR): shutil.rmtree(WORKSPACE_DIR) | |
| os.makedirs(WORKSPACE_DIR) | |
| logger.info("Aplicação Gradio iniciada. Lançando interface...") | |
| demo.queue().launch() |