|
|
import gradio as gr |
|
|
import subprocess |
|
|
import os |
|
|
import sys |
|
|
import time |
|
|
from threading import Thread |
|
|
from queue import Queue, Empty |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
INSTALLATION_FLAG = ".installation_complete" |
|
|
SEEDVR_REPO_DIR = "SeedVR" |
|
|
|
|
|
def run_subprocess(command, cwd=None): |
|
|
"""Executa um comando de subprocesso e imprime a saída em tempo real.""" |
|
|
print(f"Executando comando: {' '.join(command)}") |
|
|
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, cwd=cwd) |
|
|
while True: |
|
|
output = process.stdout.readline() |
|
|
if output == '' and process.poll() is not None: |
|
|
break |
|
|
if output: |
|
|
print(output.strip()) |
|
|
rc = process.poll() |
|
|
if rc != 0: |
|
|
raise RuntimeError(f"Comando falhou com código de saída {rc}: {' '.join(command)}") |
|
|
|
|
|
def setup_environment(): |
|
|
""" |
|
|
Traduz os comandos do manual do SeedVR para o ambiente do Hugging Face Spaces. |
|
|
1. Clona o repositório. |
|
|
2. Instala dependências especiais. |
|
|
3. Cria um "flag" para não repetir a instalação. |
|
|
""" |
|
|
print("--- Verificando o ambiente de instalação ---") |
|
|
|
|
|
|
|
|
if os.path.exists(INSTALLATION_FLAG): |
|
|
print("Ambiente já configurado. Pulando a instalação.") |
|
|
return |
|
|
|
|
|
print("--- Iniciando configuração pela primeira vez ---") |
|
|
|
|
|
|
|
|
if not os.path.exists(SEEDVR_REPO_DIR): |
|
|
run_subprocess(["git", "clone", "https://github.com/bytedance-seed/SeedVR.git"]) |
|
|
else: |
|
|
print("Repositório SeedVR já existe.") |
|
|
|
|
|
|
|
|
print("Versão do Python já definida pelo Hugging Face Spaces.") |
|
|
|
|
|
|
|
|
print("Dependências do requirements.txt já instaladas.") |
|
|
|
|
|
|
|
|
print("Instalando flash_attn com flags especiais...") |
|
|
|
|
|
flash_attn_command = [ |
|
|
sys.executable, "-m", "pip", "install", |
|
|
"flash_attn==2.5.9.post1", "--no-build-isolation" |
|
|
] |
|
|
run_subprocess(flash_attn_command) |
|
|
|
|
|
print("--- Configuração do ambiente concluída com sucesso! ---") |
|
|
|
|
|
|
|
|
with open(INSTALLATION_FLAG, "w") as f: |
|
|
f.write("OK") |
|
|
|
|
|
|
|
|
setup_environment() |
|
|
|
|
|
|
|
|
|
|
|
from huggingface_hub import snapshot_download |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CKPTS_DIR = os.path.join(SEEDVR_REPO_DIR, "ckpts") |
|
|
if not os.path.exists(os.path.join(CKPTS_DIR, "README.md")): |
|
|
print("Baixando o modelo SeedVR2-3B...") |
|
|
snapshot_download( |
|
|
repo_id="ByteDance-Seed/SeedVR2-3B", |
|
|
local_dir=CKPTS_DIR, |
|
|
local_dir_use_symlinks=False, |
|
|
resume_download=True, |
|
|
allow_patterns=["*.json", "*.safetensors", "*.pth", "*.bin", "*.py", "*.md", "*.txt"], |
|
|
) |
|
|
else: |
|
|
print("Modelo já foi baixado.") |
|
|
|
|
|
def run_inference_app(video_file, seed_num): |
|
|
if video_file is None: |
|
|
return None, "Por favor, envie um arquivo de vídeo." |
|
|
|
|
|
|
|
|
input_folder = "inputs" |
|
|
os.makedirs(input_folder, exist_ok=True) |
|
|
input_video_path = os.path.join(input_folder, os.path.basename(video_file.name)) |
|
|
with open(input_video_path, "wb") as f_out, open(video_file.name, "rb") as f_in: |
|
|
f_out.write(f_in.read()) |
|
|
|
|
|
output_folder = "outputs" |
|
|
os.makedirs(output_folder, exist_ok=True) |
|
|
|
|
|
|
|
|
|
|
|
command = [ |
|
|
"torchrun", "--nproc-per-node=4", |
|
|
"projects/inference_seedvr2_3b.py", |
|
|
"--video_path", f"../{input_folder}", |
|
|
"--output_dir", f"../{output_folder}", |
|
|
"--seed", str(seed_num), |
|
|
"--res_h", "320", |
|
|
"--res_w", "512", |
|
|
"--sp_size", "1" |
|
|
] |
|
|
|
|
|
log_output = "Iniciando a inferência...\n" + ' '.join(command) + "\n\n" |
|
|
|
|
|
try: |
|
|
process = subprocess.Popen( |
|
|
command, |
|
|
cwd=SEEDVR_REPO_DIR, |
|
|
stdout=subprocess.PIPE, |
|
|
stderr=subprocess.STDOUT, |
|
|
text=True, |
|
|
encoding='utf-8' |
|
|
) |
|
|
|
|
|
while True: |
|
|
line = process.stdout.readline() |
|
|
if not line: |
|
|
break |
|
|
log_output += line |
|
|
print(line.strip()) |
|
|
yield None, log_output |
|
|
|
|
|
process.wait() |
|
|
|
|
|
if process.returncode != 0: |
|
|
raise RuntimeError("O script de inferência falhou.") |
|
|
|
|
|
|
|
|
result_files = [os.path.join(output_folder, f) for f in os.listdir(output_folder) if f.endswith('.mp4')] |
|
|
if not result_files: |
|
|
return None, log_output + "\nERRO: Nenhum vídeo foi gerado." |
|
|
|
|
|
return result_files, log_output + "\n\nInferência concluída com sucesso!" |
|
|
|
|
|
except Exception as e: |
|
|
error_message = f"{log_output}\n\nOcorreu um erro: {str(e)}" |
|
|
print(error_message) |
|
|
return None, error_message |
|
|
|
|
|
|
|
|
|
|
|
with gr.Blocks() as demo: |
|
|
gr.Markdown("# 🚀 Automação de Inferência para SeedVR2") |
|
|
gr.Markdown("Envie um vídeo, clique em 'Gerar' e o processo de instalação e inferência será executado.") |
|
|
|
|
|
with gr.Row(): |
|
|
with gr.Column(scale=1): |
|
|
video_input = gr.File(label="Vídeo de Entrada") |
|
|
seed_input = gr.Number(label="Seed", value=42) |
|
|
run_button = gr.Button("Gerar Vídeo", variant="primary") |
|
|
|
|
|
with gr.Column(scale=2): |
|
|
gallery_output = gr.Gallery(label="Vídeo de Saída", show_label=True) |
|
|
log_display = gr.Textbox(label="Logs de Execução", lines=15, interactive=False, autoscroll=True) |
|
|
|
|
|
run_button.click( |
|
|
fn=run_inference_app, |
|
|
inputs=[video_input, seed_input], |
|
|
outputs=[gallery_output, log_display] |
|
|
) |
|
|
|
|
|
demo.launch() |