Files changed (1) hide show
  1. facefusion/core.py +517 -445
facefusion/core.py CHANGED
@@ -1,445 +1,517 @@
1
- import shutil
2
- import signal
3
- import sys
4
- from time import time
5
-
6
- import numpy
7
-
8
- from facefusion import content_analyser, face_classifier, face_detector, face_landmarker, face_masker, face_recognizer, logger, process_manager, state_manager, voice_extractor, wording
9
- from facefusion.args import apply_args, collect_job_args, reduce_step_args
10
- from facefusion.common_helper import get_first
11
- from facefusion.content_analyser import analyse_image, analyse_video
12
- from facefusion.download import conditional_download_hashes, conditional_download_sources
13
- from facefusion.exit_helper import conditional_exit, graceful_exit, hard_exit
14
- from facefusion.face_analyser import get_average_face, get_many_faces, get_one_face
15
- from facefusion.face_selector import sort_and_filter_faces
16
- from facefusion.face_store import append_reference_face, clear_reference_faces, get_reference_faces
17
- from facefusion.ffmpeg import copy_image, extract_frames, finalize_image, merge_video, replace_audio, restore_audio
18
- from facefusion.filesystem import filter_audio_paths, is_image, is_video, list_directory, resolve_relative_path
19
- from facefusion.jobs import job_helper, job_manager, job_runner
20
- from facefusion.jobs.job_list import compose_job_list
21
- from facefusion.memory import limit_system_memory
22
- from facefusion.processors.core import get_processors_modules
23
- from facefusion.program import create_program
24
- from facefusion.program_helper import validate_args
25
- from facefusion.statistics import conditional_log_statistics
26
- from facefusion.temp_helper import clear_temp_directory, create_temp_directory, get_temp_file_path, get_temp_frame_paths, move_temp_file
27
- from facefusion.typing import Args, ErrorCode
28
- from facefusion.vision import get_video_frame, pack_resolution, read_image, read_static_images, restrict_image_resolution, restrict_video_fps, restrict_video_resolution, unpack_resolution
29
-
30
-
31
- def cli() -> None:
32
- signal.signal(signal.SIGINT, lambda signal_number, frame: graceful_exit(0))
33
- program = create_program()
34
-
35
- if validate_args(program):
36
- args = vars(program.parse_args())
37
- apply_args(args, state_manager.init_item)
38
-
39
- if state_manager.get_item('command'):
40
- logger.init('info')
41
- route(args)
42
- else:
43
- program.print_help()
44
-
45
-
46
- def route(args : Args) -> None:
47
- system_memory_limit = state_manager.get_item('system_memory_limit')
48
- if system_memory_limit and system_memory_limit > 0:
49
- limit_system_memory(system_memory_limit)
50
- if state_manager.get_item('command') == 'force-download':
51
- error_code = force_download()
52
- return conditional_exit(error_code)
53
- if state_manager.get_item('command') in [ 'job-list', 'job-create', 'job-submit', 'job-submit-all', 'job-delete', 'job-delete-all', 'job-add-step', 'job-remix-step', 'job-insert-step', 'job-remove-step' ]:
54
- if not job_manager.init_jobs(state_manager.get_item('jobs_path')):
55
- hard_exit(1)
56
- error_code = route_job_manager(args)
57
- hard_exit(error_code)
58
- if not pre_check():
59
- return conditional_exit(2)
60
- if state_manager.get_item('command') == 'run':
61
- import facefusion.uis.core as ui
62
-
63
- if not common_pre_check() or not processors_pre_check():
64
- return conditional_exit(2)
65
- for ui_layout in ui.get_ui_layouts_modules(state_manager.get_item('ui_layouts')):
66
- if not ui_layout.pre_check():
67
- return conditional_exit(2)
68
- ui.launch()
69
- if state_manager.get_item('command') == 'headless-run':
70
- if not job_manager.init_jobs(state_manager.get_item('jobs_path')):
71
- hard_exit(1)
72
- error_core = process_headless(args)
73
- hard_exit(error_core)
74
- if state_manager.get_item('command') in [ 'job-run', 'job-run-all', 'job-retry', 'job-retry-all' ]:
75
- if not job_manager.init_jobs(state_manager.get_item('jobs_path')):
76
- hard_exit(1)
77
- error_code = route_job_runner()
78
- hard_exit(error_code)
79
-
80
-
81
- def pre_check() -> bool:
82
- if sys.version_info < (3, 9):
83
- logger.error(wording.get('python_not_supported').format(version = '3.9'), __name__)
84
- return False
85
- if not shutil.which('curl'):
86
- logger.error(wording.get('curl_not_installed'), __name__)
87
- return False
88
- if not shutil.which('ffmpeg'):
89
- logger.error(wording.get('ffmpeg_not_installed'), __name__)
90
- return False
91
- return True
92
-
93
-
94
- def common_pre_check() -> bool:
95
- modules =\
96
- [
97
- content_analyser,
98
- face_classifier,
99
- face_detector,
100
- face_landmarker,
101
- face_masker,
102
- face_recognizer,
103
- voice_extractor
104
- ]
105
-
106
- return all(module.pre_check() for module in modules)
107
-
108
-
109
- def processors_pre_check() -> bool:
110
- for processor_module in get_processors_modules(state_manager.get_item('processors')):
111
- if not processor_module.pre_check():
112
- return False
113
- return True
114
-
115
-
116
- def conditional_process() -> ErrorCode:
117
- start_time = time()
118
- for processor_module in get_processors_modules(state_manager.get_item('processors')):
119
- if not processor_module.pre_process('output'):
120
- return 2
121
- conditional_append_reference_faces()
122
- if is_image(state_manager.get_item('target_path')):
123
- return process_image(start_time)
124
- if is_video(state_manager.get_item('target_path')):
125
- return process_video(start_time)
126
- return 0
127
-
128
-
129
- def conditional_append_reference_faces() -> None:
130
- if 'reference' in state_manager.get_item('face_selector_mode') and not get_reference_faces():
131
- source_frames = read_static_images(state_manager.get_item('source_paths'))
132
- source_faces = get_many_faces(source_frames)
133
- source_face = get_average_face(source_faces)
134
- if is_video(state_manager.get_item('target_path')):
135
- reference_frame = get_video_frame(state_manager.get_item('target_path'), state_manager.get_item('reference_frame_number'))
136
- else:
137
- reference_frame = read_image(state_manager.get_item('target_path'))
138
- reference_faces = sort_and_filter_faces(get_many_faces([ reference_frame ]))
139
- reference_face = get_one_face(reference_faces, state_manager.get_item('reference_face_position'))
140
- append_reference_face('origin', reference_face)
141
-
142
- if source_face and reference_face:
143
- for processor_module in get_processors_modules(state_manager.get_item('processors')):
144
- abstract_reference_frame = processor_module.get_reference_frame(source_face, reference_face, reference_frame)
145
- if numpy.any(abstract_reference_frame):
146
- abstract_reference_faces = sort_and_filter_faces(get_many_faces([ abstract_reference_frame ]))
147
- abstract_reference_face = get_one_face(abstract_reference_faces, state_manager.get_item('reference_face_position'))
148
- append_reference_face(processor_module.__name__, abstract_reference_face)
149
-
150
-
151
- def force_download() -> ErrorCode:
152
- download_directory_path = resolve_relative_path('../.assets/models')
153
- available_processors = list_directory('facefusion/processors/modules')
154
- common_modules =\
155
- [
156
- content_analyser,
157
- face_classifier,
158
- face_detector,
159
- face_landmarker,
160
- face_recognizer,
161
- face_masker,
162
- voice_extractor
163
- ]
164
- processor_modules = get_processors_modules(available_processors)
165
-
166
- for module in common_modules + processor_modules:
167
- if hasattr(module, 'MODEL_SET'):
168
- for model in module.MODEL_SET.values():
169
- model_hashes = model.get('hashes')
170
- model_sources = model.get('sources')
171
-
172
- if model_hashes and model_sources:
173
- if not conditional_download_hashes(download_directory_path, model_hashes) or not conditional_download_sources(download_directory_path, model_sources):
174
- return 1
175
-
176
- return 0
177
-
178
-
179
- def route_job_manager(args : Args) -> ErrorCode:
180
- if state_manager.get_item('command') == 'job-list':
181
- job_headers, job_contents = compose_job_list(state_manager.get_item('job_status'))
182
-
183
- if job_contents:
184
- logger.table(job_headers, job_contents)
185
- return 0
186
- return 1
187
- if state_manager.get_item('command') == 'job-create':
188
- if job_manager.create_job(state_manager.get_item('job_id')):
189
- logger.info(wording.get('job_created').format(job_id = state_manager.get_item('job_id')), __name__)
190
- return 0
191
- logger.error(wording.get('job_not_created').format(job_id = state_manager.get_item('job_id')), __name__)
192
- return 1
193
- if state_manager.get_item('command') == 'job-submit':
194
- if job_manager.submit_job(state_manager.get_item('job_id')):
195
- logger.info(wording.get('job_submitted').format(job_id = state_manager.get_item('job_id')), __name__)
196
- return 0
197
- logger.error(wording.get('job_not_submitted').format(job_id = state_manager.get_item('job_id')), __name__)
198
- return 1
199
- if state_manager.get_item('command') == 'job-submit-all':
200
- if job_manager.submit_jobs():
201
- logger.info(wording.get('job_all_submitted'), __name__)
202
- return 0
203
- logger.error(wording.get('job_all_not_submitted'), __name__)
204
- return 1
205
- if state_manager.get_item('command') == 'job-delete':
206
- if job_manager.delete_job(state_manager.get_item('job_id')):
207
- logger.info(wording.get('job_deleted').format(job_id = state_manager.get_item('job_id')), __name__)
208
- return 0
209
- logger.error(wording.get('job_not_deleted').format(job_id = state_manager.get_item('job_id')), __name__)
210
- return 1
211
- if state_manager.get_item('command') == 'job-delete-all':
212
- if job_manager.delete_jobs():
213
- logger.info(wording.get('job_all_deleted'), __name__)
214
- return 0
215
- logger.error(wording.get('job_all_not_deleted'), __name__)
216
- return 1
217
- if state_manager.get_item('command') == 'job-add-step':
218
- step_args = reduce_step_args(args)
219
-
220
- if job_manager.add_step(state_manager.get_item('job_id'), step_args):
221
- logger.info(wording.get('job_step_added').format(job_id = state_manager.get_item('job_id')), __name__)
222
- return 0
223
- logger.error(wording.get('job_step_not_added').format(job_id = state_manager.get_item('job_id')), __name__)
224
- return 1
225
- if state_manager.get_item('command') == 'job-remix-step':
226
- step_args = reduce_step_args(args)
227
-
228
- if job_manager.remix_step(state_manager.get_item('job_id'), state_manager.get_item('step_index'), step_args):
229
- logger.info(wording.get('job_remix_step_added').format(job_id = state_manager.get_item('job_id'), step_index = state_manager.get_item('step_index')), __name__)
230
- return 0
231
- logger.error(wording.get('job_remix_step_not_added').format(job_id = state_manager.get_item('job_id'), step_index = state_manager.get_item('step_index')), __name__)
232
- return 1
233
- if state_manager.get_item('command') == 'job-insert-step':
234
- step_args = reduce_step_args(args)
235
-
236
- if job_manager.insert_step(state_manager.get_item('job_id'), state_manager.get_item('step_index'), step_args):
237
- logger.info(wording.get('job_step_inserted').format(job_id = state_manager.get_item('job_id'), step_index = state_manager.get_item('step_index')), __name__)
238
- return 0
239
- logger.error(wording.get('job_step_not_inserted').format(job_id = state_manager.get_item('job_id'), step_index = state_manager.get_item('step_index')), __name__)
240
- return 1
241
- if state_manager.get_item('command') == 'job-remove-step':
242
- if job_manager.remove_step(state_manager.get_item('job_id'), state_manager.get_item('step_index')):
243
- logger.info(wording.get('job_step_removed').format(job_id = state_manager.get_item('job_id'), step_index = state_manager.get_item('step_index')), __name__)
244
- return 0
245
- logger.error(wording.get('job_step_not_removed').format(job_id = state_manager.get_item('job_id'), step_index = state_manager.get_item('step_index')), __name__)
246
- return 1
247
- return 1
248
-
249
-
250
- def route_job_runner() -> ErrorCode:
251
- if state_manager.get_item('command') == 'job-run':
252
- logger.info(wording.get('running_job').format(job_id = state_manager.get_item('job_id')), __name__)
253
- if job_runner.run_job(state_manager.get_item('job_id'), process_step):
254
- logger.info(wording.get('processing_job_succeed').format(job_id = state_manager.get_item('job_id')), __name__)
255
- return 0
256
- logger.info(wording.get('processing_job_failed').format(job_id = state_manager.get_item('job_id')), __name__)
257
- return 1
258
- if state_manager.get_item('command') == 'job-run-all':
259
- logger.info(wording.get('running_jobs'), __name__)
260
- if job_runner.run_jobs(process_step):
261
- logger.info(wording.get('processing_jobs_succeed'), __name__)
262
- return 0
263
- logger.info(wording.get('processing_jobs_failed'), __name__)
264
- return 1
265
- if state_manager.get_item('command') == 'job-retry':
266
- logger.info(wording.get('retrying_job').format(job_id = state_manager.get_item('job_id')), __name__)
267
- if job_runner.retry_job(state_manager.get_item('job_id'), process_step):
268
- logger.info(wording.get('processing_job_succeed').format(job_id = state_manager.get_item('job_id')), __name__)
269
- return 0
270
- logger.info(wording.get('processing_job_failed').format(job_id = state_manager.get_item('job_id')), __name__)
271
- return 1
272
- if state_manager.get_item('command') == 'job-retry-all':
273
- logger.info(wording.get('retrying_jobs'), __name__)
274
- if job_runner.retry_jobs(process_step):
275
- logger.info(wording.get('processing_jobs_succeed'), __name__)
276
- return 0
277
- logger.info(wording.get('processing_jobs_failed'), __name__)
278
- return 1
279
- return 2
280
-
281
-
282
- def process_step(job_id : str, step_index : int, step_args : Args) -> bool:
283
- clear_reference_faces()
284
- step_total = job_manager.count_step_total(job_id)
285
- step_args.update(collect_job_args())
286
- apply_args(step_args, state_manager.set_item)
287
-
288
- logger.info(wording.get('processing_step').format(step_current = step_index + 1, step_total = step_total), __name__)
289
- if common_pre_check() and processors_pre_check():
290
- error_code = conditional_process()
291
- return error_code == 0
292
- return False
293
-
294
-
295
- def process_headless(args : Args) -> ErrorCode:
296
- job_id = job_helper.suggest_job_id('headless')
297
- step_args = reduce_step_args(args)
298
-
299
- if job_manager.create_job(job_id) and job_manager.add_step(job_id, step_args) and job_manager.submit_job(job_id) and job_runner.run_job(job_id, process_step):
300
- return 0
301
- return 1
302
-
303
-
304
- def process_image(start_time : float) -> ErrorCode:
305
- if analyse_image(state_manager.get_item('target_path')):
306
- return 3
307
- # clear temp
308
- logger.debug(wording.get('clearing_temp'), __name__)
309
- clear_temp_directory(state_manager.get_item('target_path'))
310
- # create temp
311
- logger.debug(wording.get('creating_temp'), __name__)
312
- create_temp_directory(state_manager.get_item('target_path'))
313
- # copy image
314
- process_manager.start()
315
- temp_image_resolution = pack_resolution(restrict_image_resolution(state_manager.get_item('target_path'), unpack_resolution(state_manager.get_item('output_image_resolution'))))
316
- logger.info(wording.get('copying_image').format(resolution = temp_image_resolution), __name__)
317
- if copy_image(state_manager.get_item('target_path'), temp_image_resolution):
318
- logger.debug(wording.get('copying_image_succeed'), __name__)
319
- else:
320
- logger.error(wording.get('copying_image_failed'), __name__)
321
- process_manager.end()
322
- return 1
323
- # process image
324
- temp_file_path = get_temp_file_path(state_manager.get_item('target_path'))
325
- for processor_module in get_processors_modules(state_manager.get_item('processors')):
326
- logger.info(wording.get('processing'), processor_module.__name__)
327
- processor_module.process_image(state_manager.get_item('source_paths'), temp_file_path, temp_file_path)
328
- processor_module.post_process()
329
- if is_process_stopping():
330
- process_manager.end()
331
- return 4
332
- # finalize image
333
- logger.info(wording.get('finalizing_image').format(resolution = state_manager.get_item('output_image_resolution')), __name__)
334
- if finalize_image(state_manager.get_item('target_path'), state_manager.get_item('output_path'), state_manager.get_item('output_image_resolution')):
335
- logger.debug(wording.get('finalizing_image_succeed'), __name__)
336
- else:
337
- logger.warn(wording.get('finalizing_image_skipped'), __name__)
338
- # clear temp
339
- logger.debug(wording.get('clearing_temp'), __name__)
340
- clear_temp_directory(state_manager.get_item('target_path'))
341
- # validate image
342
- if is_image(state_manager.get_item('output_path')):
343
- seconds = '{:.2f}'.format((time() - start_time) % 60)
344
- logger.info(wording.get('processing_image_succeed').format(seconds = seconds), __name__)
345
- conditional_log_statistics()
346
- else:
347
- logger.error(wording.get('processing_image_failed'), __name__)
348
- process_manager.end()
349
- return 1
350
- process_manager.end()
351
- return 0
352
-
353
-
354
- def process_video(start_time : float) -> ErrorCode:
355
- if analyse_video(state_manager.get_item('target_path'), state_manager.get_item('trim_frame_start'), state_manager.get_item('trim_frame_end')):
356
- return 3
357
- # clear temp
358
- logger.debug(wording.get('clearing_temp'), __name__)
359
- clear_temp_directory(state_manager.get_item('target_path'))
360
- # create temp
361
- logger.debug(wording.get('creating_temp'), __name__)
362
- create_temp_directory(state_manager.get_item('target_path'))
363
- # extract frames
364
- process_manager.start()
365
- temp_video_resolution = pack_resolution(restrict_video_resolution(state_manager.get_item('target_path'), unpack_resolution(state_manager.get_item('output_video_resolution'))))
366
- temp_video_fps = restrict_video_fps(state_manager.get_item('target_path'), state_manager.get_item('output_video_fps'))
367
- logger.info(wording.get('extracting_frames').format(resolution = temp_video_resolution, fps = temp_video_fps), __name__)
368
- if extract_frames(state_manager.get_item('target_path'), temp_video_resolution, temp_video_fps):
369
- logger.debug(wording.get('extracting_frames_succeed'), __name__)
370
- else:
371
- if is_process_stopping():
372
- process_manager.end()
373
- return 4
374
- logger.error(wording.get('extracting_frames_failed'), __name__)
375
- process_manager.end()
376
- return 1
377
- # process frames
378
- temp_frame_paths = get_temp_frame_paths(state_manager.get_item('target_path'))
379
- if temp_frame_paths:
380
- for processor_module in get_processors_modules(state_manager.get_item('processors')):
381
- logger.info(wording.get('processing'), processor_module.__name__)
382
- processor_module.process_video(state_manager.get_item('source_paths'), temp_frame_paths)
383
- processor_module.post_process()
384
- if is_process_stopping():
385
- return 4
386
- else:
387
- logger.error(wording.get('temp_frames_not_found'), __name__)
388
- process_manager.end()
389
- return 1
390
- # merge video
391
- logger.info(wording.get('merging_video').format(resolution = state_manager.get_item('output_video_resolution'), fps = state_manager.get_item('output_video_fps')), __name__)
392
- if merge_video(state_manager.get_item('target_path'), state_manager.get_item('output_video_resolution'), state_manager.get_item('output_video_fps')):
393
- logger.debug(wording.get('merging_video_succeed'), __name__)
394
- else:
395
- if is_process_stopping():
396
- process_manager.end()
397
- return 4
398
- logger.error(wording.get('merging_video_failed'), __name__)
399
- process_manager.end()
400
- return 1
401
- # handle audio
402
- if state_manager.get_item('skip_audio'):
403
- logger.info(wording.get('skipping_audio'), __name__)
404
- move_temp_file(state_manager.get_item('target_path'), state_manager.get_item('output_path'))
405
- else:
406
- source_audio_path = get_first(filter_audio_paths(state_manager.get_item('source_paths')))
407
- if source_audio_path:
408
- if replace_audio(state_manager.get_item('target_path'), source_audio_path, state_manager.get_item('output_path')):
409
- logger.debug(wording.get('replacing_audio_succeed'), __name__)
410
- else:
411
- if is_process_stopping():
412
- process_manager.end()
413
- return 4
414
- logger.warn(wording.get('replacing_audio_skipped'), __name__)
415
- move_temp_file(state_manager.get_item('target_path'), state_manager.get_item('output_path'))
416
- else:
417
- if restore_audio(state_manager.get_item('target_path'), state_manager.get_item('output_path'), state_manager.get_item('output_video_fps')):
418
- logger.debug(wording.get('restoring_audio_succeed'), __name__)
419
- else:
420
- if is_process_stopping():
421
- process_manager.end()
422
- return 4
423
- logger.warn(wording.get('restoring_audio_skipped'), __name__)
424
- move_temp_file(state_manager.get_item('target_path'), state_manager.get_item('output_path'))
425
- # clear temp
426
- logger.debug(wording.get('clearing_temp'), __name__)
427
- clear_temp_directory(state_manager.get_item('target_path'))
428
- # validate video
429
- if is_video(state_manager.get_item('output_path')):
430
- seconds = '{:.2f}'.format((time() - start_time))
431
- logger.info(wording.get('processing_video_succeed').format(seconds = seconds), __name__)
432
- conditional_log_statistics()
433
- else:
434
- logger.error(wording.get('processing_video_failed'), __name__)
435
- process_manager.end()
436
- return 1
437
- process_manager.end()
438
- return 0
439
-
440
-
441
- def is_process_stopping() -> bool:
442
- if process_manager.is_stopping():
443
- process_manager.end()
444
- logger.info(wording.get('processing_stopped'), __name__)
445
- return process_manager.is_pending()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import inspect
2
+ import itertools
3
+ import shutil
4
+ import signal
5
+ import sys
6
+ from time import time
7
+
8
+ import numpy
9
+
10
+ from facefusion import benchmarker, cli_helper, content_analyser, face_classifier, face_detector, face_landmarker, face_masker, face_recognizer, hash_helper, logger, process_manager, state_manager, video_manager, voice_extractor, wording
11
+ from facefusion.args import apply_args, collect_job_args, reduce_job_args, reduce_step_args
12
+ from facefusion.common_helper import get_first
13
+ from facefusion.content_analyser import analyse_image, analyse_video
14
+ from facefusion.download import conditional_download_hashes, conditional_download_sources
15
+ from facefusion.exit_helper import hard_exit, signal_exit
16
+ from facefusion.face_analyser import get_average_face, get_many_faces, get_one_face
17
+ from facefusion.face_selector import sort_and_filter_faces
18
+ from facefusion.face_store import append_reference_face, clear_reference_faces, get_reference_faces
19
+ from facefusion.ffmpeg import copy_image, extract_frames, finalize_image, merge_video, replace_audio, restore_audio
20
+ from facefusion.filesystem import filter_audio_paths, get_file_name, is_image, is_video, resolve_file_paths, resolve_file_pattern
21
+ from facefusion.jobs import job_helper, job_manager, job_runner
22
+ from facefusion.jobs.job_list import compose_job_list
23
+ from facefusion.memory import limit_system_memory
24
+ from facefusion.processors.core import get_processors_modules
25
+ from facefusion.program import create_program
26
+ from facefusion.program_helper import validate_args
27
+ from facefusion.temp_helper import clear_temp_directory, create_temp_directory, get_temp_file_path, move_temp_file, resolve_temp_frame_paths
28
+ from facefusion.types import Args, ErrorCode
29
+ from facefusion.vision import pack_resolution, read_image, read_static_images, read_video_frame, restrict_image_resolution, restrict_trim_frame, restrict_video_fps, restrict_video_resolution, unpack_resolution
30
+
31
+
32
+ def cli() -> None:
33
+ if pre_check():
34
+ signal.signal(signal.SIGINT, signal_exit)
35
+ program = create_program()
36
+
37
+ if validate_args(program):
38
+ args = vars(program.parse_args())
39
+ apply_args(args, state_manager.init_item)
40
+
41
+ if state_manager.get_item('command'):
42
+ logger.init(state_manager.get_item('log_level'))
43
+ route(args)
44
+ else:
45
+ program.print_help()
46
+ else:
47
+ hard_exit(2)
48
+ else:
49
+ hard_exit(2)
50
+
51
+
52
+ def route(args : Args) -> None:
53
+ system_memory_limit = state_manager.get_item('system_memory_limit')
54
+
55
+ if system_memory_limit and system_memory_limit > 0:
56
+ limit_system_memory(system_memory_limit)
57
+
58
+ if state_manager.get_item('command') == 'force-download':
59
+ error_code = force_download()
60
+ return hard_exit(error_code)
61
+
62
+ if state_manager.get_item('command') == 'benchmark':
63
+ if not common_pre_check() or not processors_pre_check() or not benchmarker.pre_check():
64
+ return hard_exit(2)
65
+ benchmarker.render()
66
+
67
+ if state_manager.get_item('command') in [ 'job-list', 'job-create', 'job-submit', 'job-submit-all', 'job-delete', 'job-delete-all', 'job-add-step', 'job-remix-step', 'job-insert-step', 'job-remove-step' ]:
68
+ if not job_manager.init_jobs(state_manager.get_item('jobs_path')):
69
+ hard_exit(1)
70
+ error_code = route_job_manager(args)
71
+ hard_exit(error_code)
72
+
73
+ if state_manager.get_item('command') == 'run':
74
+ import facefusion.uis.core as ui
75
+
76
+ if not common_pre_check() or not processors_pre_check():
77
+ return hard_exit(2)
78
+ for ui_layout in ui.get_ui_layouts_modules(state_manager.get_item('ui_layouts')):
79
+ if not ui_layout.pre_check():
80
+ return hard_exit(2)
81
+ ui.init()
82
+ ui.launch()
83
+
84
+ if state_manager.get_item('command') == 'headless-run':
85
+ if not job_manager.init_jobs(state_manager.get_item('jobs_path')):
86
+ hard_exit(1)
87
+ error_core = process_headless(args)
88
+ hard_exit(error_core)
89
+
90
+ if state_manager.get_item('command') == 'batch-run':
91
+ if not job_manager.init_jobs(state_manager.get_item('jobs_path')):
92
+ hard_exit(1)
93
+ error_core = process_batch(args)
94
+ hard_exit(error_core)
95
+
96
+ if state_manager.get_item('command') in [ 'job-run', 'job-run-all', 'job-retry', 'job-retry-all' ]:
97
+ if not job_manager.init_jobs(state_manager.get_item('jobs_path')):
98
+ hard_exit(1)
99
+ error_code = route_job_runner()
100
+ hard_exit(error_code)
101
+
102
+
103
+ def pre_check() -> bool:
104
+ if sys.version_info < (3, 10):
105
+ logger.error(wording.get('python_not_supported').format(version = '3.10'), __name__)
106
+ return False
107
+
108
+ if not shutil.which('curl'):
109
+ logger.error(wording.get('curl_not_installed'), __name__)
110
+ return False
111
+
112
+ if not shutil.which('ffmpeg'):
113
+ logger.error(wording.get('ffmpeg_not_installed'), __name__)
114
+ return False
115
+ return True
116
+
117
+
118
+ def common_pre_check() -> bool:
119
+ common_modules =\
120
+ [
121
+ content_analyser,
122
+ face_classifier,
123
+ face_detector,
124
+ face_landmarker,
125
+ face_masker,
126
+ face_recognizer,
127
+ voice_extractor
128
+ ]
129
+
130
+ content_analyser_content = inspect.getsource(content_analyser).encode()
131
+ is_valid = True#hash_helper.create_hash(content_analyser_content) == 'b159fd9d'
132
+
133
+ return all(module.pre_check() for module in common_modules) and is_valid
134
+
135
+
136
+ def processors_pre_check() -> bool:
137
+ for processor_module in get_processors_modules(state_manager.get_item('processors')):
138
+ if not processor_module.pre_check():
139
+ return False
140
+ return True
141
+
142
+
143
+ def force_download() -> ErrorCode:
144
+ common_modules =\
145
+ [
146
+ content_analyser,
147
+ face_classifier,
148
+ face_detector,
149
+ face_landmarker,
150
+ face_masker,
151
+ face_recognizer,
152
+ voice_extractor
153
+ ]
154
+ available_processors = [ get_file_name(file_path) for file_path in resolve_file_paths('facefusion/processors/modules') ]
155
+ processor_modules = get_processors_modules(available_processors)
156
+
157
+ for module in common_modules + processor_modules:
158
+ if hasattr(module, 'create_static_model_set'):
159
+ for model in module.create_static_model_set(state_manager.get_item('download_scope')).values():
160
+ model_hash_set = model.get('hashes')
161
+ model_source_set = model.get('sources')
162
+
163
+ if model_hash_set and model_source_set:
164
+ if not conditional_download_hashes(model_hash_set) or not conditional_download_sources(model_source_set):
165
+ return 1
166
+
167
+ return 0
168
+
169
+
170
+ def route_job_manager(args : Args) -> ErrorCode:
171
+ if state_manager.get_item('command') == 'job-list':
172
+ job_headers, job_contents = compose_job_list(state_manager.get_item('job_status'))
173
+
174
+ if job_contents:
175
+ cli_helper.render_table(job_headers, job_contents)
176
+ return 0
177
+ return 1
178
+
179
+ if state_manager.get_item('command') == 'job-create':
180
+ if job_manager.create_job(state_manager.get_item('job_id')):
181
+ logger.info(wording.get('job_created').format(job_id = state_manager.get_item('job_id')), __name__)
182
+ return 0
183
+ logger.error(wording.get('job_not_created').format(job_id = state_manager.get_item('job_id')), __name__)
184
+ return 1
185
+
186
+ if state_manager.get_item('command') == 'job-submit':
187
+ if job_manager.submit_job(state_manager.get_item('job_id')):
188
+ logger.info(wording.get('job_submitted').format(job_id = state_manager.get_item('job_id')), __name__)
189
+ return 0
190
+ logger.error(wording.get('job_not_submitted').format(job_id = state_manager.get_item('job_id')), __name__)
191
+ return 1
192
+
193
+ if state_manager.get_item('command') == 'job-submit-all':
194
+ if job_manager.submit_jobs(state_manager.get_item('halt_on_error')):
195
+ logger.info(wording.get('job_all_submitted'), __name__)
196
+ return 0
197
+ logger.error(wording.get('job_all_not_submitted'), __name__)
198
+ return 1
199
+
200
+ if state_manager.get_item('command') == 'job-delete':
201
+ if job_manager.delete_job(state_manager.get_item('job_id')):
202
+ logger.info(wording.get('job_deleted').format(job_id = state_manager.get_item('job_id')), __name__)
203
+ return 0
204
+ logger.error(wording.get('job_not_deleted').format(job_id = state_manager.get_item('job_id')), __name__)
205
+ return 1
206
+
207
+ if state_manager.get_item('command') == 'job-delete-all':
208
+ if job_manager.delete_jobs(state_manager.get_item('halt_on_error')):
209
+ logger.info(wording.get('job_all_deleted'), __name__)
210
+ return 0
211
+ logger.error(wording.get('job_all_not_deleted'), __name__)
212
+ return 1
213
+
214
+ if state_manager.get_item('command') == 'job-add-step':
215
+ step_args = reduce_step_args(args)
216
+
217
+ if job_manager.add_step(state_manager.get_item('job_id'), step_args):
218
+ logger.info(wording.get('job_step_added').format(job_id = state_manager.get_item('job_id')), __name__)
219
+ return 0
220
+ logger.error(wording.get('job_step_not_added').format(job_id = state_manager.get_item('job_id')), __name__)
221
+ return 1
222
+
223
+ if state_manager.get_item('command') == 'job-remix-step':
224
+ step_args = reduce_step_args(args)
225
+
226
+ if job_manager.remix_step(state_manager.get_item('job_id'), state_manager.get_item('step_index'), step_args):
227
+ logger.info(wording.get('job_remix_step_added').format(job_id = state_manager.get_item('job_id'), step_index = state_manager.get_item('step_index')), __name__)
228
+ return 0
229
+ logger.error(wording.get('job_remix_step_not_added').format(job_id = state_manager.get_item('job_id'), step_index = state_manager.get_item('step_index')), __name__)
230
+ return 1
231
+
232
+ if state_manager.get_item('command') == 'job-insert-step':
233
+ step_args = reduce_step_args(args)
234
+
235
+ if job_manager.insert_step(state_manager.get_item('job_id'), state_manager.get_item('step_index'), step_args):
236
+ logger.info(wording.get('job_step_inserted').format(job_id = state_manager.get_item('job_id'), step_index = state_manager.get_item('step_index')), __name__)
237
+ return 0
238
+ logger.error(wording.get('job_step_not_inserted').format(job_id = state_manager.get_item('job_id'), step_index = state_manager.get_item('step_index')), __name__)
239
+ return 1
240
+
241
+ if state_manager.get_item('command') == 'job-remove-step':
242
+ if job_manager.remove_step(state_manager.get_item('job_id'), state_manager.get_item('step_index')):
243
+ logger.info(wording.get('job_step_removed').format(job_id = state_manager.get_item('job_id'), step_index = state_manager.get_item('step_index')), __name__)
244
+ return 0
245
+ logger.error(wording.get('job_step_not_removed').format(job_id = state_manager.get_item('job_id'), step_index = state_manager.get_item('step_index')), __name__)
246
+ return 1
247
+ return 1
248
+
249
+
250
+ def route_job_runner() -> ErrorCode:
251
+ if state_manager.get_item('command') == 'job-run':
252
+ logger.info(wording.get('running_job').format(job_id = state_manager.get_item('job_id')), __name__)
253
+ if job_runner.run_job(state_manager.get_item('job_id'), process_step):
254
+ logger.info(wording.get('processing_job_succeed').format(job_id = state_manager.get_item('job_id')), __name__)
255
+ return 0
256
+ logger.info(wording.get('processing_job_failed').format(job_id = state_manager.get_item('job_id')), __name__)
257
+ return 1
258
+
259
+ if state_manager.get_item('command') == 'job-run-all':
260
+ logger.info(wording.get('running_jobs'), __name__)
261
+ if job_runner.run_jobs(process_step, state_manager.get_item('halt_on_error')):
262
+ logger.info(wording.get('processing_jobs_succeed'), __name__)
263
+ return 0
264
+ logger.info(wording.get('processing_jobs_failed'), __name__)
265
+ return 1
266
+
267
+ if state_manager.get_item('command') == 'job-retry':
268
+ logger.info(wording.get('retrying_job').format(job_id = state_manager.get_item('job_id')), __name__)
269
+ if job_runner.retry_job(state_manager.get_item('job_id'), process_step):
270
+ logger.info(wording.get('processing_job_succeed').format(job_id = state_manager.get_item('job_id')), __name__)
271
+ return 0
272
+ logger.info(wording.get('processing_job_failed').format(job_id = state_manager.get_item('job_id')), __name__)
273
+ return 1
274
+
275
+ if state_manager.get_item('command') == 'job-retry-all':
276
+ logger.info(wording.get('retrying_jobs'), __name__)
277
+ if job_runner.retry_jobs(process_step, state_manager.get_item('halt_on_error')):
278
+ logger.info(wording.get('processing_jobs_succeed'), __name__)
279
+ return 0
280
+ logger.info(wording.get('processing_jobs_failed'), __name__)
281
+ return 1
282
+ return 2
283
+
284
+
285
+ def process_headless(args : Args) -> ErrorCode:
286
+ job_id = job_helper.suggest_job_id('headless')
287
+ step_args = reduce_step_args(args)
288
+
289
+ if job_manager.create_job(job_id) and job_manager.add_step(job_id, step_args) and job_manager.submit_job(job_id) and job_runner.run_job(job_id, process_step):
290
+ return 0
291
+ return 1
292
+
293
+
294
+ def process_batch(args : Args) -> ErrorCode:
295
+ job_id = job_helper.suggest_job_id('batch')
296
+ step_args = reduce_step_args(args)
297
+ job_args = reduce_job_args(args)
298
+ source_paths = resolve_file_pattern(job_args.get('source_pattern'))
299
+ target_paths = resolve_file_pattern(job_args.get('target_pattern'))
300
+
301
+ if job_manager.create_job(job_id):
302
+ if source_paths and target_paths:
303
+ for index, (source_path, target_path) in enumerate(itertools.product(source_paths, target_paths)):
304
+ step_args['source_paths'] = [ source_path ]
305
+ step_args['target_path'] = target_path
306
+ step_args['output_path'] = job_args.get('output_pattern').format(index = index)
307
+ if not job_manager.add_step(job_id, step_args):
308
+ return 1
309
+ if job_manager.submit_job(job_id) and job_runner.run_job(job_id, process_step):
310
+ return 0
311
+
312
+ if not source_paths and target_paths:
313
+ for index, target_path in enumerate(target_paths):
314
+ step_args['target_path'] = target_path
315
+ step_args['output_path'] = job_args.get('output_pattern').format(index = index)
316
+ if not job_manager.add_step(job_id, step_args):
317
+ return 1
318
+ if job_manager.submit_job(job_id) and job_runner.run_job(job_id, process_step):
319
+ return 0
320
+ return 1
321
+
322
+
323
+ def process_step(job_id : str, step_index : int, step_args : Args) -> bool:
324
+ clear_reference_faces()
325
+ step_total = job_manager.count_step_total(job_id)
326
+ step_args.update(collect_job_args())
327
+ apply_args(step_args, state_manager.set_item)
328
+
329
+ logger.info(wording.get('processing_step').format(step_current = step_index + 1, step_total = step_total), __name__)
330
+ if common_pre_check() and processors_pre_check():
331
+ error_code = conditional_process()
332
+ return error_code == 0
333
+ return False
334
+
335
+
336
+ def conditional_process() -> ErrorCode:
337
+ start_time = time()
338
+
339
+ for processor_module in get_processors_modules(state_manager.get_item('processors')):
340
+ if not processor_module.pre_process('output'):
341
+ return 2
342
+
343
+ conditional_append_reference_faces()
344
+
345
+ if is_image(state_manager.get_item('target_path')):
346
+ return process_image(start_time)
347
+ if is_video(state_manager.get_item('target_path')):
348
+ return process_video(start_time)
349
+
350
+ return 0
351
+
352
+
353
+ def conditional_append_reference_faces() -> None:
354
+ if 'reference' in state_manager.get_item('face_selector_mode') and not get_reference_faces():
355
+ source_frames = read_static_images(state_manager.get_item('source_paths'))
356
+ source_faces = get_many_faces(source_frames)
357
+ source_face = get_average_face(source_faces)
358
+ if is_video(state_manager.get_item('target_path')):
359
+ reference_frame = read_video_frame(state_manager.get_item('target_path'), state_manager.get_item('reference_frame_number'))
360
+ else:
361
+ reference_frame = read_image(state_manager.get_item('target_path'))
362
+ reference_faces = sort_and_filter_faces(get_many_faces([ reference_frame ]))
363
+ reference_face = get_one_face(reference_faces, state_manager.get_item('reference_face_position'))
364
+ append_reference_face('origin', reference_face)
365
+
366
+ if source_face and reference_face:
367
+ for processor_module in get_processors_modules(state_manager.get_item('processors')):
368
+ abstract_reference_frame = processor_module.get_reference_frame(source_face, reference_face, reference_frame)
369
+ if numpy.any(abstract_reference_frame):
370
+ abstract_reference_faces = sort_and_filter_faces(get_many_faces([ abstract_reference_frame ]))
371
+ abstract_reference_face = get_one_face(abstract_reference_faces, state_manager.get_item('reference_face_position'))
372
+ append_reference_face(processor_module.__name__, abstract_reference_face)
373
+
374
+
375
+ def process_image(start_time : float) -> ErrorCode:
376
+ if analyse_image(state_manager.get_item('target_path')):
377
+ return 3
378
+
379
+ logger.debug(wording.get('clearing_temp'), __name__)
380
+ clear_temp_directory(state_manager.get_item('target_path'))
381
+ logger.debug(wording.get('creating_temp'), __name__)
382
+ create_temp_directory(state_manager.get_item('target_path'))
383
+
384
+ process_manager.start()
385
+ temp_image_resolution = pack_resolution(restrict_image_resolution(state_manager.get_item('target_path'), unpack_resolution(state_manager.get_item('output_image_resolution'))))
386
+ logger.info(wording.get('copying_image').format(resolution = temp_image_resolution), __name__)
387
+ if copy_image(state_manager.get_item('target_path'), temp_image_resolution):
388
+ logger.debug(wording.get('copying_image_succeed'), __name__)
389
+ else:
390
+ logger.error(wording.get('copying_image_failed'), __name__)
391
+ process_manager.end()
392
+ return 1
393
+
394
+ temp_image_path = get_temp_file_path(state_manager.get_item('target_path'))
395
+ for processor_module in get_processors_modules(state_manager.get_item('processors')):
396
+ logger.info(wording.get('processing'), processor_module.__name__)
397
+ processor_module.process_image(state_manager.get_item('source_paths'), temp_image_path, temp_image_path)
398
+ processor_module.post_process()
399
+ if is_process_stopping():
400
+ process_manager.end()
401
+ return 4
402
+
403
+ logger.info(wording.get('finalizing_image').format(resolution = state_manager.get_item('output_image_resolution')), __name__)
404
+ if finalize_image(state_manager.get_item('target_path'), state_manager.get_item('output_path'), state_manager.get_item('output_image_resolution')):
405
+ logger.debug(wording.get('finalizing_image_succeed'), __name__)
406
+ else:
407
+ logger.warn(wording.get('finalizing_image_skipped'), __name__)
408
+
409
+ logger.debug(wording.get('clearing_temp'), __name__)
410
+ clear_temp_directory(state_manager.get_item('target_path'))
411
+
412
+ if is_image(state_manager.get_item('output_path')):
413
+ seconds = '{:.2f}'.format((time() - start_time) % 60)
414
+ logger.info(wording.get('processing_image_succeed').format(seconds = seconds), __name__)
415
+ else:
416
+ logger.error(wording.get('processing_image_failed'), __name__)
417
+ process_manager.end()
418
+ return 1
419
+ process_manager.end()
420
+ return 0
421
+
422
+
423
+ def process_video(start_time : float) -> ErrorCode:
424
+ trim_frame_start, trim_frame_end = restrict_trim_frame(state_manager.get_item('target_path'), state_manager.get_item('trim_frame_start'), state_manager.get_item('trim_frame_end'))
425
+ if analyse_video(state_manager.get_item('target_path'), trim_frame_start, trim_frame_end):
426
+ return 3
427
+
428
+ logger.debug(wording.get('clearing_temp'), __name__)
429
+ clear_temp_directory(state_manager.get_item('target_path'))
430
+ logger.debug(wording.get('creating_temp'), __name__)
431
+ create_temp_directory(state_manager.get_item('target_path'))
432
+
433
+ process_manager.start()
434
+ temp_video_resolution = pack_resolution(restrict_video_resolution(state_manager.get_item('target_path'), unpack_resolution(state_manager.get_item('output_video_resolution'))))
435
+ temp_video_fps = restrict_video_fps(state_manager.get_item('target_path'), state_manager.get_item('output_video_fps'))
436
+ logger.info(wording.get('extracting_frames').format(resolution = temp_video_resolution, fps = temp_video_fps), __name__)
437
+ if extract_frames(state_manager.get_item('target_path'), temp_video_resolution, temp_video_fps, trim_frame_start, trim_frame_end):
438
+ logger.debug(wording.get('extracting_frames_succeed'), __name__)
439
+ else:
440
+ if is_process_stopping():
441
+ process_manager.end()
442
+ return 4
443
+ logger.error(wording.get('extracting_frames_failed'), __name__)
444
+ process_manager.end()
445
+ return 1
446
+
447
+ temp_frame_paths = resolve_temp_frame_paths(state_manager.get_item('target_path'))
448
+ if temp_frame_paths:
449
+ for processor_module in get_processors_modules(state_manager.get_item('processors')):
450
+ logger.info(wording.get('processing'), processor_module.__name__)
451
+ processor_module.process_video(state_manager.get_item('source_paths'), temp_frame_paths)
452
+ processor_module.post_process()
453
+ if is_process_stopping():
454
+ return 4
455
+ else:
456
+ logger.error(wording.get('temp_frames_not_found'), __name__)
457
+ process_manager.end()
458
+ return 1
459
+
460
+ logger.info(wording.get('merging_video').format(resolution = state_manager.get_item('output_video_resolution'), fps = state_manager.get_item('output_video_fps')), __name__)
461
+ if merge_video(state_manager.get_item('target_path'), temp_video_fps, state_manager.get_item('output_video_resolution'), state_manager.get_item('output_video_fps'), trim_frame_start, trim_frame_end):
462
+ logger.debug(wording.get('merging_video_succeed'), __name__)
463
+ else:
464
+ if is_process_stopping():
465
+ process_manager.end()
466
+ return 4
467
+ logger.error(wording.get('merging_video_failed'), __name__)
468
+ process_manager.end()
469
+ return 1
470
+
471
+ if state_manager.get_item('output_audio_volume') == 0:
472
+ logger.info(wording.get('skipping_audio'), __name__)
473
+ move_temp_file(state_manager.get_item('target_path'), state_manager.get_item('output_path'))
474
+ else:
475
+ source_audio_path = get_first(filter_audio_paths(state_manager.get_item('source_paths')))
476
+ if source_audio_path:
477
+ if replace_audio(state_manager.get_item('target_path'), source_audio_path, state_manager.get_item('output_path')):
478
+ video_manager.clear_video_pool()
479
+ logger.debug(wording.get('replacing_audio_succeed'), __name__)
480
+ else:
481
+ video_manager.clear_video_pool()
482
+ if is_process_stopping():
483
+ process_manager.end()
484
+ return 4
485
+ logger.warn(wording.get('replacing_audio_skipped'), __name__)
486
+ move_temp_file(state_manager.get_item('target_path'), state_manager.get_item('output_path'))
487
+ else:
488
+ if restore_audio(state_manager.get_item('target_path'), state_manager.get_item('output_path'), trim_frame_start, trim_frame_end):
489
+ video_manager.clear_video_pool()
490
+ logger.debug(wording.get('restoring_audio_succeed'), __name__)
491
+ else:
492
+ video_manager.clear_video_pool()
493
+ if is_process_stopping():
494
+ process_manager.end()
495
+ return 4
496
+ logger.warn(wording.get('restoring_audio_skipped'), __name__)
497
+ move_temp_file(state_manager.get_item('target_path'), state_manager.get_item('output_path'))
498
+
499
+ logger.debug(wording.get('clearing_temp'), __name__)
500
+ clear_temp_directory(state_manager.get_item('target_path'))
501
+
502
+ if is_video(state_manager.get_item('output_path')):
503
+ seconds = '{:.2f}'.format((time() - start_time))
504
+ logger.info(wording.get('processing_video_succeed').format(seconds = seconds), __name__)
505
+ else:
506
+ logger.error(wording.get('processing_video_failed'), __name__)
507
+ process_manager.end()
508
+ return 1
509
+ process_manager.end()
510
+ return 0
511
+
512
+
513
+ def is_process_stopping() -> bool:
514
+ if process_manager.is_stopping():
515
+ process_manager.end()
516
+ logger.info(wording.get('processing_stopped'), __name__)
517
+ return process_manager.is_pending()