EuuIia commited on
Commit
579a3a7
·
verified ·
1 Parent(s): ed88963

Update app_seedvr.py

Browse files
Files changed (1) hide show
  1. app_seedvr.py +136 -74
app_seedvr.py CHANGED
@@ -1,11 +1,14 @@
1
  #!/usr/bin/env python3
2
  """
3
- SeedVR UI (Gradio) CLI torchrun
4
-
5
- - Upload único: vídeo (.mp4) ou imagem (.png/.jpg/.jpeg/.webp).
6
- - Parâmetros: seed, res_h, res_w, sp_size.
7
- - Executa via torchrun com NUM_GPUS (do ambiente).
8
- - Exibe vídeo se a entrada for vídeo; imagem se for imagem.
 
 
 
9
  """
10
 
11
  import os
@@ -15,24 +18,37 @@ from typing import Optional
15
 
16
  import gradio as gr
17
 
18
- from services.seed_server import SeedVRServer
 
 
 
 
 
 
19
 
20
- # Instância única do servidor (clona repo, baixa modelo, cria symlink)
21
  server = SeedVRServer()
22
 
23
- # Paths padrão (para allowed_paths e debug)
24
  OUTPUT_ROOT = Path(os.getenv("OUTPUT_ROOT", "/app/outputs"))
25
- CKPTS_ROOT = Path(os.getenv("CKPTS_ROOT", "/app/ckpts/SeedVR2-3B"))
26
 
27
  def _is_video(path: str) -> bool:
 
 
 
28
  mime, _ = mimetypes.guess_type(path)
29
- return (mime or "").startswith("video") or str(path).lower().endswith(".mp4")
 
 
30
 
31
  def _is_image(path: str) -> bool:
 
 
 
32
  mime, _ = mimetypes.guess_type(path)
33
- if mime and mime.startswith("image"):
34
- return True
35
- return str(path).lower().endswith((".png", ".jpg", ".jpeg", ".webp"))
36
 
37
  def ui_infer(
38
  input_path: Optional[str],
@@ -40,78 +56,124 @@ def ui_infer(
40
  res_h: int,
41
  res_w: int,
42
  sp_size: int,
 
 
43
  ):
 
 
 
 
44
  if not input_path or not Path(input_path).exists():
45
- gr.Warning("Arquivo de entrada ausente ou inválido.")
46
- return None, None
47
-
48
- is_vid = _is_video(input_path)
49
- is_img = _is_image(input_path)
50
- if not (is_vid or is_img):
51
- gr.Warning("Tipo de arquivo não suportado. Envie .mp4, .png, .jpg, .jpeg ou .webp.")
52
- return None, None
53
 
54
  try:
55
- video_out, image_out, _ = server.run_inference(
56
- file_path=input_path,
 
 
 
57
  seed=int(seed),
58
- res_h=int(res_h),
59
- res_w=int(res_w),
60
- sp_size=int(sp_size),
 
61
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
  except Exception as e:
63
- gr.Warning(f"Erro na inferência: {e}")
64
- return None, None
65
-
66
- if is_vid:
67
- if video_out and Path(video_out).exists():
68
- return None, video_out
69
- if image_out and Path(image_out).exists():
70
- return image_out, None
71
- gr.Warning("Nenhum resultado encontrado.")
72
- return None, None
73
- else:
74
- if image_out and Path(image_out).exists():
75
- return image_out, None
76
- if video_out and Path(video_out).exists():
77
- return None, video_out
78
- gr.Warning("Nenhum resultado encontrado.")
79
- return None, None
80
-
81
- with gr.Blocks(title="SeedVR (CLI torchrun)") as demo:
82
- gr.Markdown(
83
- "\n".join([
84
- "# SeedVR — Restauração (CLI torchrun)",
85
- "- Envie um vídeo (.mp4) ou uma imagem (.png/.jpg/.jpeg/.webp).",
86
- "- A execução utiliza torchrun com múltiplas GPUs.",
87
- ])
88
  )
89
-
90
- with gr.Row():
91
- inp = gr.File(label="Entrada (vídeo .mp4 ou imagem)", type="filepath")
92
-
93
  with gr.Row():
94
- seed = gr.Number(label="Seed", value=int(os.getenv("SEED", "42")), precision=0)
95
- res_h = gr.Number(label="Altura (res_h)", value=int(os.getenv("RES_H", "720")), precision=0)
96
- res_w = gr.Number(label="Largura (res_w)", value=int(os.getenv("RES_W", "1280")), precision=0)
97
- sp_size = gr.Number(label="sp_size", value=int(os.getenv("SP_SIZE", "4")), precision=0)
98
-
99
- run = gr.Button("Restaurar", variant="primary")
100
-
101
- out_image = gr.Image(label="Resultado (imagem)")
102
- out_video = gr.Video(label="Resultado (vídeo)")
103
-
104
- run.click(
105
- ui_infer,
106
- inputs=[inp, seed, res_h, res_w, sp_size],
107
- outputs=[out_image, out_video],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
108
  )
 
 
 
 
 
 
109
 
 
110
  if __name__ == "__main__":
111
  demo.launch(
112
  server_name=os.getenv("GRADIO_SERVER_NAME", "0.0.0.0"),
113
- server_port=int(os.getenv("GRADIO_SERVER_PORT", os.getenv("PORT", "7860"))),
114
- allowed_paths=[str(OUTPUT_ROOT), str(CKPTS_ROOT)],
115
  show_error=True,
116
- )
117
-
 
1
  #!/usr/bin/env python3
2
  """
3
+ SeedVR UI (Gradio) - Interface de Usuário para Restauração de Mídia
4
+
5
+ - Permite o upload de um único arquivo de vídeo (.mp4) ou imagem.
6
+ - Oferece controle sobre parâmetros de geração como seed, resolução,
7
+ paralelismo e FPS de saída para vídeos.
8
+ - Delega a execução da inferência para a classe `SeedVRServer`, que gerencia
9
+ o ambiente e a chamada ao `torchrun`.
10
+ - Possui uma lógica de retorno robusta para exibir o resultado correto (imagem ou vídeo)
11
+ ou notificar o usuário se nenhum resultado for encontrado.
12
  """
13
 
14
  import os
 
18
 
19
  import gradio as gr
20
 
21
+ # Importa a classe do servidor que gerencia a lógica de backend.
22
+ # A inicialização do servidor (download de modelos, etc.) acontece aqui.
23
+ try:
24
+ from services.seedvr_server import SeedVRServer
25
+ except ImportError:
26
+ print("ERRO FATAL: Não foi possível importar o SeedVRServer. Verifique o caminho em services/seed_server.py")
27
+ raise
28
 
29
+ # Cria uma instância única e persistente do servidor.
30
  server = SeedVRServer()
31
 
32
+ # Define o caminho de saída para referência, caso seja necessário.
33
  OUTPUT_ROOT = Path(os.getenv("OUTPUT_ROOT", "/app/outputs"))
34
+
35
 
36
  def _is_video(path: str) -> bool:
37
+ """Verifica se um caminho de arquivo corresponde a um tipo de vídeo."""
38
+ if not path:
39
+ return False
40
  mime, _ = mimetypes.guess_type(path)
41
+ # Verifica tanto o MIME type quanto a extensão do arquivo para maior robustez.
42
+ return (mime or "").startswith("video") or path.lower().endswith((".mp4", ".mov", ".avi", ".mkv"))
43
+
44
 
45
  def _is_image(path: str) -> bool:
46
+ """Verifica se um caminho de arquivo corresponde a um tipo de imagem."""
47
+ if not path:
48
+ return False
49
  mime, _ = mimetypes.guess_type(path)
50
+ return (mime or "").startswith("image") or path.lower().endswith((".png", ".jpg", ".jpeg", ".webp"))
51
+
 
52
 
53
  def ui_infer(
54
  input_path: Optional[str],
 
56
  res_h: int,
57
  res_w: int,
58
  sp_size: int,
59
+ fps: float,
60
+ progress=gr.Progress(track_tqdm=True)
61
  ):
62
+ """
63
+ Função principal de callback do Gradio. Acionada pelo botão "Restaurar".
64
+ """
65
+ progress(0.1, desc="Validando entradas...")
66
  if not input_path or not Path(input_path).exists():
67
+ gr.Warning("Arquivo de entrada ausente ou inválido. Por favor, faça o upload de um vídeo ou imagem.")
68
+ return None, None, None # Retorna None para todas as saídas
 
 
 
 
 
 
69
 
70
  try:
71
+ progress(0.4, desc="Enviando tarefa para o backend. A inferência pode levar vários minutos...")
72
+
73
+ # Chama o método do servidor, passando todos os parâmetros da UI.
74
+ video_out, image_out, out_dir = server.run_inference(
75
+ filepath=input_path,
76
  seed=int(seed),
77
+ resh=int(res_h),
78
+ resw=int(res_w),
79
+ spsize=int(sp_size),
80
+ fps=float(fps) if fps and fps > 0 else None, # Passa None se o campo for 0 ou vazio
81
  )
82
+
83
+ progress(0.9, desc="Inferência concluída. Processando resultados...")
84
+
85
+ # Lógica de retorno robusta
86
+ final_image = None
87
+ final_video = None
88
+ result_file_for_download = None
89
+
90
+ is_video_input = _is_video(input_path)
91
+
92
+ if is_video_input:
93
+ # Se a entrada foi um vídeo, a saída principal esperada é um vídeo.
94
+ if video_out:
95
+ final_video = video_out
96
+ result_file_for_download = video_out
97
+ elif image_out: # Fallback
98
+ gr.Info("A inferência de vídeo resultou em uma única imagem.")
99
+ final_image = image_out
100
+ result_file_for_download = image_out
101
+ else: # A entrada foi uma imagem
102
+ # Se a entrada foi uma imagem, a saída principal esperada é uma imagem.
103
+ if image_out:
104
+ final_image = image_out
105
+ result_file_for_download = image_out
106
+ elif video_out: # Fallback
107
+ gr.Info("A inferência de imagem resultou em um vídeo.")
108
+ final_video = video_out
109
+ result_file_for_download = video_out
110
+
111
+ if not result_file_for_download:
112
+ gr.Warning("A inferência foi concluída, mas nenhum arquivo de mídia de saída foi encontrado no diretório de resultados.")
113
+
114
+ return final_image, final_video, result_file_for_download
115
+
116
  except Exception as e:
117
+ print(f"[UI ERROR] A inferência falhou: {e}")
118
+ # Exibe uma notificação de erro clara na interface do Gradio.
119
+ gr.Error(f"Erro na Inferência: {e}")
120
+ return None, None, None
121
+
122
+
123
+ # --- Construção da Interface Gráfica com Gradio ---
124
+ with gr.Blocks(title="SeedVR (Aduc-SDR)", theme=gr.themes.Soft()) as demo:
125
+ gr.HTML(
126
+ """
127
+ <div style='text-align:center; margin-bottom: 20px;'>
128
+ <h1>SeedVR - Restauração de Imagem e Vídeo</h1>
129
+ <p>Implementação com backend Aduc-SDR</p>
130
+ </div>
131
+ """
 
 
 
 
 
 
 
 
 
 
132
  )
133
+
 
 
 
134
  with gr.Row():
135
+ with gr.Column(scale=1):
136
+ inp = gr.File(label="Arquivo de Entrada (Vídeo ou Imagem)", type="filepath")
137
+
138
+ with gr.Accordion("Parâmetros de Geração", open=True):
139
+ with gr.Row():
140
+ seed = gr.Number(label="Seed", value=42, precision=0)
141
+ fps_out = gr.Number(label="FPS de Saída", value=24, precision=0, info="Apenas para vídeos.")
142
+
143
+ with gr.Row():
144
+ res_h = gr.Number(label="Altura (Height)", value=720, precision=0)
145
+ res_w = gr.Number(label="Largura (Width)", value=1280, precision=0)
146
+
147
+ sp_size = gr.Slider(label="Paralelismo de Sequência (sp_size)", minimum=1, maximum=160, step=4, value=4, info="Para vídeos em multi-GPU. Use 1 para imagens.")
148
+
149
+ run_button = gr.Button("Restaurar Mídia", variant="primary")
150
+
151
+ with gr.Column(scale=2):
152
+ gr.Markdown("### Resultado")
153
+ out_image = gr.Image(label="Resultado (Imagem)", show_download_button=True)
154
+ out_video = gr.Video(label="Resultado (Vídeo)")
155
+ # Componente de arquivo para download, pode ser visível ou não.
156
+ # Deixá-lo visível pode ser uma boa alternativa se a pré-visualização falhar.
157
+ out_download = gr.File(label="Baixar Resultado")
158
+
159
+ # Define a ação do botão
160
+ run_button.click(
161
+ fn=ui_infer,
162
+ inputs=[inp, seed, res_h, res_w, sp_size, fps_out],
163
+ outputs=[out_image, out_video, out_download],
164
  )
165
+
166
+ gr.Markdown("---")
167
+ gr.Markdown("### Exemplos")
168
+ # Nota: Exemplos precisam de arquivos presentes no contêiner para funcionar.
169
+ # Adicione os arquivos de exemplo ao seu Dockerfile se desejar usá-los.
170
+ # gr.Examples(...)
171
 
172
+ # --- Ponto de Entrada da Aplicação ---
173
  if __name__ == "__main__":
174
  demo.launch(
175
  server_name=os.getenv("GRADIO_SERVER_NAME", "0.0.0.0"),
176
+ server_port=int(os.getenv("GRADIO_SERVER_PORT", "7860")),
177
+ allowed_paths=[str(OUTPUT_ROOT), str(os.getenv("INPUT_ROOT", "/app/inputs"))],
178
  show_error=True,
179
+ )