boheng.xie commited on
Commit
587c188
·
1 Parent(s): f47f29b
Files changed (7) hide show
  1. README.md +1 -1
  2. app.py +377 -0
  3. configs/infer.yaml +46 -0
  4. download_models.py +83 -0
  5. packages.txt +1 -0
  6. requirements.txt +30 -0
  7. runtime.txt +1 -0
README.md CHANGED
@@ -2,7 +2,7 @@
2
  title: Follow Your Emoji
3
  emoji: 👁
4
  colorFrom: indigo
5
- colorTo: blue
6
  sdk: gradio
7
  sdk_version: 5.29.0
8
  app_file: app.py
 
2
  title: Follow Your Emoji
3
  emoji: 👁
4
  colorFrom: indigo
5
+ colorTo: green
6
  sdk: gradio
7
  sdk_version: 5.29.0
8
  app_file: app.py
app.py ADDED
@@ -0,0 +1,377 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import os
3
+ import numpy as np
4
+ import yaml
5
+ import cv2
6
+ import zipfile
7
+ from utils import process_video, get_npy_files, get_frame_count, process_image
8
+ from infer_script import run_inference
9
+
10
+ import time
11
+ import datetime
12
+ import shutil
13
+
14
+ import imageio
15
+ from media_pipe.draw_util import FaceMeshVisualizer
16
+
17
+ from download_models import download
18
+
19
+ # Download models and check for exists
20
+ download()
21
+
22
+ PROCESSED_VIDEO_DIR = './processed_videos'
23
+ TEMP_DIR = './temp'
24
+ INFER_CONFIG_PATH = './configs/infer.yaml'
25
+ MODEL_PATH = './ckpt_models/ckpts'
26
+ OUTPUT_PATH = './output'
27
+
28
+ def load_config():
29
+ with open(INFER_CONFIG_PATH, 'r') as file:
30
+ return yaml.safe_load(file)
31
+
32
+ def save_config(config):
33
+ with open(INFER_CONFIG_PATH, 'w') as file:
34
+ yaml.dump(config, file)
35
+
36
+ config = load_config()
37
+
38
+ def get_video_fps(video_path):
39
+ video = cv2.VideoCapture(video_path)
40
+ fps = video.get(cv2.CAP_PROP_FPS)
41
+ video.release()
42
+ return int(fps)
43
+
44
+ def update_npy_choices():
45
+ npy_files = get_npy_files(PROCESSED_VIDEO_DIR)
46
+ return gr.update(choices=["None"] + npy_files)
47
+
48
+ def create_gif_from_npy(npy_path, gif_path):
49
+ face_results = np.load(npy_path, allow_pickle=True)
50
+ vis = FaceMeshVisualizer(forehead_edge=False)
51
+
52
+ frames = []
53
+ for face_result in face_results:
54
+ width = face_result['width']
55
+ height = face_result['height']
56
+ lmks = face_result['lmks'].astype(np.float32)
57
+ frame = vis.draw_landmarks((width, height), lmks, normed=True)
58
+ frames.append(frame)
59
+
60
+ imageio.mimsave(gif_path, frames, 'GIF', duration=0.2, loop=0)
61
+ return gif_path
62
+
63
+ def show_gif_for_npy(npy_file, video_path):
64
+ if npy_file and npy_file != "None":
65
+ npy_path = npy_file
66
+ elif video_path:
67
+ video_name = os.path.splitext(os.path.basename(video_path))[0]
68
+ npy_path = os.path.join(PROCESSED_VIDEO_DIR if input_video_save.value else TEMP_DIR, video_name, f"{video_name}_mppose.npy")
69
+ else:
70
+ return None, None, "No NPY file or video selected"
71
+
72
+ if not os.path.exists(npy_path):
73
+ return None, None, "NPY file not found"
74
+
75
+ try:
76
+ gif_path = os.path.join(os.path.dirname(npy_path), f"{os.path.splitext(os.path.basename(npy_path))[0]}_preview.gif")
77
+ gif_path_align = os.path.join(os.path.dirname(npy_path), f"{os.path.splitext(os.path.basename(npy_path))[0]}_aligned.gif")
78
+ create_gif_from_npy(npy_path, gif_path)
79
+ return gif_path,gif_path_align, "GIF created and displayed"
80
+ except Exception as e:
81
+ return None, None, f"Failed to create GIF: {str(e)}"
82
+
83
+
84
+ def process_input_video(video, save_to_processed):
85
+ if video is None:
86
+ return "No video uploaded", None, gr.update(), gr.update()
87
+
88
+ video_name = os.path.splitext(os.path.basename(video))[0]
89
+
90
+ if save_to_processed:
91
+ save_dir = os.path.join(PROCESSED_VIDEO_DIR, video_name)
92
+ else:
93
+ save_dir = os.path.join(TEMP_DIR, video_name)
94
+
95
+ os.makedirs(save_dir, exist_ok=True)
96
+
97
+ npy_path, frame_count = process_video(video, save_dir)
98
+ frame_count = frame_count - 1
99
+ fps = get_video_fps(video)
100
+
101
+ return (f"Video processed. NPY file saved at {npy_path}. Original FPS: {fps}",
102
+ npy_path,
103
+ gr.update(maximum=frame_count, value=frame_count),
104
+ gr.update(value=f"Reference video FPS: {fps}"))
105
+
106
+ def update_frame_count(npy_file):
107
+ if npy_file is None or npy_file == "None":
108
+ return gr.update()
109
+ frame_count = get_frame_count(npy_file)
110
+ return gr.update(maximum=frame_count, value=frame_count)
111
+
112
+ def update_gif_on_video_change(video):
113
+ if video:
114
+ gif_path,gif_path_align, status = show_gif_for_npy(None, video)
115
+ return gif_path,gif_path_align, status
116
+ return None, None, "No video selected"
117
+
118
+ def toggle_fps_slider(use_custom):
119
+ return gr.update(interactive=use_custom)
120
+
121
+ def crop_face(image_path, should_crop_face, npy_file, video_path, expand_x, expand_y, offset_x, offset_y):
122
+ if not should_crop_face:
123
+ return image_path, "Face cropping not requested"
124
+
125
+ if npy_file and npy_file != "None":
126
+ npy_path = npy_file
127
+ elif video_path:
128
+ video_name = os.path.splitext(os.path.basename(video_path))[0]
129
+ npy_path = os.path.join(PROCESSED_VIDEO_DIR, video_name, f"{video_name}_mppose.npy")
130
+ if not os.path.exists(npy_path):
131
+ npy_path = os.path.join(TEMP_DIR, video_name, f"{video_name}_mppose.npy")
132
+ else:
133
+ return image_path, "No NPY file or video selected for face cropping"
134
+
135
+ if not os.path.exists(npy_path):
136
+ return image_path, "NPY file not found for face cropping"
137
+
138
+ save_dir = os.path.dirname(npy_path)
139
+ cropped_image_path, motion_path = process_image(image_path, npy_path, save_dir, expand_x, expand_y, offset_x, offset_y)
140
+
141
+ if cropped_image_path:
142
+ return cropped_image_path, "Face cropped successfully"
143
+ else:
144
+ return image_path, "Face cropping failed"
145
+
146
+ def preview_crop(image_path, npy_file, video_path, expand_x, expand_y, offset_x, offset_y):
147
+ if not image_path:
148
+ return None,None, "No image uploaded"
149
+
150
+ if npy_file and npy_file != "None":
151
+ npy_path = npy_file
152
+ elif video_path:
153
+ video_name = os.path.splitext(os.path.basename(video_path))[0]
154
+ npy_path = os.path.join(PROCESSED_VIDEO_DIR, video_name, f"{video_name}_mppose.npy")
155
+ if not os.path.exists(npy_path):
156
+ npy_path = os.path.join(TEMP_DIR, video_name, f"{video_name}_mppose.npy")
157
+ else:
158
+ return None,None, "No NPY file or video selected for face cropping"
159
+
160
+ if not os.path.exists(npy_path):
161
+ return None,None, "NPY file not found for face cropping"
162
+
163
+ save_dir = TEMP_DIR
164
+ # Create if not exists
165
+ os.makedirs(save_dir, exist_ok=True)
166
+ cropped_image_path, motion_path = process_image(image_path, npy_path, save_dir, expand_x, expand_y, offset_x, offset_y)
167
+
168
+ if cropped_image_path:
169
+ return cropped_image_path,motion_path, "Crop preview generated"
170
+ else:
171
+ return None,None, "Failed to generate crop preview"
172
+
173
+ def generate_video(input_img, should_crop_face, expand_x, expand_y, offset_x, offset_y, input_video_type, input_video, input_npy_select, input_npy, input_video_frames,
174
+ settings_steps, settings_cfg_scale, settings_seed, resolution_w, resolution_h,
175
+ model_step, custom_output_path, use_custom_fps, output_fps, callback_steps, context_frames, context_stride, context_overlap, context_batch_size, anomaly_action,intropolate_factor):
176
+ config['resolution_w'] = resolution_w
177
+ config['resolution_h'] = resolution_h
178
+ config['video_length'] = input_video_frames
179
+ save_config(config)
180
+
181
+ if input_video_type == "video":
182
+ video_name = os.path.splitext(os.path.basename(input_video))[0]
183
+ lmk_path = os.path.join(PROCESSED_VIDEO_DIR if input_video_save.value else TEMP_DIR, video_name, f"{video_name}_mppose.npy")
184
+ if not use_custom_fps:
185
+ output_fps = 7
186
+ else:
187
+ if input_npy_select != "None":
188
+ lmk_path = input_npy_select
189
+ else:
190
+ lmk_path = input_npy
191
+ video_name = os.path.splitext(os.path.basename(lmk_path))[0]
192
+ if not use_custom_fps:
193
+ output_fps = 7 # default FPS
194
+
195
+ timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
196
+ output_folder = f"{video_name}_{timestamp}"
197
+
198
+ if custom_output_path:
199
+ output_path = os.path.join(custom_output_path, output_folder)
200
+ else:
201
+ output_path = os.path.join(OUTPUT_PATH, output_folder)
202
+
203
+ os.makedirs(output_path, exist_ok=True)
204
+
205
+ if should_crop_face:
206
+ cropped_image_path, crop_status = crop_face(input_img, should_crop_face, input_npy_select if input_video_type == "npy" else None, input_video if input_video_type == "video" else None, expand_x, expand_y, offset_x, offset_y)
207
+ print(crop_status)
208
+
209
+ if cropped_image_path and os.path.exists(cropped_image_path):
210
+ cropped_face_in_result = os.path.join(output_path, "cropped_face.png")
211
+ shutil.copy(cropped_image_path, cropped_face_in_result)
212
+ print(f"Cropped face saved in result folder: {cropped_face_in_result}")
213
+
214
+ input_img = cropped_image_path
215
+
216
+ status, oo_video_path, all_video_path = run_inference(
217
+ config_path=INFER_CONFIG_PATH,
218
+ model_path=MODEL_PATH,
219
+ input_path=input_img,
220
+ lmk_path=lmk_path,
221
+ output_path=output_path,
222
+ model_step=model_step,
223
+ seed=settings_seed,
224
+ resolution_w=resolution_w,
225
+ resolution_h=resolution_h,
226
+ video_length=input_video_frames,
227
+ num_inference_steps=settings_steps,
228
+ guidance_scale=settings_cfg_scale,
229
+ output_fps=output_fps,
230
+ callback_steps=callback_steps,
231
+ context_frames=context_frames,
232
+ context_stride=context_stride,
233
+ context_overlap=context_overlap,
234
+ context_batch_size=context_batch_size,
235
+ anomaly_action=anomaly_action,
236
+ interpolation_factor=intropolate_factor
237
+ )
238
+
239
+
240
+ frames_archive = None
241
+ frames_dir = os.path.join(output_path, f"frames")
242
+ if os.path.exists(frames_dir):
243
+ archive_path = os.path.join(output_path, f"frames.zip")
244
+ with zipfile.ZipFile(archive_path, 'w') as zipf:
245
+ for root, dirs, files in os.walk(frames_dir):
246
+ for file in files:
247
+ zipf.write(os.path.join(root, file),
248
+ os.path.relpath(os.path.join(root, file),
249
+ os.path.join(frames_dir, '..')))
250
+ frames_archive = archive_path
251
+ print(f"The archive has been created: {archive_path}")
252
+ else:
253
+ print(f"Directory with frames not found: {frames_dir}")
254
+
255
+ return status, oo_video_path, all_video_path, frames_archive
256
+
257
+ with gr.Blocks() as demo:
258
+ gr.Markdown("# FollowYourEmoji Webui")
259
+
260
+ with gr.Row():
261
+ with gr.Column(scale=1):
262
+ input_img = gr.Image(label="Upload reference image", type="filepath", height=500)
263
+
264
+ crop_face_checkbox = gr.Checkbox(label="Crop face according to video",info="If your picture is too far away or the face doesn't fit you can use cropping, you can see a preview in the tab below", value=False)
265
+ with gr.Accordion("Face Cropping", open=False):
266
+ expand_x = gr.Slider(label="Expand X", minimum=0.5, maximum=5.0, value=1.2, step=0.01)
267
+ expand_y = gr.Slider(label="Expand Y", minimum=0.5, maximum=5.0, value=1.2, step=0.01)
268
+ offset_x = gr.Slider(label="Offset X", minimum=-1, maximum=1, value=0.0, step=0.01)
269
+ offset_y = gr.Slider(label="Offset Y", minimum=-1, maximum=1, value=0.0, step=0.01)
270
+
271
+ preview_crop_btn = gr.Button(value="Preview Crop")
272
+ with gr.Row():
273
+ crop_preview = gr.Image(label="Crop Preview", height=300)
274
+ crop_preview_motion = gr.Image(label="Preview motion Crop", height=300)
275
+
276
+ with gr.Accordion("Input Video", open=True):
277
+ input_video_type = gr.Radio(label="Input reference video type",info="You can either upload the video through the interface or use an already compiled npy file", choices=["video","npy"], value="video")
278
+
279
+ with gr.Group() as video_group:
280
+ input_video = gr.Video(label="Upload reference video", height=500)
281
+ input_video_save = gr.Checkbox(label="Save video to processed video folder", value=True)
282
+
283
+ with gr.Group(visible=False) as npy_group:
284
+ input_npy_select = gr.Dropdown(label="Select from processed video folder", choices=["None"], value="None")
285
+ input_npy_refresh = gr.Button(value="Update NPY list")
286
+ input_npy = gr.File(file_types=[".npy"], label="Upload preprocessed video in .npy")
287
+ with gr.Accordion("Animation Preview",open=False):
288
+ show_gif_btn = gr.Button(value="Show Animation preview")
289
+ with gr.Row():
290
+ gif_output = gr.Image(label="GIF Preview", height=300)
291
+ gif_output_align = gr.Image(label="Aligned GIF Preview", height=300)
292
+
293
+ with gr.Accordion("Animation Settings", open=True):
294
+ input_video_frames = gr.Slider(label="Video frames", minimum=1, maximum=30, value=30, step=1)
295
+ settings_steps = gr.Slider(label="Steps", minimum=1, maximum=200, value=30)
296
+ settings_cfg_scale = gr.Slider(label="CFG scale", minimum=0.1, maximum=20, value=3.5, step=0.1)
297
+ settings_seed = gr.Slider(minimum=0, maximum=1000, value=42, step=1, label="Seed")
298
+ intropolate_factor = gr.Slider(label="Intropolate Factor Frames",info="This is the number of frames to interpolate between the frames", minimum=1, maximum=50, value=1, step=1)
299
+
300
+ use_custom_fps = gr.Checkbox(label="Use custom FPS",info="By default the FPS is set to 7", value=True)
301
+ with gr.Row():
302
+ output_fps = gr.Slider(label="Output FPS",info="if you upload video fps slider updates to video fps", minimum=1, maximum=240, value=15, step=1)
303
+ output_fps_info = gr.Label(value="This will be the FPS information of the video you uploaded")
304
+
305
+ with gr.Accordion("Generation Settings", open=True):
306
+ context_frames = gr.Slider(label="Context Frames", minimum=1, maximum=50, value=24, step=1)
307
+ context_stride = gr.Slider(label="Context Stride", minimum=1, maximum=10, value=1, step=1)
308
+ context_overlap = gr.Slider(label="Context Overlap", minimum=0, maximum=10, value=4, step=1)
309
+ context_batch_size = gr.Slider(label="Context Batch Size", minimum=1, maximum=10, value=1, step=1)
310
+ callback_steps = gr.Slider(label="Callback Steps", minimum=1, maximum=50, value=1, step=1)
311
+
312
+ with gr.Accordion("Advanced Settings", open=False):
313
+ resolution_w = gr.Slider(label="Resolution Width", minimum=64, maximum=1024, value=config['resolution_w'], step=64)
314
+ resolution_h = gr.Slider(label="Resolution Height", minimum=64, maximum=1024, value=config['resolution_h'], step=64)
315
+ model_step = gr.Slider(label="Model Step", value=0, minimum=0, maximum=100)
316
+ custom_output_path = gr.Textbox(label="Custom Output Path", placeholder="Leave empty for default")
317
+ anomaly_action = gr.Radio(label="Anomaly Action",info="Sometimes a bad frame can slip through and this function will detect it and do what you specify", choices=["none", "remove"], value="none")
318
+
319
+ with gr.Column(scale=1):
320
+ result_status = gr.Label(value="Status")
321
+ result_video = gr.Video(label="Result Video (oo)", interactive=False, height=500)
322
+ result_video_2 = gr.Video(label="Result Video (all)", interactive=False, height=500)
323
+ result_btn = gr.Button(value="Generate Video")
324
+ frames_output = gr.File(label="Frames Archive ( You'll get an archive with all the frames )")
325
+
326
+ input_video_type.change(
327
+ fn=lambda x: (gr.update(visible=(x=="video")), gr.update(visible=(x=="npy"))),
328
+ inputs=[input_video_type],
329
+ outputs=[video_group, npy_group]
330
+ )
331
+
332
+ input_npy_refresh.click(fn=update_npy_choices, outputs=[input_npy_select])
333
+
334
+ input_video.change(
335
+ fn=process_input_video,
336
+ inputs=[input_video, input_video_save],
337
+ outputs=[result_status, input_npy, input_video_frames, output_fps_info]
338
+ )
339
+
340
+ input_npy_select.change(fn=update_frame_count, inputs=[input_npy_select], outputs=[input_video_frames])
341
+ input_npy.change(fn=update_frame_count, inputs=[input_npy], outputs=[input_video_frames])
342
+
343
+ show_gif_btn.click(fn=show_gif_for_npy, inputs=[input_npy_select, input_video], outputs=[gif_output, gif_output_align, result_status])
344
+
345
+ input_video.change(
346
+ fn=update_gif_on_video_change,
347
+ inputs=[input_video],
348
+ outputs=[gif_output,gif_output_align, result_status]
349
+ )
350
+
351
+ use_custom_fps.change(fn=toggle_fps_slider, inputs=[use_custom_fps], outputs=[output_fps])
352
+
353
+ preview_crop_btn.click(
354
+ fn=preview_crop,
355
+ inputs=[input_img, input_npy_select, input_video, expand_x, expand_y, offset_x, offset_y],
356
+ outputs=[crop_preview,crop_preview_motion, result_status]
357
+ )
358
+
359
+ result_btn.click(
360
+ fn=generate_video,
361
+ inputs=[input_img, crop_face_checkbox, expand_x, expand_y, offset_x, offset_y, input_video_type, input_video, input_npy_select, input_npy, input_video_frames,
362
+ settings_steps, settings_cfg_scale, settings_seed, resolution_w, resolution_h,
363
+ model_step, custom_output_path, use_custom_fps, output_fps, callback_steps, context_frames, context_stride, context_overlap, context_batch_size, anomaly_action,intropolate_factor],
364
+ outputs=[result_status, result_video, result_video_2, frames_output]
365
+ )
366
+
367
+ if __name__ == "__main__":
368
+ import argparse
369
+
370
+ parser = argparse.ArgumentParser()
371
+ parser.add_argument("--share", action="store_true", help="Enable sharing")
372
+ args = parser.parse_args()
373
+
374
+ share = args.share
375
+
376
+ demo.queue()
377
+ demo.launch(inbrowser=True, share=share)
configs/infer.yaml ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ base_model_path: ./ckpt_models/base/unet
2
+ enable_xformers_memory_efficient_attention: true
3
+ enable_zero_snr: true
4
+ image_encoder_path: ./ckpt_models/base/image_encoder
5
+ init_checkpoint: ''
6
+ init_num: 0
7
+ model:
8
+ referencenet_additional_kwargs:
9
+ info_mode: addRefImg
10
+ unet_additional_kwargs:
11
+ attention_mode: SpatialAtten
12
+ motion_module_decoder_only: false
13
+ motion_module_kwargs:
14
+ attention_block_types:
15
+ - Temporal_Self
16
+ - Temporal_Self
17
+ num_attention_heads: 8
18
+ num_transformer_block: 1
19
+ temporal_attention_dim_div: 1
20
+ temporal_position_encoding: true
21
+ temporal_position_encoding_max_len: 32
22
+ motion_module_mid_block: true
23
+ motion_module_resolutions:
24
+ - 1
25
+ - 2
26
+ - 4
27
+ - 8
28
+ motion_module_type: Vanilla
29
+ unet_use_cross_frame_attention: false
30
+ unet_use_temporal_attention: false
31
+ use_inflated_groupnorm: true
32
+ use_motion_module: true
33
+ motion_module_path: ./ckpt_models/base/animatediff/mm_sd_v15_v2.ckpt
34
+ resolution_h: 512
35
+ resolution_w: 512
36
+ scheduler:
37
+ beta_end: 0.012
38
+ beta_schedule: scaled_linear
39
+ beta_start: 0.00085
40
+ clip_sample: false
41
+ num_train_timesteps: 1000
42
+ steps_offset: 1
43
+ seed: 12580
44
+ vae_model_path: ./ckpt_models/base/vae
45
+ video_length: 97
46
+ weight_dtype: fp16
download_models.py ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import requests # 平台预装
3
+ from tqdm import tqdm # 平台预装
4
+
5
+ def create_directory(path):
6
+ if not os.path.exists(path):
7
+ os.makedirs(path)
8
+
9
+ def download_file(url, filepath):
10
+ response = requests.get(url, stream=True)
11
+ total_size = int(response.headers.get('content-length', 0))
12
+
13
+ with open(filepath, 'wb') as file, tqdm(
14
+ desc=filepath,
15
+ total=total_size,
16
+ unit='iB',
17
+ unit_scale=True,
18
+ unit_divisor=1024,
19
+ ) as progress_bar:
20
+ for data in response.iter_content(chunk_size=1024):
21
+ size = file.write(data)
22
+ progress_bar.update(size)
23
+
24
+ def verify_file(filepath):
25
+ if not os.path.exists(filepath):
26
+ return False
27
+
28
+ if filepath.endswith(('.bin', '.pth', '.ckpt', '.safetensors')):
29
+ if os.path.getsize(filepath) < 1000000: # Less than 1 MB
30
+ return False
31
+ elif filepath.endswith('.json'):
32
+ try:
33
+ with open(filepath, 'r') as f:
34
+ f.read()
35
+ except:
36
+ return False
37
+
38
+ return True
39
+
40
+ def download_and_verify(url, filepath):
41
+ max_attempts = 3
42
+ for attempt in range(max_attempts):
43
+ try:
44
+ if not verify_file(filepath):
45
+ print(f"Downloading {filepath}...")
46
+ download_file(url, filepath)
47
+
48
+ if verify_file(filepath):
49
+ print(f"File {filepath} successfully downloaded and verified.")
50
+ return True
51
+ else:
52
+ print(f"File {filepath} failed verification. Attempt {attempt + 1} of {max_attempts}.")
53
+ except Exception as e:
54
+ print(f"Error downloading {filepath}: {str(e)}. Attempt {attempt + 1} of {max_attempts}.")
55
+
56
+ print(f"Failed to download file {filepath} after {max_attempts} attempts.")
57
+ return False
58
+
59
+ def download():
60
+ base_dir = "ckpt_models"
61
+ create_directory(base_dir)
62
+
63
+ files = {
64
+ "base/vae/config.json": "https://huggingface.co/daswer123/FollowYourEmoji_BaseModelPack/resolve/main/vae/config.json?download=true",
65
+ "base/vae/diffusion_pytorch_model.bin": "https://huggingface.co/daswer123/FollowYourEmoji_BaseModelPack/resolve/main/vae/diffusion_pytorch_model.bin?download=true",
66
+ "base/vae/diffusion_pytorch_model.safetensors": "https://huggingface.co/daswer123/FollowYourEmoji_BaseModelPack/resolve/main/vae/diffusion_pytorch_model.safetensors?download=true",
67
+ "base/unet/config.json": "https://huggingface.co/daswer123/FollowYourEmoji_BaseModelPack/resolve/main/unet/config.json?download=true",
68
+ "base/unet/diffusion_pytorch_model.bin": "https://huggingface.co/daswer123/FollowYourEmoji_BaseModelPack/resolve/main/unet/diffusion_pytorch_model.bin?download=true",
69
+ "base/image_encoder/config.json": "https://huggingface.co/daswer123/FollowYourEmoji_BaseModelPack/resolve/main/image_encoder/config.json?download=true",
70
+ "base/image_encoder/pytorch_model.bin": "https://huggingface.co/daswer123/FollowYourEmoji_BaseModelPack/resolve/main/image_encoder/pytorch_model.bin?download=true",
71
+ "base/animatediff/mm_sd_v15_v2.ckpt": "https://huggingface.co/daswer123/FollowYourEmoji_BaseModelPack/resolve/main/animatediff/mm_sd_v15_v2.ckpt?download=true",
72
+ "ckpts/lmk_guider.pth": "https://huggingface.co/YueMafighting/FollowYourEmoji/resolve/main/ckpts/lmk_guider.pth?download=true",
73
+ "ckpts/referencenet.pth": "https://huggingface.co/YueMafighting/FollowYourEmoji/resolve/main/ckpts/referencenet.pth?download=true",
74
+ "ckpts/unet.pth": "https://huggingface.co/YueMafighting/FollowYourEmoji/resolve/main/ckpts/unet.pth?download=true"
75
+ }
76
+
77
+ for file_path, url in files.items():
78
+ full_path = os.path.join(base_dir, file_path)
79
+ create_directory(os.path.dirname(full_path))
80
+ download_and_verify(url, full_path)
81
+
82
+ if __name__ == "__main__":
83
+ download()
packages.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ git-lfs
requirements.txt ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ decord==0.6.0
2
+ easydict==1.10
3
+ einops==0.4.1
4
+ imageio==2.33.0
5
+ numpy==1.23.5
6
+ onnx==1.16.1
7
+ onnxruntime-gpu==1.14.0
8
+ open-clip-torch==2.26.1
9
+ opencv-python==4.8.1.78
10
+ Pillow==9.5.0
11
+ tensorboard==2.14.0
12
+ torch==2.1.1
13
+ torchvision==0.16.1
14
+ torchaudio==2.1.1
15
+ onnxruntime
16
+ matplotlib
17
+ imageio[ffmpeg]
18
+ imageio[pyav]
19
+ omegaconf
20
+ transformers
21
+ accelerate
22
+ mediapipe==0.10.13
23
+ protobuf==4.25.3
24
+ xformers==0.0.23
25
+ gradio
26
+ scikit-image
27
+ # extra dependencies
28
+ torch==2.1.1
29
+ torchaudio==2.1.1
30
+ deepspeed==0.13.1
runtime.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ python-3.10