eeuuia commited on
Commit
cebfbc8
·
verified ·
1 Parent(s): 9a6b3d7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +124 -84
app.py CHANGED
@@ -1,105 +1,129 @@
1
  # FILE: app.py
2
  # DESCRIPTION: Final Gradio web interface for the ADUC-SDR Video Suite.
3
- # This version is refactored to use the central LtxAducOrchestrator, simplifying the UI logic
4
- # and making it a pure client of the backend services.
5
 
6
  import gradio as gr
7
  import traceback
8
  import sys
9
  import os
10
  import logging
11
- from PIL import Image
 
12
 
13
  # ==============================================================================
14
- # --- IMPORTAÇÃO DOS SERVIÇOS DE BACKEND E UTILS ---
15
  # ==============================================================================
16
 
17
- #try:
18
- # --- MUDANÇA PRINCIPAL: Importamos apenas o ORQUESTRADOR ---
19
- # O orquestrador é agora nosso único ponto de entrada para a geração de vídeo.
20
- from api.ltx.ltx_aduc_orchestrator import ltx_aduc_orchestrator
21
 
22
- # O SeedVR (upscaler de resolução) ainda é um serviço separado que pode ser chamado após a geração.
23
- from api.seedvr.seedvr_aduc_pipeline import seed_aduc_pipeline
24
-
25
- # Nosso decorador de logging para depuração
26
- from utils.debug_utils import log_function_io
27
-
28
- logging.info("All backend services (Orchestrator, SeedVR) and debug utils imported successfully.")
29
-
30
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
 
32
  # ==============================================================================
33
  # --- FUNÇÕES WRAPPER (PONTE ENTRE UI E BACKEND) ---
34
  # ==============================================================================
35
 
36
  @log_function_io
37
- def run_orchestrated_generation(
38
- prompt: str, start_img_path: str,
39
  height: int, width: int, duration: float,
40
- fp_guidance_preset: str, fp_guidance_scale_list: str, fp_stg_scale_list: str,
41
- fp_num_inference_steps: int,
42
  progress=gr.Progress(track_tqdm=True)
43
  ) -> tuple:
44
  """
45
- Função wrapper simplificada que coleta dados da UI e chama o orquestrador principal.
46
  """
47
  try:
48
- logging.info("[UI] Request received. Submitting job to the main orchestrator...")
49
-
50
- # Monta o dicionário de configurações avançadas LTX a partir da UI
 
 
 
 
 
 
51
  ltx_configs = {
52
- "guidance_preset": fp_guidance_preset,
53
- "guidance_scale_list": fp_guidance_scale_list,
54
- "stg_scale_list": fp_stg_scale_list,
55
- "num_inference_steps": fp_num_inference_steps
56
  }
57
 
58
- # Carrega a imagem inicial para um objeto PIL, que é o que o orquestrador espera.
59
- initial_image_pil = Image.open(start_img_path).convert("RGB") if start_img_path else None
60
-
61
- # --- CHAMADA ÚNICA E LIMPA PARA O ORQUESTRADOR ---
62
- video_path = ltx_aduc_orchestrator(
63
- prompt=prompt,
64
- initial_image=initial_image_pil,
65
- height=height,
66
- width=width,
67
- duration_in_seconds=duration,
68
- ltx_configs=ltx_configs
69
  )
70
 
71
- if not video_path:
72
- raise RuntimeError("Orchestrator failed to return a valid video path. Check backend logs for details.")
73
-
74
- logging.info(f"[UI] Orchestrator job successful. Video path: {video_path}")
75
-
76
- # O estado agora pode ser mais simples, apenas guardando o caminho do vídeo gerado para o próximo passo (SeedVR).
77
- new_state = {"low_res_video": video_path}
78
  return video_path, new_state, gr.update(visible=True)
79
 
80
  except Exception as e:
81
- error_message = f"❌ An error occurred during the orchestrated generation:\n{e}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
82
  logging.error(f"{error_message}\nDetails: {traceback.format_exc()}", exc_info=True)
83
  raise gr.Error(error_message)
84
 
85
 
86
  @log_function_io
87
  def run_seedvr_upscaling(state: dict, seed: int, resolution: int, batch_size: int, fps: int, progress=gr.Progress(track_tqdm=True)) -> tuple:
88
- """Wrapper para o upscale de resolução SeedVR. Esta função permanece a mesma."""
89
  if not state or not state.get("low_res_video"):
90
  raise gr.Error("Error: Please generate a base video in Step 1 before upscaling.")
91
- if not seed_aduc_pipeline:
92
  raise gr.Error("Error: The SeedVR upscaling server is not available.")
93
-
94
  try:
95
  logging.info(f"[UI] Requesting SeedVR upscaling for video: {state.get('low_res_video')}")
96
  def progress_wrapper(p, desc=""): progress(p, desc=desc)
97
-
98
- output_filepath = seed_aduc_pipeline.run_inference(
99
  file_path=state["low_res_video"], seed=int(seed), resolution=int(resolution),
100
  batch_size=int(batch_size), fps=float(fps), progress=progress_wrapper
101
  )
102
-
103
  status_message = f"✅ Upscaling complete!\nSaved to: {output_filepath}"
104
  logging.info(f"[UI] SeedVR upscaling successful. Path: {output_filepath}")
105
  return gr.update(value=output_filepath), gr.update(value=status_message)
@@ -115,50 +139,56 @@ def run_seedvr_upscaling(state: dict, seed: int, resolution: int, batch_size: in
115
  def build_ui():
116
  """Constrói a interface completa do Gradio."""
117
  with gr.Blocks(theme=gr.themes.Soft(primary_hue="indigo")) as demo:
118
- app_state = gr.State(value={"low_res_video": None})
119
  ui_components = {}
120
- gr.Markdown("# ADUC-SDR Video Suite - Orchestrated Workflow", elem_id="main-title")
121
  with gr.Row():
122
  with gr.Column(scale=1): _build_generation_controls(ui_components)
123
  with gr.Column(scale=1):
124
- gr.Markdown("### Etapa 1: Vídeo Base Gerado pelo Orquestrador")
125
  ui_components['low_res_video_output'] = gr.Video(label="O resultado aparecerá aqui", interactive=False)
 
126
  _build_postprod_controls(ui_components)
127
  _register_event_handlers(app_state, ui_components)
128
  return demo
129
 
130
  def _build_generation_controls(ui: dict):
131
- """Constrói os componentes da UI para a Etapa 1: Geração."""
132
  gr.Markdown("### Configurações de Geração")
133
- ui['prompt'] = gr.Textbox(label="Prompt(s) de Geração",
134
- info="Escreva sua história. Cada nova linha será tratada como uma nova cena.",
135
- value="Um leão majestoso caminha pela savana\nEle sobe em uma grande pedra e olha o horizonte",
136
- lines=4)
137
- ui['start_image'] = gr.Image(label="Imagem de Início (Opcional)", type="filepath", sources=["upload"])
138
 
139
  with gr.Accordion("Parâmetros Principais", open=True):
140
  ui['duration'] = gr.Slider(label="Duração Total (s)", value=4, step=1, minimum=1, maximum=30)
141
  with gr.Row():
142
- ui['height'] = gr.Slider(label="Altura", value=432, step=8, minimum=256, maximum=1024)
143
- ui['width'] = gr.Slider(label="Largura", value=768, step=8, minimum=256, maximum=1024)
144
 
145
  with gr.Accordion("Opções Avançadas LTX", open=False):
146
- ui['fp_num_inference_steps'] = gr.Slider(label="Número de Passos", minimum=1, maximum=100, step=1, value=20)
147
- ui['fp_guidance_preset'] = gr.Dropdown(label="Preset de Guiagem", choices=["Padrão (Recomendado)", "Customizado"], value="Padrão (Recomendado)")
148
- with gr.Group(visible=False) as ui['custom_guidance_group']:
149
- gr.Markdown("⚠️ Edite as listas em formato JSON. Ex: `[1.0, 2.5, 3.0]`")
150
- ui['fp_guidance_scale_list'] = gr.Textbox(label="Lista de Guidance Scale", value="[1, 1, 6, 8, 6, 1, 1]")
151
- ui['fp_stg_scale_list'] = gr.Textbox(label="Lista de STG Scale (Movimento)", value="[0, 0, 4, 4, 4, 2, 1]")
152
 
153
- ui['generate_low_btn'] = gr.Button("1. Gerar Vídeo via Orquestrador", variant="primary")
154
 
155
  def _build_postprod_controls(ui: dict):
156
- """Constrói os componentes da UI para a Etapa 2: Pós-Produção (Upscaling)."""
157
  with gr.Group(visible=False) as ui['post_prod_group']:
158
  gr.Markdown("--- \n## Etapa 2: Pós-Produção")
159
  with gr.Tabs():
 
 
 
 
 
 
 
 
160
  with gr.TabItem("✨ Upscaler de Resolução (SeedVR)"):
161
- is_seedvr_available = seed_aduc_pipeline is not None
162
  if not is_seedvr_available:
163
  gr.Markdown("🔴 **AVISO: O serviço SeedVR não está disponível.**")
164
  with gr.Row():
@@ -174,20 +204,22 @@ def _build_postprod_controls(ui: dict):
174
 
175
  def _register_event_handlers(app_state: gr.State, ui: dict):
176
  """Registra todos os manipuladores de eventos do Gradio."""
177
- def toggle_custom_guidance(preset_choice: str) -> gr.update:
178
- return gr.update(visible=(preset_choice == "Customizado"))
179
-
180
- ui['fp_guidance_preset'].change(fn=toggle_custom_guidance, inputs=ui['fp_guidance_preset'], outputs=ui['custom_guidance_group'])
181
 
182
  gen_inputs = [
183
- ui['prompt'], ui['start_image'],
184
  ui['height'], ui['width'], ui['duration'],
185
- ui['fp_guidance_preset'], ui['fp_guidance_scale_list'], ui['fp_stg_scale_list'],
186
- ui['fp_num_inference_steps'],
187
  ]
188
  gen_outputs = [ui['low_res_video_output'], app_state, ui['post_prod_group']]
189
 
190
- ui['generate_low_btn'].click(fn=run_orchestrated_generation, inputs=gen_inputs, outputs=gen_outputs)
 
 
 
 
 
191
 
192
  if 'run_seedvr_btn' in ui and ui['run_seedvr_btn'].interactive:
193
  seedvr_inputs = [app_state, ui['seedvr_seed'], ui['seedvr_resolution'], ui['seedvr_batch_size'], ui['seedvr_fps']]
@@ -197,7 +229,15 @@ def _register_event_handlers(app_state: gr.State, ui: dict):
197
  # ==============================================================================
198
  # --- PONTO DE ENTRADA DA APLICAÇÃO ---
199
  # ==============================================================================
200
-
201
  if __name__ == "__main__":
202
- demo = build_ui()
203
- demo.queue().launch(server_name="0.0.0.0", server_port=7860, debug=True, show_error=True)
 
 
 
 
 
 
 
 
 
 
1
  # FILE: app.py
2
  # DESCRIPTION: Final Gradio web interface for the ADUC-SDR Video Suite.
3
+ # This version is updated to import from the new modular file structure,
4
+ # including the renamed ADUC pipelines and moved managers.
5
 
6
  import gradio as gr
7
  import traceback
8
  import sys
9
  import os
10
  import logging
11
+ from typing import List
12
+ from PIL import Image as PILImage
13
 
14
  # ==============================================================================
15
+ # --- IMPORTAÇÃO DOS SERVIÇOS DE BACKEND E UTILS (CAMINHOS ATUALIZADOS) ---
16
  # ==============================================================================
17
 
18
+ try:
19
+ # Importa o serviço principal do seu novo local e nome
20
+ from api.ltx.ltx_aduc_pipeline import video_generation_service
 
21
 
22
+ # Importa o decorador de logging do seu novo local
23
+ from api.utils.debug_utils import log_function_io
 
 
 
 
 
 
24
 
25
+ # A importação do SeedVR permanece a mesma, mas verificamos sua existência
26
+ from api.seedvr_server import seedvr_server_singleton as seedvr_inference_server
27
+
28
+ logging.info("All backend services and utils imported successfully from new paths.")
29
+
30
+ except ImportError as e:
31
+ def log_function_io(func): return func
32
+ logging.warning(f"Could not import a module. Some services or debug logs may be unavailable. Details: {e}")
33
+ if 'video_generation_service' not in locals():
34
+ logging.critical(f"FATAL: Main LTX service (ltx_aduc_pipeline) failed to import.", exc_info=True)
35
+ sys.exit(1)
36
+ if 'seedvr_inference_server' not in locals():
37
+ seedvr_inference_server = None
38
+ logging.warning("SeedVR server could not be initialized. Upscaling tab will be disabled.")
39
+ except Exception as e:
40
+ logging.critical(f"FATAL ERROR during backend initialization. Details: {e}", exc_info=True)
41
+ sys.exit(1)
42
 
43
  # ==============================================================================
44
  # --- FUNÇÕES WRAPPER (PONTE ENTRE UI E BACKEND) ---
45
  # ==============================================================================
46
 
47
  @log_function_io
48
+ def run_generate_base_video(
49
+ prompt: str, neg_prompt: str, start_img: PILImage.Image,
50
  height: int, width: int, duration: float,
51
+ fp_num_inference_steps: int, fp_skip_initial_steps: int, fp_skip_final_steps: int,
 
52
  progress=gr.Progress(track_tqdm=True)
53
  ) -> tuple:
54
  """
55
+ Wrapper final que prepara os dados da UI e chama o backend com a API simplificada.
56
  """
57
  try:
58
+ prompt_list = [p.strip() for p in prompt.splitlines() if p.strip()]
59
+ if not prompt_list:
60
+ raise gr.Error("O campo de prompt não pode estar vazio.")
61
+ logging.info(f"[UI] Request received with {len(prompt_list)} scene(s).")
62
+
63
+ initial_media_list = []
64
+ if start_img:
65
+ initial_media_list.append((start_img, 0, 1.0))
66
+
67
  ltx_configs = {
68
+ "num_inference_steps": fp_num_inference_steps,
69
+ "skip_initial_inference_steps": fp_skip_initial_steps,
70
+ "skip_final_inference_steps": fp_skip_final_steps,
 
71
  }
72
 
73
+ video_path, tensor_path, final_seed = video_generation_service.generate_low_resolution(
74
+ prompt_list=prompt_list,
75
+ negative_prompt=neg_prompt,
76
+ height=height, width=width, duration=duration,
77
+ initial_media_items=initial_media_list,
78
+ ltx_configs_override=ltx_configs
 
 
 
 
 
79
  )
80
 
81
+ if not video_path: raise RuntimeError("Backend failed to return a valid video path.")
82
+ new_state = {"low_res_video": video_path, "low_res_latents": tensor_path, "used_seed": final_seed}
83
+ logging.info(f"[UI] Base video generation successful. Seed used: {final_seed}, Path: {video_path}")
 
 
 
 
84
  return video_path, new_state, gr.update(visible=True)
85
 
86
  except Exception as e:
87
+ error_message = f"❌ An error occurred during base generation:\n{e}"
88
+ logging.error(f"{error_message}\nDetails: {traceback.format_exc()}", exc_info=True)
89
+ raise gr.Error(error_message)
90
+
91
+ @log_function_io
92
+ def run_ltx_refinement(state: dict, prompt: str, neg_prompt: str, progress=gr.Progress(track_tqdm=True)) -> tuple:
93
+ """Wrapper para o refinamento de textura LTX."""
94
+ if not state or not state.get("low_res_latents"):
95
+ raise gr.Error("Error: Please generate a base video in Step 1 before refining.")
96
+ try:
97
+ logging.info(f"[UI] Requesting LTX refinement for latents: {state.get('low_res_latents')}")
98
+ video_path, tensor_path = video_generation_service.generate_upscale_denoise(
99
+ latents_path=state["low_res_latents"],
100
+ prompt=prompt, negative_prompt=neg_prompt,
101
+ seed=state["used_seed"]
102
+ )
103
+ state["refined_video_ltx"] = video_path
104
+ state["refined_latents_ltx"] = tensor_path
105
+ logging.info(f"[UI] LTX refinement successful. Path: {video_path}")
106
+ return video_path, state
107
+ except Exception as e:
108
+ error_message = f"❌ An error occurred during LTX Refinement:\n{e}"
109
  logging.error(f"{error_message}\nDetails: {traceback.format_exc()}", exc_info=True)
110
  raise gr.Error(error_message)
111
 
112
 
113
  @log_function_io
114
  def run_seedvr_upscaling(state: dict, seed: int, resolution: int, batch_size: int, fps: int, progress=gr.Progress(track_tqdm=True)) -> tuple:
115
+ """Wrapper para o upscale de resolução SeedVR."""
116
  if not state or not state.get("low_res_video"):
117
  raise gr.Error("Error: Please generate a base video in Step 1 before upscaling.")
118
+ if not seedvr_inference_server:
119
  raise gr.Error("Error: The SeedVR upscaling server is not available.")
 
120
  try:
121
  logging.info(f"[UI] Requesting SeedVR upscaling for video: {state.get('low_res_video')}")
122
  def progress_wrapper(p, desc=""): progress(p, desc=desc)
123
+ output_filepath = seedvr_inference_server.run_inference(
 
124
  file_path=state["low_res_video"], seed=int(seed), resolution=int(resolution),
125
  batch_size=int(batch_size), fps=float(fps), progress=progress_wrapper
126
  )
 
127
  status_message = f"✅ Upscaling complete!\nSaved to: {output_filepath}"
128
  logging.info(f"[UI] SeedVR upscaling successful. Path: {output_filepath}")
129
  return gr.update(value=output_filepath), gr.update(value=status_message)
 
139
  def build_ui():
140
  """Constrói a interface completa do Gradio."""
141
  with gr.Blocks(theme=gr.themes.Soft(primary_hue="indigo")) as demo:
142
+ app_state = gr.State(value={"low_res_video": None, "low_res_latents": None, "used_seed": None})
143
  ui_components = {}
144
+ gr.Markdown("# ADUC-SDR Video Suite - LTX & SeedVR Workflow", elem_id="main-title")
145
  with gr.Row():
146
  with gr.Column(scale=1): _build_generation_controls(ui_components)
147
  with gr.Column(scale=1):
148
+ gr.Markdown("### Etapa 1: Vídeo Base Gerado")
149
  ui_components['low_res_video_output'] = gr.Video(label="O resultado aparecerá aqui", interactive=False)
150
+ ui_components['used_seed_display'] = gr.Textbox(label="Seed Utilizada", interactive=False)
151
  _build_postprod_controls(ui_components)
152
  _register_event_handlers(app_state, ui_components)
153
  return demo
154
 
155
  def _build_generation_controls(ui: dict):
156
+ """Constrói os componentes da UI, sem seleção de modo."""
157
  gr.Markdown("### Configurações de Geração")
158
+ ui['prompt'] = gr.Textbox(label="Prompt(s)", info="Para múltiplas cenas (modo narrativo), escreva um prompt por linha.", value="Um leão majestoso caminha pela savana\nEle sobe em uma grande pedra e olha o horizonte", lines=4)
159
+ ui['neg_prompt'] = gr.Textbox(label="Negative Prompt", value="blurry, low quality, bad anatomy, deformed", lines=2)
160
+ ui['start_image'] = gr.Image(label="Imagem de Início (Opcional)", type="pil", sources=["upload"])
 
 
161
 
162
  with gr.Accordion("Parâmetros Principais", open=True):
163
  ui['duration'] = gr.Slider(label="Duração Total (s)", value=4, step=1, minimum=1, maximum=30)
164
  with gr.Row():
165
+ ui['height'] = gr.Slider(label="Height", value=432, step=8, minimum=256, maximum=1024)
166
+ ui['width'] = gr.Slider(label="Width", value=768, step=8, minimum=256, maximum=1024)
167
 
168
  with gr.Accordion("Opções Avançadas LTX", open=False):
169
+ gr.Markdown("#### Configurações de Passos de Inferência")
170
+ gr.Markdown("*Deixe o valor padrão (ex: 20) ou 0 para usar a configuração do `config.yaml`.*")
171
+ ui['fp_num_inference_steps'] = gr.Slider(label="Número de Passos", minimum=0, maximum=100, step=1, value=20, info="Padrão LTX: 20.")
172
+ ui['fp_skip_initial_steps'] = gr.Slider(label="Pular Passos Iniciais", minimum=0, maximum=100, step=1, value=0)
173
+ ui['fp_skip_final_steps'] = gr.Slider(label="Pular Passos Finais", minimum=0, maximum=100, step=1, value=0)
 
174
 
175
+ ui['generate_low_btn'] = gr.Button("1. Gerar Vídeo Base", variant="primary")
176
 
177
  def _build_postprod_controls(ui: dict):
178
+ """Constrói os componentes da UI para a Etapa 2: Pós-Produção."""
179
  with gr.Group(visible=False) as ui['post_prod_group']:
180
  gr.Markdown("--- \n## Etapa 2: Pós-Produção")
181
  with gr.Tabs():
182
+ with gr.TabItem("🚀 Upscaler de Textura (LTX)"):
183
+ with gr.Row():
184
+ with gr.Column(scale=1):
185
+ gr.Markdown("Usa o prompt e a semente originais para refinar o vídeo, adicionando detalhes e texturas de alta qualidade.")
186
+ ui['ltx_refine_btn'] = gr.Button("2. Aplicar Refinamento LTX", variant="primary")
187
+ with gr.Column(scale=1):
188
+ ui['ltx_refined_video_output'] = gr.Video(label="Vídeo com Textura Refinada", interactive=False)
189
+
190
  with gr.TabItem("✨ Upscaler de Resolução (SeedVR)"):
191
+ is_seedvr_available = seedvr_inference_server is not None
192
  if not is_seedvr_available:
193
  gr.Markdown("🔴 **AVISO: O serviço SeedVR não está disponível.**")
194
  with gr.Row():
 
204
 
205
  def _register_event_handlers(app_state: gr.State, ui: dict):
206
  """Registra todos os manipuladores de eventos do Gradio."""
207
+ def update_seed_display(state):
208
+ return state.get("used_seed", "N/A")
 
 
209
 
210
  gen_inputs = [
211
+ ui['prompt'], ui['neg_prompt'], ui['start_image'],
212
  ui['height'], ui['width'], ui['duration'],
213
+ ui['fp_num_inference_steps'], ui['fp_skip_initial_steps'], ui['fp_skip_final_steps'],
 
214
  ]
215
  gen_outputs = [ui['low_res_video_output'], app_state, ui['post_prod_group']]
216
 
217
+ (ui['generate_low_btn'].click(fn=run_generate_base_video, inputs=gen_inputs, outputs=gen_outputs)
218
+ .then(fn=update_seed_display, inputs=[app_state], outputs=[ui['used_seed_display']]))
219
+
220
+ refine_inputs = [app_state, ui['prompt'], ui['neg_prompt']]
221
+ refine_outputs = [ui['ltx_refined_video_output'], app_state]
222
+ ui['ltx_refine_btn'].click(fn=run_ltx_refinement, inputs=refine_inputs, outputs=refine_outputs)
223
 
224
  if 'run_seedvr_btn' in ui and ui['run_seedvr_btn'].interactive:
225
  seedvr_inputs = [app_state, ui['seedvr_seed'], ui['seedvr_resolution'], ui['seedvr_batch_size'], ui['seedvr_fps']]
 
229
  # ==============================================================================
230
  # --- PONTO DE ENTRADA DA APLICAÇÃO ---
231
  # ==============================================================================
 
232
  if __name__ == "__main__":
233
+ log_level = os.environ.get("ADUC_LOG_LEVEL", "INFO").upper()
234
+ logging.basicConfig(level=log_level, format='[%(levelname)s] [%(name)s] %(message)s')
235
+
236
+ print("Building Gradio UI...")
237
+ gradio_app = build_ui()
238
+ print("Launching Gradio app...")
239
+ gradio_app.queue().launch(
240
+ server_name=os.getenv("GRADIO_SERVER_NAME", "0.0.0.0"),
241
+ server_port=int(os.getenv("GRADIO_SERVER_PORT", "7860")),
242
+ show_error=True
243
+ )