"""Modified from https://github.com/guoyww/AnimateDiff/blob/main/app.py """ import gc import json import os import random import base64 import requests from datetime import datetime from glob import glob import gradio as gr import torch import numpy as np from diffusers import (AutoencoderKL, DDIMScheduler, DPMSolverMultistepScheduler, EulerAncestralDiscreteScheduler, EulerDiscreteScheduler, PNDMScheduler) from easyanimate.models.autoencoder_magvit import AutoencoderKLMagvit from diffusers.utils.import_utils import is_xformers_available from omegaconf import OmegaConf from safetensors import safe_open from transformers import T5EncoderModel, T5Tokenizer from easyanimate.models.transformer3d import Transformer3DModel from easyanimate.pipeline.pipeline_easyanimate import EasyAnimatePipeline from easyanimate.utils.lora_utils import merge_lora, unmerge_lora from easyanimate.utils.utils import save_videos_grid from PIL import Image sample_idx = 0 scheduler_dict = { "Euler": EulerDiscreteScheduler, "Euler A": EulerAncestralDiscreteScheduler, "DPM++": DPMSolverMultistepScheduler, "PNDM": PNDMScheduler, "DDIM": DDIMScheduler, } css = """ .toolbutton { margin-buttom: 0em 0em 0em 0em; max-width: 2.5em; min-width: 2.5em !important; height: 2.5em; } """ class EasyAnimateController: def __init__(self): # config dirs self.basedir = os.getcwd() self.config_dir = os.path.join(self.basedir, "config") self.diffusion_transformer_dir = os.path.join(self.basedir, "models", "Diffusion_Transformer") self.motion_module_dir = os.path.join(self.basedir, "models", "Motion_Module") self.personalized_model_dir = os.path.join(self.basedir, "models", "Personalized_Model") self.savedir = os.path.join(self.basedir, "samples", datetime.now().strftime("Gradio-%Y-%m-%dT%H-%M-%S")) self.savedir_sample = os.path.join(self.savedir, "sample") self.edition = "v2" self.inference_config = OmegaConf.load(os.path.join(self.config_dir, "easyanimate_video_magvit_motion_module_v2.yaml")) os.makedirs(self.savedir, exist_ok=True) self.diffusion_transformer_list = [] self.motion_module_list = [] self.personalized_model_list = [] self.refresh_diffusion_transformer() self.refresh_motion_module() self.refresh_personalized_model() # config models self.tokenizer = None self.text_encoder = None self.vae = None self.transformer = None self.pipeline = None self.motion_module_path = "none" self.base_model_path = "none" self.lora_model_path = "none" self.weight_dtype = torch.bfloat16 def refresh_diffusion_transformer(self): self.diffusion_transformer_list = glob(os.path.join(self.diffusion_transformer_dir, "*/")) def refresh_motion_module(self): motion_module_list = glob(os.path.join(self.motion_module_dir, "*.safetensors")) self.motion_module_list = [os.path.basename(p) for p in motion_module_list] def refresh_personalized_model(self): personalized_model_list = glob(os.path.join(self.personalized_model_dir, "*.safetensors")) self.personalized_model_list = [os.path.basename(p) for p in personalized_model_list] def update_edition(self, edition): print("Update edition of EasyAnimate") self.edition = edition if edition == "v1": self.inference_config = OmegaConf.load(os.path.join(self.config_dir, "easyanimate_video_motion_module_v1.yaml")) return gr.Dropdown.update(), gr.update(value="none"), gr.update(visible=True), gr.update(visible=True), \ gr.update(visible=False), gr.update(value=512, minimum=384, maximum=704, step=32), \ gr.update(value=512, minimum=384, maximum=704, step=32), gr.update(value=80, minimum=40, maximum=80, step=1) else: self.inference_config = OmegaConf.load(os.path.join(self.config_dir, "easyanimate_video_magvit_motion_module_v2.yaml")) return gr.Dropdown.update(), gr.update(value="none"), gr.update(visible=False), gr.update(visible=False), \ gr.update(visible=True), gr.update(value=672, minimum=128, maximum=1280, step=16), \ gr.update(value=384, minimum=128, maximum=1280, step=16), gr.update(value=144, minimum=9, maximum=144, step=9) def update_diffusion_transformer(self, diffusion_transformer_dropdown): print("Update diffusion transformer") if diffusion_transformer_dropdown == "none": return gr.Dropdown.update() if OmegaConf.to_container(self.inference_config['vae_kwargs'])['enable_magvit']: Choosen_AutoencoderKL = AutoencoderKLMagvit else: Choosen_AutoencoderKL = AutoencoderKL self.vae = Choosen_AutoencoderKL.from_pretrained( diffusion_transformer_dropdown, subfolder="vae", ).to(self.weight_dtype) self.transformer = Transformer3DModel.from_pretrained_2d( diffusion_transformer_dropdown, subfolder="transformer", transformer_additional_kwargs=OmegaConf.to_container(self.inference_config.transformer_additional_kwargs) ).to(self.weight_dtype) self.tokenizer = T5Tokenizer.from_pretrained(diffusion_transformer_dropdown, subfolder="tokenizer") self.text_encoder = T5EncoderModel.from_pretrained(diffusion_transformer_dropdown, subfolder="text_encoder", torch_dtype=self.weight_dtype) # Get pipeline self.pipeline = EasyAnimatePipeline( vae=self.vae, text_encoder=self.text_encoder, tokenizer=self.tokenizer, transformer=self.transformer, scheduler=scheduler_dict["Euler"](**OmegaConf.to_container(self.inference_config.noise_scheduler_kwargs)) ) self.pipeline.enable_model_cpu_offload() print("Update diffusion transformer done") return gr.Dropdown.update() def update_motion_module(self, motion_module_dropdown): self.motion_module_path = motion_module_dropdown print("Update motion module") if motion_module_dropdown == "none": return gr.Dropdown.update() if self.transformer is None: gr.Info(f"Please select a pretrained model path.") return gr.Dropdown.update(value=None) else: motion_module_dropdown = os.path.join(self.motion_module_dir, motion_module_dropdown) if motion_module_dropdown.endswith(".safetensors"): from safetensors.torch import load_file, safe_open motion_module_state_dict = load_file(motion_module_dropdown) else: if not os.path.isfile(motion_module_dropdown): raise RuntimeError(f"{motion_module_dropdown} does not exist") motion_module_state_dict = torch.load(motion_module_dropdown, map_location="cpu") missing, unexpected = self.transformer.load_state_dict(motion_module_state_dict, strict=False) print("Update motion module done.") return gr.Dropdown.update() def update_base_model(self, base_model_dropdown): self.base_model_path = base_model_dropdown print("Update base model") if base_model_dropdown == "none": return gr.Dropdown.update() if self.transformer is None: gr.Info(f"Please select a pretrained model path.") return gr.Dropdown.update(value=None) else: base_model_dropdown = os.path.join(self.personalized_model_dir, base_model_dropdown) base_model_state_dict = {} with safe_open(base_model_dropdown, framework="pt", device="cpu") as f: for key in f.keys(): base_model_state_dict[key] = f.get_tensor(key) self.transformer.load_state_dict(base_model_state_dict, strict=False) print("Update base done") return gr.Dropdown.update() def update_lora_model(self, lora_model_dropdown): print("Update lora model") if lora_model_dropdown == "none": self.lora_model_path = "none" return gr.Dropdown.update() lora_model_dropdown = os.path.join(self.personalized_model_dir, lora_model_dropdown) self.lora_model_path = lora_model_dropdown return gr.Dropdown.update() def generate( self, diffusion_transformer_dropdown, motion_module_dropdown, base_model_dropdown, lora_model_dropdown, lora_alpha_slider, prompt_textbox, negative_prompt_textbox, sampler_dropdown, sample_step_slider, width_slider, height_slider, is_image, length_slider, cfg_scale_slider, seed_textbox, is_api = False, ): global sample_idx if self.transformer is None: raise gr.Error(f"Please select a pretrained model path.") if self.base_model_path != base_model_dropdown: self.update_base_model(base_model_dropdown) if self.motion_module_path != motion_module_dropdown: self.update_motion_module(motion_module_dropdown) if self.lora_model_path != lora_model_dropdown: print("Update lora model") self.update_lora_model(lora_model_dropdown) if is_xformers_available(): self.transformer.enable_xformers_memory_efficient_attention() self.pipeline.scheduler = scheduler_dict[sampler_dropdown](**OmegaConf.to_container(self.inference_config.noise_scheduler_kwargs)) if self.lora_model_path != "none": # lora part self.pipeline = merge_lora(self.pipeline, self.lora_model_path, multiplier=lora_alpha_slider) self.pipeline.to("cuda") if int(seed_textbox) != -1 and seed_textbox != "": torch.manual_seed(int(seed_textbox)) else: seed_textbox = np.random.randint(0, 1e10) generator = torch.Generator(device="cuda").manual_seed(int(seed_textbox)) try: sample = self.pipeline( prompt_textbox, negative_prompt = negative_prompt_textbox, num_inference_steps = sample_step_slider, guidance_scale = cfg_scale_slider, width = width_slider, height = height_slider, video_length = length_slider if not is_image else 1, generator = generator ).videos except Exception as e: gc.collect() torch.cuda.empty_cache() torch.cuda.ipc_collect() if self.lora_model_path != "none": self.pipeline = unmerge_lora(self.pipeline, self.lora_model_path, multiplier=lora_alpha_slider) if is_api: return "", f"Error. error information is {str(e)}" else: return gr.Image.update(), gr.Video.update(), f"Error. error information is {str(e)}" # lora part if self.lora_model_path != "none": self.pipeline = unmerge_lora(self.pipeline, self.lora_model_path, multiplier=lora_alpha_slider) sample_config = { "prompt": prompt_textbox, "n_prompt": negative_prompt_textbox, "sampler": sampler_dropdown, "num_inference_steps": sample_step_slider, "guidance_scale": cfg_scale_slider, "width": width_slider, "height": height_slider, "video_length": length_slider, "seed_textbox": seed_textbox } json_str = json.dumps(sample_config, indent=4) with open(os.path.join(self.savedir, "logs.json"), "a") as f: f.write(json_str) f.write("\n\n") if not os.path.exists(self.savedir_sample): os.makedirs(self.savedir_sample, exist_ok=True) index = len([path for path in os.listdir(self.savedir_sample)]) + 1 prefix = str(index).zfill(3) gc.collect() torch.cuda.empty_cache() torch.cuda.ipc_collect() if is_image or length_slider == 1: save_sample_path = os.path.join(self.savedir_sample, prefix + f".png") image = sample[0, :, 0] image = image.transpose(0, 1).transpose(1, 2) image = (image * 255).numpy().astype(np.uint8) image = Image.fromarray(image) image.save(save_sample_path) if is_api: return save_sample_path, "Success" else: return gr.Image.update(value=save_sample_path, visible=True), gr.Video.update(value=None, visible=False), "Success" else: save_sample_path = os.path.join(self.savedir_sample, prefix + f".mp4") save_videos_grid(sample, save_sample_path, fps=12 if self.edition == "v1" else 24) if is_api: return save_sample_path, "Success" else: return gr.Image.update(visible=False, value=None), gr.Video.update(value=save_sample_path, visible=True), "Success" def ui(): controller = EasyAnimateController() with gr.Blocks(css=css) as demo: gr.Markdown( """ # EasyAnimate: Integrated generation of baseline scheme for videos and images. Generate your videos easily [Github](https://github.com/aigc-apps/EasyAnimate/) """ ) with gr.Column(variant="panel"): gr.Markdown( """ ### 1. EasyAnimate Edition (select easyanimate edition first). """ ) with gr.Row(): easyanimate_edition_dropdown = gr.Dropdown( label="The config of EasyAnimate Edition", choices=["v1", "v2"], value="v2", interactive=True, ) gr.Markdown( """ ### 2. Model checkpoints (select pretrained model path). """ ) with gr.Row(): diffusion_transformer_dropdown = gr.Dropdown( label="Pretrained Model Path", choices=controller.diffusion_transformer_list, value="none", interactive=True, ) diffusion_transformer_dropdown.change( fn=controller.update_diffusion_transformer, inputs=[diffusion_transformer_dropdown], outputs=[diffusion_transformer_dropdown] ) diffusion_transformer_refresh_button = gr.Button(value="\U0001F503", elem_classes="toolbutton") def refresh_diffusion_transformer(): controller.refresh_diffusion_transformer() return gr.Dropdown.update(choices=controller.diffusion_transformer_list) diffusion_transformer_refresh_button.click(fn=refresh_diffusion_transformer, inputs=[], outputs=[diffusion_transformer_dropdown]) with gr.Row(): motion_module_dropdown = gr.Dropdown( label="Select motion module", choices=controller.motion_module_list, value="none", interactive=True, visible=False ) motion_module_refresh_button = gr.Button(value="\U0001F503", elem_classes="toolbutton", visible=False) def update_motion_module(): controller.refresh_motion_module() return gr.Dropdown.update(choices=controller.motion_module_list) motion_module_refresh_button.click(fn=update_motion_module, inputs=[], outputs=[motion_module_dropdown]) base_model_dropdown = gr.Dropdown( label="Select base Dreambooth model (optional)", choices=controller.personalized_model_list, value="none", interactive=True, ) lora_model_dropdown = gr.Dropdown( label="Select LoRA model (optional)", choices=["none"] + controller.personalized_model_list, value="none", interactive=True, ) lora_alpha_slider = gr.Slider(label="LoRA alpha", value=0.55, minimum=0, maximum=2, interactive=True) personalized_refresh_button = gr.Button(value="\U0001F503", elem_classes="toolbutton") def update_personalized_model(): controller.refresh_personalized_model() return [ gr.Dropdown.update(choices=controller.personalized_model_list), gr.Dropdown.update(choices=["none"] + controller.personalized_model_list) ] personalized_refresh_button.click(fn=update_personalized_model, inputs=[], outputs=[base_model_dropdown, lora_model_dropdown]) with gr.Column(variant="panel"): gr.Markdown( """ ### 3. Configs for Generation. """ ) prompt_textbox = gr.Textbox(label="Prompt", lines=2, value="This video shows the majestic beauty of a waterfall cascading down a cliff into a serene lake. The waterfall, with its powerful flow, is the central focus of the video. The surrounding landscape is lush and green, with trees and foliage adding to the natural beauty of the scene") negative_prompt_textbox = gr.Textbox(label="Negative prompt", lines=2, value="The video is not of a high quality, it has a low resolution, and the audio quality is not clear. Strange motion trajectory, a poor composition and deformed video, low resolution, duplicate and ugly, strange body structure, long and strange neck, bad teeth, bad eyes, bad limbs, bad hands, rotating camera, blurry camera, shaking camera. Deformation, low-resolution, blurry, ugly, distortion. " ) with gr.Row(): with gr.Column(): with gr.Row(): sampler_dropdown = gr.Dropdown(label="Sampling method", choices=list(scheduler_dict.keys()), value=list(scheduler_dict.keys())[0]) sample_step_slider = gr.Slider(label="Sampling steps", value=50, minimum=10, maximum=100, step=1) width_slider = gr.Slider(label="Width", value=672, minimum=128, maximum=1280, step=16) height_slider = gr.Slider(label="Height", value=384, minimum=128, maximum=1280, step=16) with gr.Row(): is_image = gr.Checkbox(False, label="Generate Image") length_slider = gr.Slider(label="Animation length", value=144, minimum=9, maximum=144, step=9) cfg_scale_slider = gr.Slider(label="CFG Scale", value=7.0, minimum=0, maximum=20) with gr.Row(): seed_textbox = gr.Textbox(label="Seed", value=43) seed_button = gr.Button(value="\U0001F3B2", elem_classes="toolbutton") seed_button.click(fn=lambda: gr.Textbox.update(value=random.randint(1, 1e8)), inputs=[], outputs=[seed_textbox]) generate_button = gr.Button(value="Generate", variant='primary') with gr.Column(): result_image = gr.Image(label="Generated Image", interactive=False, visible=False) result_video = gr.Video(label="Generated Animation", interactive=False) infer_progress = gr.Textbox( label="Generation Info", value="No task currently", interactive=False ) is_image.change( lambda x: gr.update(visible=not x), inputs=[is_image], outputs=[length_slider], ) easyanimate_edition_dropdown.change( fn=controller.update_edition, inputs=[easyanimate_edition_dropdown], outputs=[ easyanimate_edition_dropdown, diffusion_transformer_dropdown, motion_module_dropdown, motion_module_refresh_button, is_image, width_slider, height_slider, length_slider, ] ) generate_button.click( fn=controller.generate, inputs=[ diffusion_transformer_dropdown, motion_module_dropdown, base_model_dropdown, lora_model_dropdown, lora_alpha_slider, prompt_textbox, negative_prompt_textbox, sampler_dropdown, sample_step_slider, width_slider, height_slider, is_image, length_slider, cfg_scale_slider, seed_textbox, ], outputs=[result_image, result_video, infer_progress] ) return demo, controller class EasyAnimateController_Modelscope: def __init__(self, edition, config_path, model_name, savedir_sample): # Config and model path weight_dtype = torch.bfloat16 self.savedir_sample = savedir_sample os.makedirs(self.savedir_sample, exist_ok=True) self.edition = edition self.inference_config = OmegaConf.load(config_path) # Get Transformer self.transformer = Transformer3DModel.from_pretrained_2d( model_name, subfolder="transformer", transformer_additional_kwargs=OmegaConf.to_container(self.inference_config['transformer_additional_kwargs']) ).to(weight_dtype) if OmegaConf.to_container(self.inference_config['vae_kwargs'])['enable_magvit']: Choosen_AutoencoderKL = AutoencoderKLMagvit else: Choosen_AutoencoderKL = AutoencoderKL self.vae = Choosen_AutoencoderKL.from_pretrained( model_name, subfolder="vae" ).to(weight_dtype) self.tokenizer = T5Tokenizer.from_pretrained( model_name, subfolder="tokenizer" ) self.text_encoder = T5EncoderModel.from_pretrained( model_name, subfolder="text_encoder", torch_dtype=weight_dtype ) self.pipeline = EasyAnimatePipeline( vae=self.vae, text_encoder=self.text_encoder, tokenizer=self.tokenizer, transformer=self.transformer, scheduler=scheduler_dict["Euler"](**OmegaConf.to_container(self.inference_config.noise_scheduler_kwargs)) ) self.pipeline.enable_model_cpu_offload() print("Update diffusion transformer done") def generate( self, prompt_textbox, negative_prompt_textbox, sampler_dropdown, sample_step_slider, width_slider, height_slider, is_image, length_slider, cfg_scale_slider, seed_textbox ): if is_xformers_available(): self.transformer.enable_xformers_memory_efficient_attention() self.pipeline.scheduler = scheduler_dict[sampler_dropdown](**OmegaConf.to_container(self.inference_config.noise_scheduler_kwargs)) self.pipeline.to("cuda") if int(seed_textbox) != -1 and seed_textbox != "": torch.manual_seed(int(seed_textbox)) else: seed_textbox = np.random.randint(0, 1e10) generator = torch.Generator(device="cuda").manual_seed(int(seed_textbox)) try: sample = self.pipeline( prompt_textbox, negative_prompt = negative_prompt_textbox, num_inference_steps = sample_step_slider, guidance_scale = cfg_scale_slider, width = width_slider, height = height_slider, video_length = length_slider if not is_image else 1, generator = generator ).videos except Exception as e: gc.collect() torch.cuda.empty_cache() torch.cuda.ipc_collect() return gr.Image.update(), gr.Video.update(), f"Error. error information is {str(e)}" if not os.path.exists(self.savedir_sample): os.makedirs(self.savedir_sample, exist_ok=True) index = len([path for path in os.listdir(self.savedir_sample)]) + 1 prefix = str(index).zfill(3) gc.collect() torch.cuda.empty_cache() torch.cuda.ipc_collect() if is_image or length_slider == 1: save_sample_path = os.path.join(self.savedir_sample, prefix + f".png") image = sample[0, :, 0] image = image.transpose(0, 1).transpose(1, 2) image = (image * 255).numpy().astype(np.uint8) image = Image.fromarray(image) image.save(save_sample_path) return gr.Image.update(value=save_sample_path, visible=True), gr.Video.update(value=None, visible=False), "Success" else: save_sample_path = os.path.join(self.savedir_sample, prefix + f".mp4") save_videos_grid(sample, save_sample_path, fps=12 if self.edition == "v1" else 24) return gr.Image.update(visible=False, value=None), gr.Video.update(value=save_sample_path, visible=True), "Success" def ui_modelscope(edition, config_path, model_name, savedir_sample): controller = EasyAnimateController_Modelscope(edition, config_path, model_name, savedir_sample) with gr.Blocks(css=css) as demo: gr.Markdown( """ # EasyAnimate: Integrated generation of baseline scheme for videos and images. Generate your videos easily [Github](https://github.com/aigc-apps/EasyAnimate/) """ ) with gr.Column(variant="panel"): prompt_textbox = gr.Textbox(label="Prompt", lines=2, value="This video shows the majestic beauty of a waterfall cascading down a cliff into a serene lake. The waterfall, with its powerful flow, is the central focus of the video. The surrounding landscape is lush and green, with trees and foliage adding to the natural beauty of the scene") negative_prompt_textbox = gr.Textbox(label="Negative prompt", lines=2, value="The video is not of a high quality, it has a low resolution, and the audio quality is not clear. Strange motion trajectory, a poor composition and deformed video, low resolution, duplicate and ugly, strange body structure, long and strange neck, bad teeth, bad eyes, bad limbs, bad hands, rotating camera, blurry camera, shaking camera. Deformation, low-resolution, blurry, ugly, distortion. " ) with gr.Row(): with gr.Column(): with gr.Row(): sampler_dropdown = gr.Dropdown(label="Sampling method", choices=list(scheduler_dict.keys()), value=list(scheduler_dict.keys())[0]) sample_step_slider = gr.Slider(label="Sampling steps", value=30, minimum=10, maximum=100, step=1) if edition == "v1": width_slider = gr.Slider(label="Width", value=512, minimum=384, maximum=704, step=32) height_slider = gr.Slider(label="Height", value=512, minimum=384, maximum=704, step=32) with gr.Row(): is_image = gr.Checkbox(False, label="Generate Image", visible=False) length_slider = gr.Slider(label="Animation length", value=80, minimum=40, maximum=96, step=1) cfg_scale_slider = gr.Slider(label="CFG Scale", value=6.0, minimum=0, maximum=20) else: width_slider = gr.Slider(label="Width", value=672, minimum=256, maximum=704, step=16) height_slider = gr.Slider(label="Height", value=384, minimum=256, maximum=704, step=16) with gr.Column(): gr.Markdown( """ To ensure the efficiency of the trial, we will limit the frame rate to no more than 81. If you want to experience longer video generation, you can go to our [Github](https://github.com/aigc-apps/EasyAnimate/). """ ) with gr.Row(): is_image = gr.Checkbox(False, label="Generate Image") length_slider = gr.Slider(label="Animation length", value=72, minimum=9, maximum=81, step=9) cfg_scale_slider = gr.Slider(label="CFG Scale", value=7.0, minimum=0, maximum=20) with gr.Row(): seed_textbox = gr.Textbox(label="Seed", value=43) seed_button = gr.Button(value="\U0001F3B2", elem_classes="toolbutton") seed_button.click(fn=lambda: gr.Textbox.update(value=random.randint(1, 1e8)), inputs=[], outputs=[seed_textbox]) generate_button = gr.Button(value="Generate", variant='primary') with gr.Column(): result_image = gr.Image(label="Generated Image", interactive=False, visible=False) result_video = gr.Video(label="Generated Animation", interactive=False) infer_progress = gr.Textbox( label="Generation Info", value="No task currently", interactive=False ) is_image.change( lambda x: gr.update(visible=not x), inputs=[is_image], outputs=[length_slider], ) generate_button.click( fn=controller.generate, inputs=[ prompt_textbox, negative_prompt_textbox, sampler_dropdown, sample_step_slider, width_slider, height_slider, is_image, length_slider, cfg_scale_slider, seed_textbox, ], outputs=[result_image, result_video, infer_progress] ) return demo, controller def post_eas( prompt_textbox, negative_prompt_textbox, sampler_dropdown, sample_step_slider, width_slider, height_slider, is_image, length_slider, cfg_scale_slider, seed_textbox, ): datas = { "base_model_path": "none", "motion_module_path": "none", "lora_model_path": "none", "lora_alpha_slider": 0.55, "prompt_textbox": prompt_textbox, "negative_prompt_textbox": negative_prompt_textbox, "sampler_dropdown": sampler_dropdown, "sample_step_slider": sample_step_slider, "width_slider": width_slider, "height_slider": height_slider, "is_image": is_image, "length_slider": length_slider, "cfg_scale_slider": cfg_scale_slider, "seed_textbox": seed_textbox, } # Token可以在公网地址调用信息中获取,详情请参见通用公网调用部分。 session = requests.session() session.headers.update({"Authorization": os.environ.get("EAS_TOKEN")}) response = session.post(url=f'{os.environ.get("EAS_URL")}/easyanimate/infer_forward', json=datas) outputs = response.json() return outputs class EasyAnimateController_EAS: def __init__(self, edition, config_path, model_name, savedir_sample): self.savedir_sample = savedir_sample os.makedirs(self.savedir_sample, exist_ok=True) def generate( self, prompt_textbox, negative_prompt_textbox, sampler_dropdown, sample_step_slider, width_slider, height_slider, is_image, length_slider, cfg_scale_slider, seed_textbox ): outputs = post_eas( prompt_textbox, negative_prompt_textbox, sampler_dropdown, sample_step_slider, width_slider, height_slider, is_image, length_slider, cfg_scale_slider, seed_textbox ) base64_encoding = outputs["base64_encoding"] decoded_data = base64.b64decode(base64_encoding) if not os.path.exists(self.savedir_sample): os.makedirs(self.savedir_sample, exist_ok=True) index = len([path for path in os.listdir(self.savedir_sample)]) + 1 prefix = str(index).zfill(3) if is_image or length_slider == 1: save_sample_path = os.path.join(self.savedir_sample, prefix + f".png") with open(save_sample_path, "wb") as file: file.write(decoded_data) return gr.Image.update(value=save_sample_path, visible=True), gr.Video.update(value=None, visible=False), "Success" else: save_sample_path = os.path.join(self.savedir_sample, prefix + f".mp4") with open(save_sample_path, "wb") as file: file.write(decoded_data) return gr.Image.update(visible=False, value=None), gr.Video.update(value=save_sample_path, visible=True), "Success" def ui_eas(edition, config_path, model_name, savedir_sample): controller = EasyAnimateController_EAS(edition, config_path, model_name, savedir_sample) with gr.Blocks(css=css) as demo: gr.Markdown( """ # EasyAnimate: Integrated generation of baseline scheme for videos and images. Generate your videos easily [Github](https://github.com/aigc-apps/EasyAnimate/) """ ) with gr.Column(variant="panel"): prompt_textbox = gr.Textbox(label="Prompt", lines=2, value="This video shows the majestic beauty of a waterfall cascading down a cliff into a serene lake. The waterfall, with its powerful flow, is the central focus of the video. The surrounding landscape is lush and green, with trees and foliage adding to the natural beauty of the scene") negative_prompt_textbox = gr.Textbox(label="Negative prompt", lines=2, value="The video is not of a high quality, it has a low resolution, and the audio quality is not clear. Strange motion trajectory, a poor composition and deformed video, low resolution, duplicate and ugly, strange body structure, long and strange neck, bad teeth, bad eyes, bad limbs, bad hands, rotating camera, blurry camera, shaking camera. Deformation, low-resolution, blurry, ugly, distortion. " ) with gr.Row(): with gr.Column(): with gr.Row(): sampler_dropdown = gr.Dropdown(label="Sampling method", choices=list(scheduler_dict.keys()), value=list(scheduler_dict.keys())[0]) sample_step_slider = gr.Slider(label="Sampling steps", value=30, minimum=10, maximum=100, step=1) if edition == "v1": width_slider = gr.Slider(label="Width", value=512, minimum=384, maximum=704, step=32) height_slider = gr.Slider(label="Height", value=512, minimum=384, maximum=704, step=32) with gr.Row(): is_image = gr.Checkbox(False, label="Generate Image", visible=False) length_slider = gr.Slider(label="Animation length", value=80, minimum=40, maximum=96, step=1) cfg_scale_slider = gr.Slider(label="CFG Scale", value=6.0, minimum=0, maximum=20) else: width_slider = gr.Slider(label="Width", value=672, minimum=256, maximum=704, step=16) height_slider = gr.Slider(label="Height", value=384, minimum=256, maximum=704, step=16) with gr.Column(): gr.Markdown( """ To ensure the efficiency of the trial, we will limit the frame rate to no more than 81. If you want to experience longer video generation, you can go to our [Github](https://github.com/aigc-apps/EasyAnimate/). """ ) with gr.Row(): is_image = gr.Checkbox(False, label="Generate Image") length_slider = gr.Slider(label="Animation length", value=72, minimum=9, maximum=81, step=9) cfg_scale_slider = gr.Slider(label="CFG Scale", value=7.0, minimum=0, maximum=20) with gr.Row(): seed_textbox = gr.Textbox(label="Seed", value=43) seed_button = gr.Button(value="\U0001F3B2", elem_classes="toolbutton") seed_button.click(fn=lambda: gr.Textbox.update(value=random.randint(1, 1e8)), inputs=[], outputs=[seed_textbox]) generate_button = gr.Button(value="Generate", variant='primary') with gr.Column(): result_image = gr.Image(label="Generated Image", interactive=False, visible=False) result_video = gr.Video(label="Generated Animation", interactive=False) infer_progress = gr.Textbox( label="Generation Info", value="No task currently", interactive=False ) is_image.change( lambda x: gr.update(visible=not x), inputs=[is_image], outputs=[length_slider], ) generate_button.click( fn=controller.generate, inputs=[ prompt_textbox, negative_prompt_textbox, sampler_dropdown, sample_step_slider, width_slider, height_slider, is_image, length_slider, cfg_scale_slider, seed_textbox, ], outputs=[result_image, result_video, infer_progress] ) return demo, controller