oznr126/echomimic-v2
0
1import os2import random3from pathlib import Path4import numpy as np5import torch6 7is_shared_ui = True if "fffiloni/echomimic-v2" in os.environ['SPACE_ID'] else False8is_gpu_associated = torch.cuda.is_available()9 10 11from diffusers import AutoencoderKL, DDIMScheduler12from PIL import Image13from src.models.unet_2d_condition import UNet2DConditionModel14from src.models.unet_3d_emo import EMOUNet3DConditionModel15from src.models.whisper.audio2feature import load_audio_model16from src.pipelines.pipeline_echomimicv2 import EchoMimicV2Pipeline17from src.utils.util import save_videos_grid18from src.models.pose_encoder import PoseEncoder19from src.utils.dwpose_util import draw_pose_select_v220from moviepy.editor import VideoFileClip, AudioFileClip21 22import gradio as gr23from datetime import datetime24from torchao.quantization import quantize_, int8_weight_only25import gc26 27import tempfile28from pydub import AudioSegment29 30def cut_audio_to_5_seconds(audio_path):31 try:32 # Load the audio file33 audio = AudioSegment.from_file(audio_path)34 35 # Trim to a maximum of 5 seconds (5000 milliseconds)36 trimmed_audio = audio[:5000]37 38 # Create a temporary directory39 temp_dir = tempfile.mkdtemp()40 output_path = os.path.join(temp_dir, "trimmed_audio.wav")41 42 # Export the trimmed audio43 trimmed_audio.export(output_path, format="wav")44 45 return output_path46 except Exception as e:47 return f"An error occurred while trying to trim audio: {str(e)}"48 49import requests50import tarfile51 52def download_and_setup_ffmpeg():53 url = "https://www.johnvansickle.com/ffmpeg/old-releases/ffmpeg-4.4-amd64-static.tar.xz"54 download_path = "ffmpeg-4.4-amd64-static.tar.xz"55 extract_dir = "ffmpeg-4.4-amd64-static"56 57 try:58 # Download the file59 response = requests.get(url, stream=True)60 response.raise_for_status() # Check for HTTP request errors61 with open(download_path, "wb") as file:62 for chunk in response.iter_content(chunk_size=8192):63 file.write(chunk)64 65 # Extract the tar.xz file66 with tarfile.open(download_path, "r:xz") as tar:67 tar.extractall(path=extract_dir)68 69 # Set the FFMPEG_PATH environment variable70 ffmpeg_binary_path = os.path.join(extract_dir, "ffmpeg-4.4-amd64-static", "ffmpeg")71 os.environ["FFMPEG_PATH"] = ffmpeg_binary_path72 73 return f"FFmpeg downloaded and setup successfully! Path: {ffmpeg_binary_path}"74 except Exception as e:75 return f"An error occurred: {str(e)}"76 77download_and_setup_ffmpeg()78 79from huggingface_hub import snapshot_download80 81# Create the main "pretrained_weights" folder82os.makedirs("pretrained_weights", exist_ok=True)83 84# List of subdirectories to create inside "pretrained_weights"85subfolders = [86 "sd-vae-ft-mse",87 "sd-image-variations-diffusers",88 "audio_processor"89]90 91# Create each subdirectory92for subfolder in subfolders:93 os.makedirs(os.path.join("pretrained_weights", subfolder), exist_ok=True)94 95snapshot_download(96 repo_id = "BadToBest/EchoMimicV2",97 local_dir="./pretrained_weights"98)99snapshot_download(100 repo_id = "stabilityai/sd-vae-ft-mse",101 local_dir="./pretrained_weights/sd-vae-ft-mse"102)103snapshot_download(104 repo_id = "lambdalabs/sd-image-variations-diffusers",105 local_dir="./pretrained_weights/sd-image-variations-diffusers"106)107 108is_shared_ui = True if "fffiloni/echomimic-v2" in os.environ['SPACE_ID'] else False109 110# Download and place the Whisper model in the "audio_processor" folder111def download_whisper_model():112 url = "https://openaipublic.azureedge.net/main/whisper/models/65147644a518d12f04e32d6f3b26facc3f8dd46e5390956a9424a650c0ce22b9/tiny.pt"113 save_path = os.path.join("pretrained_weights", "audio_processor", "tiny.pt")114 115 try:116 # Download the file117 response = requests.get(url, stream=True)118 response.raise_for_status() # Check for HTTP request errors119 with open(save_path, "wb") as file:120 for chunk in response.iter_content(chunk_size=8192):121 file.write(chunk)122 print(f"Whisper model downloaded and saved to {save_path}")123 except Exception as e:124 print(f"An error occurred while downloading the model: {str(e)}")125 126 127if torch.cuda.is_available():128 device = "cuda"129 130 # Download the Whisper model131 download_whisper_model()132 133 total_vram_in_gb = torch.cuda.get_device_properties(0).total_memory / 1073741824134 print(f'\033[32mCUDA版本:{torch.version.cuda}\033[0m')135 print(f'\033[32mPytorch版本:{torch.__version__}\033[0m')136 print(f'\033[32m显卡型号:{torch.cuda.get_device_name()}\033[0m')137 print(f'\033[32m显存大小:{total_vram_in_gb:.2f}GB\033[0m')138 print(f'\033[32m精度:float16\033[0m')139 140 dtype = torch.float16141 142else:143 print("cuda not available, using cpu")144 device = "cpu"145 146ffmpeg_path = os.getenv('FFMPEG_PATH')147if ffmpeg_path is None:148 print("please download ffmpeg-static and export to FFMPEG_PATH. \nFor example: export FFMPEG_PATH=./ffmpeg-4.4-amd64-static")149elif ffmpeg_path not in os.getenv('PATH'):150 print("add ffmpeg to path")151 os.environ["PATH"] = f"{ffmpeg_path}:{os.environ['PATH']}"152 153 154def generate(image_input, audio_input, pose_input, width, height, length, steps, sample_rate, cfg, fps, context_frames, context_overlap, quantization_input, seed, progress=gr.Progress(track_tqdm=True)):155 gc.collect()156 torch.cuda.empty_cache()157 torch.cuda.ipc_collect()158 timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")159 save_dir = Path("outputs")160 save_dir.mkdir(exist_ok=True, parents=True)161 162 ############# model_init started #############163 ## vae init164 vae = AutoencoderKL.from_pretrained("./pretrained_weights/sd-vae-ft-mse").to(device, dtype=dtype)165 if quantization_input:166 quantize_(vae, int8_weight_only())167 print("Use int8 quantization.")168 169 ## reference net init170 reference_unet = UNet2DConditionModel.from_pretrained("./pretrained_weights/sd-image-variations-diffusers", subfolder="unet", use_safetensors=False).to(dtype=dtype, device=device)171 reference_unet.load_state_dict(torch.load("./pretrained_weights/reference_unet.pth", weights_only=True))172 if quantization_input:173 quantize_(reference_unet, int8_weight_only())174 175 ## denoising net init176 if os.path.exists("./pretrained_weights/motion_module.pth"):177 print('using motion module')178 else:179 exit("motion module not found")180 ### stage1 + stage2181 denoising_unet = EMOUNet3DConditionModel.from_pretrained_2d(182 "./pretrained_weights/sd-image-variations-diffusers",183 "./pretrained_weights/motion_module.pth",184 subfolder="unet",185 unet_additional_kwargs = {186 "use_inflated_groupnorm": True,187 "unet_use_cross_frame_attention": False,188 "unet_use_temporal_attention": False,189 "use_motion_module": True,190 "cross_attention_dim": 384,191 "motion_module_resolutions": [192 1,193 2,194 4,195 8196 ],197 "motion_module_mid_block": True ,198 "motion_module_decoder_only": False,199 "motion_module_type": "Vanilla",200 "motion_module_kwargs":{201 "num_attention_heads": 8,202 "num_transformer_block": 1,203 "attention_block_types": [204 'Temporal_Self',205 'Temporal_Self'206 ],207 "temporal_position_encoding": True,208 "temporal_position_encoding_max_len": 32,209 "temporal_attention_dim_div": 1,210 }211 },212 ).to(dtype=dtype, device=device)213 denoising_unet.load_state_dict(torch.load("./pretrained_weights/denoising_unet.pth", weights_only=True),strict=False)214 215 # pose net init216 pose_net = PoseEncoder(320, conditioning_channels=3, block_out_channels=(16, 32, 96, 256)).to(dtype=dtype, device=device)217 pose_net.load_state_dict(torch.load("./pretrained_weights/pose_encoder.pth", weights_only=True))218 219 ### load audio processor params220 audio_processor = load_audio_model(model_path="./pretrained_weights/audio_processor/tiny.pt", device=device)221 222 ############# model_init finished #############223 sched_kwargs = {224 "beta_start": 0.00085,225 "beta_end": 0.012,226 "beta_schedule": "linear",227 "clip_sample": False,228 "steps_offset": 1,229 "prediction_type": "v_prediction",230 "rescale_betas_zero_snr": True,231 "timestep_spacing": "trailing"232 }233 scheduler = DDIMScheduler(**sched_kwargs)234 235 pipe = EchoMimicV2Pipeline(236 vae=vae,237 reference_unet=reference_unet,238 denoising_unet=denoising_unet,239 audio_guider=audio_processor,240 pose_encoder=pose_net,241 scheduler=scheduler,242 )243 244 pipe = pipe.to(device, dtype=dtype)245 246 if seed is not None and seed > -1:247 generator = torch.manual_seed(seed)248 else:249 seed = random.randint(100, 1000000)250 generator = torch.manual_seed(seed)251 252 if is_shared_ui:253 audio_input = cut_audio_to_5_seconds(audio_input)254 print(f"Trimmed audio saved at: {audio_input}")255 256 inputs_dict = {257 "refimg": image_input,258 "audio": audio_input,259 "pose": pose_input,260 }261 262 print('Pose:', inputs_dict['pose'])263 print('Reference:', inputs_dict['refimg'])264 print('Audio:', inputs_dict['audio'])265 266 save_name = f"{save_dir}/{timestamp}"267 268 ref_image_pil = Image.open(inputs_dict['refimg']).resize((width, height))269 audio_clip = AudioFileClip(inputs_dict['audio'])270 271 length = min(length, int(audio_clip.duration * fps), len(os.listdir(inputs_dict['pose'])))272 273 start_idx = 0274 275 pose_list = []276 for index in range(start_idx, start_idx + length):277 tgt_musk = np.zeros((width, height, 3)).astype('uint8')278 tgt_musk_path = os.path.join(inputs_dict['pose'], "{}.npy".format(index))279 detected_pose = np.load(tgt_musk_path, allow_pickle=True).tolist()280 imh_new, imw_new, rb, re, cb, ce = detected_pose['draw_pose_params']281 im = draw_pose_select_v2(detected_pose, imh_new, imw_new, ref_w=800)282 im = np.transpose(np.array(im),(1, 2, 0))283 tgt_musk[rb:re,cb:ce,:] = im284 285 tgt_musk_pil = Image.fromarray(np.array(tgt_musk)).convert('RGB')286 pose_list.append(torch.Tensor(np.array(tgt_musk_pil)).to(dtype=dtype, device=device).permute(2,0,1) / 255.0)287 288 poses_tensor = torch.stack(pose_list, dim=1).unsqueeze(0)289 audio_clip = AudioFileClip(inputs_dict['audio'])290 291 audio_clip = audio_clip.set_duration(length / fps)292 video = pipe(293 ref_image_pil,294 inputs_dict['audio'],295 poses_tensor[:,:,:length,...],296 width,297 height,298 length,299 steps,300 cfg,301 generator=generator,302 audio_sample_rate=sample_rate,303 context_frames=context_frames,304 fps=fps,305 context_overlap=context_overlap,306 start_idx=start_idx,307 ).videos 308 309 final_length = min(video.shape[2], poses_tensor.shape[2], length)310 video_sig = video[:, :, :final_length, :, :]311 312 save_videos_grid(313 video_sig,314 save_name + "_woa_sig.mp4",315 n_rows=1,316 fps=fps,317 )318 319 video_clip_sig = VideoFileClip(save_name + "_woa_sig.mp4",)320 video_clip_sig = video_clip_sig.set_audio(audio_clip)321 video_clip_sig.write_videofile(save_name + "_sig.mp4", codec="libx264", audio_codec="aac", threads=2)322 video_output = save_name + "_sig.mp4"323 seed_text = gr.update(visible=True, value=seed)324 return video_output, seed_text325 326css = """327div#warning-duplicate {328 background-color: #ebf5ff;329 padding: 0 16px 16px;330 margin: 20px 0;331 color: #030303!important;332}333div#warning-duplicate > .gr-prose > h2, div#warning-duplicate > .gr-prose > p {334 color: #0f4592!important;335}336div#warning-duplicate strong {337 color: #0f4592;338}339p.actions {340 display: flex;341 align-items: center;342 margin: 20px 0;343}344div#warning-duplicate .actions a {345 display: inline-block;346 margin-right: 10px;347}348div#warning-setgpu {349 background-color: #fff4eb;350 padding: 0 16px 16px;351 margin: 20px 0;352 color: #030303!important;353}354div#warning-setgpu > .gr-prose > h2, div#warning-setgpu > .gr-prose > p {355 color: #92220f!important;356}357div#warning-setgpu a, div#warning-setgpu b {358 color: #91230f;359}360div#warning-setgpu p.actions > a {361 display: inline-block;362 background: #1f1f23;363 border-radius: 40px;364 padding: 6px 24px;365 color: antiquewhite;366 text-decoration: none;367 font-weight: 600;368 font-size: 1.2em;369}370div#warning-ready {371 background-color: #ecfdf5;372 padding: 0 16px 16px;373 margin: 20px 0;374 color: #030303!important;375}376div#warning-ready > .gr-prose > h2, div#warning-ready > .gr-prose > p {377 color: #057857!important;378}379.custom-color {380 color: #030303 !important;381}382"""383 384with gr.Blocks(css=css) as demo:385 gr.Markdown("""386 # EchoMimicV2387 388 ⚠️ This demonstration is for academic research and experiential use only.389 """)390 gr.HTML("""391 <div style="display:flex;column-gap:4px;">392 <a href="https://github.com/antgroup/echomimic_v2">393 <img src='https://img.shields.io/badge/GitHub-Repo-blue'>394 </a> 395 <a href="https://antgroup.github.io/ai/echomimic_v2/">396 <img src='https://img.shields.io/badge/Project-Page-green'>397 </a>398 <a href="https://arxiv.org/abs/2411.10061">399 <img src='https://img.shields.io/badge/ArXiv-Paper-red'>400 </a>401 <a href="https://huggingface.co/spaces/fffiloni/echomimic-v2?duplicate=true">402 <img src="https://huggingface.co/datasets/huggingface/badges/resolve/main/duplicate-this-space-sm.svg" alt="Duplicate this Space">403 </a>404 <a href="https://huggingface.co/fffiloni">405 <img src="https://huggingface.co/datasets/huggingface/badges/resolve/main/follow-me-on-HF-sm-dark.svg" alt="Follow me on HF">406 </a>407 </div>408 """)409 with gr.Column():410 with gr.Row():411 with gr.Column():412 with gr.Group():413 image_input = gr.Image(label="Image Input (Auto Scaling)", type="filepath")414 audio_input = gr.Audio(label="Audio Input - max 5 seconds on shared UI", type="filepath")415 pose_input = gr.Textbox(label="Pose Input (Directory Path)", placeholder="Please enter the directory path for pose data.", value="assets/halfbody_demo/pose/01", interactive=False, visible=False)416 with gr.Accordion("Advanced Settings", open=False):417 with gr.Row():418 width = gr.Number(label="Width (multiple of 16, recommended: 768)", value=768)419 height = gr.Number(label="Height (multiple of 16, recommended: 768)", value=768)420 length = gr.Number(label="Video Length (recommended: 240)", value=240)421 with gr.Row():422 steps = gr.Number(label="Steps (recommended: 30)", value=20)423 sample_rate = gr.Number(label="Sampling Rate (recommended: 16000)", value=16000)424 cfg = gr.Number(label="CFG (recommended: 2.5)", value=2.5, step=0.1)425 with gr.Row():426 fps = gr.Number(label="Frame Rate (recommended: 24)", value=24)427 context_frames = gr.Number(label="Context Frames (recommended: 12)", value=12)428 context_overlap = gr.Number(label="Context Overlap (recommended: 3)", value=3)429 with gr.Row():430 quantization_input = gr.Checkbox(label="Int8 Quantization (recommended for users with 12GB VRAM, use audio no longer than 5 seconds)", value=False)431 seed = gr.Number(label="Seed (-1 for random)", value=-1)432 generate_button = gr.Button("🎬 Generate Video", interactive=False if is_shared_ui else True)433 with gr.Column():434 435 if is_shared_ui:436 top_description = gr.HTML(f'''437 <div class="gr-prose">438 <h2 class="custom-color"><svg xmlns="http://www.w3.org/2000/svg" width="18px" height="18px" style="margin-right: 0px;display: inline-block;"fill="none"><path fill="#fff" d="M7 13.2a6.3 6.3 0 0 0 4.4-10.7A6.3 6.3 0 0 0 .6 6.9 6.3 6.3 0 0 0 7 13.2Z"/><path fill="#fff" fill-rule="evenodd" d="M7 0a6.9 6.9 0 0 1 4.8 11.8A6.9 6.9 0 0 1 0 7 6.9 6.9 0 0 1 7 0Zm0 0v.7V0ZM0 7h.6H0Zm7 6.8v-.6.6ZM13.7 7h-.6.6ZM9.1 1.7c-.7-.3-1.4-.4-2.2-.4a5.6 5.6 0 0 0-4 1.6 5.6 5.6 0 0 0-1.6 4 5.6 5.6 0 0 0 1.6 4 5.6 5.6 0 0 0 4 1.7 5.6 5.6 0 0 0 4-1.7 5.6 5.6 0 0 0 1.7-4 5.6 5.6 0 0 0-1.7-4c-.5-.5-1.1-.9-1.8-1.2Z" clip-rule="evenodd"/><path fill="#000" fill-rule="evenodd" d="M7 2.9a.8.8 0 1 1 0 1.5A.8.8 0 0 1 7 3ZM5.8 5.7c0-.4.3-.6.6-.6h.7c.3 0 .6.2.6.6v3.7h.5a.6.6 0 0 1 0 1.3H6a.6.6 0 0 1 0-1.3h.4v-3a.6.6 0 0 1-.6-.7Z" clip-rule="evenodd"/></svg>439 Attention: this Space need to be duplicated to work</h2>440 <p class="main-message custom-color">441 To make it work, <strong>duplicate the Space</strong> and run it on your own profile using a <strong>private</strong> GPU (L40s recommended).<br />442 A L40s costs <strong>US$1.80/h</strong>. 443 </p>444 <p class="actions custom-color">445 <a href="https://huggingface.co/spaces/{os.environ['SPACE_ID']}?duplicate=true">446 <img src="https://huggingface.co/datasets/huggingface/badges/resolve/main/duplicate-this-space-lg-dark.svg" alt="Duplicate this Space" />447 </a>448 to start experimenting with this demo449 </p>450 </div>451 ''', elem_id="warning-duplicate")452 else:453 if(is_gpu_associated):454 top_description = gr.HTML(f'''455 <div class="gr-prose">456 <h2 class="custom-color"><svg xmlns="http://www.w3.org/2000/svg" width="18px" height="18px" style="margin-right: 0px;display: inline-block;"fill="none"><path fill="#fff" d="M7 13.2a6.3 6.3 0 0 0 4.4-10.7A6.3 6.3 0 0 0 .6 6.9 6.3 6.3 0 0 0 7 13.2Z"/><path fill="#fff" fill-rule="evenodd" d="M7 0a6.9 6.9 0 0 1 4.8 11.8A6.9 6.9 0 0 1 0 7 6.9 6.9 0 0 1 7 0Zm0 0v.7V0ZM0 7h.6H0Zm7 6.8v-.6.6ZM13.7 7h-.6.6ZM9.1 1.7c-.7-.3-1.4-.4-2.2-.4a5.6 5.6 0 0 0-4 1.6 5.6 5.6 0 0 0-1.6 4 5.6 5.6 0 0 0 1.6 4 5.6 5.6 0 0 0 4 1.7 5.6 5.6 0 0 0 4-1.7 5.6 5.6 0 0 0 1.7-4 5.6 5.6 0 0 0-1.7-4c-.5-.5-1.1-.9-1.8-1.2Z" clip-rule="evenodd"/><path fill="#000" fill-rule="evenodd" d="M7 2.9a.8.8 0 1 1 0 1.5A.8.8 0 0 1 7 3ZM5.8 5.7c0-.4.3-.6.6-.6h.7c.3 0 .6.2.6.6v3.7h.5a.6.6 0 0 1 0 1.3H6a.6.6 0 0 1 0-1.3h.4v-3a.6.6 0 0 1-.6-.7Z" clip-rule="evenodd"/></svg>457 You have successfully associated a GPU to this Space 🎉</h2>458 <p class="custom-color">459 You will be billed by the minute from when you activated the GPU until when it is turned off.460 </p> 461 </div>462 ''', elem_id="warning-ready")463 else:464 top_description = gr.HTML(f'''465 <div class="gr-prose">466 <h2 class="custom-color"><svg xmlns="http://www.w3.org/2000/svg" width="18px" height="18px" style="margin-right: 0px;display: inline-block;"fill="none"><path fill="#fff" d="M7 13.2a6.3 6.3 0 0 0 4.4-10.7A6.3 6.3 0 0 0 .6 6.9 6.3 6.3 0 0 0 7 13.2Z"/><path fill="#fff" fill-rule="evenodd" d="M7 0a6.9 6.9 0 0 1 4.8 11.8A6.9 6.9 0 0 1 0 7 6.9 6.9 0 0 1 7 0Zm0 0v.7V0ZM0 7h.6H0Zm7 6.8v-.6.6ZM13.7 7h-.6.6ZM9.1 1.7c-.7-.3-1.4-.4-2.2-.4a5.6 5.6 0 0 0-4 1.6 5.6 5.6 0 0 0-1.6 4 5.6 5.6 0 0 0 1.6 4 5.6 5.6 0 0 0 4 1.7 5.6 5.6 0 0 0 4-1.7 5.6 5.6 0 0 0 1.7-4 5.6 5.6 0 0 0-1.7-4c-.5-.5-1.1-.9-1.8-1.2Z" clip-rule="evenodd"/><path fill="#000" fill-rule="evenodd" d="M7 2.9a.8.8 0 1 1 0 1.5A.8.8 0 0 1 7 3ZM5.8 5.7c0-.4.3-.6.6-.6h.7c.3 0 .6.2.6.6v3.7h.5a.6.6 0 0 1 0 1.3H6a.6.6 0 0 1 0-1.3h.4v-3a.6.6 0 0 1-.6-.7Z" clip-rule="evenodd"/></svg>467 You have successfully duplicated the MimicMotion Space 🎉</h2>468 <p class="custom-color">There's only one step left before you can properly play with this demo: <a href="https://huggingface.co/spaces/{os.environ['SPACE_ID']}/settings" style="text-decoration: underline" target="_blank">attribute a GPU</b> to it (via the Settings tab)</a> and run the app below.469 You will be billed by the minute from when you activate the GPU until when it is turned off.</p> 470 <p class="actions custom-color">471 <a href="https://huggingface.co/spaces/{os.environ['SPACE_ID']}/settings">🔥 Set recommended GPU</a>472 </p>473 </div>474 ''', elem_id="warning-setgpu")475 476 video_output = gr.Video(label="Output Video")477 seed_text = gr.Textbox(label="Seed", interactive=False, visible=False)478 gr.Examples(479 examples=[480 ["EMTD_dataset/ref_imgs_by_FLUX/man/0001.png", "assets/halfbody_demo/audio/chinese/echomimicv2_man.wav"],481 ["EMTD_dataset/ref_imgs_by_FLUX/woman/0077.png", "assets/halfbody_demo/audio/chinese/echomimicv2_woman.wav"],482 ["EMTD_dataset/ref_imgs_by_FLUX/man/0003.png", "assets/halfbody_demo/audio/chinese/fighting.wav"],483 ["EMTD_dataset/ref_imgs_by_FLUX/woman/0033.png", "assets/halfbody_demo/audio/chinese/good.wav"],484 ["EMTD_dataset/ref_imgs_by_FLUX/man/0010.png", "assets/halfbody_demo/audio/chinese/news.wav"],485 ["EMTD_dataset/ref_imgs_by_FLUX/man/1168.png", "assets/halfbody_demo/audio/chinese/no_smoking.wav"],486 ["EMTD_dataset/ref_imgs_by_FLUX/woman/0057.png", "assets/halfbody_demo/audio/chinese/ultraman.wav"]487 ],488 inputs=[image_input, audio_input], 489 label="Preset Characters and Audio",490 )491 492 generate_button.click(493 generate,494 inputs=[image_input, audio_input, pose_input, width, height, length, steps, sample_rate, cfg, fps, context_frames, context_overlap, quantization_input, seed],495 outputs=[video_output, seed_text],496 )497 498 499 500if __name__ == "__main__":501 demo.queue()502 demo.launch(show_api=False, show_error=True, ssr_mode=False)503 