EuuIia commited on
Commit
3e978e1
·
verified ·
1 Parent(s): 1c3867e

Update app_seedvr.py

Browse files
Files changed (1) hide show
  1. app_seedvr.py +76 -111
app_seedvr.py CHANGED
@@ -1,145 +1,120 @@
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
15
- import mimetypes
16
  from pathlib import Path
17
  from typing import Optional
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 api.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],
55
- seed: int,
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
  file_path=input_path,
76
  seed=int(seed),
77
  res_h=int(res_h),
78
  res_w=int(res_w),
79
  sp_size=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)
@@ -150,30 +125,20 @@ with gr.Blocks(title="SeedVR (Aduc-SDR)", theme=gr.themes.Soft()) as demo:
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
  )
 
1
+ # app_seedvr.py
 
 
 
 
 
 
 
 
 
 
 
2
 
3
  import os
 
4
  from pathlib import Path
5
  from typing import Optional
 
6
  import gradio as gr
7
+ import cv2
8
 
 
 
9
  try:
10
+ # Importa a classe de servidor que agora é uma biblioteca local
11
  from api.seedvr_server import SeedVRServer
12
+ except ImportError as e:
13
+ print(f"ERRO FATAL: Não foi possível importar o SeedVRServer. Detalhes: {e}")
14
+ # Se a importação falhar, a aplicação não pode continuar.
15
  raise
16
 
17
+ # Cria uma instância única do servidor. A inicialização (clonar repo, baixar modelos) acontece aqui.
18
  server = SeedVRServer()
19
 
 
 
 
 
20
  def _is_video(path: str) -> bool:
21
  """Verifica se um caminho de arquivo corresponde a um tipo de vídeo."""
22
+ if not path: return False
23
+ import mimetypes
 
 
 
 
 
 
 
 
 
24
  mime, _ = mimetypes.guess_type(path)
25
+ return (mime or "").startswith("video")
26
 
27
+ def _extract_first_frame(video_path: str) -> Optional[str]:
28
+ """Extrai o primeiro frame de um vídeo e o salva como uma imagem JPG."""
29
+ if not video_path or not os.path.exists(video_path): return None
30
+ try:
31
+ vid_cap = cv2.VideoCapture(video_path)
32
+ if not vid_cap.isOpened(): return None
33
+ success, image = vid_cap.read()
34
+ vid_cap.release()
35
+ if not success: return None
36
+
37
+ # Salva o frame no mesmo diretório do vídeo, com extensão .jpg
38
+ image_path = Path(video_path).with_suffix(".jpg")
39
+ cv2.imwrite(str(image_path), image)
40
+ return str(image_path)
41
+ except Exception as e:
42
+ print(f"Erro ao extrair o primeiro frame: {e}")
43
+ return None
44
 
45
  def ui_infer(
46
  input_path: Optional[str],
47
+ seed: int, res_h: int, res_w: int,
48
+ sp_size: int, fps: float,
 
 
 
49
  progress=gr.Progress(track_tqdm=True)
50
  ):
51
  """
52
+ Função de callback principal do Gradio. Agora chama a lógica de inferência diretamente.
53
  """
54
+ if not input_path:
55
+ gr.Warning("Por favor, faça o upload de um arquivo.")
56
+ return None, None, None
 
57
 
58
+ was_input_video = _is_video(input_path)
59
+
60
  try:
61
+ # Desabilita o botão enquanto processa
62
+ yield gr.update(interactive=False, value="Processando..."), None, None, None
63
+
64
+ # Chama o método direto do servidor, passando o objeto de progresso do Gradio
65
+ video_result_path = server.run_inference_direct(
66
  file_path=input_path,
67
  seed=int(seed),
68
  res_h=int(res_h),
69
  res_w=int(res_w),
70
  sp_size=int(sp_size),
71
+ fps=float(fps) if fps and fps > 0 else None,
72
+ progress=progress,
73
  )
74
 
75
+ progress(1.0, desc="Concluído!")
76
+
77
+ final_image, final_video = None, None
78
+ if was_input_video:
79
+ final_video = video_result_path
80
+ else: # Se a entrada foi uma imagem
81
+ final_image = _extract_first_frame(video_result_path)
82
+ final_video = video_result_path
83
+
84
+ # Retorna o resultado e reabilita o botão
85
+ yield (
86
+ gr.update(interactive=True, value="Restaurar Mídia"),
87
+ gr.update(value=final_image, visible=final_image is not None),
88
+ gr.update(value=final_video, visible=final_video is not None),
89
+ gr.update(value=video_result_path, visible=video_result_path is not None)
90
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
 
92
  except Exception as e:
93
+ error_message = f"A inferência falhou: {e}"
94
+ gr.Error(error_message)
95
+ print(error_message)
96
+ import traceback
97
+ traceback.print_exc()
98
+ # Limpa os resultados e reabilita o botão em caso de erro
99
+ yield gr.update(interactive=True, value="Restaurar Mídia"), None, None, None
100
+
101
+ # --- Construção da Interface Gráfica ---
102
  with gr.Blocks(title="SeedVR (Aduc-SDR)", theme=gr.themes.Soft()) as demo:
103
+ gr.HTML("""
 
104
  <div style='text-align:center; margin-bottom: 20px;'>
105
  <h1>SeedVR - Restauração de Imagem e Vídeo</h1>
106
  <p>Implementação com backend Aduc-SDR</p>
107
  </div>
108
+ """)
 
109
 
110
  with gr.Row():
111
  with gr.Column(scale=1):
112
+ inp = gr.File(label="Arquivo de Entrada (Vídeo .mp4 ou Imagem)", type="filepath")
113
 
114
  with gr.Accordion("Parâmetros de Geração", open=True):
115
  with gr.Row():
116
  seed = gr.Number(label="Seed", value=42, precision=0)
117
+ fps_out = gr.Number(label="FPS de Saída (para Vídeos)", value=24, precision=0, info="0 para usar o FPS original.")
 
118
  with gr.Row():
119
  res_h = gr.Number(label="Altura (Height)", value=720, precision=0)
120
  res_w = gr.Number(label="Largura (Width)", value=1280, precision=0)
 
125
 
126
  with gr.Column(scale=2):
127
  gr.Markdown("### Resultado")
128
+ out_image = gr.Image(label="Resultado (Imagem)", show_download_button=True, type="filepath", visible=True)
129
  out_video = gr.Video(label="Resultado (Vídeo)")
130
+ out_download = gr.File(label="Baixar Resultado (Vídeo)")
 
 
131
 
132
+ # A função click agora é um gerador.
133
  run_button.click(
134
  fn=ui_infer,
135
  inputs=[inp, seed, res_h, res_w, sp_size, fps_out],
136
+ outputs=[run_button, out_image, out_video, out_download],
137
  )
 
 
 
 
 
 
138
 
 
139
  if __name__ == "__main__":
140
  demo.launch(
141
  server_name=os.getenv("GRADIO_SERVER_NAME", "0.0.0.0"),
142
  server_port=int(os.getenv("GRADIO_SERVER_PORT", "7860")),
143
+ show_error=True
 
144
  )