CoolFace
Datasetpublic

mrdarkbr/wan22-code-backup

sourceHugging Faceupdated 1mo agoView on Hugging Face
0likes56downloads
maskvid_client.py135 linesDownload Raw Back to root
1import os2import sys3import argparse4import subprocess5import time6from pathlib import Path7 8 9def clean_path(p: str) -> str:10    """Remove aspas e espaços extras de caminhos arrastados no terminal do Windows."""11    if not p:12        return ""13    p = p.strip()14    if (p.startswith('"') and p.endswith('"')) or (p.startswith("'") and p.endswith("'")):15        p = p[1:-1].strip()16    return os.path.abspath(p)17 18 19def main():20    parser = argparse.ArgumentParser(description="Cliente Face Swap com MaskVidExperiments no Modal")21    parser.add_argument("--source", "-s", type=str, help="Caminho da Foto 1 (rosto de origem)")22    parser.add_argument("--target", "-t", type=str, help="Caminho do Vídeo 2 (vídeo de destino)")23    parser.add_argument("--output", "-o", type=str, default="", help="Caminho do arquivo de saída .mp4")24    parser.add_argument("--crop-scale", type=float, default=2.2, help="Escala de enquadramento do MaskVid (padrão: 2.2)")25    parser.add_argument("--mp", "--megapixels", type=float, default=1.0, help="Resolução alvo em Megapixels para o crop facial (padrão: 1.0 MP)")26    parser.add_argument("--no-enhance", action="store_true", help="Desativa o restaurador facial GFPGAN HD")27    parser.add_argument("--enhance-weight", type=float, default=0.90, help="Força do aprimoramento facial HD (0.0 a 1.0, padrão: 0.90)")28    29    args = parser.parse_args()30 31    source_path = clean_path(args.source) if args.source else ""32    target_path = clean_path(args.target) if args.target else ""33    enhance = not args.no_enhance34    enhance_weight = args.enhance_weight35    megapixels = args.mp36 37    print("=" * 65)38    print("      🎭 MASKVID EXPERIMENTS - FACE SWAP EM VÍDEO (MODAL)")39    print("=" * 65)40    print()41 42    # Se não passou foto por argumento, solicita interativamente43    while not source_path or not os.path.exists(source_path):44        if source_path and not os.path.exists(source_path):45            print(f"❌ Arquivo não encontrado: {source_path}")46        print("📌 [1/2] Arraste e solte aqui a FOTO 1 (Rosto de Origem):")47        try:48            source_path = clean_path(input("👉 Foto 1: "))49        except KeyboardInterrupt:50            print("\nOperação cancelada.")51            sys.exit(0)52 53    # Se não passou vídeo por argumento, solicita interativamente54    while not target_path or not os.path.exists(target_path):55        if target_path and not os.path.exists(target_path):56            print(f"❌ Arquivo não encontrado: {target_path}")57        print("\n📌 [2/2] Arraste e solte aqui o VÍDEO 2 (Vídeo de Destino):")58        try:59            target_path = clean_path(input("👉 Vídeo 2: "))60        except KeyboardInterrupt:61            print("\nOperação cancelada.")62            sys.exit(0)63 64    # Auto-correção se o usuário inverteu os arquivos (ex: passou vídeo na Foto 1 e imagem no Vídeo 2)65    vid_exts = {".mp4", ".mov", ".avi", ".mkv", ".webm", ".flv", ".wmv"}66    img_exts = {".jpg", ".jpeg", ".png", ".webp", ".bmp", ".jfif"}67    src_ext = Path(source_path).suffix.lower()68    tgt_ext = Path(target_path).suffix.lower()69 70    if src_ext in vid_exts and tgt_ext in img_exts:71        print("\n💡 [Info] Detectado que a Foto 1 é um vídeo e o Vídeo 2 é uma foto.")72        print("🔄 Invertendo automaticamente para a ordem correta!")73        source_path, target_path = target_path, source_path74 75    # Define saída76    if not args.output:77        timestamp = time.strftime("%Y%m%d_%H%M%S")78        target_name = Path(target_path).stem79        output_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "geradas")80        os.makedirs(output_dir, exist_ok=True)81        output_path = os.path.join(output_dir, f"faceswap_{target_name}_{timestamp}.mp4")82    else:83        output_path = clean_path(args.output)84        os.makedirs(os.path.dirname(os.path.abspath(output_path)), exist_ok=True)85 86    print()87    print("-" * 65)88    print(f"📸 Foto 1 (Origem) : {source_path}")89    print(f"🎥 Vídeo 2 (Alvo)   : {target_path}")90    print(f"💾 Saída           : {output_path}")91    print("-" * 65)92    print("\n⏳ Enviando para a nuvem do Modal e processando...")93    print("   (O primeiro start pode demorar 1-2 minutos para inicializar a GPU)\n")94 95    modal_script = os.path.join(os.path.dirname(os.path.abspath(__file__)), "maskvid_modal.py")96    97    cmd = [98        sys.executable, "-m", "modal", "run", modal_script,99        "--source", source_path,100        "--target", target_path,101        "--output", output_path,102        "--enhance-weight", str(enhance_weight),103        "--crop-scale", str(args.crop_scale),104        "--megapixels", str(megapixels),105    ]106    if not enhance:107        cmd.extend(["--no-enhance"])108 109    start_time = time.time()110    try:111        proc = subprocess.run(cmd, check=True)112        elapsed = time.time() - start_time113        print()114        print("=" * 65)115        print(f"🎉 SUCESSO! Vídeo gerado em {elapsed:.1f} segundos.")116        print(f"📁 Local: {output_path}")117        print("=" * 65)118 119        # Abre o vídeo gerado automaticamente no Windows120        if os.path.exists(output_path):121            try:122                os.startfile(output_path)123            except Exception:124                pass125    except subprocess.CalledProcessError as e:126        print(f"\n❌ Erro na execução do Modal (Código de saída: {e.returncode}).")127        sys.exit(e.returncode)128    except Exception as e:129        print(f"\n❌ Ocorreu um erro: {e}")130        sys.exit(1)131 132 133if __name__ == "__main__":134    main()135