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
![]() |