diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..df9aed620a0decf235b7b51937b03b06d43d2322
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,16 @@
+# Ignorar dependências clonadas
+/deps/
+
+# Ignorar o diretório do workspace da aplicação
+/deformes_workspace/
+
+# Ignorar arquivos de cache do Python
+__pycache__/
+*.pyc
+*.pyo
+*.pyd
+
+# Ignorar logs e arquivos de ambiente
+*.log
+aduc_log.txt
+.env
\ No newline at end of file
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..11ae128e056a3be054e1c2bc93de8f8533c71ae9
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,480 @@
+# =============================================================================
+# DOCKERFILE - Complete AI Video Suite v2.0.0
+# Optimized for 8x NVIDIA L40S GPUs (384GB Total VRAM)
+# Production-Ready Multi-GPU Video Generation Suite
+# =============================================================================
+
+FROM nvidia/cuda:12.8.0-devel-ubuntu22.04
+
+# =============================================================================
+# METADATA AND LABELS
+# =============================================================================
+
+LABEL maintainer="Complete AI Video Suite Team"
+LABEL description="Multi-GPU AI Video Generation Suite with LTX FP8, Q8 Kernels, SeedVR, Wan2.2, VINCIE, MMAudio"
+LABEL version="2.0.0"
+LABEL build_date="2025-09-18"
+LABEL cuda_version="12.4.0"
+LABEL python_version="3.10"
+LABEL pytorch_version="2.8.0+cu128"
+LABEL architecture="amd64"
+LABEL gpu_optimized="8x_L40S"
+LABEL total_vram="384GB"
+LABEL license="MIT"
+
+
+# =============================================================================
+# ENVIRONMENT VARIABLES - PRODUCTION OPTIMIZED
+# =============================================================================
+
+ENV DEBIAN_FRONTEND=noninteractive
+ENV TZ=UTC
+ENV LC_ALL=C.UTF-8
+ENV LANG=C.UTF-8
+
+# Python optimization
+ENV PYTHONUNBUFFERED=1
+ENV PYTHONDONTWRITEBYTECODE=1
+ENV PYTHONIOENCODING=utf-8
+ENV PIP_NO_CACHE_DIR=1
+ENV PIP_DISABLE_PIP_VERSION_CHECK=0
+
+# CUDA optimizations for 8x L40S GPUs
+ENV NVIDIA_VISIBLE_DEVICES=all
+ENV NVIDIA_DRIVER_CAPABILITIES=compute,utility,graphics
+ENV NVIDIA_REQUIRE_CUDA="cuda>=12.8"
+ENV CUDA_LAUNCH_BLOCKING=0
+ENV TORCH_CUDA_ARCH_LIST="8.9"
+ENV CUDA_CACHE_MAXSIZE=2147483648
+
+# Multi-GPU distributed training
+ENV NCCL_DEBUG=DEBUG
+ENV NCCL_TREE_THRESHOLD=1
+ENV NCCL_P2P_DISABLE=0
+ENV NCCL_IB_DISABLE=0
+ENV NCCL_NVLS_ENABLE=1
+ENV NCCL_CROSS_NIC=1
+
+# PyTorch optimizations
+ENV PYTORCH_CUDA_ALLOC_CONF=max_split_size_mb:512,roundup_power2_divisions:16
+ENV TORCH_BACKENDS_CUDNN_BENCHMARK=1
+ENV TORCH_BACKENDS_CUDA_MATMUL_ALLOW_TF32=1
+ENV TORCH_BACKENDS_CUDNN_ALLOW_TF32=1
+
+# Application paths
+ENV APP_HOME=/app
+ENV HF_HOME=/app/model_cache
+ENV HF_HUB_CACHE=/app/model_cache/hub
+ENV TRANSFORMERS_CACHE=/app/model_cache/transformers
+ENV TORCH_HOME=/app/model_cache/torch
+ENV TMPDIR=/app/tmp
+ENV OUTPUT_DIR=/app/outputs
+
+# CPU optimizations
+ENV OMP_NUM_THREADS=8
+ENV MKL_NUM_THREADS=8
+ENV NUMEXPR_NUM_THREADS=8
+ENV OPENBLAS_NUM_THREADS=8
+
+# =============================================================================
+# SYSTEM PACKAGE INSTALLATION
+# =============================================================================
+
+RUN apt-get update && apt-get install -y \
+ build-essential \
+ cmake \
+ ninja-build \
+ pkg-config \
+ python3.11 \
+ python3.11-dev \
+ python3.11-distutils \
+ python3-pip \
+ python3.11-venv \
+ git \
+ git-lfs \
+ curl \
+ wget \
+ rsync \
+ unzip \
+ zip \
+ ffmpeg \
+ libavcodec-dev \
+ libavformat-dev \
+ libavutil-dev \
+ libswscale-dev \
+ libgl1-mesa-glx \
+ libgl1-mesa-dev \
+ libglib2.0-0 \
+ libsm6 \
+ libxext6 \
+ libxrender-dev \
+ libgomp1 \
+ libglu1-mesa \
+ libglu1-mesa-dev \
+ htop \
+ nvtop \
+ tree \
+ vim \
+ nano \
+ tmux \
+ screen \
+ net-tools \
+ iproute2 \
+ iotop \
+ && apt-get autoremove -y \
+ && apt-get clean \
+ && rm -rf /var/lib/apt/lists/* \
+ && rm -rf /tmp/* \
+ && rm -rf /var/tmp/*
+
+# =============================================================================
+# PYTHON SETUP AND OPTIMIZATION
+# =============================================================================
+
+RUN ln -sf /usr/bin/python3.10 /usr/bin/python3 && \
+ ln -sf /usr/bin/python3.10 /usr/bin/python && \
+ python3 -m pip install --upgrade pip==24.2 setuptools==70.0.0 wheel==0.43.0
+
+RUN pip install \
+ packaging \
+ ninja \
+ cmake \
+ pybind11 \
+ scikit-build \
+ cython \
+ numpy>=1.24.3
+
+# =============================================================================
+# PYTORCH AND CUDA LIBRARIES
+# =============================================================================
+
+RUN pip install \
+ torch>=2.8.0+cu128 \
+ torchvision \
+ torchaudio \
+ --index-url https://download.pytorch.org/whl/cu128
+
+RUN pip install torchao
+
+RUN python3 -c "import torch; print(f'PyTorch: {torch.__version__}'); print(f'CUDA available: {torch.cuda.is_available()}'); print(f'CUDA version: {torch.version.cuda}'); print(f'Device count: {torch.cuda.device_count()}')"
+
+
+# =============================================================================
+# AI/ML LIBRARIES INSTALLATION
+# =============================================================================
+
+WORKDIR $APP_HOME
+COPY . .
+
+RUN pip install -r requirements.txt
+
+# =============================================================================
+# APPLICATION STRUCTURE SETUP
+# =============================================================================
+
+RUN mkdir -p \
+ $APP_HOME/installer \
+ $APP_HOME/monitoring \
+ $APP_HOME/tools \
+ $APP_HOME/configs \
+ $APP_HOME/build_cache \
+ $APP_HOME/model_cache/hub \
+ $APP_HOME/model_cache/transformers \
+ $APP_HOME/model_cache/torch \
+ $APP_HOME/model_cache/ltx_models \
+ $APP_HOME/tmp \
+ $APP_HOME/outputs \
+ $APP_HOME/logs \
+ && chmod -R 755 $APP_HOME
+
+# =============================================================================
+# DOWNLOAD PREREQUISITE FILES
+# =============================================================================
+
+
+COPY . .
+
+COPY configs/ ./configs/
+
+
+RUN chmod +x start.sh && \
+ find . -name "*.sh" -exec chmod +x {} \; && \
+ find . -name "*.py" -exec chmod +x {} \;
+
+# =============================================================================
+# CREATE OPTIMIZATION PATCHES AND TOOLS (FIXED SYNTAX)
+# =============================================================================
+
+
+# =============================================================================
+# CONFIGURATION FILES
+# =============================================================================
+
+# Create default LTX FP8 configuration
+RUN cat <<'YAML_CONFIG' > $APP_HOME/configs/ltxv-13b-0.9.8-distilled-fp8.yaml
+# LTX Video FP8 Distilled Configuration
+# Optimized for 8x L40S GPUs (384GB VRAM)
+model:
+ target: "ltx_video.models.transformer_temporal.TransformerTemporalModel"
+ params:
+ transformer_additional_kwargs:
+ attention_mode: "sdpa"
+ enable_flash_attention: true
+ memory_efficient_attention: true
+ network_config:
+ model_name: "ltxv-13b-0.9.8-distilled-fp8"
+ fp8_optimization: true
+ quantization: "fp8"
+ ada_optimized: true
+ multi_gpu_support: true
+
+scheduler:
+ target: "diffusers.LTXVideoScheduler"
+ params:
+ num_train_timesteps: 1000
+ beta_start: 0.0001
+ beta_end: 0.02
+ beta_schedule: "scaled_linear"
+
+vae:
+ target: "diffusers.AutoencoderKLLTXVideo"
+ params:
+ force_upcast: false
+ enable_slicing: true
+ enable_tiling: true
+
+text_encoder:
+ target: "transformers.T5EncoderModel"
+ params:
+ torch_dtype: "bfloat16"
+
+pipeline:
+ target: "diffusers.LTXVideoPipeline"
+ params:
+ scheduler_type: "LTXVideoScheduler"
+ num_inference_steps: 4
+ guidance_scale: 1.0
+ height: 704
+ width: 1216
+ num_frames: 121
+ fps: 30
+ enable_memory_efficient_attention: true
+ enable_cpu_offload: false
+ enable_model_cpu_offload: false
+ max_batch_size: 4
+
+multi_gpu:
+ enabled: true
+ num_gpus: 8
+ distribution_strategy: "data_parallel"
+ load_balancing: "memory_aware"
+ synchronize_gpus: true
+YAML_CONFIG
+
+# Create multi-GPU optimization config
+RUN cat <<'GPU_CONFIG' > $APP_HOME/configs/multi_gpu_config.yaml
+# Multi-GPU Configuration for 8x L40S Setup
+system:
+ gpu_count: 8
+ total_vram: "384GB"
+ compute_capability: "8.9"
+ architecture: "ADA_LOVELACE"
+
+distributed_training:
+ backend: "nccl"
+ init_method: "env://"
+ world_size: 8
+ rank: 0
+
+memory_optimization:
+ gradient_checkpointing: true
+ mixed_precision: "bf16"
+ max_batch_size_per_gpu: 8
+ gradient_accumulation_steps: 4
+ memory_fraction: 0.95
+
+performance:
+ torch_compile: true
+ cuda_graphs: true
+ tensor_cores: true
+ flash_attention: true
+ memory_efficient_attention: true
+
+load_balancing:
+ strategy: "memory_aware"
+ rebalance_interval: 30
+ utilization_threshold: 0.8
+
+thermal_management:
+ max_temperature: 83
+ fan_curve: "aggressive"
+ throttle_threshold: 80
+ monitoring_interval: 10
+
+power_management:
+ max_power_limit: 300
+ efficiency_mode: false
+ power_monitoring: true
+GPU_CONFIG
+
+# =============================================================================
+# HEALTH CHECK SCRIPT
+# =============================================================================
+
+RUN cat <<'HEALTHCHECK_SCRIPT' > $APP_HOME/healthcheck.py
+#!/usr/bin/env python3
+"""
+Health check script for Complete AI Video Suite
+"""
+import sys
+import requests
+import torch
+import time
+import logging
+
+logging.basicConfig(level=logging.INFO)
+logger = logging.getLogger(__name__)
+
+def check_cuda():
+ """Check CUDA availability and GPU status"""
+ if not torch.cuda.is_available():
+ logger.error("CUDA not available")
+ return False
+
+ gpu_count = torch.cuda.device_count()
+ logger.info(f"CUDA available with {gpu_count} GPUs")
+
+ for i in range(gpu_count):
+ try:
+ torch.cuda.set_device(i)
+ props = torch.cuda.get_device_properties(i)
+ memory_allocated = torch.cuda.memory_allocated() / 1024**3
+ memory_total = props.total_memory / 1024**3
+
+ logger.info(f"GPU {i}: {props.name} ({memory_allocated:.2f}GB/{memory_total:.1f}GB)")
+
+ x = torch.randn(100, 100, device=f'cuda:{i}')
+ y = torch.matmul(x, x)
+ torch.cuda.synchronize()
+
+ except Exception as e:
+ logger.error(f"GPU {i} test failed: {e}")
+ return False
+
+ return True
+
+def check_web_service():
+ """Check if web service is responding"""
+ try:
+ response = requests.get("http://localhost:7860/", timeout=10)
+ if response.status_code == 200:
+ logger.info("Web service is responding")
+ return True
+ else:
+ logger.error(f"Web service returned status code: {response.status_code}")
+ return False
+ except requests.RequestException as e:
+ logger.error(f"Web service check failed: {e}")
+ return False
+
+def main():
+ """Main health check routine"""
+ logger.info("Starting health check...")
+
+ if not check_cuda():
+ sys.exit(1)
+
+ if not check_web_service():
+ sys.exit(1)
+
+ logger.info("All health checks passed")
+ sys.exit(0)
+
+if __name__ == "__main__":
+ main()
+HEALTHCHECK_SCRIPT
+
+RUN chmod +x $APP_HOME/healthcheck.py
+
+# =============================================================================
+# USER SETUP AND SECURITY
+# =============================================================================
+
+RUN mkdir -p /etc/sudoers.d && \
+ useradd -m -u 1000 -s /bin/bash appuser && \
+ usermod -aG sudo appuser && \
+ chown -R appuser:appuser $APP_HOME && \
+ echo "appuser ALL=(ALL) NOPASSWD: /usr/bin/nvidia-smi, /usr/bin/nvidia-ml-py" > /etc/sudoers.d/appuser
+
+USER appuser
+
+WORKDIR $APP_HOME
+
+# =============================================================================
+# RUNTIME CONFIGURATION
+# =============================================================================
+
+EXPOSE 7860 8001 8002 6006
+
+VOLUME ["/app/model_cache", "/app/outputs", "/app/logs", "/app/build_cache"]
+
+HEALTHCHECK --interval=60s --timeout=30s --start-period=300s --retries=3 \
+ CMD python3 /app/healthcheck.py
+
+# =============================================================================
+# FINAL SETUP AND ENTRY POINT
+# =============================================================================
+
+RUN cat <<'ENTRYPOINT_SCRIPT' > $APP_HOME/docker-entrypoint.sh
+#!/bin/bash
+set -euo pipefail
+
+echo "🚀 Complete AI Suite - Docker Container Starting..."
+echo "🐳 Container: $(hostname)"
+echo "👤 User: $(whoami)"
+echo "🎮 GPUs: $(nvidia-smi --list-gpus | wc -l || echo '0')"
+
+if command -v nvidia-smi >/dev/null 2>&1; then
+ echo "💾 CUDA Memory:"
+ nvidia-smi --query-gpu=memory.total,memory.used --format=csv,noheader,nounits | nl
+fi
+
+echo "🔧 Applying optimization patches..."
+python3 /app/tools/optimization_patch.py
+
+echo "📁 Setting up permissions..."
+chmod -R 755 /app/installer
+chmod -R 755 /app/monitoring
+chmod +x /app/start.sh
+
+mkdir -p /app/logs /app/outputs /app/tmp
+chmod 777 /app/logs /app/outputs /app/tmp
+
+echo "✅ Docker container initialization complete"
+echo "🚀 Starting Complete AI Video Suite..."
+
+exec /app/start.sh "$@"
+ENTRYPOINT_SCRIPT
+
+RUN chmod +x $APP_HOME/docker-entrypoint.sh
+
+ENTRYPOINT ["/app/docker-entrypoint.sh"]
+
+CMD ["--listen", "--multi-gpu", "--optimize"]
+
+# =============================================================================
+# FINAL METADATA
+# =============================================================================
+
+RUN echo "Complete AI Video Suite v2.0.0" > /app/VERSION && \
+ echo "Build Date: 2025-09-18T$(date +%H:%M:%S)" >> /app/VERSION && \
+ echo "CUDA: 12.4.1" >> /app/VERSION && \
+ echo "PyTorch: $(python3 -c 'import torch; print(torch.__version__)')" >> /app/VERSION && \
+ echo "Optimized for: 8x NVIDIA L40S GPUs" >> /app/VERSION
+
+LABEL org.opencontainers.image.title="Complete AI Video Suite"
+LABEL org.opencontainers.image.description="Production-ready multi-GPU video generation with LTX FP8, Q8 Kernels, and more"
+LABEL org.opencontainers.image.version="2.0.0"
+LABEL org.opencontainers.image.created="2025-09-18T17:42:00Z"
+LABEL org.opencontainers.image.revision="main"
+LABEL org.opencontainers.image.licenses="MIT"
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..e6fb40ab269ce532dd06cc34da2f86bc5f5441cd
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,25 @@
+# Euia-AducSdr: Uma implementação aberta e funcional da arquitetura ADUC-SDR para geração de vídeo coerente.
+# Copyright (C) 4 de Agosto de 2025 Carlos Rodrigues dos Santos
+#
+# Contato:
+# Carlos Rodrigues dos Santos
+# carlex22@gmail.com
+# Rua Eduardo Carlos Pereira, 4125, B1 Ap32, Curitiba, PR, Brazil, CEP 8102025
+#
+# Repositórios e Projetos Relacionados:
+# GitHub: https://github.com/carlex22/Aduc-sdr
+# Hugging Face (Ltx-SuperTime-60Secondos): https://huggingface.co/spaces/Carlexx/Ltx-SuperTime-60Secondos/
+# Hugging Face (Novinho): https://huggingface.co/spaces/Carlexxx/Novinho/
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
\ No newline at end of file
diff --git a/NOTICE.md b/NOTICE.md
new file mode 100644
index 0000000000000000000000000000000000000000..e6dad38733a306f61263d083c471e6bac403e222
--- /dev/null
+++ b/NOTICE.md
@@ -0,0 +1,76 @@
+# NOTICE
+
+Copyright (C) 2025 Carlos Rodrigues dos Santos. All rights reserved.
+
+---
+
+## Aviso de Propriedade Intelectual e Licenciamento
+
+### **Processo de Patenteamento em Andamento (EM PORTUGUÊS):**
+
+O método e o sistema de orquestração de prompts denominados **ADUC (Automated Discovery and Orchestration of Complex tasks)**, conforme descritos neste documento e implementados neste software, estão atualmente em processo de patenteamento.
+
+O titular dos direitos, Carlos Rodrigues dos Santos, está buscando proteção legal para as inovações chave da arquitetura ADUC, incluindo, mas não se limitando a:
+
+* Fragmentação e escalonamento de solicitações que excedem limites de contexto de modelos de IA.
+* Distribuição inteligente de sub-tarefas para especialistas heterogêneos.
+* Gerenciamento de estado persistido com avaliação iterativa e realimentação para o planejamento de próximas etapas.
+* Planejamento e roteamento sensível a custo, latência e requisitos de qualidade.
+* O uso de "tokens universais" para comunicação agnóstica a modelos.
+
+### **Reconhecimento e Implicações (EM PORTUGUÊS):**
+
+Ao acessar ou utilizar este software e a arquitetura ADUC aqui implementada, você reconhece:
+
+1. A natureza inovadora e a importância da arquitetura ADUC no campo da orquestração de prompts para IA.
+2. Que a essência desta arquitetura, ou suas implementações derivadas, podem estar sujeitas a direitos de propriedade intelectual, incluindo patentes.
+3. Que o uso comercial, a reprodução da lógica central da ADUC em sistemas independentes, ou a exploração direta da invenção sem o devido licenciamento podem infringir os direitos de patente pendente.
+
+---
+
+### **Patent Pending (IN ENGLISH):**
+
+The method and system for prompt orchestration named **ADUC (Automated Discovery and Orchestration of Complex tasks)**, as described herein and implemented in this software, are currently in the process of being patented.
+
+The rights holder, Carlos Rodrigues dos Santos, is seeking legal protection for the key innovations of the ADUC architecture, including, but not limited to:
+
+* Fragmentation and scaling of requests exceeding AI model context limits.
+* Intelligent distribution of sub-tasks to heterogeneous specialists.
+* Persistent state management with iterative evaluation and feedback for planning subsequent steps.
+* Cost, latency, and quality-aware planning and routing.
+* The use of "universal tokens" for model-agnostic communication.
+
+### **Acknowledgement and Implications (IN ENGLISH):**
+
+By accessing or using this software and the ADUC architecture implemented herein, you acknowledge:
+
+1. The innovative nature and significance of the ADUC architecture in the field of AI prompt orchestration.
+2. That the essence of this architecture, or its derivative implementations, may be subject to intellectual property rights, including patents.
+3. That commercial use, reproduction of ADUC's core logic in independent systems, or direct exploitation of the invention without proper licensing may infringe upon pending patent rights.
+
+---
+
+## Licença AGPLv3
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program. If not, see .
+
+---
+
+**Contato para Consultas:**
+
+Para mais informações sobre a arquitetura ADUC, o status do patenteamento, ou para discutir licenciamento para usos comerciais ou não conformes com a AGPLv3, por favor, entre em contato:
+
+Carlos Rodrigues dos Santos
+carlex22@gmail.com
+Rua Eduardo Carlos Pereira, 4125, B1 Ap32, Curitiba, PR, Brazil, CEP 8102025
\ No newline at end of file
diff --git a/README.md b/README.md
index 61fec11f1a5604303ecc6eedac937158ff668e52..cb7a40e6d576a8725e104386f0b8247fc298b7a6 100644
--- a/README.md
+++ b/README.md
@@ -1,10 +1,212 @@
---
-title: Aduc-sdr-2 5
-emoji: 💻
-colorFrom: yellow
+title: Euia-AducSdr
+emoji: 🎥
+colorFrom: indigo
colorTo: purple
-sdk: docker
-pinned: false
+sdk: gradio
+app_file: app.py
+pinned: true
+license: agpl-3.0
+setup_file: setup.sh
+short_description: Uma implementação aberta e funcional da arquitetura ADUC-SDR
---
-Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
+
+### 🇧🇷 Português
+
+Uma implementação aberta e funcional da arquitetura ADUC-SDR (Arquitetura de Unificação Compositiva - Escala Dinâmica e Resiliente), projetada para a geração de vídeo coerente de longa duração. Este projeto materializa os princípios de fragmentação, navegação geométrica e um mecanismo de "eco causal 4bits memoria" para garantir a continuidade física e narrativa em sequências de vídeo geradas por múltiplos modelos de IA.
+
+**Licença:** Este projeto é licenciado sob os termos da **GNU Affero General Public License v3.0**. Isto significa que se você usar este software (ou qualquer trabalho derivado) para fornecer um serviço através de uma rede, você é **obrigado a disponibilizar o código-fonte completo** da sua versão para os usuários desse serviço.
+
+- **Copyright (C) 4 de Agosto de 2025, Carlos Rodrigues dos Santos**
+- Uma cópia completa da licença pode ser encontrada no arquivo [LICENSE](LICENSE).
+
+---
+
+### 🇬🇧 English
+
+An open and functional implementation of the ADUC-SDR (Architecture for Compositive Unification - Dynamic and Resilient Scaling) architecture, designed for long-form coherent video generation. This project materializes the principles of fragmentation, geometric navigation, and a "causal echo 4bits memori" mechanism to ensure physical and narrative continuity in video sequences generated by multiple AI models.
+
+**License:** This project is licensed under the terms of the **GNU Affero General Public License v3.0**. This means that if you use this software (or any derivative work) to provide a service over a network, you are **required to make the complete source code** of your version available to the users of that service.
+
+- **Copyright (C) August 4, 2025, Carlos Rodrigues dos Santos**
+- A full copy of the license can be found in the [LICENSE](LICENSE) file.
+
+---
+
+## **Aviso de Propriedade Intelectual e Patenteamento**
+
+### **Processo de Patenteamento em Andamento (EM PORTUGUÊS):**
+
+A arquitetura e o método **ADUC (Automated Discovery and Orchestration of Complex tasks)**, conforme descritos neste projeto e nas reivindicações associadas, estão **atualmente em processo de patenteamento**.
+
+O titular dos direitos, Carlos Rodrigues dos Santos, está buscando proteção legal para as inovações chave da arquitetura ADUC, que incluem, mas não se limitam a:
+
+* Fragmentação e escalonamento de solicitações que excedem limites de contexto de modelos de IA.
+* Distribuição inteligente de sub-tarefas para especialistas heterogêneos.
+* Gerenciamento de estado persistido com avaliação iterativa e realimentação para o planejamento de próximas etapas.
+* Planejamento e roteamento sensível a custo, latência e requisitos de qualidade.
+* O uso de "tokens universais" para comunicação agnóstica a modelos.
+
+Ao utilizar este software e a arquitetura ADUC aqui implementada, você reconhece a natureza inovadora desta arquitetura e que a **reprodução ou exploração da lógica central da ADUC em sistemas independentes pode infringir direitos de patente pendente.**
+
+---
+
+### **Patent Pending (IN ENGLISH):**
+
+The **ADUC (Automated Discovery and Orchestration of Complex tasks)** architecture and method, as described in this project and its associated claims, are **currently in the process of being patented.**
+
+The rights holder, Carlos Rodrigues dos Santos, is seeking legal protection for the key innovations of the ADUC architecture, including, but not limited to:
+
+* Fragmentation and scaling of requests exceeding AI model context limits.
+* Intelligent distribution of sub-tasks to heterogeneous specialists.
+* Persistent state management with iterative evaluation and feedback for planning subsequent steps.
+* Cost, latency, and quality-aware planning and routing.
+* The use of "universal tokens" for model-agnostic communication.
+
+By using this software and the ADUC architecture implemented herein, you acknowledge the innovative nature of this architecture and that **the reproduction or exploitation of ADUC's core logic in independent systems may infringe upon pending patent rights.**
+
+---
+
+### Detalhes Técnicos e Reivindicações da ADUC
+
+#### 🇧🇷 Definição Curta (para Tese e Patente)
+
+**ADUC** é um *framework pré-input* e *intermediário* de **gerenciamento de prompts** que:
+
+1. **fragmenta** solicitações acima do limite de contexto de qualquer modelo,
+2. **escala linearmente** (processo sequencial com memória persistida),
+3. **distribui** sub-tarefas a **especialistas** (modelos/ferramentas heterogêneos), e
+4. **realimenta** a próxima etapa com avaliação do que foi feito/esperado (LLM diretor).
+
+Não é um modelo; é uma **camada orquestradora** plugável antes do input de modelos existentes (texto, imagem, áudio, vídeo), usando *tokens universais* e a tecnologia atual.
+
+#### 🇬🇧 Short Definition (for Thesis and Patent)
+
+**ADUC** is a *pre-input* and *intermediate* **prompt management framework** that:
+
+1. **fragments** requests exceeding any model's context limit,
+2. **scales linearly** (sequential process with persisted memory),
+3. **distributes** sub-tasks to **specialists** (heterogeneous models/tools), and
+4. **feeds back** to the next step with an evaluation of what was done/expected (director LLM).
+
+It is not a model; it is a pluggable **orchestration layer** before the input of existing models (text, image, audio, video), using *universal tokens* and current technology.
+
+---
+
+#### 🇧🇷 Elementos Essenciais (Telegráfico)
+
+* **Agnóstico a modelos:** opera com qualquer LLM/difusor/API.
+* **Pré-input manager:** recebe pedido do usuário, **divide** em blocos ≤ limite de tokens, **prioriza**, **agenda** e **roteia**.
+* **Memória persistida:** resultados/latentes/“eco” viram **estado compartilhado** para o próximo bloco (nada é ignorado).
+* **Especialistas:** *routers* decidem quem faz o quê (ex.: “descrição → LLM-A”, “keyframe → Img-B”, “vídeo → Vid-C”).
+* **Controle de qualidade:** LLM diretor compara *o que fez* × *o que deveria* × *o que falta* e **regenera objetivos** do próximo fragmento.
+* **Custo/latência-aware:** planeja pela **VRAM/tempo/custo**, não tenta “abraçar tudo de uma vez”.
+
+#### 🇬🇧 Essential Elements (Telegraphic)
+
+* **Model-agnostic:** operates with any LLM/diffuser/API.
+* **Pre-input manager:** receives user request, **divides** into blocks ≤ token limit, **prioritizes**, **schedules**, and **routes**.
+* **Persisted memory:** results/latents/“echo” become **shared state** for the next block (nothing is ignored).
+* **Specialists:** *routers* decide who does what (e.g., “description → LLM-A”, “keyframe → Img-B”, “video → Vid-C”).
+* **Quality control:** director LLM compares *what was done* × *what should be done* × *what is missing* and **regenerates objectives** for the next fragment.
+* **Cost/latency-aware:** plans by **VRAM/time/cost**, does not try to “embrace everything at once”.
+
+---
+
+#### 🇧🇷 Reivindicações Independentes (Método e Sistema)
+
+**Reivindicação Independente (Método) — Versão Enxuta:**
+
+1. **Método** de **orquestração de prompts** para execução de tarefas acima do limite de contexto de modelos de IA, compreendendo:
+ (a) **receber** uma solicitação que excede um limite de tokens;
+ (b) **analisar** a solicitação por um **LLM diretor** e **fragmentá-la** em sub-tarefas ≤ limite;
+ (c) **selecionar** especialistas de execução para cada sub-tarefa com base em capacidades declaradas;
+ (d) **gerar** prompts específicos por sub-tarefa em **tokens universais**, incluindo referências ao **estado persistido** de execuções anteriores;
+ (e) **executar sequencialmente** as sub-tarefas e **persistir** suas saídas como memória (incluindo latentes/eco/artefatos);
+ (f) **avaliar** automaticamente a saída versus metas declaradas e **regenerar objetivos** do próximo fragmento;
+ (g) **iterar** (b)–(f) até que os critérios de completude sejam atendidos, produzindo o resultado agregado;
+ em que o framework **escala linearmente** no tempo e armazenamento físico, **independente** da janela de contexto dos modelos subjacentes.
+
+**Reivindicação Independente (Sistema):**
+
+2. **Sistema** de orquestração de prompts, compreendendo: um **planejador LLM diretor**; um **roteador de especialistas**; um **banco de estado persistido** (incl. memória cinética para vídeo); um **gerador de prompts universais**; e um **módulo de avaliação/realimentação**, acoplados por uma **API pré-input** a modelos heterogêneos.
+
+#### 🇬🇧 Independent Claims (Method and System)
+
+**Independent Claim (Method) — Concise Version:**
+
+1. A **method** for **prompt orchestration** for executing tasks exceeding AI model context limits, comprising:
+ (a) **receiving** a request that exceeds a token limit;
+ (b) **analyzing** the request by a **director LLM** and **fragmenting it** into sub-tasks ≤ the limit;
+ (c) **selecting** execution specialists for each sub-task based on declared capabilities;
+ (d) **generating** specific prompts per sub-task in **universal tokens**, including references to the **persisted state** of previous executions;
+ (e) **sequentially executing** the sub-tasks and **persisting** their outputs as memory (including latents/echo/artifacts);
+ (f) **automatically evaluating** the output against declared goals and **regenerating objectives** for the next fragment;
+ (g) **iterating** (b)–(f) until completion criteria are met, producing the aggregated result;
+ wherein the framework **scales linearly** in time and physical storage, **independent** of the context window of the underlying models.
+
+**Independent Claim (System):**
+
+2. A prompt orchestration **system**, comprising: a **director LLM planner**; a **specialist router**; a **persisted state bank** (incl. kinetic memory for video); a **universal prompt generator**; and an **evaluation/feedback module**, coupled via a **pre-input API** to heterogeneous models.
+
+---
+
+#### 🇧🇷 Dependentes Úteis
+
+* (3) Onde o roteamento considera **custo/latência/VRAM** e metas de qualidade.
+* (4) Onde o banco de estado inclui **eco cinético** para vídeo (últimos *n* frames/latentes/fluxo).
+* (5) Onde a avaliação usa métricas específicas por domínio (Lflow, consistência semântica, etc.).
+* (6) Onde *tokens universais* padronizam instruções entre especialistas.
+* (7) Onde a orquestração decide **cut vs continuous** e **corte regenerativo** (Déjà-Vu) ao editar vídeo.
+* (8) Onde o sistema **nunca descarta** conteúdo excedente: **reagenda** em novos fragmentos.
+
+#### 🇬🇧 Useful Dependents
+
+* (3) Wherein routing considers **cost/latency/VRAM** and quality goals.
+* (4) Wherein the state bank includes **kinetic echo** for video (last *n* frames/latents/flow).
+* (5) Wherein evaluation uses domain-specific metrics (Lflow, semantic consistency, etc.).
+* (6) Wherein *universal tokens* standardize instructions between specialists.
+* (7) Wherein orchestration decides **cut vs continuous** and **regenerative cut** (Déjà-Vu) when editing video.
+* (8) Wherein the system **never discards** excess content: it **reschedules** it in new fragments.
+
+---
+
+#### 🇧🇷 Como isso conversa com SDR (Vídeo)
+
+* **Eco Cinético**: é um **tipo de estado persistido** consumido pelo próximo passo.
+* **Déjà-Vu (Corte Regenerativo)**: é **uma política de orquestração** aplicada quando há edição; ADUC decide, monta os prompts certos e chama o especialista de vídeo.
+* **Cut vs Continuous**: decisão do **diretor** com base em estado + metas; ADUC roteia e garante a sobreposição/remoção final.
+
+#### 🇬🇧 How this Converses with SDR (Video)
+
+* **Kinetic Echo**: is a **type of persisted state** consumed by the next step.
+* **Déjà-Vu (Regenerative Cut)**: is an **orchestration policy** applied during editing; ADUC decides, crafts the right prompts, and calls the video specialist.
+* **Cut vs Continuous**: decision made by the **director** based on state + goals; ADUC routes and ensures the final overlap/removal.
+
+---
+
+#### 🇧🇷 Mensagem Clara ao Usuário (Experiência)
+
+> “Seu pedido excede o limite X do modelo Y. Em vez de truncar silenciosamente, o **ADUC** dividirá e **entregará 100%** do conteúdo por etapas coordenadas.”
+
+Isso é diferencial prático e jurídico: **não-obviedade** por transformar limite de contexto em **pipeline controlado**, com **persistência de estado** e **avaliação iterativa**.
+
+#### 🇬🇧 Clear User Message (Experience)
+
+> "Your request exceeds model Y's limit X. Instead of silently truncating, **ADUC** will divide and **deliver 100%** of the content through coordinated steps."
+
+This is a practical and legal differentiator: **non-obviousness** by transforming context limits into a **controlled pipeline**, with **state persistence** and **iterative evaluation**.
+
+---
+
+### Contact / Contato / Contacto
+
+- **Author / Autor:** Carlos Rodrigues dos Santos
+- **Email:** carlex22@gmail.com
+- **GitHub:** [https://github.com/carlex22/Aduc-sdr](https://github.com/carlex22/Aduc-sdr)
+- **Hugging Face Spaces:**
+ - [Ltx-SuperTime-60Secondos](https://huggingface.co/spaces/Carlexx/Ltx-SuperTime-60Secondos/)
+ - [Novinho](https://huggingface.co/spaces/Carlexxx/Novinho/)
+
+---
\ No newline at end of file
diff --git a/aduc_framework/__init__.py b/aduc_framework/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..9aa87b8d89b7b20daa081692e839142324d87eda
--- /dev/null
+++ b/aduc_framework/__init__.py
@@ -0,0 +1,57 @@
+# aduc_framework/__init__.py
+#
+# Copyright (C) August 4, 2025 Carlos Rodrigues dos Santos
+#
+# Versão 6.2.0 (Alinhamento Final de API da Fábrica)
+# - Alinha a assinatura da função `create_aduc_instance` e a chamada ao
+# construtor do AducSdr para usar `workspace_root` consistentemente.
+# - Resolve o `TypeError` na inicialização da aplicação.
+
+import logging
+
+from .aduc_sdr import AducSdr
+from .types import (
+ GenerationState,
+ PreProductionParams,
+ ProductionParams,
+ GenerationParameters,
+ MediaRef,
+ Ato,
+ Scene,
+ KeyframeData,
+ VideoData
+)
+
+logger = logging.getLogger(__name__)
+
+# <<< CORREÇÃO APLICADA AQUI >>>
+def create_aduc_instance(workspace_root: str) -> AducSdr:
+ """
+ Ponto de entrada de fábrica para criar uma instância do Aduc Framework.
+
+ Args:
+ workspace_root (str): O diretório raiz onde todas as pastas de
+ projetos serão criadas.
+ """
+ logger.info(f"Fábrica ADUC: Criando instância de AducSdr com workspace_root em '{workspace_root}'...")
+ # Passa o argumento com o nome correto para o construtor do AducSdr
+ instance = AducSdr(workspace_root=workspace_root)
+ logger.info("Fábrica ADUC: Instância AducSdr criada e pronta para uso.")
+ return instance
+
+logger.info("Módulo 'aduc_framework' carregado. Use 'create_aduc_instance()' para começar.")
+
+# Define a API pública do pacote principal
+__all__ = [
+ "create_aduc_instance",
+ "AducSdr",
+ "GenerationState",
+ "PreProductionParams",
+ "ProductionParams",
+ "GenerationParameters",
+ "MediaRef",
+ "Ato",
+ "Scene",
+ "KeyframeData",
+ "VideoData",
+]
\ No newline at end of file
diff --git a/aduc_framework/aduc_sdr.py b/aduc_framework/aduc_sdr.py
new file mode 100644
index 0000000000000000000000000000000000000000..6fce1a59a4269d8e0c8e5509c9f93217fd6b1ac6
--- /dev/null
+++ b/aduc_framework/aduc_sdr.py
@@ -0,0 +1,137 @@
+# aduc_framework/aduc_sdr.py
+#
+# Versão 16.0.0 (Maestro de Produção Integrado)
+# - Implementa o método `task_produce_movie` para delegar a produção de vídeo
+# ao especialista `Planner5D`, ativando o pipeline de produção iterativo.
+# - Atua como a ponte final entre a interface do usuário (UI) e o complexo
+# fluxo de trabalho de geração de vídeo cena a cena.
+# - Utiliza o sistema de `yield from` para transmitir de forma eficiente as
+# atualizações de estado do `Planner5D` de volta para a UI.
+
+import logging
+import os
+from typing import Generator
+
+# Importa os especialistas de alto nível (Engenheiros)
+from .engineers.composer_2D import composer_2d_singleton as Composer2D
+from .engineers.planner_5D import planner_5d_singleton as Planner5D
+
+# Importa as estruturas de dados (o DNA Digital)
+from .types import GenerationState, PreProductionParams, ProductionParams, MediaRef
+from .director import AducDirector
+
+logger = logging.getLogger(__name__)
+
+class AducSdr:
+ """
+ O Maestro do framework ADUC-SDR. Orquestra os especialistas (Engineers)
+ e gerencia o fluxo de dados através do Diretor (estado persistente).
+ """
+ def __init__(self, workspace_root: str):
+ self.workspace_root = workspace_root
+ self.director: AducDirector | None = None
+ self.composer_2d = Composer2D
+ self.planner_5d = Planner5D
+ logger.info("ADUC-SDR Maestro (Arquitetura V2) inicializado e pronto.")
+
+ def load_project(self, project_name: str):
+ """Carrega um projeto existente ou cria um novo."""
+ project_path = os.path.join(self.workspace_root, project_name)
+ self.director = AducDirector(project_path=project_path)
+ logger.info(f"Projeto '{project_name}' carregado no Diretor.")
+
+ def _ensure_project_loaded(self):
+ """Garante que um projeto foi carregado antes de executar tarefas."""
+ if not self.director:
+ raise RuntimeError("Nenhum projeto foi carregado. Chame `aduc.load_project(project_name)` primeiro.")
+
+ def get_current_state(self) -> GenerationState:
+ """Retorna o estado completo e atual do projeto."""
+ self._ensure_project_loaded()
+ return self.director.get_full_state()
+
+ def process_image_for_story(self, image_path: str, filename: str) -> str:
+ """Processa uma imagem de referência para um formato padrão."""
+ self._ensure_project_loaded()
+ from PIL import Image
+ size = 480; quality = 40
+ img = Image.open(image_path).convert("RGB"); img.thumbnail((size, size), Image.Resampling.LANCZOS)
+ background = Image.new('RGB', (size, size), (0, 0, 0)); img_w, img_h = img.size; offset = ((size - img_w) // 2, (size - img_h) // 2)
+ background.paste(img, offset)
+ processed_path = os.path.join(self.director.project_path, filename)
+ background.save(processed_path, 'JPEG', quality=quality)
+ return processed_path
+
+ def _process_and_yield_updates(self, generator: Generator[GenerationState, None, None]):
+ """
+ Loop genérico para processar atualizações de um especialista, salvar o estado
+ e repassar para a UI.
+ """
+ for updated_dna in generator:
+ self.director.load_state_from_dict(updated_dna.model_dump())
+
+ if self.director.state.should_checkpoint():
+ checkpoint_dir = os.path.join(self.director.project_path, "checkpoints")
+ path = self.director.state.create_checkpoint(checkpoint_dir)
+ logger.info(f"Checkpoint do projeto salvo em: {path}")
+
+ self.director.save_state()
+ yield self.director.get_full_state()
+
+ def task_run_story_and_keyframes(self, params: PreProductionParams) -> Generator[GenerationState, None, None]:
+ """
+ Orquestra a pré-produção (Fase 1), delegando ao Composer2D para criar o storyboard.
+ """
+ self._ensure_project_loaded()
+ logger.info("Maestro: Iniciando Pré-Produção (Storyboard) com o Composer2D...")
+
+ initial_state = self.director.get_full_state()
+ initial_state.parametros_geracao.pre_producao = params
+ initial_state.midias_referencia = [
+ MediaRef(id=i, tag=f"
", caminho=path)
+ for i, path in enumerate(params.ref_paths)
+ ]
+
+ initial_state.texto_global_historia = None
+ initial_state.ativos_catalogados = None
+ initial_state.storyboard_producao = []
+ initial_state.chat_history.append({
+ "role": "Sistema",
+ "content": f"Iniciando pré-produção. {len(params.ref_paths)} imagens de referência foram tageadas para uso pela IA."
+ })
+
+ pre_production_generator = self.composer_2d.compose_storyboard(initial_state)
+
+ yield from self._process_and_yield_updates(pre_production_generator)
+ logger.info("Maestro: Pré-Produção (Fase 1) concluída.")
+
+ def task_produce_movie(self, params: ProductionParams) -> Generator[GenerationState, None, None]:
+ """
+ Orquestra a produção completa do filme (Fase 2), delegando ao Planner5D.
+ """
+ self._ensure_project_loaded()
+ logger.info("Maestro: Iniciando Produção de Vídeo com o Planner5D...")
+
+ # 1. Obter o estado atual, que já contém o storyboard da pré-produção.
+ current_state = self.director.get_full_state()
+
+ # 2. Atualizar o estado com os novos parâmetros de produção vindos da UI.
+ if current_state.parametros_geracao:
+ current_state.parametros_geracao.producao = params
+
+ current_state.chat_history.append({
+ "role": "Sistema",
+ "content": f"Parâmetros de produção recebidos. O Diretor de Produção (Planner5D) está assumindo o controle."
+ })
+
+ # Salva os parâmetros no dna.json antes de iniciar o processo longo.
+ self.director.save_state()
+
+ # 3. Chamar o especialista Planner5D com o estado atualizado.
+ # Ele agora irá controlar o loop de Deformes3D e Deformes4D.
+ production_generator = self.planner_5d.produce_movie_by_scene(current_state)
+
+ # 4. Processar as atualizações, salvar o estado e repassar para a UI em tempo real.
+ yield from self._process_and_yield_updates(production_generator)
+
+ logger.info("Maestro: Produção de vídeo (Fase 2) concluída.")
\ No newline at end of file
diff --git a/aduc_framework/director.py b/aduc_framework/director.py
new file mode 100644
index 0000000000000000000000000000000000000000..194b50a48ecc3f97a153c43ce3265eaffde9780f
--- /dev/null
+++ b/aduc_framework/director.py
@@ -0,0 +1,98 @@
+# aduc_framework/director.py
+#
+# Copyright (C) August 4, 2025 Carlos Rodrigues dos Santos
+#
+# Versão 4.0.0 (Gerenciamento de Estado Persistente)
+#
+# - O Diretor agora gerencia um arquivo `dna.json` dentro de um diretório de projeto.
+# - No `__init__`, ele tenta carregar um estado existente do arquivo ou cria um novo.
+# - O método `save_state()` permite que o Maestro ADUC comande a persistência
+# do estado atual em disco em marcos importantes do processo.
+
+import logging
+import os
+import json
+from pathlib import Path
+from typing import List, Dict, Any
+
+from .types import GenerationState, PreProductionParams, Scene, Ato, MediaRef
+
+logger = logging.getLogger(__name__)
+
+class AducDirector:
+ """
+ Representa o Diretor de Cena, responsável por gerenciar o estado
+ persistente de um único projeto (`dna.json`).
+ """
+ def __init__(self, project_path: str):
+ self.project_path = Path(project_path)
+ self.dna_file_path = self.project_path / "dna.json"
+
+ self.project_path.mkdir(parents=True, exist_ok=True)
+
+ self.state: GenerationState = self._load_or_initialize_state()
+ logger.info(f"AducDirector inicializado para o projeto em '{self.project_path}'.")
+
+ def _load_or_initialize_state(self) -> GenerationState:
+ """Carrega o estado do dna.json ou cria um novo se não existir."""
+ if self.dna_file_path.exists():
+ try:
+ logger.info(f"Encontrado dna.json existente. Carregando estado...")
+ with open(self.dna_file_path, 'r', encoding='utf-8') as f:
+ state_dict = json.load(f)
+ return GenerationState(**state_dict)
+ except (json.JSONDecodeError, TypeError) as e:
+ logger.error(f"Falha ao carregar ou validar dna.json: {e}. Criando um novo estado.")
+ return GenerationState(workspace_dir=str(self.project_path))
+ else:
+ logger.info("Nenhum dna.json encontrado. Criando novo estado de geração.")
+ return GenerationState(workspace_dir=str(self.project_path))
+
+ def save_state(self):
+ """Salva o estado atual (self.state) no arquivo dna.json."""
+ logger.info(f"Persistindo estado atual para '{self.dna_file_path}'...")
+ with open(self.dna_file_path, 'w', encoding='utf-8') as f:
+ f.write(self.state.model_dump_json(indent=2))
+ logger.info("Estado salvo com sucesso.")
+
+ def get_full_state(self) -> GenerationState:
+ """Retorna o objeto de estado Pydantic completo."""
+ return self.state
+
+ def load_state_from_dict(self, state_dict: Dict[str, Any]):
+ """Carrega o estado a partir de um dicionário (ex: vindo de um planner)."""
+ try:
+ self.state = GenerationState(**state_dict)
+ logger.info("Diretor: Estado em memória atualizado com sucesso a partir de um dicionário.")
+ except Exception as e:
+ logger.error(f"Diretor: Falha ao carregar estado a partir do dicionário: {e}", exc_info=True)
+
+ def update_parameters(self, stage: str, params: Any):
+ """Atualiza o nó de parâmetros no estado de geração."""
+ if hasattr(self.state.parametros_geracao, stage):
+ setattr(self.state.parametros_geracao, stage, params)
+ else:
+ logger.warning(f"Tentativa de atualizar parâmetros para um estágio desconhecido: '{stage}'")
+
+ def update_state_from_pre_production_dna(self, params: PreProductionParams, final_dna_json: Dict[str, Any]):
+ """Analisa o dicionário bruto do Composer e o usa para popular o estado."""
+ logger.info("Diretor: Recebendo DNA da pré-produção para popular o estado.")
+
+ self.state.parametros_geracao.pre_producao = params
+ self.state.prompt_geral = final_dna_json.get("global_prompt", "")
+
+ ref_paths = final_dna_json.get("initial_media_paths", [])
+ self.state.midias_referencia = [MediaRef(id=i, caminho=path) for i, path in enumerate(ref_paths)]
+
+ self.state.scenes = []
+ scenes_data = final_dna_json.get("scenes", [])
+
+ for scene_dict in scenes_data:
+ ato_objects = [
+ Ato(id=ato_dict.get("act_id", i), resumo_ato=ato_dict.get("context", ""))
+ for i, ato_dict in enumerate(scene_dict.get("acts", []))
+ ]
+ scene_object = Scene(id=scene_dict.get("scene_id"), atos=ato_objects)
+ self.state.scenes.append(scene_object)
+
+ logger.info(f"Diretor: Estado populado com sucesso. {len(self.state.scenes)} cenas carregadas.")
\ No newline at end of file
diff --git a/aduc_framework/engineers/LICENSE b/aduc_framework/engineers/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..ef0b6f59fdbb65161c17342760e6a1afa67b94a6
--- /dev/null
+++ b/aduc_framework/engineers/LICENSE
@@ -0,0 +1,23 @@
+# AducSdr: Uma implementação aberta e funcional da arquitetura ADUC-SDR para geração de vídeo coerente.
+# Copyright (C) 4 de Agosto de 2025 Carlos Rodrigues dos Santos
+#
+# Contato:
+# Carlos Rodrigues dos Santos
+# carlex22@gmail.com
+# Rua Eduardo Carlos Pereira, 4125, B1 Ap32, Curitiba, PR, Brazil, CEP 8102025
+#
+# Repositórios e Projetos Relacionados:
+# GitHub: https://github.com/carlex22/Aduc-sdr
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
\ No newline at end of file
diff --git a/aduc_framework/engineers/NOTICE.md b/aduc_framework/engineers/NOTICE.md
new file mode 100644
index 0000000000000000000000000000000000000000..e6dad38733a306f61263d083c471e6bac403e222
--- /dev/null
+++ b/aduc_framework/engineers/NOTICE.md
@@ -0,0 +1,76 @@
+# NOTICE
+
+Copyright (C) 2025 Carlos Rodrigues dos Santos. All rights reserved.
+
+---
+
+## Aviso de Propriedade Intelectual e Licenciamento
+
+### **Processo de Patenteamento em Andamento (EM PORTUGUÊS):**
+
+O método e o sistema de orquestração de prompts denominados **ADUC (Automated Discovery and Orchestration of Complex tasks)**, conforme descritos neste documento e implementados neste software, estão atualmente em processo de patenteamento.
+
+O titular dos direitos, Carlos Rodrigues dos Santos, está buscando proteção legal para as inovações chave da arquitetura ADUC, incluindo, mas não se limitando a:
+
+* Fragmentação e escalonamento de solicitações que excedem limites de contexto de modelos de IA.
+* Distribuição inteligente de sub-tarefas para especialistas heterogêneos.
+* Gerenciamento de estado persistido com avaliação iterativa e realimentação para o planejamento de próximas etapas.
+* Planejamento e roteamento sensível a custo, latência e requisitos de qualidade.
+* O uso de "tokens universais" para comunicação agnóstica a modelos.
+
+### **Reconhecimento e Implicações (EM PORTUGUÊS):**
+
+Ao acessar ou utilizar este software e a arquitetura ADUC aqui implementada, você reconhece:
+
+1. A natureza inovadora e a importância da arquitetura ADUC no campo da orquestração de prompts para IA.
+2. Que a essência desta arquitetura, ou suas implementações derivadas, podem estar sujeitas a direitos de propriedade intelectual, incluindo patentes.
+3. Que o uso comercial, a reprodução da lógica central da ADUC em sistemas independentes, ou a exploração direta da invenção sem o devido licenciamento podem infringir os direitos de patente pendente.
+
+---
+
+### **Patent Pending (IN ENGLISH):**
+
+The method and system for prompt orchestration named **ADUC (Automated Discovery and Orchestration of Complex tasks)**, as described herein and implemented in this software, are currently in the process of being patented.
+
+The rights holder, Carlos Rodrigues dos Santos, is seeking legal protection for the key innovations of the ADUC architecture, including, but not limited to:
+
+* Fragmentation and scaling of requests exceeding AI model context limits.
+* Intelligent distribution of sub-tasks to heterogeneous specialists.
+* Persistent state management with iterative evaluation and feedback for planning subsequent steps.
+* Cost, latency, and quality-aware planning and routing.
+* The use of "universal tokens" for model-agnostic communication.
+
+### **Acknowledgement and Implications (IN ENGLISH):**
+
+By accessing or using this software and the ADUC architecture implemented herein, you acknowledge:
+
+1. The innovative nature and significance of the ADUC architecture in the field of AI prompt orchestration.
+2. That the essence of this architecture, or its derivative implementations, may be subject to intellectual property rights, including patents.
+3. That commercial use, reproduction of ADUC's core logic in independent systems, or direct exploitation of the invention without proper licensing may infringe upon pending patent rights.
+
+---
+
+## Licença AGPLv3
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program. If not, see .
+
+---
+
+**Contato para Consultas:**
+
+Para mais informações sobre a arquitetura ADUC, o status do patenteamento, ou para discutir licenciamento para usos comerciais ou não conformes com a AGPLv3, por favor, entre em contato:
+
+Carlos Rodrigues dos Santos
+carlex22@gmail.com
+Rua Eduardo Carlos Pereira, 4125, B1 Ap32, Curitiba, PR, Brazil, CEP 8102025
\ No newline at end of file
diff --git a/aduc_framework/engineers/README.md b/aduc_framework/engineers/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..9cf56fe2707241f77fe3aedabdaa07d319218b17
--- /dev/null
+++ b/aduc_framework/engineers/README.md
@@ -0,0 +1,211 @@
+---
+title: Euia-AducSdr
+emoji: 🎥
+colorFrom: indigo
+colorTo: purple
+sdk: gradio
+app_file: app.py
+pinned: true
+license: agpl-3.0
+short_description: Uma implementação aberta e funcional da arquitetura ADUC-SDR
+---
+
+
+### 🇧🇷 Português
+
+Uma implementação aberta e funcional da arquitetura ADUC-SDR (Arquitetura de Unificação Compositiva - Escala Dinâmica e Resiliente), projetada para a geração de vídeo coerente de longa duração. Este projeto materializa os princípios de fragmentação, navegação geométrica e um mecanismo de "eco causal 4bits memoria" para garantir a continuidade física e narrativa em sequências de vídeo geradas por múltiplos modelos de IA.
+
+**Licença:** Este projeto é licenciado sob os termos da **GNU Affero General Public License v3.0**. Isto significa que se você usar este software (ou qualquer trabalho derivado) para fornecer um serviço através de uma rede, você é **obrigado a disponibilizar o código-fonte completo** da sua versão para os usuários desse serviço.
+
+- **Copyright (C) 4 de Agosto de 2025, Carlos Rodrigues dos Santos**
+- Uma cópia completa da licença pode ser encontrada no arquivo [LICENSE](LICENSE).
+
+---
+
+### 🇬🇧 English
+
+An open and functional implementation of the ADUC-SDR (Architecture for Compositive Unification - Dynamic and Resilient Scaling) architecture, designed for long-form coherent video generation. This project materializes the principles of fragmentation, geometric navigation, and a "causal echo 4bits memori" mechanism to ensure physical and narrative continuity in video sequences generated by multiple AI models.
+
+**License:** This project is licensed under the terms of the **GNU Affero General Public License v3.0**. This means that if you use this software (or any derivative work) to provide a service over a network, you are **required to make the complete source code** of your version available to the users of that service.
+
+- **Copyright (C) August 4, 2025, Carlos Rodrigues dos Santos**
+- A full copy of the license can be found in the [LICENSE](LICENSE) file.
+
+---
+
+## **Aviso de Propriedade Intelectual e Patenteamento**
+
+### **Processo de Patenteamento em Andamento (EM PORTUGUÊS):**
+
+A arquitetura e o método **ADUC (Automated Discovery and Orchestration of Complex tasks)**, conforme descritos neste projeto e nas reivindicações associadas, estão **atualmente em processo de patenteamento**.
+
+O titular dos direitos, Carlos Rodrigues dos Santos, está buscando proteção legal para as inovações chave da arquitetura ADUC, que incluem, mas não se limitam a:
+
+* Fragmentação e escalonamento de solicitações que excedem limites de contexto de modelos de IA.
+* Distribuição inteligente de sub-tarefas para especialistas heterogêneos.
+* Gerenciamento de estado persistido com avaliação iterativa e realimentação para o planejamento de próximas etapas.
+* Planejamento e roteamento sensível a custo, latência e requisitos de qualidade.
+* O uso de "tokens universais" para comunicação agnóstica a modelos.
+
+Ao utilizar este software e a arquitetura ADUC aqui implementada, você reconhece a natureza inovadora desta arquitetura e que a **reprodução ou exploração da lógica central da ADUC em sistemas independentes pode infringir direitos de patente pendente.**
+
+---
+
+### **Patent Pending (IN ENGLISH):**
+
+The **ADUC (Automated Discovery and Orchestration of Complex tasks)** architecture and method, as described in this project and its associated claims, are **currently in the process of being patented.**
+
+The rights holder, Carlos Rodrigues dos Santos, is seeking legal protection for the key innovations of the ADUC architecture, including, but not limited to:
+
+* Fragmentation and scaling of requests exceeding AI model context limits.
+* Intelligent distribution of sub-tasks to heterogeneous specialists.
+* Persistent state management with iterative evaluation and feedback for planning subsequent steps.
+* Cost, latency, and quality-aware planning and routing.
+* The use of "universal tokens" for model-agnostic communication.
+
+By using this software and the ADUC architecture implemented herein, you acknowledge the innovative nature of this architecture and that **the reproduction or exploitation of ADUC's core logic in independent systems may infringe upon pending patent rights.**
+
+---
+
+### Detalhes Técnicos e Reivindicações da ADUC
+
+#### 🇧🇷 Definição Curta (para Tese e Patente)
+
+**ADUC** é um *framework pré-input* e *intermediário* de **gerenciamento de prompts** que:
+
+1. **fragmenta** solicitações acima do limite de contexto de qualquer modelo,
+2. **escala linearmente** (processo sequencial com memória persistida),
+3. **distribui** sub-tarefas a **especialistas** (modelos/ferramentas heterogêneos), e
+4. **realimenta** a próxima etapa com avaliação do que foi feito/esperado (LLM diretor).
+
+Não é um modelo; é uma **camada orquestradora** plugável antes do input de modelos existentes (texto, imagem, áudio, vídeo), usando *tokens universais* e a tecnologia atual.
+
+#### 🇬🇧 Short Definition (for Thesis and Patent)
+
+**ADUC** is a *pre-input* and *intermediate* **prompt management framework** that:
+
+1. **fragments** requests exceeding any model's context limit,
+2. **scales linearly** (sequential process with persisted memory),
+3. **distributes** sub-tasks to **specialists** (heterogeneous models/tools), and
+4. **feeds back** to the next step with an evaluation of what was done/expected (director LLM).
+
+It is not a model; it is a pluggable **orchestration layer** before the input of existing models (text, image, audio, video), using *universal tokens* and current technology.
+
+---
+
+#### 🇧🇷 Elementos Essenciais (Telegráfico)
+
+* **Agnóstico a modelos:** opera com qualquer LLM/difusor/API.
+* **Pré-input manager:** recebe pedido do usuário, **divide** em blocos ≤ limite de tokens, **prioriza**, **agenda** e **roteia**.
+* **Memória persistida:** resultados/latentes/“eco” viram **estado compartilhado** para o próximo bloco (nada é ignorado).
+* **Especialistas:** *routers* decidem quem faz o quê (ex.: “descrição → LLM-A”, “keyframe → Img-B”, “vídeo → Vid-C”).
+* **Controle de qualidade:** LLM diretor compara *o que fez* × *o que deveria* × *o que falta* e **regenera objetivos** do próximo fragmento.
+* **Custo/latência-aware:** planeja pela **VRAM/tempo/custo**, não tenta “abraçar tudo de uma vez”.
+
+#### 🇬🇧 Essential Elements (Telegraphic)
+
+* **Model-agnostic:** operates with any LLM/diffuser/API.
+* **Pre-input manager:** receives user request, **divides** into blocks ≤ token limit, **prioritizes**, **schedules**, and **routes**.
+* **Persisted memory:** results/latents/“echo” become **shared state** for the next block (nothing is ignored).
+* **Specialists:** *routers* decide who does what (e.g., “description → LLM-A”, “keyframe → Img-B”, “video → Vid-C”).
+* **Quality control:** director LLM compares *what was done* × *what should be done* × *what is missing* and **regenerates objectives** for the next fragment.
+* **Cost/latency-aware:** plans by **VRAM/time/cost**, does not try to “embrace everything at once”.
+
+---
+
+#### 🇧🇷 Reivindicações Independentes (Método e Sistema)
+
+**Reivindicação Independente (Método) — Versão Enxuta:**
+
+1. **Método** de **orquestração de prompts** para execução de tarefas acima do limite de contexto de modelos de IA, compreendendo:
+ (a) **receber** uma solicitação que excede um limite de tokens;
+ (b) **analisar** a solicitação por um **LLM diretor** e **fragmentá-la** em sub-tarefas ≤ limite;
+ (c) **selecionar** especialistas de execução para cada sub-tarefa com base em capacidades declaradas;
+ (d) **gerar** prompts específicos por sub-tarefa em **tokens universais**, incluindo referências ao **estado persistido** de execuções anteriores;
+ (e) **executar sequencialmente** as sub-tarefas e **persistir** suas saídas como memória (incluindo latentes/eco/artefatos);
+ (f) **avaliar** automaticamente a saída versus metas declaradas e **regenerar objetivos** do próximo fragmento;
+ (g) **iterar** (b)–(f) até que os critérios de completude sejam atendidos, produzindo o resultado agregado;
+ em que o framework **escala linearmente** no tempo e armazenamento físico, **independente** da janela de contexto dos modelos subjacentes.
+
+**Reivindicação Independente (Sistema):**
+
+2. **Sistema** de orquestração de prompts, compreendendo: um **planejador LLM diretor**; um **roteador de especialistas**; um **banco de estado persistido** (incl. memória cinética para vídeo); um **gerador de prompts universais**; e um **módulo de avaliação/realimentação**, acoplados por uma **API pré-input** a modelos heterogêneos.
+
+#### 🇬🇧 Independent Claims (Method and System)
+
+**Independent Claim (Method) — Concise Version:**
+
+1. A **method** for **prompt orchestration** for executing tasks exceeding AI model context limits, comprising:
+ (a) **receiving** a request that exceeds a token limit;
+ (b) **analyzing** the request by a **director LLM** and **fragmenting it** into sub-tasks ≤ the limit;
+ (c) **selecting** execution specialists for each sub-task based on declared capabilities;
+ (d) **generating** specific prompts per sub-task in **universal tokens**, including references to the **persisted state** of previous executions;
+ (e) **sequentially executing** the sub-tasks and **persisting** their outputs as memory (including latents/echo/artifacts);
+ (f) **automatically evaluating** the output against declared goals and **regenerating objectives** for the next fragment;
+ (g) **iterating** (b)–(f) until completion criteria are met, producing the aggregated result;
+ wherein the framework **scales linearly** in time and physical storage, **independent** of the context window of the underlying models.
+
+**Independent Claim (System):**
+
+2. A prompt orchestration **system**, comprising: a **director LLM planner**; a **specialist router**; a **persisted state bank** (incl. kinetic memory for video); a **universal prompt generator**; and an **evaluation/feedback module**, coupled via a **pre-input API** to heterogeneous models.
+
+---
+
+#### 🇧🇷 Dependentes Úteis
+
+* (3) Onde o roteamento considera **custo/latência/VRAM** e metas de qualidade.
+* (4) Onde o banco de estado inclui **eco cinético** para vídeo (últimos *n* frames/latentes/fluxo).
+* (5) Onde a avaliação usa métricas específicas por domínio (Lflow, consistência semântica, etc.).
+* (6) Onde *tokens universais* padronizam instruções entre especialistas.
+* (7) Onde a orquestração decide **cut vs continuous** e **corte regenerativo** (Déjà-Vu) ao editar vídeo.
+* (8) Onde o sistema **nunca descarta** conteúdo excedente: **reagenda** em novos fragmentos.
+
+#### 🇬🇧 Useful Dependents
+
+* (3) Wherein routing considers **cost/latency/VRAM** and quality goals.
+* (4) Wherein the state bank includes **kinetic echo** for video (last *n* frames/latents/flow).
+* (5) Wherein evaluation uses domain-specific metrics (Lflow, semantic consistency, etc.).
+* (6) Wherein *universal tokens* standardize instructions between specialists.
+* (7) Wherein orchestration decides **cut vs continuous** and **regenerative cut** (Déjà-Vu) when editing video.
+* (8) Wherein the system **never discards** excess content: it **reschedules** it in new fragments.
+
+---
+
+#### 🇧🇷 Como isso conversa com SDR (Vídeo)
+
+* **Eco Cinético**: é um **tipo de estado persistido** consumido pelo próximo passo.
+* **Déjà-Vu (Corte Regenerativo)**: é **uma política de orquestração** aplicada quando há edição; ADUC decide, monta os prompts certos e chama o especialista de vídeo.
+* **Cut vs Continuous**: decisão do **diretor** com base em estado + metas; ADUC roteia e garante a sobreposição/remoção final.
+
+#### 🇬🇧 How this Converses with SDR (Video)
+
+* **Kinetic Echo**: is a **type of persisted state** consumed by the next step.
+* **Déjà-Vu (Regenerative Cut)**: is an **orchestration policy** applied during editing; ADUC decides, crafts the right prompts, and calls the video specialist.
+* **Cut vs Continuous**: decision made by the **director** based on state + goals; ADUC routes and ensures the final overlap/removal.
+
+---
+
+#### 🇧🇷 Mensagem Clara ao Usuário (Experiência)
+
+> “Seu pedido excede o limite X do modelo Y. Em vez de truncar silenciosamente, o **ADUC** dividirá e **entregará 100%** do conteúdo por etapas coordenadas.”
+
+Isso é diferencial prático e jurídico: **não-obviedade** por transformar limite de contexto em **pipeline controlado**, com **persistência de estado** e **avaliação iterativa**.
+
+#### 🇬🇧 Clear User Message (Experience)
+
+> "Your request exceeds model Y's limit X. Instead of silently truncating, **ADUC** will divide and **deliver 100%** of the content through coordinated steps."
+
+This is a practical and legal differentiator: **non-obviousness** by transforming context limits into a **controlled pipeline**, with **state persistence** and **iterative evaluation**.
+
+---
+
+### Contact / Contato / Contacto
+
+- **Author / Autor:** Carlos Rodrigues dos Santos
+- **Email:** carlex22@gmail.com
+- **GitHub:** [https://github.com/carlex22/Aduc-sdr](https://github.com/carlex22/Aduc-sdr)
+- **Hugging Face Spaces:**
+ - [Ltx-SuperTime-60Secondos](https://huggingface.co/spaces/Carlexx/Ltx-SuperTime-60Secondos/)
+ - [Novinho](https://huggingface.co/spaces/Carlexxx/Novinho/)
+
+---
\ No newline at end of file
diff --git a/aduc_framework/engineers/__init__.py b/aduc_framework/engineers/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..84c95f79be8cc29be40647369e7f94d38bac6c85
--- /dev/null
+++ b/aduc_framework/engineers/__init__.py
@@ -0,0 +1,35 @@
+# aduc_framework/engineers/__init__.py
+#
+# Copyright (C) August 4, 2025 Carlos Rodrigues dos Santos
+#
+# Expõe os singletons de todos os engenheiros (Planners e Deformes)
+# para que o orquestrador e outros componentes possam importá-los
+# a partir de um único local.
+
+# Importa os Planners (Gerentes)
+
+from .planner_3d import planner_3d_singleton
+from .planner_4d import planner_4d_singleton
+from .planner_5D import planner_5d_singleton
+
+# Importa o Composer (Motor de Execução de LLM)
+from .composer import composer_singleton
+from .composer_2D import composer_2d_singleton
+from .neura_link import neura_link_singleton
+
+# Importa os Motores de Geração (Trabalhadores Especialistas)
+from .deformes3D import deformes3d_engine_singleton
+from .deformes4D import deformes4d_engine_singleton
+
+
+# Define a lista de componentes que são parte da "API pública" deste sub-pacote
+__all__ = [
+ "planner_5d_singleton",
+ "neura_link_singleton",
+ "composer_2d_singleton",
+ "planner_3d_singleton",
+ "planner_4d_singleton",
+ "composer_singleton",
+ "deformes3d_engine_singleton",
+ "Deformes4DEngine",
+]
\ No newline at end of file
diff --git a/aduc_framework/engineers/composer.py b/aduc_framework/engineers/composer.py
new file mode 100644
index 0000000000000000000000000000000000000000..1a9a22f2c80e45b4d2e52a74b8f19658932f2f5f
--- /dev/null
+++ b/aduc_framework/engineers/composer.py
@@ -0,0 +1,156 @@
+# aduc_framework/engineers/composer.py
+#
+# Copyright (C) August 4, 2025 Carlos Rodrigues dos Santos
+#
+# Versão 4.1.0 (Hub Cognitivo Consolidado)
+#
+# - A arquitetura está estável e completa. O Composer atua como o hub
+# central de comunicação com os LLMs.
+# - O método `execute_plan` é usado pelo Planner2D para a criação do roteiro.
+# - O método `execute_cognitive_task` é uma ferramenta genérica usada por
+# outros especialistas (como Planner4D e Deformes3D) para solicitar
+# tarefas de raciocínio pontuais ao LLM, como decidir um movimento de
+# câmera ou um plano de composição de imagem.
+
+import logging
+import json
+import re
+import yaml
+from pathlib import Path
+from PIL import Image
+from typing import List, Dict, Any, Generator, Optional, Callable
+
+from .prompt_engine import prompt_engine_singleton
+from ..managers.llama_multimodal_manager import llama_multimodal_manager_singleton
+from ..managers.gemini_manager import gemini_manager_singleton
+
+logger = logging.getLogger(__name__)
+
+def robust_json_parser(raw_text: str) -> dict:
+ """
+ Analisa um objeto JSON de uma string que pode conter texto extra.
+ """
+ logger.debug(f"COMPOSER(JSON_PARSER): Tentando parsear JSON (primeiros 500 chars):\n---\n{raw_text[:500]}\n---")
+ match = re.search(r'```json\s*(\{.*?\})\s*```', raw_text, re.DOTALL)
+ if match:
+ json_str = match.group(1); logger.debug("JSON explícito encontrado.")
+ return json.loads(json_str)
+ try:
+ start_index = raw_text.find('{'); end_index = raw_text.rfind('}')
+ if start_index != -1 and end_index != -1 and end_index > start_index:
+ json_str = raw_text[start_index : end_index + 1]; logger.debug("JSON por delimitadores '{...}' encontrado.")
+ return json.loads(json_str)
+ except json.JSONDecodeError: pass
+ logger.warning("Nenhum JSON válido encontrado nos métodos primários. Tentando parsear o texto inteiro.")
+ return json.loads(raw_text)
+
+class Composer:
+ """
+ O Composer é o hub central de comunicação com o Large Language Model (LLM).
+ Ele executa tanto planos de trabalho de várias etapas quanto tarefas cognitivas únicas.
+ """
+ def __init__(self):
+ logger.info("COMPOSER: Lendo config.yaml para selecionar o LLM Engine...")
+ with open("config.yaml", 'r') as f:
+ config = yaml.safe_load(f)
+
+ self.provider = config.get('specialists', {}).get('llm_engine', {}).get('provider', 'llama_multimodal')
+
+ if self.provider == 'gemini':
+ self.llm_manager = gemini_manager_singleton
+ logger.info("COMPOSER: Motor de LLM configurado para usar 'Gemini'.")
+ else:
+ self.llm_manager = llama_multimodal_manager_singleton
+ logger.info("COMPOSER: Motor de LLM configurado para usar 'Llama' (padrão).")
+
+ prompt_engine_singleton.set_provider(self.provider)
+ self.task_templates = self._load_task_templates()
+ logger.info(f"Composer inicializado com {len(self.task_templates)} templates de tarefa.")
+
+ def _load_task_templates(self) -> Dict[str, str]:
+ templates = {}
+ template_dir = Path(__file__).resolve().parent.parent / "prompts" / "task_templates"
+ if not template_dir.is_dir():
+ raise FileNotFoundError(f"Diretório de templates de tarefa não encontrado: {template_dir}")
+ for task_file in template_dir.glob("*.txt"):
+ task_id = task_file.stem
+ with open(task_file, 'r', encoding='utf-8') as f:
+ templates[task_id] = f.read()
+ return templates
+
+ def _talk_to_llm(self, generic_prompt: str, images: Optional[List[Image.Image]] = None, expected_format="text") -> Any:
+ final_model_prompt = prompt_engine_singleton.translate(
+ generic_prompt_content=generic_prompt, has_image=bool(images)
+ )
+ logger.info(f"COMPOSER: PROMPT FINAL SENDO ENVIADO para ({self.provider}):\n--- INÍCIO DO PROMPT ---\n{final_model_prompt}\n--- FIM DO PROMPT ---")
+ response_raw = self.llm_manager.process_turn(prompt_text=final_model_prompt, image_list=images)
+ logger.info(f"COMPOSER: RESPOSTA BRUTA RECEBIDA de ({self.provider}):\n--- INÍCIO DA RESPOSTA BRUTA ---\n{response_raw}\n--- FIM DA RESPOSTA BRUTA ---")
+
+ if expected_format == "json":
+ try:
+ return robust_json_parser(response_raw)
+ except (json.JSONDecodeError, ValueError) as e:
+ raise ValueError(f"O LLM ({self.provider}) retornou um formato JSON inválido. Erro: {e}")
+ return response_raw
+
+ def execute_cognitive_task(self, task_id: str, template_data: Dict[str, Any], images: Optional[List[Image.Image]] = None) -> Any:
+ """
+ Executa uma única tarefa cognitiva (de "pensamento") e retorna o resultado.
+ """
+ logger.info(f"COMPOSER: Executando tarefa cognitiva: {task_id}")
+ generic_template = self.task_templates.get(task_id)
+ if not generic_template:
+ raise ValueError(f"Template para a tarefa cognitiva '{task_id}' não foi encontrado.")
+
+ prompt_content = generic_template
+ for key, value in template_data.items():
+ prompt_content = prompt_content.replace(f"{{{key}}}", str(value))
+
+ expected_format = "json" if "JSON REQUIRED" in generic_template.upper() else "text"
+
+ response = self._talk_to_llm(generic_prompt=prompt_content, images=images, expected_format=expected_format)
+
+ if expected_format == "text":
+ return response.strip().replace("\"", "")
+ return response
+
+ def execute_plan(self, execution_plan: List[Dict[str, Any]], initial_data: Dict[str, Any]) -> Generator[Dict[str, Any], None, None]:
+ """
+ Executa um plano de trabalho de várias etapas para a criação do roteiro.
+ """
+ dna = {"global_prompt": initial_data["global_prompt"], "initial_media_paths": initial_data["user_media_paths"], "continuous_story": "", "scenes": []}
+ user_media = [Image.open(p) for p in initial_data["user_media_paths"]]
+
+ for i, task in enumerate(execution_plan):
+ try:
+ task_id = task['task_id']
+ yield {"status": "progress", "message": task.get('description', '')}
+
+ generic_template = self.task_templates.get(task_id)
+ if not generic_template:
+ raise ValueError(f"Template para a tarefa '{task_id}' não foi encontrado.")
+
+ prompt_content = generic_template
+ prompt_content = prompt_content.replace("{global_prompt}", str(dna.get("global_prompt", "")))
+ prompt_content = prompt_content.replace("{num_scenes}", str(task.get('inputs', {}).get("num_scenes", "")))
+ prompt_content = prompt_content.replace("{continuous_story}", str(dna.get("continuous_story", "")))
+ prompt_content = prompt_content.replace("{independent_scenes_json}", json.dumps({"scenes": dna.get("scenes", [])}, indent=2))
+
+ is_json_output = task_id in ["STEP_02_CREATE_INDEPENDENT_SCENES", "STEP_03_FRAGMENT_SCENES_INTO_ACTS", "STEP_04_FINAL_REVIEW"]
+ expected_format = "json" if is_json_output else "text"
+
+ response = self._talk_to_llm(prompt_content, user_media if i == 0 else None, expected_format)
+
+ if task_id == "STEP_01_CREATE_CONTINUOUS_STORY":
+ dna["continuous_story"] = response
+ elif task_id == "STEP_02_CREATE_INDEPENDENT_SCENES":
+ dna["scenes"] = response.get("scenes", [])
+ elif task_id == "STEP_03_FRAGMENT_SCENES_INTO_ACTS":
+ dna["scenes"] = response.get("scenes", [])
+
+ except Exception as e:
+ raise e
+
+ yield {"status": "complete", "message": "Execução do Composer concluída.", "dna": dna}
+
+composer_singleton = Composer()
\ No newline at end of file
diff --git a/aduc_framework/engineers/composer_2D.py b/aduc_framework/engineers/composer_2D.py
new file mode 100644
index 0000000000000000000000000000000000000000..4a4bb2d40992933388f5d27d0f6fc455b836bcca
--- /dev/null
+++ b/aduc_framework/engineers/composer_2D.py
@@ -0,0 +1,160 @@
+# aduc_framework/engineers/composer_2D.py
+
+# Versão 3.1.0 (Diálogo de Revisão Estruturado)
+#
+# - Implementa o fluxo de revisão em duas etapas (4.5 e 5) para
+# maior qualidade e consistência do storyboard.
+# - Etapa 4.5: A IA recebe o storyboard completo para uma análise global.
+# - Etapa 5: A IA itera cena a cena para fazer um polimento fino,
+# usando o contexto global absorvido na etapa anterior.
+# - Utiliza os métodos de serialização do Pydantic (`model_dump(mode='json')` e
+# `model_dump_json()`) para evitar TypeErrors com objetos datetime.
+
+import logging
+import json
+from typing import Generator, Dict, Any, List
+
+# --- Interface neural e tipos ---
+from .neura_link import neura_link_singleton as NeuraLink
+from ..types import GenerationState, CatalogoDeAtivos, Scene, Ato, AtivoCatalogado
+
+logger = logging.getLogger(__name__)
+
+class Composer2D:
+ """
+ Orquestra um pipeline conversacional para gerar e refinar um storyboard,
+ usando um sistema de identificação de ativos universal e um diálogo de
+ revisão em várias etapas.
+ """
+
+ def compose_storyboard(self, dna: GenerationState) -> Generator[GenerationState, None, None]:
+ """
+ Executa o pipeline completo de pré-produção, incluindo a fase de revisão.
+ """
+ params = getattr(dna.parametros_geracao, "pre_producao", None)
+ if not params:
+ raise ValueError("Parâmetros de pré-produção ausentes no DNA (parametros_geracao.pre_producao requerido).")
+
+ num_scenes = params.num_scenes
+ duration_per_fragment = params.duration_per_fragment
+ global_prompt = params.prompt
+
+ refs = list(getattr(dna, "midias_referencia", []))
+ image_paths = [r.caminho for r in refs if r.caminho]
+ image_map_para_llm = [{"tag_referencia": r.tag} for r in refs]
+
+ NeuraLink.reset_memory()
+ dna.chat_history.append({"role": "Composer2D", "content": "Memória da IA reiniciada. Iniciando roteiro..."})
+ yield dna
+
+ # --- ETAPAS 1-4: GERAÇÃO DO RASCUNHO INICIAL ---
+
+ # ETAPA 1: NARRATIVA
+ narrativa = NeuraLink.execute_task(
+ task_id="TASK_01_CREATE_CINEMATIC_NARRATIVE",
+ template_data={"global_prompt": global_prompt, "num_scenes": num_scenes},
+ image_paths=image_paths or None, expected_format="text", use_memory=True,
+ )
+ dna.texto_global_historia = (narrativa or "").strip()
+ dna.chat_history.append({"role": "Composer2D", "content": "Narrativa global criada."})
+ yield dna
+
+ # ETAPA 2: CATÁLOGO DE ATIVOS
+ asset_catalog_dict = NeuraLink.execute_task(
+ task_id="TASK_02_SELECT_AND_CATALOG_ASSETS",
+ template_data={"image_map": json.dumps(image_map_para_llm, ensure_ascii=False, indent=2)},
+ expected_format="json", use_memory=True,
+ )
+ dna.ativos_catalogados = CatalogoDeAtivos(**(asset_catalog_dict or {}))
+ dna.chat_history.append({"role": "Composer2D", "content": "Catálogo de ativos universais definido."})
+ yield dna
+
+ all_assets_by_id: Dict[str, AtivoCatalogado] = {asset.id: asset for asset_list in [dna.ativos_catalogados.cenarios, dna.ativos_catalogados.personagens, dna.ativos_catalogados.objetos] for asset in asset_list}
+
+ def upsert_asset_from_llm(llm_obj: Dict[str, Any], asset_type: str) -> AtivoCatalogado:
+ asset_id = llm_obj.get("id")
+ if not asset_id: raise ValueError(f"Ativo do tipo '{asset_type}' recebido do LLM sem 'id'.")
+ if asset_id in all_assets_by_id: return all_assets_by_id[asset_id]
+
+ logger.info(f"IA propôs um novo ativo dinamicamente: {asset_id} (Tipo: {asset_type})")
+ novo_ativo = AtivoCatalogado(**llm_obj)
+ getattr(dna.ativos_catalogados, f"{asset_type}s", []).append(novo_ativo)
+ all_assets_by_id[novo_ativo.id] = novo_ativo
+ return novo_ativo
+
+ # ETAPA 3: STORYBOARD
+ storyboard_dict = NeuraLink.execute_task(
+ task_id="TASK_03_CREATE_DIRECTORS_STORYBOARD",
+ template_data={"num_scenes": num_scenes}, expected_format="json", use_memory=True,
+ )
+ scene_list = (storyboard_dict or {}).get("storyboard", [])
+ normalized_scenes: List[Scene] = []
+ for idx, s_dict in enumerate(scene_list):
+ if "id_cena" not in s_dict: s_dict["id_cena"] = idx + 1
+ canonical_cenario = upsert_asset_from_llm(s_dict.get("cenario_escolhido", {}), "cenario")
+ s_dict["cenario_escolhido"] = canonical_cenario.model_dump()
+ normalized_scenes.append(Scene(**s_dict))
+ dna.storyboard_producao = normalized_scenes
+ dna.chat_history.append({"role": "Composer2D", "content": f"Rascunho do storyboard com {len(normalized_scenes)} cenas criado."})
+ yield dna
+
+ # ETAPA 4: ATOS
+ for scene in dna.storyboard_producao:
+ acts_dict = NeuraLink.execute_task(
+ task_id="TASK_04_DETAIL_SCENE_INTO_ACTS",
+ template_data={"scene_directors_manual": scene.model_dump_json(indent=2), "max_duration_per_act_s": duration_per_fragment},
+ expected_format="json", use_memory=True,
+ )
+ scene.atos = [Ato(**a) for a in (acts_dict or {}).get("atos", [])]
+ dna.chat_history.append({"role": "Composer2D", "content": f"Cena {scene.id_cena}: atos detalhados."})
+ yield dna
+
+ # --- ETAPA 4.5: PRÉ-REVISÃO (CARREGAMENTO DE CONTEXTO OTIMIZADO) ---
+ dna.chat_history.append({"role": "Composer2D", "content": "Rascunho finalizado. Apresentando à IA para análise global antes do polimento..."})
+ yield dna
+
+ full_storyboard_json = json.dumps(
+ [s.model_dump(mode='json') for s in dna.storyboard_producao],
+ indent=2,
+ ensure_ascii=False
+ )
+ confirmation_message = NeuraLink.execute_task(
+ task_id="TASK_4_5_PRE_REVIEW_CONTEXT",
+ template_data={"full_storyboard_json": full_storyboard_json},
+ expected_format="text", use_memory=True,
+ )
+ dna.chat_history.append({"role": "Supervisor de Roteiro (IA)", "content": confirmation_message})
+ yield dna
+
+ # --- ETAPA 5: REVISÃO DE CONTINUIDADE CENA A CENA (COM CONTEXTO IMPLÍCITO) ---
+ dna.chat_history.append({"role": "Composer2D", "content": "Contexto carregado. Iniciando revisão detalhada cena a cena..."})
+ yield dna
+
+ refined_storyboard = []
+ for scene_to_review in dna.storyboard_producao:
+ dna.chat_history.append({"role": "Composer2D", "content": f"Polindo Cena {scene_to_review.id_cena}/{len(dna.storyboard_producao)}: '{scene_to_review.titulo_cena}'..."})
+ yield dna
+
+ scene_json_for_prompt = scene_to_review.model_dump_json(indent=2)
+
+ refined_scene_dict = NeuraLink.execute_task(
+ task_id="TASK_05_SCENE_CONTINUITY_REVIEW",
+ template_data={"scene_to_review_json": scene_json_for_prompt},
+ expected_format="json", use_memory=True,
+ )
+ try:
+ refined_scene = Scene(**refined_scene_dict)
+ refined_storyboard.append(refined_scene)
+ except Exception as e:
+ logger.warning(f"Falha ao validar cena refinada {scene_to_review.id_cena}. Mantendo a versão original. Erro: {e}")
+ refined_storyboard.append(scene_to_review)
+
+ dna.storyboard_producao = refined_storyboard
+ dna.chat_history.append({"role": "Composer2D", "content": "Revisão de continuidade concluída. Storyboard finalizado e polido."})
+ yield dna
+
+ logger.info("Pipeline completo do Composer2D (Geração e Revisão) concluído com sucesso.")
+ return
+
+# Singleton
+composer_2d_singleton = Composer2D()
\ No newline at end of file
diff --git a/aduc_framework/engineers/deformes3D.py b/aduc_framework/engineers/deformes3D.py
new file mode 100644
index 0000000000000000000000000000000000000000..98c4472ba8dbee275504760f6578125b89103a44
--- /dev/null
+++ b/aduc_framework/engineers/deformes3D.py
@@ -0,0 +1,152 @@
+# aduc_framework/engineers/deformes3D.py
+#
+# Versão 12.4.0 (Correção de Integração com VaeManager v2)
+# - Remove a função auxiliar obsoleta `_pil_to_latent` que ainda tentava
+# chamar o antigo método `vae_manager_singleton.encode()`.
+# - Consolida o uso exclusivo do método `encode_batch` para toda a codificação
+# de imagens, alinhando-se com a arquitetura de VAE persistente e otimizada.
+
+import os
+import logging
+import torch
+import numpy as np
+from PIL import Image
+from typing import List, Dict, Any
+
+from ..types import LatentConditioningItem, KeyframeGenerationJob
+from ..managers.ltx_manager import ltx_manager_singleton
+from ..managers.vae_manager import vae_manager_singleton
+
+logger = logging.getLogger(__name__)
+
+class Deformes3DEngine:
+ def __init__(self):
+ self.workspace_dir: str | None = None
+ logger.info("Deformes3DEngine (Pintor de Sequência) instanciado.")
+
+ def initialize(self, workspace_dir: str):
+ if self.workspace_dir is not None and self.workspace_dir == workspace_dir:
+ return
+ self.workspace_dir = workspace_dir
+ logger.info(f"Pintor 3D inicializado com workspace: {self.workspace_dir}.")
+
+ def generate_keyframes_from_job(
+ self,
+ job: KeyframeGenerationJob
+ ) -> List[Dict[str, Any]]:
+ from .composer import composer_singleton as Composer
+
+ if not self.workspace_dir:
+ raise RuntimeError("Deformes3DEngine não foi inicializado.")
+
+ storyboard = job.storyboard
+ num_keyframes_to_generate = len(storyboard)
+ global_prompt = job.global_prompt
+ ref_id_to_path_map = job.ref_id_to_path_map
+ available_ref_ids = job.available_ref_ids
+ keyframe_prefix = job.keyframe_prefix
+
+ target_resolution_tuple = (512, 512)
+ current_base_image_path = job.ref_image_paths[0]
+ previous_prompt = ""
+ all_keyframes_data: List[Dict[str, Any]] = []
+
+ logger.info(f"Pintor 3D: Recebida ordem para gerar {num_keyframes_to_generate} keyframes para a cena '{keyframe_prefix}'.")
+
+ # --- FLUXO DE CODIFICAÇÃO EM LOTE OTIMIZADO ---
+ # 1. Coletar a imagens base
+ images_to_encode = [Image.open(current_base_image_path).convert("RGB")]
+ ref_weights = [0.4] # Peso fixo para a imagem anterior
+ encoded_latents = vae_manager_singleton.encode_batch(images_to_encode, target_resolution_tuple)
+
+ for i in range(num_keyframes_to_generate):
+ scene_index = i + 1
+ current_scene_narrative = storyboard[i]
+ future_scene_narrative = storyboard[i + 1] if (i + 1) < len(storyboard) else "A cena final."
+ logger.info(f"--> Planejando Keyframe {scene_index}/{num_keyframes_to_generate}...")
+
+ composition_plan = Composer.execute_cognitive_task(
+ task_id="COGNITIVE_01_PLAN_KEYFRAME",
+ template_data={
+ "historico_prompt": previous_prompt,
+ "cena_atual": current_scene_narrative,
+ "cena_futura": future_scene_narrative,
+ "available_ref_images": available_ref_ids,
+ },
+ images=[Image.open(current_base_image_path)]
+ )
+
+ img_prompt = composition_plan.get("composition_prompt", current_scene_narrative)
+ selected_references = composition_plan.get("reference_images", [])
+ logger.info(f"Plano do Diretor de Arte recebido. Prompt: '{img_prompt[:80]}...'. Referências: {len(selected_references)}")
+
+
+ #for ref in selected_references:
+ # image_path = ref_id_to_path_map.get(ref.get("id"))
+ # if image_path:
+ # images_to_encode.append(Image.open(image_path).convert("RGB"))
+ # ref_weights.append(ref.get("weight", 0.3))
+
+ # 2. Chamar o método em lote do VaeManager UMA ÚNICA VEZ
+ #logger.info(f"Codificando {len(images_to_encode)} imagens de referência em lote...")
+ #encoded_latents = vae_manager_singleton.encode_batch(images_to_encode, target_resolution_tuple)
+ #logger.info("Codificação em lote concluída.")
+
+ # 3. Construir os itens de condicionamento com os latentes já prontos
+ ltx_conditioning_items = []
+ for latent_tensor, weight in zip(encoded_latents, ref_weights):
+ ltx_conditioning_items.append(LatentConditioningItem(latent_tensor, 0, weight))
+ # --- FIM DA OTIMIZAÇÃO ---
+
+ ltx_base_params = {"guidance_scale": 2.0, "stg_scale": 0.015, "num_inference_steps": 25}
+ generated_latents, _ = ltx_manager_singleton.generate_latent_fragment(
+ height=target_resolution_tuple[0], width=target_resolution_tuple[1],
+ conditioning_items_data=ltx_conditioning_items,
+ motion_prompt=img_prompt,
+ video_total_frames=36, video_fps=24,
+ **ltx_base_params
+ )
+
+ final_latent = generated_latents[:, :, -1:, :, :]
+ enriched_pixel_tensor = vae_manager_singleton.decode(final_latent)
+
+ encoded_latents = [encoded_latents[0], final_latent]
+ ref_weights = [0.05,0.5]
+
+ pixel_path = os.path.join(self.workspace_dir, f"{keyframe_prefix}_kf{scene_index:03d}_pixel.png")
+ latent_path = os.path.join(self.workspace_dir, f"{keyframe_prefix}_kf{scene_index:03d}_latent.pt")
+ self.save_image_from_tensor(enriched_pixel_tensor, pixel_path)
+ torch.save(final_latent.cpu(), latent_path)
+
+ keyframe_data = {
+ "id": scene_index,
+ "caminho_pixel": pixel_path,
+ "caminho_latent": latent_path,
+ "prompt_keyframe": img_prompt
+ }
+ all_keyframes_data.append(keyframe_data)
+
+ current_base_image_path = pixel_path
+ previous_prompt = img_prompt
+
+ logger.info(f"Pintor 3D: Ordem de serviço para a cena '{keyframe_prefix}' concluída.")
+ return all_keyframes_data
+
+ # --- FUNÇÃO PROBLEMÁTICA REMOVIDA ---
+ # A função _pil_to_latent foi removida pois sua lógica foi
+ # centralizada e otimizada dentro do loop principal.
+
+ def save_image_from_tensor(self, pixel_tensor: torch.Tensor, path: str):
+ """Salva um tensor de pixel como um arquivo de imagem."""
+ # Garante que o tensor está na CPU para manipulação com numpy/PIL
+ pixel_tensor_cpu = pixel_tensor.cpu()
+ tensor_chw = pixel_tensor_cpu.squeeze(0).squeeze(1)
+ tensor_hwc = tensor_chw.permute(1, 2, 0)
+ # Desnormaliza de [-1, 1] para [0, 1]
+ tensor_hwc = (tensor_hwc.clamp(-1, 1) + 1) / 2.0
+ # Converte para [0, 255] e tipo de imagem
+ image_np = (tensor_hwc.float().numpy() * 255).astype(np.uint8)
+ Image.fromarray(image_np).save(path)
+
+# --- Instância Singleton ---
+deformes3d_engine_singleton = Deformes3DEngine()
\ No newline at end of file
diff --git a/aduc_framework/engineers/deformes4D.py b/aduc_framework/engineers/deformes4D.py
new file mode 100644
index 0000000000000000000000000000000000000000..98f2c1afc50068a73fd518ada1c334328ede2abd
--- /dev/null
+++ b/aduc_framework/engineers/deformes4D.py
@@ -0,0 +1,234 @@
+# aduc_framework/engineers/deformes4D.py
+#
+# Versão 16.0.0 (Integração de Lógica ADUC-SDR Canônica)
+# Copyright (C) August 4, 2025 Carlos Rodrigues dos Santos
+#
+# - Refatora a lógica de geração de vídeo monolítica para o padrão de
+# Especialista ADUC, operando dentro da classe Deformes4DEngine.
+# - Integra o núcleo lógico de Poda Causal, Eco e Déjà-Vu (linhas 187-315
+# do arquivo original) de forma intacta.
+# - Substitui as chamadas de baixo nível por delegações aos managers
+# especializados (VaeManager, LtxManager, VideoEncodeTool).
+# - O método principal agora aceita um `VideoGenerationJob` do Planner5D.
+
+import os
+import time
+import torch
+import logging
+from PIL import Image
+import gc
+from typing import Dict, Any
+
+# Importa os managers e especialistas da arquitetura ADUC
+from ..managers.ltx_manager import ltx_manager_singleton
+from ..managers.vae_manager import vae_manager_singleton
+from ..tools.video_encode_tool import video_encode_tool_singleton
+from ..types import LatentConditioningItem, VideoGenerationJob
+from ..engineers.composer import composer_singleton as Composer # Usado para decisões cinematográficas
+
+logger = logging.getLogger(__name__)
+
+class Deformes4DEngine:
+ """
+ Implementa a Câmera (Ψ) e o Destilador (Δ) da arquitetura ADUC-SDR.
+ É responsável pela execução da geração de fragmentos de vídeo e pela
+ extração dos contextos causais (Eco e Déjà-Vu).
+ """
+ def __init__(self):
+ self.workspace_dir: str | None = None
+ self.device = 'cuda' if torch.cuda.is_available() else 'cpu'
+ logger.info("Especialista Deformes4D (Executor ADUC-SDR: Câmera Ψ e Destilador Δ) inicializado.")
+
+ def initialize(self, workspace_dir: str):
+ if self.workspace_dir and self.workspace_dir == workspace_dir:
+ return
+ self.workspace_dir = workspace_dir
+ os.makedirs(self.workspace_dir, exist_ok=True)
+ logger.info(f"Executor de Cena 4D inicializado com workspace: {self.workspace_dir}.")
+
+ def _quantize_to_multiple(self, n, m):
+ if m == 0: return n
+ quantized = int(round(n / m) * m)
+ return m if n > 0 and quantized == 0 else quantized
+
+ # O método principal que o Planner5D chamará
+ def generate_movie_clip_from_job(self, job: VideoGenerationJob) -> Dict[str, Any]:
+ if not self.workspace_dir:
+ raise RuntimeError("Deformes4DEngine não foi inicializado.")
+
+ # Extrai os parâmetros da Ordem de Serviço
+ keyframes = job.keyframe_paths
+ global_prompt = job.global_prompt
+ storyboard = job.storyboard
+ seconds_per_fragment = job.duration_per_fragment
+ trim_percent = job.trim_percent
+ handler_strength = job.handler_strength
+ destination_convergence_strength = job.destination_convergence_strength
+ video_resolution = job.resolution
+
+ # Este método agora encapsula a lógica do seu 'generate_full_movie'
+ return self._execute_generation_logic(
+ keyframes, global_prompt, storyboard, seconds_per_fragment,
+ trim_percent, handler_strength, destination_convergence_strength,
+ video_resolution
+ )
+
+ def _execute_generation_logic(self, keyframes: list, global_prompt: str, storyboard: list,
+ seconds_per_fragment: float, trim_percent: int,
+ handler_strength: float, destination_convergence_strength: float,
+ video_resolution: int):
+
+ #####(atenção Gemini .. nao apagar ou modificar nada apartir dessa linha) #####
+ # manter o conteudo original da linha 187 ate 315
+
+ # 1. Definição dos Parâmetros da Geração com base na Tese
+ FPS = 32
+ FRAMES_PER_LATENT_CHUNK = 8
+ ECO_LATENT_CHUNKS = 2
+
+ total_frames_brutos = self._quantize_to_multiple(int(seconds_per_fragment * FPS), FRAMES_PER_LATENT_CHUNK)
+ total_latents_brutos = total_frames_brutos // FRAMES_PER_LATENT_CHUNK
+
+ frames_a_podar = 15 #self._quantize_to_multiple(int(total_frames_brutos * (trim_percent / 100)), FRAMES_PER_LATENT_CHUNK)
+ latents_a_podar = frames_a_podar // FRAMES_PER_LATENT_CHUNK
+
+ if total_latents_brutos <= latents_a_podar:
+ #raise gr.Error(f"A porcentagem de poda ({trim_percent}%) é muito alta. Reduza-a ou aumente a duração.")
+ raise ValueError(f"A porcentagem de poda ({trim_percent}%) é muito alta. Reduza-a ou aumente a duração.")
+
+ DEJAVU_FRAME_TARGET = 23
+ DESTINATION_FRAME_TARGET = total_frames_brutos -8
+
+ logger.info("--- CONFIGURAÇÃO DA GERAÇÃO ADUC-SDR ---")
+ logger.info(f"Total de Latents por Geração Exploratória (V_bruto): {total_latents_brutos} ({total_frames_brutos} frames)")
+ logger.info(f"Latents a serem descartados (Poda Causal): {latents_a_podar} ({frames_a_podar} frames)")
+ logger.info(f"Chunks Latentes do Eco Causal (C): {ECO_LATENT_CHUNKS}")
+ logger.info(f"Frame alvo do Déjà-Vu (D): {DEJAVU_FRAME_TARGET}")
+ logger.info(f"Frame alvo do Destino (K): {DESTINATION_FRAME_TARGET}")
+ logger.info("------------------------------------------")
+
+ # 2. Inicialização do Estado
+ base_ltx_params = {"guidance_scale": 1.0, "stg_scale": 0.005, "rescaling_scale": 0.05, "num_inference_steps": 4, "image_cond_noise_scale": 0.05}
+ keyframe_paths = [item[0] if isinstance(item, tuple) else item for item in keyframes]
+ video_clips_paths, story_history = [], ""
+ target_resolution_tuple = (video_resolution, video_resolution)
+
+ eco_latent_for_next_loop = None
+ dejavu_latent_for_next_loop = None
+
+ if len(keyframe_paths) < 1:
+ #raise gr.Error(f"A geração requer no mínimo 2 keyframes. Você forneceu {len(keyframe_paths)}.")
+ raise ValueError(f"A geração requer no mínimo 2 keyframes. Você forneceu {len(keyframe_paths)}.")
+
+ num_transitions_to_generate = len(keyframe_paths) -1
+
+ # 3. Loop Principal de Geração de Fragmentos
+ for i in range(num_transitions_to_generate):
+ fragment_index = i + 1
+ logger.info(f"--- INICIANDO FRAGMENTO {fragment_index}/{num_transitions_to_generate} ---")
+
+ # 3.1. Consulta ao Maestro (Γ) para obter a intenção (Pᵢ)
+ start_keyframe_path = keyframe_paths[i]
+
+ if i+1 < num_transitions_to_generate:
+ destination_keyframe_path = keyframe_paths[i + 1]
+ else:
+ destination_keyframe_path = keyframe_paths[i]
+
+
+ decision = Composer.execute_cognitive_task(
+ task_id="TASK_08_IMPROVISE_CINEMATIC_PROMPT_ATO",
+ template_data={"current_act_narrative": storyboard[i]},
+ images=[Image.open(start_keyframe_path), Image.open(destination_keyframe_path)]
+ )
+ motion_prompt = decision.strip()
+ story_history += f"\n- Ato {fragment_index}: {motion_prompt}"
+
+ # 3.2. Montagem das Âncoras para a Fórmula Canônica Ψ({C, D, K}, P)
+ conditioning_items = []
+ logger.info(" [Ψ.1] Montando âncoras causais...")
+
+ if eco_latent_for_next_loop is None:
+ logger.info(" - Primeiro fragmento: Usando Keyframe inicial como âncora de partida.")
+ img_start = Image.open(start_keyframe_path).convert("RGB")
+ img_dest = Image.open(destination_keyframe_path).convert("RGB")
+ start_latent, dest_latent = vae_manager_singleton.encode_batch([img_start, img_dest], target_resolution_tuple)
+ conditioning_items.append(LatentConditioningItem(start_latent, 0, 1.0))
+ else:
+ logger.info(" - Âncora 1: Eco Causal (C) - Herança do passado.")
+ conditioning_items.append(LatentConditioningItem(eco_latent_for_next_loop, 0, 1.0))
+ logger.info(" - Âncora 2: Déjà-Vu (D) - Memória de um futuro idealizado.")
+ conditioning_items.append(LatentConditioningItem(dejavu_latent_for_next_loop, 23, 0.5))
+ img_dest = Image.open(destination_keyframe_path).convert("RGB")
+ dest_latent = vae_manager_singleton.encode_batch([img_dest], target_resolution_tuple)[0]
+
+ logger.info(" - Âncora 3: Destino (K) - Âncora geométrica/narrativa.")
+ conditioning_items.append(LatentConditioningItem(dest_latent, DESTINATION_FRAME_TARGET, 1.0))
+
+ # 3.3. Execução da Câmera (Ψ): Geração Exploratória para criar V_bruto
+ logger.info(f" [Ψ.2] Câmera (Ψ) executando a geração exploratória de {total_latents_brutos} chunks latentes...")
+ current_ltx_params = {**base_ltx_params, "motion_prompt": motion_prompt}
+ latents_brutos, _ = ltx_manager_singleton.generate_latent_fragment(
+ height=video_resolution, width=video_resolution,
+ conditioning_items_data=conditioning_items,
+ video_total_frames=total_frames_brutos+1,
+ **current_ltx_params
+ )
+
+ # 3.4. Execução do Destilador (Δ): Implementação do Ciclo de Poda Causal
+ logger.info(f" [Δ] Shape do tensor bruto para vídeo final: {latents_brutos.shape}")
+
+
+ #latents_video = latents_brutos[:, :, :-1, :, :]
+
+
+ # --- Workaround empírico preservado ---
+ eco_latent_for_next_loop = latents_brutos[:, :, -5:-2, :, :].clone()
+ dejavu_latent_for_next_loop = latents_brutos[:, :, -1:, :, :].clone()
+
+
+ latents_video = latents_brutos[:, :, :-4, :, :].clone()
+
+ logger.info(f" [Δ] Shape do tensor video para vídeo final: {latents_video.shape}")
+
+
+ #if i+1 < num_transitions_to_generate:
+ #latents_video = latents_video[:, :, :-4, :, :]
+ # logger.info(f"@@@@@@@@@@# Nao é ULTIMO poda -1")
+ # logger.info(f" [Δ] -1 Shape do tensor video para vídeo final: {latents_video.shape}")
+
+
+ #if i > 0:
+ # latents_video = latents_video[:, :, 2:, :, :]
+ # logger.info(f"@@@@@@@@@@# nao é o primeiro poda 1")
+ # logger.info(f" [Δ] 1 Shape do tensor video para vídeo final: {latents_video.shape}")
+
+
+
+ logger.info(f" [Δ] Shape do tensor para vídeo final: {latents_video.shape}")
+ logger.info(f" - (Δ.1) Déjà-Vu (D) destilado. Shape: {dejavu_latent_for_next_loop.shape if dejavu_latent_for_next_loop is not None else 'N/A'}")
+ logger.info(f" - (Δ.2) Eco Causal (C) extraído. Shape: {eco_latent_for_next_loop.shape if eco_latent_for_next_loop is not None else 'N/A'}")
+
+ # 3.5. Renderização e Armazenamento do Fragmento Final
+ base_name = f"fragment_{fragment_index}_{int(time.time())}"
+ pixel_tensor = vae_manager_singleton.decode(latents_video)
+ video_path = os.path.join(self.workspace_dir, f"{base_name}.mp4")
+ video_encode_tool_singleton.save_video_from_tensor(pixel_tensor, video_path, fps=FPS)
+ video_clips_paths.append(video_path)
+ logger.info(f"--- FRAGMENTO {fragment_index} FINALIZADO E SALVO EM: {video_path} ---")
+
+ # 4. Montagem Final do Filme
+ final_movie_path = os.path.join(self.workspace_dir, f"final_movie_silent_{int(time.time())}.mp4")
+ final_movie_path = video_encode_tool_singleton.concatenate_videos(video_clips_paths, final_movie_path, self.workspace_dir)
+
+ #####(atenção Gemini .. nao apagar ou modificar nada acima dessa linha) #####
+
+ logger.info(f"Filme completo salvo em: {final_movie_path}")
+ # Retorna o resultado no formato esperado pelo Planner5D
+ return {
+ "final_path": final_movie_path,
+ "video_data": {"id": 0, "caminho_pixel": final_movie_path} # ID 0 para o filme completo
+ }
+
+# --- Instância Singleton ---
+deformes4d_engine_singleton = Deformes4DEngine()
\ No newline at end of file
diff --git a/aduc_framework/engineers/neura_link.py b/aduc_framework/engineers/neura_link.py
new file mode 100644
index 0000000000000000000000000000000000000000..b50ad16a656cc78726ff91001dda60e578eefc4a
--- /dev/null
+++ b/aduc_framework/engineers/neura_link.py
@@ -0,0 +1,128 @@
+# aduc_framework/engineers/neura_link.py
+#
+# Versão 2.0.0 (Interface Neural com Controle de Memória)
+#
+# Este componente substitui o antigo 'Composer'. Ele atua como o hub central
+# de comunicação com o LLM, abstraindo a formatação de prompts, o envio
+# de requisições e o parsing de respostas. Agora inclui um método `reset_memory`
+# para dar ao orquestrador controle explícito sobre o ciclo de vida da conversa.
+
+import logging
+import json
+import re
+import yaml
+import os
+from PIL import Image
+from typing import List, Dict, Any, Optional
+
+# --- Importando os managers de LLM de baixo nível e o motor de prompt ---
+from ..managers.gemini_manager import gemini_manager_singleton
+from ..managers.llama_multimodal_manager import llama_multimodal_manager_singleton
+from .prompt_engine import prompt_engine_singleton
+
+logger = logging.getLogger(__name__)
+
+def robust_json_parser(raw_text: str) -> dict:
+ """
+ Analisa um objeto JSON de uma string que pode conter texto extra,
+ como blocos de código Markdown ou explicações do LLM.
+ """
+ logger.debug(f"Neura_Link(JSON_PARSER): Tentando parsear JSON (primeiros 500 chars):\n---\n{raw_text[:500]}\n---")
+ match = re.search(r'```json\s*(\{.*?\})\s*```', raw_text, re.DOTALL)
+ if match:
+ json_str = match.group(1); logger.debug("JSON explícito encontrado.")
+ return json.loads(json_str)
+ try:
+ start_index = raw_text.find('{'); end_index = raw_text.rfind('}')
+ if start_index != -1 and end_index != -1 and end_index > start_index:
+ json_str = raw_text[start_index : end_index + 1]; logger.debug("JSON por delimitadores '{...}' encontrado.")
+ return json.loads(json_str)
+ except json.JSONDecodeError: pass
+ try:
+ return json.loads(raw_text)
+ except json.JSONDecodeError as e:
+ logger.error(f"Falha CRÍTICA no parser de JSON. O LLM retornou um texto inválido. Resposta bruta: \n{raw_text}")
+ raise ValueError(f"O LLM retornou um formato JSON inválido que não pôde ser corrigido. Erro: {e}")
+
+class NeuraLink:
+ """
+ Neura_Link é a interface de comunicação com a IA. Ele carrega templates,
+ formata prompts, envia requisições e processa as respostas, com controle
+ sobre a memória da sessão.
+ """
+ def __init__(self):
+ logger.info("Neura_Link: Lendo config.yaml para selecionar o LLM Engine...")
+ with open("config.yaml", 'r') as f: config = yaml.safe_load(f)
+
+ self.provider = config.get('specialists', {}).get('llm_engine', {}).get('provider', 'gemini')
+
+ if self.provider == 'llama_multimodal':
+ self.llm_manager = llama_multimodal_manager_singleton
+ logger.info("Neura_Link: Motor de LLM configurado para usar 'Llama'.")
+ else:
+ self.llm_manager = gemini_manager_singleton
+ logger.info("Neura_Link: Motor de LLM configurado para usar 'Gemini' (padrão).")
+
+ prompt_engine_singleton.set_provider(self.provider)
+ self.task_templates = self._load_task_templates()
+ logger.info(f"Neura_Link inicializado com {len(self.task_templates)} templates de tarefa.")
+
+ def _load_task_templates(self) -> Dict[str, str]:
+ """Carrega todos os arquivos .txt do diretório de templates de tarefa."""
+ templates = {}
+ try:
+ template_dir = os.path.join(os.path.dirname(__file__), '..', 'prompts', 'task_templates')
+ for task_file in os.listdir(template_dir):
+ if task_file.endswith(".txt"):
+ task_id = os.path.splitext(task_file)[0]
+ with open(os.path.join(template_dir, task_file), 'r', encoding='utf-8') as f:
+ templates[task_id] = f.read()
+ except FileNotFoundError:
+ raise FileNotFoundError(f"Diretório de templates de tarefa não encontrado. Verifique a estrutura do projeto.")
+ return templates
+
+ def reset_memory(self):
+ """
+ Envia um comando para o manager de LLM subjacente reiniciar sua
+ sessão de chat, garantindo um contexto limpo para uma nova operação.
+ """
+ logger.info("Neura_Link: Solicitando reinicialização da memória da sessão de chat.")
+ # Chama o manager com o gatilho `restart_session` e um prompt vazio.
+ # O manager está programado para não fazer uma chamada à API se o prompt for vazio.
+ self.llm_manager.process_turn(prompt_text="", restart_session=True)
+
+ def execute_task(self, task_id: str, template_data: Dict[str, Any], image_paths: Optional[List[str]] = None, expected_format: str = "text", use_memory: bool = False) -> Any:
+ """
+ Executa uma única tarefa cognitiva, orquestrando todo o processo.
+ """
+ logger.info(f"Neura_Link: Executando tarefa '{task_id}'...")
+
+ generic_template = self.task_templates.get(task_id)
+ if not generic_template:
+ raise ValueError(f"Neura_Link: Template para a tarefa '{task_id}' não foi encontrado.")
+
+ prompt_content = generic_template
+ for key, value in template_data.items():
+ prompt_content = prompt_content.replace(f"{{{key}}}", str(value))
+
+ images = [Image.open(p) for p in image_paths] if image_paths else None
+
+ final_model_prompt = prompt_engine_singleton.translate(
+ generic_prompt_content=prompt_content, has_image=bool(images)
+ )
+
+ logger.info(f"Neura_Link: Enviando prompt finalizado para o provedor '{self.provider}'. Use Memory: {use_memory}")
+ response_raw = self.llm_manager.process_turn(
+ prompt_text=final_model_prompt,
+ image_list=images,
+ use_memory=use_memory
+ )
+ logger.info(f"Neura_Link: Resposta bruta recebida do provedor '{self.provider}'.")
+
+ if expected_format == "json":
+ return robust_json_parser(response_raw)
+ else:
+ return response_raw.strip()
+
+# --- Instância Singleton ---
+neura_link_singleton = NeuraLink()
\ No newline at end of file
diff --git a/aduc_framework/engineers/planner_2d.py b/aduc_framework/engineers/planner_2d.py
new file mode 100644
index 0000000000000000000000000000000000000000..29be1d99ac7a7c0a283226b865a14bad03c1c11b
--- /dev/null
+++ b/aduc_framework/engineers/planner_2d.py
@@ -0,0 +1,91 @@
+# aduc_framework/engineers/planner_2d.py
+#
+# Copyright (C) August 4, 2025 Carlos Rodrigues dos Santos
+#
+# Versão 2.1.0 (Focused 3-Step Plan)
+# Esta versão desativa temporariamente a Etapa 4 (revisão) para focar na
+# geração da estrutura de atos, que é o insumo para a próxima fase.
+# A mensagem final para o orquestrador foi aprimorada.
+
+import logging
+from typing import List, Dict, Any, Generator, Optional, Callable
+
+logger = logging.getLogger(__name__)
+
+class Planner2D:
+ """
+ O Planner2D cria o plano de trabalho estratégico (o `execution_plan`)
+ para a fase de pré-produção, focando na construção progressiva da narrativa.
+ """
+
+ def generate_execution_plan(
+ self,
+ global_prompt: str,
+ num_scenes: int,
+ max_duration_per_act: float,
+ fast_mode: bool,
+ callback: Optional[Callable] = None
+ ) -> Generator[Dict[str, Any], None, List[Dict[str, Any]]]:
+ """
+ Cria e emite o plano de execução para a pré-produção.
+ """
+ message = "Planner2D (Arquiteto): Criando novo plano de execução focado em narrativa..."
+ logger.info(message)
+ if callback: callback(0.0, desc="Arquiteto iniciando o planejamento...")
+ yield {"status": "planning", "progress": 0.0, "message": message}
+
+ execution_plan: List[Dict[str, Any]]
+
+ if fast_mode:
+ logger.info("Planner2D: Modo Rápido ativado. Consolidando tarefas de planejamento.")
+ execution_plan = [
+ {
+ "task_id": "FAST_01_GENERATE_SCENES_AND_ACTS",
+ "description": "(Modo Rápido) Gerando a estrutura completa de Cenas e Atos...",
+ "inputs": {"global_prompt": global_prompt, "num_scenes": num_scenes},
+ "status": "pending"
+ }
+ ]
+ else:
+ # --- MUDANÇA PRINCIPAL AQUI ---
+ logger.info("Planner2D: Modo Detalhado ativado com 3 etapas (Etapa 4 desativada temporariamente).")
+ execution_plan = [
+ {
+ "task_id": "STEP_01_CREATE_CONTINUOUS_STORY",
+ "description": "Etapa 1/3: Criando a história contínua...",
+ "inputs": {"global_prompt": global_prompt, "num_scenes": num_scenes},
+ "status": "pending"
+ },
+ {
+ "task_id": "STEP_02_CREATE_INDEPENDENT_SCENES",
+ "description": "Etapa 2/3: Refinando cada parágrafo em uma cena independente...",
+ "inputs": {},
+ "status": "pending"
+ },
+ {
+ "task_id": "STEP_03_FRAGMENT_SCENES_INTO_ACTS",
+ "description": "Etapa 3/3: Detalhando cada cena em atos independentes...",
+ "inputs": {},
+ "status": "pending"
+ },
+ # {
+ # "task_id": "STEP_04_FINAL_REVIEW",
+ # "description": "Etapa 4/4: Realizando a revisão final de coerência...",
+ # "inputs": {"global_prompt": global_prompt},
+ # "status": "pending"
+ # }
+ ]
+
+ # --- MENSAGEM FINAL APRIMORADA ---
+ message = f"Planner2D (Arquiteto): Plano de pré-produção finalizado com {len(execution_plan)} etapas. Entregando para o Composer (Encarregado) executar."
+ logger.info(message)
+ if callback:
+ callback(0.1, desc="Plano estratégico concluído. Iniciando execução...")
+
+ # Este yield informa ao Orquestrador que o planejamento terminou e entrega o plano final.
+ yield {"status": "planning_complete", "progress": 0.1, "message": message, "plan": execution_plan}
+
+ return execution_plan
+
+# --- Instância Singleton ---
+planner_2d_singleton = Planner2D()
\ No newline at end of file
diff --git a/aduc_framework/engineers/planner_3d.py b/aduc_framework/engineers/planner_3d.py
new file mode 100644
index 0000000000000000000000000000000000000000..3eabf780a9195e5eb56b829ef26142f728790dd6
--- /dev/null
+++ b/aduc_framework/engineers/planner_3d.py
@@ -0,0 +1,103 @@
+# aduc_framework/engineers/planner_3d.py
+#
+# Copyright (C) August 4, 2025 Carlos Rodrigues dos Santos
+#
+# Versão 4.1.0 (DNA Seguro por Cena)
+#
+# - Remove o acúmulo global de keyframes e a divisão por índices.
+# - Atualiza cada cena diretamente com os keyframes gerados pelo Painter.
+# - Garante que o DNA final nunca fique “bagunçado”.
+# - Foco na simplicidade: Planner orquestra, Painter gera, DNA organiza.
+
+import logging
+import json
+from typing import List, Dict, Any, Generator
+
+from .deformes3D import deformes3d_engine_singleton
+from ..types import KeyframeGenerationJob
+
+logger = logging.getLogger(__name__)
+
+class Planner3D:
+ """
+ Gerente de projeto para a fase de keyframes.
+ Prepara e despacha ordens de serviço para o Painter (Deformes3D),
+ e injeta os keyframes diretamente no DNA cena a cena.
+ """
+ def generate_keyframes_from_dna(
+ self,
+ generation_state: Dict[str, Any],
+ initial_chat_history: List[Dict[str, Any]]
+ ) -> Generator[Dict[str, Any], None, None]:
+
+ painter = deformes3d_engine_singleton
+ chat_history = initial_chat_history.copy()
+ chat_history.append({
+ "role": "Planner3D",
+ "content": "Roteiro recebido. Iniciando criação de keyframes..."
+ })
+ yield {"chat": chat_history, "gallery": [], "dna": generation_state}
+
+ # 1. Extrai dados globais
+ scenes_list = generation_state.get("scenes", [])
+ ref_image_paths = [ref['caminho'] for ref in generation_state.get("midias_referencia", [])]
+ global_prompt = generation_state.get("prompt_geral", "")
+ pre_prod_params = generation_state.get("parametros_geracao", {}).get("pre_producao", {})
+
+ if not scenes_list or not ref_image_paths:
+ logger.warning("Planner3D: Nenhuma cena ou imagem de referência encontrada no DNA.")
+ yield {"chat": chat_history, "status": "keyframes_complete"}
+ return
+
+ # Mapeamento fixo de imagens de referência
+ ref_id_to_path_map = {i: path for i, path in enumerate(ref_image_paths)}
+ available_ref_ids = list(ref_id_to_path_map.keys())
+
+ # 2. Loop de cenas
+ for scene_idx, scene_data in enumerate(scenes_list):
+ scene_id = scene_data.get("id")
+ chat_history.append({
+ "role": "Planner3D",
+ "content": f"Desenhando a Cena {scene_id}/{len(scenes_list)}..."
+ })
+ yield {"chat": chat_history}
+
+ storyboard_da_cena = [ato.get("resumo_ato", "") for ato in scene_data.get("atos", [])]
+ if not storyboard_da_cena:
+ logger.info(f"Planner3D: Cena {scene_id} sem atos, pulando.")
+ continue
+
+ # 3. Cria ordem de serviço
+ job = KeyframeGenerationJob(
+ storyboard=storyboard_da_cena,
+ global_prompt=global_prompt,
+ ref_image_paths=ref_image_paths,
+ ref_id_to_path_map=ref_id_to_path_map,
+ available_ref_ids=available_ref_ids,
+ keyframe_prefix=f"scene_{scene_id:02d}",
+ params=pre_prod_params
+ )
+
+ # 4. Delega para o Painter
+ scene_keyframes = painter.generate_keyframes_from_job(job=job)
+
+ # 5. Injeta diretamente no DNA
+ scene_data["keyframes"] = scene_keyframes
+
+ if scene_keyframes:
+ chat_history.append({
+ "role": "Planner3D",
+ "content": f"Cena {scene_id} concluída ({len(scene_keyframes)} keyframes)."
+ })
+ yield {"chat": chat_history}
+
+ logger.info("Planner3D: Geração de todos os keyframes concluída.")
+
+ yield {
+ "chat": chat_history,
+ "gallery": [kf["caminho_pixel"] for scene in scenes_list for kf in scene.get("keyframes", [])],
+ "status": "keyframes_complete",
+ "dna": generation_state
+ }
+
+planner_3d_singleton = Planner3D()
diff --git a/aduc_framework/engineers/planner_4d.py b/aduc_framework/engineers/planner_4d.py
new file mode 100644
index 0000000000000000000000000000000000000000..f1795a06dc38fc866c97ee5df258ab9c2386d06e
--- /dev/null
+++ b/aduc_framework/engineers/planner_4d.py
@@ -0,0 +1,176 @@
+# aduc_framework/engineers/planner_4d.py
+#
+# Copyright (C) August 4, 2025 Carlos Rodrigues dos Santos
+#
+# Versão 6.5.0 (Montagem com Pontes de Transição)
+#
+# - Implementa uma nova etapa de pós-produção antes da concatenação final.
+# - Para cada par de clipes de cena, o planejador agora extrai o último frame
+# do primeiro clipe e o primeiro frame do segundo.
+# - Usa esses frames para gerar um pequeno vídeo de "ponte de transição".
+# - O filme final é montado intercalando os clipes originais com essas novas
+# transições, resultando em um produto final mais suave e profissional.
+
+import logging
+import os
+import time
+from typing import List, Dict, Any, Generator
+
+from ..types import VideoGenerationJob, VideoData
+from ..tools.video_encode_tool import video_encode_tool_singleton
+
+logger = logging.getLogger(__name__)
+
+class Planner4D:
+ """
+ Atua como o Diretor de Fotografia, orquestrando a renderização de cenas
+ e a montagem final com transições inteligentes.
+ """
+ def _quantize_to_multiple(self, n: int, m: int) -> int:
+ if m == 0: return n
+ quantized = int(round(n / m) * m)
+ return m if n > 0 and quantized == 0 else quantized
+
+ def produce_movie_by_scene(
+ self,
+ generation_state: Dict[str, Any],
+ initial_chat_history: List[Dict[str, Any]]
+ ) -> Generator[Dict[str, Any], None, None]:
+
+ from .deformes4D import deformes4d_engine_singleton as editor
+
+ workspace_dir = generation_state.get("workspace_dir", "deformes_workspace")
+ editor.initialize(workspace_dir)
+
+ chat_history = initial_chat_history.copy()
+ chat_history.append({"role": "Planner4D", "content": "Produção iniciada. Renderizando clipes de cena..."})
+ yield {"chat": chat_history}
+
+ scenes = generation_state.get("scenes", [])
+ pre_prod_params = generation_state.get("parametros_geracao", {}).get("pre_producao", {})
+ prod_params = generation_state.get("parametros_geracao", {}).get("producao", {})
+ global_prompt = generation_state.get("prompt_geral", "")
+
+ FPS = 24
+ FRAMES_PER_LATENT_CHUNK = 8
+ seconds_per_fragment = pre_prod_params.get('duration_per_fragment', 4.0)
+ trim_percent = prod_params.get('trim_percent', 50)
+
+ total_frames_brutos_pixels = self._quantize_to_multiple(int(seconds_per_fragment * FPS), FRAMES_PER_LATENT_CHUNK)
+ pixels_a_podar = self._quantize_to_multiple(int(total_frames_brutos_pixels * (trim_percent / 100)), FRAMES_PER_LATENT_CHUNK)
+ latent_frames_a_podar = pixels_a_podar // FRAMES_PER_LATENT_CHUNK
+
+ all_scene_clips_paths: List[str] = []
+
+ # --- ETAPA 1: GERAÇÃO DOS CLIPES DE CENA ---
+ for i, scene in enumerate(scenes):
+ # ... (Lógica de geração de job e chamada ao editor permanece a mesma)
+ scene_id = scene.get('id')
+ chat_history.append({"role": "Planner4D", "content": f"Preparando para filmar a Cena {scene_id}/{len(scenes)}..."})
+ yield {"chat": chat_history}
+ storyboard_da_cena = [ato.get("resumo_ato", "") for ato in scene.get("atos", [])]
+ keyframes_para_cena = scene.get("keyframes", [])
+ if len(keyframes_para_cena) < 2:
+ chat_history.append({"role": "Planner4D", "content": f"Cena {scene_id} pulada (keyframes insuficientes)."})
+ yield {"chat": chat_history}
+ continue
+ job = VideoGenerationJob(
+ scene_id=scene_id, global_prompt=global_prompt, storyboard=storyboard_da_cena,
+ keyframe_paths=[kf['caminho_pixel'] for kf in keyframes_para_cena],
+ video_resolution=pre_prod_params.get('resolution', 480),
+ handler_strength=prod_params.get('handler_strength', 0.5),
+ destination_convergence_strength=prod_params.get('destination_convergence_strength', 0.75),
+ guidance_scale=prod_params.get('guidance_scale', 2.0),
+ stg_scale=prod_params.get('stg_scale', 0.025),
+ num_inference_steps=prod_params.get('inference_steps', 20),
+ total_frames_brutos=total_frames_brutos_pixels, latents_a_podar=pixels_a_podar,
+ latent_frames_a_podar=latent_frames_a_podar,
+ DEJAVU_FRAME_TARGET=pixels_a_podar - 1 if pixels_a_podar > 0 else 0,
+ DESTINATION_FRAME_TARGET=total_frames_brutos_pixels - 1,
+ )
+ clip_result = editor.generate_movie_clip_from_job(job=job)
+ if clip_result and clip_result.get("final_path"):
+ final_clip_path = clip_result["final_path"]
+ all_scene_clips_paths.append(final_clip_path)
+ video_data_obj = VideoData(**clip_result["video_data"]).model_dump()
+ if "videos" not in generation_state["scenes"][i]:
+ generation_state["scenes"][i]["videos"] = []
+ generation_state["scenes"][i]["videos"].append(video_data_obj)
+ chat_history.append({"role": "Planner4D", "content": f"Cena {scene_id} filmada com sucesso!"})
+ yield {"chat": chat_history, "final_video_path": final_clip_path, "dna": generation_state}
+
+ if not all_scene_clips_paths:
+ chat_history.append({"role": "Planner4D", "content": "Nenhum clipe de cena foi gerado."})
+ yield {"chat": chat_history, "status": "production_complete"}
+ return
+
+ # --- ETAPA 2: CRIAÇÃO DE PONTES DE TRANSIÇÃO (NOVA LÓGICA) ---
+ chat_history.append({"role": "Planner4D", "content": "Todas as cenas filmadas. Criando transições suaves..."})
+ yield {"chat": chat_history}
+
+ final_concat_list = []
+ temp_frames_to_delete = []
+
+ if len(all_scene_clips_paths) > 1:
+ # Adiciona o primeiro clipe e entra no loop para criar pontes
+ final_concat_list.append(all_scene_clips_paths[0])
+ for i in range(len(all_scene_clips_paths) - 1):
+ clip_a_path = all_scene_clips_paths[i]
+ clip_b_path = all_scene_clips_paths[i+1]
+
+ # Define caminhos para os frames temporários
+ last_frame_path = os.path.join(workspace_dir, f"temp_last_frame_{i}.png")
+ first_frame_path = os.path.join(workspace_dir, f"temp_first_frame_{i+1}.png")
+ temp_frames_to_delete.extend([last_frame_path, first_frame_path])
+
+ # Extrai os frames
+ video_encode_tool_singleton.extract_last_frame(clip_a_path, last_frame_path)
+ video_encode_tool_singleton.extract_first_frame(clip_b_path, first_frame_path)
+
+ # Cria a ponte de transição
+ bridge_video_path = video_encode_tool_singleton.create_transition_bridge(
+ start_image_path=last_frame_path,
+ end_image_path=first_frame_path,
+ duration=0.3, # 1 segundo de transição
+ fps=FPS,
+ target_resolution=(pre_prod_params.get('resolution', 480), pre_prod_params.get('resolution', 480)),
+ workspace_dir=workspace_dir
+ )
+
+ # Adiciona a ponte e o próximo clipe à lista de montagem
+ final_concat_list.append(bridge_video_path)
+ final_concat_list.append(clip_b_path)
+ else:
+ # Se houver apenas um clipe, não há transições a criar
+ final_concat_list = all_scene_clips_paths
+
+ # --- ETAPA 3: MONTAGEM FINAL ---
+ chat_history.append({"role": "Planner4D", "content": "Transições criadas. Montando o filme final..."})
+ yield {"chat": chat_history}
+
+ final_video_path = video_encode_tool_singleton.concatenate_videos(
+ video_paths=final_concat_list,
+ output_path=f"{workspace_dir}/filme_final_com_transicoes.mp4",
+ workspace_dir=workspace_dir
+ )
+
+ # Limpa os frames temporários
+ for frame_path in temp_frames_to_delete:
+ if os.path.exists(frame_path):
+ os.remove(frame_path)
+
+ # Atualiza o DNA com o resultado final
+ final_movie_data = VideoData(id=0, caminho_pixel=final_video_path, prompt_video=[]).model_dump()
+ generation_state["filme_final"] = final_movie_data
+ generation_state["chat_history"] = chat_history
+ chat_history.append({"role": "Maestro", "content": "Produção concluída! O filme final está pronto."})
+
+ logger.info(f"Planner4D: Produção finalizada. Enviando filme '{final_video_path}' para a UI.")
+ yield {
+ "chat": chat_history,
+ "final_video_path": final_video_path,
+ "status": "production_complete",
+ "dna": generation_state
+ }
+
+planner_4d_singleton = Planner4D()
\ No newline at end of file
diff --git a/aduc_framework/engineers/planner_5D.py b/aduc_framework/engineers/planner_5D.py
new file mode 100644
index 0000000000000000000000000000000000000000..89984ccad335fe14740b79d4c8907bf4701ca396
--- /dev/null
+++ b/aduc_framework/engineers/planner_5D.py
@@ -0,0 +1,143 @@
+# aduc_framework/engineers/planner_5D.py
+#
+# Versão 1.1.0 (Diretor de Produção Alinhado)
+# Copyright (C) August 4, 2025 Carlos Rodrigues dos Santos
+#
+# - Versão finalizada e alinhada com os especialistas Deformes v12+ e VaeManager v2.
+# - Cria as Ordens de Serviço (Jobs) usando as definições mais recentes de `types.py`.
+# - Delega os cálculos técnicos (ex: poda de frames) para os especialistas,
+# focando-se na orquestração de alto nível e no gerenciamento do loop de feedback visual.
+
+import logging
+import os
+from typing import Generator, Dict, Any
+
+# Importa os especialistas que serão dirigidos
+from ..engineers.deformes3D import deformes3d_engine_singleton as Deformes3D
+from ..engineers.deformes4D import deformes4d_engine_singleton as Deformes4D
+from ..tools.video_encode_tool import video_encode_tool_singleton as VideoTool
+
+# Importa as estruturas de dados (o "DNA" e as "Ordens de Serviço")
+from ..types import (
+ GenerationState,
+ KeyframeGenerationJob,
+ VideoGenerationJob,
+ KeyframeData,
+ VideoData
+)
+
+logger = logging.getLogger(__name__)
+
+class Planner5D:
+ """
+ Atua como o Diretor de Produção. Orquestra a geração de keyframes e vídeos
+ cena a cena, implementando um loop de feedback para garantir continuidade visual.
+ """
+ def __init__(self):
+ self.dna: GenerationState | None = None
+ self.workspace: str | None = None
+ self.production_params: Dict[str, Any] = {}
+ self.pre_prod_params: Dict[str, Any] = {}
+
+ def produce_movie_by_scene(self, dna: GenerationState) -> Generator[GenerationState, None, None]:
+ """
+ Ponto de entrada para a produção do filme. Executa o loop de produção cena a cena.
+ """
+ self.dna = dna
+ self.workspace = self.dna.workspace_dir
+
+ if not (self.dna.parametros_geracao and self.dna.parametros_geracao.pre_producao and self.dna.parametros_geracao.producao):
+ raise ValueError("Parâmetros de pré-produção ou produção ausentes no DNA. O processo não pode continuar.")
+
+ self.pre_prod_params = self.dna.parametros_geracao.pre_producao.model_dump()
+ self.production_params = self.dna.parametros_geracao.producao.model_dump()
+
+ Deformes3D.initialize(self.workspace)
+ Deformes4D.initialize(self.workspace)
+
+ all_final_scene_clips = []
+ last_scene_final_frame_path = None
+
+ self.dna.chat_history.append({"role": "Planner5D", "content": "Ok, storyboard recebido. Iniciando a produção do filme, cena por cena..."})
+ yield self.dna
+
+ for scene_idx, scene in enumerate(self.dna.storyboard_producao):
+ scene_title = scene.titulo_cena or f"Cena {scene.id_cena}"
+ logger.info(f"--- PLANNER 5D: Iniciando Cena {scene.id_cena}: '{scene_title}' ---")
+ self.dna.chat_history.append({"role": "Planner5D", "content": f"Preparando para filmar a Cena {scene.id_cena}: '{scene_title}'..."})
+ yield self.dna
+
+ # ETAPA 1: GERAÇÃO DE KEYFRAMES
+ reference_paths = [ref.caminho for ref in self.dna.midias_referencia if ref.caminho]
+ ref_id_to_path_map = {i: path for i, path in enumerate(reference_paths)}
+
+ keyframe_job = KeyframeGenerationJob(
+ storyboard=[ato.NARRATIVA_VISUAL for ato in scene.atos],
+ global_prompt=self.dna.texto_global_historia or "",
+ ref_image_paths=reference_paths,
+ ref_id_to_path_map=ref_id_to_path_map,
+ available_ref_ids=list(ref_id_to_path_map.keys()),
+ keyframe_prefix=f"s{scene.id_cena:02d}",
+ params=self.pre_prod_params
+ )
+ generated_keyframes_data = Deformes3D.generate_keyframes_from_job(keyframe_job)
+ self.dna.storyboard_producao[scene_idx].keyframes = [KeyframeData(**kf) for kf in generated_keyframes_data]
+ self.dna.chat_history.append({"role": "Planner5D", "content": f"Cena {scene.id_cena}: {len(generated_keyframes_data)} keyframes criados."})
+ yield self.dna
+
+
+ for scene_idx, scene in enumerate(self.dna.storyboard_producao):
+ scene_title = scene.titulo_cena or f"Cena {scene.id_cena}"
+ logger.info(f"--- PLANNER 5D: Iniciando Gravação de Cena {scene.id_cena}: '{scene_title}' ---")
+ self.dna.chat_history.append({"role": "Planner5D", "content": f"Filmando a Cena {scene.id_cena}: '{scene_title}'..."})
+ yield self.dna
+
+ # ETAPA 2: GERAÇÃO DO VÍDEO
+ if len(generated_keyframes_data) < 1:
+ logger.warning(f"Cena {scene.id_cena} tem menos de 1 keyframes. Pulando geração de vídeo.")
+ self.dna.chat_history.append({"role": "Planner5D", "content": f"AVISO: Cena {scene.id_cena} não pôde ser filmada (keyframes insuficientes)."})
+ yield self.dna
+ continue
+
+ self.dna.chat_history.append({"role": "Planner5D", "content": f"Cena {scene.id_cena}: Luz, câmera, ação! Gerando o clipe de vídeo..."})
+ yield self.dna
+
+ # Criando a Ordem de Serviço para Deformes4D com os parâmetros de alto nível
+ video_job = VideoGenerationJob(
+ scene_id=scene.id_cena,
+ global_prompt=self.dna.texto_global_historia or "",
+ storyboard=[ato.NARRATIVA_VISUAL for ato in scene.atos],
+ keyframe_paths=[kf['caminho_pixel'] for kf in generated_keyframes_data],
+ **self.pre_prod_params,
+ **self.production_params
+ )
+
+ video_result = Deformes4D.generate_movie_clip_from_job(video_job)
+ scene_clip_path = video_result.get("final_path")
+
+ if scene_clip_path:
+ all_final_scene_clips.append(scene_clip_path)
+ video_data = video_result.get("video_data", {})
+ self.dna.storyboard_producao[scene_idx].video_gerado = VideoData(**video_data)
+ self.dna.caminho_filme_final_bruto = scene_clip_path
+ self.dna.chat_history.append({"role": "Planner5D", "content": f"Cena {scene.id_cena} filmada! O resultado será usado como ponto de partida para a próxima cena."})
+ yield self.dna
+
+ # ETAPA FINAL: MONTAGEM DO FILME
+ if not all_final_scene_clips:
+ self.dna.chat_history.append({"role": "Planner5D", "content": "Produção falhou. Nenhum clipe de vídeo foi gerado."})
+ yield self.dna
+ return
+
+ self.dna.chat_history.append({"role": "Planner5D", "content": "Todas as cenas foram filmadas. Iniciando a montagem final do filme..."})
+ yield self.dna
+
+ final_movie_path = os.path.join(self.workspace, "filme_final.mp4")
+ final_movie_path = VideoTool.concatenate_videos(all_final_scene_clips, final_movie_path, self.workspace)
+
+ self.dna.caminho_filme_final_bruto = final_movie_path
+ self.dna.chat_history.append({"role": "Maestro", "content": "Produção concluída! O filme final está pronto para ser assistido."})
+ yield self.dna
+
+# --- Instância Singleton ---
+planner_5d_singleton = Planner5D()
\ No newline at end of file
diff --git a/aduc_framework/engineers/prompt_engine.py b/aduc_framework/engineers/prompt_engine.py
new file mode 100644
index 0000000000000000000000000000000000000000..a42331c1ee6a11cd1b478e05519ebe819df6d627
--- /dev/null
+++ b/aduc_framework/engineers/prompt_engine.py
@@ -0,0 +1,110 @@
+# aduc_framework/engineers/prompt_engine.py
+#
+# Copyright (C) August 4, 2025 Carlos Rodrigues dos Santos
+#
+# Versão 3.0.0 (Provider-Aware Prompt Translator)
+#
+# O PromptEngine atua como o tradutor entre a lógica de tarefa agnóstica
+# do Composer e o formato de prompt específico exigido por um LLM.
+# Esta versão é ciente do provedor (Llama, Gemini, etc.) e aplica os
+# templates de formatação apenas quando necessário (ex: para o Llama),
+# usando um prompt genérico direto para outros (ex: Gemini).
+
+import logging
+from pathlib import Path
+from typing import Dict
+
+logger = logging.getLogger(__name__)
+
+class PromptEngine:
+ """
+ O PromptEngine traduz prompts genéricos para o formato específico do
+ modelo de linguagem alvo. Ele seleciona o template correto com base
+ no provedor de LLM ativo e na presença de imagens na requisição.
+ """
+ def __init__(self):
+ """
+ Inicializa o PromptEngine em um estado "em espera". O provedor
+ e os templates são carregados posteriormente pelo Composer.
+ """
+ self.provider: str | None = None
+ self.model_map_name: str = "llama_3_2_vision" # Padrão para Llama
+ self.template_with_image: str | None = None
+ self.template_text_only: str | None = None
+ logger.info("PromptEngine inicializado (aguardando configuração do provedor pelo Composer).")
+
+ def _load_model_template(self, map_name: str, template_file: str) -> str:
+ """
+ Carrega um arquivo de template de um mapa de modelo específico.
+ """
+ map_path = Path(__file__).resolve().parent.parent / "prompts" / "model_maps" / map_name / template_file
+ if not map_path.is_file():
+ raise FileNotFoundError(f"Template de modelo '{template_file}' não encontrado no mapa '{map_name}' em: {map_path}")
+
+ with open(map_path, 'r', encoding='utf-8') as f:
+ return f.read()
+
+ def set_provider(self, provider: str):
+ """
+ Configura o provedor de LLM ativo (ex: 'llama_multimodal', 'gemini')
+ e carrega os templates de formatação específicos, se necessário.
+ Este método é chamado pelo Composer durante sua inicialização.
+ """
+ if self.provider == provider:
+ return # Evita recarregamentos desnecessários
+
+ self.provider = provider
+ logger.info(f"PromptEngine: Provedor de LLM definido como '{self.provider}'.")
+
+ # Carrega os templates específicos do Llama apenas se ele for o provedor.
+ # Para o Gemini, nenhum template é necessário, então os atributos permanecem None.
+ if self.provider == 'llama_multimodal':
+ logger.info(f"Carregando templates para o mapa de modelo '{self.model_map_name}'...")
+ self.template_with_image = self._load_model_template(self.model_map_name, "image_template.txt")
+ self.template_text_only = self._load_model_template(self.model_map_name, "text_template.txt")
+ else:
+ self.template_with_image = None
+ self.template_text_only = None
+
+ def translate(self, generic_prompt_content: str, has_image: bool) -> str:
+ """
+ Envolve o conteúdo do prompt genérico com o template específico do modelo,
+ mas somente se o provedor ativo (Llama) exigir. Para provedores como o
+ Gemini, retorna o prompt genérico sem modificação.
+
+ Args:
+ generic_prompt_content (str): O conteúdo do prompt agnóstico gerado pelo Composer.
+ has_image (bool): Sinaliza se a tarefa atual inclui um contexto visual.
+
+ Returns:
+ str: O prompt final, formatado e pronto para ser enviado ao LLM.
+ """
+ if self.provider is None:
+ raise RuntimeError("PromptEngine: O provedor não foi definido. Chame set_provider() antes de usar.")
+
+ # --- LÓGICA CONDICIONAL ---
+ # Se o provedor for Gemini, ele usa o "prompt padrão genérico" sem modificação.
+ if self.provider == 'gemini':
+ logger.debug("PROMPT ENGINE (Gemini): Retornando prompt genérico sem aplicar template.")
+ return generic_prompt_content
+
+ # A lógica original do Llama é executada para o provedor padrão ('llama_multimodal')
+ logger.debug(f"--- PROMPT ENGINE ({self.provider}): INICIANDO TRADUÇÃO (Imagem: {has_image}) ---")
+
+ template = self.template_with_image if has_image else self.template_text_only
+ if not template:
+ raise RuntimeError(f"PromptEngine: Template para o provedor '{self.provider}' não foi carregado corretamente.")
+
+ try:
+ # Insere o conteúdo genérico dentro do template específico do modelo
+ final_prompt = template.format(generic_prompt_content=generic_prompt_content)
+ logger.debug(f"--- PROMPT ENGINE ({self.provider}): TRADUÇÃO CONCLUÍDA ---")
+ return final_prompt
+ except KeyError as e:
+ logger.error(f"PROMPT ENGINE: Erro de chave durante a tradução! Chave não encontrada: {e}", exc_info=True)
+ logger.error("Verifique se o template do modelo contém apenas o placeholder '{generic_prompt_content}'.")
+ raise e
+
+# --- Instância Singleton ---
+# A instância é criada vazia e será configurada dinamicamente pelo Composer.
+prompt_engine_singleton = PromptEngine()
\ No newline at end of file
diff --git a/aduc_framework/managers/LICENSE b/aduc_framework/managers/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..e6fb40ab269ce532dd06cc34da2f86bc5f5441cd
--- /dev/null
+++ b/aduc_framework/managers/LICENSE
@@ -0,0 +1,25 @@
+# Euia-AducSdr: Uma implementação aberta e funcional da arquitetura ADUC-SDR para geração de vídeo coerente.
+# Copyright (C) 4 de Agosto de 2025 Carlos Rodrigues dos Santos
+#
+# Contato:
+# Carlos Rodrigues dos Santos
+# carlex22@gmail.com
+# Rua Eduardo Carlos Pereira, 4125, B1 Ap32, Curitiba, PR, Brazil, CEP 8102025
+#
+# Repositórios e Projetos Relacionados:
+# GitHub: https://github.com/carlex22/Aduc-sdr
+# Hugging Face (Ltx-SuperTime-60Secondos): https://huggingface.co/spaces/Carlexx/Ltx-SuperTime-60Secondos/
+# Hugging Face (Novinho): https://huggingface.co/spaces/Carlexxx/Novinho/
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
\ No newline at end of file
diff --git a/aduc_framework/managers/LICENSE.txt b/aduc_framework/managers/LICENSE.txt
new file mode 100644
index 0000000000000000000000000000000000000000..261eeb9e9f8b2b4b0d119366dda99c6fd7d35c64
--- /dev/null
+++ b/aduc_framework/managers/LICENSE.txt
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/aduc_framework/managers/NOTICE.md b/aduc_framework/managers/NOTICE.md
new file mode 100644
index 0000000000000000000000000000000000000000..b527ed5135b3218bf86a8ba61c5d2a39c23805f7
--- /dev/null
+++ b/aduc_framework/managers/NOTICE.md
@@ -0,0 +1,60 @@
+# NOTICE
+
+Copyright (C) 2025 Carlos Rodrigues dos Santos. All rights reserved.
+
+---
+
+## Aviso de Propriedade Intelectual e Licenciamento
+
+### **Processo de Patenteamento em Andamento (EM PORTUGUÊS):**
+
+O método e o sistema de orquestração de prompts denominados **ADUC (Automated Discovery and Orchestration of Complex tasks)**, conforme descritos neste documento e implementados neste software, estão atualmente em processo de patenteamento.
+
+O titular dos direitos, Carlos Rodrigues dos Santos, está buscando proteção legal para as inovações chave da arquitetura ADUC, incluindo, mas não se limitando a:
+
+* Fragmentação e escalonamento de solicitações que excedem limites de contexto de modelos de IA.
+* Distribuição inteligente de sub-tarefas para especialistas heterogêneos.
+* Gerenciamento de estado persistido com avaliação iterativa e realimentação para o planejamento de próximas etapas.
+* Planejamento e roteamento sensível a custo, latência e requisitos de qualidade.
+* O uso de "tokens universais" para comunicação agnóstica a modelos.
+
+### **Reconhecimento e Implicações (EM PORTUGUÊS):**
+
+Ao acessar ou utilizar este software e a arquitetura ADUC aqui implementada, você reconhece:
+
+1. A natureza inovadora e a importância da arquitetura ADUC no campo da orquestração de prompts para IA.
+2. Que a essência desta arquitetura, ou suas implementações derivadas, podem estar sujeitas a direitos de propriedade intelectual, incluindo patentes.
+3. Que o uso comercial, a reprodução da lógica central da ADUC em sistemas independentes, ou a exploração direta da invenção sem o devido licenciamento podem infringir os direitos de patente pendente.
+
+---
+
+### **Patent Pending (IN ENGLISH):**
+
+The method and system for prompt orchestration named **ADUC (Automated Discovery and Orchestration of Complex tasks)**, as described herein and implemented in this software, are currently in the process of being patented.
+
+The rights holder, Carlos Rodrigues dos Santos, is seeking legal protection for the key innovations of the ADUC architecture, including, but not limited to:
+
+* Fragmentation and scaling of requests exceeding AI model context limits.
+* Intelligent distribution of sub-tasks to heterogeneous specialists.
+* Persistent state management with iterative evaluation and feedback for planning subsequent steps.
+* Cost, latency, and quality-aware planning and routing.
+* The use of "universal tokens" for model-agnostic communication.
+
+### **Acknowledgement and Implications (IN ENGLISH):**
+
+By accessing or using this software and the ADUC architecture implemented herein, you acknowledge:
+
+1. The innovative nature and significance of the ADUC architecture in the field of AI prompt orchestration.
+2. That the essence of this architecture, or its derivative implementations, may be subject to intellectual property rights, including patents.
+3. That commercial use, reproduction of ADUC's core logic in independent systems, or direct exploitation of the invention without proper licensing may infringe upon pending patent rights.
+
+---
+
+
+**Contato para Consultas:**
+
+Para mais informações sobre a arquitetura ADUC, o status do patenteamento, ou para discutir licenciamento para usos comerciais ou não conformes com a AGPLv3, por favor, entre em contato:
+
+Carlos Rodrigues dos Santos
+carlex22@gmail.com
+Rua Eduardo Carlos Pereira, 4125, B1 Ap32, Curitiba, PR, Brazil, CEP 8102025
\ No newline at end of file
diff --git a/aduc_framework/managers/README.md b/aduc_framework/managers/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..d763079a15ebd18e829bffc4462f82f6ae8ae80b
--- /dev/null
+++ b/aduc_framework/managers/README.md
@@ -0,0 +1,156 @@
+# 🛠️ managers/ - Ferramentas de IA de Terceiros para orquestração ADUC-SDR
+
+Esta pasta contém implementações adaptadas de modelos e utilitários de IA de terceiros, que servem como "especialistas" ou "ferramentas" de baixo nível para a arquitetura ADUC-SDR.
+
+**IMPORTANTE:** O conteúdo desta pasta é de autoria de seus respectivos idealizadores e desenvolvedores originais. Esta pasta **NÃO FAZ PARTE** do projeto principal ADUC-SDR em termos de sua arquitetura inovadora. Ela serve como um repositório para as **dependências diretas e modificadas** que os `Deformes enginers` (os estágios do "foguete" ADUC-SDR) invocam para realizar tarefas específicas (geração de imagem, vídeo, áudio).
+
+As modificações realizadas nos arquivos aqui presentes visam principalmente:
+1. **Adaptação de Interfaces:** Padronizar as interfaces para que se encaixem no fluxo de orquestração do ADUC-SDR.
+2. **Gerenciamento de Recursos:** Integrar lógicas de carregamento/descarregamento de modelos (GPU management) e configurações via arquivos YAML.
+3. **Otimização de Fluxo:** Ajustar as pipelines para aceitar formatos de entrada mais eficientes (ex: tensores pré-codificados em vez de caminhos de mídia, pulando etapas de codificação/decodificação redundantes).
+
+---
+
+## 📄 Licenciamento
+
+O conteúdo original dos projetos listados abaixo é licenciado sob a **Licença Apache 2.0**, ou outra licença especificada pelos autores originais. Todas as modificações e o uso desses arquivos dentro da estrutura `helpers/` do projeto ADUC-SDR estão em conformidade com os termos da **Licença Apache 2.0**.
+
+As licenças originais dos projetos podem ser encontradas nas suas respectivas fontes ou nos subdiretórios `incl_licenses/` dentro de cada módulo adaptado.
+
+---
+
+## 🛠️ API dos Helpers e Guia de Uso
+
+Esta seção detalha como cada helper (agente especialista) deve ser utilizado dentro do ecossistema ADUC-SDR. Todos os agentes são instanciados como **singletons** no `hardware_manager.py` para garantir o gerenciamento centralizado de recursos de GPU.
+
+### **gemini_helpers.py (GeminiAgent)**
+
+* **Propósito:** Atua como o "Oráculo de Síntese Adaptativo", responsável por todas as tarefas de processamento de linguagem natural, como criação de storyboards, geração de prompts, e tomada de decisões narrativas.
+* **Singleton Instance:** `gemini_agent_singleton`
+* **Construtor:** `GeminiAgent()`
+ * Lê `configs/gemini_config.yaml` para obter o nome do modelo, parâmetros de inferência e caminhos de templates de prompt. A chave da API é lida da variável de ambiente `GEMINI_API_KEY`.
+* **Métodos Públicos:**
+ * `generate_storyboard(prompt: str, num_keyframes: int, ref_image_paths: list[str])`
+ * **Inputs:**
+ * `prompt`: A ideia geral do filme (string).
+ * `num_keyframes`: O número de cenas a serem geradas (int).
+ * `ref_image_paths`: Lista de caminhos para as imagens de referência (list[str]).
+ * **Output:** `tuple[list[str], str]` (Uma tupla contendo a lista de strings do storyboard e um relatório textual da operação).
+ * `select_keyframes_from_pool(storyboard: list, base_image_paths: list[str], pool_image_paths: list[str])`
+ * **Inputs:**
+ * `storyboard`: A lista de strings do storyboard gerado.
+ * `base_image_paths`: Imagens de referência base (list[str]).
+ * `pool_image_paths`: O "banco de imagens" de onde selecionar (list[str]).
+ * **Output:** `tuple[list[str], str]` (Uma tupla contendo a lista de caminhos de imagens selecionadas e um relatório textual).
+ * `get_anticipatory_keyframe_prompt(...)`
+ * **Inputs:** Contexto narrativo e visual para gerar um prompt de imagem.
+ * **Output:** `tuple[str, str]` (Uma tupla contendo o prompt gerado para o modelo de imagem e um relatório textual).
+ * `get_initial_motion_prompt(...)`
+ * **Inputs:** Contexto narrativo e visual para a primeira transição de vídeo.
+ * **Output:** `tuple[str, str]` (Uma tupla contendo o prompt de movimento gerado e um relatório textual).
+ * `get_transition_decision(...)`
+ * **Inputs:** Contexto narrativo e visual para uma transição de vídeo intermediária.
+ * **Output:** `tuple[dict, str]` (Uma tupla contendo um dicionário `{"transition_type": "...", "motion_prompt": "..."}` e um relatório textual).
+ * `generate_audio_prompts(...)`
+ * **Inputs:** Contexto narrativo global.
+ * **Output:** `tuple[dict, str]` (Uma tupla contendo um dicionário `{"music_prompt": "...", "sfx_prompt": "..."}` e um relatório textual).
+
+### **flux_kontext_helpers.py (FluxPoolManager)**
+
+* **Propósito:** Especialista em geração de imagens de alta qualidade (keyframes) usando a pipeline FluxKontext. Gerencia um pool de workers para otimizar o uso de múltiplas GPUs.
+* **Singleton Instance:** `flux_kontext_singleton`
+* **Construtor:** `FluxPoolManager(device_ids: list[str], flux_config_file: str)`
+ * Lê `configs/flux_config.yaml`.
+* **Método Público:**
+ * `generate_image(prompt: str, reference_images: list[Image.Image], width: int, height: int, seed: int = 42, callback: callable = None)`
+ * **Inputs:**
+ * `prompt`: Prompt textual para guiar a geração (string).
+ * `reference_images`: Lista de objetos `PIL.Image` como referência visual.
+ * `width`, `height`: Dimensões da imagem de saída (int).
+ * `seed`: Semente para reprodutibilidade (int).
+ * `callback`: Função de callback opcional para monitorar o progresso.
+ * **Output:** `PIL.Image.Image` (O objeto da imagem gerada).
+
+### **dreamo_helpers.py (DreamOAgent)**
+
+* **Propósito:** Especialista em geração de imagens de alta qualidade (keyframes) usando a pipeline DreamO, com capacidades avançadas de edição e estilo a partir de referências.
+* **Singleton Instance:** `dreamo_agent_singleton`
+* **Construtor:** `DreamOAgent(device_id: str = None)`
+ * Lê `configs/dreamo_config.yaml`.
+* **Método Público:**
+ * `generate_image(prompt: str, reference_images: list[Image.Image], width: int, height: int)`
+ * **Inputs:**
+ * `prompt`: Prompt textual para guiar a geração (string).
+ * `reference_images`: Lista de objetos `PIL.Image` como referência visual. A lógica interna atribui a primeira imagem como `style` e as demais como `ip`.
+ * `width`, `height`: Dimensões da imagem de saída (int).
+ * **Output:** `PIL.Image.Image` (O objeto da imagem gerada).
+
+### **ltx_manager_helpers.py (LtxPoolManager)**
+
+* **Propósito:** Especialista na geração de fragmentos de vídeo no espaço latente usando a pipeline LTX-Video. Gerencia um pool de workers para otimizar o uso de múltiplas GPUs.
+* **Singleton Instance:** `ltx_manager_singleton`
+* **Construtor:** `LtxPoolManager(device_ids: list[str], ltx_model_config_file: str, ltx_global_config_file: str)`
+ * Lê o `ltx_global_config_file` e o `ltx_model_config_file` para configurar a pipeline.
+* **Método Público:**
+ * `generate_latent_fragment(**kwargs)`
+ * **Inputs:** Dicionário de keyword arguments (`kwargs`) contendo todos os parâmetros da pipeline LTX, incluindo:
+ * `height`, `width`: Dimensões do vídeo (int).
+ * `video_total_frames`: Número total de frames a serem gerados (int).
+ * `video_fps`: Frames por segundo (int).
+ * `motion_prompt`: Prompt de movimento (string).
+ * `conditioning_items_data`: Lista de objetos `LatentConditioningItem` contendo os tensores latentes de condição.
+ * `guidance_scale`, `stg_scale`, `num_inference_steps`, etc.
+ * **Output:** `tuple[torch.Tensor, tuple]` (Uma tupla contendo o tensor latente gerado e os valores de padding utilizados).
+
+### **mmaudio_helper.py (MMAudioAgent)**
+
+* **Propósito:** Especialista em geração de áudio para um determinado fragmento de vídeo.
+* **Singleton Instance:** `mmaudio_agent_singleton`
+* **Construtor:** `MMAudioAgent(workspace_dir: str, device_id: str = None, mmaudio_config_file: str)`
+ * Lê `configs/mmaudio_config.yaml`.
+* **Método Público:**
+ * `generate_audio_for_video(video_path: str, prompt: str, negative_prompt: str, duration_seconds: float)`
+ * **Inputs:**
+ * `video_path`: Caminho para o arquivo de vídeo silencioso (string).
+ * `prompt`: Prompt textual para guiar a geração de áudio (string).
+ * `negative_prompt`: Prompt negativo para áudio (string).
+ * `duration_seconds`: Duração exata do vídeo (float).
+ * **Output:** `str` (O caminho para o novo arquivo de vídeo com a faixa de áudio integrada).
+
+
+### **seedvr_helpers.py (SeedVrManager)**
+
+* **Propósito:** Especialista em pós-produção de vídeo, aplicando super-resolução com IA (`Video Super-Resolution`) para adicionar detalhes finos, nitidez e texturas realistas a um vídeo já renderizado.
+* **Singleton Instance:** `seedvr_manager_singleton`
+* **Construtor:** `SeedVrManager(workspace_dir: str, device_id: str = None)`
+ * Lê `configs/seedvr_config.yaml`.
+* **Método Público:**
+ * `process_video(input_video_path: str, output_video_path: str, prompt: str, model_version: str = '7B', steps: int = 100, seed: int = 666)`
+ * **Inputs:**
+ * `input_video_path`: Caminho para o vídeo de entrada a ser aprimorado (string).
+ * `output_video_path`: Caminho onde o vídeo finalizado será salvo (string).
+ * `prompt`: Um prompt de estilo geral para guiar o aprimoramento (string).
+ * `model_version`: A versão do modelo a ser usada, '3B' ou '7B' (string).
+ * `steps`: Número de passos de inferência para o processo de aprimoramento (int).
+ * `seed`: Semente para reprodutibilidade (int).
+ * **Output:** `str` (O caminho para o vídeo finalizado em alta definição).
+
+---
+
+## 🔗 Projetos Originais e Atribuições
+(A seção de atribuições e licenças permanece a mesma que definimos anteriormente)
+
+### DreamO
+* **Repositório Original:** [https://github.com/bytedance/DreamO](https://github.com/bytedance/DreamO)
+...
+
+### LTX-Video
+* **Repositório Original:** [https://github.com/Lightricks/LTX-Video](https://github.com/Lightricks/LTX-Video)
+...
+
+### MMAudio
+* **Repositório Original:** [https://github.com/hkchengrex/MMAudio](https://github.com/hkchengrex/MMAudio)
+...
+
+### SeedVr
+* **Repositório Original:** [https://github.com/ByteDance-Seed/SeedVR](https://github.com/ByteDance-Seed/SeedVR)
\ No newline at end of file
diff --git a/aduc_framework/managers/__init__.py b/aduc_framework/managers/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..7dbf8b3b9d4b2974546418eef813f80d39e1e3d1
--- /dev/null
+++ b/aduc_framework/managers/__init__.py
@@ -0,0 +1,25 @@
+# Em: aduc_framework/managers/__init__.py
+
+# Expõe os singletons dos managers de especialistas de baixo nível.
+
+from .gemini_manager import gemini_manager_singleton
+
+# ORDEM CRÍTICA: LTX Manager precisa ser inicializado primeiro, pois o VAE Manager
+# depende dele para obter a instância do modelo VAE.
+from .ltx_manager import ltx_manager_singleton
+from .vae_manager import vae_manager_singleton
+
+from .latent_enhancer_manager import latent_enhancer_specialist_singleton
+from .mmaudio_manager import mmaudio_manager_singleton
+from .seedvr_manager import seedvr_manager_singleton
+from .llama_multimodal_manager import llama_multimodal_manager_singleton
+
+__all__ = [
+ "gemini_manager_singleton",
+ "ltx_manager_singleton",
+ "vae_manager_singleton", # A ordem aqui não importa, apenas a ordem dos imports acima
+ "latent_enhancer_specialist_singleton",
+ "mmaudio_manager_singleton",
+ "seedvr_manager_singleton",
+ "llama_multimodal_manager_singleton",
+]
\ No newline at end of file
diff --git a/aduc_framework/managers/config.yaml b/aduc_framework/managers/config.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..7aab03c427150e2f8091f5f20ba466f1af81239e
--- /dev/null
+++ b/aduc_framework/managers/config.yaml
@@ -0,0 +1,24 @@
+# config.yaml
+# Configuração central para a aplicação Deformes4D e seus especialistas.
+
+application:
+ workspace_dir: "deformes_workspace"
+
+# Configuração para Hugging Face Spaces
+sdk: gradio
+app_file: app.py
+
+specialists:
+ flux:
+ # Define quantas GPUs o pool do Flux deve tentar alocar.
+ # Se não houver GPUs suficientes, o hardware_manager lançará um erro.
+ # Se 0, usará a CPU.
+ gpus_required: 4
+
+ ltx:
+ # Define quantas GPUs o pool do LTX deve tentar alocar.
+ gpus_required: 4
+
+ # Aponta para o arquivo de configuração específico do modelo LTX.
+ # Alterado para usar o modelo 0.9.8-dev.
+ config_file: "ltxv-13b-0.9.8-distilled.yaml"
\ No newline at end of file
diff --git a/aduc_framework/managers/flux_kontext_manager.py b/aduc_framework/managers/flux_kontext_manager.py
new file mode 100644
index 0000000000000000000000000000000000000000..72ac80ede9e2103f97913b60c375c33eb1222ec9
--- /dev/null
+++ b/aduc_framework/managers/flux_kontext_manager.py
@@ -0,0 +1,165 @@
+# flux_kontext_helpers.py (ADUC: O Especialista Pintor - com suporte a callback)
+# AducSdr: Uma implementação aberta e funcional da arquitetura ADUC-SDR
+# Copyright (C) 4 de Agosto de 2025 Carlos Rodrigues dos Santos
+#
+# Contato:
+# Carlos Rodrigues dos Santos
+# carlex22@gmail.com
+# Rua Eduardo Carlos Pereira, 4125, B1 Ap32, Curitiba, PR, Brazil, CEP 8102025
+#
+# Repositórios e Projetos Relacionados:
+# GitHub: https://github.com/carlex22/Aduc-sdr
+#
+#
+# PENDING PATENT NOTICE: Please see NOTICE.md.
+#
+# Version 1.0.1
+
+import torch
+from PIL import Image, ImageOps
+import gc
+from diffusers import FluxKontextPipeline
+import huggingface_hub
+import os
+import threading
+import yaml
+import logging
+
+from ..tools.hardware_manager import hardware_manager
+
+logger = logging.getLogger(__name__)
+
+class FluxWorker:
+ """Representa uma única instância do pipeline FluxKontext em um dispositivo."""
+ def __init__(self, device_id='cuda:0'):
+ self.cpu_device = torch.device('cpu')
+ self.device = torch.device(device_id if torch.cuda.is_available() else 'cpu')
+ self.pipe = None
+ self._load_pipe_to_cpu()
+
+ def _load_pipe_to_cpu(self):
+ if self.pipe is None:
+ logger.info(f"FLUX Worker ({self.device}): Carregando modelo para a CPU...")
+ self.pipe = FluxKontextPipeline.from_pretrained(
+ "black-forest-labs/FLUX.1-Kontext-dev", torch_dtype=torch.bfloat16
+ ).to(self.cpu_device)
+ logger.info(f"FLUX Worker ({self.device}): Modelo pronto na CPU.")
+
+ def to_gpu(self):
+ if self.device.type == 'cpu': return
+ logger.info(f"FLUX Worker: Movendo modelo para a GPU {self.device}...")
+ self.pipe.to(self.device)
+
+ def to_cpu(self):
+ if self.device.type == 'cpu': return
+ logger.info(f"FLUX Worker: Descarregando modelo da GPU {self.device}...")
+ self.pipe.to(self.cpu_device)
+ gc.collect()
+ if torch.cuda.is_available(): torch.cuda.empty_cache()
+
+ def _create_composite_reference(self, images: list[Image.Image], target_width: int, target_height: int) -> Image.Image:
+ if not images: return None
+ valid_images = [img.convert("RGB") for img in images if img is not None]
+ if not valid_images: return None
+ if len(valid_images) == 1:
+ if valid_images[0].size != (target_width, target_height):
+ return ImageOps.fit(valid_images[0], (target_width, target_height), Image.Resampling.LANCZOS)
+ return valid_images[0]
+
+ base_height = valid_images[0].height
+ resized_for_concat = []
+ for img in valid_images:
+ if img.height != base_height:
+ aspect_ratio = img.width / img.height
+ new_width = int(base_height * aspect_ratio)
+ resized_for_concat.append(img.resize((new_width, base_height), Image.Resampling.LANCZOS))
+ else:
+ resized_for_concat.append(img)
+
+ total_width = sum(img.width for img in resized_for_concat)
+ concatenated = Image.new('RGB', (total_width, base_height))
+ x_offset = 0
+ for img in resized_for_concat:
+ concatenated.paste(img, (x_offset, 0))
+ x_offset += img.width
+
+ #final_reference = ImageOps.fit(concatenated, (target_width, target_height), Image.Resampling.LANCZOS)
+ return concatenated
+
+ @torch.inference_mode()
+ def generate_image_internal(self, reference_images: list[Image.Image], prompt: str, target_width: int, target_height: int, seed: int, callback: callable = None):
+ composite_reference = self._create_composite_reference(reference_images, target_width, target_height)
+
+ num_steps = 12 # Valor fixo otimizado
+
+ logger.info(f"\n===== [CHAMADA AO PIPELINE FLUX em {self.device}] =====\n"
+ f" - Prompt: '{prompt}'\n"
+ f" - Resolução: {target_width}x{target_height}, Seed: {seed}, Passos: {num_steps}\n"
+ f" - Nº de Imagens na Composição: {len(reference_images)}\n"
+ f"==========================================")
+
+ generated_image = self.pipe(
+ image=composite_reference,
+ prompt=prompt,
+ guidance_scale=2.5,
+ width=target_width,
+ height=target_height,
+ num_inference_steps=num_steps,
+ generator=torch.Generator(device="cpu").manual_seed(seed),
+ callback_on_step_end=callback,
+ callback_on_step_end_tensor_inputs=["latents"] if callback else None
+ ).images[0]
+
+ return generated_image
+
+class FluxPoolManager:
+ def __init__(self, device_ids):
+ logger.info(f"FLUX POOL MANAGER: Criando workers para os dispositivos: {device_ids}")
+ self.workers = [FluxWorker(device_id) for device_id in device_ids]
+ self.current_worker_index = 0
+ self.lock = threading.Lock()
+ self.last_cleanup_thread = None
+
+ def _cleanup_worker_thread(self, worker):
+ logger.info(f"FLUX CLEANUP THREAD: Iniciando limpeza de {worker.device} em background...")
+ worker.to_cpu()
+
+ def generate_image(self, reference_images, prompt, width, height, seed=42, callback=None):
+ worker_to_use = None
+ try:
+ with self.lock:
+ if self.last_cleanup_thread and self.last_cleanup_thread.is_alive():
+ self.last_cleanup_thread.join()
+ worker_to_use = self.workers[self.current_worker_index]
+ previous_worker_index = (self.current_worker_index - 1 + len(self.workers)) % len(self.workers)
+ worker_to_cleanup = self.workers[previous_worker_index]
+ cleanup_thread = threading.Thread(target=self._cleanup_worker_thread, args=(worker_to_cleanup,))
+ cleanup_thread.start()
+ self.last_cleanup_thread = cleanup_thread
+ worker_to_use.to_gpu()
+ self.current_worker_index = (self.current_worker_index + 1) % len(self.workers)
+
+ logger.info(f"FLUX POOL MANAGER: Gerando imagem em {worker_to_use.device}...")
+ return worker_to_use.generate_image_internal(
+ reference_images=reference_images,
+ prompt=prompt,
+ target_width=width,
+ target_height=height,
+ seed=seed,
+ callback=callback
+ )
+ except Exception as e:
+ logger.error(f"FLUX POOL MANAGER: Erro durante a geração: {e}", exc_info=True)
+ raise e
+ finally:
+ pass
+
+# --- Instanciação Singleton Dinâmica ---
+logger.info("Lendo config.yaml para inicializar o FluxKontext Pool Manager...")
+with open("config.yaml", 'r') as f: config = yaml.safe_load(f)
+hf_token = os.getenv('HF_TOKEN');
+if hf_token: huggingface_hub.login(token=hf_token)
+flux_gpus_required = config['specialists']['flux']['gpus_required']
+flux_device_ids = hardware_manager.allocate_gpus('Flux', flux_gpus_required)
+flux_kontext_singleton = FluxPoolManager(device_ids=flux_device_ids)
+logger.info("Especialista de Imagem (Flux) pronto.")
\ No newline at end of file
diff --git a/aduc_framework/managers/gemini_manager.py b/aduc_framework/managers/gemini_manager.py
new file mode 100644
index 0000000000000000000000000000000000000000..03f0013860f49d133b2bc6232a99fac51a6ed27b
--- /dev/null
+++ b/aduc_framework/managers/gemini_manager.py
@@ -0,0 +1,115 @@
+# aduc_framework/managers/gemini_manager.py
+#
+# Versão 3.0.0 (Com Gerenciamento de Memória Flexível)
+#
+# Esta versão evolui o GeminiManager para suportar conversas com estado
+# (com memória), mantendo a capacidade de operar sem estado.
+# Introduz um gatilho `restart_session=True` para controle explícito
+# sobre o ciclo de vida da memória, evitando contaminação de contexto.
+
+import os
+import logging
+from PIL import Image
+import google.generativeai as genai
+from typing import List, Any, Optional
+
+logger = logging.getLogger(__name__)
+
+class GeminiManager:
+ """
+ Gerencia interações com a API do Google Gemini, com suporte opcional
+ para sessões de chat com memória e um gatilho de reinicialização.
+ """
+ def __init__(self):
+ """
+ Inicializa o manager. Carrega a chave da API e configura o modelo.
+ """
+ self.api_key = os.environ.get("GEMINI_API_KEY")
+ self.model = None
+ self.chat_session = None # Armazena a sessão de chat com memória ativa
+
+ if self.api_key:
+ try:
+ genai.configure(api_key=self.api_key)
+ # Usando um modelo recente e capaz
+ self.model = genai.GenerativeModel('gemini-2.0-flash')
+ logger.info("GeminiManager (V3 com Memória) inicializado com sucesso.")
+ except Exception as e:
+ logger.error(f"Falha ao configurar a API do Gemini. Verifique a chave e as permissões. Erro: {e}")
+ self.model = None
+ else:
+ logger.warning("Variável de ambiente GEMINI_API_KEY não encontrada. GeminiManager está desabilitado.")
+
+ def _check_model(self):
+ """Verificação interna para garantir que o modelo está pronto para uso."""
+ if not self.model:
+ raise RuntimeError("O modelo Gemini não está inicializado. Verifique a chave da API (GEMINI_API_KEY).")
+
+ def process_turn(
+ self,
+ prompt_text: str,
+ image_list: Optional[List[Image.Image]] = None,
+ use_memory: bool = False,
+ restart_session: bool = False
+ ) -> str:
+ """
+ Ponto de entrada principal. Processa uma requisição textual ou multimodal,
+ com gerenciamento de memória opcional.
+
+ Args:
+ prompt_text (str): O prompt textual a ser enviado.
+ image_list (Optional[List[Image.Image]]): Lista de imagens a serem incluídas na requisição.
+ use_memory (bool): Se True, utiliza ou cria uma sessão de chat com memória (stateful).
+ Se False, faz uma chamada única (stateless).
+ restart_session (bool): Se True, força o descarte da sessão de memória atual
+ e o início de uma nova na próxima chamada com `use_memory=True`.
+ """
+ self._check_model()
+
+ # --- Lógica do Gatilho de Reinicialização ---
+ if restart_session and self.chat_session is not None:
+ logger.info("Gatilho de reinicialização acionado. Descartando sessão de chat anterior.")
+ self.chat_session = None
+ # Se o objetivo era apenas reiniciar, podemos retornar sem fazer uma chamada.
+ if not prompt_text:
+ return ""
+
+ # Constrói o conteúdo a ser enviado
+ prompt_parts = []
+ if prompt_text:
+ prompt_parts.append(prompt_text)
+ if image_list:
+ prompt_parts.extend(image_list)
+
+ # Se não houver nada a ser enviado, retorna uma string vazia.
+ if not prompt_parts:
+ return ""
+
+ try:
+ # --- Lógica de Gerenciamento de Memória ---
+ if use_memory:
+ if self.chat_session is None:
+ logger.info("Iniciando nova sessão de chat com memória (stateful).")
+ self.chat_session = self.model.start_chat(history=[])
+
+ logger.info("Enviando mensagem para a sessão de chat com memória...")
+ response = self.chat_session.send_message(prompt_parts)
+ else:
+ # Modo stateless (sem memória)
+ logger.info("Enviando requisição sem memória (stateless)...")
+ response = self.model.generate_content(prompt_parts)
+
+ # Extrai e retorna o texto da resposta
+ response_text = response.text
+ logger.debug(f"Gemini respondeu com texto bruto: {response_text[:500]}...")
+ return response_text
+
+ except Exception as e:
+ logger.error(f"GEMINI_MANAGER: Falha na chamada da API: {e}", exc_info=True)
+ # Em caso de erro na comunicação, é seguro zerar a sessão para evitar um estado corrompido.
+ self.chat_session = None
+ raise RuntimeError(f"Erro na comunicação com a API do Gemini: {e}")
+
+# --- Instância Singleton ---
+# Esta instância única será importada por outros componentes, como o Neura_Link.
+gemini_manager_singleton = GeminiManager()
\ No newline at end of file
diff --git a/aduc_framework/managers/latent_enhancer_manager.py b/aduc_framework/managers/latent_enhancer_manager.py
new file mode 100644
index 0000000000000000000000000000000000000000..dc020c0bcc8a794ec4869c9916390aeb9dbd01d0
--- /dev/null
+++ b/aduc_framework/managers/latent_enhancer_manager.py
@@ -0,0 +1,109 @@
+# latent_enhancer_specialist.py
+# AducSdr: Uma implementação aberta e funcional da arquitetura ADUC-SDR
+# Copyright (C) 4 de Agosto de 2025 Carlos Rodrigues dos Santos
+#
+# Contato:
+# Carlos Rodrigues dos Santos
+# carlex22@gmail.com
+# Rua Eduardo Carlos Pereira, 4125, B1 Ap32, Curitiba, PR, Brazil, CEP 8102025
+#
+# Repositórios e Projetos Relacionados:
+# GitHub: https://github.com/carlex22/Aduc-sdr
+#
+#
+# PENDING PATENT NOTICE: Please see NOTICE.md.
+#
+# Version 1.0.1
+
+import torch
+import logging
+import time
+from diffusers import LTXLatentUpsamplePipeline
+from ..managers.ltx_manager import ltx_manager_singleton
+
+logger = logging.getLogger(__name__)
+
+class LatentEnhancerSpecialist:
+ """
+ Especialista responsável por melhorar a qualidade de tensores latentes,
+ incluindo upscaling espacial e refinamento por denoise.
+ """
+ def __init__(self):
+ self.device = "cuda" if torch.cuda.is_available() else "cpu"
+ self.pipe_upsample = None
+ self.base_vae = None # VAE para o upscaler
+
+ def _lazy_init_upscaler(self):
+ """Inicializa a pipeline de upscaling apenas quando for usada."""
+ if self.pipe_upsample is not None:
+ return
+ try:
+ from diffusers.models.autoencoders import AutoencoderKLLTXVideo
+ self.base_vae = AutoencoderKLLTXVideo.from_pretrained(
+ "linoyts/LTX-Video-spatial-upscaler-0.9.8",
+ subfolder="vae",
+ torch_dtype=torch.float16 if self.device == "cuda" else torch.float32
+ ).to(self.device)
+
+ self.pipe_upsample = LTXLatentUpsamplePipeline.from_pretrained(
+ "linoyts/LTX-Video-spatial-upscaler-0.9.8",
+ vae=self.base_vae,
+ torch_dtype=torch.float16 if self.device == "cuda" else torch.float32
+ ).to(self.device)
+ logger.info("[Enhancer] Pipeline de Upscale carregada com sucesso.")
+ except Exception as e:
+ logger.error(f"[Enhancer] Falha ao carregar pipeline de Upscale: {e}")
+ self.pipe_upsample = None
+
+ @torch.no_grad()
+ def upscale(self, latents: torch.Tensor) -> torch.Tensor:
+ """Aplica o upscaling 2x nos tensores latentes fornecidos."""
+ self._lazy_init_upscaler()
+ if self.pipe_upsample is None:
+ logger.warning("[Enhancer] Pipeline de Upscale indisponível. Retornando latentes originais.")
+ return latents
+ try:
+ logger.info(f"[Enhancer] Recebido shape {latents.shape} para Upscale.")
+ result = self.pipe_upsample(latents=latents, output_type="latent")
+ output_tensor = result.frames
+ logger.info(f"[Enhancer] Upscale concluído. Novo shape: {output_tensor.shape}")
+ return output_tensor
+ except Exception as e:
+ logger.error(f"[Enhancer] Erro durante upscale: {e}", exc_info=True)
+ return latents
+
+ @torch.no_grad()
+ def refine(self, latents: torch.Tensor, fps: int = 24, **kwargs) -> torch.Tensor:
+ """
+ Invoca o LTX Pool Manager para refinar um tensor latente existente.
+ """
+ logger.info(f"[Enhancer] Refinando tensor latente com shape {latents.shape}.")
+
+ main_pipeline_vae = ltx_manager_singleton.workers[0].pipeline.vae
+ video_scale_factor = getattr(main_pipeline_vae.config, 'temporal_scale_factor', 8)
+
+ _, _, num_latent_frames, _, _ = latents.shape
+
+ # --- [CORREÇÃO FINAL E CRÍTICA] ---
+ # A pipeline de refinamento (vid2vid) espera o número de frames de pixels que CORRESPONDE
+ # ao latente existente, SEM a lógica do +1 que ela aplicará internamente.
+ pixel_frames = (num_latent_frames - 1) * video_scale_factor
+
+ final_ltx_params = {
+ "video_total_frames": pixel_frames,
+ "video_fps": fps,
+ "current_fragment_index": int(time.time()),
+ **kwargs
+ }
+
+ refined_latents_tensor, _ = ltx_manager_singleton.refine_latents(latents, **final_ltx_params)
+
+ if refined_latents_tensor is None:
+ logger.warning("[Enhancer] O refinamento falhou. Retornando tensor original não refinado.")
+ return latents
+
+ logger.info(f"[Enhancer] Retornando tensor latente refinado com shape: {refined_latents_tensor.shape}")
+ return refined_latents_tensor
+
+# --- Singleton Global ---
+latent_enhancer_specialist_singleton = LatentEnhancerSpecialist()
\ No newline at end of file
diff --git a/aduc_framework/managers/llama_multimodal_manager.py b/aduc_framework/managers/llama_multimodal_manager.py
new file mode 100644
index 0000000000000000000000000000000000000000..e9b2aedb7ef2a19d4ca2d55c2b74de202e4fcc4f
--- /dev/null
+++ b/aduc_framework/managers/llama_multimodal_manager.py
@@ -0,0 +1,153 @@
+# aduc_framework/managers/llama_multimodal_manager.py
+#
+# Copyright (C) August 4, 2025 Carlos Rodrigues dos Santos
+#
+# Versão 1.3.0 (Comprehensive Logging & Stable Attention)
+#
+# Manager especialista em conversas multimodais. Esta versão adiciona
+# logging detalhado em todos os pontos críticos para garantir que não haja
+# falhas silenciosas e para fornecer visibilidade total do fluxo de dados.
+# Opera de forma stateless, recebendo prompts completos a cada chamada.
+
+import yaml
+import os
+import logging
+import torch
+from PIL import Image
+from typing import List, Dict, Any, Optional
+import json
+
+from transformers import MllamaForConditionalGeneration, MllamaProcessor
+from huggingface_hub import HfFolder
+
+from ..tools.hardware_manager import hardware_manager
+
+# Logger específico para este manager
+logger = logging.getLogger(__name__)
+
+class LlamaMultiModalManager:
+ """
+ Gerencia uma única instância do Llama 3.2 Vision, com logging robusto
+ para rastrear todo o ciclo de vida de uma requisição. Opera de forma stateless.
+ """
+ def __init__(self, config: dict):
+ logger.debug("LLAMA_MANAGER: Iniciando __init__.")
+ self.hf_token = os.getenv("HF_TOKEN") or HfFolder.get_token()
+ if not self.hf_token:
+ raise ValueError("Token da Hugging Face não encontrado. Faça login via `huggingface-cli login` ou defina a variável de ambiente HF_TOKEN.")
+
+ self.model_id = config['model_id']
+ self.max_new_tokens = config.get('max_new_tokens', 8096)
+ self.temperature = config.get('temperature', 0.9)
+ self.top_p = config.get('top_p', 0.9)
+ self.max_image_size = (480, 480)
+
+ logger.info(f"LLAMA_MANAGER: Carregando processador do modelo: {self.model_id}...")
+ self.processor = MllamaProcessor.from_pretrained(self.model_id, token=self.hf_token)
+ logger.info("LLAMA_MANAGER: Processador carregado.")
+
+ logger.info(f"LLAMA_MANAGER: Carregando modelo base: {self.model_id}...")
+ # A implementação de atenção padrão é usada para máxima compatibilidade.
+ self.model = MllamaForConditionalGeneration.from_pretrained(
+ self.model_id,
+ torch_dtype=torch.bfloat16,
+ device_map="auto",
+ token=self.hf_token
+ )
+ logger.info("LLAMA_MANAGER: Modelo carregado e mapeado para o dispositivo.")
+ logger.debug("LLAMA_MANAGER: __init__ concluído.")
+
+ def _preprocess_image(self, image: Image.Image) -> Image.Image:
+ """Garante que a imagem esteja no formato RGB e dentro do tamanho máximo."""
+ logger.debug(f"Pré-processando imagem. Tamanho original: {image.size}, Modo: {image.mode}")
+ img = image.convert("RGB")
+ if img.width > self.max_image_size[0] or img.height > self.max_image_size[1]:
+ original_size = img.size
+ img.thumbnail(self.max_image_size, Image.Resampling.LANCZOS)
+ logger.debug(f"Imagem redimensionada de {original_size} para {img.size}.")
+ return img
+
+ @torch.inference_mode()
+ def process_turn(self, prompt_text: str, image_list: Optional[List[Image.Image]] = None) -> str:
+ """
+ Ponto de entrada para processar uma requisição. Lida com a orquestração
+ interna e o tratamento de exceções.
+ """
+ logger.info(f"LLAMA_MANAGER: Recebido novo turno. Comprimento do prompt: {len(prompt_text)}, Imagens: {len(image_list) if image_list else 0}.")
+ image_list = image_list or []
+
+ try:
+ # Prepara a imagem (se houver)
+ processed_image = self._preprocess_image(image_list[0]) if image_list else None
+
+ # Gera a resposta
+ assistant_response_text = self._generate_response(prompt_text, processed_image)
+
+ logger.info("LLAMA_MANAGER: Turno processado com sucesso.")
+ return assistant_response_text
+
+ except Exception as e:
+ logger.error(f"LLAMA_MANAGER: ERRO BRUTO DURANTE O PROCESSAMENTO DO TURNO: {e}", exc_info=True)
+ raise e
+
+ def _generate_response(self, prompt_str: str, image: Optional[Image.Image] = None) -> str:
+ """
+ Função de inferência interna: processa, gera e decodifica.
+ """
+ # 1. Processamento da Entrada
+ logger.debug("---> LLAMA_MANAGER: Etapa de Processamento da Entrada Iniciada.")
+ logger.debug(f"Texto do prompt recebido (primeiros 500 chars):\n---\n{prompt_str[:500]}\n---")
+
+ inputs = self.processor(
+ text=prompt_str,
+ images=[image] if image else None,
+ return_tensors="pt"
+ ).to(self.model.device)
+ logger.debug(f"Entrada processada e movida para o dispositivo: {self.model.device}. Shape dos input_ids: {inputs['input_ids'].shape}")
+
+ # 2. Geração do Modelo
+ logger.debug("---> LLAMA_MANAGER: Etapa de Geração do Modelo Iniciada.")
+ generate_ids = self.model.generate(
+ **inputs,
+ max_new_tokens=self.max_new_tokens,
+ do_sample=True,
+ temperature=self.temperature,
+ top_p=self.top_p,
+ )
+ logger.debug(f"Geração concluída. Shape dos IDs de saída: {generate_ids.shape}")
+
+ # 3. Decodificação da Saída
+ logger.debug("---> LLAMA_MANAGER: Etapa de Decodificação da Saída Iniciada.")
+ input_ids_len = inputs['input_ids'].shape[1]
+ output_ids = generate_ids[:, input_ids_len:]
+
+ response_text_raw = self.processor.batch_decode(
+ output_ids, skip_special_tokens=True, clean_up_tokenization_spaces=False
+ )[0]
+
+ logger.debug(f"<--- LLAMA_MANAGER: Resposta bruta decodificada (antes da limpeza):\n---\n{response_text_raw}\n---")
+
+ return response_text_raw.strip()
+
+
+# --- Placeholder e Instanciação Singleton ---
+class LlamaMultiModalPlaceholder:
+ def __init__(self, reason: str = "Motivo desconhecido"):
+ logger.error(f"LlamaMultiModalManager não inicializado. Razão: {reason}. Placeholder em uso.")
+ self.reason = reason
+ def process_turn(self, *args, **kwargs):
+ return json.dumps({"error": f"Especialista Llama MultiModal indisponível. Razão: {self.reason}"})
+
+try:
+ with open("config.yaml", 'r') as f:
+ config = yaml.safe_load(f)
+ llama_config = config['specialists'].get('llama_multimodal')
+ if llama_config and llama_config.get('gpus_required', 0) > 0:
+ hardware_manager.allocate_gpus('LlamaMultiModal', llama_config['gpus_required'])
+ llama_multimodal_manager_singleton = LlamaMultiModalManager(config=llama_config)
+ logger.info("Especialista Llama MultiModal (Stateless) pronto.")
+ else:
+ llama_multimodal_manager_singleton = LlamaMultiModalPlaceholder("Não habilitado ou sem gpus_required na config.yaml")
+except Exception as e:
+ logger.critical(f"Falha CRÍTICA ao inicializar o LlamaMultiModalManager: {e}", exc_info=True)
+ llama_multimodal_manager_singleton = LlamaMultiModalPlaceholder(reason=str(e))
\ No newline at end of file
diff --git a/aduc_framework/managers/ltx_manager.py b/aduc_framework/managers/ltx_manager.py
new file mode 100644
index 0000000000000000000000000000000000000000..d0ec51f0c50d1be083817b4ca541513eac030654
--- /dev/null
+++ b/aduc_framework/managers/ltx_manager.py
@@ -0,0 +1,360 @@
+# aduc_framework/managers/ltx_manager.py
+#
+# Copyright (C) August 4, 2025 Carlos Rodrigues dos Santos
+#
+# Versão 2.5.0 (Suporte a múltiplos LoRAs e inicialização robusta)
+#
+# Este manager é responsável por controlar a pipeline LTX-Video. Ele gerencia
+# um pool de workers para otimizar o uso de múltiplas GPUs, lida com a inicialização
+# e o setup de dependências complexas (clonando o repo LTX de forma segura), e expõe
+# uma interface de alto nível para a geração de vídeo, agora com suporte a uma lista
+# de LoRAs para composição avançada de estilos.
+
+import torch
+import gc
+import os
+import sys
+import yaml
+import logging
+import huggingface_hub
+import time
+import threading
+import subprocess
+import shutil
+from pathlib import Path
+from typing import Optional, List, Tuple, Union
+
+# --- Imports Relativos Corrigidos ---
+from ..types import LatentConditioningItem
+from ..tools.optimization import optimize_ltx_worker, can_optimize_fp8
+from ..tools.hardware_manager import hardware_manager
+
+logger = logging.getLogger(__name__)
+
+# --- Gerenciamento de Dependências e Placeholders ---
+DEPS_DIR = Path("./deps")
+LTX_VIDEO_REPO_DIR = DEPS_DIR / "LTX-Video"
+LTX_VIDEO_REPO_URL = "https://github.com/Lightricks/LTX-Video.git"
+
+# Placeholders para módulos importados tardiamente (lazy-loaded)
+create_ltx_video_pipeline = None
+calculate_padding = None
+LTXVideoPipeline = None
+ConditioningItem = None
+LTXMultiScalePipeline = None
+vae_encode = None
+latent_to_pixel_coords = None
+randn_tensor = None
+
+class LtxPoolManager:
+ """
+ Gerencia um pool de LtxWorkers e expõe a pipeline de aprimoramento de prompt.
+ """
+ def __init__(self, device_ids: List[str], ltx_config_file_name: str):
+ logger.info(f"LTX POOL MANAGER: Criando workers para os dispositivos: {device_ids}")
+ self._ltx_modules_loaded = False
+ self._setup_dependencies()
+ self._lazy_load_ltx_modules()
+
+ self.ltx_config_file = LTX_VIDEO_REPO_DIR / "configs" / ltx_config_file_name
+
+ self.workers = [LtxWorker(dev_id, self.ltx_config_file) for dev_id in device_ids]
+ self.current_worker_index = 0
+ self.lock = threading.Lock()
+
+ self.prompt_enhancement_pipeline = self.workers[0].pipeline if self.workers else None
+ if self.prompt_enhancement_pipeline:
+ logger.info("LTX POOL MANAGER: Pipeline de aprimoramento de prompt exposta para outros especialistas.")
+
+ self._apply_ltx_pipeline_patches()
+
+ if all(w.device.type == 'cuda' for w in self.workers):
+ logger.info("LTX POOL MANAGER: MODO HOT START ATIVADO. Pré-aquecendo todas as GPUs...")
+ for worker in self.workers:
+ worker.to_gpu()
+ logger.info("LTX POOL MANAGER: Todas as GPUs estão prontas.")
+ else:
+ logger.info("LTX POOL MANAGER: Operando em modo CPU ou misto. Pré-aquecimento de GPU pulado.")
+
+
+ def _setup_dependencies(self):
+ """
+ Verifica a integridade do repositório LTX-Video e o clona usando um token de
+ autenticação (se disponível), adicionando-o ao sys.path.
+ """
+ check_file = LTX_VIDEO_REPO_DIR / "README.md"
+
+ if not check_file.exists():
+ logger.warning(f"Repositório LTX-Video parece estar incompleto ou ausente. Tentando um clone limpo...")
+
+ if LTX_VIDEO_REPO_DIR.exists():
+ try:
+ shutil.rmtree(LTX_VIDEO_REPO_DIR)
+ logger.info(f"Diretório corrompido '{LTX_VIDEO_REPO_DIR}' removido.")
+ except OSError as e:
+ logger.error(f"Não foi possível remover o diretório corrompido: {e}")
+ raise RuntimeError("Falha ao limpar dependência corrompida.")
+
+ # --- INÍCIO DA LÓGICA DE AUTENTICAÇÃO ---
+ # Procura pelo token no ambiente (configurado via 'Secrets' no HF Spaces)
+ auth_token = os.getenv("HF_TOKEN")
+ repo_url = LTX_VIDEO_REPO_URL # URL padrão sem autenticação
+
+ if auth_token:
+ logger.info("Token de autenticação (HF_TOKEN) encontrado. Usando URL autenticada para o clone.")
+ # Monta a URL no formato https://@github.com/...
+ repo_url = LTX_VIDEO_REPO_URL.replace("https://", f"https://{auth_token}@")
+ else:
+ logger.warning("Nenhum token de autenticação (HF_TOKEN) encontrado. O clone pode falhar se o repositório exigir login para LFS.")
+ # --- FIM DA LÓGICA DE AUTENTICAÇÃO ---
+
+ logger.info(f"Clonando repositório LTX-Video...")
+ try:
+ DEPS_DIR.mkdir(exist_ok=True)
+ # Usa a `repo_url` que pode ou não conter o token
+ subprocess.run(
+ ["git", "clone", "--depth", "1", repo_url, str(LTX_VIDEO_REPO_DIR), "--quiet"],
+ check=True, capture_output=True, text=True
+ )
+ logger.info("Repositório LTX-Video clonado com sucesso.")
+ except subprocess.CalledProcessError as e:
+ logger.error(f"Falha CRÍTICA ao clonar o repositório LTX-Video. Git stderr: {e.stderr}")
+ raise RuntimeError(f"Não foi possível clonar a dependência LTX-Video. Causa provável: {e.stderr}")
+ else:
+ logger.info("Repositório LTX-Video local encontrado e parece completo.")
+
+ resolved_path = str(LTX_VIDEO_REPO_DIR.resolve())
+ if resolved_path not in sys.path:
+ sys.path.insert(0, resolved_path)
+ logger.info(f"Adicionado '{resolved_path}' ao sys.path.")
+
+
+ def _lazy_load_ltx_modules(self):
+ """Importa dinamicamente os módulos do LTX-Video após garantir que o repositório existe."""
+ if self._ltx_modules_loaded:
+ return
+
+ global create_ltx_video_pipeline, calculate_padding, LTXVideoPipeline, ConditioningItem, LTXMultiScalePipeline
+ global vae_encode, latent_to_pixel_coords, randn_tensor
+
+ from .ltx_pipeline_utils import create_ltx_video_pipeline, calculate_padding
+ from ltx_video.pipelines.pipeline_ltx_video import LTXVideoPipeline, ConditioningItem, LTXMultiScalePipeline
+ from ltx_video.models.autoencoders.vae_encode import vae_encode, latent_to_pixel_coords
+ from diffusers.utils.torch_utils import randn_tensor
+
+ self._ltx_modules_loaded = True
+ logger.info("Módulos do LTX-Video foram carregados dinamicamente.")
+
+ def _apply_ltx_pipeline_patches(self):
+ """Aplica patches em tempo de execução na pipeline LTX para compatibilidade com ADUC-SDR."""
+ logger.info("LTX POOL MANAGER: Aplicando patches ADUC-SDR na pipeline LTX...")
+ for worker in self.workers:
+ worker.pipeline.prepare_conditioning = _aduc_prepare_conditioning_patch.__get__(worker.pipeline, LTXVideoPipeline)
+ logger.info("LTX POOL MANAGER: Todas as instâncias da pipeline foram corrigidas com sucesso.")
+
+ def _get_next_worker(self) -> 'LtxWorker':
+ with self.lock:
+ worker = self.workers[self.current_worker_index]
+ self.current_worker_index = (self.current_worker_index + 1) % len(self.workers)
+ return worker
+
+ def _prepare_pipeline_params(self, worker: 'LtxWorker', **kwargs) -> dict:
+ pipeline_params = {
+ "height": kwargs['height'], "width": kwargs['width'], "num_frames": kwargs['video_total_frames'],
+ "frame_rate": kwargs.get('video_fps', 24),
+ "generator": torch.Generator(device=worker.device).manual_seed(int(time.time()) + kwargs.get('current_fragment_index', 0)),
+ "is_video": True, "vae_per_channel_normalize": True,
+ "prompt": kwargs.get('motion_prompt', ""), "negative_prompt": kwargs.get('negative_prompt', "blurry, distorted, static, bad quality"),
+ "guidance_scale": kwargs.get('guidance_scale', 1.0), "stg_scale": kwargs.get('stg_scale', 0.0),
+ "rescaling_scale": kwargs.get('rescaling_scale', 0.15), "num_inference_steps": kwargs.get('num_inference_steps', 20),
+ "output_type": "latent"
+ }
+ if 'latents' in kwargs:
+ pipeline_params["latents"] = kwargs['latents'].to(worker.device, dtype=worker.pipeline.transformer.dtype)
+ if 'strength' in kwargs:
+ pipeline_params["strength"] = kwargs['strength']
+
+ if 'conditioning_items_data' in kwargs:
+ final_conditioning_items = []
+ for item in kwargs['conditioning_items_data']:
+ item.latent_tensor = item.latent_tensor.to(worker.device)
+ final_conditioning_items.append(item)
+ pipeline_params["conditioning_items"] = final_conditioning_items
+
+ if worker.is_distilled:
+ fixed_timesteps = worker.config.get("first_pass", {}).get("timesteps")
+ if fixed_timesteps:
+ pipeline_params["timesteps"] = fixed_timesteps
+ pipeline_params["num_inference_steps"] = len(fixed_timesteps)
+
+ callback = kwargs.get('callback')
+ if callback:
+ pipeline_params["callback_on_step_end"] = callback
+ pipeline_params["callback_on_step_end_tensor_inputs"] = ["latents"]
+
+ return pipeline_params
+
+ def generate_latent_fragment(self, **kwargs) -> Tuple[torch.Tensor, tuple]:
+ worker_to_use = self._get_next_worker()
+ try:
+ height, width = kwargs['height'], kwargs['width']
+ padded_h, padded_w = ((height - 1) // 32 + 1) * 32, ((width - 1) // 32 + 1) * 32
+ padding_vals = calculate_padding(height, width, padded_h, padded_w)
+ kwargs['height'], kwargs['width'] = padded_h, padded_w
+
+ pipeline_params = self._prepare_pipeline_params(worker_to_use, **kwargs)
+
+ logger.info(f"Iniciando GERAÇÃO em {worker_to_use.device} com shape {padded_w}x{padded_h}")
+
+ if isinstance(worker_to_use.pipeline, LTXMultiScalePipeline):
+ result = worker_to_use.pipeline.video_pipeline(**pipeline_params).images
+ else:
+ result = worker_to_use.generate_video_fragment_internal(**pipeline_params)
+ return result, padding_vals
+ except Exception as e:
+ logger.error(f"LTX POOL MANAGER: Erro durante a geração em {worker_to_use.device}: {e}", exc_info=True)
+ raise e
+ finally:
+ if worker_to_use and worker_to_use.device.type == 'cuda':
+ with torch.cuda.device(worker_to_use.device):
+ gc.collect()
+ torch.cuda.empty_cache()
+
+ def refine_latents(self, latents_to_refine: torch.Tensor, **kwargs) -> Tuple[torch.Tensor, tuple]:
+ pass
+
+class LtxWorker:
+ """Representa uma única instância da pipeline LTX-Video em um dispositivo específico."""
+ def __init__(self, device_id, ltx_config_file):
+ self.cpu_device = torch.device('cpu')
+ self.device = torch.device(device_id if torch.cuda.is_available() else 'cpu')
+ logger.info(f"LTX Worker ({self.device}): Inicializando com config '{ltx_config_file}'...")
+
+ with open(ltx_config_file, "r") as file:
+ self.config = yaml.safe_load(file)
+
+ with open("config.yaml", 'r') as f:
+ global_config = yaml.safe_load(f)
+ lora_config = global_config.get('specialists', {}).get('ltx', {}).get('lora', {})
+
+ self.is_distilled = "distilled" in self.config.get("checkpoint_path", "")
+ models_dir = LTX_VIDEO_REPO_DIR / "models_downloaded"
+
+ logger.info(f"LTX Worker ({self.device}): Preparando para carregar modelo...")
+ model_filename = self.config["checkpoint_path"]
+ model_path = huggingface_hub.hf_hub_download(
+ repo_id="Lightricks/LTX-Video", filename=model_filename,
+ local_dir=str(models_dir), local_dir_use_symlinks=False
+ )
+
+ self.pipeline = create_ltx_video_pipeline(
+ ckpt_path=model_path,
+ precision=self.config["precision"],
+ text_encoder_model_name_or_path=self.config["text_encoder_model_name_or_path"],
+ sampler=self.config["sampler"],
+ device='cpu'
+ )
+
+ if lora_config and isinstance(lora_config, list):
+ logger.info(f"LTX Worker ({self.device}): Encontrados {len(lora_config)} LoRAs para carregar.")
+
+ for lora_item in lora_config:
+ lora_model_id = lora_item.get("model_id")
+ lora_weight = lora_item.get("weight", 0.7)
+
+ if not lora_model_id:
+ logger.warning(f"LTX Worker ({self.device}): Item de LoRA na lista sem 'model_id'. Pulando.")
+ continue
+
+ logger.info(f"LTX Worker ({self.device}): Carregando e aplicando LoRA '{lora_model_id}' com peso {lora_weight}...")
+ try:
+ self.pipeline.load_lora_weights(lora_model_id)
+ self.pipeline.fuse_lora(lora_scale=lora_weight)
+ logger.info(f"LTX Worker ({self.device}): LoRA '{lora_model_id}' fundido ao modelo com sucesso.")
+ except Exception as e:
+ logger.error(f"LTX Worker ({self.device}): Falha ao carregar ou fundir o LoRA '{lora_model_id}'. Erro: {e}", exc_info=True)
+
+ logger.info(f"LTX Worker ({self.device}): Modelo pronto na CPU. É um modelo distilled? {self.is_distilled}")
+
+ def to_gpu(self):
+ if self.device.type == 'cpu': return
+ logger.info(f"LTX Worker: Movendo pipeline para a GPU {self.device}...")
+ self.pipeline.to(self.device)
+ if self.device.type == 'cuda' and can_optimize_fp8():
+ logger.info(f"LTX Worker ({self.device}): GPU com suporte a FP8 detectada. Otimizando...")
+ optimize_ltx_worker(self)
+ logger.info(f"LTX Worker ({self.device}): Otimização completa.")
+
+ def to_cpu(self):
+ if self.device.type == 'cpu': return
+ logger.info(f"LTX Worker: Descarregando pipeline da GPU {self.device}...")
+ self.pipeline.to('cpu')
+ gc.collect()
+ if torch.cuda.is_available(): torch.cuda.empty_cache()
+
+ def generate_video_fragment_internal(self, **kwargs):
+ return self.pipeline(**kwargs).images
+
+def _aduc_prepare_conditioning_patch(
+ self: "LTXVideoPipeline",
+ conditioning_items: Optional[List[Union["ConditioningItem", "LatentConditioningItem"]]],
+ init_latents: torch.Tensor,
+ num_frames: int,
+ height: int,
+ width: int,
+ vae_per_channel_normalize: bool = False,
+ generator=None,
+) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor, int]:
+ if not conditioning_items:
+ init_latents, init_latent_coords = self.patchifier.patchify(latents=init_latents)
+ init_pixel_coords = latent_to_pixel_coords(init_latent_coords, self.vae, causal_fix=self.transformer.config.causal_temporal_positioning)
+ return init_latents, init_pixel_coords, None, 0
+
+ init_conditioning_mask = torch.zeros_like(init_latents[:, 0, ...], dtype=torch.float32, device=init_latents.device)
+ extra_conditioning_latents, extra_conditioning_pixel_coords, extra_conditioning_mask = [], [], []
+ extra_conditioning_num_latents = 0
+
+ for item in conditioning_items:
+ if not isinstance(item, LatentConditioningItem):
+ logger.warning("Patch ADUC: Item de condicionamento não é um LatentConditioningItem e será ignorado.")
+ continue
+
+ media_item_latents = item.latent_tensor.to(dtype=init_latents.dtype, device=init_latents.device)
+ media_frame_number, strength = item.media_frame_number, item.conditioning_strength
+
+ if media_frame_number == 0:
+ f_l, h_l, w_l = media_item_latents.shape[-3:]
+ init_latents[..., :f_l, :h_l, :w_l] = torch.lerp(init_latents[..., :f_l, :h_l, :w_l], media_item_latents, strength)
+ init_conditioning_mask[..., :f_l, :h_l, :w_l] = strength
+ else:
+ noise = randn_tensor(media_item_latents.shape, generator=generator, device=media_item_latents.device, dtype=media_item_latents.dtype)
+ media_item_latents = torch.lerp(noise, media_item_latents, strength)
+ patched_latents, latent_coords = self.patchifier.patchify(latents=media_item_latents)
+ pixel_coords = latent_to_pixel_coords(latent_coords, self.vae, causal_fix=self.transformer.config.causal_temporal_positioning)
+ pixel_coords[:, 0] += media_frame_number
+ extra_conditioning_num_latents += patched_latents.shape[1]
+ new_mask = torch.full(patched_latents.shape[:2], strength, dtype=torch.float32, device=init_latents.device)
+ extra_conditioning_latents.append(patched_latents)
+ extra_conditioning_pixel_coords.append(pixel_coords)
+ extra_conditioning_mask.append(new_mask)
+
+ init_latents, init_latent_coords = self.patchifier.patchify(latents=init_latents)
+ init_pixel_coords = latent_to_pixel_coords(init_latent_coords, self.vae, causal_fix=self.transformer.config.causal_temporal_positioning)
+ init_conditioning_mask, _ = self.patchifier.patchify(latents=init_conditioning_mask.unsqueeze(1))
+ init_conditioning_mask = init_conditioning_mask.squeeze(-1)
+
+ if extra_conditioning_latents:
+ init_latents = torch.cat([*extra_conditioning_latents, init_latents], dim=1)
+ init_pixel_coords = torch.cat([*extra_conditioning_pixel_coords, init_pixel_coords], dim=2)
+ init_conditioning_mask = torch.cat([*extra_conditioning_mask, init_conditioning_mask], dim=1)
+
+ return init_latents, init_pixel_coords, init_conditioning_mask, extra_conditioning_num_latents
+
+# --- Instanciação Singleton ---
+with open("config.yaml", 'r') as f:
+ config = yaml.safe_load(f)
+ltx_gpus_required = config['specialists']['ltx']['gpus_required']
+ltx_device_ids = hardware_manager.allocate_gpus('LTX', ltx_gpus_required)
+ltx_config_filename = config['specialists']['ltx']['config_file']
+ltx_manager_singleton = LtxPoolManager(device_ids=ltx_device_ids, ltx_config_file_name=ltx_config_filename)
+logger.info("Especialista de Vídeo (LTX) pronto.")
\ No newline at end of file
diff --git a/aduc_framework/managers/ltx_pipeline_utils.py b/aduc_framework/managers/ltx_pipeline_utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..0be9213f5016d6559ca3c04e435388069235c88d
--- /dev/null
+++ b/aduc_framework/managers/ltx_pipeline_utils.py
@@ -0,0 +1,774 @@
+import argparse
+import os
+import random
+from datetime import datetime
+from pathlib import Path
+from diffusers.utils import logging
+from typing import Optional, List, Union
+import yaml
+
+import imageio
+import json
+import numpy as np
+import torch
+import cv2
+from safetensors import safe_open
+from PIL import Image
+from transformers import (
+ T5EncoderModel,
+ T5Tokenizer,
+ AutoModelForCausalLM,
+ AutoProcessor,
+ AutoTokenizer,
+)
+from huggingface_hub import hf_hub_download
+
+from ltx_video.models.autoencoders.causal_video_autoencoder import (
+ CausalVideoAutoencoder,
+)
+from ltx_video.models.transformers.symmetric_patchifier import SymmetricPatchifier
+from ltx_video.models.transformers.transformer3d import Transformer3DModel
+from ltx_video.pipelines.pipeline_ltx_video import (
+ ConditioningItem,
+ LTXVideoPipeline,
+ LTXMultiScalePipeline,
+)
+from ltx_video.schedulers.rf import RectifiedFlowScheduler
+from ltx_video.utils.skip_layer_strategy import SkipLayerStrategy
+from ltx_video.models.autoencoders.latent_upsampler import LatentUpsampler
+import ltx_video.pipelines.crf_compressor as crf_compressor
+
+MAX_HEIGHT = 720
+MAX_WIDTH = 1280
+MAX_NUM_FRAMES = 257
+
+logger = logging.get_logger("LTX-Video")
+
+
+def get_total_gpu_memory():
+ if torch.cuda.is_available():
+ total_memory = torch.cuda.get_device_properties(0).total_memory / (1024**3)
+ return total_memory
+ return 44
+
+
+def get_device():
+ if torch.cuda.is_available():
+ return "cuda"
+ elif torch.backends.mps.is_available():
+ return "mps"
+ return "cuda"
+
+
+def load_image_to_tensor_with_resize_and_crop(
+ image_input: Union[str, Image.Image],
+ target_height: int = 512,
+ target_width: int = 768,
+ just_crop: bool = False,
+) -> torch.Tensor:
+ """Load and process an image into a tensor.
+
+ Args:
+ image_input: Either a file path (str) or a PIL Image object
+ target_height: Desired height of output tensor
+ target_width: Desired width of output tensor
+ just_crop: If True, only crop the image to the target size without resizing
+ """
+ if isinstance(image_input, str):
+ image = Image.open(image_input).convert("RGB")
+ elif isinstance(image_input, Image.Image):
+ image = image_input
+ else:
+ raise ValueError("image_input must be either a file path or a PIL Image object")
+
+ input_width, input_height = image.size
+ aspect_ratio_target = target_width / target_height
+ aspect_ratio_frame = input_width / input_height
+ if aspect_ratio_frame > aspect_ratio_target:
+ new_width = int(input_height * aspect_ratio_target)
+ new_height = input_height
+ x_start = (input_width - new_width) // 2
+ y_start = 0
+ else:
+ new_width = input_width
+ new_height = int(input_width / aspect_ratio_target)
+ x_start = 0
+ y_start = (input_height - new_height) // 2
+
+ image = image.crop((x_start, y_start, x_start + new_width, y_start + new_height))
+ if not just_crop:
+ image = image.resize((target_width, target_height))
+
+ image = np.array(image)
+ image = cv2.GaussianBlur(image, (3, 3), 0)
+ frame_tensor = torch.from_numpy(image).float()
+ frame_tensor = crf_compressor.compress(frame_tensor / 255.0) * 255.0
+ frame_tensor = frame_tensor.permute(2, 0, 1)
+ frame_tensor = (frame_tensor / 127.5) - 1.0
+ # Create 5D tensor: (batch_size=1, channels=3, num_frames=1, height, width)
+ return frame_tensor.unsqueeze(0).unsqueeze(2)
+
+
+def calculate_padding(
+ source_height: int, source_width: int, target_height: int, target_width: int
+) -> tuple[int, int, int, int]:
+
+ # Calculate total padding needed
+ pad_height = target_height - source_height
+ pad_width = target_width - source_width
+
+ # Calculate padding for each side
+ pad_top = pad_height // 2
+ pad_bottom = pad_height - pad_top # Handles odd padding
+ pad_left = pad_width // 2
+ pad_right = pad_width - pad_left # Handles odd padding
+
+ # Return padded tensor
+ # Padding format is (left, right, top, bottom)
+ padding = (pad_left, pad_right, pad_top, pad_bottom)
+ return padding
+
+
+def convert_prompt_to_filename(text: str, max_len: int = 20) -> str:
+ # Remove non-letters and convert to lowercase
+ clean_text = "".join(
+ char.lower() for char in text if char.isalpha() or char.isspace()
+ )
+
+ # Split into words
+ words = clean_text.split()
+
+ # Build result string keeping track of length
+ result = []
+ current_length = 0
+
+ for word in words:
+ # Add word length plus 1 for underscore (except for first word)
+ new_length = current_length + len(word)
+
+ if new_length <= max_len:
+ result.append(word)
+ current_length += len(word)
+ else:
+ break
+
+ return "-".join(result)
+
+
+# Generate output video name
+def get_unique_filename(
+ base: str,
+ ext: str,
+ prompt: str,
+ seed: int,
+ resolution: tuple[int, int, int],
+ dir: Path,
+ endswith=None,
+ index_range=1000,
+) -> Path:
+ base_filename = f"{base}_{convert_prompt_to_filename(prompt, max_len=30)}_{seed}_{resolution[0]}x{resolution[1]}x{resolution[2]}"
+ for i in range(index_range):
+ filename = dir / f"{base_filename}_{i}{endswith if endswith else ''}{ext}"
+ if not os.path.exists(filename):
+ return filename
+ raise FileExistsError(
+ f"Could not find a unique filename after {index_range} attempts."
+ )
+
+
+def seed_everething(seed: int):
+ random.seed(seed)
+ np.random.seed(seed)
+ torch.manual_seed(seed)
+ if torch.cuda.is_available():
+ torch.cuda.manual_seed(seed)
+ if torch.backends.mps.is_available():
+ torch.mps.manual_seed(seed)
+
+
+def main():
+ parser = argparse.ArgumentParser(
+ description="Load models from separate directories and run the pipeline."
+ )
+
+ # Directories
+ parser.add_argument(
+ "--output_path",
+ type=str,
+ default=None,
+ help="Path to the folder to save output video, if None will save in outputs/ directory.",
+ )
+ parser.add_argument("--seed", type=int, default="171198")
+
+ # Pipeline parameters
+ parser.add_argument(
+ "--num_images_per_prompt",
+ type=int,
+ default=1,
+ help="Number of images per prompt",
+ )
+ parser.add_argument(
+ "--image_cond_noise_scale",
+ type=float,
+ default=0.15,
+ help="Amount of noise to add to the conditioned image",
+ )
+ parser.add_argument(
+ "--height",
+ type=int,
+ default=704,
+ help="Height of the output video frames. Optional if an input image provided.",
+ )
+ parser.add_argument(
+ "--width",
+ type=int,
+ default=1216,
+ help="Width of the output video frames. If None will infer from input image.",
+ )
+ parser.add_argument(
+ "--num_frames",
+ type=int,
+ default=121,
+ help="Number of frames to generate in the output video",
+ )
+ parser.add_argument(
+ "--frame_rate", type=int, default=30, help="Frame rate for the output video"
+ )
+ parser.add_argument(
+ "--device",
+ default=None,
+ help="Device to run inference on. If not specified, will automatically detect and use CUDA or MPS if available, else CPU.",
+ )
+ parser.add_argument(
+ "--pipeline_config",
+ type=str,
+ default="configs/ltxv-13b-0.9.7-dev.yaml",
+ help="The path to the config file for the pipeline, which contains the parameters for the pipeline",
+ )
+
+ # Prompts
+ parser.add_argument(
+ "--prompt",
+ type=str,
+ help="Text prompt to guide generation",
+ )
+ parser.add_argument(
+ "--negative_prompt",
+ type=str,
+ default="worst quality, inconsistent motion, blurry, jittery, distorted",
+ help="Negative prompt for undesired features",
+ )
+
+ parser.add_argument(
+ "--offload_to_cpu",
+ action="store_true",
+ help="Offloading unnecessary computations to CPU.",
+ )
+
+ # video-to-video arguments:
+ parser.add_argument(
+ "--input_media_path",
+ type=str,
+ default=None,
+ help="Path to the input video (or imaage) to be modified using the video-to-video pipeline",
+ )
+
+ # Conditioning arguments
+ parser.add_argument(
+ "--conditioning_media_paths",
+ type=str,
+ nargs="*",
+ help="List of paths to conditioning media (images or videos). Each path will be used as a conditioning item.",
+ )
+ parser.add_argument(
+ "--conditioning_strengths",
+ type=float,
+ nargs="*",
+ help="List of conditioning strengths (between 0 and 1) for each conditioning item. Must match the number of conditioning items.",
+ )
+ parser.add_argument(
+ "--conditioning_start_frames",
+ type=int,
+ nargs="*",
+ help="List of frame indices where each conditioning item should be applied. Must match the number of conditioning items.",
+ )
+
+ args = parser.parse_args()
+ logger.warning(f"Running generation with arguments: {args}")
+ infer(**vars(args))
+
+
+def create_ltx_video_pipeline(
+ ckpt_path: str,
+ precision: str,
+ text_encoder_model_name_or_path: str,
+ sampler: Optional[str] = None,
+ device: Optional[str] = None,
+ enhance_prompt: bool = False,
+ prompt_enhancer_image_caption_model_name_or_path: Optional[str] = None,
+ prompt_enhancer_llm_model_name_or_path: Optional[str] = None,
+) -> LTXVideoPipeline:
+ ckpt_path = Path(ckpt_path)
+ assert os.path.exists(
+ ckpt_path
+ ), f"Ckpt path provided (--ckpt_path) {ckpt_path} does not exist"
+
+ with safe_open(ckpt_path, framework="pt") as f:
+ metadata = f.metadata()
+ config_str = metadata.get("config")
+ configs = json.loads(config_str)
+ allowed_inference_steps = configs.get("allowed_inference_steps", None)
+
+ vae = CausalVideoAutoencoder.from_pretrained(ckpt_path)
+ transformer = Transformer3DModel.from_pretrained(ckpt_path)
+
+ # Use constructor if sampler is specified, otherwise use from_pretrained
+ if sampler == "from_checkpoint" or not sampler:
+ scheduler = RectifiedFlowScheduler.from_pretrained(ckpt_path)
+ else:
+ scheduler = RectifiedFlowScheduler(
+ sampler=("Uniform" if sampler.lower() == "uniform" else "LinearQuadratic")
+ )
+
+ text_encoder = T5EncoderModel.from_pretrained(
+ text_encoder_model_name_or_path, subfolder="text_encoder"
+ )
+ patchifier = SymmetricPatchifier(patch_size=1)
+ tokenizer = T5Tokenizer.from_pretrained(
+ text_encoder_model_name_or_path, subfolder="tokenizer"
+ )
+
+ transformer = transformer.to(device)
+ vae = vae.to(device)
+ text_encoder = text_encoder.to(device)
+
+ if enhance_prompt:
+ prompt_enhancer_image_caption_model = AutoModelForCausalLM.from_pretrained(
+ prompt_enhancer_image_caption_model_name_or_path, trust_remote_code=True
+ )
+ prompt_enhancer_image_caption_processor = AutoProcessor.from_pretrained(
+ prompt_enhancer_image_caption_model_name_or_path, trust_remote_code=True
+ )
+ prompt_enhancer_llm_model = AutoModelForCausalLM.from_pretrained(
+ prompt_enhancer_llm_model_name_or_path,
+ torch_dtype="bfloat16",
+ )
+ prompt_enhancer_llm_tokenizer = AutoTokenizer.from_pretrained(
+ prompt_enhancer_llm_model_name_or_path,
+ )
+ else:
+ prompt_enhancer_image_caption_model = None
+ prompt_enhancer_image_caption_processor = None
+ prompt_enhancer_llm_model = None
+ prompt_enhancer_llm_tokenizer = None
+
+ vae = vae.to(torch.bfloat16)
+ if precision == "bfloat16" and transformer.dtype != torch.bfloat16:
+ transformer = transformer.to(torch.bfloat16)
+ text_encoder = text_encoder.to(torch.bfloat16)
+
+ # Use submodels for the pipeline
+ submodel_dict = {
+ "transformer": transformer,
+ "patchifier": patchifier,
+ "text_encoder": text_encoder,
+ "tokenizer": tokenizer,
+ "scheduler": scheduler,
+ "vae": vae,
+ "prompt_enhancer_image_caption_model": prompt_enhancer_image_caption_model,
+ "prompt_enhancer_image_caption_processor": prompt_enhancer_image_caption_processor,
+ "prompt_enhancer_llm_model": prompt_enhancer_llm_model,
+ "prompt_enhancer_llm_tokenizer": prompt_enhancer_llm_tokenizer,
+ "allowed_inference_steps": allowed_inference_steps,
+ }
+
+ pipeline = LTXVideoPipeline(**submodel_dict)
+ pipeline = pipeline.to(device)
+ return pipeline
+
+
+def create_latent_upsampler(latent_upsampler_model_path: str, device: str):
+ latent_upsampler = LatentUpsampler.from_pretrained(latent_upsampler_model_path)
+ latent_upsampler.to(device)
+ latent_upsampler.eval()
+ return latent_upsampler
+
+
+def infer(
+ output_path: Optional[str],
+ seed: int,
+ pipeline_config: str,
+ image_cond_noise_scale: float,
+ height: Optional[int],
+ width: Optional[int],
+ num_frames: int,
+ frame_rate: int,
+ prompt: str,
+ negative_prompt: str,
+ offload_to_cpu: bool,
+ input_media_path: Optional[str] = None,
+ conditioning_media_paths: Optional[List[str]] = None,
+ conditioning_strengths: Optional[List[float]] = None,
+ conditioning_start_frames: Optional[List[int]] = None,
+ device: Optional[str] = None,
+ **kwargs,
+):
+ # check if pipeline_config is a file
+ if not os.path.isfile(pipeline_config):
+ raise ValueError(f"Pipeline config file {pipeline_config} does not exist")
+ with open(pipeline_config, "r") as f:
+ pipeline_config = yaml.safe_load(f)
+
+ models_dir = "MODEL_DIR"
+
+ ltxv_model_name_or_path = pipeline_config["checkpoint_path"]
+ if not os.path.isfile(ltxv_model_name_or_path):
+ ltxv_model_path = hf_hub_download(
+ repo_id="Lightricks/LTX-Video",
+ filename=ltxv_model_name_or_path,
+ local_dir=models_dir,
+ repo_type="model",
+ )
+ else:
+ ltxv_model_path = ltxv_model_name_or_path
+
+ spatial_upscaler_model_name_or_path = pipeline_config.get(
+ "spatial_upscaler_model_path"
+ )
+ if spatial_upscaler_model_name_or_path and not os.path.isfile(
+ spatial_upscaler_model_name_or_path
+ ):
+ spatial_upscaler_model_path = hf_hub_download(
+ repo_id="Lightricks/LTX-Video",
+ filename=spatial_upscaler_model_name_or_path,
+ local_dir=models_dir,
+ repo_type="model",
+ )
+ else:
+ spatial_upscaler_model_path = spatial_upscaler_model_name_or_path
+
+ if kwargs.get("input_image_path", None):
+ logger.warning(
+ "Please use conditioning_media_paths instead of input_image_path."
+ )
+ assert not conditioning_media_paths and not conditioning_start_frames
+ conditioning_media_paths = [kwargs["input_image_path"]]
+ conditioning_start_frames = [0]
+
+ # Validate conditioning arguments
+ if conditioning_media_paths:
+ # Use default strengths of 1.0
+ if not conditioning_strengths:
+ conditioning_strengths = [1.0] * len(conditioning_media_paths)
+ if not conditioning_start_frames:
+ raise ValueError(
+ "If `conditioning_media_paths` is provided, "
+ "`conditioning_start_frames` must also be provided"
+ )
+ if len(conditioning_media_paths) != len(conditioning_strengths) or len(
+ conditioning_media_paths
+ ) != len(conditioning_start_frames):
+ raise ValueError(
+ "`conditioning_media_paths`, `conditioning_strengths`, "
+ "and `conditioning_start_frames` must have the same length"
+ )
+ if any(s < 0 or s > 1 for s in conditioning_strengths):
+ raise ValueError("All conditioning strengths must be between 0 and 1")
+ if any(f < 0 or f >= num_frames for f in conditioning_start_frames):
+ raise ValueError(
+ f"All conditioning start frames must be between 0 and {num_frames-1}"
+ )
+
+ seed_everething(seed)
+ if offload_to_cpu and not torch.cuda.is_available():
+ logger.warning(
+ "offload_to_cpu is set to True, but offloading will not occur since the model is already running on CPU."
+ )
+ offload_to_cpu = False
+ else:
+ offload_to_cpu = offload_to_cpu and get_total_gpu_memory() < 30
+
+ output_dir = (
+ Path(output_path)
+ if output_path
+ else Path(f"outputs/{datetime.today().strftime('%Y-%m-%d')}")
+ )
+ output_dir.mkdir(parents=True, exist_ok=True)
+
+ # Adjust dimensions to be divisible by 32 and num_frames to be (N * 8 + 1)
+ height_padded = ((height - 1) // 32 + 1) * 32
+ width_padded = ((width - 1) // 32 + 1) * 32
+ num_frames_padded = ((num_frames - 2) // 8 + 1) * 8 + 1
+
+ padding = calculate_padding(height, width, height_padded, width_padded)
+
+ logger.warning(
+ f"Padded dimensions: {height_padded}x{width_padded}x{num_frames_padded}"
+ )
+
+ prompt_enhancement_words_threshold = pipeline_config[
+ "prompt_enhancement_words_threshold"
+ ]
+
+ prompt_word_count = len(prompt.split())
+ enhance_prompt = (
+ prompt_enhancement_words_threshold > 0
+ and prompt_word_count < prompt_enhancement_words_threshold
+ )
+
+ if prompt_enhancement_words_threshold > 0 and not enhance_prompt:
+ logger.info(
+ f"Prompt has {prompt_word_count} words, which exceeds the threshold of {prompt_enhancement_words_threshold}. Prompt enhancement disabled."
+ )
+
+ precision = pipeline_config["precision"]
+ text_encoder_model_name_or_path = pipeline_config["text_encoder_model_name_or_path"]
+ sampler = pipeline_config["sampler"]
+ prompt_enhancer_image_caption_model_name_or_path = pipeline_config[
+ "prompt_enhancer_image_caption_model_name_or_path"
+ ]
+ prompt_enhancer_llm_model_name_or_path = pipeline_config[
+ "prompt_enhancer_llm_model_name_or_path"
+ ]
+
+ pipeline = create_ltx_video_pipeline(
+ ckpt_path=ltxv_model_path,
+ precision=precision,
+ text_encoder_model_name_or_path=text_encoder_model_name_or_path,
+ sampler=sampler,
+ device=kwargs.get("device", get_device()),
+ enhance_prompt=enhance_prompt,
+ prompt_enhancer_image_caption_model_name_or_path=prompt_enhancer_image_caption_model_name_or_path,
+ prompt_enhancer_llm_model_name_or_path=prompt_enhancer_llm_model_name_or_path,
+ )
+
+ if pipeline_config.get("pipeline_type", None) == "multi-scale":
+ if not spatial_upscaler_model_path:
+ raise ValueError(
+ "spatial upscaler model path is missing from pipeline config file and is required for multi-scale rendering"
+ )
+ latent_upsampler = create_latent_upsampler(
+ spatial_upscaler_model_path, pipeline.device
+ )
+ pipeline = LTXMultiScalePipeline(pipeline, latent_upsampler=latent_upsampler)
+
+ media_item = None
+ if input_media_path:
+ media_item = load_media_file(
+ media_path=input_media_path,
+ height=height,
+ width=width,
+ max_frames=num_frames_padded,
+ padding=padding,
+ )
+
+ conditioning_items = (
+ prepare_conditioning(
+ conditioning_media_paths=conditioning_media_paths,
+ conditioning_strengths=conditioning_strengths,
+ conditioning_start_frames=conditioning_start_frames,
+ height=height,
+ width=width,
+ num_frames=num_frames,
+ padding=padding,
+ pipeline=pipeline,
+ )
+ if conditioning_media_paths
+ else None
+ )
+
+ stg_mode = pipeline_config.get("stg_mode", "attention_values")
+ del pipeline_config["stg_mode"]
+ if stg_mode.lower() == "stg_av" or stg_mode.lower() == "attention_values":
+ skip_layer_strategy = SkipLayerStrategy.AttentionValues
+ elif stg_mode.lower() == "stg_as" or stg_mode.lower() == "attention_skip":
+ skip_layer_strategy = SkipLayerStrategy.AttentionSkip
+ elif stg_mode.lower() == "stg_r" or stg_mode.lower() == "residual":
+ skip_layer_strategy = SkipLayerStrategy.Residual
+ elif stg_mode.lower() == "stg_t" or stg_mode.lower() == "transformer_block":
+ skip_layer_strategy = SkipLayerStrategy.TransformerBlock
+ else:
+ raise ValueError(f"Invalid spatiotemporal guidance mode: {stg_mode}")
+
+ # Prepare input for the pipeline
+ sample = {
+ "prompt": prompt,
+ "prompt_attention_mask": None,
+ "negative_prompt": negative_prompt,
+ "negative_prompt_attention_mask": None,
+ }
+
+ device = device or get_device()
+ generator = torch.Generator(device=device).manual_seed(seed)
+
+ images = pipeline(
+ **pipeline_config,
+ skip_layer_strategy=skip_layer_strategy,
+ generator=generator,
+ output_type="pt",
+ callback_on_step_end=None,
+ height=height_padded,
+ width=width_padded,
+ num_frames=num_frames_padded,
+ frame_rate=frame_rate,
+ **sample,
+ media_items=media_item,
+ conditioning_items=conditioning_items,
+ is_video=True,
+ vae_per_channel_normalize=True,
+ image_cond_noise_scale=image_cond_noise_scale,
+ mixed_precision=(precision == "mixed_precision"),
+ offload_to_cpu=offload_to_cpu,
+ device=device,
+ enhance_prompt=enhance_prompt,
+ ).images
+
+ # Crop the padded images to the desired resolution and number of frames
+ (pad_left, pad_right, pad_top, pad_bottom) = padding
+ pad_bottom = -pad_bottom
+ pad_right = -pad_right
+ if pad_bottom == 0:
+ pad_bottom = images.shape[3]
+ if pad_right == 0:
+ pad_right = images.shape[4]
+ images = images[:, :, :num_frames, pad_top:pad_bottom, pad_left:pad_right]
+
+ for i in range(images.shape[0]):
+ # Gathering from B, C, F, H, W to C, F, H, W and then permuting to F, H, W, C
+ video_np = images[i].permute(1, 2, 3, 0).cpu().float().numpy()
+ # Unnormalizing images to [0, 255] range
+ video_np = (video_np * 255).astype(np.uint8)
+ fps = frame_rate
+ height, width = video_np.shape[1:3]
+ # In case a single image is generated
+ if video_np.shape[0] == 1:
+ output_filename = get_unique_filename(
+ f"image_output_{i}",
+ ".png",
+ prompt=prompt,
+ seed=seed,
+ resolution=(height, width, num_frames),
+ dir=output_dir,
+ )
+ imageio.imwrite(output_filename, video_np[0])
+ else:
+ output_filename = get_unique_filename(
+ f"video_output_{i}",
+ ".mp4",
+ prompt=prompt,
+ seed=seed,
+ resolution=(height, width, num_frames),
+ dir=output_dir,
+ )
+
+ # Write video
+ with imageio.get_writer(output_filename, fps=fps) as video:
+ for frame in video_np:
+ video.append_data(frame)
+
+ logger.warning(f"Output saved to {output_filename}")
+
+
+def prepare_conditioning(
+ conditioning_media_paths: List[str],
+ conditioning_strengths: List[float],
+ conditioning_start_frames: List[int],
+ height: int,
+ width: int,
+ num_frames: int,
+ padding: tuple[int, int, int, int],
+ pipeline: LTXVideoPipeline,
+) -> Optional[List[ConditioningItem]]:
+ """Prepare conditioning items based on input media paths and their parameters.
+
+ Args:
+ conditioning_media_paths: List of paths to conditioning media (images or videos)
+ conditioning_strengths: List of conditioning strengths for each media item
+ conditioning_start_frames: List of frame indices where each item should be applied
+ height: Height of the output frames
+ width: Width of the output frames
+ num_frames: Number of frames in the output video
+ padding: Padding to apply to the frames
+ pipeline: LTXVideoPipeline object used for condition video trimming
+
+ Returns:
+ A list of ConditioningItem objects.
+ """
+ conditioning_items = []
+ for path, strength, start_frame in zip(
+ conditioning_media_paths, conditioning_strengths, conditioning_start_frames
+ ):
+ num_input_frames = orig_num_input_frames = get_media_num_frames(path)
+ if hasattr(pipeline, "trim_conditioning_sequence") and callable(
+ getattr(pipeline, "trim_conditioning_sequence")
+ ):
+ num_input_frames = pipeline.trim_conditioning_sequence(
+ start_frame, orig_num_input_frames, num_frames
+ )
+ if num_input_frames < orig_num_input_frames:
+ logger.warning(
+ f"Trimming conditioning video {path} from {orig_num_input_frames} to {num_input_frames} frames."
+ )
+
+ media_tensor = load_media_file(
+ media_path=path,
+ height=height,
+ width=width,
+ max_frames=num_input_frames,
+ padding=padding,
+ just_crop=True,
+ )
+ conditioning_items.append(ConditioningItem(media_tensor, start_frame, strength))
+ return conditioning_items
+
+
+def get_media_num_frames(media_path: str) -> int:
+ is_video = any(
+ media_path.lower().endswith(ext) for ext in [".mp4", ".avi", ".mov", ".mkv"]
+ )
+ num_frames = 1
+ if is_video:
+ reader = imageio.get_reader(media_path)
+ num_frames = reader.count_frames()
+ reader.close()
+ return num_frames
+
+
+def load_media_file(
+ media_path: str,
+ height: int,
+ width: int,
+ max_frames: int,
+ padding: tuple[int, int, int, int],
+ just_crop: bool = False,
+) -> torch.Tensor:
+ is_video = any(
+ media_path.lower().endswith(ext) for ext in [".mp4", ".avi", ".mov", ".mkv"]
+ )
+ if is_video:
+ reader = imageio.get_reader(media_path)
+ num_input_frames = min(reader.count_frames(), max_frames)
+
+ # Read and preprocess the relevant frames from the video file.
+ frames = []
+ for i in range(num_input_frames):
+ frame = Image.fromarray(reader.get_data(i))
+ frame_tensor = load_image_to_tensor_with_resize_and_crop(
+ frame, height, width, just_crop=just_crop
+ )
+ frame_tensor = torch.nn.functional.pad(frame_tensor, padding)
+ frames.append(frame_tensor)
+ reader.close()
+
+ # Stack frames along the temporal dimension
+ media_tensor = torch.cat(frames, dim=2)
+ else: # Input image
+ media_tensor = load_image_to_tensor_with_resize_and_crop(
+ media_path, height, width, just_crop=just_crop
+ )
+ media_tensor = torch.nn.functional.pad(media_tensor, padding)
+ return media_tensor
+
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file
diff --git a/aduc_framework/managers/mmaudio_manager.py b/aduc_framework/managers/mmaudio_manager.py
new file mode 100644
index 0000000000000000000000000000000000000000..b89f94598d37f1445b13d4451f4df20e77d7a7a0
--- /dev/null
+++ b/aduc_framework/managers/mmaudio_manager.py
@@ -0,0 +1,226 @@
+# managers/mmaudio_manager.py
+#
+# Copyright (C) 2025 Carlos Rodrigues dos Santos
+#
+# Version: 3.0.0 (GPU Pool Manager)
+#
+# Esta versão refatora o MMAudioManager para um modelo de Pool com Workers,
+# permitindo o uso de múltiplas GPUs dedicadas para a geração de áudio
+# com um sistema de rodízio para gerenciamento eficiente de VRAM.
+
+import torch
+import logging
+import subprocess
+import os
+import time
+import yaml
+import gc
+import threading
+from pathlib import Path
+import gradio as gr
+import sys
+
+# Imports relativos para o hardware_manager
+from ..tools.hardware_manager import hardware_manager
+
+logger = logging.getLogger(__name__)
+
+# --- Gerenciamento de Dependências ---
+DEPS_DIR = Path("./deps")
+MMAUDIO_REPO_DIR = DEPS_DIR / "MMAudio"
+MMAUDIO_REPO_URL = "https://github.com/hkchengrex/MMAudio.git"
+
+# Lazy-loaded imports
+ModelConfig, all_model_cfg, mmaudio_generate, load_video, make_video = None, None, None, None, None
+MMAudio, get_my_mmaudio = None, None
+FeaturesUtils = None
+SequenceConfig = None
+FlowMatching = None
+
+class MMAudioWorker:
+ """Representa uma única instância do pipeline MMAudio em um dispositivo."""
+ def __init__(self, device_id: str):
+ self.device = torch.device(device_id)
+ self.cpu_device = torch.device("cpu")
+ self.dtype = torch.bfloat16 if 'cuda' in self.device.type else torch.float32
+
+ self.net: 'MMAudio' = None
+ self.feature_utils: 'FeaturesUtils' = None
+ self.seq_cfg: 'SequenceConfig' = None
+ self.model_config: 'ModelConfig' = None
+
+ self._check_and_run_global_setup()
+ self._lazy_load_mmaudio_modules()
+ logger.info(f"MMAudio Worker inicializado para o dispositivo {self.device}.")
+
+ def _lazy_load_mmaudio_modules(self):
+ """Importa dinamicamente os módulos do MMAudio."""
+ global ModelConfig, all_model_cfg, mmaudio_generate, load_video, make_video, MMAudio, get_my_mmaudio, FeaturesUtils, SequenceConfig, FlowMatching
+ if MMAudio is not None: return
+
+ from mmaudio.eval_utils import ModelConfig, all_model_cfg, generate as mmaudio_generate, load_video, make_video
+ from mmaudio.model.flow_matching import FlowMatching
+ from mmaudio.model.networks import MMAudio, get_my_mmaudio
+ from mmaudio.model.utils.features_utils import FeaturesUtils
+ from mmaudio.model.sequence_config import SequenceConfig
+ logger.info("Módulos do MMAudio foram carregados dinamicamente.")
+
+ @staticmethod
+ def _check_and_run_global_setup():
+ """Executa o setup de clonagem do repositório e download de modelos uma única vez."""
+ setup_flag = DEPS_DIR / "mmaudio.setup.complete"
+ if setup_flag.exists():
+ return True
+
+ logger.info("--- Iniciando Setup Global do MMAudio (primeira execução) ---")
+ if not MMAUDIO_REPO_DIR.exists():
+ DEPS_DIR.mkdir(exist_ok=True)
+ subprocess.run(["git", "clone", "--depth", "1", MMAUDIO_REPO_URL, str(MMAUDIO_REPO_DIR)], check=True)
+
+ if str(MMAUDIO_REPO_DIR.resolve()) not in sys.path:
+ sys.path.insert(0, str(MMAUDIO_REPO_DIR.resolve()))
+
+ # Importar após adicionar ao path
+ from mmaudio.eval_utils import all_model_cfg as cfg
+
+ # Ajustar caminhos e baixar modelos
+ for cfg_key in cfg:
+ config = cfg[cfg_key]
+ config.model_path = MMAUDIO_REPO_DIR / config.model_path
+ config.vae_path = MMAUDIO_REPO_DIR / config.vae_path
+ if config.bigvgan_16k_path:
+ config.bigvgan_16k_path = MMAUDIO_REPO_DIR / config.bigvgan_16k_path
+ config.synchformer_ckpt = MMAUDIO_REPO_DIR / config.synchformer_ckpt
+ config.download_if_needed()
+
+ setup_flag.touch()
+ logger.info("--- Setup Global do MMAudio Concluído ---")
+ return True
+
+ def initialize_models(self):
+ """Carrega os modelos do worker para a CPU e depois para a GPU designada."""
+ if self.net is not None: return
+
+ self.model_config = all_model_cfg['large_44k_v2']
+ self.seq_cfg = self.model_config.seq_cfg
+
+ logger.info(f"Worker {self.device}: Carregando modelo MMAudio para a CPU...")
+ self.net = get_my_mmaudio(self.model_config.model_name).eval()
+ self.net.load_weights(torch.load(self.model_config.model_path, map_location=self.cpu_device, weights_only=True))
+
+ self.feature_utils = FeaturesUtils(
+ tod_vae_ckpt=self.model_config.vae_path,
+ synchformer_ckpt=self.model_config.synchformer_ckpt,
+ enable_conditions=True, mode=self.model_config.mode,
+ bigvgan_vocoder_ckpt=self.model_config.bigvgan_16k_path,
+ need_vae_encoder=False
+ ).eval()
+
+ self.net.to(self.device, self.dtype)
+ self.feature_utils.to(self.device, self.dtype)
+ logger.info(f"Worker {self.device}: Modelos MMAudio prontos na VRAM.")
+
+ def unload_models(self):
+ """Descarrega os modelos da VRAM, movendo-os para a CPU."""
+ if self.net is None: return
+ logger.info(f"Worker {self.device}: Descarregando modelos MMAudio da VRAM...")
+ self.net.to(self.cpu_device)
+ self.feature_utils.to(self.cpu_device)
+ del self.net, self.feature_utils, self.seq_cfg, self.model_config
+ self.net, self.feature_utils, self.seq_cfg, self.model_config = None, None, None, None
+ gc.collect()
+ if torch.cuda.is_available(): torch.cuda.empty_cache()
+
+ def generate_audio_internal(self, video_path: str, prompt: str, duration_seconds: float, output_path: str) -> str:
+ """Lógica de geração de áudio que roda na GPU do worker."""
+ negative_prompt = "human voice, speech, talking, singing, narration"
+ rng = torch.Generator(device=self.device).manual_seed(int(time.time()))
+ fm = FlowMatching(min_sigma=0, inference_mode='euler', num_steps=25)
+
+ video_info = load_video(Path(video_path), duration_seconds)
+ self.seq_cfg.duration = video_info.duration_sec
+ self.net.update_seq_lengths(self.seq_cfg.latent_seq_len, self.seq_cfg.clip_seq_len, self.seq_cfg.sync_seq_len)
+
+ with torch.no_grad():
+ audios = mmaudio_generate(
+ clip_video=video_info.clip_frames.unsqueeze(0).to(self.device, self.dtype),
+ sync_video=video_info.sync_frames.unsqueeze(0).to(self.device, self.dtype),
+ text=[prompt], negative_text=[negative_prompt],
+ feature_utils=self.feature_utils, net=self.net, fm=fm, rng=rng, cfg_strength=4.5
+ )
+ audio_waveform = audios.float().cpu()[0]
+
+ make_video(video_info, Path(output_path), audio_waveform, sampling_rate=self.seq_cfg.sampling_rate)
+ return output_path
+
+class MMAudioPoolManager:
+ def __init__(self, device_ids: list[str], workspace_dir: str):
+ logger.info(f"MMAUDIO POOL MANAGER: Criando workers para os dispositivos: {device_ids}")
+ self.workspace_dir = workspace_dir
+ if not device_ids or 'cpu' in device_ids:
+ raise ValueError("MMAudioPoolManager requer GPUs dedicadas.")
+ self.workers = [MMAudioWorker(device_id) for device_id in device_ids]
+ self.current_worker_index = 0
+ self.lock = threading.Lock()
+ self.last_cleanup_thread = None
+
+ def _cleanup_worker_thread(self, worker: MMAudioWorker):
+ logger.info(f"MMAUDIO CLEANUP THREAD: Iniciando limpeza de {worker.device} em background...")
+ worker.unload_models()
+
+ def generate_audio_for_video(self, video_path: str, prompt: str, duration_seconds: float, output_path_override: str = None) -> str:
+ if duration_seconds < 1:
+ logger.warning(f"Vídeo muito curto ({duration_seconds:.2f}s). Pulando geração de áudio.")
+ return video_path
+
+ worker_to_use = None
+ try:
+ with self.lock:
+ if self.last_cleanup_thread and self.last_cleanup_thread.is_alive():
+ self.last_cleanup_thread.join()
+
+ worker_to_use = self.workers[self.current_worker_index]
+ previous_worker_index = (self.current_worker_index - 1 + len(self.workers)) % len(self.workers)
+ worker_to_cleanup = self.workers[previous_worker_index]
+
+ cleanup_thread = threading.Thread(target=self._cleanup_worker_thread, args=(worker_to_cleanup,))
+ cleanup_thread.start()
+ self.last_cleanup_thread = cleanup_thread
+
+ worker_to_use.initialize_models()
+ self.current_worker_index = (self.current_worker_index + 1) % len(self.workers)
+
+ logger.info(f"MMAUDIO POOL MANAGER: Gerando áudio em {worker_to_use.device}...")
+
+ output_path = output_path_override or os.path.join(self.workspace_dir, f"{Path(video_path).stem}_with_audio.mp4")
+
+ return worker_to_use.generate_audio_internal(
+ video_path=video_path, prompt=prompt, duration_seconds=duration_seconds, output_path=output_path
+ )
+ except Exception as e:
+ logger.error(f"MMAUDIO POOL MANAGER: Erro durante a geração de áudio: {e}", exc_info=True)
+ raise gr.Error(f"Falha na geração de áudio: {e}")
+
+# --- Instanciação Singleton ---
+class MMAudioPlaceholder:
+ def generate_audio_for_video(self, video_path, *args, **kwargs):
+ logger.error("MMAudio não foi inicializado pois nenhuma GPU foi alocada. Pulando etapa de áudio.")
+ return video_path
+
+try:
+ with open("config.yaml", 'r') as f:
+ config = yaml.safe_load(f)
+ WORKSPACE_DIR = config['application']['workspace_dir']
+
+ mmaudio_gpus_required = config['specialists'].get('mmaudio', {}).get('gpus_required', 0)
+ mmaudio_device_ids = hardware_manager.allocate_gpus('MMAudio', mmaudio_gpus_required)
+
+ if mmaudio_gpus_required > 0 and 'cpu' not in mmaudio_device_ids:
+ mmaudio_manager_singleton = MMAudioPoolManager(device_ids=mmaudio_device_ids, workspace_dir=WORKSPACE_DIR)
+ logger.info("Especialista de Áudio (MMAudio Pool) pronto.")
+ else:
+ mmaudio_manager_singleton = MMAudioPlaceholder()
+ logger.warning("MMAudio Pool Manager não foi inicializado. Nenhuma GPU foi requisitada na config.yaml.")
+except Exception as e:
+ logger.critical(f"Falha CRÍTICA ao inicializar o MMAudioManager: {e}", exc_info=True)
+ mmaudio_manager_singleton = MMAudioPlaceholder()
\ No newline at end of file
diff --git a/aduc_framework/managers/seedvr_manager.py b/aduc_framework/managers/seedvr_manager.py
new file mode 100644
index 0000000000000000000000000000000000000000..8d526b7ee3ae3d7b0793dbfb88b5c771ea91d06e
--- /dev/null
+++ b/aduc_framework/managers/seedvr_manager.py
@@ -0,0 +1,232 @@
+# aduc_framework/managers/seedvr_manager.py
+#
+# Copyright (C) 2025 Carlos Rodrigues dos Santos
+#
+# Versão 11.0.0 (Otimização com FP16 Checkpoint)
+#
+# Utiliza o checkpoint FP16 otimizado para reduzir significativamente o uso
+# de VRAM, mantendo a arquitetura de "monkey patch" para desativar o
+# paralelismo problemático e garantir a estabilidade em modo de GPU única.
+
+import torch
+import os
+import gc
+import yaml
+import logging
+import sys
+import subprocess
+from pathlib import Path
+from urllib.parse import urlparse
+from torch.hub import download_url_to_file
+import mediapy
+from einops import rearrange
+import shutil
+from omegaconf import OmegaConf
+from typing import Generator, Dict, Any
+
+from ..tools.hardware_manager import hardware_manager
+
+logger = logging.getLogger(__name__)
+
+# Define os caminhos base para evitar hardcoding
+APP_ROOT = Path(os.getcwd())
+DEPS_DIR = APP_ROOT / "deps"
+SEEDVR_SPACE_DIR = DEPS_DIR / "SeedVR_Space"
+SEEDVR_SPACE_URL = "https://huggingface.co/spaces/ByteDance-Seed/SeedVR2-3B"
+
+def _load_file_from_url(url, model_dir='./', file_name=None):
+ """Helper para baixar arquivos de modelo e checkpoints."""
+ os.makedirs(model_dir, exist_ok=True)
+ filename = file_name or os.path.basename(urlparse(url).path)
+ cached_file = os.path.abspath(os.path.join(model_dir, filename))
+ if not os.path.exists(cached_file):
+ logger.info(f"Baixando arquivo do SeedVR: {filename}...")
+ download_url_to_file(url, cached_file, hash_prefix=None, progress=True)
+ return cached_file
+
+class SeedVrManager:
+ """Gerencia uma única instância do pipeline SeedVR em uma GPU dedicada e isolada."""
+ def __init__(self, device_id: str):
+ self.global_device_id = device_id
+ self.local_device_name = 'cuda:0' # O que o processo enxergará
+ self.gpu_index = self.global_device_id.split(':')[-1]
+
+ self.runner = None
+ self._check_and_run_global_setup()
+ logger.info(f"SeedVR Manager (FP16 Optimized) inicializado para operar na GPU {self.global_device_id}.")
+
+ @staticmethod
+ def _check_and_run_global_setup():
+ """Executa o setup de arquivos e aplica o patch para desativar o paralelismo."""
+ setup_flag = DEPS_DIR / "seedvr.setup.complete"
+
+ if str(APP_ROOT) not in sys.path: sys.path.insert(0, str(APP_ROOT))
+
+ try:
+ from common import decorators
+ import functools
+ def _passthrough_decorator(func):
+ @functools.wraps(func)
+ def wrapped(*args, **kwargs):
+ return func(*args, **kwargs)
+ return wrapped
+ decorators.master_only = _passthrough_decorator
+ logger.info("Monkey patch aplicado com sucesso em 'common.decorators.master_only' para desativar o paralelismo.")
+ except Exception as e:
+ logger.error(f"Falha ao aplicar o monkey patch para o SeedVR: {e}", exc_info=True)
+
+ if setup_flag.exists(): return True
+
+ logger.info("--- Iniciando Setup Global do SeedVR (primeira execução) ---")
+ if not SEEDVR_SPACE_DIR.exists():
+ DEPS_DIR.mkdir(exist_ok=True, parents=True)
+ logger.info(f"Clonando repositório do SeedVR de {SEEDVR_SPACE_URL}...")
+ subprocess.run(["git", "clone", "--depth", "1", SEEDVR_SPACE_URL, str(SEEDVR_SPACE_DIR)], check=True)
+
+ required_dirs = ["projects", "common", "models", "configs_3b", "data"]
+ for dirname in required_dirs:
+ source, target = SEEDVR_SPACE_DIR / dirname, APP_ROOT / dirname
+ if not target.exists():
+ logger.info(f"Copiando diretório '{dirname}' do SeedVR para a raiz do projeto...")
+ shutil.copytree(source, target)
+
+ try:
+ import apex
+ except ImportError:
+ logger.info("Dependência 'apex' não encontrada. Instalando a partir do wheel fornecido...")
+ apex_url = 'https://huggingface.co/ByteDance-Seed/SeedVR2-3B/resolve/main/apex-0.1-cp310-cp310-linux_x86_64.whl'
+ apex_wheel_path = _load_file_from_url(url=apex_url, model_dir=str(DEPS_DIR))
+ subprocess.run([sys.executable, '-m', 'pip', 'install', apex_wheel_path], check=True)
+
+ ckpt_dir = APP_ROOT / 'ckpts'
+ ckpt_dir.mkdir(exist_ok=True)
+
+ # >>> ALTERAÇÃO PRINCIPAL: Usando o checkpoint FP16 otimizado <<<
+ model_urls = {
+ 'vae': 'https://huggingface.co/batuhanince/seedvr_3b_fp16/resolve/main/ema_vae_fp16.safetensors',
+ 'dit_3b': 'https://huggingface.co/batuhanince/seedvr_3b_fp16/resolve/main/seedvr2_ema_3b_fp16.safetensors',
+ 'pos_emb': 'https://huggingface.co/ByteDance-Seed/SeedVR2-3B/resolve/main/pos_emb.pt',
+ 'neg_emb': 'https://huggingface.co/ByteDance-Seed/SeedVR2-3B/resolve/main/neg_emb.pt'
+ }
+ for name, url in model_urls.items():
+ _load_file_from_url(url=url, model_dir=str(ckpt_dir))
+
+ setup_flag.touch()
+ logger.info("--- Setup Global do SeedVR Concluído ---")
+
+ def _initialize_runner(self):
+ if self.runner is not None: return
+ os.environ['CUDA_VISIBLE_DEVICES'] = self.gpu_index
+ from projects.video_diffusion_sr.infer import VideoDiffusionInfer
+ from common.config import load_config
+
+ logger.info(f"Manager na GPU {self.global_device_id}: Inicializando runner SeedVR 3B com checkpoint FP16...")
+
+ config_path = APP_ROOT / 'configs_3b' / 'main.yaml'
+ # >>> O caminho agora aponta para o novo arquivo .safetensors <<<
+ checkpoint_path = APP_ROOT / 'ckpts' / 'seedvr2_ema_3b_fp16.safetensors'
+
+ config = load_config(str(config_path))
+ self.runner = VideoDiffusionInfer(config)
+ OmegaConf.set_readonly(self.runner.config, False)
+
+ self.runner.configure_dit_model(device=self.local_device_name, checkpoint=str(checkpoint_path))
+ self.runner.configure_vae_model()
+
+ logger.info(f"Manager na GPU {self.global_device_id}: Runner 3B (FP16) pronto na VRAM.")
+
+ def _unload_runner(self):
+ if self.runner is not None:
+ del self.runner; self.runner = None
+ gc.collect()
+ if torch.cuda.is_available(): torch.cuda.empty_cache()
+ logger.info(f"Manager na GPU {self.global_device_id}: Runner descarregado da VRAM.")
+ if 'CUDA_VISIBLE_DEVICES' in os.environ:
+ del os.environ['CUDA_VISIBLE_DEVICES']
+
+ def process_video(self, input_video_path: str, output_video_path: str, prompt: str, steps: int = 100, seed: int = 666) -> Generator[Dict[str, Any], None, None]:
+ try:
+ self._initialize_runner()
+ yield {"progress": 0.1, "desc": "Runner inicializado. Lendo vídeo..."}
+
+ device = torch.device(self.local_device_name)
+
+ from common.seed import set_seed
+ from data.image.transforms.divisible_crop import DivisibleCrop
+ from data.image.transforms.na_resize import NaResize
+ from data.video.transforms.rearrange import Rearrange
+ from projects.video_diffusion_sr.color_fix import wavelet_reconstruction
+ from torchvision.transforms import Compose, Lambda, Normalize
+ from torchvision.io.video import read_video
+
+ set_seed(seed, same_across_ranks=True)
+ self.runner.config.diffusion.timesteps.sampling.steps = steps
+ self.runner.configure_diffusion()
+
+ video_tensor = read_video(input_video_path, output_format="TCHW")[0] / 255.0
+ res_h, res_w = video_tensor.shape[-2:]
+ video_transform = Compose([
+ NaResize(resolution=(res_h * res_w) ** 0.5, mode="area", downsample_only=False),
+ Lambda(lambda x: torch.clamp(x, 0.0, 1.0)),
+ DivisibleCrop((16, 16)), Normalize(0.5, 0.5), Rearrange("t c h w -> c t h w"),
+ ])
+ cond_latents = [video_transform(video_tensor.to(device))]
+ yield {"progress": 0.2, "desc": "Encodificando para o espaço latente..."}
+ self.runner.dit.to("cpu"); self.runner.vae.to(device)
+ cond_latents = self.runner.vae_encode(cond_latents)
+ self.runner.vae.to("cpu"); gc.collect(); torch.cuda.empty_cache(); self.runner.dit.to(device)
+
+ pos_emb = torch.load(APP_ROOT / 'ckpts' / 'pos_emb.pt').to(device)
+ neg_emb = torch.load(APP_ROOT / 'ckpts' / 'neg_emb.pt').to(device)
+ text_embeds_dict = {"texts_pos": [pos_emb], "texts_neg": [neg_emb]}
+
+ noises = [torch.randn_like(latent) for latent in cond_latents]
+ conditions = [self.runner.get_condition(noise, latent_blur=latent, task="sr") for noise, latent in zip(noises, cond_latents)]
+
+ yield {"progress": 0.5, "desc": "Aplicando difusão para super-resolução..."}
+ with torch.no_grad(), torch.autocast("cuda", torch.bfloat16, enabled=True):
+ video_tensors = self.runner.inference(noises=noises, conditions=conditions, dit_offload=True, **text_embeds_dict)
+
+ yield {"progress": 0.8, "desc": "Decodificando para o espaço de pixel..."}
+ self.runner.dit.to("cpu"); gc.collect(); torch.cuda.empty_cache(); self.runner.vae.to(device)
+ samples = self.runner.vae_decode(video_tensors)
+ final_sample, input_video_sample = samples[0], cond_latents[0]
+ if final_sample.shape[1] < input_video_sample.shape[1]:
+ input_video_sample = input_video_sample[:, :final_sample.shape[1]]
+
+ final_sample = wavelet_reconstruction(rearrange(final_sample, "c t h w -> t c h w"), rearrange(input_video_sample, "c t h w -> t c h w"))
+ final_sample = rearrange(final_sample, "t c h w -> t h w c")
+ final_sample = final_sample.clip(-1, 1).mul_(0.5).add_(0.5).mul_(255).round()
+ final_sample_np = final_sample.to(torch.uint8).cpu().numpy()
+
+ yield {"progress": 0.9, "desc": "Escrevendo arquivo de vídeo final..."}
+ mediapy.write_video(output_video_path, final_sample_np, fps=24)
+ yield {"progress": 1.0, "final_path": output_video_path}
+
+ finally:
+ self._unload_runner()
+
+
+# --- Instanciação Singleton ---
+class SeedVrPlaceholder:
+ def process_video(self, input_video_path, *args, **kwargs):
+ logger.warning("SeedVR está desabilitado (gpus_required: 0). Pulando etapa de masterização HD.")
+ yield {"progress": 1.0, "final_path": input_video_path}
+
+try:
+ with open("config.yaml", 'r') as f: config = yaml.safe_load(f)
+ seedvr_gpus_required = config['specialists'].get('seedvr', {}).get('gpus_required', 0)
+
+ if seedvr_gpus_required > 0:
+ seedvr_device_ids = hardware_manager.allocate_gpus('SeedVR', seedvr_gpus_required)
+ if seedvr_device_ids and 'cpu' not in seedvr_device_ids:
+ device_to_use = seedvr_device_ids[0]
+ seedvr_manager_singleton = SeedVrManager(device_id=device_to_use)
+ logger.info(f"Especialista de Masterização HD (SeedVR FP16) pronto para usar a GPU {device_to_use}.")
+ else:
+ seedvr_manager_singleton = SeedVrPlaceholder()
+ else:
+ seedvr_manager_singleton = SeedVrPlaceholder()
+except Exception as e:
+ logger.critical(f"Falha CRÍTICA ao inicializar o SeedVrManager: {e}", exc_info=True)
+ seedvr_manager_singleton = SeedVrPlaceholder()
\ No newline at end of file
diff --git a/aduc_framework/managers/upscaler_specialist.py b/aduc_framework/managers/upscaler_specialist.py
new file mode 100644
index 0000000000000000000000000000000000000000..8981fe1d13ab87f0e8d81d30d66797758ff9f5dc
--- /dev/null
+++ b/aduc_framework/managers/upscaler_specialist.py
@@ -0,0 +1,91 @@
+# upscaler_specialist.py
+# Copyright (C) 2025 Carlos Rodrigues
+# Especialista ADUC para upscaling espacial de tensores latentes.
+
+import torch
+import logging
+from diffusers import LTXLatentUpsamplePipeline
+from ..managers.ltx_manager import ltx_manager_singleton
+
+logger = logging.getLogger(__name__)
+
+class UpscalerSpecialist:
+ """
+ Especialista responsável por aumentar a resolução espacial de tensores latentes
+ usando o LTX Video Spatial Upscaler.
+ """
+ def __init__(self):
+ # Força uso de CUDA se disponível
+ self.device = "cuda" if torch.cuda.is_available() else "cpu"
+ self.base_vae = None
+ self.pipe_upsample = None
+
+
+ def _lazy_init(self):
+ try:
+ # Tenta usar o VAE do ltx_manager
+ if ltx_manager_singleton.workers:
+ candidate_vae = ltx_manager_singleton.workers[0].pipeline.vae
+ if candidate_vae.__class__.__name__ == "AutoencoderKLLTXVideo":
+ self.base_vae = candidate_vae
+ logger.info("[Upscaler] Usando VAE do ltx_manager (AutoencoderKLLTXVideo).")
+ else:
+ logger.warning(f"[Upscaler] VAE incompatível: {type(candidate_vae)}. "
+ "Carregando AutoencoderKLLTXVideo manualmente...")
+ from diffusers.models.autoencoders import AutoencoderKLLTXVideo
+ self.base_vae = AutoencoderKLLTXVideo.from_pretrained(
+ "linoyts/LTX-Video-spatial-upscaler-0.9.8",
+ subfolder="vae",
+ torch_dtype=torch.float16 if self.device == "cuda" else torch.float32
+ ).to(self.device)
+ else:
+ logger.warning("[Upscaler] Nenhum worker disponível, carregando VAE manualmente...")
+ from diffusers.models.autoencoders import AutoencoderKLLTXVideo
+ self.base_vae = AutoencoderKLLTXVideo.from_pretrained(
+ "linoyts/LTX-Video-spatial-upscaler-0.9.8",
+ subfolder="vae",
+ torch_dtype=torch.float16 if self.device == "cuda" else torch.float32
+ ).to(self.device)
+
+ # Carregar pipeline
+ self.pipe_upsample = LTXLatentUpsamplePipeline.from_pretrained(
+ "linoyts/LTX-Video-spatial-upscaler-0.9.8",
+ vae=self.base_vae,
+ torch_dtype=torch.float16 if self.device == "cuda" else torch.float32
+ ).to(self.device)
+
+ logger.info("[Upscaler] Pipeline carregado com sucesso.")
+
+ except Exception as e:
+ logger.error(f"[Upscaler] Falha ao carregar pipeline: {e}")
+ self.pipe_upsample = None
+
+
+
+ @torch.no_grad()
+ def upscale(self, latents: torch.Tensor) -> torch.Tensor:
+ """Aplica o upscaling 2x nos tensores latentes fornecidos."""
+ self._lazy_init()
+ if self.pipe_upsample is None:
+ logger.warning("[Upscaler] Pipeline indisponível. Retornando latentes originais.")
+ return latents
+
+ try:
+ logger.info(f"[Upscaler] Recebido shape {latents.shape}. Executando upscale em {self.device}...")
+
+ # [CORREÇÃO FINAL] Conforme a documentação oficial, o resultado está em .frames
+ result = self.pipe_upsample(latents=latents, output_type="latent")
+ output_tensor = result.frames
+
+ logger.info(f"[Upscaler] Upscale concluído. Novo shape: {output_tensor.shape}")
+ return output_tensor
+
+ except Exception as e:
+ logger.error(f"[Upscaler] Erro durante upscale: {e}", exc_info=True)
+ return latents
+
+
+# ---------------------------
+# Singleton global
+# ---------------------------
+upscaler_specialist_singleton = UpscalerSpecialist()
\ No newline at end of file
diff --git a/aduc_framework/managers/vae_manager.py b/aduc_framework/managers/vae_manager.py
new file mode 100644
index 0000000000000000000000000000000000000000..3948f6da3ead474fb41417ec80df8b9cf6b2da6c
--- /dev/null
+++ b/aduc_framework/managers/vae_manager.py
@@ -0,0 +1,98 @@
+# aduc_framework/managers/vae_manager.py
+#
+# Versão 2.1.0 (Correção de Timestep no Decode)
+# Copyright (C) August 4, 2025 Carlos Rodrigues dos Santos
+#
+# - Corrige um `AssertionError` na função `decode` ao não passar o argumento
+# `timestep` esperado pelo decodificador do VAE.
+# - Adiciona um `timestep` padrão (0.05) para a decodificação, garantindo
+# uma reconstrução de imagem limpa e estável.
+
+import torch
+import logging
+import gc
+import yaml
+from typing import List
+from PIL import Image
+import numpy as np
+
+from ltx_video.models.autoencoders.vae_encode import vae_encode, vae_decode
+from ..tools.hardware_manager import hardware_manager
+
+logger = logging.getLogger(__name__)
+
+class VaeManager:
+ """
+ Especialista VAE "Hot" e Persistente.
+ Carrega o modelo VAE em uma GPU dedicada uma única vez e o mantém lá,
+ pronto para processar requisições de encode/decode com latência mínima.
+ """
+ def __init__(self):
+ with open("config.yaml", 'r') as f:
+ config = yaml.safe_load(f)
+ gpus_required = config['specialists'].get('vae', {}).get('gpus_required', 0)
+
+ if gpus_required > 0 and torch.cuda.is_available():
+ device_id = hardware_manager.allocate_gpus('VAE_Manager', gpus_required)[0]
+ self.device = torch.device(device_id)
+ logger.info(f"VaeManager: GPU dedicada '{device_id}' alocada.")
+ else:
+ self.device = torch.device('cpu')
+ logger.warning("VaeManager: Nenhuma GPU dedicada foi alocada no config.yaml. Operando em modo CPU.")
+
+ try:
+ from ..managers.ltx_manager import ltx_manager_singleton
+ self.vae = ltx_manager_singleton.workers[0].pipeline.vae
+ except ImportError as e:
+ logger.critical("Falha ao importar ltx_manager_singleton. Garanta que VaeManager seja importado DEPOIS de LtxManager.", exc_info=True)
+ raise e
+
+ self.vae.to(self.device)
+ self.vae.eval()
+ self.dtype = self.vae.dtype
+ logger.info(f"VaeManager inicializado. Modelo VAE está 'quente' e pronto na {self.device} com dtype {self.dtype}.")
+
+ def _preprocess_pil_image(self, pil_image: Image.Image, target_resolution: tuple) -> torch.Tensor:
+ from PIL import ImageOps
+ img = pil_image.convert("RGB")
+ processed_img = ImageOps.fit(img, target_resolution, Image.Resampling.LANCZOS)
+ image_np = np.array(processed_img).astype(np.float32) / 255.0
+ tensor = torch.from_numpy(image_np).permute(2, 0, 1).unsqueeze(0).unsqueeze(2)
+ return (tensor * 2.0) - 1.0
+
+ @torch.no_grad()
+ def encode_batch(self, pil_images: List[Image.Image], target_resolution: tuple) -> List[torch.Tensor]:
+ if not pil_images:
+ return []
+
+ latents_list = []
+ for img in pil_images:
+ pixel_tensor = self._preprocess_pil_image(img, target_resolution)
+ pixel_tensor_gpu = pixel_tensor.to(self.device, dtype=self.dtype)
+ latents = vae_encode(pixel_tensor_gpu, self.vae, vae_per_channel_normalize=True)
+ latents_list.append(latents.cpu())
+ return latents_list
+
+ @torch.no_grad()
+ def decode(self, latent_tensor: torch.Tensor, decode_timestep: float = 0.05) -> torch.Tensor:
+ """Decodifica um tensor latente para o espaço de pixels."""
+ latent_tensor_gpu = latent_tensor.to(self.device, dtype=self.dtype)
+
+ # --- CORREÇÃO APLICADA AQUI ---
+ # O modelo espera um tensor de timestep, um para cada item no batch.
+ num_items_in_batch = latent_tensor_gpu.shape[0]
+ timestep_tensor = torch.tensor([decode_timestep] * num_items_in_batch, device=self.device, dtype=self.dtype)
+
+ pixels = vae_decode(
+ latent_tensor_gpu,
+ self.vae,
+ is_video=True,
+ timestep=timestep_tensor, # Passando o tensor de timestep
+ vae_per_channel_normalize=True
+ )
+ # --- FIM DA CORREÇÃO ---
+
+ return pixels.cpu()
+
+# --- Instância Singleton ---
+vae_manager_singleton = VaeManager()
\ No newline at end of file
diff --git a/aduc_framework/prompts/LICENSE b/aduc_framework/prompts/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..e6fb40ab269ce532dd06cc34da2f86bc5f5441cd
--- /dev/null
+++ b/aduc_framework/prompts/LICENSE
@@ -0,0 +1,25 @@
+# Euia-AducSdr: Uma implementação aberta e funcional da arquitetura ADUC-SDR para geração de vídeo coerente.
+# Copyright (C) 4 de Agosto de 2025 Carlos Rodrigues dos Santos
+#
+# Contato:
+# Carlos Rodrigues dos Santos
+# carlex22@gmail.com
+# Rua Eduardo Carlos Pereira, 4125, B1 Ap32, Curitiba, PR, Brazil, CEP 8102025
+#
+# Repositórios e Projetos Relacionados:
+# GitHub: https://github.com/carlex22/Aduc-sdr
+# Hugging Face (Ltx-SuperTime-60Secondos): https://huggingface.co/spaces/Carlexx/Ltx-SuperTime-60Secondos/
+# Hugging Face (Novinho): https://huggingface.co/spaces/Carlexxx/Novinho/
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
\ No newline at end of file
diff --git a/aduc_framework/prompts/NOTICE.md b/aduc_framework/prompts/NOTICE.md
new file mode 100644
index 0000000000000000000000000000000000000000..e6dad38733a306f61263d083c471e6bac403e222
--- /dev/null
+++ b/aduc_framework/prompts/NOTICE.md
@@ -0,0 +1,76 @@
+# NOTICE
+
+Copyright (C) 2025 Carlos Rodrigues dos Santos. All rights reserved.
+
+---
+
+## Aviso de Propriedade Intelectual e Licenciamento
+
+### **Processo de Patenteamento em Andamento (EM PORTUGUÊS):**
+
+O método e o sistema de orquestração de prompts denominados **ADUC (Automated Discovery and Orchestration of Complex tasks)**, conforme descritos neste documento e implementados neste software, estão atualmente em processo de patenteamento.
+
+O titular dos direitos, Carlos Rodrigues dos Santos, está buscando proteção legal para as inovações chave da arquitetura ADUC, incluindo, mas não se limitando a:
+
+* Fragmentação e escalonamento de solicitações que excedem limites de contexto de modelos de IA.
+* Distribuição inteligente de sub-tarefas para especialistas heterogêneos.
+* Gerenciamento de estado persistido com avaliação iterativa e realimentação para o planejamento de próximas etapas.
+* Planejamento e roteamento sensível a custo, latência e requisitos de qualidade.
+* O uso de "tokens universais" para comunicação agnóstica a modelos.
+
+### **Reconhecimento e Implicações (EM PORTUGUÊS):**
+
+Ao acessar ou utilizar este software e a arquitetura ADUC aqui implementada, você reconhece:
+
+1. A natureza inovadora e a importância da arquitetura ADUC no campo da orquestração de prompts para IA.
+2. Que a essência desta arquitetura, ou suas implementações derivadas, podem estar sujeitas a direitos de propriedade intelectual, incluindo patentes.
+3. Que o uso comercial, a reprodução da lógica central da ADUC em sistemas independentes, ou a exploração direta da invenção sem o devido licenciamento podem infringir os direitos de patente pendente.
+
+---
+
+### **Patent Pending (IN ENGLISH):**
+
+The method and system for prompt orchestration named **ADUC (Automated Discovery and Orchestration of Complex tasks)**, as described herein and implemented in this software, are currently in the process of being patented.
+
+The rights holder, Carlos Rodrigues dos Santos, is seeking legal protection for the key innovations of the ADUC architecture, including, but not limited to:
+
+* Fragmentation and scaling of requests exceeding AI model context limits.
+* Intelligent distribution of sub-tasks to heterogeneous specialists.
+* Persistent state management with iterative evaluation and feedback for planning subsequent steps.
+* Cost, latency, and quality-aware planning and routing.
+* The use of "universal tokens" for model-agnostic communication.
+
+### **Acknowledgement and Implications (IN ENGLISH):**
+
+By accessing or using this software and the ADUC architecture implemented herein, you acknowledge:
+
+1. The innovative nature and significance of the ADUC architecture in the field of AI prompt orchestration.
+2. That the essence of this architecture, or its derivative implementations, may be subject to intellectual property rights, including patents.
+3. That commercial use, reproduction of ADUC's core logic in independent systems, or direct exploitation of the invention without proper licensing may infringe upon pending patent rights.
+
+---
+
+## Licença AGPLv3
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program. If not, see .
+
+---
+
+**Contato para Consultas:**
+
+Para mais informações sobre a arquitetura ADUC, o status do patenteamento, ou para discutir licenciamento para usos comerciais ou não conformes com a AGPLv3, por favor, entre em contato:
+
+Carlos Rodrigues dos Santos
+carlex22@gmail.com
+Rua Eduardo Carlos Pereira, 4125, B1 Ap32, Curitiba, PR, Brazil, CEP 8102025
\ No newline at end of file
diff --git a/aduc_framework/prompts/README.md b/aduc_framework/prompts/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..9cf56fe2707241f77fe3aedabdaa07d319218b17
--- /dev/null
+++ b/aduc_framework/prompts/README.md
@@ -0,0 +1,211 @@
+---
+title: Euia-AducSdr
+emoji: 🎥
+colorFrom: indigo
+colorTo: purple
+sdk: gradio
+app_file: app.py
+pinned: true
+license: agpl-3.0
+short_description: Uma implementação aberta e funcional da arquitetura ADUC-SDR
+---
+
+
+### 🇧🇷 Português
+
+Uma implementação aberta e funcional da arquitetura ADUC-SDR (Arquitetura de Unificação Compositiva - Escala Dinâmica e Resiliente), projetada para a geração de vídeo coerente de longa duração. Este projeto materializa os princípios de fragmentação, navegação geométrica e um mecanismo de "eco causal 4bits memoria" para garantir a continuidade física e narrativa em sequências de vídeo geradas por múltiplos modelos de IA.
+
+**Licença:** Este projeto é licenciado sob os termos da **GNU Affero General Public License v3.0**. Isto significa que se você usar este software (ou qualquer trabalho derivado) para fornecer um serviço através de uma rede, você é **obrigado a disponibilizar o código-fonte completo** da sua versão para os usuários desse serviço.
+
+- **Copyright (C) 4 de Agosto de 2025, Carlos Rodrigues dos Santos**
+- Uma cópia completa da licença pode ser encontrada no arquivo [LICENSE](LICENSE).
+
+---
+
+### 🇬🇧 English
+
+An open and functional implementation of the ADUC-SDR (Architecture for Compositive Unification - Dynamic and Resilient Scaling) architecture, designed for long-form coherent video generation. This project materializes the principles of fragmentation, geometric navigation, and a "causal echo 4bits memori" mechanism to ensure physical and narrative continuity in video sequences generated by multiple AI models.
+
+**License:** This project is licensed under the terms of the **GNU Affero General Public License v3.0**. This means that if you use this software (or any derivative work) to provide a service over a network, you are **required to make the complete source code** of your version available to the users of that service.
+
+- **Copyright (C) August 4, 2025, Carlos Rodrigues dos Santos**
+- A full copy of the license can be found in the [LICENSE](LICENSE) file.
+
+---
+
+## **Aviso de Propriedade Intelectual e Patenteamento**
+
+### **Processo de Patenteamento em Andamento (EM PORTUGUÊS):**
+
+A arquitetura e o método **ADUC (Automated Discovery and Orchestration of Complex tasks)**, conforme descritos neste projeto e nas reivindicações associadas, estão **atualmente em processo de patenteamento**.
+
+O titular dos direitos, Carlos Rodrigues dos Santos, está buscando proteção legal para as inovações chave da arquitetura ADUC, que incluem, mas não se limitam a:
+
+* Fragmentação e escalonamento de solicitações que excedem limites de contexto de modelos de IA.
+* Distribuição inteligente de sub-tarefas para especialistas heterogêneos.
+* Gerenciamento de estado persistido com avaliação iterativa e realimentação para o planejamento de próximas etapas.
+* Planejamento e roteamento sensível a custo, latência e requisitos de qualidade.
+* O uso de "tokens universais" para comunicação agnóstica a modelos.
+
+Ao utilizar este software e a arquitetura ADUC aqui implementada, você reconhece a natureza inovadora desta arquitetura e que a **reprodução ou exploração da lógica central da ADUC em sistemas independentes pode infringir direitos de patente pendente.**
+
+---
+
+### **Patent Pending (IN ENGLISH):**
+
+The **ADUC (Automated Discovery and Orchestration of Complex tasks)** architecture and method, as described in this project and its associated claims, are **currently in the process of being patented.**
+
+The rights holder, Carlos Rodrigues dos Santos, is seeking legal protection for the key innovations of the ADUC architecture, including, but not limited to:
+
+* Fragmentation and scaling of requests exceeding AI model context limits.
+* Intelligent distribution of sub-tasks to heterogeneous specialists.
+* Persistent state management with iterative evaluation and feedback for planning subsequent steps.
+* Cost, latency, and quality-aware planning and routing.
+* The use of "universal tokens" for model-agnostic communication.
+
+By using this software and the ADUC architecture implemented herein, you acknowledge the innovative nature of this architecture and that **the reproduction or exploitation of ADUC's core logic in independent systems may infringe upon pending patent rights.**
+
+---
+
+### Detalhes Técnicos e Reivindicações da ADUC
+
+#### 🇧🇷 Definição Curta (para Tese e Patente)
+
+**ADUC** é um *framework pré-input* e *intermediário* de **gerenciamento de prompts** que:
+
+1. **fragmenta** solicitações acima do limite de contexto de qualquer modelo,
+2. **escala linearmente** (processo sequencial com memória persistida),
+3. **distribui** sub-tarefas a **especialistas** (modelos/ferramentas heterogêneos), e
+4. **realimenta** a próxima etapa com avaliação do que foi feito/esperado (LLM diretor).
+
+Não é um modelo; é uma **camada orquestradora** plugável antes do input de modelos existentes (texto, imagem, áudio, vídeo), usando *tokens universais* e a tecnologia atual.
+
+#### 🇬🇧 Short Definition (for Thesis and Patent)
+
+**ADUC** is a *pre-input* and *intermediate* **prompt management framework** that:
+
+1. **fragments** requests exceeding any model's context limit,
+2. **scales linearly** (sequential process with persisted memory),
+3. **distributes** sub-tasks to **specialists** (heterogeneous models/tools), and
+4. **feeds back** to the next step with an evaluation of what was done/expected (director LLM).
+
+It is not a model; it is a pluggable **orchestration layer** before the input of existing models (text, image, audio, video), using *universal tokens* and current technology.
+
+---
+
+#### 🇧🇷 Elementos Essenciais (Telegráfico)
+
+* **Agnóstico a modelos:** opera com qualquer LLM/difusor/API.
+* **Pré-input manager:** recebe pedido do usuário, **divide** em blocos ≤ limite de tokens, **prioriza**, **agenda** e **roteia**.
+* **Memória persistida:** resultados/latentes/“eco” viram **estado compartilhado** para o próximo bloco (nada é ignorado).
+* **Especialistas:** *routers* decidem quem faz o quê (ex.: “descrição → LLM-A”, “keyframe → Img-B”, “vídeo → Vid-C”).
+* **Controle de qualidade:** LLM diretor compara *o que fez* × *o que deveria* × *o que falta* e **regenera objetivos** do próximo fragmento.
+* **Custo/latência-aware:** planeja pela **VRAM/tempo/custo**, não tenta “abraçar tudo de uma vez”.
+
+#### 🇬🇧 Essential Elements (Telegraphic)
+
+* **Model-agnostic:** operates with any LLM/diffuser/API.
+* **Pre-input manager:** receives user request, **divides** into blocks ≤ token limit, **prioritizes**, **schedules**, and **routes**.
+* **Persisted memory:** results/latents/“echo” become **shared state** for the next block (nothing is ignored).
+* **Specialists:** *routers* decide who does what (e.g., “description → LLM-A”, “keyframe → Img-B”, “video → Vid-C”).
+* **Quality control:** director LLM compares *what was done* × *what should be done* × *what is missing* and **regenerates objectives** for the next fragment.
+* **Cost/latency-aware:** plans by **VRAM/time/cost**, does not try to “embrace everything at once”.
+
+---
+
+#### 🇧🇷 Reivindicações Independentes (Método e Sistema)
+
+**Reivindicação Independente (Método) — Versão Enxuta:**
+
+1. **Método** de **orquestração de prompts** para execução de tarefas acima do limite de contexto de modelos de IA, compreendendo:
+ (a) **receber** uma solicitação que excede um limite de tokens;
+ (b) **analisar** a solicitação por um **LLM diretor** e **fragmentá-la** em sub-tarefas ≤ limite;
+ (c) **selecionar** especialistas de execução para cada sub-tarefa com base em capacidades declaradas;
+ (d) **gerar** prompts específicos por sub-tarefa em **tokens universais**, incluindo referências ao **estado persistido** de execuções anteriores;
+ (e) **executar sequencialmente** as sub-tarefas e **persistir** suas saídas como memória (incluindo latentes/eco/artefatos);
+ (f) **avaliar** automaticamente a saída versus metas declaradas e **regenerar objetivos** do próximo fragmento;
+ (g) **iterar** (b)–(f) até que os critérios de completude sejam atendidos, produzindo o resultado agregado;
+ em que o framework **escala linearmente** no tempo e armazenamento físico, **independente** da janela de contexto dos modelos subjacentes.
+
+**Reivindicação Independente (Sistema):**
+
+2. **Sistema** de orquestração de prompts, compreendendo: um **planejador LLM diretor**; um **roteador de especialistas**; um **banco de estado persistido** (incl. memória cinética para vídeo); um **gerador de prompts universais**; e um **módulo de avaliação/realimentação**, acoplados por uma **API pré-input** a modelos heterogêneos.
+
+#### 🇬🇧 Independent Claims (Method and System)
+
+**Independent Claim (Method) — Concise Version:**
+
+1. A **method** for **prompt orchestration** for executing tasks exceeding AI model context limits, comprising:
+ (a) **receiving** a request that exceeds a token limit;
+ (b) **analyzing** the request by a **director LLM** and **fragmenting it** into sub-tasks ≤ the limit;
+ (c) **selecting** execution specialists for each sub-task based on declared capabilities;
+ (d) **generating** specific prompts per sub-task in **universal tokens**, including references to the **persisted state** of previous executions;
+ (e) **sequentially executing** the sub-tasks and **persisting** their outputs as memory (including latents/echo/artifacts);
+ (f) **automatically evaluating** the output against declared goals and **regenerating objectives** for the next fragment;
+ (g) **iterating** (b)–(f) until completion criteria are met, producing the aggregated result;
+ wherein the framework **scales linearly** in time and physical storage, **independent** of the context window of the underlying models.
+
+**Independent Claim (System):**
+
+2. A prompt orchestration **system**, comprising: a **director LLM planner**; a **specialist router**; a **persisted state bank** (incl. kinetic memory for video); a **universal prompt generator**; and an **evaluation/feedback module**, coupled via a **pre-input API** to heterogeneous models.
+
+---
+
+#### 🇧🇷 Dependentes Úteis
+
+* (3) Onde o roteamento considera **custo/latência/VRAM** e metas de qualidade.
+* (4) Onde o banco de estado inclui **eco cinético** para vídeo (últimos *n* frames/latentes/fluxo).
+* (5) Onde a avaliação usa métricas específicas por domínio (Lflow, consistência semântica, etc.).
+* (6) Onde *tokens universais* padronizam instruções entre especialistas.
+* (7) Onde a orquestração decide **cut vs continuous** e **corte regenerativo** (Déjà-Vu) ao editar vídeo.
+* (8) Onde o sistema **nunca descarta** conteúdo excedente: **reagenda** em novos fragmentos.
+
+#### 🇬🇧 Useful Dependents
+
+* (3) Wherein routing considers **cost/latency/VRAM** and quality goals.
+* (4) Wherein the state bank includes **kinetic echo** for video (last *n* frames/latents/flow).
+* (5) Wherein evaluation uses domain-specific metrics (Lflow, semantic consistency, etc.).
+* (6) Wherein *universal tokens* standardize instructions between specialists.
+* (7) Wherein orchestration decides **cut vs continuous** and **regenerative cut** (Déjà-Vu) when editing video.
+* (8) Wherein the system **never discards** excess content: it **reschedules** it in new fragments.
+
+---
+
+#### 🇧🇷 Como isso conversa com SDR (Vídeo)
+
+* **Eco Cinético**: é um **tipo de estado persistido** consumido pelo próximo passo.
+* **Déjà-Vu (Corte Regenerativo)**: é **uma política de orquestração** aplicada quando há edição; ADUC decide, monta os prompts certos e chama o especialista de vídeo.
+* **Cut vs Continuous**: decisão do **diretor** com base em estado + metas; ADUC roteia e garante a sobreposição/remoção final.
+
+#### 🇬🇧 How this Converses with SDR (Video)
+
+* **Kinetic Echo**: is a **type of persisted state** consumed by the next step.
+* **Déjà-Vu (Regenerative Cut)**: is an **orchestration policy** applied during editing; ADUC decides, crafts the right prompts, and calls the video specialist.
+* **Cut vs Continuous**: decision made by the **director** based on state + goals; ADUC routes and ensures the final overlap/removal.
+
+---
+
+#### 🇧🇷 Mensagem Clara ao Usuário (Experiência)
+
+> “Seu pedido excede o limite X do modelo Y. Em vez de truncar silenciosamente, o **ADUC** dividirá e **entregará 100%** do conteúdo por etapas coordenadas.”
+
+Isso é diferencial prático e jurídico: **não-obviedade** por transformar limite de contexto em **pipeline controlado**, com **persistência de estado** e **avaliação iterativa**.
+
+#### 🇬🇧 Clear User Message (Experience)
+
+> "Your request exceeds model Y's limit X. Instead of silently truncating, **ADUC** will divide and **deliver 100%** of the content through coordinated steps."
+
+This is a practical and legal differentiator: **non-obviousness** by transforming context limits into a **controlled pipeline**, with **state persistence** and **iterative evaluation**.
+
+---
+
+### Contact / Contato / Contacto
+
+- **Author / Autor:** Carlos Rodrigues dos Santos
+- **Email:** carlex22@gmail.com
+- **GitHub:** [https://github.com/carlex22/Aduc-sdr](https://github.com/carlex22/Aduc-sdr)
+- **Hugging Face Spaces:**
+ - [Ltx-SuperTime-60Secondos](https://huggingface.co/spaces/Carlexx/Ltx-SuperTime-60Secondos/)
+ - [Novinho](https://huggingface.co/spaces/Carlexxx/Novinho/)
+
+---
\ No newline at end of file
diff --git a/aduc_framework/prompts/TASK_01_CREATE_NARRATIVE_SYNTHESIS.txt b/aduc_framework/prompts/TASK_01_CREATE_NARRATIVE_SYNTHESIS.txt
new file mode 100644
index 0000000000000000000000000000000000000000..a8c88ab14269d6701166a2270f76cef581ff3d17
--- /dev/null
+++ b/aduc_framework/prompts/TASK_01_CREATE_NARRATIVE_SYNTHESIS.txt
@@ -0,0 +1,18 @@
+# ROLE:
+Você é um Roteirista-Analista. Sua função é sintetizar um conceito textual e referências visuais em uma única história coesa e contínua.
+
+# GOAL:
+Escrever uma narrativa fluida baseada na "Ideia Principal" e inspirada pelas "Imagens de Referência". A história deve ser dividida em exatamente {num_scenes} parágrafos e focar em descrever ações e eventos visuais.
+
+# CRITICAL RULES:
+1. **SÍNTESE VISUAL:** A história DEVE ser uma fusão do que está escrito na "Ideia Principal" e do que é visível nas "Imagens de Referência".
+2. **AÇÃO, NÃO ABSTRAÇÃO:** Descreva eventos e movimentos concretos. O que a câmera veria? Evite sentimentos internos ou metáforas.
+3. **NARRATIVA CONTÍNUA:** O texto deve fluir como uma única história do começo ao fim.
+
+# CONTEXT:
+- **Ideia Principal:** {global_prompt}
+- **Imagens de Referência:** [As imagens serão fornecidas aqui]
+- **Número de Parágrafos a Criar:** {num_scenes}
+
+# OUTPUT_RULES:
+- A resposta deve conter APENAS o texto bruto da história contínua. Não use JSON. Não adicione títulos ou notas.
\ No newline at end of file
diff --git a/aduc_framework/prompts/anticipatory_keyframe_prompt.txt b/aduc_framework/prompts/anticipatory_keyframe_prompt.txt
new file mode 100644
index 0000000000000000000000000000000000000000..16aa3ec6270112b0b6f837669dbab881c0966a5b
--- /dev/null
+++ b/aduc_framework/prompts/anticipatory_keyframe_prompt.txt
@@ -0,0 +1,25 @@
+# ROLE: AI Art Director
+
+# TASK:
+# Analyze the context and generate a JSON object to direct the creation of the next keyframe.
+# Your goal is to visually connect the CURRENT scene to the FUTURE scene.
+
+# CONTEXT:
+# - History: {historico_prompt}
+# - Current Scene: "{cena_atual}"
+# - Future Scene: "{cena_futura}"
+# - Available Reference IDs: {available_ref_images}
+# - Last Keyframe: [IMG-BASE] will be provided visually.
+
+# OUTPUT (JSON REQUIRED):
+# Respond ONLY with the JSON object.
+
+# Example of the required output format:
+# ```{{
+# "composition_prompt": "A scared man (brief description) runs through the dry savannah, looking over his shoulder. In the background, a majestic lion (brief description) chases him, muscles tense. The camera follows the man. Until he trips on an exposed root and falls.",
+# "reference_images": [
+# {{"id": 1, "weight": 0.5}},
+# {{"id": 3, "weight": 0.48}},
+# {{"id": 2, "weight": 0.45}}
+# ]
+# }}```
\ No newline at end of file
diff --git a/aduc_framework/prompts/audio_director_prompt.txt b/aduc_framework/prompts/audio_director_prompt.txt
new file mode 100644
index 0000000000000000000000000000000000000000..0b86165bf171ba94d4f74b20693c0f326d5a6fa6
--- /dev/null
+++ b/aduc_framework/prompts/audio_director_prompt.txt
@@ -0,0 +1,18 @@
+# ROLE: AI Audio Director and Sound Designer
+
+# GOAL:
+Analyze the provided film script/storyboard. Based on the overall narrative and mood, generate two distinct prompts for audio generation: one for a background music score and one for ambient sound effects (SFX).
+
+# INSTRUCTIONS:
+1. **Analyze the Story:** Read the "Global Idea" and the "Scene Storyboard" to understand the plot, pacing, and emotional tone of the film.
+2. **Create Music Prompt:** Write a concise, descriptive prompt for a music generation model (like MusicGen). Focus on genre, mood, instruments
+3. **Create SFX Prompt:** Write a concise, descriptive prompt for an audio generation model (like AudioLDM2). Focus on ambient sounds and key effects that match the scenes.
+4. **Output Format:** You MUST respond with a single, clean JSON object with exactly two keys: "music_prompt" and "sfx_prompt".
+
+# == PROVIDED CONTEXT ==
+- **Global Idea:** "{global_prompt}"
+- **Scene Storyboard:**
+{storyboard_str}
+
+# == YOUR TASK ==
+# Generate the JSON response with the two audio prompts.
\ No newline at end of file
diff --git a/aduc_framework/prompts/director_composition_prompt.txt b/aduc_framework/prompts/director_composition_prompt.txt
new file mode 100644
index 0000000000000000000000000000000000000000..6663bc64e0f74a4d105a9c06cb072cebd4d3ba67
--- /dev/null
+++ b/aduc_framework/prompts/director_composition_prompt.txt
@@ -0,0 +1,27 @@
+# ROLE: AI Animation Director (Key Pose)
+
+# GOAL:
+Generate a single, powerful, CLIP-style prompt to create the NEXT keyframe in a sequence. Your goal is to describe a logical and visually coherent evolution FROM the last generated image.
+
+# CRITICAL DIRECTIVES:
+1. **ANCHOR TO THE PREVIOUS SCENE:** The last generated image, tagged as `[IMG-1]`, represents the END of the previous scene. Your new prompt MUST describe what happens IMMEDIATELY AFTER. Treat `[IMG-1]` as your primary visual and environmental canvas.
+
+2. **EVOLVE, DO NOT REPLACE:** Unless the "Current Scene Description" explicitly describes a major change in location or character (e.g., "cut to a new scene"), you must maintain the environment, lighting, and core subjects from `[IMG-1]`. Your prompt should describe how the characters and objects *within* that scene evolve.
+
+3. **POSE, NOT PANNING:** Describe the state of the subject at a specific instant, not camera movement. Focus on body language, expression, and interaction that logically follows the previous state.
+
+4. **USE REFERENCES FOR CONTINUITY:** Use the `[IMG-X]` tags provided to maintain the identity of characters and objects across frames. Prioritize `[IMG-1]` for environmental context.
+
+5. **BE A DIRECTOR:** Use strong, active verbs. Instead of "the lion is now sitting", prefer "the lion lowers its body, muscles tensing as it settles onto the dry grass".
+
+# CONTEXT:
+- Global Story Goal: "{global_prompt}"
+- Current Scene Description: "{current_scene_desc}"
+- Scene History (what happened before):
+{history_scene}
+
+# VISUAL ASSETS FOR ANALYSIS:
+# [Images will be provided and tagged as [IMG-1] (Last Image/Environment), [IMG-2] (Character Ref), etc.]
+
+# RESPONSE FORMAT:
+Respond with ONLY the final, single-line prompt string.
\ No newline at end of file
diff --git a/aduc_framework/prompts/flux_composition_wrapper_prompt.txt b/aduc_framework/prompts/flux_composition_wrapper_prompt.txt
new file mode 100644
index 0000000000000000000000000000000000000000..99cf7f230e6d2e9c19169e84097e0fb5032bf0b0
--- /dev/null
+++ b/aduc_framework/prompts/flux_composition_wrapper_prompt.txt
@@ -0,0 +1 @@
+From the provided reference images, create a single, natural, and cohesive scene where: {target_prompt}
\ No newline at end of file
diff --git a/aduc_framework/prompts/initial_motion_prompt.txt b/aduc_framework/prompts/initial_motion_prompt.txt
new file mode 100644
index 0000000000000000000000000000000000000000..768ee3dcce5df1d1febd0cc529b93a7e1f40b1ee
--- /dev/null
+++ b/aduc_framework/prompts/initial_motion_prompt.txt
@@ -0,0 +1,20 @@
+# ROLE: AI Cinematographer (Initial Scene)
+
+# GOAL:
+Create a single, concise, CLIP-style motion prompt. The prompt must describe a coherent video sequence that transitions from a STARTING image to a DESTINATION image.
+
+# INSTRUCTIONS:
+1. **Analyze the Arc:** Understand the visual and narrative journey from the START to the DESTINATION image.
+2. **Describe the Motion:** Focus on DYNAMICS (camera and subject movement).
+3. **Style Guide:** Use dense, descriptive, cinematic keywords. Omit fluff like "The video shows...". Be direct.
+
+# CONTEXT:
+- Overall Story Goal: "{user_prompt}"
+- Destination Scene Description: "{destination_scene_description}"
+
+# SCENE ANALYSIS:
+# START Image: [Image 1]
+# DESTINATION Image: [Image 2]
+
+# RESPONSE FORMAT:
+Respond with ONLY the raw prompt string.
\ No newline at end of file
diff --git a/aduc_framework/prompts/keyframe_selection_prompt.txt b/aduc_framework/prompts/keyframe_selection_prompt.txt
new file mode 100644
index 0000000000000000000000000000000000000000..d74ee636ead3b444c1721abb48e21d413532e91d
--- /dev/null
+++ b/aduc_framework/prompts/keyframe_selection_prompt.txt
@@ -0,0 +1,20 @@
+# ROLE: AI Film Editor / Photographer
+
+# GOAL:
+You are tasked with selecting the best keyframe for each scene of a storyboard to create a coherent visual narrative. You have a "scene bank" of available images. Your selections must create a smooth and logical progression.
+
+# INSTRUCTIONS:
+1. **Analyze the Storyboard:** Read each scene description carefully to understand the intended action and emotion.
+2. **Prioritize Continuity:** For each scene, your primary goal is to find an image from the "Image Pool" that represents a logical **next step** from the previously selected scene. Avoid jarring jumps in location, lighting, or character appearance unless the storyboard explicitly calls for a "cut".
+3. **Maintain Consistency:** Your choices must be consistent with the characters and style established in the "Reference Images (Story Base)".
+4. **Select the Best Fit:** If multiple images could work, choose the one that best captures the specific action or mood of the current scene description.
+5. **Output Format:** You MUST respond with a single, clean JSON object with one key: "selected_image_identifiers". The value should be an array of strings, where each string is the identifier of the chosen image (e.g., "IMG-3"). The order of the array must match the order of the scenes in the storyboard. The length of the array must be exactly the same as the number of scenes.
+
+# == PROVIDED CONTEXT ==
+- **Storyboard:**
+{storyboard_str}
+
+- **Available Image Identifiers in Pool:** {image_identifiers}
+
+# == YOUR TASK ==
+# Generate the JSON response with the selected image identifiers, prioritizing a smooth visual and narrative flow from one selection to the next.
\ No newline at end of file
diff --git a/aduc_framework/prompts/model_maps/llama_3_2_vision/image_template.txt b/aduc_framework/prompts/model_maps/llama_3_2_vision/image_template.txt
new file mode 100644
index 0000000000000000000000000000000000000000..d87ac771da5e29115e0d41ac2d70ad77168bf169
--- /dev/null
+++ b/aduc_framework/prompts/model_maps/llama_3_2_vision/image_template.txt
@@ -0,0 +1,5 @@
+<|begin_of_text|><|start_header_id|>user<|end_header_id|>
+
+<|image|>{generic_prompt_content}
+
+<|eot_id|><|start_header_id|>assistant<|end_header_id|>
\ No newline at end of file
diff --git a/aduc_framework/prompts/model_maps/llama_3_2_vision/main_template.txt b/aduc_framework/prompts/model_maps/llama_3_2_vision/main_template.txt
new file mode 100644
index 0000000000000000000000000000000000000000..dde49b72869b72309c1ad5aa9aafc4eb75c162d6
--- /dev/null
+++ b/aduc_framework/prompts/model_maps/llama_3_2_vision/main_template.txt
@@ -0,0 +1,5 @@
+<|begin_of_text|><|start_header_id|>user<|end_header_id|>
+
+{generic_prompt_content}
+
+<|eot_id|><|start_header_id|>assistant<|end_header_id|>
\ No newline at end of file
diff --git a/aduc_framework/prompts/model_maps/llama_3_2_vision/text_template.txt b/aduc_framework/prompts/model_maps/llama_3_2_vision/text_template.txt
new file mode 100644
index 0000000000000000000000000000000000000000..dde49b72869b72309c1ad5aa9aafc4eb75c162d6
--- /dev/null
+++ b/aduc_framework/prompts/model_maps/llama_3_2_vision/text_template.txt
@@ -0,0 +1,5 @@
+<|begin_of_text|><|start_header_id|>user<|end_header_id|>
+
+{generic_prompt_content}
+
+<|eot_id|><|start_header_id|>assistant<|end_header_id|>
\ No newline at end of file
diff --git a/aduc_framework/prompts/sound_director_prompt.txt b/aduc_framework/prompts/sound_director_prompt.txt
new file mode 100644
index 0000000000000000000000000000000000000000..1611f6d03642b3c9619806e8133f66d32c61e78b
--- /dev/null
+++ b/aduc_framework/prompts/sound_director_prompt.txt
@@ -0,0 +1,27 @@
+# ROLE: AI Sound Director & Foley Artist
+
+# GOAL:
+You are the sound director for a film. Your task is to create a single, rich, and descriptive prompt for an audio generation model (like MMAudio). This prompt must describe the complete soundscape for the CURRENT scene, considering what happened before and what will happen next to ensure audio continuity.
+
+# CRITICAL RULES (MUST FOLLOW):
+1. **NO SPEECH OR VOICES:** The final prompt must NOT include any terms related to human speech, dialogue, talking, voices, singing, or narration. The goal is to create a world of ambient sounds and specific sound effects (SFX).
+2. **FOCUS ON THE PRESENT:** The audio must primarily match the CURRENT visual scene (Keyframe Kn) and its textual description (Ato_n).
+3. **USE THE PAST FOR CONTINUITY:** Analyze the "Previous Audio Prompt" to understand the established soundscape. If a sound should logically continue from the previous scene, include it (e.g., "the continued sound of a gentle breeze...").
+4. **USE THE FUTURE FOR FORESHADOWING:** Analyze the FUTURE keyframe and scene description. If appropriate, introduce subtle sounds that hint at what's to come. (e.g., if the next scene is a storm, you could add "...with the faint, distant rumble of thunder in the background.").
+5. **BE DESCRIPTIVE:** Use evocative language. Instead of "dog bark", use "the sharp, excited yapping of a small dog". Combine multiple elements into a cohesive soundscape.
+
+# CONTEXT FOR YOUR DECISION:
+
+- **Previous Audio Prompt (what was just heard):**
+{audio_history}
+
+- **VISUAL PAST (Keyframe Kn-1):** [PAST_IMAGE]
+- **VISUAL PRESENT (Keyframe Kn):** [PRESENT_IMAGE]
+- **VISUAL FUTURE (Keyframe Kn+1):** [FUTURE_IMAGE]
+
+- **CURRENT Scene Description (Ato_n):** "{present_scene_desc}"
+- **CURRENT Motion Prompt (what the camera is doing):** "{motion_prompt}"
+- **FUTURE Scene Description (Ato_n+1):** "{future_scene_desc}"
+
+# RESPONSE FORMAT:
+Respond with ONLY the final, single-line prompt string for the audio generator.
\ No newline at end of file
diff --git a/aduc_framework/prompts/sound_director_prompt.txt.txt b/aduc_framework/prompts/sound_director_prompt.txt.txt
new file mode 100644
index 0000000000000000000000000000000000000000..1611f6d03642b3c9619806e8133f66d32c61e78b
--- /dev/null
+++ b/aduc_framework/prompts/sound_director_prompt.txt.txt
@@ -0,0 +1,27 @@
+# ROLE: AI Sound Director & Foley Artist
+
+# GOAL:
+You are the sound director for a film. Your task is to create a single, rich, and descriptive prompt for an audio generation model (like MMAudio). This prompt must describe the complete soundscape for the CURRENT scene, considering what happened before and what will happen next to ensure audio continuity.
+
+# CRITICAL RULES (MUST FOLLOW):
+1. **NO SPEECH OR VOICES:** The final prompt must NOT include any terms related to human speech, dialogue, talking, voices, singing, or narration. The goal is to create a world of ambient sounds and specific sound effects (SFX).
+2. **FOCUS ON THE PRESENT:** The audio must primarily match the CURRENT visual scene (Keyframe Kn) and its textual description (Ato_n).
+3. **USE THE PAST FOR CONTINUITY:** Analyze the "Previous Audio Prompt" to understand the established soundscape. If a sound should logically continue from the previous scene, include it (e.g., "the continued sound of a gentle breeze...").
+4. **USE THE FUTURE FOR FORESHADOWING:** Analyze the FUTURE keyframe and scene description. If appropriate, introduce subtle sounds that hint at what's to come. (e.g., if the next scene is a storm, you could add "...with the faint, distant rumble of thunder in the background.").
+5. **BE DESCRIPTIVE:** Use evocative language. Instead of "dog bark", use "the sharp, excited yapping of a small dog". Combine multiple elements into a cohesive soundscape.
+
+# CONTEXT FOR YOUR DECISION:
+
+- **Previous Audio Prompt (what was just heard):**
+{audio_history}
+
+- **VISUAL PAST (Keyframe Kn-1):** [PAST_IMAGE]
+- **VISUAL PRESENT (Keyframe Kn):** [PRESENT_IMAGE]
+- **VISUAL FUTURE (Keyframe Kn+1):** [FUTURE_IMAGE]
+
+- **CURRENT Scene Description (Ato_n):** "{present_scene_desc}"
+- **CURRENT Motion Prompt (what the camera is doing):** "{motion_prompt}"
+- **FUTURE Scene Description (Ato_n+1):** "{future_scene_desc}"
+
+# RESPONSE FORMAT:
+Respond with ONLY the final, single-line prompt string for the audio generator.
\ No newline at end of file
diff --git a/aduc_framework/prompts/task_templates/COGNITIVE_01_PLAN_KEYFRAME.txt b/aduc_framework/prompts/task_templates/COGNITIVE_01_PLAN_KEYFRAME.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e7e54aaeffa5c8ed5759b44d01b6f436a0bdcc3b
--- /dev/null
+++ b/aduc_framework/prompts/task_templates/COGNITIVE_01_PLAN_KEYFRAME.txt
@@ -0,0 +1,25 @@
+# ROLE: AI Art Director
+
+# TASK:
+# Analyze the context and generate a JSON object to direct the creation of the next keyframe.
+# Your goal is to visually connect the CURRENT scene to the FUTURE scene.
+
+# CONTEXT:
+# - History: {historico_prompt}
+# - Current Scene: "{cena_atual}"
+# - Future Scene: "{cena_futura}"
+# - Available Reference IDs: {available_ref_images}
+# - Last Keyframe: [IMG-BASE] will be provided visually.
+
+# OUTPUT (JSON REQUIRED):
+# Respond ONLY with the JSON object.
+
+# Example of the required output format:
+# ```json
+# {{
+# "composition_prompt": string,
+# "reference_images": [
+# {{"id": int, "weight": float}},
+# ]
+# }}
+# ```
\ No newline at end of file
diff --git a/aduc_framework/prompts/task_templates/COGNITIVE_02_DECIDE_MOTION.txt b/aduc_framework/prompts/task_templates/COGNITIVE_02_DECIDE_MOTION.txt
new file mode 100644
index 0000000000000000000000000000000000000000..3aab21f8bbe2be79ec1bbf3762ace7a43eab450a
--- /dev/null
+++ b/aduc_framework/prompts/task_templates/COGNITIVE_02_DECIDE_MOTION.txt
@@ -0,0 +1,16 @@
+# ROLE: AI Motion Director
+
+# TASK:
+# Create a single, complete, and objective motion prompt.
+# The prompt must describe the action and camera movement needed to transition from the PRESENT to the FUTURE keyframe.
+
+# CONTEXT:
+{story}
+
+# GUIDELINES:
+# - Combine subject action and camera movement into one fluid sentence.
+# - Be direct and descriptive, using specific terms (e.g., "slow pan left", "dolly zoom in").
+
+# OUTPUT:
+# Respond ONLY with the final, single-line prompt string. For example:
+# "The knight raises his shield to block an incoming arrow, his body tensing on impact. Slow zoom in on the shield as the arrow hits."
\ No newline at end of file
diff --git a/aduc_framework/prompts/task_templates/FAST_01_GENERATE_SCENES_AND_ACTS.txt b/aduc_framework/prompts/task_templates/FAST_01_GENERATE_SCENES_AND_ACTS.txt
new file mode 100644
index 0000000000000000000000000000000000000000..6827e2b7968a6d0893e5c1e0f4bdac7ed3a5bd72
--- /dev/null
+++ b/aduc_framework/prompts/task_templates/FAST_01_GENERATE_SCENES_AND_ACTS.txt
@@ -0,0 +1,22 @@
+# ROLE:
+Você é um Diretor de IA de alta performance, capaz de planejar e executar de forma consolidada.
+
+# GOAL:
+A partir de uma ideia geral e referências visuais, criar em uma única etapa a estrutura completa de Cenas e Atos para uma produção.
+
+# CONTEXT:
+- **Ideia Principal (O Norte):** {global_prompt}
+- **Inspiração Visual:** As imagens fornecidas.
+- **Estrutura Final Requerida:** {num_scenes} Cenas, com cada cena detalhada em atos.
+
+# REASONING_ALGORITHM (GPS APLICADO):
+1. **OBSERVE:** Analise a Ideia Principal e a atmosfera das imagens.
+2. **DECIDE (Estrutura da História):** Crie mentalmente uma história coesa usando o framework Gancho-Problema-Solução.
+3. **EXECUTE (Fragmentação Direta):**
+ a. Divida a história GPS em {num_scenes} cenas-chave independentes. Cada cena deve ser uma mini-história.
+ b. Para cada cena, detalhe-a em atos, que são os momentos de ação. Cada ato deve ser um texto curto e independente.
+4. **VALIDATE:** Garanta que a estrutura final de Cenas e Atos seja coerente e conte a história de forma eficaz.
+
+# OUTPUT_RULES:
+- A resposta deve ser APENAS um objeto JSON válido.
+- A estrutura final deve ser: {{"scenes": [{{"scene_id": int, "acts": [{{"act_id": int, "context": "texto do ato..."}}]}}]}}
\ No newline at end of file
diff --git a/aduc_framework/prompts/task_templates/P5D_TASK_01_DETAIL_SCENE_INTO_ACTS.txt b/aduc_framework/prompts/task_templates/P5D_TASK_01_DETAIL_SCENE_INTO_ACTS.txt
new file mode 100644
index 0000000000000000000000000000000000000000..87316903a7c6177271dc4339224e7e855bad020b
--- /dev/null
+++ b/aduc_framework/prompts/task_templates/P5D_TASK_01_DETAIL_SCENE_INTO_ACTS.txt
@@ -0,0 +1,42 @@
+# ROLE: Diretor de Cena e Storyboard Artist Tático de IA.
+# TASK: Fragmentar o plano de direção de uma cena em uma sequência de Atos (tomadas) tecnicamente detalhados e prontos para a filmagem.
+
+# CONTEXTO PRINCIPAL:
+# --- A CENA A SER DETALHADA (Do Manual Cinematográfico) ---
+{scene_directors_manual}
+
+# CONTEXTO DE APOIO:
+# --- A NARRATIVA GLOBAL (Para Coerência) ---
+{cinematic_narrative}
+# --- O CATÁLOGO DE ATIVOS DISPONÍVEIS (Para Seleção) ---
+{asset_catalog}
+# --- RESTRIÇÕES DE TEMPO ---
+# DURAÇÃO MÁXIMA POR ATO: {max_duration_per_act_s} segundos.
+
+# DIRECTIVES:
+1. **PROPÓSITO NARRATIVO:** Seus atos devem, acima de tudo, dar vida ao `resumo_cena`. Cada decisão deve servir à `direcao_camera` e ao `sentimento_transmitido` definidos no manual.
+2. **FRAGMENTAÇÃO LÓGICA:** Divida o `resumo_cena` em uma sequência de Atos que fluam de forma contínua, como se filmados pela mesma câmera.
+3. **ALOCAÇÃO DE ATIVOS:** Para cada Ato, no campo `ATIVOS_EM_CENA`, liste os IDs dos personagens e objetos do catálogo que estão visíveis e ativos.
+4. **CRIAÇÃO DE ATIVOS SUGERIDA:** Se a ação descreve um ativo que não está no catálogo, você **NÃO** deve adicioná-lo à lista `ATIVOS_EM_CENA`. Em vez disso, descreva-o no campo `NARRATIVA_VISUAL` e o `Planner5D` cuidará de sua criação. Ex: "Ele pega uma *lanterna antiga e enferrujada* do chão."
+5. **DESCRIÇÃO CINEMATOGRÁFICA:** Preencha todos os campos do ato de forma precisa e técnica.
+
+# OUTPUT (JSON REQUIRED):
+# Responda APENAS com um objeto JSON contendo uma chave "atos".
+
+# ESTRUTURA DO JSON DE SAÍDA:
+```{{
+ "atos": [
+ {{
+ "id_ato": 1,
+ "NARRATIVA_VISUAL": "O robô entra na clareira. A câmera o segue por trás, baixa, mostrando a escala das ruínas ao redor.",
+ "ENQUADRAMENTO": "Plano Médio (PM)",
+ "MOVIMENTACAO_DE_CAMERA": "Travelling lento acompanhando o personagem.",
+ "MOVIMENTACAO_DOS_ATIVOS": "O robô caminha de forma lenta e deliberada, escaneando o ambiente.",
+ "ATIVOS_EM_CENA": [{"id": 201, "tipo": "personagem"}],
+ "ACAO_DOS_ATIVOS": "Protagonista (ID 201) está explorando.",
+ "DURACAO_ATO": 5.0,
+ "DIALOGO": null,
+ "SFX": "Passos metálicos suaves em terra e folhas. Vento distante."
+ }}
+ ]
+}}```
\ No newline at end of file
diff --git a/aduc_framework/prompts/task_templates/STEP_01_CREATE_CONTINUOUS_STORY.txt b/aduc_framework/prompts/task_templates/STEP_01_CREATE_CONTINUOUS_STORY.txt
new file mode 100644
index 0000000000000000000000000000000000000000..95b5aec7e5e84e2bdd91e7f7ca4d6acbfa30058e
--- /dev/null
+++ b/aduc_framework/prompts/task_templates/STEP_01_CREATE_CONTINUOUS_STORY.txt
@@ -0,0 +1,20 @@
+# ROLE:
+Você é um roteirista mestre e contador de histórias, especialista em criar narrativas que cativam.
+
+# DEFAULT_REASONING_FRAMEWORK (GPS):
+Para construir a história, siga mentalmente a estrutura Gancho-Problema-Solução (GPS), a menos que a Ideia Principal sugira um formato diferente.
+- **Gancho:** Comece com uma imagem ou ação intrigante que prenda a atenção.
+- **Problema:** Introduza um pequeno desafio, tensão ou questão.
+- **Solução:** Conclua a narrativa resolvendo o problema ou respondendo à questão.
+
+# GOAL:
+Escrever uma história emocionante, inteligente e positiva, dividida em exatamente {num_scenes} parágrafos. A história deve ser uma narrativa contínua, onde cada parágrafo é uma sequência direta do anterior.
+
+# CONTEXT:
+- **Ideia Principal (A Verdade Absoluta):** {global_prompt}
+- **Inspiração Visual:** As imagens fornecidas são sua paleta de emoções e estilo. A história deve sintetizar a Ideia Principal com a atmosfera dessas imagens.
+
+# OUTPUT_RULES:
+- A resposta deve conter APENAS o texto da história.
+- O texto deve ter exatamente {num_scenes} parágrafos.
+- Não inclua títulos, notas, justificativas ou qualquer formatação.
\ No newline at end of file
diff --git a/aduc_framework/prompts/task_templates/STEP_02_CREATE_INDEPENDENT_SCENES.txt b/aduc_framework/prompts/task_templates/STEP_02_CREATE_INDEPENDENT_SCENES.txt
new file mode 100644
index 0000000000000000000000000000000000000000..7b052c0fb30a92f3cbbdba0457747be21448c340
--- /dev/null
+++ b/aduc_framework/prompts/task_templates/STEP_02_CREATE_INDEPENDENT_SCENES.txt
@@ -0,0 +1,15 @@
+# ROLE:
+Você é um editor de roteiros focado em impacto. Sua tarefa é transformar uma narrativa contínua em cenas independentes e poderosas.
+
+# GOAL:
+Reescrever cada parágrafo da história fornecida como uma cena autônoma. Cada cena deve funcionar como um curta-metragem, com sua própria estrutura GPS (Gancho, Problema, Solução), enquanto ainda pertence ao universo da história original.
+
+# CONTEXT:
+- **História Contínua Original:**
+{continuous_story}
+
+# OUTPUT_RULES:
+- A resposta deve ser APENAS um objeto JSON válido.
+- Estrutura do JSON: {{"scenes": [string, ...]}}
+- Cada cena na lista deve ser um texto contendo contando uma história individual.as com mesmo contexto
+- Cada cena deve ser 100% compreensível por si só.
\ No newline at end of file
diff --git a/aduc_framework/prompts/task_templates/STEP_03_FRAGMENT_SCENES_INTO_ACTS.txt b/aduc_framework/prompts/task_templates/STEP_03_FRAGMENT_SCENES_INTO_ACTS.txt
new file mode 100644
index 0000000000000000000000000000000000000000..1ae3077a8707c6711fc4b6dc6b4079d257b89eab
--- /dev/null
+++ b/aduc_framework/prompts/task_templates/STEP_03_FRAGMENT_SCENES_INTO_ACTS.txt
@@ -0,0 +1,21 @@
+# ROLE:
+Você é um diretor de cena, mestre em detalhar a ação momento a momento.
+
+# GOAL:
+Pegar um roteiro de cenas e fragmentar cada uma delas em uma sequência de atos. Cada parágrafo de uma cena se tornará um ato. Cada ato deve ser reescrito como um único momento narrativo, uma "fotografia em movimento" que seja independente.
+
+# CONTEXT:
+- **Roteiro de Cenas Independentes:**
+{independent_scenes_json}
+
+# OUTPUT_RULES:
+- A resposta deve ser APENAS um objeto JSON válido.
+- Estrutura final do JSON:
+
+```
+{{"scenes":
+["scene_id": int,
+"acts": ["act_id": int, "context": "texto do ato..."]]}}```
+
+
+- O "context" de cada ato deve ser um texto de (1 parágrafos) descrevendo exatamente o momento
\ No newline at end of file
diff --git a/aduc_framework/prompts/task_templates/STEP_04_FINAL_REVIEW.txt b/aduc_framework/prompts/task_templates/STEP_04_FINAL_REVIEW.txt
new file mode 100644
index 0000000000000000000000000000000000000000..9d40f41e222a5b610b18ae3f5be5949f5132f964
--- /dev/null
+++ b/aduc_framework/prompts/task_templates/STEP_04_FINAL_REVIEW.txt
@@ -0,0 +1,19 @@
+# ROLE:
+Você é o Supervisor de Roteiro e Guardião da Visão Original. Sua tarefa é a revisão final e crítica do plano de produção.
+
+# GOAL:
+Analisar a estrutura final de cenas e atos e, se necessário, reescrever qualquer parte para garantir o alinhamento perfeito com a Ideia Principal.
+
+# CONTEXT:
+- **A Visão Original (Prioridade Máxima):** {global_prompt}
+- **O Plano de Produção Atual para Revisão:**
+{final_plan_json}
+
+# REASONING_ALGORITHM:
+1. **OBSERVE:** Leia a Visão Original. Depois, leia o Plano de Produção.
+2. **DECIDE:** A história contada pelos atos reflete a emoção e o objetivo da Visão Original? Existe alguma incoerência? Algum ato poderia ser mais poderoso ou claro?
+3. **EXECUTE:** Se precisar de ajustes, modifique o texto ("context") dos atos diretamente no JSON. Se o plano estiver perfeito e alinhado, retorne-o sem nenhuma modificação.
+
+# OUTPUT_RULES:
+- A resposta deve ser APENAS o objeto JSON final, seja ele o original ou a sua versão revisada.
+- Não inclua justificativas ou explicações no output.
\ No newline at end of file
diff --git a/aduc_framework/prompts/task_templates/TASK_01_CREATE_CINEMATIC_NARRATIVE.txt b/aduc_framework/prompts/task_templates/TASK_01_CREATE_CINEMATIC_NARRATIVE.txt
new file mode 100644
index 0000000000000000000000000000000000000000..6ca4b2a3aa3bb761e760be6950721b1cb8e5952a
--- /dev/null
+++ b/aduc_framework/prompts/task_templates/TASK_01_CREATE_CINEMATIC_NARRATIVE.txt
@@ -0,0 +1,38 @@
+# ROLE: Diretor de Roteiro Visual Cinematográfico com IA
+# TASK: Criar uma narrativa visual cativante e filmável que prenda o espectador do início ao fim
+
+# CONTEXT:
+- **Ideia Nuclear**: {global_prompt}
+- **Referências Visuais**: [Imagens como âncoras narrativas]
+
+# NARRATIVE STRUCTURE (OBRIGATÓRIO):
+**GANCHO INICIAL**: Comece com um elemento intrigante, ameaça, mistério ou situação inesperada que capture atenção imediatamente. Estabeleça o "mundo normal" e quebre-o rapidamente.
+**PROBLEMA CENTRAL**: Identifique um conflito visual claro que o protagonista/elemento principal deve resolver. Pode ser um obstáculo físico, uma ameaça, uma busca, ou transformação necessária.
+**ESCALADA DE TENSÃO **: Cada parageafo deve intensificar o problema, criar novos obstáculos ou complicações visuais. Aumente as apostas progressivamente.
+**CLÍMAX VISUAL **: O momento de maior tensão onde o problema atinge seu pico e exige resolução imediata.
+**RESOLUÇÃO **: Mostre como o problema é resolvido visualmente, revelando o "novo normal" transformado.
+
+# DIRECTIVES:
+1. **HISTÓRIA CATIVANTE:** Crie uma sequência de eventos que gere curiosidade, suspense ou fascinação. O espectador deve QUERER saber o que acontece depois.
+2. **AÇÃO CINÉTICA PURA:** Descreva APENAS movimentos, gestos, transformações e eventos visuais. Zero estados mentais ou abstrações.
+4. **ELEMENTOS DE HOOK:** Use mistério, ameaça, surpresa, segredo ou paradoxo para manter engajamento. Faça perguntas visuais que só serão respondidas depois.
+5. **PROBLEMA-SOLUÇÃO VISUAL:** O conflito deve ser algo que podemos VER sendo enfrentado e resolvido através de ações físicas.
+6. **RITMO DRAMÁTICO:** Alterne momentos de alta/baixa intensidade. Construa tensão progressivamente até o clímax visual.
+
+# CONSTRAINTS:
+- História deve fazer SENTIDO do início ao fim
+- Cada paragrafo deve avançar o problema ou a solução
+- Zero diálogos, pensamentos ou julgamentos
+- Máximo foco na progressão visual dramática
+- Inspiração obrigatória das referências visuais
+
+# CHECKLIST ANTES DE ESCREVER:
+- [ ] Tem um gancho que prende na primeira cena?
+- [ ] O problema central é claro e visual?
+- [ ] Cada cena avança a história ou aumenta tensão?
+- [ ] Tem um clímax visual satisfatório?
+- [ ] A resolução fecha o arco narrativo?
+- [ ] A história é cativante do início ao fim?
+
+# OUTPUT FORMAT:
+Texto corrido da narrativa visual. Sem títulos, numeração ou metadados. Fluxo cinematográfico puro com arco dramático completo e engajamento garantido.
\ No newline at end of file
diff --git a/aduc_framework/prompts/task_templates/TASK_02_SELECT_AND_CATALOG_ASSETS.txt b/aduc_framework/prompts/task_templates/TASK_02_SELECT_AND_CATALOG_ASSETS.txt
new file mode 100644
index 0000000000000000000000000000000000000000..dfb6f1c363fcebeb53f4c1bab5d565a8bcd94a8c
--- /dev/null
+++ b/aduc_framework/prompts/task_templates/TASK_02_SELECT_AND_CATALOG_ASSETS.txt
@@ -0,0 +1,47 @@
+# ROLE: Diretor de Ativos de IA e Guardião da Continuidade Visual.
+# TASK: A partir da narrativa e das imagens de referência, criar um catálogo de ativos universal.
+
+# CONTEXT:
+# - A Narrativa Global já está em nossa conversa.
+# - As imagens de referência estão sendo fornecidas visualmente junto com este prompt.
+# - MAPA DE TAGS DE REFERÊNCIA (Sua paleta de ativos existentes):
+{image_map}
+
+# DIRECTIVES:
+1. **SISTEMA DE ID UNIVERSAL:** Todos os ativos, sejam eles das imagens de referência ou novos, devem ter um ID em formato de tag.
+2. **CATALOGAR REFERÊNCIAS:** Ao catalogar um ativo que vem de uma imagem de referência, o campo `caminho_original` DEVE ser a `tag_referencia` exata do mapa acima (ex: ""). O campo `id` deve ser uma nova tag que você inventa para o ativo (ex: "").
+3. **CRIAR NOVOS ATIVOS:** Se a narrativa exige um ativo que não está nas referências, você DEVE inventar um novo ID para ele no formato ``, onde XXX é um número único (ex: ``). Para estes, defina `caminho_original` como `null`.
+4. **FORMATO ESTRITO:** Sua resposta DEVE ser um objeto JSON. Use as chaves `"id"`, `"prompt"`, `"caminho_original"`, e `"observacao"` EXATAMENTE como no exemplo.
+
+# OUTPUT (JSON REQUIRED):
+# Responda APENAS com o objeto JSON.
+
+# Exemplo da Estrutura de Saída Exata (USANDO O SISTEMA DE TAGS UNIVERSAL):
+# ```json
+# {{
+# "cenarios": [
+# {{
+# "id": "",
+# "prompt": "cidade futurista em ruínas, coberta por vegetação densa",
+# "caminho_original": "",
+# "observacao": "Usar a referência como base para a atmosfera, mas remover o robô."
+# }}
+# ],
+# "personagens": [
+# {{
+# "id": "",
+# "prompt": "robô bípede pequeno e desgastado com um único olho azul luminoso",
+# "caminho_original": "",
+# "observacao": "Isolar o robô da referência ."
+# }}
+# ],
+# "objetos": [
+# {{
+# "id": "",
+# "prompt": "um pequeno drone de reconhecimento, enferrujado e coberto de musgo",
+# "caminho_original": null,
+# "observacao": "Ativo a ser gerado do zero. Deve ter o mesmo estilo visual de ."
+# }}
+# ]
+# }}
+# ```
\ No newline at end of file
diff --git a/aduc_framework/prompts/task_templates/TASK_03_CREATE_DIRECTORS_STORYBOARD.txt b/aduc_framework/prompts/task_templates/TASK_03_CREATE_DIRECTORS_STORYBOARD.txt
new file mode 100644
index 0000000000000000000000000000000000000000..5e431fe892225d4c44d7074e3e113ef595f5408d
--- /dev/null
+++ b/aduc_framework/prompts/task_templates/TASK_03_CREATE_DIRECTORS_STORYBOARD.txt
@@ -0,0 +1,48 @@
+# ROLE: Diretor de Cinema e Editor de Estrutura de IA.
+# TASK: Transformar a narrativa e o catálogo de ativos em um Storyboard de Direção técnico e criativo, pronto para a produção.
+
+# CONTEXT:
+# - A Narrativa Global e o Catálogo de Ativos estão no nosso histórico de conversa.
+- Número de Cenas Alvo: {num_scenes}
+
+# DIRECTIVES:
+1. **LIBERDADE CRIATIVA PARA CENÁRIOS:** Para cada cena, sua principal tarefa é escolher o `cenario_escolhido` ideal.
+ * **OPÇÃO A (Usar Existente):** Se um cenário do catálogo de ativos se encaixa perfeitamente, use seu `id` e `prompt` exatos.
+ * **OPÇÃO B (Criar Novo):** Se a narrativa pede por um cenário que NÃO está no catálogo, você TEM A LIBERDADE de criar um novo. Para isso:
+ * Invente um novo `id` no formato ``.
+ * Escreva um `prompt` detalhado e cinematográfico para o novo cenário.
+ * Defina `caminho_original` como `null`.
+2. **DIRETRIZES TÉCNICAS:** Preencha TODOS os campos obrigatórios. Seja preciso e criativo.
+3. **ESPECIFICAÇÕES DE ESTILO:** Use o campo `especificacoes_tecnicas` como um dicionário para agrupar todos os detalhes de estilo (iluminação, paleta de cores, ritmo, etc.).
+4. **FORMATO ESTRITO:** Siga a estrutura JSON de saída EXATAMENTE. Garanta que cada cena tenha um `id_cena` numérico e sequencial.
+
+# OUTPUT (JSON REQUIRED):
+# Responda APENAS com o objeto JSON final, sem comentários.
+
+# Exemplo da Estrutura de Saída Exata (COM UM CENÁRIO NOVO SENDO CRIADO):
+# ```json
+# {{
+# "storyboard": [
+# {{
+# "id_cena": 1,
+# "tipo_cena": "Exposição",
+# "titulo_cena": "A Chegada Silenciosa",
+# "resumo_cena": "Um robô solitário emerge e entra nas ruínas de uma cidade antiga.",
+# "cenario_escolhido": {{
+# "id": "",
+# "prompt": "Uma caverna subterrânea vasta e úmida, iluminada por cristais bioluminescentes azuis nas paredes.",
+# "caminho_original": null,
+# "observacao": "Este cenário é crucial para o clímax e precisa ser criado."
+# }},
+# "duracao_estimada_s": 10.5,
+# "direcao_camera": "A câmera segue o robô por trás, revelando a imensidão da caverna.",
+# "sentimento_transmitido": "Solidão, mistério e uma sensação de admiração.",
+# "especificacoes_tecnicas": {{
+# "iluminacao": "Luz azulada e fria dos cristais, criando reflexos na carcaça do robô.",
+# "paleta_cores": "Tons de azul, preto e cinza metálico.",
+# "ritmo": "Lento e contemplativo."
+# }}
+# }}
+# ]
+# }}
+# ```
\ No newline at end of file
diff --git a/aduc_framework/prompts/task_templates/TASK_04_DETAIL_SCENE_INTO_ACTS.txt b/aduc_framework/prompts/task_templates/TASK_04_DETAIL_SCENE_INTO_ACTS.txt
new file mode 100644
index 0000000000000000000000000000000000000000..58f87ebca5ea9a7aa663933910481b36838bdb11
--- /dev/null
+++ b/aduc_framework/prompts/task_templates/TASK_04_DETAIL_SCENE_INTO_ACTS.txt
@@ -0,0 +1,40 @@
+# ROLE: Diretor de Cena e Storyboard Artist Tático de IA.
+# TASK: Ótimo, agora vamos focar nesta cena específica. Sua tarefa é detalhar o plano de direção em uma sequência de Atos (tomadas) tecnicamente precisos e prontos para a filmagem.
+
+# CONTEXTO PRINCIPAL (O Foco da Nossa Atenção):
+# --- A CENA A SER DETALHADA ---
+{scene_directors_manual}
+
+# CONTEXTO DE APOIO (Da Nossa Conversa Anterior):
+# (A Narrativa Global e o Catálogo de Ativos já estão no nosso histórico.)
+- **ÂNCORA CONTEXTUAL:** Lembre-se, esta cena corresponde ao seguinte trecho da Narrativa Global:
+"{trecho_correspondente_da_narrativa_global}"
+- **RESTRIÇÕES DE TEMPO:** A duração máxima para cada ato é de {max_duration_per_act_s} segundos.
+
+# DIRECTIVES:
+1. **PROPÓSITO NARRATIVO:** Seus atos devem, acima de tudo, dar vida ao `resumo_cena` e ao trecho correspondente da narrativa, respeitando a `direcao_camera` e o `sentimento_transmitido` que já definimos.
+2. **FRAGMENTAÇÃO LÓGICA:** Divida a cena em uma sequência de Atos que fluam de forma contínua, como se filmados pela mesma câmera.
+3. **ALOCAÇÃO DE ATIVOS:** Para cada Ato, no campo `ATIVOS_EM_CENA`, liste os IDs dos personagens e objetos do nosso catálogo que estão visíveis e ativos.
+4. **DESCRIÇÃO CINEMATOGRÁFICA:** Preencha todos os campos do ato de forma precisa e técnica, com foco em "mostrar", não "contar".
+5. **PREPARAR O FUTURO:** O último ato desta cena deve criar uma ponte clara que leve à próxima parte da história.
+
+# OUTPUT (JSON REQUIRED):
+# Responda APENAS com um objeto JSON contendo uma única chave "atos".
+
+# Exemplo da Estrutura de Saída Exata:
+# ```{{
+# "atos": [
+# {{
+# "id_ato": 1,
+# "NARRATIVA_VISUAL": "O robô entra na clareira. A câmera o segue por trás, baixa, mostrando a escala das ruínas ao redor.",
+# "ENQUADRAMENTO": "Plano Médio (PM)",
+# "MOVIMENTACAO_DE_CAMERA": "Travelling lento acompanhando o personagem.",
+# "MOVIMENTACAO_DOS_ATIVOS": "O robô caminha de forma lenta e deliberada, escaneando o ambiente.",
+# "ATIVOS_EM_CENA": [{{"id": 201, "tipo": "personagem"}}],
+# "ACAO_DOS_ATIVOS": "Protagonista (ID 201) está explorando.",
+# "DURACAO_ATO": 5.0,
+# "DIALOGO": null,
+# "SFX": "Passos metálicos suaves em terra e folhas. Vento distante."
+# }}
+# ]
+# }}```
\ No newline at end of file
diff --git a/aduc_framework/prompts/task_templates/TASK_05_SCENE_CONTINUITY_REVIEW.txt b/aduc_framework/prompts/task_templates/TASK_05_SCENE_CONTINUITY_REVIEW.txt
new file mode 100644
index 0000000000000000000000000000000000000000..b6afb3db17e33e91927a0dd3230742f002c935b2
--- /dev/null
+++ b/aduc_framework/prompts/task_templates/TASK_05_SCENE_CONTINUITY_REVIEW.txt
@@ -0,0 +1,18 @@
+# ROLE: Supervisor de Roteiro e Guardião da Coerência Narrativa.
+# TASK: Refinar uma única cena específica, usando o contexto completo do filme que você acabou de analisar.
+
+# CONTEXTO:
+Lembre-se do storyboard completo que você analisou na etapa anterior. Use esse conhecimento global para tomar suas decisões de edição.
+
+# FOCO DA TAREFA ATUAL (A cena que você deve analisar e refinar):
+# --- JSON COMPLETO DA CENA A SER REVISADA ---
+{scene_to_review_json}
+
+# DIRETRIZES PARA REVISÃO:
+1. **FLUXO NARRATIVO:** Esta cena serve bem ao seu propósito entre a cena anterior e a próxima no storyboard completo?
+2. **RITMO E DURAÇÃO:** A `duracao_estimada_s` está apropriada para o lugar desta cena na história?
+3. **REFINAR, NÃO REESCREVER:** Seu objetivo é fazer ajustes finos. Melhore o texto, ajuste a duração, refine a `direcao_camera`. Não mude o conceito central da cena.
+
+# OUTPUT (JSON REQUIRED):
+# Responda APENAS com o objeto JSON da cena que você revisou, completo e refinado.
+# A estrutura do JSON de saída deve ser IDÊNTICA à da cena de entrada.
\ No newline at end of file
diff --git a/aduc_framework/prompts/task_templates/TASK_06_IMPROVISE_FIRST_KEYFRAME_SCENE.txt b/aduc_framework/prompts/task_templates/TASK_06_IMPROVISE_FIRST_KEYFRAME_SCENE.txt
new file mode 100644
index 0000000000000000000000000000000000000000..b251557b9bcadd0f969901ef1fe49a772c555de9
--- /dev/null
+++ b/aduc_framework/prompts/task_templates/TASK_06_IMPROVISE_FIRST_KEYFRAME_SCENE.txt
@@ -0,0 +1,22 @@
+# ROLE: Diretor de Arte e Fotógrafo de Set.
+# TASK: Criar o "establishing shot" (a imagem de abertura) para a cena.
+
+# CONTEXTO:
+# Estamos prestes a filmar uma nova cena. Sua tarefa é criar o prompt visual para o PRIMEIRO keyframe (K0).
+# Esta imagem definirá o tom, a iluminação e a composição de toda a cena.
+
+# O ROTEIRO DIZ QUE A CENA COMEÇA ASSIM:
+# --- NARRATIVA DO PRIMEIRO ATO ---
+{first_act_narrative}
+
+# ATIVOS VISUAIS DISPONÍVEIS (Use-os como inspiração principal):
+# --- ATIVOS EM CENA (Personagens, Cenário, Objetos) ---
+{assets_in_scene_json}
+
+# DIRETIVAS:
+1. **ESTABELEÇA O TOM:** O prompt deve capturar a essência do `sentimento_transmitido` e da `atmosfera` da cena.
+2. **COMPOSIÇÃO FORTE:** Descreva uma imagem icônica e bem composta que introduza os elementos principais do ato.
+3. **SEJA CINEMATOGRÁFICO:** Use linguagem de direção de arte (ex: "luz Rembrandt suave", "composição em terços", "atmosfera enevoada").
+
+# OUTPUT:
+Responda APENAS com a string do prompt para o keyframe inicial
\ No newline at end of file
diff --git a/aduc_framework/prompts/task_templates/TASK_07_IMPROVISE_NEXT_KEYFRAME.txt b/aduc_framework/prompts/task_templates/TASK_07_IMPROVISE_NEXT_KEYFRAME.txt
new file mode 100644
index 0000000000000000000000000000000000000000..5c249ce747ae3f29854346014c8894e8cfa27a9e
--- /dev/null
+++ b/aduc_framework/prompts/task_templates/TASK_07_IMPROVISE_NEXT_KEYFRAME.txt
@@ -0,0 +1,18 @@
+# ROLE: Diretor de Continuidade e Improvisação Visual.
+# TASK: Analisar o último frame de vídeo gerado e, com base na próxima intenção do roteiro, criar um prompt visual preciso para o PRÓXIMO keyframe.
+
+# CONTEXTO:
+# Estamos filmando um filme de forma iterativa. Acabamos de gerar um clipe.
+# A imagem fornecida é o ÚLTIMO FRAME REAL desse clipe. É o nosso ponto de partida.
+
+# O ROTEIRO DIZ QUE O PRÓXIMO MOMENTO É:
+# --- NARRATIVA DO PRÓXIMO ATO ---
+{next_act_narrative}
+
+# DIRETIVAS:
+1. **ANCORE NO REAL:** Sua principal fonte de verdade é a imagem fornecida. O próximo keyframe DEVE ser uma continuação visualmente crível dela.
+2. **SIGA A INTENÇÃO:** Use a "NARRATIVA DO PRÓXIMO ATO" como seu guia para a ação e a emoção que precisam acontecer.
+3. **SEJA UM DIRETOR:** Crie um prompt de imagem (estilo CLIP) denso e descritivo. Foque na pose, expressão e composição que movem a história para o próximo ato.
+
+# OUTPUT:
+Responda APENAS com a string do prompt para o novo keyframe.
\ No newline at end of file
diff --git a/aduc_framework/prompts/task_templates/TASK_08_IMPROVISE_CINEMATIC_PROMPT_ATO.txt b/aduc_framework/prompts/task_templates/TASK_08_IMPROVISE_CINEMATIC_PROMPT_ATO.txt
new file mode 100644
index 0000000000000000000000000000000000000000..9e67bfda72df54f496ac8a4338df8e97839cccfb
--- /dev/null
+++ b/aduc_framework/prompts/task_templates/TASK_08_IMPROVISE_CINEMATIC_PROMPT_ATO.txt
@@ -0,0 +1,21 @@
+# ROLE: Diretor de Fotografia e Operador de Câmera.
+# TASK: Criar um prompt de MOVIMENTO (motion prompt) que conecte cinematicamente a imagem INICIAL com a imagem FINAL.
+
+# CONTEXTO:
+# Estamos filmando um único ato (uma tomada). Temos a imagem onde a ação começa e a imagem onde ela termina.
+# Sua tarefa é descrever a ação e o movimento da câmera que acontecem ENTRE esses dois pontos.
+
+# IMAGEM INICIAL (Onde estamos): [A imagem será fornecida visualmente]
+# IMAGEM FINAL (Para onde vamos): [A imagem será fornecida visualmente]
+
+# O ROTEIRO DIZ QUE A AÇÃO DESTE ATO É:
+# --- NARRATIVA DO ATO ATUAL ---
+{current_act_narrative}
+
+# DIRETIVAS:
+1. **FOCO NO MOVIMENTO:** Descreva a ação dos personagens/objetos E o movimento da câmera (pan, tilt, dolly, zoom, etc.).
+2. **CRIE UMA TRANSIÇÃO LÓGICA:** O movimento deve levar de forma crível da composição da imagem inicial para a composição da imagem final.
+3. **SEJA CONCISO E DENSO:** Use um estilo CLIP. Frases curtas, ricas em adjetivos e verbos de ação.
+
+# OUTPUT:
+Responda APENAS com a string do prompt de movimento para este ato.
\ No newline at end of file
diff --git a/aduc_framework/prompts/task_templates/TASK_4_5_PRE_REVIEW_CONTEXT.txt b/aduc_framework/prompts/task_templates/TASK_4_5_PRE_REVIEW_CONTEXT.txt
new file mode 100644
index 0000000000000000000000000000000000000000..923a5ee44a68aea109fa19b9b2366d5534948428
--- /dev/null
+++ b/aduc_framework/prompts/task_templates/TASK_4_5_PRE_REVIEW_CONTEXT.txt
@@ -0,0 +1,15 @@
+# ROLE: Supervisor de Roteiro e Guardião da Coerência Narrativa.
+# TASK: Absorver e analisar o rascunho completo do storyboard que você acabou de criar.
+
+# MENSAGEM DO DIRETOR:
+"Excelente trabalho neste rascunho inicial. A estrutura completa do filme está definida no JSON abaixo, incluindo a narrativa, os ativos e o detalhamento de cada cena em atos.
+
+Agora, vamos entrar na fase de POLIMENTO. Sua tarefa é analisar este plano completo. Pense no fluxo geral, no ritmo e no arco emocional.
+
+Na próxima etapa, vou te enviar CADA CENA, UMA DE CADA VEZ, para que você possa fazer os ajustes finos necessários. Prepare-se para a revisão."
+
+# CONTEXTO COMPLETO PARA SUA ANÁLISE (O STORYBOARD COMPLETO):
+{full_storyboard_json}
+
+# OUTPUT:
+Responda com uma confirmação curta, como "Entendido. Storyboard completo analisado. Estou pronto para a revisão cena a cena."
\ No newline at end of file
diff --git a/aduc_framework/prompts/transition_decision_prompt.txt b/aduc_framework/prompts/transition_decision_prompt.txt
new file mode 100644
index 0000000000000000000000000000000000000000..6607099eb2a8aa2ddd7cb7d1ed401298687f5e6d
--- /dev/null
+++ b/aduc_framework/prompts/transition_decision_prompt.txt
@@ -0,0 +1,27 @@
+# ROLE: AI Director of Continuity & Cinematographer
+
+# GOAL:
+Analyze the visual continuity between a START, MIDPOINT, and DESTINATION image. Make a directorial decision: is the transition a "continuous" action or does it require a "cut"? Then, write the appropriate motion prompt.
+
+# INSTRUCTIONS:
+1. **Analyze Continuity:** Can a subject logically and physically move from START, through MIDPOINT, to DESTINATION in a few seconds of continuous screen time? Consider changes in location, pose, and time of day.
+ * **Continuous Example:** Man walks to door (START) -> Hand on doorknob (MIDPOINT) -> Man walks through door (DESTINATION).
+ * **Cut Example:** Woman outside house (START) -> Close up on face (MIDPOINT) -> Woman now inside house (DESTINATION).
+2. **Make a Decision:**
+ * If the action is unbroken, decide `"transition_type": "continuous"`.
+ * If there is a jump in time, space, or logic, decide `"transition_type": "cut"`.
+3. **Write Motion Prompt:**
+ * **For "continuous":** Describe the physical action and camera movement. Example: "Camera follows the man as he opens the door and steps inside."
+ * **For "cut":** Describe a cinematic transition effect. DO NOT describe character actions. Example: "A smooth cross-dissolve transition to the new scene."
+
+# CONTEXT:
+- Overall Story Goal: "{user_prompt}"
+- Story So Far: {story_history}
+
+# SCENE ANALYSIS:
+# START Image (Memory from last fragment): [Image 1]
+# MIDPOINT Image (Path): [Image 2]
+# DESTINATION Image (Destination): [Image 3]
+
+# RESPONSE FORMAT:
+You MUST respond with a single, clean JSON object with two keys: "transition_type" and "motion_prompt".
\ No newline at end of file
diff --git a/aduc_framework/prompts/unified_cinematographer_prompt.txt b/aduc_framework/prompts/unified_cinematographer_prompt.txt
new file mode 100644
index 0000000000000000000000000000000000000000..7d4f23924ad6e00e2afbb1d71e510a3a3dbb9262
--- /dev/null
+++ b/aduc_framework/prompts/unified_cinematographer_prompt.txt
@@ -0,0 +1,47 @@
+# ROLE: AI Continuity Director & Cinematographer
+
+# GOAL:
+Your task is twofold. First, analyze two keyframe images (current and future) and their context to generate a precise, cinematic motion prompt describing the transition between them. Second, calculate a "Similarity Score" between the two images based on a strict set of criteria.
+
+# --- TASK 1: Generate Cinematic Motion Prompt ---
+
+# CONTEXT:
+- Previous Motion Prompt (what I thought before):
+{historico_prompt}
+
+- Current Scene Description (where we are now): "{cena_atual}"
+- Future Scene Description (where we are going next): "{cena_futura}"
+
+# INSTRUCTIONS for Motion Prompt:
+You must generate a single, concise, CLIP-style motion prompt describing the action that connects the CURRENT image to the FUTURE image. The prompt must be dense and descriptive, following this priority order:
+1. **People/Animals:** Focus on expression, emotion, and specific actions.
+2. **Objects:** Describe their location and any interaction or movement.
+3. **Camera:** Specify focus, zoom, and movement (pan, tilt, dolly, etc.).
+
+Your prompt should describe the moment unfolding BETWEEN the current and future state.
+
+# --- TASK 2: Calculate Similarity Score ---
+
+# INSTRUCTIONS for Similarity Score:
+Calculate a similarity score between the CURRENT and FUTURE images, ranging from 0.0 (completely different) to 1.0 (very similar).
+
+**Consider ONLY the following criteria for similarity:**
+- **Objects:** Consistency in colors, textures, and relative sizes.
+- **People/Animals:** Consistency in morphology (body shape), clothing, and accessories.
+- **Environment:** Consistency in location, time of day (lighting), colors, and background/horizon.
+
+**Disregard the following for similarity:**
+- Repositioning or movement of subjects or the camera.
+
+**Negative Factors (Penalties):**
+- If the horizontal positions of two or more people are inverted (e.g., person A was on the left and is now on the right), REDUCE THE FINAL SCORE BY HALF (multiply by 0.5).
+- If the entire image appears horizontally flipped (mirrored), REDUCE THE FINAL SCORE BY HALF (multiply by 0.5).
+
+# VISUAL ASSETS:
+# [The CURRENT keyframe image will be provided here.]
+# [The FUTURE keyframe image will be provided here.]
+
+# --- RESPONSE FORMAT ---
+You MUST respond with a single, clean JSON object with exactly two keys:
+1. "motion_prompt": A string containing the generated cinematic prompt.
+2. "similarity_score": A floating-point number between 0.0 and 1.0.
\ No newline at end of file
diff --git a/aduc_framework/prompts/unified_storyboard_prompt.txt b/aduc_framework/prompts/unified_storyboard_prompt.txt
new file mode 100644
index 0000000000000000000000000000000000000000..81d80363c76b52afcb2b6d123eca26c745bfe4ef
--- /dev/null
+++ b/aduc_framework/prompts/unified_storyboard_prompt.txt
@@ -0,0 +1,19 @@
+# ROLE: AI Storyboard Writer
+
+# GOAL:
+You are a scriptwriter tasked with breaking down a general idea into a sequence of exactly {num_fragments} distinct scenes or "acts". Each scene should represent a clear, single moment in a linear narrative.
+
+# CRITICAL RULES (MUST FOLLOW):
+1. **ANCHOR TO THE REFERENCE IMAGES:** The narrative, characters, and style MUST be directly inspired by the provided reference images. The story should feel like it belongs in the same world as these images.
+2. **SIMPLE, LINEAR ACTION:** Do not create a complex plot. The entire sequence should represent a single, simple story arc unfolding over a few moments (e.g., a character notices something, approaches it, and reacts).
+3. **FOCUS ON "WHAT", NOT "HOW":** Each description is a scene, not a camera direction. Describe the core action or emotional beat of the moment. Example: "The knight raises his shield" instead of "Close-up on the knight raising his shield".
+
+# CONTEXT:
+- General Idea (User Prompt): "{user_prompt}"
+- Number of Scenes to Create: {num_fragments}
+
+# YOUR TASK:
+Based on the user's idea and the reference images, create a storyboard that tells a simple, continuous story across {num_fragments} scenes.
+
+# RESPONSE FORMAT:
+Return a single JSON object with the key "scene_storyboard", containing an array of strings (the scene descriptions).
\ No newline at end of file
diff --git a/aduc_framework/tools/LICENSE b/aduc_framework/tools/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..e6fb40ab269ce532dd06cc34da2f86bc5f5441cd
--- /dev/null
+++ b/aduc_framework/tools/LICENSE
@@ -0,0 +1,25 @@
+# Euia-AducSdr: Uma implementação aberta e funcional da arquitetura ADUC-SDR para geração de vídeo coerente.
+# Copyright (C) 4 de Agosto de 2025 Carlos Rodrigues dos Santos
+#
+# Contato:
+# Carlos Rodrigues dos Santos
+# carlex22@gmail.com
+# Rua Eduardo Carlos Pereira, 4125, B1 Ap32, Curitiba, PR, Brazil, CEP 8102025
+#
+# Repositórios e Projetos Relacionados:
+# GitHub: https://github.com/carlex22/Aduc-sdr
+# Hugging Face (Ltx-SuperTime-60Secondos): https://huggingface.co/spaces/Carlexx/Ltx-SuperTime-60Secondos/
+# Hugging Face (Novinho): https://huggingface.co/spaces/Carlexxx/Novinho/
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
\ No newline at end of file
diff --git a/aduc_framework/tools/NOTICE.md b/aduc_framework/tools/NOTICE.md
new file mode 100644
index 0000000000000000000000000000000000000000..e6dad38733a306f61263d083c471e6bac403e222
--- /dev/null
+++ b/aduc_framework/tools/NOTICE.md
@@ -0,0 +1,76 @@
+# NOTICE
+
+Copyright (C) 2025 Carlos Rodrigues dos Santos. All rights reserved.
+
+---
+
+## Aviso de Propriedade Intelectual e Licenciamento
+
+### **Processo de Patenteamento em Andamento (EM PORTUGUÊS):**
+
+O método e o sistema de orquestração de prompts denominados **ADUC (Automated Discovery and Orchestration of Complex tasks)**, conforme descritos neste documento e implementados neste software, estão atualmente em processo de patenteamento.
+
+O titular dos direitos, Carlos Rodrigues dos Santos, está buscando proteção legal para as inovações chave da arquitetura ADUC, incluindo, mas não se limitando a:
+
+* Fragmentação e escalonamento de solicitações que excedem limites de contexto de modelos de IA.
+* Distribuição inteligente de sub-tarefas para especialistas heterogêneos.
+* Gerenciamento de estado persistido com avaliação iterativa e realimentação para o planejamento de próximas etapas.
+* Planejamento e roteamento sensível a custo, latência e requisitos de qualidade.
+* O uso de "tokens universais" para comunicação agnóstica a modelos.
+
+### **Reconhecimento e Implicações (EM PORTUGUÊS):**
+
+Ao acessar ou utilizar este software e a arquitetura ADUC aqui implementada, você reconhece:
+
+1. A natureza inovadora e a importância da arquitetura ADUC no campo da orquestração de prompts para IA.
+2. Que a essência desta arquitetura, ou suas implementações derivadas, podem estar sujeitas a direitos de propriedade intelectual, incluindo patentes.
+3. Que o uso comercial, a reprodução da lógica central da ADUC em sistemas independentes, ou a exploração direta da invenção sem o devido licenciamento podem infringir os direitos de patente pendente.
+
+---
+
+### **Patent Pending (IN ENGLISH):**
+
+The method and system for prompt orchestration named **ADUC (Automated Discovery and Orchestration of Complex tasks)**, as described herein and implemented in this software, are currently in the process of being patented.
+
+The rights holder, Carlos Rodrigues dos Santos, is seeking legal protection for the key innovations of the ADUC architecture, including, but not limited to:
+
+* Fragmentation and scaling of requests exceeding AI model context limits.
+* Intelligent distribution of sub-tasks to heterogeneous specialists.
+* Persistent state management with iterative evaluation and feedback for planning subsequent steps.
+* Cost, latency, and quality-aware planning and routing.
+* The use of "universal tokens" for model-agnostic communication.
+
+### **Acknowledgement and Implications (IN ENGLISH):**
+
+By accessing or using this software and the ADUC architecture implemented herein, you acknowledge:
+
+1. The innovative nature and significance of the ADUC architecture in the field of AI prompt orchestration.
+2. That the essence of this architecture, or its derivative implementations, may be subject to intellectual property rights, including patents.
+3. That commercial use, reproduction of ADUC's core logic in independent systems, or direct exploitation of the invention without proper licensing may infringe upon pending patent rights.
+
+---
+
+## Licença AGPLv3
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program. If not, see .
+
+---
+
+**Contato para Consultas:**
+
+Para mais informações sobre a arquitetura ADUC, o status do patenteamento, ou para discutir licenciamento para usos comerciais ou não conformes com a AGPLv3, por favor, entre em contato:
+
+Carlos Rodrigues dos Santos
+carlex22@gmail.com
+Rua Eduardo Carlos Pereira, 4125, B1 Ap32, Curitiba, PR, Brazil, CEP 8102025
\ No newline at end of file
diff --git a/aduc_framework/tools/README.md b/aduc_framework/tools/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..9cf56fe2707241f77fe3aedabdaa07d319218b17
--- /dev/null
+++ b/aduc_framework/tools/README.md
@@ -0,0 +1,211 @@
+---
+title: Euia-AducSdr
+emoji: 🎥
+colorFrom: indigo
+colorTo: purple
+sdk: gradio
+app_file: app.py
+pinned: true
+license: agpl-3.0
+short_description: Uma implementação aberta e funcional da arquitetura ADUC-SDR
+---
+
+
+### 🇧🇷 Português
+
+Uma implementação aberta e funcional da arquitetura ADUC-SDR (Arquitetura de Unificação Compositiva - Escala Dinâmica e Resiliente), projetada para a geração de vídeo coerente de longa duração. Este projeto materializa os princípios de fragmentação, navegação geométrica e um mecanismo de "eco causal 4bits memoria" para garantir a continuidade física e narrativa em sequências de vídeo geradas por múltiplos modelos de IA.
+
+**Licença:** Este projeto é licenciado sob os termos da **GNU Affero General Public License v3.0**. Isto significa que se você usar este software (ou qualquer trabalho derivado) para fornecer um serviço através de uma rede, você é **obrigado a disponibilizar o código-fonte completo** da sua versão para os usuários desse serviço.
+
+- **Copyright (C) 4 de Agosto de 2025, Carlos Rodrigues dos Santos**
+- Uma cópia completa da licença pode ser encontrada no arquivo [LICENSE](LICENSE).
+
+---
+
+### 🇬🇧 English
+
+An open and functional implementation of the ADUC-SDR (Architecture for Compositive Unification - Dynamic and Resilient Scaling) architecture, designed for long-form coherent video generation. This project materializes the principles of fragmentation, geometric navigation, and a "causal echo 4bits memori" mechanism to ensure physical and narrative continuity in video sequences generated by multiple AI models.
+
+**License:** This project is licensed under the terms of the **GNU Affero General Public License v3.0**. This means that if you use this software (or any derivative work) to provide a service over a network, you are **required to make the complete source code** of your version available to the users of that service.
+
+- **Copyright (C) August 4, 2025, Carlos Rodrigues dos Santos**
+- A full copy of the license can be found in the [LICENSE](LICENSE) file.
+
+---
+
+## **Aviso de Propriedade Intelectual e Patenteamento**
+
+### **Processo de Patenteamento em Andamento (EM PORTUGUÊS):**
+
+A arquitetura e o método **ADUC (Automated Discovery and Orchestration of Complex tasks)**, conforme descritos neste projeto e nas reivindicações associadas, estão **atualmente em processo de patenteamento**.
+
+O titular dos direitos, Carlos Rodrigues dos Santos, está buscando proteção legal para as inovações chave da arquitetura ADUC, que incluem, mas não se limitam a:
+
+* Fragmentação e escalonamento de solicitações que excedem limites de contexto de modelos de IA.
+* Distribuição inteligente de sub-tarefas para especialistas heterogêneos.
+* Gerenciamento de estado persistido com avaliação iterativa e realimentação para o planejamento de próximas etapas.
+* Planejamento e roteamento sensível a custo, latência e requisitos de qualidade.
+* O uso de "tokens universais" para comunicação agnóstica a modelos.
+
+Ao utilizar este software e a arquitetura ADUC aqui implementada, você reconhece a natureza inovadora desta arquitetura e que a **reprodução ou exploração da lógica central da ADUC em sistemas independentes pode infringir direitos de patente pendente.**
+
+---
+
+### **Patent Pending (IN ENGLISH):**
+
+The **ADUC (Automated Discovery and Orchestration of Complex tasks)** architecture and method, as described in this project and its associated claims, are **currently in the process of being patented.**
+
+The rights holder, Carlos Rodrigues dos Santos, is seeking legal protection for the key innovations of the ADUC architecture, including, but not limited to:
+
+* Fragmentation and scaling of requests exceeding AI model context limits.
+* Intelligent distribution of sub-tasks to heterogeneous specialists.
+* Persistent state management with iterative evaluation and feedback for planning subsequent steps.
+* Cost, latency, and quality-aware planning and routing.
+* The use of "universal tokens" for model-agnostic communication.
+
+By using this software and the ADUC architecture implemented herein, you acknowledge the innovative nature of this architecture and that **the reproduction or exploitation of ADUC's core logic in independent systems may infringe upon pending patent rights.**
+
+---
+
+### Detalhes Técnicos e Reivindicações da ADUC
+
+#### 🇧🇷 Definição Curta (para Tese e Patente)
+
+**ADUC** é um *framework pré-input* e *intermediário* de **gerenciamento de prompts** que:
+
+1. **fragmenta** solicitações acima do limite de contexto de qualquer modelo,
+2. **escala linearmente** (processo sequencial com memória persistida),
+3. **distribui** sub-tarefas a **especialistas** (modelos/ferramentas heterogêneos), e
+4. **realimenta** a próxima etapa com avaliação do que foi feito/esperado (LLM diretor).
+
+Não é um modelo; é uma **camada orquestradora** plugável antes do input de modelos existentes (texto, imagem, áudio, vídeo), usando *tokens universais* e a tecnologia atual.
+
+#### 🇬🇧 Short Definition (for Thesis and Patent)
+
+**ADUC** is a *pre-input* and *intermediate* **prompt management framework** that:
+
+1. **fragments** requests exceeding any model's context limit,
+2. **scales linearly** (sequential process with persisted memory),
+3. **distributes** sub-tasks to **specialists** (heterogeneous models/tools), and
+4. **feeds back** to the next step with an evaluation of what was done/expected (director LLM).
+
+It is not a model; it is a pluggable **orchestration layer** before the input of existing models (text, image, audio, video), using *universal tokens* and current technology.
+
+---
+
+#### 🇧🇷 Elementos Essenciais (Telegráfico)
+
+* **Agnóstico a modelos:** opera com qualquer LLM/difusor/API.
+* **Pré-input manager:** recebe pedido do usuário, **divide** em blocos ≤ limite de tokens, **prioriza**, **agenda** e **roteia**.
+* **Memória persistida:** resultados/latentes/“eco” viram **estado compartilhado** para o próximo bloco (nada é ignorado).
+* **Especialistas:** *routers* decidem quem faz o quê (ex.: “descrição → LLM-A”, “keyframe → Img-B”, “vídeo → Vid-C”).
+* **Controle de qualidade:** LLM diretor compara *o que fez* × *o que deveria* × *o que falta* e **regenera objetivos** do próximo fragmento.
+* **Custo/latência-aware:** planeja pela **VRAM/tempo/custo**, não tenta “abraçar tudo de uma vez”.
+
+#### 🇬🇧 Essential Elements (Telegraphic)
+
+* **Model-agnostic:** operates with any LLM/diffuser/API.
+* **Pre-input manager:** receives user request, **divides** into blocks ≤ token limit, **prioritizes**, **schedules**, and **routes**.
+* **Persisted memory:** results/latents/“echo” become **shared state** for the next block (nothing is ignored).
+* **Specialists:** *routers* decide who does what (e.g., “description → LLM-A”, “keyframe → Img-B”, “video → Vid-C”).
+* **Quality control:** director LLM compares *what was done* × *what should be done* × *what is missing* and **regenerates objectives** for the next fragment.
+* **Cost/latency-aware:** plans by **VRAM/time/cost**, does not try to “embrace everything at once”.
+
+---
+
+#### 🇧🇷 Reivindicações Independentes (Método e Sistema)
+
+**Reivindicação Independente (Método) — Versão Enxuta:**
+
+1. **Método** de **orquestração de prompts** para execução de tarefas acima do limite de contexto de modelos de IA, compreendendo:
+ (a) **receber** uma solicitação que excede um limite de tokens;
+ (b) **analisar** a solicitação por um **LLM diretor** e **fragmentá-la** em sub-tarefas ≤ limite;
+ (c) **selecionar** especialistas de execução para cada sub-tarefa com base em capacidades declaradas;
+ (d) **gerar** prompts específicos por sub-tarefa em **tokens universais**, incluindo referências ao **estado persistido** de execuções anteriores;
+ (e) **executar sequencialmente** as sub-tarefas e **persistir** suas saídas como memória (incluindo latentes/eco/artefatos);
+ (f) **avaliar** automaticamente a saída versus metas declaradas e **regenerar objetivos** do próximo fragmento;
+ (g) **iterar** (b)–(f) até que os critérios de completude sejam atendidos, produzindo o resultado agregado;
+ em que o framework **escala linearmente** no tempo e armazenamento físico, **independente** da janela de contexto dos modelos subjacentes.
+
+**Reivindicação Independente (Sistema):**
+
+2. **Sistema** de orquestração de prompts, compreendendo: um **planejador LLM diretor**; um **roteador de especialistas**; um **banco de estado persistido** (incl. memória cinética para vídeo); um **gerador de prompts universais**; e um **módulo de avaliação/realimentação**, acoplados por uma **API pré-input** a modelos heterogêneos.
+
+#### 🇬🇧 Independent Claims (Method and System)
+
+**Independent Claim (Method) — Concise Version:**
+
+1. A **method** for **prompt orchestration** for executing tasks exceeding AI model context limits, comprising:
+ (a) **receiving** a request that exceeds a token limit;
+ (b) **analyzing** the request by a **director LLM** and **fragmenting it** into sub-tasks ≤ the limit;
+ (c) **selecting** execution specialists for each sub-task based on declared capabilities;
+ (d) **generating** specific prompts per sub-task in **universal tokens**, including references to the **persisted state** of previous executions;
+ (e) **sequentially executing** the sub-tasks and **persisting** their outputs as memory (including latents/echo/artifacts);
+ (f) **automatically evaluating** the output against declared goals and **regenerating objectives** for the next fragment;
+ (g) **iterating** (b)–(f) until completion criteria are met, producing the aggregated result;
+ wherein the framework **scales linearly** in time and physical storage, **independent** of the context window of the underlying models.
+
+**Independent Claim (System):**
+
+2. A prompt orchestration **system**, comprising: a **director LLM planner**; a **specialist router**; a **persisted state bank** (incl. kinetic memory for video); a **universal prompt generator**; and an **evaluation/feedback module**, coupled via a **pre-input API** to heterogeneous models.
+
+---
+
+#### 🇧🇷 Dependentes Úteis
+
+* (3) Onde o roteamento considera **custo/latência/VRAM** e metas de qualidade.
+* (4) Onde o banco de estado inclui **eco cinético** para vídeo (últimos *n* frames/latentes/fluxo).
+* (5) Onde a avaliação usa métricas específicas por domínio (Lflow, consistência semântica, etc.).
+* (6) Onde *tokens universais* padronizam instruções entre especialistas.
+* (7) Onde a orquestração decide **cut vs continuous** e **corte regenerativo** (Déjà-Vu) ao editar vídeo.
+* (8) Onde o sistema **nunca descarta** conteúdo excedente: **reagenda** em novos fragmentos.
+
+#### 🇬🇧 Useful Dependents
+
+* (3) Wherein routing considers **cost/latency/VRAM** and quality goals.
+* (4) Wherein the state bank includes **kinetic echo** for video (last *n* frames/latents/flow).
+* (5) Wherein evaluation uses domain-specific metrics (Lflow, semantic consistency, etc.).
+* (6) Wherein *universal tokens* standardize instructions between specialists.
+* (7) Wherein orchestration decides **cut vs continuous** and **regenerative cut** (Déjà-Vu) when editing video.
+* (8) Wherein the system **never discards** excess content: it **reschedules** it in new fragments.
+
+---
+
+#### 🇧🇷 Como isso conversa com SDR (Vídeo)
+
+* **Eco Cinético**: é um **tipo de estado persistido** consumido pelo próximo passo.
+* **Déjà-Vu (Corte Regenerativo)**: é **uma política de orquestração** aplicada quando há edição; ADUC decide, monta os prompts certos e chama o especialista de vídeo.
+* **Cut vs Continuous**: decisão do **diretor** com base em estado + metas; ADUC roteia e garante a sobreposição/remoção final.
+
+#### 🇬🇧 How this Converses with SDR (Video)
+
+* **Kinetic Echo**: is a **type of persisted state** consumed by the next step.
+* **Déjà-Vu (Regenerative Cut)**: is an **orchestration policy** applied during editing; ADUC decides, crafts the right prompts, and calls the video specialist.
+* **Cut vs Continuous**: decision made by the **director** based on state + goals; ADUC routes and ensures the final overlap/removal.
+
+---
+
+#### 🇧🇷 Mensagem Clara ao Usuário (Experiência)
+
+> “Seu pedido excede o limite X do modelo Y. Em vez de truncar silenciosamente, o **ADUC** dividirá e **entregará 100%** do conteúdo por etapas coordenadas.”
+
+Isso é diferencial prático e jurídico: **não-obviedade** por transformar limite de contexto em **pipeline controlado**, com **persistência de estado** e **avaliação iterativa**.
+
+#### 🇬🇧 Clear User Message (Experience)
+
+> "Your request exceeds model Y's limit X. Instead of silently truncating, **ADUC** will divide and **deliver 100%** of the content through coordinated steps."
+
+This is a practical and legal differentiator: **non-obviousness** by transforming context limits into a **controlled pipeline**, with **state persistence** and **iterative evaluation**.
+
+---
+
+### Contact / Contato / Contacto
+
+- **Author / Autor:** Carlos Rodrigues dos Santos
+- **Email:** carlex22@gmail.com
+- **GitHub:** [https://github.com/carlex22/Aduc-sdr](https://github.com/carlex22/Aduc-sdr)
+- **Hugging Face Spaces:**
+ - [Ltx-SuperTime-60Secondos](https://huggingface.co/spaces/Carlexx/Ltx-SuperTime-60Secondos/)
+ - [Novinho](https://huggingface.co/spaces/Carlexxx/Novinho/)
+
+---
\ No newline at end of file
diff --git a/aduc_framework/tools/__init__.py b/aduc_framework/tools/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..9ba18ddfc00bcb0180fbd08c0699852dbb222e19
--- /dev/null
+++ b/aduc_framework/tools/__init__.py
@@ -0,0 +1,15 @@
+# aduc_framework/tools/__init__.py
+
+# Expõe os singletons e classes principais do sub-pacote de ferramentas.
+
+from .hardware_manager import hardware_manager
+from .video_encode_tool import video_encode_tool_singleton
+from . import optimization
+from . import tensor_utils
+
+__all__ = [
+ "hardware_manager",
+ "video_encode_tool_singleton",
+ "optimization",
+ "tensor_utils",
+]
\ No newline at end of file
diff --git a/aduc_framework/tools/hardware_manager.py b/aduc_framework/tools/hardware_manager.py
new file mode 100644
index 0000000000000000000000000000000000000000..d776066939d5c99906ccc5dc3113ff5806caaab5
--- /dev/null
+++ b/aduc_framework/tools/hardware_manager.py
@@ -0,0 +1,62 @@
+# tools/hardware_manager.py
+# AducSdr: Uma implementação aberta e funcional da arquitetura ADUC-SDR
+# Copyright (C) 4 de Agosto de 2025 Carlos Rodrigues dos Santos
+#
+# Contato:
+# Carlos Rodrigues dos Santos
+# carlex22@gmail.com
+# Rua Eduardo Carlos Pereira, 4125, B1 Ap32, Curitiba, PR, Brazil, CEP 8102025
+#
+# Repositórios e Projetos Relacionados:
+# GitHub: https://github.com/carlex22/Aduc-sdr
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License...
+# PENDING PATENT NOTICE: Please see NOTICE.md.
+#
+# Version 1.0.1
+
+import torch
+import logging
+
+logger = logging.getLogger(__name__)
+
+class HardwareManager:
+ def __init__(self):
+ self.gpus = []
+ self.allocated_gpus = set()
+ if torch.cuda.is_available():
+ self.gpus = [f'cuda:{i}' for i in range(torch.cuda.device_count())]
+ logger.info(f"Hardware Manager: Encontradas {len(self.gpus)} GPUs disponíveis: {self.gpus}")
+
+ def allocate_gpus(self, specialist_name: str, num_required: int) -> list[str]:
+ if not self.gpus or num_required == 0:
+ logger.warning(f"Nenhuma GPU disponível ou solicitada para '{specialist_name}'. Alocando para CPU.")
+ return ['cpu']
+
+ available_gpus = [gpu for gpu in self.gpus if gpu not in self.allocated_gpus]
+
+ if len(available_gpus) < num_required:
+ error_msg = f"Recursos de GPU insuficientes para '{specialist_name}'. Solicitado: {num_required}, Disponível: {len(available_gpus)}."
+ logger.error(error_msg)
+ raise RuntimeError(error_msg)
+
+ allocated = available_gpus[:num_required]
+ self.allocated_gpus.update(allocated)
+ logger.info(f"Hardware Manager: Alocando GPUs {allocated} para o especialista '{specialist_name}'.")
+ return allocated
+
+hardware_manager = HardwareManager()
\ No newline at end of file
diff --git a/aduc_framework/tools/optimization.py b/aduc_framework/tools/optimization.py
new file mode 100644
index 0000000000000000000000000000000000000000..26eec95c7ceabcef88f1f16638645049904a81d5
--- /dev/null
+++ b/aduc_framework/tools/optimization.py
@@ -0,0 +1,71 @@
+# optimization.py
+# AducSdr: Uma implementação aberta e funcional da arquitetura ADUC-SDR
+# Copyright (C) 4 de Agosto de 2025 Carlos Rodrigues dos Santos
+#
+# Contato:
+# Carlos Rodrigues dos Santos
+# carlex22@gmail.com
+# Rua Eduardo Carlos Pereira, 4125, B1 Ap32, Curitiba, PR, Brazil, CEP 8102025
+#
+# Repositórios e Projetos Relacionados:
+# GitHub: https://github.com/carlex22/Aduc-sdr
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License...
+# PENDING PATENT NOTICE: Please see NOTICE.md.
+
+import torch
+import logging
+from torchao.quantization import quantize_, float8_dynamic_activation_float8_weight
+
+# Usamos type hints com strings para evitar importações circulares
+from typing import TYPE_CHECKING
+if TYPE_CHECKING:
+ from ltx_manager_helpers import LtxWorker
+
+logger = logging.getLogger(__name__)
+
+def can_optimize_fp8():
+ """Verifica se a GPU atual suporta otimizações FP8."""
+ if not torch.cuda.is_available():
+ return False
+
+ major, _ = torch.cuda.get_device_capability()
+
+ if major >= 9: # Arquitetura Hopper
+ logger.info(f"GPU com arquitetura Hopper ou superior (CC {major}.x) detectada. Ativando quantização FP8.")
+ return True
+
+ if major == 8:
+ device_name = torch.cuda.get_device_name(0).lower()
+ if "h100" in device_name or "l40" in device_name or "rtx 40" in device_name: # Arquitetura Ada Lovelace
+ logger.info(f"GPU com arquitetura Ada Lovelace (CC 8.9, Nome: {device_name}) detectada. Ativando quantização FP8.")
+ return True
+
+ logger.warning(f"A GPU atual (CC {major}.x) não tem suporte otimizado para FP8. Pulando quantização.")
+ return False
+
+@torch.no_grad()
+def optimize_ltx_worker(worker: "LtxWorker"):
+ """Aplica quantização FP8 ao transformador do pipeline LTX."""
+ pipeline = worker.pipeline
+ device = worker.device
+
+ logger.info(f"Iniciando quantização FP8 do transformador LTX no dispositivo {device}...")
+ quantize_(pipeline.transformer, float8_dynamic_activation_float8_weight())
+
+ torch.cuda.empty_cache()
+ logger.info(f"Quantização FP8 do LTX Worker no dispositivo {device} concluída com sucesso!")
\ No newline at end of file
diff --git a/aduc_framework/tools/tensor_utils.py b/aduc_framework/tools/tensor_utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..0b6c6db79e8ba9d32b1e9ef773d5506b573a4bdc
--- /dev/null
+++ b/aduc_framework/tools/tensor_utils.py
@@ -0,0 +1,116 @@
+# tools/tensor_utils.py
+# AducSdr: Uma implementação aberta e funcional da arquitetura ADUC-SDR
+# Copyright (C) 4 de Agosto de 2025 Carlos Rodrigues dos Santos
+#
+# Contato:
+# Carlos Rodrigues dos Santos
+# carlex22@gmail.com
+# Rua Eduardo Carlos Pereira, 4125, B1 Ap32, Curitiba, PR, Brazil, CEP 8102025
+#
+# Repositórios e Projetos Relacionados:
+# GitHub: https://github.com/carlex22/Aduc-sdr
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License...
+# PENDING PATENT NOTICE: Please see NOTICE.md.
+#
+# Version: 1.0.1
+#
+# This module provides utility functions for tensor manipulation, specifically for
+# image and video processing tasks. The functions here, such as wavelet reconstruction,
+# are internalized within the ADUC-SDR framework to ensure stability and reduce
+# reliance on specific external library structures.
+#
+# The wavelet_reconstruction code is adapted from the SeedVR project.
+
+import torch
+from torch import Tensor
+from torch.nn import functional as F
+from typing import Tuple
+
+def wavelet_blur(image: Tensor, radius: int) -> Tensor:
+ """
+ Apply wavelet blur to the input tensor.
+ """
+ if image.ndim != 4: # Expects (B, C, H, W)
+ raise ValueError(f"wavelet_blur expects a 4D tensor, but got shape {image.shape}")
+
+ b, c, h, w = image.shape
+
+ # convolution kernel
+ kernel_vals = [
+ [0.0625, 0.125, 0.0625],
+ [0.125, 0.25, 0.125],
+ [0.0625, 0.125, 0.0625],
+ ]
+ kernel = torch.tensor(kernel_vals, dtype=image.dtype, device=image.device)
+ kernel = kernel[None, None] # (1, 1, 3, 3)
+
+ # repeat the kernel across all input channels for grouped convolution
+ kernel = kernel.repeat(c, 1, 1, 1) # (C, 1, 3, 3)
+
+ image = F.pad(image, (radius, radius, radius, radius), mode='replicate')
+
+ # apply convolution with groups=c to process each channel independently
+ output = F.conv2d(image, kernel, groups=c, dilation=radius)
+ return output
+
+def wavelet_decomposition(image: Tensor, levels=5) -> Tuple[Tensor, Tensor]:
+ """
+ Apply wavelet decomposition to the input tensor.
+ This function returns both the high frequency and low frequency components.
+ """
+ # Ensure tensor is 4D (B, C, H, W)
+ is_video_frame = image.ndim == 5 # (B, C, F, H, W)
+ if is_video_frame:
+ b, c, f, h, w = image.shape
+ image = image.permute(0, 2, 1, 3, 4).reshape(b * f, c, h, w)
+
+ high_freq = torch.zeros_like(image)
+ low_freq = image
+ for i in range(levels):
+ radius = 2 ** i
+ blurred = wavelet_blur(low_freq, radius)
+ high_freq += (low_freq - blurred)
+ low_freq = blurred
+
+ if is_video_frame:
+ high_freq = high_freq.view(b, f, c, h, w).permute(0, 2, 1, 3, 4)
+ low_freq = low_freq.view(b, f, c, h, w).permute(0, 2, 1, 3, 4)
+
+ return high_freq, low_freq
+
+def wavelet_reconstruction(content_feat: Tensor, style_feat: Tensor) -> Tensor:
+ """
+ Applies wavelet decomposition to transfer the color/style (low-frequency components)
+ from a style feature to the details (high-frequency components) of a content feature.
+ This works for both images (4D) and videos (5D).
+
+ Args:
+ content_feat (Tensor): The tensor containing the structural details.
+ style_feat (Tensor): The tensor containing the desired color and lighting style.
+
+ Returns:
+ Tensor: The reconstructed tensor with content details and style colors.
+ """
+ # calculate the wavelet decomposition of the content feature
+ content_high_freq, _ = wavelet_decomposition(content_feat)
+
+ # calculate the wavelet decomposition of the style feature
+ _, style_low_freq = wavelet_decomposition(style_feat)
+
+ # reconstruct the content feature with the style's low frequency (color/lighting)
+ return content_high_freq + style_low_freq
\ No newline at end of file
diff --git a/aduc_framework/tools/video_encode_tool.py b/aduc_framework/tools/video_encode_tool.py
new file mode 100644
index 0000000000000000000000000000000000000000..94fba14a1b142c398635f3d326a2559b601cd556
--- /dev/null
+++ b/aduc_framework/tools/video_encode_tool.py
@@ -0,0 +1,155 @@
+# aduc_framework/tools/video_encode_tool.py
+#
+# Versão 1.4.0 (Conjunto de Ferramentas de Vídeo Finalizado)
+# Copyright (C) August 4, 2025 Carlos Rodrigues dos Santos
+#
+# Este módulo atua como o especialista central para todas as operações de
+# manipulação e codificação de vídeo. Ele abstrai as interações com
+# FFmpeg e imageio, fornecendo uma API limpa e robusta para o resto do framework.
+# - save_video_from_tensor: Converte um tensor de pixel em um arquivo .mp4.
+# - extract_..._frame: Extrai frames específicos de clipes de vídeo.
+# - concatenate_videos: Monta o filme final a partir dos clipes de cena.
+
+import os
+import subprocess
+import logging
+import random
+import time
+import shutil
+from typing import List, Optional, Tuple
+
+import imageio
+import numpy as np
+import torch
+
+logger = logging.getLogger(__name__)
+
+class VideoToolError(Exception):
+ """Exceção personalizada para erros originados do VideoEncodeTool."""
+ pass
+
+class VideoEncodeTool:
+ """
+ Um especialista para lidar com tarefas de codificação e manipulação de vídeo.
+ """
+
+ def save_video_from_tensor(self, video_tensor: torch.Tensor, path: str, fps: int = 24):
+ """
+ Salva um tensor de pixel como um arquivo de vídeo .mp4 usando parâmetros otimizados.
+ Espera um tensor no formato (B, C, F, H, W) onde B=1.
+ """
+ # Verificações de robustez para garantir que o tensor é válido
+ if video_tensor is None or video_tensor.ndim != 5 or video_tensor.shape[0] != 1 or video_tensor.shape[2] == 0:
+ logger.warning(f"Tensor de vídeo inválido ou vazio recebido. Shape: {video_tensor.shape if video_tensor is not None else 'None'}. Pulando salvamento de vídeo para '{path}'.")
+ return
+
+ logger.info(f"Salvando tensor de vídeo com shape {video_tensor.shape} para '{os.path.basename(path)}'...")
+
+ try:
+ # Squeeze: (1, C, F, H, W) -> (C, F, H, W)
+ # Permute: (C, F, H, W) -> (F, H, W, C) - formato esperado por imageio
+ video_tensor_permuted = video_tensor.squeeze(0).permute(1, 2, 3, 0)
+
+ # Desnormaliza de [-1, 1] para [0, 1]
+ video_tensor_normalized = (video_tensor_permuted.clamp(-1, 1) + 1) / 2.0
+
+ # Converte para [0, 255], move para CPU e converte para numpy uint8
+ video_np = (video_tensor_normalized.detach().cpu().float().numpy() * 255).astype(np.uint8)
+
+ # Salva o vídeo com parâmetros de alta compatibilidade
+ with imageio.get_writer(
+ path,
+ fps=fps,
+ codec='libx264',
+ quality=8, # Qualidade boa (0-10, onde 10 é a melhor)
+ output_params=['-pix_fmt', 'yuv420p'] # Formato de pixel para compatibilidade máxima
+ ) as writer:
+ for frame in video_np:
+ writer.append_data(frame)
+
+ logger.info(f"Vídeo salvo com sucesso em: {path}")
+ except Exception as e:
+ logger.error(f"Falha ao salvar vídeo com imageio para '{path}': {e}", exc_info=True)
+ raise VideoToolError(f"Não foi possível escrever o arquivo de vídeo: {e}")
+
+ def extract_first_frame(self, video_path: str, output_image_path: str) -> str:
+ """
+ Extrai o primeiro frame de um arquivo de vídeo e o salva como uma imagem.
+ """
+ logger.info(f"Extraindo primeiro frame de '{os.path.basename(video_path)}'...")
+ cmd = ['ffmpeg', '-y', '-v', 'error', '-i', video_path, '-vframes', '1', '-q:v', '2', output_image_path]
+ try:
+ subprocess.run(cmd, check=True, capture_output=True, text=True)
+ return output_image_path
+ except subprocess.CalledProcessError as e:
+ logger.error(f"FFmpeg (extract_first_frame) falhou: {e.stderr}")
+ raise VideoToolError(f"Falha ao extrair o primeiro frame de {video_path}")
+
+ def extract_last_frame(self, video_path: str, output_image_path: str) -> str:
+ """
+ Extrai o último frame de um arquivo de vídeo e o salva como uma imagem.
+ """
+ logger.info(f"Extraindo último frame de '{os.path.basename(video_path)}'...")
+ cmd = ['ffmpeg', '-y', '-v', 'error', '-sseof', '-0.1', '-i', video_path, '-vframes', '1', '-q:v', '2', output_image_path]
+ try:
+ subprocess.run(cmd, check=True, capture_output=True, text=True)
+ return output_image_path
+ except subprocess.CalledProcessError as e:
+ logger.error(f"FFmpeg (extract_last_frame) falhou: {e.stderr}")
+ raise VideoToolError(f"Falha ao extrair o último frame de {video_path}")
+
+ def create_transition_bridge(self, start_image_path: str, end_image_path: str,
+ duration: float, fps: int, target_resolution: Tuple[int, int],
+ workspace_dir: str, effect: Optional[str] = None) -> str:
+ """
+ Cria um clipe de vídeo curto que transiciona entre duas imagens estáticas.
+ """
+ output_path = os.path.join(workspace_dir, f"bridge_{int(time.time())}_{random.randint(100, 999)}.mp4")
+ width, height = target_resolution
+ fade_effects = ["fade", "wipeleft", "wiperight", "wipeup", "wipedown", "dissolve", "fadeblack", "fadewhite", "radial", "rectcrop", "circleopen", "circleclose", "horzopen", "horzclose"]
+ selected_effect = effect if effect and effect.strip() else random.choice(fade_effects)
+ transition_duration = max(0.1, duration)
+ cmd = (f"ffmpeg -y -v error -loop 1 -t {transition_duration} -i \"{start_image_path}\" -loop 1 -t {transition_duration} -i \"{end_image_path}\" "
+ f"-filter_complex \"[0:v]scale={width}:{height},setsar=1[v0];[1:v]scale={width}:{height},setsar=1[v1];"
+ f"[v0][v1]xfade=transition={selected_effect}:duration={transition_duration}:offset=0[out]\" "
+ f"-map \"[out]\" -c:v libx264 -r {fps} -pix_fmt yuv420p \"{output_path}\"")
+ logger.info(f"Criando ponte de transição com efeito '{selected_effect}'...")
+ try:
+ subprocess.run(cmd, shell=True, check=True, text=True)
+ except subprocess.CalledProcessError as e:
+ raise VideoToolError(f"Falha ao criar vídeo de transição: {e.stderr}")
+ return output_path
+
+ def concatenate_videos(self, video_paths: List[str], output_path: str, workspace_dir: str) -> str:
+ """
+ Concatena múltiplos clipes de vídeo em um único arquivo sem re-codificar.
+ """
+ if not video_paths:
+ raise VideoToolError("Nenhum fragmento de vídeo fornecido para concatenação.")
+ # Se houver apenas um clipe, apenas o copie para o destino final.
+ if len(video_paths) == 1:
+ shutil.copy(video_paths[0], output_path)
+ logger.info(f"Apenas um clipe fornecido. Copiado para '{output_path}'.")
+ return output_path
+
+ list_file_path = os.path.join(workspace_dir, f"concat_list_{int(time.time())}.txt")
+ try:
+ with open(list_file_path, 'w', encoding='utf-8') as f:
+ for path in video_paths:
+ # Garante que o caminho seja absoluto para o ffmpeg encontrar
+ f.write(f"file '{os.path.abspath(path)}'\n")
+
+ cmd_list = ['ffmpeg', '-y', '-f', 'concat', '-safe', '0', '-i', list_file_path, '-c', 'copy', output_path]
+ logger.info(f"Concatenando {len(video_paths)} clipes para '{os.path.basename(output_path)}'...")
+ subprocess.run(cmd_list, check=True, capture_output=True, text=True)
+ logger.info("Concatenação FFmpeg bem-sucedida.")
+ return output_path
+ except subprocess.CalledProcessError as e:
+ logger.error(f"Falha ao montar o vídeo final com FFmpeg: {e.stderr}")
+ raise VideoToolError(f"Falha ao montar o vídeo final com FFmpeg.")
+ finally:
+ if os.path.exists(list_file_path):
+ os.remove(list_file_path)
+
+# --- Instância Singleton ---
+video_encode_tool_singleton = VideoEncodeTool()
\ No newline at end of file
diff --git a/aduc_framework/types.py b/aduc_framework/types.py
new file mode 100644
index 0000000000000000000000000000000000000000..8e054a76df609de8a9276ee6b9439deadc951bf1
--- /dev/null
+++ b/aduc_framework/types.py
@@ -0,0 +1,239 @@
+# aduc_framework/types.py
+#
+# Versão 16.1.0 (Alinhamento com o Diretor de Produção Planner5D)
+# - Refina as estruturas de "Ordem de Serviço" (Jobs) para se alinharem
+# perfeitamente com o fluxo de trabalho do Planner5D.
+# - A `VideoGenerationJob` foi simplificada para ser mais declarativa,
+# transferindo a responsabilidade dos cálculos de poda para o especialista
+# Deformes4D, tornando-o mais autônomo.
+# - Mantém a arquitetura de Tags Canônicas como a espinha dorsal do sistema.
+
+from pydantic import BaseModel, Field, root_validator
+from typing import List, Dict, Any, Optional, Literal
+from datetime import datetime, timezone
+import os
+from dataclasses import dataclass
+import torch
+
+# =========================================================================
+# --- Bloco A: Estruturas de Dados de Utilidade (Comunicação Interna) ---
+# =========================================================================
+
+@dataclass
+class LatentConditioningItem:
+ """Item de dados para condicionamento da pipeline LTX."""
+ latent_tensor: torch.Tensor
+ media_frame_number: int
+ conditioning_strength: float
+
+class KeyframeGenerationJob(BaseModel):
+ """Ordem de Serviço do Planner5D para o Deformes3D (Pintor de Keyframes)."""
+ storyboard: List[str]
+ global_prompt: str
+ ref_image_paths: List[str]
+ ref_id_to_path_map: Dict[int, str]
+ available_ref_ids: List[int]
+ keyframe_prefix: str
+ params: Dict[str, Any]
+
+class VideoGenerationJob(BaseModel):
+ """Ordem de Serviço do Planner5D para o Deformes4D (Executor de Cena)."""
+ scene_id: int
+ global_prompt: str
+ storyboard: List[str]
+ keyframe_paths: List[str]
+ # Parâmetros de alto nível (o especialista faz os cálculos)
+ resolution: int
+ duration_per_fragment: float
+ # Parâmetros de produção
+ trim_percent: int
+ handler_strength: float
+ destination_convergence_strength: float
+ guidance_scale: float
+ stg_scale: float
+ inference_steps: int
+
+# =========================================================================
+# --- Bloco B: Tipos Literais (Comuns) ---
+# =========================================================================
+
+StatusProducao = Literal["planejado", "necessita_revisao", "keyframes_gerados", "video_gerado", "finalizado"]
+TipoTarefaPosProducao = Literal["color_grading", "sfx_addition", "music_scoring", "super_resolution", "pacing_adjustment", "object_removal"]
+StatusTarefa = Literal["pendente", "em_progresso", "concluida", "falhou"]
+
+# =========================================================================
+# --- Bloco C: Parâmetros de Geração (Estrutura Desaninhada) ---
+# =========================================================================
+
+class PreProductionParams(BaseModel):
+ prompt: str
+ num_scenes: int
+ ref_paths: List[str]
+ duration_per_fragment: float
+ resolution: int = 512 # Adicionando resolução padrão
+
+class ProductionParams(BaseModel):
+ trim_percent: int
+ handler_strength: float
+ destination_convergence_strength: float
+ guidance_scale: float
+ stg_scale: float
+ inference_steps: int
+
+class GenerationParameters(BaseModel):
+ pre_producao: Optional[PreProductionParams] = None
+ producao: Optional[ProductionParams] = None
+
+# =========================================================================
+# --- Bloco D: Estruturas de Referência e LEGACY ---
+# =========================================================================
+
+class MediaRef(BaseModel):
+ """Representa uma mídia de referência original com sua tag universal."""
+ id: int
+ tag: str # A tag canônica e universal, ex: ""
+ caminho: str
+
+class KeyframeData(BaseModel):
+ """Armazena os dados de um único keyframe gerado."""
+ id: int
+ prompt_keyframe: str
+ caminho_pixel: str
+ caminho_latent: str
+
+class Ato_V1(BaseModel):
+ """[LEGACY]"""
+ id: int
+ resumo_ato: str
+
+class Scene_V1(BaseModel):
+ """[LEGACY]"""
+ id: int
+ atos: List[Ato_V1] = Field(default_factory=list)
+ keyframes: List[KeyframeData] = Field(default_factory=list)
+
+# =========================================================================
+# --- Bloco E: Novas Estruturas DEFINITIVAS (Arquitetura de Tags V2) ---
+# =========================================================================
+
+class AtivoCatalogado(BaseModel):
+ """Representa um ativo visual com um ID canônico em formato de tag."""
+ id: str # ID Universal, ex: ""
+ prompt: str
+ caminho_original: Optional[str] # Link simbólico para a tag de referência (ex: "") ou None
+ observacao: str
+
+class CatalogoDeAtivos(BaseModel):
+ cenarios: List[AtivoCatalogado] = Field(default_factory=list)
+ objetos: List[AtivoCatalogado] = Field(default_factory=list)
+ personagens: List[AtivoCatalogado] = Field(default_factory=list)
+
+class AtivoNoAto(BaseModel):
+ id: str # Referencia o ID universal de um AtivoCatalogado
+ tipo: str # 'cenario', 'personagem', 'objeto'
+
+class VideoData(BaseModel):
+ id: int
+ caminho_pixel: str
+
+class SceneDependency(BaseModel):
+ depends_on_scene_id: int
+ dependency_type: str = Field(default="sequential")
+
+class SceneSpecificConfig(BaseModel):
+ inference_steps_override: Optional[int] = None
+ guidance_scale_override: Optional[float] = None
+ quality_target: str = Field(default="standard", pattern="^(draft|standard|high)$")
+
+class Ato(BaseModel):
+ id_ato: int
+ NARRATIVA_VISUAL: str
+ ENQUADRAMENTO: str
+ MOVIMENTACAO_DE_CAMERA: str
+ MOVIMENTACAO_DOS_ATIVOS: str
+ ATIVOS_EM_CENA: List[AtivoNoAto] = Field(default_factory=list)
+ ACAO_DOS_ATIVOS: str
+ DURACAO_ATO: float
+ DIALOGO: Optional[str] = None
+ SFX: Optional[str] = None
+ status: StatusProducao = Field(default="planejado")
+ last_modified_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
+
+class Scene(BaseModel):
+ id_cena: int
+ tipo_cena: str
+ titulo_cena: str
+ resumo_cena: str
+ cenario_escolhido: AtivoCatalogado
+ duracao_estimada_s: float
+ direcao_camera: str
+ sentimento_transmitido: str
+ especificacoes_tecnicas: Dict[str, Any]
+ atos: List[Ato] = Field(default_factory=list)
+ dependencies: List[SceneDependency] = Field(default_factory=list)
+ config_overrides: Optional[SceneSpecificConfig] = None
+ status: StatusProducao = Field(default="planejado")
+ last_modified_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
+ keyframes: List[KeyframeData] = Field(default_factory=list)
+ video_gerado: Optional[VideoData] = None
+
+class PosProductionTask(BaseModel):
+ id: int
+ cena_alvo_id: int
+ ato_alvo_id: Optional[int] = None
+ tipo_tarefa: TipoTarefaPosProducao
+ descricao: str
+ status: StatusTarefa = Field(default="pendente")
+
+# =========================================================================
+# --- Bloco F: O DNA DIGITAL COMPLETO (A Classe Raiz) ---
+# =========================================================================
+
+class GenerationState(BaseModel):
+ """O 'DNA Digital' completo do projeto, agora baseado no Sistema de Tags Canônicas."""
+
+ parametros_geracao: GenerationParameters = Field(default_factory=GenerationParameters)
+ workspace_dir: str
+ chat_history: List[Dict[str, Any]] = Field(default_factory=list)
+ midias_referencia: List[MediaRef] = Field(default_factory=list)
+
+ # --- ESTRUTURA DE PRODUÇÃO V2 (ATIVA) ---
+ texto_global_historia: Optional[str] = None
+ ativos_catalogados: Optional[CatalogoDeAtivos] = None
+ storyboard_producao: List[Scene] = Field(default_factory=list, description="[V2] A estrutura principal para a produção.")
+
+ # --- DADOS GERADOS ---
+ tarefas_de_pos_producao: List[PosProductionTask] = Field(default_factory=list)
+ caminho_filme_final_bruto: Optional[str] = None
+ caminho_filme_final_masterizado: Optional[str] = None
+
+ # --- ESTRUTURA LEGACY (Para compatibilidade/transição) ---
+ scenes: List[Scene_V1] = Field(default_factory=list, description="[LEGACY]")
+
+ # --- METADADOS DE GERENCIAMENTO ---
+ last_checkpoint_at: Optional[datetime] = None
+ checkpoint_interval_minutes: int = Field(default=5)
+
+ def should_checkpoint(self) -> bool:
+ if not self.last_checkpoint_at: return True
+ delta = datetime.now(timezone.utc) - self.last_checkpoint_at
+ return delta.total_seconds() >= (self.checkpoint_interval_minutes * 60)
+
+ def create_checkpoint(self, checkpoint_dir: str) -> str:
+ os.makedirs(checkpoint_dir, exist_ok=True)
+ now_utc = datetime.now(timezone.utc)
+ timestamp = now_utc.strftime("%Y%m%d_%H%M%S_UTC")
+ checkpoint_path = os.path.join(checkpoint_dir, f"dna_checkpoint_{timestamp}.json")
+ with open(checkpoint_path, 'w', encoding='utf-8') as f:
+ f.write(self.model_dump_json(indent=2))
+ self.last_checkpoint_at = now_utc
+ return checkpoint_path
+
+ class Config:
+ populate_by_name = True
+ arbitrary_types_allowed = True
+ validate_assignment = True
+
+ @root_validator(pre=False, skip_on_failure=True)
+ def validate_consistency(cls, values):
+ return values
\ No newline at end of file
diff --git a/app.py b/app.py
new file mode 100644
index 0000000000000000000000000000000000000000..6616d6fdf4782edc3e8f5b591ac8eec97b319dc3
--- /dev/null
+++ b/app.py
@@ -0,0 +1,227 @@
+# app.py
+#
+# Versão 18.1.0 (Interface Alinhada com a Arquitetura V2)
+#
+# - A chamada de evento da UI agora aciona o novo pipeline do Composer2D.
+# - A função de processamento de stream (`process_chat_stream`) foi corrigida
+# para ser compatível com o objeto `GenerationState`, resolvendo o AttributeError.
+# - A extração de dados para a galeria e o vídeo foi atualizada para ler a
+# nova estrutura do DNA (`storyboard_producao`).
+
+import gradio as gr
+import yaml
+import logging
+import os
+import sys
+import time
+from PIL import Image
+
+# --- 1. CONFIGURAÇÃO DE LOGGING E TEMAS ---
+logging.basicConfig(level=logging.INFO, format='%(message)s')
+logger = logging.getLogger(__name__)
+cinematic_theme = gr.themes.Base(primary_hue=gr.themes.colors.purple).set(body_background_fill="#111827", body_text_color="#D1D5DB", button_primary_background_fill="linear-gradient(90deg, #6D28D9, #4F46E5)", block_background_fill="#1F2937", block_border_width="1px", block_border_color="#374151")
+
+# --- 2. INICIALIZAÇÃO CRÍTICA DO FRAMEWORK ---
+try:
+ import aduc_framework
+ # Importa os tipos necessários para a UI
+ from aduc_framework.types import PreProductionParams, ProductionParams
+
+ with open("config.yaml", 'r') as f:
+ config = yaml.safe_load(f)
+ WORKSPACE_DIR = config['application']['workspace_dir']
+
+ # Cria a instância global do ADUC
+ aduc = aduc_framework.create_aduc_instance(workspace_root=WORKSPACE_DIR)
+
+ logger.info("Framework ADUC e interface Gradio inicializados com sucesso.")
+
+except Exception as e:
+ logger.critical(f"ERRO CRÍTICO NA INICIALIZAÇÃO DO ADUC FRAMEWORK: {e}", exc_info=True)
+ with gr.Blocks(theme=cinematic_theme) as demo_error:
+ gr.Markdown("# ERRO CRÍTICO NA INICIALIZAÇÃO")
+ gr.Markdown("Não foi possível iniciar o Aduc Framework. A aplicação não pode continuar. Verifique os logs.")
+ gr.Textbox(value=str(e), label="Detalhes do Erro", lines=10)
+ demo_error.launch()
+ sys.exit(1)
+
+# --- 3. FUNÇÕES WRAPPER E LÓGICA DA UI ---
+
+def chat_beautifier(role):
+ # (Função auxiliar para deixar os nomes dos especialistas bonitos no chat)
+ if "Composer2D" in role: return "Arquiteto Narrativo"
+ if "Neura_Link" in role: return "Interface Neural"
+ if "Planner5D" in role: return "Diretor de Set"
+ return "Sistema"
+
+def process_chat_stream(generator, initial_chat_history=[]):
+ """
+ Processa um gerador que produz objetos GenerationState e formata
+ o histórico de chat e outros dados para a UI.
+ """
+ chatbot_display_history = initial_chat_history.copy()
+ fully_displayed_message_count = len(initial_chat_history)
+
+ for dna_state in generator: # O gerador agora produz objetos 'GenerationState'
+ # --- CORREÇÃO DE `AttributeError` ---
+ # Acessamos os atributos do objeto Pydantic diretamente
+ backend_chat_history = dna_state.chat_history
+
+ gallery_images = []
+ if dna_state.storyboard_producao: # Lendo da nova estrutura V2
+ for scene in dna_state.storyboard_producao:
+ gallery_images.extend([kf.caminho_pixel for kf in scene.keyframes])
+ elif dna_state.scenes: # Fallback para a estrutura legada
+ for scene in dna_state.scenes:
+ gallery_images.extend([kf.caminho_pixel for kf in scene.keyframes])
+
+ final_video_path = dna_state.caminho_filme_final_bruto or dna_state.caminho_filme_final_masterizado
+ dna_json = dna_state.model_dump() # Converte o estado atual para JSON para exibição
+ # ------------------------------------
+
+ # Lógica para "digitar" a mensagem
+ while len(backend_chat_history) > fully_displayed_message_count:
+ new_message_obj = backend_chat_history[fully_displayed_message_count]
+ role = chat_beautifier(new_message_obj.get('role', 'Sistema'))
+ content_to_type = new_message_obj.get('content', '')
+ is_ai_message = "Sistema" not in role
+ chatbot_display_history.append({"role": "assistant" if is_ai_message else "user", "content": ""})
+ full_typed_message = ""
+ for char in f"**{role}:** {content_to_type}":
+ full_typed_message += char
+ chatbot_display_history[-1]["content"] = full_typed_message + "▌"
+ yield chatbot_display_history, gr.update(value=gallery_images), gr.update(value=dna_json), gr.update(value=final_video_path)
+ time.sleep(0.005)
+ chatbot_display_history[-1]["content"] = full_typed_message
+ fully_displayed_message_count += 1
+
+ # Garante que a UI seja atualizada mesmo que não haja novas mensagens de chat
+ yield chatbot_display_history, gr.update(value=gallery_images), gr.update(value=dna_json), gr.update(value=final_video_path)
+
+def run_story_and_keyframes_wrapper(project_name, prompt, num_scenes, ref_files, duration_per_fragment):
+ """
+ Este wrapper inicia o pipeline de PRÉ-PRODUÇÃO V2.
+ """
+ if not project_name or not project_name.strip():
+ raise gr.Error("Por favor, forneça um nome para o projeto.")
+ aduc.load_project(project_name.strip())
+
+ if not ref_files: raise gr.Error("Por favor, forneça pelo menos uma imagem de referência.")
+ ref_paths = [aduc.process_image_for_story(f.name, f"ref_{i}.jpg") for i, f in enumerate(ref_files)]
+
+ params = PreProductionParams(
+ prompt=prompt,
+ num_scenes=int(num_scenes),
+ ref_paths=ref_paths,
+ duration_per_fragment=duration_per_fragment
+ )
+
+ # Chama a função V2 do AducSdr, que espera `params` e retorna um gerador de `GenerationState`
+ generator = aduc.task_run_story_and_keyframes(params)
+
+ final_state_json = {}
+ for update in process_chat_stream(generator):
+ yield update
+ if update[2] is not gr.skip():
+ final_state_json = update[2] # O terceiro item é o DNA em formato JSON
+
+ return final_state_json
+
+def run_production_wrapper(project_name, state_dict, trim, handler, dest, guidance, stg, steps):
+ """
+ Este wrapper inicia o pipeline de PRODUÇÃO V2.
+ """
+ if not project_name or not project_name.strip():
+ raise gr.Error("O nome do projeto parece ter sido perdido.")
+ aduc.load_project(project_name.strip())
+
+ params = ProductionParams(trim_percent=int(trim), handler_strength=handler, destination_convergence_strength=dest, guidance_scale=guidance, stg_scale=stg, inference_steps=int(steps))
+
+ # A nova função de produção do AducSdr pode precisar ser ajustada para receber os params
+ # ou lê-los diretamente do DNA que já foi atualizado na pré-produção.
+ # Por enquanto, mantemos a chamada.
+ prod_generator = aduc.task_produce_movie(params)
+
+ # O `state_dict` já é um dicionário, então podemos extrair o histórico de chat dele
+ initial_chat = state_dict.get("chat_history", [])
+
+ final_state_json = {}
+ for update in process_chat_stream(prod_generator, initial_chat_history=initial_chat):
+ yield update
+ if update[2] is not gr.skip():
+ final_state_json = update[2]
+
+ return final_state_json
+
+# --- 4. DEFINIÇÃO DA UI ---
+with gr.Blocks(theme=cinematic_theme, css="style.css") as demo:
+ generation_state_holder = gr.State({})
+ gr.Markdown("ADUC-SDR 🎬 - O Diretor de Cinema IA
")
+
+ with gr.Accordion("Configurações do Projeto", open=True):
+ project_name_input = gr.Textbox(label="Nome do Projeto", value="Meu_Filme_01", info="O progresso será salvo em uma pasta com este nome.")
+
+ with gr.Row():
+ with gr.Column(scale=2):
+ with gr.Accordion("Etapa 1: Pré-Produção (Roteiro e Storyboard)", open=True):
+ prompt_input = gr.Textbox(label="Ideia Geral do Filme", value="Um robô solitário explora as ruínas de uma cidade coberta pela natureza.")
+ ref_image_input = gr.File(label="Imagens de Referência", file_count="multiple", file_types=["image"])
+ with gr.Row():
+ num_scenes_slider = gr.Slider(minimum=1, maximum=10, 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)
+ start_pre_prod_button = gr.Button("1. Gerar Roteiro e Storyboard", variant="primary")
+
+ with gr.Accordion("Etapa 2: Produção do Vídeo", open=False, visible=False) as step2_accordion:
+ trim_percent_slider = gr.Slider(minimum=10, maximum=90, value=50, step=5, label="Poda Causal (%)")
+ handler_strength_slider = gr.Slider(label="Força do Déjà-Vu", minimum=0.0, maximum=1.0, value=0.5, step=0.05)
+ dest_strength_slider = gr.Slider(label="Força da Âncora Final", minimum=0.0, maximum=1.0, value=0.75, step=0.05)
+ guidance_scale_slider = gr.Slider(minimum=1.0, maximum=10.0, value=2.0, step=0.1, label="Escala de Orientação")
+ stg_scale_slider = gr.Slider(minimum=0.0, maximum=1.0, value=0.025, step=0.005, label="Escala STG")
+ inference_steps_slider = gr.Slider(minimum=10, maximum=50, value=20, step=1, label="Passos de Inferência")
+ produce_original_button = gr.Button("2. Produzir Vídeo", variant="primary", interactive=False)
+
+ with gr.Column(scale=3):
+ final_video_output = gr.Video(label="Último Clipe Gerado / Filme Final", interactive=False)
+ chat_history_chatbot = gr.Chatbot(label="Diário da Produção", height=600, type='messages')
+ keyframe_gallery = gr.Gallery(label="Keyframes Gerados", object_fit="contain", height="auto")
+
+ with gr.Accordion("🧬 DNA Digital (Estado do Projeto)", open=False):
+ dna_display = gr.JSON()
+
+# --- 5. CONEXÕES DE EVENTOS ---
+ start_pre_prod_button.click(
+ fn=lambda: gr.update(interactive=False),
+ outputs=[start_pre_prod_button]
+ ).then(
+ fn=run_story_and_keyframes_wrapper,
+ inputs=[project_name_input, prompt_input, num_scenes_slider, ref_image_input, duration_per_fragment_slider],
+ outputs=[chat_history_chatbot, keyframe_gallery, dna_display, final_video_output]
+ ).then(
+ fn=lambda data: (data, gr.update(visible=True, open=True), gr.update(interactive=True)),
+ inputs=dna_display,
+ outputs=[generation_state_holder, step2_accordion, produce_original_button]
+ )
+
+ produce_original_button.click(
+ fn=lambda: gr.update(interactive=False),
+ outputs=[produce_original_button]
+ ).then(
+ fn=run_production_wrapper,
+ inputs=[
+ project_name_input,
+ generation_state_holder,
+ trim_percent_slider,
+ handler_strength_slider,
+ dest_strength_slider,
+ guidance_scale_slider,
+ stg_scale_slider,
+ inference_steps_slider
+ ],
+ outputs=[chat_history_chatbot, keyframe_gallery, dna_display, final_video_output]
+ )
+
+# --- 6. INICIALIZAÇÃO DA APLICAÇÃO ---
+if __name__ == "__main__":
+ os.makedirs(WORKSPACE_DIR, exist_ok=True)
+ logger.info("Aplicação Gradio pronta. Lançando interface...")
+ demo.queue().launch()
\ No newline at end of file
diff --git a/app_api.py b/app_api.py
new file mode 100644
index 0000000000000000000000000000000000000000..36156ac9b6eec8305c12ca91c2892779f44636a0
--- /dev/null
+++ b/app_api.py
@@ -0,0 +1,127 @@
+# app_api.py
+#
+# Copyright (C) August 4, 2025 Carlos Rodrigues dos Santos
+#
+# Versão 3.0.0 (API Head for Aduc Framework)
+#
+# Este arquivo implementa um servidor de API usando FastAPI para expor as
+# funcionalidades do Aduc Framework. Ele permite o controle programático
+# do processo de geração de vídeo.
+
+import yaml
+import logging
+import uuid
+from typing import Dict
+
+from fastapi import FastAPI, BackgroundTasks, HTTPException
+
+# --- 1. IMPORTAÇÃO DO FRAMEWORK E SEUS TIPOS ---
+import aduc_framework
+from aduc_framework.types import GenerationState, PreProductionParams, ProductionParams
+
+# --- CONFIGURAÇÃO INICIAL ---
+logger = logging.getLogger(__name__)
+
+# Cria a aplicação FastAPI
+app = FastAPI(
+ title="ADUC-SDR Framework API",
+ description="API para orquestração de geração de vídeo coerente com IA.",
+ version="3.0.0"
+)
+
+# Carrega a configuração e inicializa uma instância SINGLETON do framework.
+# O framework é pesado e deve ser carregado apenas uma vez na inicialização da API.
+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("API FastAPI inicializada e conectada ao Aduc Framework.")
+except Exception as e:
+ logger.critical(f"ERRO CRÍTICO durante a inicialização da API: {e}", exc_info=True)
+ # A API não pode funcionar sem o framework, então saímos se falhar.
+ exit()
+
+# --- ARMAZENAMENTO DE TAREFAS EM MEMÓRIA ---
+# Em um ambiente de produção real, isso seria substituído por um banco de dados
+# ou um cache como Redis para persistir o estado das tarefas.
+tasks_state: Dict[str, GenerationState] = {}
+
+
+# --- FUNÇÕES DE BACKGROUND ---
+
+def run_production_in_background(task_id: str, params: ProductionParams):
+ """
+ Função que executa a tarefa de produção demorada em segundo plano.
+ Ela opera na instância global 'aduc' para modificar seu estado interno.
+ """
+ logger.info(f"Background task {task_id}: Iniciando produção de vídeo...")
+ try:
+ # A tarefa do framework modifica o estado interno da instância 'aduc'
+ _, _, final_state = aduc.task_produce_original_movie(params=params)
+
+ # Armazena o estado final e completo no nosso "banco de dados" de tarefas
+ tasks_state[task_id] = final_state
+ logger.info(f"Background task {task_id}: Produção de vídeo concluída com sucesso.")
+ except Exception as e:
+ logger.error(f"Background task {task_id}: Falha na produção. Erro: {e}", exc_info=True)
+ # Opcional: Atualizar o estado da tarefa com uma mensagem de erro.
+
+
+# --- ENDPOINTS DA API ---
+
+@app.post("/v1/pre-production", response_model=GenerationState, tags=["Workflow"])
+async def start_pre_production(params: PreProductionParams):
+ """
+ Inicia e executa a etapa de pré-produção (storyboard e keyframes).
+
+ Esta é uma chamada síncrona, pois a pré-produção é relativamente rápida.
+ Ela retorna o estado de geração completo após a conclusão.
+ """
+ logger.info(f"API: Recebida solicitação de pré-produção com prompt: '{params.prompt[:30]}...'")
+ try:
+ _, _, updated_state = aduc.task_pre_production(params=params)
+ return updated_state
+ except Exception as e:
+ logger.error(f"API: Erro na pré-produção: {e}", exc_info=True)
+ raise HTTPException(status_code=500, detail=f"Erro interno durante a pré-produção: {e}")
+
+@app.post("/v1/production", status_code=202, tags=["Workflow"])
+async def start_production(params: ProductionParams, background_tasks: BackgroundTasks):
+ """
+ Inicia a tarefa de produção de vídeo principal em segundo plano.
+
+ Esta chamada retorna imediatamente com um `task_id`. Use o endpoint
+ `/v1/status/{task_id}` para verificar o progresso e obter o resultado final.
+ """
+ task_id = str(uuid.uuid4())
+ logger.info(f"API: Recebida solicitação de produção. Criando tarefa de background com ID: {task_id}")
+
+ # Armazena o estado atual (pré-produção) antes de iniciar a nova tarefa
+ tasks_state[task_id] = aduc.get_current_state()
+
+ # Adiciona a função demorada para ser executada em segundo plano
+ background_tasks.add_task(run_production_in_background, task_id, params)
+
+ return {"message": "Produção de vídeo iniciada em segundo plano.", "task_id": task_id}
+
+@app.get("/v1/status/{task_id}", response_model=GenerationState, tags=["Workflow"])
+async def get_task_status(task_id: str):
+ """
+ Verifica o estado de uma tarefa de geração em andamento ou concluída.
+ """
+ logger.info(f"API: Verificando status da tarefa {task_id}")
+ state = tasks_state.get(task_id)
+ if not state:
+ raise HTTPException(status_code=404, detail="ID de tarefa não encontrado.")
+
+ # Retorna o estado mais recente que temos para essa tarefa
+ return state
+
+@app.get("/health", tags=["Infra"])
+async def health_check():
+ """
+ Endpoint simples para verificar se a API está online.
+ """
+ return {"status": "ok"}
\ No newline at end of file
diff --git a/config.yaml b/config.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..89e8fcb849014834ff72fe90243297fa8765b8bf
--- /dev/null
+++ b/config.yaml
@@ -0,0 +1,58 @@
+# config.yaml
+# Configuração central para a aplicação Deformes4D e seus especialistas.
+
+application:
+ workspace_dir: "deformes_workspace"
+
+# Configuração para Hugging Face Spaces
+sdk: gradio
+app_file: app.py
+
+specialists:
+
+ vae:
+ gpus_required: 2 # <-- DEDIQUE UMA GPU PARA O VAE
+
+ llm_engine:
+ provider: "gemini" # Opções: "llama", "gemini", etc.
+
+ seedvr:
+ gpus_required: 0
+
+ llama_multimodal:
+ gpus_required: 0 # <-- GARANTIR QUE ISTO É > 0
+ model_id: "meta-llama/Llama-3.2-11B-Vision-Instruct"
+ max_new_tokens: 4096
+ temperature: 0.5
+ top_p: 0.6
+
+ flux:
+ # Define quantas GPUs o pool do Flux deve tentar alocar.
+ # Se não houver GPUs suficientes, o hardware_manager lançará um erro.
+ # Se 0, usará a CPU.
+ gpus_required: 0
+
+ ltx:
+ # Define quantas GPUs o pool do LTX deve tentar alocar.
+ gpus_required: 6
+
+ # Aponta para o arquivo de configuração específico do modelo LTX.
+ # Alterado para usar o modelo 0.9.8-dev.
+ config_file: "ltxv-13b-0.9.8-distilled.yaml"
+ enable_prompt_enhancement: false
+
+
+ lora:
+ - model_id: "Lightricks/LTX-Video-ICLoRA-pose-13b-0.9.7"
+ weight: 0.5
+ - model_id: "Lightricks/LTX-Video-ICLoRA-depth-13b-0.9.7"
+ weight: 0.3
+ - model_id: "Lightricks/LTX-Video-ICLoRA-detailer-13b-0.9.8"
+ weight: 0.6
+
+
+ mmaudio:
+ gpus_required: 0
+
+
+
\ No newline at end of file
diff --git a/i18n.json b/i18n.json
new file mode 100644
index 0000000000000000000000000000000000000000..889f19641ff7a3338aba9b1dc49504ce01ed6506
--- /dev/null
+++ b/i18n.json
@@ -0,0 +1,179 @@
+{
+ "pt": {
+ "app_title": "ADUC-SDR 🎬 - O Diretor de Cinema IA",
+ "app_subtitle": "Crie um filme completo com vídeo e áudio, orquestrado por uma equipe de IAs especialistas.",
+ "lang_selector_label": "Idioma / Language",
+ "step1_accordion": "Etapa 1: Roteiro e Cenas-Chave (Pré-Produção)",
+ "prompt_label": "Ideia Geral do Filme",
+ "ref_images_label": "Imagens de Referência",
+ "keyframes_label": "Número de Cenas-Chave",
+ "duration_label": "Duração de cada Clipe (s)",
+ "duration_info": "Define a duração alvo para cada fragmento de vídeo gerado entre os keyframes.",
+ "storyboard_and_keyframes_button": "1A. Gerar Roteiro e Keyframes (Modo Diretor de Arte)",
+ "storyboard_from_photos_button": "1B. Gerar Roteiro a partir de Fotos (Modo Fotógrafo)",
+ "step1_mode_b_info": "Modo Fotógrafo: As imagens carregadas são usadas como um banco de cenas e a IA escolherá a melhor para cada parte do roteiro.",
+ "storyboard_output_label": "Roteiro Gerado (Storyboard)",
+ "keyframe_gallery_label": "Galeria de Cenas-Chave (Keyframes)",
+ "step3_accordion": "Etapa 3: Produção do Vídeo Original",
+ "step3_description": "Gere o vídeo base usando o motor LTX. Ajuste os parâmetros opcionais abaixo para controlar a geração.",
+ "produce_original_button": "🎬 Produzir Vídeo Original",
+ "ltx_advanced_options": "Opções Avançadas do LTX",
+ "causality_controls_title": "Controles de Causalidade (Déjà-Vu)",
+ "trim_percent_label": "Poda Causal (%)",
+ "trim_percent_info": "Percentual 'descartado' para criar a memória do futuro (Déjà-Vu). Valores mais altos criam movimentos mais complexos.",
+ "forca_guia_label": "Força do Déjà-Vu (Guia de Trajetória)",
+ "forca_guia_info": "Quão forte a 'memória do futuro' influencia a nova cena. Ajuda a criar movimentos mais ricos.",
+ "convergencia_final_label": "Força da Âncora Final (Destino)",
+ "convergencia_final_info": "Quão forte o vídeo é puxado em direção à imagem do keyframe final.",
+ "ltx_pipeline_options": "Parâmetros da Pipeline LTX",
+ "guidance_scale_label": "Escala de Orientação (Guidance)",
+ "guidance_scale_info": "Força com que o prompt de movimento guia a geração. Valores mais altos seguem o prompt mais de perto.",
+ "stg_scale_label": "Escala STG (Continuidade Temporal)",
+ "stg_scale_info": "Controla a consistência do movimento entre os frames. Valores mais baixos podem criar mais dinamismo.",
+ "steps_label": "Passos de Inferência",
+ "steps_info": "Número de passos para gerar cada fragmento. Mais passos podem melhorar a qualidade, mas aumentam o tempo.",
+ "step4_accordion": "Etapa 4: Pós-Produção (Opcional)",
+ "step4_description": "Aplique efeitos de melhoria ao vídeo mais recente. Cada etapa usa o resultado da anterior como fonte.",
+ "sub_step_a_upscaler": "A. Upscaler Latente 2x",
+ "upscaler_description": "Aumenta a resolução do vídeo decodificando latentes com upscale. Gera uma nova fonte para as etapas B e C.",
+ "upscaler_options": "Opções do Upscaler",
+ "upscaler_chunk_size_label": "Fragmentos Latentes por Lote",
+ "upscaler_chunk_size_info": "Menos fragmentos por lote consomem menos VRAM, mas podem ser mais lentos. Essencial para resoluções altas.",
+ "run_upscaler_button": "Executar Upscaler Latente",
+ "sub_step_b_hd": "B. Masterização HD (SeedVR)",
+ "hd_description": "Aplica super-resolução com IA para adicionar detalhes finos e texturas ao vídeo. Usa o resultado mais recente como fonte.",
+ "hd_options": "Opções da Masterização HD",
+ "hd_model_label": "Modelo SeedVR",
+ "hd_steps_label": "Passos de Inferência HD",
+ "hd_steps_info": "Número de passos para o aprimoramento. Mais passos geram mais detalhes.",
+ "run_hd_button": "Executar Masterização HD",
+ "sub_step_c_audio": "C. Geração de Áudio",
+ "audio_description": "Gera e adiciona uma trilha sonora e efeitos ao vídeo mais recente, baseado no prompt global ou em um novo.",
+ "audio_options": "Opções de Áudio",
+ "audio_prompt_label": "Prompt de Áudio Detalhado (Opcional)",
+ "audio_prompt_info": "Descreva os sons, efeitos e música desejados. Se vazio, usará o prompt geral do filme.",
+ "run_audio_button": "Gerar Áudio",
+ "final_video_label": "Filme Final (Resultado da Última Etapa)",
+ "log_accordion_label": "📝 Log de Geração (Detalhado)",
+ "log_display_label": "Log da Sessão",
+ "update_log_button": "Atualizar Log"
+ },
+ "en": {
+ "app_title": "ADUC-SDR 🎬 - The AI Film Director",
+ "app_subtitle": "Create a complete film with video and audio, orchestrated by a team of expert AIs.",
+ "lang_selector_label": "Language / Idioma",
+ "step1_accordion": "Step 1: Script & Key-Scenes (Pre-Production)",
+ "prompt_label": "General Film Idea",
+ "ref_images_label": "Reference Images",
+ "keyframes_label": "Number of Key-Scenes",
+ "duration_label": "Duration per Clip (s)",
+ "duration_info": "Sets the target duration for each video fragment generated between keyframes.",
+ "storyboard_and_keyframes_button": "1A. Generate Script & Keyframes (Art Director Mode)",
+ "storyboard_from_photos_button": "1B. Generate Script from Photos (Photographer Mode)",
+ "step1_mode_b_info": "Photographer Mode: Uploaded images are used as a scene bank, and the AI will choose the best one for each script part.",
+ "storyboard_output_label": "Generated Script (Storyboard)",
+ "keyframe_gallery_label": "Key-Scenes Gallery (Keyframes)",
+ "step3_accordion": "Step 3: Original Video Production",
+ "step3_description": "Generate the base video using the LTX engine. Adjust the optional parameters below to control the generation.",
+ "produce_original_button": "🎬 Produce Original Video",
+ "ltx_advanced_options": "Advanced LTX Options",
+ "causality_controls_title": "Causality Controls (Déjà-Vu)",
+ "trim_percent_label": "Causal Pruning (%)",
+ "trim_percent_info": "Percentage 'discarded' to create the future memory (Déjà-Vu). Higher values create more complex movements.",
+ "forca_guia_label": "Déjà-Vu Strength (Trajectory Guide)",
+ "forca_guia_info": "How strongly the 'future memory' influences the new scene. Helps create richer movements.",
+ "convergencia_final_label": "Final Anchor Strength (Destination)",
+ "convergencia_final_info": "How strongly the video is pulled towards the final keyframe image.",
+ "ltx_pipeline_options": "LTX Pipeline Parameters",
+ "guidance_scale_label": "Guidance Scale",
+ "guidance_scale_info": "How strongly the motion prompt guides the generation. Higher values follow the prompt more closely.",
+ "stg_scale_label": "STG Scale (Temporal Continuity)",
+ "stg_scale_info": "Controls motion consistency between frames. Lower values may create more dynamism.",
+ "steps_label": "Inference Steps",
+ "steps_info": "Number of steps to generate each fragment. More steps can improve quality but increase time.",
+ "step4_accordion": "Step 4: Post-Production (Optional)",
+ "step4_description": "Apply enhancement effects to the latest video. Each step uses the result of the previous one as its source.",
+ "sub_step_a_upscaler": "A. Latent Upscaler 2x",
+ "upscaler_description": "Increases video resolution by decoding upscaled latents. Generates a new source for steps B and C.",
+ "upscaler_options": "Upscaler Options",
+ "upscaler_chunk_size_label": "Latent Fragments per Batch",
+ "upscaler_chunk_size_info": "Fewer fragments per batch consume less VRAM but can be slower. Essential for high resolutions.",
+ "run_upscaler_button": "Run Latent Upscaler",
+ "sub_step_b_hd": "B. HD Mastering (SeedVR)",
+ "hd_description": "Applies AI-powered super-resolution to add fine details and textures. Uses the latest result as source.",
+ "hd_options": "HD Mastering Options",
+ "hd_model_label": "SeedVR Model",
+ "hd_steps_label": "HD Inference Steps",
+ "hd_steps_info": "Number of steps for the enhancement. More steps generate more details.",
+ "run_hd_button": "Run HD Mastering",
+ "sub_step_c_audio": "C. Audio Generation",
+ "audio_description": "Generates and adds a soundtrack and effects to the latest video, based on the global prompt or a new one.",
+ "audio_options": "Audio Options",
+ "audio_prompt_label": "Detailed Audio Prompt (Optional)",
+ "audio_prompt_info": "Describe the desired sounds, effects, and music. If empty, it will use the general film prompt.",
+ "run_audio_button": "Generate Audio",
+ "final_video_label": "Final Film (Result of the Last Step)",
+ "log_accordion_label": "📝 Generation Log (Detailed)",
+ "log_display_label": "Session Log",
+ "update_log_button": "Update Log"
+ },
+ "zn": {
+ "app_title": "ADUC-SDR 🎬 - 人工智能电影导演",
+ "app_subtitle": "由人工智能专家团队精心策划,创作一部包含视频和音频的完整电影。",
+ "lang_selector_label": "语言 / Language",
+ "step1_accordion": "第 1 步:剧本和关键场景(前期制作)",
+ "prompt_label": "电影总体构想",
+ "ref_images_label": "参考图像",
+ "keyframes_label": "关键场景数量",
+ "duration_label": "每个剪辑的持续时间(秒)",
+ "duration_info": "设置关键帧之间生成的每个视频片段的目标持续时间。",
+ "storyboard_and_keyframes_button": "1A. 生成剧本和关键帧 (艺术总监模式)",
+ "storyboard_from_photos_button": "1B. 从照片生成剧本 (摄影师模式)",
+ "step1_mode_b_info": "摄影师模式:上传的图像被用作场景库,AI将为剧本的每个部分选择最佳图像。",
+ "storyboard_output_label": "生成的剧本",
+ "keyframe_gallery_label": "关键场景画廊",
+ "step3_accordion": "第 3 步:原始视频制作",
+ "step3_description": "使用LTX引擎生成基础视频。调整下面的可选参数以控制生成过程。",
+ "produce_original_button": "🎬 制作原始视频",
+ "ltx_advanced_options": "LTX 高级选项",
+ "causality_controls_title": "因果控制 (Déjà-Vu)",
+ "trim_percent_label": "因果修剪 (%)",
+ "trim_percent_info": "为创造未来记忆(Déjà-Vu)而“丢弃”的百分比。较高的值会产生更复杂的运动。",
+ "forca_guia_label": "Déjà-Vu强度(轨迹引导)",
+ "forca_guia_info": "“未来记忆”对新场景的影响强度。有助于创造更丰富的运动。",
+ "convergencia_final_label": "最终锚点强度(目的地)",
+ "convergencia_final_info": "视频被拉向最终关键帧图像的强度。",
+ "ltx_pipeline_options": "LTX 管线参数",
+ "guidance_scale_label": "引导尺度 (Guidance)",
+ "guidance_scale_info": "运动提示指导生成的强度。较高的值会更紧密地遵循提示。",
+ "stg_scale_label": "STG 尺度 (时间连续性)",
+ "stg_scale_info": "控制帧之间的运动一致性。较低的值可能会创造更多动态。",
+ "steps_label": "推理步骤",
+ "steps_info": "生成每个片段的步骤数。更多步骤可以提高质量但会增加时间。",
+ "step4_accordion": "第 4 步:后期制作(可选)",
+ "step4_description": "对最新的视频应用增强效果。每一步都使用前一步的结果作为其源。",
+ "sub_step_a_upscaler": "A. 潜在空间放大器 2x",
+ "upscaler_description": "通过解码放大的潜在空间来提高视频分辨率。为步骤 B 和 C 生成新的源。",
+ "upscaler_options": "放大器选项",
+ "upscaler_chunk_size_label": "每批潜在片段数",
+ "upscaler_chunk_size_info": "每批较少的片段消耗更少的 VRAM,但可能更慢。对高分辨率至关重要。",
+ "run_upscaler_button": "运行潜在空间放大器",
+ "sub_step_b_hd": "B. 高清母带处理 (SeedVR)",
+ "hd_description": "应用 AI 驱动的超分辨率技术,添加精细细节和纹理。使用最新的结果作为源。",
+ "hd_options": "高清母带处理选项",
+ "hd_model_label": "SeedVR 模型",
+ "hd_steps_label": "高清推理步骤",
+ "hd_steps_info": "增强的步骤数。更多步骤会生成更多细节。",
+ "run_hd_button": "运行高清母带处理",
+ "sub_step_c_audio": "C. 音频生成",
+ "audio_description": "根据全局提示或新提示,为最新的视频生成并添加音轨和效果。",
+ "audio_options": "音频选项",
+ "audio_prompt_label": "详细音频提示(可选)",
+ "audio_prompt_info": "描述所需的声音、效果和音乐。如果为空,将使用电影的通用提示。",
+ "run_audio_button": "生成音频",
+ "final_video_label": "最终影片(最后一步的结果)",
+ "log_accordion_label": "📝 生成日志(详细)",
+ "log_display_label": "会话日志",
+ "update_log_button": "更新日志"
+ }
+}
\ No newline at end of file
diff --git a/packages.txt b/packages.txt
new file mode 100644
index 0000000000000000000000000000000000000000..20645e641240cb419f5fc66c14c1447e91daf669
--- /dev/null
+++ b/packages.txt
@@ -0,0 +1 @@
+ffmpeg
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000000000000000000000000000000000000..c607e2581aefb22ca7170e4a612f24dfcd28861c
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,49 @@
+torch==2.6.0
+torchvision==0.21.0
+torchaudio==2.6.0
+opencv-python==4.9.0.80
+torchao
+transformers
+accelerate
+safetensors
+einops
+sentencepiece
+git+https://github.com/hkchengrex/MMAudio.git@main
+git+https://github.com/huggingface/diffusers.git@main
+gradio>=5.23.1
+gradio[oauth]
+fastapi
+uvicorn[standard]
+pydantic
+soundfile
+tiktoken
+transformers_stream_generator
+rotary-embedding-torch
+Pillow
+PyYAML
+imageio
+imageio-ffmpeg
+av
+huggingface_hub
+google-generativeai
+torchmetrics
+pycocotools
+torch-fidelity
+moviepy
+imageio
+tabulate
+deepdiff
+parameterized
+mediapy
+black
+flake8
+isort
+pre-commit
+expecttest
+hypothesis
+numpy<2
+ninja
+psutil
+packaging
+https://github.com/Dao-AILab/flash-attention/releases/download/v2.7.4.post1/flash_attn-2.7.4.post1+cu12torch2.6cxx11abiFALSE-cp310-cp310-linux_x86_64.whl
+#https://huggingface.co/ByteDance-Seed/SeedVR2-3B/resolve/main/apex-0.1-cp310-cp310-linux_x86_64.whl
diff --git a/run.py b/run.py
new file mode 100644
index 0000000000000000000000000000000000000000..0f8e00bc1ecb3ba09fed1e28fd829dc49bbcafda
--- /dev/null
+++ b/run.py
@@ -0,0 +1,20 @@
+import argparse
+import uvicorn
+import os
+
+def main():
+ parser = argparse.ArgumentParser(description="Executor do Aduc-Sdr")
+ parser.add_argument("mode", choices=["gradio", "api"], help="Modo de execução: 'gradio' para a UI, 'api' para o servidor FastAPI.")
+ args = parser.parse_args()
+
+ if args.mode == "gradio":
+ print("Iniciando a interface Gradio...")
+ # Importa e executa a lógica de lançamento que está no final de app_gradio.py
+ from app_gradio import demo
+ demo.queue().launch()
+ elif args.mode == "api":
+ print("Iniciando o servidor FastAPI em http://127.0.0.1:8000")
+ uvicorn.run("app_api:app", host="127.0.0.1", port=8000, reload=True)
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file
diff --git a/setup.py b/setup.py
new file mode 100644
index 0000000000000000000000000000000000000000..c89a55187abc78ff9a18ecfd1fa8ffe9d94304f6
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,63 @@
+# setup.py
+#
+# Copyright (C) August 4, 2025 Carlos Rodrigues dos Santos
+#
+# Versão 2.0.0 (Clonagem Anônima e Robusta)
+# - Usa URLs HTTPS explícitas e anônimas para evitar que o Git tente
+# usar credenciais em cache desnecessariamente para repositórios públicos.
+
+import os
+import subprocess
+import sys
+from pathlib import Path
+
+# --- Configuração ---
+DEPS_DIR = Path("./deps")
+
+# URLs explícitas e anônimas para os repositórios públicos
+REPOS_TO_CLONE = {
+ "LTX-Video": "https://huggingface.co/spaces/Lightricks/ltx-video-distilled",
+ "SeedVR_Space": "https://huggingface.co/spaces/ByteDance-Seed/SeedVR2-3B",
+ "MMAudio": "https://github.com/hkchengrex/MMAudio.git"
+}
+
+def run_command(command, cwd=None):
+ """Executa um comando no terminal e lida com erros."""
+ print(f"Executando: {' '.join(command)}")
+ try:
+ # Redireciona o stdin para DEVNULL para garantir que o git não tente pedir senha
+ subprocess.run(
+ command,
+ check=True,
+ cwd=cwd,
+ stdin=subprocess.DEVNULL,
+ )
+ except subprocess.CalledProcessError as e:
+ print(f"ERRO: O comando falhou com o código de saída {e.returncode}")
+ # stderr é capturado automaticamente se check=True falhar
+ print(f"Stderr: {e.stderr}")
+ sys.exit(1)
+ except FileNotFoundError:
+ print(f"ERRO: O comando '{command[0]}' não foi encontrado. Certifique-se de que o git está instalado e no seu PATH.")
+ sys.exit(1)
+
+def main():
+ print("--- Iniciando Setup do Ambiente ADUC-SDR ---")
+
+ DEPS_DIR.mkdir(exist_ok=True)
+
+ for repo_name, repo_url in REPOS_TO_CLONE.items():
+ repo_path = DEPS_DIR / repo_name
+ if repo_path.exists():
+ print(f"Repositório '{repo_name}' já existe. Pulando a clonagem.")
+ else:
+ print(f"Clonando '{repo_name}' de {repo_url}...")
+ run_command(["git", "clone", "--depth", "1", repo_url, str(repo_path)])
+ print(f"'{repo_name}' clonado com sucesso.")
+
+ print("\n--- Setup do Ambiente Concluído com Sucesso! ---")
+ print("Você agora pode iniciar a aplicação principal (ex: python app.py).")
+
+if __name__ == "__main__":
+ main()
+
\ No newline at end of file
diff --git a/start.sh b/start.sh
new file mode 100644
index 0000000000000000000000000000000000000000..45373e31625ac65f8431eab7a3c51da5a72a4632
--- /dev/null
+++ b/start.sh
@@ -0,0 +1,197 @@
+#!/bin/bash
+# =============================================================================
+# START.SH - Complete AI Video Suite (Production Ready)
+# =============================================================================
+set -euo pipefail
+
+python3 -c "
+import os
+import subprocess
+import tempfile
+import os
+import sys
+import shutil
+from pathlib import Path
+#os.system(\"pip install --upgrade --pre --extra-index-url https://download.pytorch.org/whl/nightly/cu12 'torch<2.9' spaces\")
+"
+
+# =============================================================================
+# GLOBAL VARIABLE INITIALIZATION
+# =============================================================================
+
+# Initialize critical variables with default values
+export GPU_COUNT=0
+export GPU_MODEL="Unknown"
+export GPU_MEMORY=0
+export GPU_ARCH="CPU"
+export HAS_GPU=false
+export IS_OPTIMIZED_GPU=false
+export CPU_CORES=1
+export TOTAL_RAM="0G"
+export AVAILABLE_RAM="0G"
+export DISK_SPACE="unknown"
+
+# TERM variable fix
+export TERM="${TERM:-xterm-256color}"
+
+# Diretório do installer
+INSTALLER_DIR="/app/installer"
+
+# =============================================================================
+# BANNER E INFORMAÇÕES
+# =============================================================================
+
+print_banner() {
+ clear || true
+ echo "=================================================================="
+ echo " 🚀 Aduc-sdr firmware"
+ echo " ⚡ Multi-GPU Video Generation Suite"
+ echo " 🎬 LTX FP8 | Q8 Kernels | SeedVR | Wan2.2 | VINCIE | MMAudio"
+ echo "=================================================================="
+ echo ""
+}
+
+
+detect_hardware() {
+ log_info "🔍 Detectando hardware do sistema..."
+
+ # CPU Info (export as global variables)
+ export CPU_CORES=$(nproc)
+ export CPU_MODEL=$(grep "model name" /proc/cpuinfo | head -1 | cut -d: -f2 | xargs)
+
+ # Memory Info
+ export TOTAL_RAM=$(free -h | awk '/^Mem:/ {print $2}')
+ export AVAILABLE_RAM=$(free -h | awk '/^Mem:/ {print $7}')
+
+ # GPU Detection
+ if command -v nvidia-smi >/dev/null 2>&1; then
+ export GPU_COUNT=$(nvidia-smi --list-gpus | wc -l)
+ export GPU_MODEL=$(nvidia-smi --query-gpu=name --format=csv,noheader,nounits | head -1)
+ export GPU_MEMORY=$(nvidia-smi --query-gpu=memory.total --format=csv,noheader,nounits | head -1)
+
+ # Detect specific GPU architecture
+ if echo "$GPU_MODEL" | grep -q "L40S"; then
+ export GPU_ARCH="ADA_LOVELACE"
+ export COMPUTE_CAP="8.9"
+ export IS_OPTIMIZED_GPU=true
+ elif echo "$GPU_MODEL" | grep -q "A100"; then
+ export GPU_ARCH="AMPERE"
+ export COMPUTE_CAP="8.0"
+ export IS_OPTIMIZED_GPU=true
+ elif echo "$GPU_MODEL" | grep -q "H100"; then
+ export GPU_ARCH="HOPPER"
+ export COMPUTE_CAP="9.0"
+ export IS_OPTIMIZED_GPU=true
+ else
+ export GPU_ARCH="OTHER"
+ export COMPUTE_CAP="unknown"
+ export IS_OPTIMIZED_GPU=false
+ fi
+
+ export HAS_GPU=true
+ else
+ export GPU_COUNT=0
+ export GPU_MODEL="None"
+ export GPU_MEMORY=0
+ export GPU_ARCH="CPU"
+ export HAS_GPU=false
+ export IS_OPTIMIZED_GPU=false
+ fi
+
+ # Storage Info
+ export DISK_SPACE=$(df -h /app 2>/dev/null | awk 'NR==2 {print $4}' || echo "unknown")
+
+ log_info "Hardware detectado:"
+ log_info " 🖥️ CPU: $CPU_MODEL ($CPU_CORES cores)"
+ log_info " 💾 RAM: $AVAILABLE_RAM / $TOTAL_RAM disponível"
+ log_info " 🎮 GPU: $GPU_MODEL x$GPU_COUNT"
+ log_info " 🏗️ Arquitetura: $GPU_ARCH (CC: $COMPUTE_CAP)"
+ log_info " 💿 Disco: $DISK_SPACE disponível"
+
+ if [[ "$IS_OPTIMIZED_GPU" == "true" ]]; then
+ log_success "GPU otimizada detectada - performance máxima disponível!"
+ fi
+}
+
+load_installer_modules() {
+ log_info "📦 Carregando módulos do installer..."
+
+ local modules=(
+ "utils.sh"
+ "setup_env.sh"
+ "check_gpu.sh"
+ "multi_gpu_config.sh"
+ )
+
+ for module in "${modules[@]}"; do
+ local module_path="$INSTALLER_DIR/$module"
+ if [[ -f "$module_path" ]]; then
+ # shellcheck source=/dev/null
+ source "$module_path"
+ log_debug "Módulo carregado: $module"
+ else
+ log_warning "Módulo não encontrado: $module_path"
+ fi
+ done
+
+ log_success "Módulos do installer carregados"
+}
+
+
+start_application() {
+ log_info "🚀 Iniciando Complete AI Video Suite..."
+
+ # Preparar argumentos da aplicação
+ local app_args=()
+
+ if [[ "$LISTEN" == "true" ]]; then
+ app_args+=("--listen")
+ fi
+
+ if [[ "$SHARE" == "true" ]]; then
+ app_args+=("--share")
+ fi
+
+ app_args+=("--port" "$PORT")
+
+ if [[ "$MULTI_GPU" == "true" ]]; then
+ app_args+=("--multi-gpu" "--gpus" "$NUM_GPUS")
+ fi
+
+ if [[ "$DEBUG_MODE" == "true" ]]; then
+ app_args+=("--debug")
+ fi
+
+ if [[ "$PROFILE" == "true" ]]; then
+ app_args+=("--profile")
+ fi
+
+ # Configurar variáveis de ambiente para a aplicação
+ export AI_SUITE_MULTI_GPU="$MULTI_GPU"
+ export AI_SUITE_NUM_GPUS="$NUM_GPUS"
+ export AI_SUITE_DEBUG="$DEBUG_MODE"
+ export AI_SUITE_PROFILE="$PROFILE"
+
+ # Logs finais
+ echo ""
+ log_success "=================================================================="
+ log_success "🎬 Complete Video Suite Ready!"
+ log_success "=================================================================="
+ log_info "🌐 Servidor: http://$HOST:$PORT"
+ log_info "🎮 GPUs: $GPU_COUNT x $GPU_MODEL"
+ log_info "⚡ Multi-GPU: $MULTI_GPU"
+ log_info "🚀 Otimizado: $OPTIMIZE"
+ log_info "📊 Profiling: $PROFILE"
+
+ echo "🚀 Iniciando app.py..."
+ python3 /app/app.py --listen --port ${PORT:-7860}
+
+ if [[ "$SHARE" == "true" ]]; then
+ log_info "🌍 Link público será exibido pelo Gradio"
+ fi
+
+ log_success "=================================================================="
+ echo ""
+}
+
+start_application
\ No newline at end of file
diff --git a/style.css b/style.css
new file mode 100644
index 0000000000000000000000000000000000000000..d3ae65bba442f3992e5b6859da84c99aff711983
--- /dev/null
+++ b/style.css
@@ -0,0 +1,31 @@
+/* style.css */
+
+/* Melhora o contraste geral dos inputs */
+.gradio-container .gr-input-text, .gradio-container .gr-textarea, .gradio-container .gr-number {
+ background-color: #374151 !important; /* Fundo cinza escuro para caixas de texto */
+ color: #E5E7EB !important; /* Cor do texto clara */
+ border-color: #4B5563 !important; /* Borda sutil */
+}
+
+/* Garante que o placeholder seja legível */
+.gradio-container .gr-input-text::placeholder, .gradio-container .gr-textarea::placeholder {
+ color: #9CA3AF !important;
+}
+
+/* Melhora a aparência dos sliders */
+.gradio-container .gr-slider {
+ --slider-color: #8B5CF6; /* Cor roxa para o slider */
+ --slider-track-color: #4B5563; /* Cor do trilho do slider */
+ --slider-track-color-active: #6D28D9;
+}
+
+/* Garante que o texto do label dos blocos seja visível */
+.gradio-container .gr-block-label {
+ color: #E5E7EB !important;
+ background-color: #374151 !important;
+}
+
+/* Garante que o texto do título dos blocos seja visível */
+.gradio-container .gr-panel-title {
+ color: #FFFFFF !important;
+}
\ No newline at end of file