video-face-swap / app.py
tonyassi's picture
Update app.py
03de52f verified
raw
history blame
3.76 kB
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()