WebPTalkHead / app.py
Akjava's picture
set max timeing-seat 32
b8a1ed1
import spaces
import gradio as gr
import subprocess
import re
from PIL import Image,ImageSequence
import webp
import io
import hashlib
import os
import time
import shutil
css="""
#col-left {
margin: 0 auto;
max-width: 640px;
}
#col-right {
margin: 0 auto;
max-width: 640px;
}
.grid-container {
display: flex;
align-items: center;
justify-content: center;
gap:10px
}
.image {
width: 128px;
height: 128px;
object-fit: cover;
}
.text {
font-size: 16px;
}
"""
output_dir = "outputs"
passed_time = 60 * 20
def load_text(text_path: str) -> str:
with open(text_path, 'r', encoding='utf-8') as f:
text = f.read()
return text
def clear_old_files(dir,passed_time):
try:
files = os.listdir(dir)
current_time = time.time()
for file in files:
file_path = os.path.join(dir,file)
ctime = os.stat(file_path).st_ctime
diff = current_time - ctime
#print(f"ctime={ctime},current_time={current_time},passed_time={passed_time},diff={diff}")
if diff > passed_time:
os.remove(file_path)
except:
print("maybe still gallery using error")
def process_images(normal_image,mouth_open_image,eye_close_image,duration=100,pattern = "nnnmmmnenmmmnnnmmmnnnmmmnnnmmm",looping = True):
# validating images
# cache control
if not os.path.exists(output_dir):
os.mkdir(output_dir)
clear_old_files(output_dir,passed_time)
if normal_image is None or mouth_open_image is None or eye_close_image is None:
raise gr.Error("Need Normal Mouth Eyes 3 images")
#validate check
normal_width, normal_height = normal_image.size
mouth_width, mouth_height = mouth_open_image.size
eye_width, eye_height = eye_close_image.size
if normal_width!=mouth_width or normal_height!=mouth_height:
raise gr.Error("Mouth Image Size must be same as normal")
if normal_width!=eye_width or normal_height!=eye_height:
raise gr.Error("Eyes Image Size must be same as normal")
if duration<1:
raise gr.Error("min duration is 1")
pattern = pattern[:32]
if pattern == "":
pattern = "nme"
else:
valids =["n","m","e"]
for ch in pattern:
if ch not in valids:
raise gr.Error("invalid pattern contain.pattern must be n or e or m")
frames = []
for ch in pattern:
if ch == "m":
frames.append(mouth_open_image)
elif ch == "e":
frames.append(eye_close_image)
else:
frames.append(normal_image)
loop = 0 if looping else 1 #MUST BE ZERO,NOT TRUE
output_buffer = io.BytesIO()
frames[0].save(output_buffer,
save_all=True,
append_images=frames[1:],
duration=duration,
loop=loop,
format='WebP')
hash_object = hashlib.sha256(output_buffer.getvalue())
hex_dig = hash_object.hexdigest()
unique_id = hex_dig[:32]
output_path = f"{output_dir}/{unique_id}.webp"
with open(output_path,"wb") as f:
f.write(output_buffer.getvalue())
return output_path
with gr.Blocks(css=css, elem_id="demo-container") as demo:
with gr.Column():
gr.HTML(load_text("demo_header.html"))
gr.HTML(load_text("demo_tools.html"))
with gr.Row():
with gr.Column():
image_normal = gr.Image(sources=['upload','clipboard'], elem_id="image_normal", type="pil", label="Normal Image",height=400, value=None)
with gr.Row(elem_id="prompt-container", equal_height=False):
with gr.Row():
btn = gr.Button("Make WebP Animation", elem_id="run_button")
image_mouth = gr.Image(sources=['upload','clipboard'], elem_id="image_mouth", type="pil", label="Mouth Opened",height=400, value=None)
image_eyes = gr.Image(sources=['upload','clipboard'], elem_id="image_eyes", type="pil", label="Eyes Closed",height=400, value=None)
id_input=gr.Text(label="Name", visible=False)
with gr.Accordion(label="Advanced Settings", open=False):
with gr.Row(equal_height=True):
animation_time = gr.Number(value=100, minimum=1, maximum=1000, step=10, label="Animation Time")
looping = gr.Checkbox(label="Loop",value=True)
with gr.Row( equal_height=True):
timing_seat = gr.Text(value="nnnmmmnenmmmnnnmmmnnnmmm", max_length=32,label="Timing Seat")
with gr.Column():
image_out = gr.Image(sources=[],label="Output", elem_id="output-img",type="filepath", format="webp")
btn.click(fn=process_images, inputs=[image_normal, image_mouth,image_eyes,animation_time,timing_seat,looping], outputs =image_out, api_name='infer')
gr.Examples(
examples=[
["examples/00003245_normal.jpg","examples/00003245_mouth.jpg","examples/00003245_eyes.jpg","examples/00003245.webp"],
["examples/00207245_normal.png","examples/00207245_mouth.png","examples/00207245_eyes.png","examples/00207245.webp"],
["examples/00350245_normal.jpg","examples/00350245_mouth.jpg","examples/00350245_eyes.jpg","examples/00350245.webp"],
["examples/00538245_normal.jpg","examples/00538245_mouth.jpg","examples/00538245_eyes.jpg","examples/00538245.webp"],
["examples/00828003_00.jpg","examples/00828003_09.jpg","examples/00828003_99.jpg","examples/00828003.webp"],
["examples/00825000_00.jpg","examples/00825000_09.jpg","examples/00825000_99.jpg","examples/00825000.webp"],
["examples/00824008_00.jpg","examples/00824008_09.jpg","examples/00824008_99.jpg","examples/00824008.webp"],
["examples/prompt01_normal.jpg","examples/prompt01_mouth.jpg","examples/prompt01_eyes.jpg","examples/prompt01.webp"],
],
inputs=[image_normal,image_mouth,image_eyes,image_out],
)
gr.HTML(
gr.HTML(load_text("demo_footer.html"))
)
if __name__ == "__main__":
demo.launch()