Spaces:
Runtime error
Runtime error
zzw
commited on
Commit
·
42643f5
1
Parent(s):
57d5456
first
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- .gitignore +1 -0
- README.md +1 -1
- app.py +148 -0
- end.md +10 -0
- requirements.txt +3 -0
- sorted.json +162 -0
- title.md +25 -0
- utils.py +237 -0
- vid2vid/3dC.png.avif +0 -0
- vid2vid/3dM.png.avif +0 -0
- vid2vid/3dQ.png.avif +0 -0
- vid2vid/Clay.png.avif +0 -0
- vid2vid/F2D.jpg.avif +0 -0
- vid2vid/G0.png.avif +0 -0
- vid2vid/Lineart-Bold.png.avif +0 -0
- vid2vid/LineartStyle1.png.avif +0 -0
- vid2vid/P1.png.avif +0 -0
- vid2vid/P2.png.avif +0 -0
- vid2vid/PVC.jpg.avif +0 -0
- vid2vid/Pixels.jpg.avif +0 -0
- vid2vid/RC.png.avif +0 -0
- vid2vid/TA.png.avif +0 -0
- vid2vid/TOY.jpg.avif +0 -0
- vid2vid/TY.png.avif +0 -0
- vid2vid/TY2.png.avif +0 -0
- vid2vid/V4AWP.jpg.avif +0 -0
- vid2vid/V4AWP.png.avif +0 -0
- vid2vid/Western.png.avif +0 -0
- vid2vid/aniflat.png.avif +0 -0
- vid2vid/animeK.png.avif +0 -0
- vid2vid/animem.png.avif +0 -0
- vid2vid/ast.png.avif +0 -0
- vid2vid/awp2.png.avif +0 -0
- vid2vid/black-white-comic.png.avif +0 -0
- vid2vid/child-crayon.png.avif +0 -0
- vid2vid/chinese_black_ink_painting.png.avif +0 -0
- vid2vid/chinese_ink.png.avif +0 -0
- vid2vid/chinese_lineart.png.avif +0 -0
- vid2vid/clay2.png.avif +0 -0
- vid2vid/cute-cartoon.png.avif +0 -0
- vid2vid/flatCJ.png.avif +0 -0
- vid2vid/flatanime-Q.png.avif +0 -0
- vid2vid/flatillustration.png.avif +0 -0
- vid2vid/flower.png.avif +0 -0
- vid2vid/ghibli1.png.avif +0 -0
- vid2vid/hcomic.png.avif +0 -0
- vid2vid/hf.png.avif +0 -0
- vid2vid/hm1.png.avif +0 -0
- vid2vid/hm2.png.avif +0 -0
- vid2vid/japanese.png.avif +0 -0
.gitignore
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
__pycache__/utils.cpython-310.pyc
|
README.md
CHANGED
|
@@ -8,7 +8,7 @@ sdk_version: 5.38.0
|
|
| 8 |
app_file: app.py
|
| 9 |
pinned: false
|
| 10 |
license: apache-2.0
|
| 11 |
-
short_description:
|
| 12 |
---
|
| 13 |
|
| 14 |
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
|
|
|
| 8 |
app_file: app.py
|
| 9 |
pinned: false
|
| 10 |
license: apache-2.0
|
| 11 |
+
short_description: Transfer your videos with different AnimeStyles & havefun!
|
| 12 |
---
|
| 13 |
|
| 14 |
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
app.py
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import gradio as gr
|
| 2 |
+
import json
|
| 3 |
+
from moviepy.video.io.VideoFileClip import VideoFileClip
|
| 4 |
+
import threading
|
| 5 |
+
import time
|
| 6 |
+
global_lock = threading.Lock()
|
| 7 |
+
ip_records = {}
|
| 8 |
+
|
| 9 |
+
def get_video_duration(video_path):
|
| 10 |
+
clip = VideoFileClip(video_path)
|
| 11 |
+
duration = clip.duration
|
| 12 |
+
clip.close()
|
| 13 |
+
return duration
|
| 14 |
+
|
| 15 |
+
from utils import processing
|
| 16 |
+
|
| 17 |
+
with open("sorted.json", "r") as f:
|
| 18 |
+
style_dicts = json.load(f)
|
| 19 |
+
|
| 20 |
+
styles = list(style_dicts.keys())
|
| 21 |
+
style_images = {k: v['thumbnailUrl'] for k, v in style_dicts.items() if v is not None}
|
| 22 |
+
|
| 23 |
+
def get_client_info(request: gr.Request):
|
| 24 |
+
clientHost = request.client.host
|
| 25 |
+
print("IP address:", clientHost)
|
| 26 |
+
return clientHost
|
| 27 |
+
|
| 28 |
+
def check_ip_limit(client_ip):
|
| 29 |
+
current_time = time.time()
|
| 30 |
+
if client_ip not in ip_records:
|
| 31 |
+
ip_records[client_ip] = [current_time]
|
| 32 |
+
return True
|
| 33 |
+
else:
|
| 34 |
+
times = ip_records[client_ip]
|
| 35 |
+
times = [t for t in times if current_time - t < 5 * 60]
|
| 36 |
+
if len(times) < 2:
|
| 37 |
+
times.append(current_time)
|
| 38 |
+
ip_records[client_ip] = times
|
| 39 |
+
return True
|
| 40 |
+
else:
|
| 41 |
+
return False
|
| 42 |
+
|
| 43 |
+
def fn(in_video, style, aspect_ratio, transfer_duration, request: gr.Request):
|
| 44 |
+
client_host = get_client_info(request)
|
| 45 |
+
flag = check_ip_limit(client_host)
|
| 46 |
+
if not flag:
|
| 47 |
+
raise gr.Error(f"Exceed the request limit of 1 requests per five minute.")
|
| 48 |
+
|
| 49 |
+
print(f"Received video: {in_video}, aspect_ratio: {aspect_ratio}, style: {style}, transfer_duration: {transfer_duration}")
|
| 50 |
+
|
| 51 |
+
if in_video is None:
|
| 52 |
+
raise Exception("input_video is None")
|
| 53 |
+
|
| 54 |
+
if aspect_ratio not in ["16:9", "9:16", "1:1"]:
|
| 55 |
+
raise Exception('aspect_ratio not in ["16:9", "9:16", "1:1"]')
|
| 56 |
+
if aspect_ratio == "16:9":
|
| 57 |
+
width, height = 1280, 720
|
| 58 |
+
elif aspect_ratio == "9:16":
|
| 59 |
+
width, height = 720, 1280
|
| 60 |
+
elif aspect_ratio == "1:1":
|
| 61 |
+
width, height = 960, 960
|
| 62 |
+
|
| 63 |
+
style_id = style_dicts[style]['id']
|
| 64 |
+
if style not in styles:
|
| 65 |
+
raise Exception("style not in styles")
|
| 66 |
+
|
| 67 |
+
video_duration = get_video_duration(in_video)
|
| 68 |
+
if video_duration < 3:
|
| 69 |
+
raise Exception("video_duration < 3")
|
| 70 |
+
|
| 71 |
+
transfer_duration = 3
|
| 72 |
+
|
| 73 |
+
res = None
|
| 74 |
+
try:
|
| 75 |
+
global_lock.acquire()
|
| 76 |
+
res = processing(in_video, width, height, style_id, transfer_duration)
|
| 77 |
+
if not res:
|
| 78 |
+
raise Exception("Processing failed")
|
| 79 |
+
finally:
|
| 80 |
+
global_lock.release()
|
| 81 |
+
|
| 82 |
+
return res
|
| 83 |
+
|
| 84 |
+
def load_description(fp):
|
| 85 |
+
with open(fp, 'r', encoding='utf-8') as f:
|
| 86 |
+
content = f.read()
|
| 87 |
+
return content
|
| 88 |
+
|
| 89 |
+
with gr.Blocks(theme=gr.themes.Ocean()) as demo:
|
| 90 |
+
# Transform your videos with different Anime styles and have fun!
|
| 91 |
+
gr.HTML(load_description("title.md"))
|
| 92 |
+
with gr.Tab("Video Processing"):
|
| 93 |
+
with gr.Row():
|
| 94 |
+
in_video = gr.Video(label="1. Input Video (Please provide a clear video clip)", interactive=True)
|
| 95 |
+
out_video = gr.Video(label="Final Output Video")
|
| 96 |
+
|
| 97 |
+
with gr.Row():
|
| 98 |
+
style = gr.Radio(
|
| 99 |
+
choices=styles,
|
| 100 |
+
label="2. Style, for more styles, please join our [Discord](https://discord.gg/cN8geBsBmu)",
|
| 101 |
+
value="ClayStyle1",
|
| 102 |
+
interactive=True
|
| 103 |
+
)
|
| 104 |
+
preview = gr.Image(
|
| 105 |
+
value=style_images["ClayStyle1"],
|
| 106 |
+
label="Style Preview",
|
| 107 |
+
show_label=True,
|
| 108 |
+
interactive=False
|
| 109 |
+
)
|
| 110 |
+
|
| 111 |
+
def update_preview(choice):
|
| 112 |
+
return style_images[choice]
|
| 113 |
+
|
| 114 |
+
style.change(fn=update_preview, inputs=style, outputs=preview)
|
| 115 |
+
|
| 116 |
+
with gr.Row():
|
| 117 |
+
|
| 118 |
+
aspect_ratio = gr.Radio(["16:9", "9:16", "1:1"], label="3. Aspect Ratio(Width:Height)", value="16:9", interactive=True)
|
| 119 |
+
transfer_duration = gr.Slider(
|
| 120 |
+
minimum=0,
|
| 121 |
+
maximum=3,
|
| 122 |
+
step=1,
|
| 123 |
+
value=3,
|
| 124 |
+
label="Transfer Duration (seconds), for more than 3 seconds, please join our Discord(https://discord.gg/cN8geBsBmu) or website",
|
| 125 |
+
interactive=True
|
| 126 |
+
)
|
| 127 |
+
submit_button = gr.Button("Generate", interactive=True)
|
| 128 |
+
|
| 129 |
+
examples = gr.Examples(
|
| 130 |
+
[
|
| 131 |
+
["test32.mp4", "ClayStyle1", "9:16" ],
|
| 132 |
+
["test32.mp4", "3D P1", "9:16" ],
|
| 133 |
+
],
|
| 134 |
+
inputs=[in_video, style, aspect_ratio, transfer_duration],
|
| 135 |
+
outputs=[out_video],
|
| 136 |
+
fn=fn,
|
| 137 |
+
)
|
| 138 |
+
|
| 139 |
+
submit_button.click(
|
| 140 |
+
fn,
|
| 141 |
+
inputs=[in_video, style, aspect_ratio, transfer_duration],
|
| 142 |
+
outputs=[out_video],
|
| 143 |
+
)
|
| 144 |
+
gr.HTML(load_description("end.md"))
|
| 145 |
+
|
| 146 |
+
|
| 147 |
+
if __name__ == "__main__":
|
| 148 |
+
demo.launch(show_error=True, share=False)
|
end.md
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<div>
|
| 2 |
+
<div>
|
| 3 |
+
<div style="display: flex; justify-content: center; align-items: center; text-align: center;">
|
| 4 |
+
<a href="https://discord.gg/cN8geBsBmu"><img src="https://img.shields.io/static/v1?label=Discord&message=Here&color=red"></a>  
|
| 5 |
+
<a href="https://www.pexeldance.com/"><img src="https://img.shields.io/static/v1?label=Official Website&message=Here&color=green"></a>  
|
| 6 |
+
<a ><img src="https://img.shields.io/static/v1?label=Report&message=tobedone&color=blue"></a>
|
| 7 |
+
</div>
|
| 8 |
+
</div>
|
| 9 |
+
</div>
|
| 10 |
+
|
requirements.txt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
gradio
|
| 2 |
+
moviepy
|
| 3 |
+
qiniu
|
sorted.json
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"ClayStyle1": {
|
| 3 |
+
"id": "vid2vid_clay1",
|
| 4 |
+
"thumbnailUrl": "vid2vid/Clay.png.avif"
|
| 5 |
+
},
|
| 6 |
+
"PVC": {
|
| 7 |
+
"id": "vid2vid_pvc",
|
| 8 |
+
"thumbnailUrl": "vid2vid/PVC.jpg.avif"
|
| 9 |
+
},
|
| 10 |
+
"FlatanimeV4-3": {
|
| 11 |
+
"id": "vid2vid_flatanimeV4-3",
|
| 12 |
+
"thumbnailUrl": "vid2vid/F2D.jpg.avif"
|
| 13 |
+
},
|
| 14 |
+
"FlatanimeV4 Delicated": {
|
| 15 |
+
"id": "vid2vid_flatanimeV4-delicated",
|
| 16 |
+
"thumbnailUrl": "vid2vid/suv.png.avif"
|
| 17 |
+
},
|
| 18 |
+
"illustrationV4-1": {
|
| 19 |
+
"id": "vid2vid_illustrationV4-1",
|
| 20 |
+
"thumbnailUrl": "vid2vid/flatCJ.png.avif"
|
| 21 |
+
},
|
| 22 |
+
"Pixels": {
|
| 23 |
+
"id": "vid2vid_pixels",
|
| 24 |
+
"thumbnailUrl": "vid2vid/Pixels.jpg.avif"
|
| 25 |
+
},
|
| 26 |
+
"cutefaceV4 style1": {
|
| 27 |
+
"id": "vid2vid_flatanimeV4-cuteface1",
|
| 28 |
+
"thumbnailUrl": "vid2vid/TY.png.avif"
|
| 29 |
+
},
|
| 30 |
+
"Western Comic": {
|
| 31 |
+
"id": "vid2vid_comic-western",
|
| 32 |
+
"thumbnailUrl": "vid2vid/Western.png.avif"
|
| 33 |
+
},
|
| 34 |
+
"flatanime-gibli": {
|
| 35 |
+
"id": "vid2vid_flatanime-ghibli1",
|
| 36 |
+
"thumbnailUrl": "vid2vid/ghibli1.png.avif"
|
| 37 |
+
},
|
| 38 |
+
"Comic Style1": {
|
| 39 |
+
"id": "vid2vid_comic-style1",
|
| 40 |
+
"thumbnailUrl": "vid2vid/hcomic.png.avif"
|
| 41 |
+
},
|
| 42 |
+
"painting": {
|
| 43 |
+
"id": "vid2vid_painting-chinese",
|
| 44 |
+
"thumbnailUrl": "vid2vid/painting.png.avif"
|
| 45 |
+
},
|
| 46 |
+
"Manga Q": {
|
| 47 |
+
"id": "vid2vid_manga-Q",
|
| 48 |
+
"thumbnailUrl": "vid2vid/symanga.png.avif"
|
| 49 |
+
},
|
| 50 |
+
"IllustrationV4-2": {
|
| 51 |
+
"id": "vid2vid_illustrationV4-2",
|
| 52 |
+
"thumbnailUrl": "vid2vid/flatillustration.png.avif"
|
| 53 |
+
},
|
| 54 |
+
"Flat Anime V4-4": {
|
| 55 |
+
"id": "vid2vid_flatanimeV4-4",
|
| 56 |
+
"thumbnailUrl": "vid2vid/hf.png.avif"
|
| 57 |
+
},
|
| 58 |
+
"Flat Anime V4-2": {
|
| 59 |
+
"id": "vid2vid_flatanimeV4-2",
|
| 60 |
+
"thumbnailUrl": "vid2vid/awp2.png.avif"
|
| 61 |
+
},
|
| 62 |
+
"Color Ink Painting": {
|
| 63 |
+
"id": "vid2vid_colorink-painting",
|
| 64 |
+
"thumbnailUrl": "vid2vid/chinese_ink.png.avif"
|
| 65 |
+
},
|
| 66 |
+
"anime2.5d-style1": {
|
| 67 |
+
"id": "vid2vid_anime2.5d-style1",
|
| 68 |
+
"thumbnailUrl": "vid2vid/RC.png.avif"
|
| 69 |
+
},
|
| 70 |
+
"2.5D Style2": {
|
| 71 |
+
"id": "vid2vid_anime2.5d-style2",
|
| 72 |
+
"thumbnailUrl": "vid2vid/kingmix.png.avif"
|
| 73 |
+
},
|
| 74 |
+
"Ink Painting BW": {
|
| 75 |
+
"id": "vid2vid_ink-painting-bw",
|
| 76 |
+
"thumbnailUrl": "vid2vid/chinese_black_ink_painting.png.avif"
|
| 77 |
+
},
|
| 78 |
+
"IllustrationV4-4": {
|
| 79 |
+
"id": "vid2vid_illustrationV4-4",
|
| 80 |
+
"thumbnailUrl": "vid2vid/japanese.png.avif"
|
| 81 |
+
},
|
| 82 |
+
"Comic BW": {
|
| 83 |
+
"id": "vid2vid_comic-black-white",
|
| 84 |
+
"thumbnailUrl": "vid2vid/black-white-comic.png.avif"
|
| 85 |
+
},
|
| 86 |
+
"flatanime G3": {
|
| 87 |
+
"id": "vid2vid_flatanime-ghibli3",
|
| 88 |
+
"thumbnailUrl": "vid2vid/hm2.png.avif"
|
| 89 |
+
},
|
| 90 |
+
"3D P2": {
|
| 91 |
+
"id": "vid2vid_3d-pixar-v2",
|
| 92 |
+
"thumbnailUrl": "vid2vid/P2.png.avif"
|
| 93 |
+
},
|
| 94 |
+
"Comic Rough": {
|
| 95 |
+
"id": "vid2vid_comic-rough",
|
| 96 |
+
"thumbnailUrl": "vid2vid/jojo.png.avif"
|
| 97 |
+
},
|
| 98 |
+
"Child Crayon Drawing": {
|
| 99 |
+
"id": "vid2vid_drawing-child-crayon1",
|
| 100 |
+
"thumbnailUrl": "vid2vid/child-crayon.png.avif"
|
| 101 |
+
},
|
| 102 |
+
"Porcelain": {
|
| 103 |
+
"id": "vid2vid_porcelain",
|
| 104 |
+
"thumbnailUrl": "vid2vid/vid2vid_porcelain.png.avif"
|
| 105 |
+
},
|
| 106 |
+
"flatanime G2": {
|
| 107 |
+
"id": "vid2vid_flatanime-ghibli2",
|
| 108 |
+
"thumbnailUrl": "vid2vid/hm1.png.avif"
|
| 109 |
+
},
|
| 110 |
+
"Lineart Style1": {
|
| 111 |
+
"id": "vid2vid_lineart-style1",
|
| 112 |
+
"thumbnailUrl": "vid2vid/LineartStyle1.png.avif"
|
| 113 |
+
},
|
| 114 |
+
"3D P1": {
|
| 115 |
+
"id": "vid2vid_3d-pixar",
|
| 116 |
+
"thumbnailUrl": "vid2vid/P1.png.avif"
|
| 117 |
+
},
|
| 118 |
+
"2.5D Style3": {
|
| 119 |
+
"id": "vid2vid_anime2.5d_style3",
|
| 120 |
+
"thumbnailUrl": "vid2vid/ast.png.avif"
|
| 121 |
+
},
|
| 122 |
+
"Hand Drawing": {
|
| 123 |
+
"id": "vid2vid_hand-drawing",
|
| 124 |
+
"thumbnailUrl": "vid2vid/chinese_lineart.png.avif"
|
| 125 |
+
},
|
| 126 |
+
"flatanimeV4-1": {
|
| 127 |
+
"id": "vid2vid_flatanimeV4-1",
|
| 128 |
+
"thumbnailUrl": "vid2vid/V4AWP.jpg.avif"
|
| 129 |
+
},
|
| 130 |
+
"flatanimev1-1": {
|
| 131 |
+
"id": "vid2vid_flatanimev1-1",
|
| 132 |
+
"thumbnailUrl": "vid2vid/animem.png.avif"
|
| 133 |
+
},
|
| 134 |
+
"Toy": {
|
| 135 |
+
"id": "vid2vid_toy",
|
| 136 |
+
"thumbnailUrl": "vid2vid/TOY.jpg.avif"
|
| 137 |
+
},
|
| 138 |
+
"flatanime1": {
|
| 139 |
+
"id": "vid2vid_flatanime1",
|
| 140 |
+
"thumbnailUrl": "vid2vid/aniflat.png.avif"
|
| 141 |
+
},
|
| 142 |
+
"3D-Q": {
|
| 143 |
+
"id": "vid2vid_3dQ",
|
| 144 |
+
"thumbnailUrl": "vid2vid/3dQ.png.avif"
|
| 145 |
+
},
|
| 146 |
+
"3D C": {
|
| 147 |
+
"id": "vid2vid_3dcw1",
|
| 148 |
+
"thumbnailUrl": "vid2vid/3dC.png.avif"
|
| 149 |
+
},
|
| 150 |
+
"Lineart-Bold": {
|
| 151 |
+
"id": "vid2vid_lineart-bold",
|
| 152 |
+
"thumbnailUrl": "vid2vid/Lineart-Bold.png.avif"
|
| 153 |
+
},
|
| 154 |
+
"cutefaceV1": {
|
| 155 |
+
"id": "vid2vid_flatanime-cute-cartoon",
|
| 156 |
+
"thumbnailUrl": "vid2vid/cute-cartoon.png.avif"
|
| 157 |
+
},
|
| 158 |
+
"Flat Anime-Y": {
|
| 159 |
+
"id": "vid2vid_flatanime-Y",
|
| 160 |
+
"thumbnailUrl": "vid2vid/ym.png.avif"
|
| 161 |
+
}
|
| 162 |
+
}
|
title.md
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<div>
|
| 2 |
+
<div>
|
| 3 |
+
<div style="display: flex; justify-content: center; align-items: center; text-align: center; font-size: 40px;">
|
| 4 |
+
<b>🎨 Multi-Style Video-to-Anime Generator</b>
|
| 5 |
+
</div>
|
| 6 |
+
<br>
|
| 7 |
+
<div style="display: flex; justify-content: center; align-items: center; text-align: center;">
|
| 8 |
+
<a href="https://discord.gg/cN8geBsBmu"><img src="https://img.shields.io/static/v1?label=Discord&message=Here&color=red"></a>  
|
| 9 |
+
<a href="https://www.pexeldance.com/"><img src="https://img.shields.io/static/v1?label=Official Website&message=Here&color=green"></a>  
|
| 10 |
+
<a ><img src="https://img.shields.io/static/v1?label=Report&message=tobedone&color=blue"></a>
|
| 11 |
+
</div>
|
| 12 |
+
<br>
|
| 13 |
+
<div style="display: flex; text-align: center; font-size: 14px; padding-right: 300px; ">
|
| 14 |
+
<strong>HF Space by PexelDance.</strong>
|
| 15 |
+
</div>
|
| 16 |
+
<br>
|
| 17 |
+
<div style=" font-size: 14px;">
|
| 18 |
+
<p>1. Select a video clip </p>
|
| 19 |
+
<p>2. Select a style </p>
|
| 20 |
+
<p>3. Select an aspect ratio </p>
|
| 21 |
+
<p>4. click Generate button </p>
|
| 22 |
+
</div>
|
| 23 |
+
</div>
|
| 24 |
+
</div>
|
| 25 |
+
|
utils.py
ADDED
|
@@ -0,0 +1,237 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import requests
|
| 3 |
+
import json
|
| 4 |
+
import time
|
| 5 |
+
from qiniu import put_file
|
| 6 |
+
import tempfile
|
| 7 |
+
import shutil
|
| 8 |
+
import random
|
| 9 |
+
|
| 10 |
+
API_KEY = os.environ['API_KEY']
|
| 11 |
+
|
| 12 |
+
headers = {
|
| 13 |
+
"User-Agent": "PexelDance Sdk/1.0",
|
| 14 |
+
'Authorization': 'Bearer %s' % API_KEY,
|
| 15 |
+
'Content-Type': 'application/json'
|
| 16 |
+
}
|
| 17 |
+
|
| 18 |
+
def get_endpoint():
|
| 19 |
+
hosts = [
|
| 20 |
+
"https://api-01.pexeldance.com",
|
| 21 |
+
"https://api-02.pexeldance.com",
|
| 22 |
+
"https://api-03.pexeldance.com",
|
| 23 |
+
"https://api-04.pexeldance.com",
|
| 24 |
+
"https://api-05.pexeldance.com",
|
| 25 |
+
"https://api-06.pexeldance.com",
|
| 26 |
+
"https://api-07.pexeldance.com",
|
| 27 |
+
"https://api-08.pexeldance.com",
|
| 28 |
+
"https://api-09.pexeldance.com",
|
| 29 |
+
"https://api-10.pexeldance.com",
|
| 30 |
+
# "https://api-11.pexeldance.com",
|
| 31 |
+
# "https://api-12.pexeldance.com",
|
| 32 |
+
# "https://api-13.pexeldance.com",
|
| 33 |
+
# "https://api-14.pexeldance.com",
|
| 34 |
+
# "https://api-15.pexeldance.com",
|
| 35 |
+
# "https://api-16.pexeldance.com",
|
| 36 |
+
# "https://api-17.pexeldance.com",
|
| 37 |
+
# "https://api-18.pexeldance.com",
|
| 38 |
+
# "https://api-19.pexeldance.com",
|
| 39 |
+
# "https://api-20.pexeldance.com",
|
| 40 |
+
]
|
| 41 |
+
return random.choice(hosts)
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
def get_upload_token(extension="mp4"):
|
| 45 |
+
endpoint = get_endpoint()
|
| 46 |
+
url = endpoint + "/api/upload/token"
|
| 47 |
+
|
| 48 |
+
payload = json.dumps({
|
| 49 |
+
"file_ext": extension,
|
| 50 |
+
})
|
| 51 |
+
|
| 52 |
+
response = requests.request("POST", url, headers=headers, data=bytes(payload, "utf-8"))
|
| 53 |
+
if 200<= response.status_code < 300:
|
| 54 |
+
return response.json()
|
| 55 |
+
return None
|
| 56 |
+
|
| 57 |
+
def upload_file(local_file, file_key, token):
|
| 58 |
+
ret, info = put_file(token, file_key, local_file)
|
| 59 |
+
if info.status_code == 200:
|
| 60 |
+
return ret
|
| 61 |
+
else:
|
| 62 |
+
return None
|
| 63 |
+
|
| 64 |
+
def confirm_upload(key, name, hash_, fsize, bucket):
|
| 65 |
+
endpoint = get_endpoint()
|
| 66 |
+
url = endpoint + "/api/upload/confirm"
|
| 67 |
+
|
| 68 |
+
payload = json.dumps({
|
| 69 |
+
"key": key,
|
| 70 |
+
"name": name,
|
| 71 |
+
"hash": hash_,
|
| 72 |
+
"fsize": fsize,
|
| 73 |
+
"bucket": bucket,
|
| 74 |
+
})
|
| 75 |
+
|
| 76 |
+
response = requests.request("POST", url, headers=headers, data=payload)
|
| 77 |
+
if 200<= response.status_code < 300:
|
| 78 |
+
return response.json()
|
| 79 |
+
return None
|
| 80 |
+
|
| 81 |
+
def upload_video(file):
|
| 82 |
+
ext = file.split(".")[-1]
|
| 83 |
+
if not os.path.exists(file):
|
| 84 |
+
return False
|
| 85 |
+
token_res = get_upload_token(ext)
|
| 86 |
+
upload_data = token_res.get('data')
|
| 87 |
+
if not upload_data:
|
| 88 |
+
return False
|
| 89 |
+
upload_token = upload_data.get('token')
|
| 90 |
+
if not upload_token:
|
| 91 |
+
return False
|
| 92 |
+
|
| 93 |
+
bucket_key = upload_data.get('bucket_key')
|
| 94 |
+
if not bucket_key:
|
| 95 |
+
return False
|
| 96 |
+
|
| 97 |
+
ret = upload_file(file, bucket_key, upload_token)
|
| 98 |
+
if not ret:
|
| 99 |
+
return False
|
| 100 |
+
key, name, hash_, fsize, bucket = ret.get('key'), upload_data.get('c_string'), ret.get('hash'), ret.get('fsize'), ret.get('bucket')
|
| 101 |
+
upload_res = confirm_upload(key, name, hash_, fsize, bucket)
|
| 102 |
+
if not upload_res:
|
| 103 |
+
return False
|
| 104 |
+
return upload_res.get('data')
|
| 105 |
+
|
| 106 |
+
def generate(item_id, style_id, width, height, ):
|
| 107 |
+
endpoint = get_endpoint()
|
| 108 |
+
url = endpoint + "/api/job/common"
|
| 109 |
+
payload = json.dumps({
|
| 110 |
+
"user_content": {
|
| 111 |
+
"item_id": item_id,
|
| 112 |
+
"seed": 11111,
|
| 113 |
+
"width": width,
|
| 114 |
+
"height": height
|
| 115 |
+
},
|
| 116 |
+
"unit": 3,
|
| 117 |
+
"use_credit_type": "credit",
|
| 118 |
+
"name": style_id
|
| 119 |
+
})
|
| 120 |
+
response = requests.request("POST", url, headers=headers, data=payload)
|
| 121 |
+
if 200<= response.status_code < 300:
|
| 122 |
+
return response.json()
|
| 123 |
+
else:
|
| 124 |
+
return None
|
| 125 |
+
|
| 126 |
+
def get_job_status(job_id):
|
| 127 |
+
endpoint = get_endpoint()
|
| 128 |
+
url = endpoint + "/api/job"
|
| 129 |
+
payload = json.dumps({
|
| 130 |
+
"id": job_id
|
| 131 |
+
})
|
| 132 |
+
response = requests.request("GET", url, headers=headers, data=payload)
|
| 133 |
+
if 200<= response.status_code < 300:
|
| 134 |
+
return response.json()
|
| 135 |
+
return None
|
| 136 |
+
|
| 137 |
+
def get_item_url(_id):
|
| 138 |
+
endpoint = get_endpoint()
|
| 139 |
+
url = endpoint + "/api/download_item"
|
| 140 |
+
payload = json.dumps({
|
| 141 |
+
"key_id": [
|
| 142 |
+
_id
|
| 143 |
+
]
|
| 144 |
+
})
|
| 145 |
+
response = requests.request("POST", url, headers=headers, data=payload)
|
| 146 |
+
if 200<= response.status_code < 300:
|
| 147 |
+
return response.json()
|
| 148 |
+
return None
|
| 149 |
+
|
| 150 |
+
def get_result(job_id):
|
| 151 |
+
endpoint = get_endpoint()
|
| 152 |
+
url = endpoint + "/api/item/job_id"
|
| 153 |
+
payload = json.dumps({
|
| 154 |
+
"job_id": job_id
|
| 155 |
+
})
|
| 156 |
+
response = requests.request("GET", url, headers=headers, data=payload)
|
| 157 |
+
if 200<= response.status_code < 300:
|
| 158 |
+
return response.json()
|
| 159 |
+
return None
|
| 160 |
+
|
| 161 |
+
def download_file(url):
|
| 162 |
+
response = requests.get(url, stream=True)
|
| 163 |
+
if response.status_code == 200:
|
| 164 |
+
tmpfile = tempfile.NamedTemporaryFile(delete=False)
|
| 165 |
+
tmpfile.close()
|
| 166 |
+
|
| 167 |
+
with open(tmpfile.name, 'wb') as f:
|
| 168 |
+
shutil.copyfileobj(response.raw, f)
|
| 169 |
+
|
| 170 |
+
return tmpfile.name
|
| 171 |
+
else:
|
| 172 |
+
return None
|
| 173 |
+
|
| 174 |
+
def processing(in_video, width, height, style_id,transfer_duration):
|
| 175 |
+
videoRes = upload_video(in_video)
|
| 176 |
+
if not videoRes:
|
| 177 |
+
return None
|
| 178 |
+
videoId = videoRes.get('id')
|
| 179 |
+
if not videoId:
|
| 180 |
+
return None
|
| 181 |
+
|
| 182 |
+
req_access = False
|
| 183 |
+
try_times = 1000
|
| 184 |
+
for i in range(try_times):
|
| 185 |
+
generate_result = generate(videoId, style_id, width, height)
|
| 186 |
+
if not generate_result:
|
| 187 |
+
time.sleep(8)
|
| 188 |
+
continue
|
| 189 |
+
jobInfo = generate_result.get('data')
|
| 190 |
+
if not jobInfo:
|
| 191 |
+
time.sleep(8)
|
| 192 |
+
continue
|
| 193 |
+
job_id = jobInfo.get("job_id")
|
| 194 |
+
if job_id:
|
| 195 |
+
req_access = True
|
| 196 |
+
break
|
| 197 |
+
if not req_access:
|
| 198 |
+
raise "too many requests"
|
| 199 |
+
|
| 200 |
+
|
| 201 |
+
while True:
|
| 202 |
+
jobStatusInfo = get_job_status(job_id)
|
| 203 |
+
js = jobStatusInfo.get('data')
|
| 204 |
+
if js is None:
|
| 205 |
+
return None
|
| 206 |
+
if js.get('status') == "finished":
|
| 207 |
+
break
|
| 208 |
+
elif js.get('status') == "failed":
|
| 209 |
+
return None
|
| 210 |
+
time.sleep(10)
|
| 211 |
+
|
| 212 |
+
result = get_result(job_id)
|
| 213 |
+
if not result:
|
| 214 |
+
return None
|
| 215 |
+
res_data = result.get('data')
|
| 216 |
+
if not res_data:
|
| 217 |
+
return None
|
| 218 |
+
li = res_data.get('list')
|
| 219 |
+
if len(li) == 0:
|
| 220 |
+
return None
|
| 221 |
+
jobRes = li[0]
|
| 222 |
+
item_id = jobRes.get('id')
|
| 223 |
+
if not item_id:
|
| 224 |
+
return None
|
| 225 |
+
itemDes = get_item_url(item_id)
|
| 226 |
+
itemData = itemDes.get('data')
|
| 227 |
+
if not itemData:
|
| 228 |
+
return None
|
| 229 |
+
signed_urls = itemData.get('signed_urls')
|
| 230 |
+
if len(signed_urls) == 0:
|
| 231 |
+
return None
|
| 232 |
+
item_url = signed_urls[0]
|
| 233 |
+
|
| 234 |
+
file_path = download_file(item_url)
|
| 235 |
+
if not file_path:
|
| 236 |
+
return None
|
| 237 |
+
return file_path
|
vid2vid/3dC.png.avif
ADDED
|
vid2vid/3dM.png.avif
ADDED
|
vid2vid/3dQ.png.avif
ADDED
|
vid2vid/Clay.png.avif
ADDED
|
vid2vid/F2D.jpg.avif
ADDED
|
vid2vid/G0.png.avif
ADDED
|
vid2vid/Lineart-Bold.png.avif
ADDED
|
vid2vid/LineartStyle1.png.avif
ADDED
|
vid2vid/P1.png.avif
ADDED
|
vid2vid/P2.png.avif
ADDED
|
vid2vid/PVC.jpg.avif
ADDED
|
vid2vid/Pixels.jpg.avif
ADDED
|
|
vid2vid/RC.png.avif
ADDED
|
vid2vid/TA.png.avif
ADDED
|
vid2vid/TOY.jpg.avif
ADDED
|
vid2vid/TY.png.avif
ADDED
|
vid2vid/TY2.png.avif
ADDED
|
vid2vid/V4AWP.jpg.avif
ADDED
|
vid2vid/V4AWP.png.avif
ADDED
|
vid2vid/Western.png.avif
ADDED
|
vid2vid/aniflat.png.avif
ADDED
|
vid2vid/animeK.png.avif
ADDED
|
vid2vid/animem.png.avif
ADDED
|
vid2vid/ast.png.avif
ADDED
|
vid2vid/awp2.png.avif
ADDED
|
vid2vid/black-white-comic.png.avif
ADDED
|
vid2vid/child-crayon.png.avif
ADDED
|
vid2vid/chinese_black_ink_painting.png.avif
ADDED
|
vid2vid/chinese_ink.png.avif
ADDED
|
vid2vid/chinese_lineart.png.avif
ADDED
|
vid2vid/clay2.png.avif
ADDED
|
vid2vid/cute-cartoon.png.avif
ADDED
|
vid2vid/flatCJ.png.avif
ADDED
|
vid2vid/flatanime-Q.png.avif
ADDED
|
vid2vid/flatillustration.png.avif
ADDED
|
vid2vid/flower.png.avif
ADDED
|
vid2vid/ghibli1.png.avif
ADDED
|
vid2vid/hcomic.png.avif
ADDED
|
vid2vid/hf.png.avif
ADDED
|
vid2vid/hm1.png.avif
ADDED
|
vid2vid/hm2.png.avif
ADDED
|
vid2vid/japanese.png.avif
ADDED
|