File size: 3,761 Bytes
eeb0d4a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
03de52f
0731858
eeb0d4a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
dfe8f97
eeb0d4a
0731858
 
 
 
eeb0d4a
0731858
eeb0d4a
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
import gradio as gr
import os, uuid, time
from gradio_client import Client, handle_file
from moviepy.editor import VideoFileClip   # NEW

hf_token   = os.environ.get("TOKEN")
output_dir = "uploads/output"
os.makedirs(output_dir, exist_ok=True)

client = Client("tonyassi/vfs2-cpu", hf_token=hf_token, download_files=output_dir)

# ── helper ───────────────────────────────────────────────────────────
def preprocess_video(path: str, target_fps: int = 12,
                     target_size: int = 800, target_len: int = 4) -> str:
    """
    Returns a path to a temp-file that is
    ≀ target_len seconds, target_fps FPS,
    and resized so the longest side == target_size.
    """
    clip = VideoFileClip(path)

    # 1) trim
    if clip.duration > target_len:
        clip = clip.subclip(0, target_len)

    # 2) resize (longest side)
    w, h = clip.size
    if w >= h:
        clip = clip.resize(width=target_size)
    else:
        clip = clip.resize(height=target_size)

    # 3) FPS
    clip = clip.set_fps(target_fps)

    # 4) write to temp file
    out_path = os.path.join(
        output_dir, f"pre_{uuid.uuid4().hex}.mp4"
    )
    clip.write_videofile(
        out_path,
        codec="libx264",
        audio_codec="aac",
        fps=target_fps,
        verbose=False,
        logger=None
    )
    clip.close()
    return out_path

# ── main generate ────────────────────────────────────────────────────
def generate(input_image, input_video, gender):

    gr.Warning('Skip the line, generate 1-5 minute HD face swap videos at <a href="https://www.face-swap.co/" target="_blank" style="color:#007bff; text-decoration:none;">face-swap.co</a>')

    if (gender=="all"): gender = None
        
    try:
        # β‡’ preprocess video locally
        pre_video = preprocess_video(input_video)

        # β‡’ submit job to remote Space
        job = client.submit(
            input_image=handle_file(input_image),
            input_video={"video": handle_file(pre_video)},
            device='cpu',
            selector='many',
            gender=gender,
            race=None,
            order=None,
            api_name="/predict"
        )

        # wait for completion
        while not job.done():
            print("Waiting for remote job to finish...")
            time.sleep(5)

        if not job.status().success:
            print("Job failed or was cancelled:", job.status())
            return None

        video_path = job.outputs()[0]["video"]
        return video_path

    except Exception as e:
        print("Error occurred:", e)
        return None

# ── Gradio interface (unchanged) ─────────────────────────────────────
demo = gr.Interface(
    fn=generate,
    title="Video Face Swap",
    description="""
    ### [face-swap.co](https://www.face-swap.co/)
    ***Skip the line, generate 1-5 minute HD videos starting at $3.00***

    ---
    
    Swaps the source image face onto the target video. Videos get downsampled to 800 pixels, 4 sec, and 12 fps to cut down render time (~5 minutes). Please ❀️ this Space.
    """,
    inputs=[
        gr.Image(type="filepath", label="Source Image"),
        gr.Video(label="Target Video"),
        gr.Radio(choices=["all", "female", "male"], label="Gender", value="all"),
    ],
    outputs=gr.Video(label="Result"),
    flagging_mode="never",
    examples=[['bella.jpg', 'wizard.mp4', 'all']],
    cache_examples=True,
)

if __name__ == "__main__":
    demo.launch()