3.0.0 Gold (#787)

* Replace audio whenever set via source

* use scale_face_landmark_5() in age_modifier

* Fix wording and ordering of options

* Adjust wording for face editor

* Fix wording for processors

* Switch order of frame colorizer options

* That condition is actual not needed

* Simplify UI layout API by removing pre_render()

* Clean args and safe cast ini values (#775)

* Clean args and safe cast ini values

* Clean args and safe cast ini values

* Clean args and safe cast ini values

* Introduce paths group

* Fix job list command and change order

* Add job list testing todo

* Fix spacing in typing

* Fix benchmark by ignoring audio

* Simplify and avoid knowing the provider values (#782)

* Fix logger table with empty value

* Complete Typing

---------

Co-authored-by: harisreedhar <h4harisreedhar.s.s@gmail.com>
This commit is contained in:
Henry Ruhs 2024-10-02 11:08:05 +02:00 committed by GitHub
parent 904de93565
commit e42f91dadf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
27 changed files with 208 additions and 155 deletions

View File

@ -36,12 +36,12 @@ commands:
run run the program run run the program
headless-run run the program in headless mode headless-run run the program in headless mode
force-download force automate downloads and exit force-download force automate downloads and exit
job-list list jobs by status
job-create create a drafted job job-create create a drafted job
job-submit submit a drafted job to become a queued job job-submit submit a drafted job to become a queued job
job-submit-all submit all drafted jobs to become a queued jobs job-submit-all submit all drafted jobs to become a queued jobs
job-delete delete a drafted, queued, failed or completed job job-delete delete a drafted, queued, failed or completed job
job-delete-all delete all drafted, queued, failed and completed jobs job-delete-all delete all drafted, queued, failed and completed jobs
job-list list jobs by status
job-add-step add a step to a drafted job job-add-step add a step to a drafted job
job-remix-step remix a previous step from a drafted job job-remix-step remix a previous step from a drafted job
job-insert-step insert a step to a drafted job job-insert-step insert a step to a drafted job

View File

@ -6,8 +6,8 @@ output_path =
[face_detector] [face_detector]
face_detector_model = face_detector_model =
face_detector_angles =
face_detector_size = face_detector_size =
face_detector_angles =
face_detector_score = face_detector_score =
[face_landmarker] [face_landmarker]
@ -17,10 +17,10 @@ face_landmarker_score =
[face_selector] [face_selector]
face_selector_mode = face_selector_mode =
face_selector_order = face_selector_order =
face_selector_gender =
face_selector_race =
face_selector_age_start = face_selector_age_start =
face_selector_age_end = face_selector_age_end =
face_selector_gender =
face_selector_race =
reference_face_position = reference_face_position =
reference_face_distance = reference_face_distance =
reference_frame_number = reference_frame_number =
@ -75,8 +75,8 @@ face_enhancer_blend =
face_swapper_model = face_swapper_model =
face_swapper_pixel_boost = face_swapper_pixel_boost =
frame_colorizer_model = frame_colorizer_model =
frame_colorizer_blend =
frame_colorizer_size = frame_colorizer_size =
frame_colorizer_blend =
frame_enhancer_model = frame_enhancer_model =
frame_enhancer_blend = frame_enhancer_blend =
lip_syncer_model = lip_syncer_model =

View File

@ -50,10 +50,10 @@ def apply_args(args : Args, apply_state_item : ApplyStateItem) -> None:
# face selector # face selector
state_manager.init_item('face_selector_mode', args.get('face_selector_mode')) state_manager.init_item('face_selector_mode', args.get('face_selector_mode'))
state_manager.init_item('face_selector_order', args.get('face_selector_order')) state_manager.init_item('face_selector_order', args.get('face_selector_order'))
state_manager.init_item('face_selector_gender', args.get('face_selector_gender'))
state_manager.init_item('face_selector_race', args.get('face_selector_race'))
state_manager.init_item('face_selector_age_start', args.get('face_selector_age_start')) state_manager.init_item('face_selector_age_start', args.get('face_selector_age_start'))
state_manager.init_item('face_selector_age_end', args.get('face_selector_age_end')) state_manager.init_item('face_selector_age_end', args.get('face_selector_age_end'))
state_manager.init_item('face_selector_gender', args.get('face_selector_gender'))
state_manager.init_item('face_selector_race', args.get('face_selector_race'))
state_manager.init_item('reference_face_position', args.get('reference_face_position')) state_manager.init_item('reference_face_position', args.get('reference_face_position'))
state_manager.init_item('reference_face_distance', args.get('reference_face_distance')) state_manager.init_item('reference_face_distance', args.get('reference_face_distance'))
state_manager.init_item('reference_frame_number', args.get('reference_frame_number')) state_manager.init_item('reference_frame_number', args.get('reference_frame_number'))
@ -97,10 +97,9 @@ def apply_args(args : Args, apply_state_item : ApplyStateItem) -> None:
for processor_module in get_processors_modules(available_processors): for processor_module in get_processors_modules(available_processors):
processor_module.apply_args(args, apply_state_item) processor_module.apply_args(args, apply_state_item)
# uis # uis
if args.get('command') == 'run': apply_state_item('open_browser', args.get('open_browser'))
apply_state_item('open_browser', args.get('open_browser')) apply_state_item('ui_layouts', args.get('ui_layouts'))
apply_state_item('ui_layouts', args.get('ui_layouts')) apply_state_item('ui_workflow', args.get('ui_workflow'))
apply_state_item('ui_workflow', args.get('ui_workflow'))
# execution # execution
apply_state_item('execution_device_id', args.get('execution_device_id')) apply_state_item('execution_device_id', args.get('execution_device_id'))
apply_state_item('execution_providers', args.get('execution_providers')) apply_state_item('execution_providers', args.get('execution_providers'))

View File

@ -1,5 +1,5 @@
import platform import platform
from typing import Any, Sequence from typing import Any, Optional, Sequence
def is_linux() -> bool: def is_linux() -> bool:
@ -50,6 +50,20 @@ def calc_float_step(float_range : Sequence[float]) -> float:
return round(float_range[1] - float_range[0], 2) return round(float_range[1] - float_range[0], 2)
def cast_int(value : Any) -> Optional[Any]:
try:
return int(value)
except (ValueError, TypeError):
return None
def cast_float(value : Any) -> Optional[Any]:
try:
return float(value)
except (ValueError, TypeError):
return None
def get_first(__list__ : Any) -> Any: def get_first(__list__ : Any) -> Any:
return next(iter(__list__), None) return next(iter(__list__), None)

View File

@ -2,6 +2,7 @@ from configparser import ConfigParser
from typing import Any, List, Optional from typing import Any, List, Optional
from facefusion import state_manager from facefusion import state_manager
from facefusion.common_helper import cast_float, cast_int
CONFIG = None CONFIG = None
@ -33,7 +34,7 @@ def get_int_value(key : str, fallback : Optional[str] = None) -> Optional[int]:
value = get_value_by_notation(key) value = get_value_by_notation(key)
if value or fallback: if value or fallback:
return int(value or fallback) return cast_int(value or fallback)
return None return None
@ -41,7 +42,7 @@ def get_float_value(key : str, fallback : Optional[str] = None) -> Optional[floa
value = get_value_by_notation(key) value = get_value_by_notation(key)
if value or fallback: if value or fallback:
return float(value or fallback) return cast_float(value or fallback)
return None return None
@ -67,7 +68,7 @@ def get_int_list(key : str, fallback : Optional[str] = None) -> Optional[List[in
value = get_value_by_notation(key) value = get_value_by_notation(key)
if value or fallback: if value or fallback:
return [ int(value) for value in (value or fallback).split(' ') ] return [ cast_int(value) for value in (value or fallback).split(' ') ]
return None return None
@ -75,7 +76,7 @@ def get_float_list(key : str, fallback : Optional[str] = None) -> Optional[List[
value = get_value_by_notation(key) value = get_value_by_notation(key)
if value or fallback: if value or fallback:
return [ float(value) for value in (value or fallback).split(' ') ] return [ cast_float(value) for value in (value or fallback).split(' ') ]
return None return None

View File

@ -50,7 +50,7 @@ def route(args : Args) -> None:
if state_manager.get_item('command') == 'force-download': if state_manager.get_item('command') == 'force-download':
error_code = force_download() error_code = force_download()
return conditional_exit(error_code) return conditional_exit(error_code)
if state_manager.get_item('command') in [ 'job-create', 'job-submit', 'job-submit-all', 'job-delete', 'job-delete-all', 'job-add-step', 'job-remix-step', 'job-insert-step', 'job-remove-step', 'job-list' ]: 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' ]:
if not job_manager.init_jobs(state_manager.get_item('jobs_path')): if not job_manager.init_jobs(state_manager.get_item('jobs_path')):
hard_exit(1) hard_exit(1)
error_code = route_job_manager(args) error_code = route_job_manager(args)
@ -177,6 +177,13 @@ def force_download() -> ErrorCode:
def route_job_manager(args : Args) -> ErrorCode: def route_job_manager(args : Args) -> ErrorCode:
if state_manager.get_item('command') == 'job-list':
job_headers, job_contents = compose_job_list(state_manager.get_item('job_status'))
if job_contents:
logger.table(job_headers, job_contents)
return 0
return 1
if state_manager.get_item('command') == 'job-create': if state_manager.get_item('command') == 'job-create':
if job_manager.create_job(state_manager.get_item('job_id')): if job_manager.create_job(state_manager.get_item('job_id')):
logger.info(wording.get('job_created').format(job_id = state_manager.get_item('job_id')), __name__) logger.info(wording.get('job_created').format(job_id = state_manager.get_item('job_id')), __name__)
@ -207,13 +214,6 @@ def route_job_manager(args : Args) -> ErrorCode:
return 0 return 0
logger.error(wording.get('job_all_not_deleted'), __name__) logger.error(wording.get('job_all_not_deleted'), __name__)
return 1 return 1
if state_manager.get_item('command') == 'job-list':
job_headers, job_contents = compose_job_list(state_manager.get_item('job_status'))
if job_contents:
logger.table(job_headers, job_contents)
return 0
return 1
if state_manager.get_item('command') == 'job-add-step': if state_manager.get_item('command') == 'job-add-step':
step_args = reduce_step_args(args) step_args = reduce_step_args(args)
@ -403,15 +403,15 @@ def process_video(start_time : float) -> ErrorCode:
logger.info(wording.get('skipping_audio'), __name__) logger.info(wording.get('skipping_audio'), __name__)
move_temp_file(state_manager.get_item('target_path'), state_manager.get_item('output_path')) move_temp_file(state_manager.get_item('target_path'), state_manager.get_item('output_path'))
else: else:
if 'lip_syncer' in state_manager.get_item('processors'): source_audio_path = get_first(filter_audio_paths(state_manager.get_item('source_paths')))
source_audio_path = get_first(filter_audio_paths(state_manager.get_item('source_paths'))) if source_audio_path:
if source_audio_path and replace_audio(state_manager.get_item('target_path'), source_audio_path, state_manager.get_item('output_path')): if replace_audio(state_manager.get_item('target_path'), source_audio_path, state_manager.get_item('output_path')):
logger.debug(wording.get('restoring_audio_succeed'), __name__) logger.debug(wording.get('replacing_audio_succeed'), __name__)
else: else:
if is_process_stopping(): if is_process_stopping():
process_manager.end() process_manager.end()
return 4 return 4
logger.warn(wording.get('restoring_audio_skipped'), __name__) logger.warn(wording.get('replacing_audio_skipped'), __name__)
move_temp_file(state_manager.get_item('target_path'), state_manager.get_item('output_path')) move_temp_file(state_manager.get_item('target_path'), state_manager.get_item('output_path'))
else: else:
if restore_audio(state_manager.get_item('target_path'), state_manager.get_item('output_path'), state_manager.get_item('output_video_fps')): if restore_audio(state_manager.get_item('target_path'), state_manager.get_item('output_path'), state_manager.get_item('output_video_fps')):

View File

@ -6,7 +6,7 @@ from typing import Any, List
from onnxruntime import get_available_providers, set_default_logger_severity from onnxruntime import get_available_providers, set_default_logger_severity
from facefusion.choices import execution_provider_set from facefusion.choices import execution_provider_set
from facefusion.typing import ExecutionDevice, ExecutionProviderKey, ExecutionProviderSet, ExecutionProviderValue, ValueAndUnit from facefusion.typing import ExecutionDevice, ExecutionProviderKey, ExecutionProviderSet, ValueAndUnit
set_default_logger_severity(3) set_default_logger_severity(3)
@ -29,23 +29,18 @@ def get_available_execution_provider_set() -> ExecutionProviderSet:
return available_execution_provider_set return available_execution_provider_set
def extract_execution_providers(execution_provider_keys : List[ExecutionProviderKey]) -> List[ExecutionProviderValue]:
return [ execution_provider_set[execution_provider_key] for execution_provider_key in execution_provider_keys if execution_provider_key in execution_provider_set ]
def create_execution_providers(execution_device_id : str, execution_provider_keys : List[ExecutionProviderKey]) -> List[Any]: def create_execution_providers(execution_device_id : str, execution_provider_keys : List[ExecutionProviderKey]) -> List[Any]:
execution_providers = extract_execution_providers(execution_provider_keys) execution_providers : List[Any] = []
execution_providers_with_options : List[Any] = []
for execution_provider in execution_providers: for execution_provider_key in execution_provider_keys:
if execution_provider == 'CUDAExecutionProvider': if execution_provider_key == 'cuda':
execution_providers_with_options.append((execution_provider, execution_providers.append((execution_provider_set.get(execution_provider_key),
{ {
'device_id': execution_device_id, 'device_id': execution_device_id,
'cudnn_conv_algo_search': 'EXHAUSTIVE' if use_exhaustive() else 'DEFAULT' 'cudnn_conv_algo_search': 'EXHAUSTIVE' if use_exhaustive() else 'DEFAULT'
})) }))
if execution_provider == 'TensorrtExecutionProvider': if execution_provider_key == 'tensorrt':
execution_providers_with_options.append((execution_provider, execution_providers.append((execution_provider_set.get(execution_provider_key),
{ {
'device_id': execution_device_id, 'device_id': execution_device_id,
'trt_engine_cache_enable': True, 'trt_engine_cache_enable': True,
@ -54,24 +49,24 @@ def create_execution_providers(execution_device_id : str, execution_provider_key
'trt_timing_cache_path': '.caches', 'trt_timing_cache_path': '.caches',
'trt_builder_optimization_level': 5 'trt_builder_optimization_level': 5
})) }))
if execution_provider == 'OpenVINOExecutionProvider': if execution_provider_key == 'openvino':
execution_providers_with_options.append((execution_provider, execution_providers.append((execution_provider_set.get(execution_provider_key),
{ {
'device_type': 'GPU.' + execution_device_id, 'device_type': 'GPU.' + execution_device_id,
'precision': 'FP32' 'precision': 'FP32'
})) }))
if execution_provider in [ 'DmlExecutionProvider', 'ROCMExecutionProvider' ]: if execution_provider_key in [ 'directml', 'rocm' ]:
execution_providers_with_options.append((execution_provider, execution_providers.append((execution_provider_set.get(execution_provider_key),
{ {
'device_id': execution_device_id 'device_id': execution_device_id
})) }))
if execution_provider == 'CoreMLExecutionProvider': if execution_provider_key == 'coreml':
execution_providers_with_options.append(execution_provider) execution_providers.append(execution_provider_set.get(execution_provider_key))
if 'CPUExecutionProvider' in execution_providers: if 'cpu' in execution_provider_keys:
execution_providers_with_options.append('CPUExecutionProvider') execution_providers.append(execution_provider_set.get('cpu'))
return execution_providers_with_options return execution_providers
def use_exhaustive() -> bool: def use_exhaustive() -> bool:

View File

@ -50,6 +50,7 @@ def table(headers : TableHeaders, contents : TableContents) -> None:
package_logger.info(table_separator) package_logger.info(table_separator)
for content in contents: for content in contents:
content = [ value if value else '' for value in content ]
package_logger.info(table_column.format(*content)) package_logger.info(table_column.format(*content))
package_logger.info(table_separator) package_logger.info(table_separator)

View File

@ -13,7 +13,7 @@ from facefusion import config, content_analyser, face_classifier, face_detector,
from facefusion.common_helper import create_int_metavar from facefusion.common_helper import create_int_metavar
from facefusion.download import conditional_download_hashes, conditional_download_sources from facefusion.download import conditional_download_hashes, conditional_download_sources
from facefusion.face_analyser import get_many_faces, get_one_face from facefusion.face_analyser import get_many_faces, get_one_face
from facefusion.face_helper import merge_matrix, paste_back, warp_face_by_face_landmark_5 from facefusion.face_helper import merge_matrix, paste_back, scale_face_landmark_5, warp_face_by_face_landmark_5
from facefusion.face_masker import create_occlusion_mask, create_static_box_mask from facefusion.face_masker import create_occlusion_mask, create_static_box_mask
from facefusion.face_selector import find_similar_faces, sort_and_filter_faces from facefusion.face_selector import find_similar_faces, sort_and_filter_faces
from facefusion.face_store import get_reference_faces from facefusion.face_store import get_reference_faces
@ -119,7 +119,7 @@ def modify_age(target_face : Face, temp_vision_frame : VisionFrame) -> VisionFra
model_size = get_model_options().get('size') model_size = get_model_options().get('size')
crop_size = (model_size[0] // 2, model_size[1] // 2) crop_size = (model_size[0] // 2, model_size[1] // 2)
face_landmark_5 = target_face.landmark_set.get('5/68').copy() face_landmark_5 = target_face.landmark_set.get('5/68').copy()
extend_face_landmark_5 = (face_landmark_5 - face_landmark_5[2]) * 2 + face_landmark_5[2] extend_face_landmark_5 = scale_face_landmark_5(face_landmark_5, 2.0)
crop_vision_frame, affine_matrix = warp_face_by_face_landmark_5(temp_vision_frame, face_landmark_5, model_template, crop_size) crop_vision_frame, affine_matrix = warp_face_by_face_landmark_5(temp_vision_frame, face_landmark_5, model_template, crop_size)
extend_vision_frame, extend_affine_matrix = warp_face_by_face_landmark_5(temp_vision_frame, extend_face_landmark_5, model_template, model_size) extend_vision_frame, extend_affine_matrix = warp_face_by_face_landmark_5(temp_vision_frame, extend_face_landmark_5, model_template, model_size)
extend_vision_frame_raw = extend_vision_frame.copy() extend_vision_frame_raw = extend_vision_frame.copy()

View File

@ -132,8 +132,8 @@ def register_args(program : ArgumentParser) -> None:
group_processors.add_argument('--face-editor-mouth-position-horizontal', help = wording.get('help.face_editor_mouth_position_horizontal'), type = float, default = config.get_float_value('processors.face_editor_mouth_position_horizontal', '0'), choices = processors_choices.face_editor_mouth_position_horizontal_range, metavar = create_float_metavar(processors_choices.face_editor_mouth_position_horizontal_range)) group_processors.add_argument('--face-editor-mouth-position-horizontal', help = wording.get('help.face_editor_mouth_position_horizontal'), type = float, default = config.get_float_value('processors.face_editor_mouth_position_horizontal', '0'), choices = processors_choices.face_editor_mouth_position_horizontal_range, metavar = create_float_metavar(processors_choices.face_editor_mouth_position_horizontal_range))
group_processors.add_argument('--face-editor-mouth-position-vertical', help = wording.get('help.face_editor_mouth_position_vertical'), type = float, default = config.get_float_value('processors.face_editor_mouth_position_vertical', '0'), choices = processors_choices.face_editor_mouth_position_vertical_range, metavar = create_float_metavar(processors_choices.face_editor_mouth_position_vertical_range)) group_processors.add_argument('--face-editor-mouth-position-vertical', help = wording.get('help.face_editor_mouth_position_vertical'), type = float, default = config.get_float_value('processors.face_editor_mouth_position_vertical', '0'), choices = processors_choices.face_editor_mouth_position_vertical_range, metavar = create_float_metavar(processors_choices.face_editor_mouth_position_vertical_range))
group_processors.add_argument('--face-editor-head-pitch', help = wording.get('help.face_editor_head_pitch'), type = float, default = config.get_float_value('processors.face_editor_head_pitch', '0'), choices = processors_choices.face_editor_head_pitch_range, metavar = create_float_metavar(processors_choices.face_editor_head_pitch_range)) group_processors.add_argument('--face-editor-head-pitch', help = wording.get('help.face_editor_head_pitch'), type = float, default = config.get_float_value('processors.face_editor_head_pitch', '0'), choices = processors_choices.face_editor_head_pitch_range, metavar = create_float_metavar(processors_choices.face_editor_head_pitch_range))
group_processors.add_argument('--face-editor-head-yaw', help=wording.get('help.face_editor_head_yaw'), type = float, default = config.get_float_value('processors.face_editor_head_yaw', '0'), choices = processors_choices.face_editor_head_yaw_range, metavar = create_float_metavar(processors_choices.face_editor_head_yaw_range)) group_processors.add_argument('--face-editor-head-yaw', help = wording.get('help.face_editor_head_yaw'), type = float, default = config.get_float_value('processors.face_editor_head_yaw', '0'), choices = processors_choices.face_editor_head_yaw_range, metavar = create_float_metavar(processors_choices.face_editor_head_yaw_range))
group_processors.add_argument('--face-editor-head-roll', help=wording.get('help.face_editor_head_roll'), type = float, default = config.get_float_value('processors.face_editor_head_roll', '0'), choices = processors_choices.face_editor_head_roll_range, metavar = create_float_metavar(processors_choices.face_editor_head_roll_range)) group_processors.add_argument('--face-editor-head-roll', help = wording.get('help.face_editor_head_roll'), type = float, default = config.get_float_value('processors.face_editor_head_roll', '0'), choices = processors_choices.face_editor_head_roll_range, metavar = create_float_metavar(processors_choices.face_editor_head_roll_range))
facefusion.jobs.job_store.register_step_keys([ 'face_editor_model', 'face_editor_eyebrow_direction', 'face_editor_eye_gaze_horizontal', 'face_editor_eye_gaze_vertical', 'face_editor_eye_open_ratio', 'face_editor_lip_open_ratio', 'face_editor_mouth_grim', 'face_editor_mouth_pout', 'face_editor_mouth_purse', 'face_editor_mouth_smile', 'face_editor_mouth_position_horizontal', 'face_editor_mouth_position_vertical', 'face_editor_head_pitch', 'face_editor_head_yaw', 'face_editor_head_roll' ]) facefusion.jobs.job_store.register_step_keys([ 'face_editor_model', 'face_editor_eyebrow_direction', 'face_editor_eye_gaze_horizontal', 'face_editor_eye_gaze_vertical', 'face_editor_eye_open_ratio', 'face_editor_lip_open_ratio', 'face_editor_mouth_grim', 'face_editor_mouth_pout', 'face_editor_mouth_purse', 'face_editor_mouth_smile', 'face_editor_mouth_position_horizontal', 'face_editor_mouth_position_vertical', 'face_editor_head_pitch', 'face_editor_head_yaw', 'face_editor_head_roll' ])

View File

@ -143,8 +143,8 @@ def register_args(program : ArgumentParser) -> None:
group_processors = find_argument_group(program, 'processors') group_processors = find_argument_group(program, 'processors')
if group_processors: if group_processors:
group_processors.add_argument('--frame-colorizer-model', help = wording.get('help.frame_colorizer_model'), default = config.get_str_value('processors.frame_colorizer_model', 'ddcolor'), choices = processors_choices.frame_colorizer_models) group_processors.add_argument('--frame-colorizer-model', help = wording.get('help.frame_colorizer_model'), default = config.get_str_value('processors.frame_colorizer_model', 'ddcolor'), choices = processors_choices.frame_colorizer_models)
group_processors.add_argument('--frame-colorizer-blend', help = wording.get('help.frame_colorizer_blend'), type = int, default = config.get_int_value('processors.frame_colorizer_blend', '100'), choices = processors_choices.frame_colorizer_blend_range, metavar = create_int_metavar(processors_choices.frame_colorizer_blend_range))
group_processors.add_argument('--frame-colorizer-size', help = wording.get('help.frame_colorizer_size'), type = str, default = config.get_str_value('processors.frame_colorizer_size', '256x256'), choices = processors_choices.frame_colorizer_sizes) group_processors.add_argument('--frame-colorizer-size', help = wording.get('help.frame_colorizer_size'), type = str, default = config.get_str_value('processors.frame_colorizer_size', '256x256'), choices = processors_choices.frame_colorizer_sizes)
group_processors.add_argument('--frame-colorizer-blend', help = wording.get('help.frame_colorizer_blend'), type = int, default = config.get_int_value('processors.frame_colorizer_blend', '100'), choices = processors_choices.frame_colorizer_blend_range, metavar = create_int_metavar(processors_choices.frame_colorizer_blend_range))
facefusion.jobs.job_store.register_step_keys([ 'frame_colorizer_model', 'frame_colorizer_blend', 'frame_colorizer_size' ]) facefusion.jobs.job_store.register_step_keys([ 'frame_colorizer_model', 'frame_colorizer_blend', 'frame_colorizer_size' ])

View File

@ -90,24 +90,41 @@ ProcessorStateKey = Literal\
'face_swapper_model', 'face_swapper_model',
'face_swapper_pixel_boost', 'face_swapper_pixel_boost',
'frame_colorizer_model', 'frame_colorizer_model',
'frame_colorizer_blend',
'frame_colorizer_size', 'frame_colorizer_size',
'frame_colorizer_blend',
'frame_enhancer_model', 'frame_enhancer_model',
'frame_enhancer_blend', 'frame_enhancer_blend',
'lip_syncer_model' 'lip_syncer_model'
] ]
ProcessorState = TypedDict('ProcessorState', ProcessorState = TypedDict('ProcessorState',
{ {
'age_modifier_model': AgeModifierModel, 'age_modifier_model' : AgeModifierModel,
'age_modifier_direction': int, 'age_modifier_direction' : int,
'expression_restorer_model' : ExpressionRestorerModel,
'expression_restorer_factor' : int,
'face_debugger_items' : List[FaceDebuggerItem], 'face_debugger_items' : List[FaceDebuggerItem],
'face_editor_model' : FaceEditorModel,
'face_editor_eyebrow_direction' : float,
'face_editor_eye_gaze_horizontal' : float,
'face_editor_eye_gaze_vertical' : float,
'face_editor_eye_open_ratio' : float,
'face_editor_lip_open_ratio' : float,
'face_editor_mouth_grim' : float,
'face_editor_mouth_pout' : float,
'face_editor_mouth_purse' : float,
'face_editor_mouth_smile' : float,
'face_editor_mouth_position_horizontal' : float,
'face_editor_mouth_position_vertical' : float,
'face_editor_head_pitch' : float,
'face_editor_head_yaw' : float,
'face_editor_head_roll' : float,
'face_enhancer_model' : FaceEnhancerModel, 'face_enhancer_model' : FaceEnhancerModel,
'face_enhancer_blend' : int, 'face_enhancer_blend' : int,
'face_swapper_model' : FaceSwapperModel, 'face_swapper_model' : FaceSwapperModel,
'face_swapper_pixel_boost' : str, 'face_swapper_pixel_boost' : str,
'frame_colorizer_model' : FrameColorizerModel, 'frame_colorizer_model' : FrameColorizerModel,
'frame_colorizer_blend' : int,
'frame_colorizer_size' : str, 'frame_colorizer_size' : str,
'frame_colorizer_blend' : int,
'frame_enhancer_model' : FrameEnhancerModel, 'frame_enhancer_model' : FrameEnhancerModel,
'frame_enhancer_blend' : int, 'frame_enhancer_blend' : int,
'lip_syncer_model' : LipSyncerModel 'lip_syncer_model' : LipSyncerModel

View File

@ -7,7 +7,7 @@ from facefusion.execution import get_execution_provider_choices
from facefusion.filesystem import list_directory from facefusion.filesystem import list_directory
from facefusion.jobs import job_store from facefusion.jobs import job_store
from facefusion.processors.core import get_processors_modules from facefusion.processors.core import get_processors_modules
from facefusion.program_helper import suggest_face_detector_choices from facefusion.program_helper import remove_args, suggest_face_detector_choices
def create_help_formatter_small(prog : str) -> HelpFormatter: def create_help_formatter_small(prog : str) -> HelpFormatter:
@ -20,7 +20,8 @@ def create_help_formatter_large(prog : str) -> HelpFormatter:
def create_config_program() -> ArgumentParser: def create_config_program() -> ArgumentParser:
program = ArgumentParser(add_help = False) program = ArgumentParser(add_help = False)
program.add_argument('-c', '--config-path', help = wording.get('help.config_path'), default = 'facefusion.ini') group_paths = program.add_argument_group('paths')
group_paths.add_argument('-c', '--config-path', help = wording.get('help.config_path'), default = 'facefusion.ini')
job_store.register_job_keys([ 'config-path' ]) job_store.register_job_keys([ 'config-path' ])
apply_config_path(program) apply_config_path(program)
return program return program
@ -28,16 +29,18 @@ def create_config_program() -> ArgumentParser:
def create_jobs_path_program() -> ArgumentParser: def create_jobs_path_program() -> ArgumentParser:
program = ArgumentParser(add_help = False) program = ArgumentParser(add_help = False)
program.add_argument('-j', '--jobs-path', help = wording.get('help.jobs_path'), default = config.get_str_value('paths.jobs_path', '.jobs')) group_paths = program.add_argument_group('paths')
group_paths.add_argument('-j', '--jobs-path', help = wording.get('help.jobs_path'), default = config.get_str_value('paths.jobs_path', '.jobs'))
job_store.register_job_keys([ 'jobs_path' ]) job_store.register_job_keys([ 'jobs_path' ])
return program return program
def create_paths_program() -> ArgumentParser: def create_paths_program() -> ArgumentParser:
program = ArgumentParser(add_help = False) program = ArgumentParser(add_help = False)
program.add_argument('-s', '--source-paths', help = wording.get('help.source_paths'), action = 'append', default = config.get_str_list('paths.source_paths')) group_paths = program.add_argument_group('paths')
program.add_argument('-t', '--target-path', help = wording.get('help.target_path'), default = config.get_str_value('paths.target_path')) group_paths.add_argument('-s', '--source-paths', help = wording.get('help.source_paths'), action = 'append', default = config.get_str_list('paths.source_paths'))
program.add_argument('-o', '--output-path', help = wording.get('help.output_path'), default = config.get_str_value('paths.output_path')) group_paths.add_argument('-t', '--target-path', help = wording.get('help.target_path'), default = config.get_str_value('paths.target_path'))
group_paths.add_argument('-o', '--output-path', help = wording.get('help.output_path'), default = config.get_str_value('paths.output_path'))
job_store.register_step_keys([ 'source_paths', 'target_path', 'output_path' ]) job_store.register_step_keys([ 'source_paths', 'target_path', 'output_path' ])
return program return program
@ -67,10 +70,10 @@ def create_face_selector_program() -> ArgumentParser:
group_face_selector = program.add_argument_group('face selector') group_face_selector = program.add_argument_group('face selector')
group_face_selector.add_argument('--face-selector-mode', help = wording.get('help.face_selector_mode'), default = config.get_str_value('face_selector.face_selector_mode', 'reference'), choices = facefusion.choices.face_selector_modes) group_face_selector.add_argument('--face-selector-mode', help = wording.get('help.face_selector_mode'), default = config.get_str_value('face_selector.face_selector_mode', 'reference'), choices = facefusion.choices.face_selector_modes)
group_face_selector.add_argument('--face-selector-order', help = wording.get('help.face_selector_order'), default = config.get_str_value('face_selector.face_selector_order', 'large-small'), choices = facefusion.choices.face_selector_orders) group_face_selector.add_argument('--face-selector-order', help = wording.get('help.face_selector_order'), default = config.get_str_value('face_selector.face_selector_order', 'large-small'), choices = facefusion.choices.face_selector_orders)
group_face_selector.add_argument('--face-selector-gender', help = wording.get('help.face_selector_gender'), default = config.get_str_value('face_selector.face_selector_gender'), choices = facefusion.choices.face_selector_genders)
group_face_selector.add_argument('--face-selector-race', help = wording.get('help.face_selector_race'), default = config.get_str_value('face_selector.face_selector_race'), choices = facefusion.choices.face_selector_races)
group_face_selector.add_argument('--face-selector-age-start', help = wording.get('help.face_selector_age_start'), type = int, default = config.get_int_value('face_selector.face_selector_age_start'), choices = facefusion.choices.face_selector_age_range, metavar = create_int_metavar(facefusion.choices.face_selector_age_range)) group_face_selector.add_argument('--face-selector-age-start', help = wording.get('help.face_selector_age_start'), type = int, default = config.get_int_value('face_selector.face_selector_age_start'), choices = facefusion.choices.face_selector_age_range, metavar = create_int_metavar(facefusion.choices.face_selector_age_range))
group_face_selector.add_argument('--face-selector-age-end', help = wording.get('help.face_selector_age_end'), type = int, default = config.get_int_value('face_selector.face_selector_age_end'), choices = facefusion.choices.face_selector_age_range, metavar = create_int_metavar(facefusion.choices.face_selector_age_range)) group_face_selector.add_argument('--face-selector-age-end', help = wording.get('help.face_selector_age_end'), type = int, default = config.get_int_value('face_selector.face_selector_age_end'), choices = facefusion.choices.face_selector_age_range, metavar = create_int_metavar(facefusion.choices.face_selector_age_range))
group_face_selector.add_argument('--face-selector-gender', help = wording.get('help.face_selector_gender'), default = config.get_str_value('face_selector.face_selector_gender'), choices = facefusion.choices.face_selector_genders)
group_face_selector.add_argument('--face-selector-race', help = wording.get('help.face_selector_race'), default = config.get_str_value('face_selector.face_selector_race'), choices = facefusion.choices.face_selector_races)
group_face_selector.add_argument('--reference-face-position', help = wording.get('help.reference_face_position'), type = int, default = config.get_int_value('face_selector.reference_face_position', '0')) group_face_selector.add_argument('--reference-face-position', help = wording.get('help.reference_face_position'), type = int, default = config.get_int_value('face_selector.reference_face_position', '0'))
group_face_selector.add_argument('--reference-face-distance', help = wording.get('help.reference_face_distance'), type = float, default = config.get_float_value('face_selector.reference_face_distance', '0.6'), choices = facefusion.choices.reference_face_distance_range, metavar = create_float_metavar(facefusion.choices.reference_face_distance_range)) group_face_selector.add_argument('--reference-face-distance', help = wording.get('help.reference_face_distance'), type = float, default = config.get_float_value('face_selector.reference_face_distance', '0.6'), choices = facefusion.choices.reference_face_distance_range, metavar = create_float_metavar(facefusion.choices.reference_face_distance_range))
group_face_selector.add_argument('--reference-frame-number', help = wording.get('help.reference_frame_number'), type = int, default = config.get_int_value('face_selector.reference_frame_number', '0')) group_face_selector.add_argument('--reference-frame-number', help = wording.get('help.reference_frame_number'), type = int, default = config.get_int_value('face_selector.reference_frame_number', '0'))
@ -211,16 +214,16 @@ def create_program() -> ArgumentParser:
sub_program.add_parser('headless-run', help = wording.get('help.headless_run'), parents = [ collect_step_program(), collect_job_program() ], formatter_class = create_help_formatter_large) sub_program.add_parser('headless-run', help = wording.get('help.headless_run'), parents = [ collect_step_program(), collect_job_program() ], formatter_class = create_help_formatter_large)
sub_program.add_parser('force-download', help = wording.get('help.force_download'), parents = [ create_log_level_program() ], formatter_class = create_help_formatter_large) sub_program.add_parser('force-download', help = wording.get('help.force_download'), parents = [ create_log_level_program() ], formatter_class = create_help_formatter_large)
# job manager # job manager
sub_program.add_parser('job-list', help = wording.get('help.job_list'), parents = [ create_job_status_program(), create_jobs_path_program(), create_log_level_program() ], formatter_class = create_help_formatter_large)
sub_program.add_parser('job-create', help = wording.get('help.job_create'), parents = [ create_job_id_program(), create_jobs_path_program(), create_log_level_program() ], formatter_class = create_help_formatter_large) sub_program.add_parser('job-create', help = wording.get('help.job_create'), parents = [ create_job_id_program(), create_jobs_path_program(), create_log_level_program() ], formatter_class = create_help_formatter_large)
sub_program.add_parser('job-submit', help = wording.get('help.job_submit'), parents = [ create_job_id_program(), create_jobs_path_program(), create_log_level_program() ], formatter_class = create_help_formatter_large) sub_program.add_parser('job-submit', help = wording.get('help.job_submit'), parents = [ create_job_id_program(), create_jobs_path_program(), create_log_level_program() ], formatter_class = create_help_formatter_large)
sub_program.add_parser('job-submit-all', help = wording.get('help.job_submit_all'), parents = [ create_jobs_path_program(), create_log_level_program() ], formatter_class = create_help_formatter_large) sub_program.add_parser('job-submit-all', help = wording.get('help.job_submit_all'), parents = [ create_jobs_path_program(), create_log_level_program() ], formatter_class = create_help_formatter_large)
sub_program.add_parser('job-delete', help = wording.get('help.job_delete'), parents = [ create_job_id_program(), create_jobs_path_program(), create_log_level_program() ], formatter_class = create_help_formatter_large) sub_program.add_parser('job-delete', help = wording.get('help.job_delete'), parents = [ create_job_id_program(), create_jobs_path_program(), create_log_level_program() ], formatter_class = create_help_formatter_large)
sub_program.add_parser('job-delete-all', help = wording.get('help.job_delete_all'), parents = [ create_jobs_path_program(), create_log_level_program() ], formatter_class = create_help_formatter_large) sub_program.add_parser('job-delete-all', help = wording.get('help.job_delete_all'), parents = [ create_jobs_path_program(), create_log_level_program() ], formatter_class = create_help_formatter_large)
sub_program.add_parser('job-list', help = wording.get('help.job_list'), parents = [ create_job_status_program(), create_jobs_path_program(), create_log_level_program() ], formatter_class = create_help_formatter_large)
sub_program.add_parser('job-add-step', help = wording.get('help.job_add_step'), parents = [ create_job_id_program(), collect_step_program(), create_log_level_program() ], formatter_class = create_help_formatter_large) sub_program.add_parser('job-add-step', help = wording.get('help.job_add_step'), parents = [ create_job_id_program(), collect_step_program(), create_log_level_program() ], formatter_class = create_help_formatter_large)
sub_program.add_parser('job-remix-step', help = wording.get('help.job_remix_step'), parents = [ create_job_id_program(), create_step_index_program(), collect_step_program(), create_log_level_program() ], formatter_class = create_help_formatter_large) sub_program.add_parser('job-remix-step', help = wording.get('help.job_remix_step'), parents = [ create_job_id_program(), create_step_index_program(), remove_args(collect_step_program(), [ 'target_path' ]), create_log_level_program() ], formatter_class = create_help_formatter_large)
sub_program.add_parser('job-insert-step', help = wording.get('help.job_insert_step'), parents = [ create_job_id_program(), create_step_index_program(), collect_step_program(), create_log_level_program() ], formatter_class = create_help_formatter_large) sub_program.add_parser('job-insert-step', help = wording.get('help.job_insert_step'), parents = [ create_job_id_program(), create_step_index_program(), collect_step_program(), create_log_level_program() ], formatter_class = create_help_formatter_large)
sub_program.add_parser('job-remove-step', help = wording.get('help.job_remove_step'), parents = [ create_job_id_program(), create_step_index_program(), collect_step_program(), create_log_level_program() ], formatter_class = create_help_formatter_large) sub_program.add_parser('job-remove-step', help = wording.get('help.job_remove_step'), parents = [ create_job_id_program(), create_step_index_program(), create_jobs_path_program(), create_log_level_program() ], formatter_class = create_help_formatter_large)
# job runner # job runner
sub_program.add_parser('job-run', help = wording.get('help.job_run'), parents = [ create_job_id_program(), create_config_program(), create_jobs_path_program(), collect_job_program() ], formatter_class = create_help_formatter_large) sub_program.add_parser('job-run', help = wording.get('help.job_run'), parents = [ create_job_id_program(), create_config_program(), create_jobs_path_program(), collect_job_program() ], formatter_class = create_help_formatter_large)
sub_program.add_parser('job-run-all', help = wording.get('help.job_run_all'), parents = [ create_config_program(), create_jobs_path_program(), collect_job_program() ], formatter_class = create_help_formatter_large) sub_program.add_parser('job-run-all', help = wording.get('help.job_run_all'), parents = [ create_config_program(), create_jobs_path_program(), collect_job_program() ], formatter_class = create_help_formatter_large)

View File

@ -13,15 +13,14 @@ def find_argument_group(program : ArgumentParser, group_name : str) -> Optional[
def validate_args(program : ArgumentParser) -> bool: def validate_args(program : ArgumentParser) -> bool:
if not validate_actions(program): if validate_actions(program):
return False for action in program._actions:
if isinstance(action, _SubParsersAction):
for action in program._actions: for _, sub_program in action._name_parser_map.items():
if isinstance(action, _SubParsersAction): if not validate_args(sub_program):
for _, sub_program in action._name_parser_map.items(): return False
if not validate_args(sub_program): return True
return False return False
return True
def validate_actions(program : ArgumentParser) -> bool: def validate_actions(program : ArgumentParser) -> bool:
@ -35,6 +34,14 @@ def validate_actions(program : ArgumentParser) -> bool:
return True return True
def remove_args(program : ArgumentParser, remove_names : List[str]) -> ArgumentParser:
actions = [ action for action in program._actions if action.dest in remove_names ]
for action in actions:
program._actions.remove(action)
return program
def suggest_face_detector_choices(program : ArgumentParser) -> List[str]: def suggest_face_detector_choices(program : ArgumentParser) -> List[str]:
known_args, _ = program.parse_known_args() known_args, _ = program.parse_known_args()
return facefusion.choices.face_detector_set.get(known_args.face_detector_model) #type:ignore[call-overload] return facefusion.choices.face_detector_set.get(known_args.face_detector_model) #type:ignore[call-overload]

View File

@ -47,7 +47,7 @@ FaceSet = Dict[str, List[Face]]
FaceStore = TypedDict('FaceStore', FaceStore = TypedDict('FaceStore',
{ {
'static_faces' : FaceSet, 'static_faces' : FaceSet,
'reference_faces': FaceSet 'reference_faces' : FaceSet
}) })
VisionFrame = NDArray[Any] VisionFrame = NDArray[Any]
@ -109,7 +109,7 @@ OutputVideoEncoder = Literal['libx264', 'libx265', 'libvpx-vp9', 'h264_nvenc', '
OutputVideoPreset = Literal['ultrafast', 'superfast', 'veryfast', 'faster', 'fast', 'medium', 'slow', 'slower', 'veryslow'] OutputVideoPreset = Literal['ultrafast', 'superfast', 'veryfast', 'faster', 'fast', 'medium', 'slow', 'slower', 'veryslow']
Download = TypedDict('Download', Download = TypedDict('Download',
{ {
'url' : str, 'url' : str,
'path' : str 'path' : str
}) })
@ -259,7 +259,7 @@ State = TypedDict('State',
'face_landmarker_score' : Score, 'face_landmarker_score' : Score,
'face_selector_mode' : FaceSelectorMode, 'face_selector_mode' : FaceSelectorMode,
'face_selector_order' : FaceSelectorOrder, 'face_selector_order' : FaceSelectorOrder,
'face_selector_race': Race, 'face_selector_race' : Race,
'face_selector_gender' : Gender, 'face_selector_gender' : Gender,
'face_selector_age_start' : int, 'face_selector_age_start' : int,
'face_selector_age_end' : int, 'face_selector_age_end' : int,
@ -287,16 +287,16 @@ State = TypedDict('State',
'open_browser' : bool, 'open_browser' : bool,
'ui_layouts' : List[str], 'ui_layouts' : List[str],
'ui_workflow' : UiWorkflow, 'ui_workflow' : UiWorkflow,
'execution_device_id': str, 'execution_device_id' : str,
'execution_providers': List[ExecutionProviderKey], 'execution_providers' : List[ExecutionProviderKey],
'execution_thread_count': int, 'execution_thread_count' : int,
'execution_queue_count': int, 'execution_queue_count' : int,
'video_memory_strategy': VideoMemoryStrategy, 'video_memory_strategy' : VideoMemoryStrategy,
'system_memory_limit': int, 'system_memory_limit' : int,
'skip_download': bool, 'skip_download' : bool,
'log_level': LogLevel, 'log_level' : LogLevel,
'job_id': str, 'job_id' : str,
'job_status': JobStatus, 'job_status' : JobStatus,
'step_index': int 'step_index' : int
}) })
StateSet = Dict[AppContext, State] StateSet = Dict[AppContext, State]

View File

@ -82,6 +82,7 @@ def start(benchmark_runs : List[str], benchmark_cycles : int) -> Generator[List[
state_manager.init_item('face_landmarker_score', 0) state_manager.init_item('face_landmarker_score', 0)
state_manager.init_item('temp_frame_format', 'bmp') state_manager.init_item('temp_frame_format', 'bmp')
state_manager.init_item('output_video_preset', 'ultrafast') state_manager.init_item('output_video_preset', 'ultrafast')
state_manager.init_item('skip_audio', True)
state_manager.sync_item('execution_providers') state_manager.sync_item('execution_providers')
state_manager.sync_item('execution_thread_count') state_manager.sync_item('execution_thread_count')
state_manager.sync_item('execution_queue_count') state_manager.sync_item('execution_queue_count')

View File

@ -10,14 +10,14 @@ from facefusion.processors.typing import FrameColorizerModel
from facefusion.uis.core import get_ui_component, register_ui_component from facefusion.uis.core import get_ui_component, register_ui_component
FRAME_COLORIZER_MODEL_DROPDOWN : Optional[gradio.Dropdown] = None FRAME_COLORIZER_MODEL_DROPDOWN : Optional[gradio.Dropdown] = None
FRAME_COLORIZER_BLEND_SLIDER : Optional[gradio.Slider] = None
FRAME_COLORIZER_SIZE_DROPDOWN : Optional[gradio.Dropdown] = None FRAME_COLORIZER_SIZE_DROPDOWN : Optional[gradio.Dropdown] = None
FRAME_COLORIZER_BLEND_SLIDER : Optional[gradio.Slider] = None
def render() -> None: def render() -> None:
global FRAME_COLORIZER_MODEL_DROPDOWN global FRAME_COLORIZER_MODEL_DROPDOWN
global FRAME_COLORIZER_BLEND_SLIDER
global FRAME_COLORIZER_SIZE_DROPDOWN global FRAME_COLORIZER_SIZE_DROPDOWN
global FRAME_COLORIZER_BLEND_SLIDER
FRAME_COLORIZER_MODEL_DROPDOWN = gradio.Dropdown( FRAME_COLORIZER_MODEL_DROPDOWN = gradio.Dropdown(
label = wording.get('uis.frame_colorizer_model_dropdown'), label = wording.get('uis.frame_colorizer_model_dropdown'),
@ -25,6 +25,12 @@ def render() -> None:
value = state_manager.get_item('frame_colorizer_model'), value = state_manager.get_item('frame_colorizer_model'),
visible = 'frame_colorizer' in state_manager.get_item('processors') visible = 'frame_colorizer' in state_manager.get_item('processors')
) )
FRAME_COLORIZER_SIZE_DROPDOWN = gradio.Dropdown(
label = wording.get('uis.frame_colorizer_size_dropdown'),
choices = processors_choices.frame_colorizer_sizes,
value = state_manager.get_item('frame_colorizer_size'),
visible = 'frame_colorizer' in state_manager.get_item('processors')
)
FRAME_COLORIZER_BLEND_SLIDER = gradio.Slider( FRAME_COLORIZER_BLEND_SLIDER = gradio.Slider(
label = wording.get('uis.frame_colorizer_blend_slider'), label = wording.get('uis.frame_colorizer_blend_slider'),
value = state_manager.get_item('frame_colorizer_blend'), value = state_manager.get_item('frame_colorizer_blend'),
@ -33,21 +39,15 @@ def render() -> None:
maximum = processors_choices.frame_colorizer_blend_range[-1], maximum = processors_choices.frame_colorizer_blend_range[-1],
visible = 'frame_colorizer' in state_manager.get_item('processors') visible = 'frame_colorizer' in state_manager.get_item('processors')
) )
FRAME_COLORIZER_SIZE_DROPDOWN = gradio.Dropdown(
label = wording.get('uis.frame_colorizer_size_dropdown'),
choices = processors_choices.frame_colorizer_sizes,
value = state_manager.get_item('frame_colorizer_size'),
visible = 'frame_colorizer' in state_manager.get_item('processors')
)
register_ui_component('frame_colorizer_model_dropdown', FRAME_COLORIZER_MODEL_DROPDOWN) register_ui_component('frame_colorizer_model_dropdown', FRAME_COLORIZER_MODEL_DROPDOWN)
register_ui_component('frame_colorizer_blend_slider', FRAME_COLORIZER_BLEND_SLIDER)
register_ui_component('frame_colorizer_size_dropdown', FRAME_COLORIZER_SIZE_DROPDOWN) register_ui_component('frame_colorizer_size_dropdown', FRAME_COLORIZER_SIZE_DROPDOWN)
register_ui_component('frame_colorizer_blend_slider', FRAME_COLORIZER_BLEND_SLIDER)
def listen() -> None: def listen() -> None:
FRAME_COLORIZER_MODEL_DROPDOWN.change(update_frame_colorizer_model, inputs = FRAME_COLORIZER_MODEL_DROPDOWN, outputs = FRAME_COLORIZER_MODEL_DROPDOWN) FRAME_COLORIZER_MODEL_DROPDOWN.change(update_frame_colorizer_model, inputs = FRAME_COLORIZER_MODEL_DROPDOWN, outputs = FRAME_COLORIZER_MODEL_DROPDOWN)
FRAME_COLORIZER_BLEND_SLIDER.release(update_frame_colorizer_blend, inputs = FRAME_COLORIZER_BLEND_SLIDER)
FRAME_COLORIZER_SIZE_DROPDOWN.change(update_frame_colorizer_size, inputs = FRAME_COLORIZER_SIZE_DROPDOWN) FRAME_COLORIZER_SIZE_DROPDOWN.change(update_frame_colorizer_size, inputs = FRAME_COLORIZER_SIZE_DROPDOWN)
FRAME_COLORIZER_BLEND_SLIDER.release(update_frame_colorizer_blend, inputs = FRAME_COLORIZER_BLEND_SLIDER)
processors_checkbox_group = get_ui_component('processors_checkbox_group') processors_checkbox_group = get_ui_component('processors_checkbox_group')
if processors_checkbox_group: if processors_checkbox_group:
@ -69,9 +69,12 @@ def update_frame_colorizer_model(frame_colorizer_model : FrameColorizerModel) ->
return gradio.Dropdown() return gradio.Dropdown()
def update_frame_colorizer_size(frame_colorizer_size : str) -> None:
state_manager.set_item('frame_colorizer_size', frame_colorizer_size)
def update_frame_colorizer_blend(frame_colorizer_blend : float) -> None: def update_frame_colorizer_blend(frame_colorizer_blend : float) -> None:
state_manager.set_item('frame_colorizer_blend', int(frame_colorizer_blend)) state_manager.set_item('frame_colorizer_blend', int(frame_colorizer_blend))
def update_frame_colorizer_size(frame_colorizer_size : str) -> None:
state_manager.set_item('frame_colorizer_size', frame_colorizer_size)

View File

@ -21,13 +21,13 @@ def render() -> None:
has_source_audio = has_audio(state_manager.get_item('source_paths')) has_source_audio = has_audio(state_manager.get_item('source_paths'))
has_source_image = has_image(state_manager.get_item('source_paths')) has_source_image = has_image(state_manager.get_item('source_paths'))
SOURCE_FILE = gradio.File( SOURCE_FILE = gradio.File(
label = wording.get('uis.source_file'),
file_count = 'multiple', file_count = 'multiple',
file_types = file_types =
[ [
'audio', 'audio',
'image' 'image'
], ],
label = wording.get('uis.source_file'),
value = state_manager.get_item('source_paths') if has_source_audio or has_source_image else None value = state_manager.get_item('source_paths') if has_source_audio or has_source_image else None
) )
source_file_names = [ source_file_value.get('path') for source_file_value in SOURCE_FILE.value ] if SOURCE_FILE.value else None source_file_names = [ source_file_value.get('path') for source_file_value in SOURCE_FILE.value ] if SOURCE_FILE.value else None

View File

@ -25,7 +25,6 @@ UI_LAYOUT_MODULES : List[ModuleType] = []
UI_LAYOUT_METHODS =\ UI_LAYOUT_METHODS =\
[ [
'pre_check', 'pre_check',
'pre_render',
'render', 'render',
'listen', 'listen',
'run' 'run'
@ -83,14 +82,14 @@ def launch() -> None:
with gradio.Blocks(theme = get_theme(), css = get_css(), title = metadata.get('name') + ' ' + metadata.get('version'), fill_width = True) as ui: with gradio.Blocks(theme = get_theme(), css = get_css(), title = metadata.get('name') + ' ' + metadata.get('version'), fill_width = True) as ui:
for ui_layout in state_manager.get_item('ui_layouts'): for ui_layout in state_manager.get_item('ui_layouts'):
ui_layout_module = load_ui_layout_module(ui_layout) ui_layout_module = load_ui_layout_module(ui_layout)
if ui_layout_module.pre_render():
if ui_layouts_total > 1: if ui_layouts_total > 1:
with gradio.Tab(ui_layout): with gradio.Tab(ui_layout):
ui_layout_module.render()
ui_layout_module.listen()
else:
ui_layout_module.render() ui_layout_module.render()
ui_layout_module.listen() ui_layout_module.listen()
else:
ui_layout_module.render()
ui_layout_module.listen()
for ui_layout in state_manager.get_item('ui_layouts'): for ui_layout in state_manager.get_item('ui_layouts'):
ui_layout_module = load_ui_layout_module(ui_layout) ui_layout_module = load_ui_layout_module(ui_layout)

View File

@ -23,10 +23,6 @@ def pre_check() -> bool:
return False return False
def pre_render() -> bool:
return True
def render() -> gradio.Blocks: def render() -> gradio.Blocks:
with gradio.Blocks() as layout: with gradio.Blocks() as layout:
with gradio.Row(): with gradio.Row():

View File

@ -8,10 +8,6 @@ def pre_check() -> bool:
return True return True
def pre_render() -> bool:
return True
def render() -> gradio.Blocks: def render() -> gradio.Blocks:
with gradio.Blocks() as layout: with gradio.Blocks() as layout:
with gradio.Row(): with gradio.Row():

View File

@ -8,10 +8,6 @@ def pre_check() -> bool:
return True return True
def pre_render() -> bool:
return True
def render() -> gradio.Blocks: def render() -> gradio.Blocks:
with gradio.Blocks() as layout: with gradio.Blocks() as layout:
with gradio.Row(): with gradio.Row():

View File

@ -8,10 +8,6 @@ def pre_check() -> bool:
return True return True
def pre_render() -> bool:
return True
def render() -> gradio.Blocks: def render() -> gradio.Blocks:
with gradio.Blocks() as layout: with gradio.Blocks() as layout:
with gradio.Row(): with gradio.Row():

View File

@ -24,6 +24,8 @@ WORDING : Dict[str, Any] =\
'merging_video_succeed': 'Merging video succeed', 'merging_video_succeed': 'Merging video succeed',
'merging_video_failed': 'Merging video failed', 'merging_video_failed': 'Merging video failed',
'skipping_audio': 'Skipping audio', 'skipping_audio': 'Skipping audio',
'replacing_audio_succeed': 'Replacing audio succeed',
'replacing_audio_skipped': 'Replacing audio skipped',
'restoring_audio_succeed': 'Restoring audio succeed', 'restoring_audio_succeed': 'Restoring audio succeed',
'restoring_audio_skipped': 'Restoring audio skipped', 'restoring_audio_skipped': 'Restoring audio skipped',
'clearing_temp': 'Clearing temporary resources', 'clearing_temp': 'Clearing temporary resources',
@ -90,37 +92,38 @@ WORDING : Dict[str, Any] =\
# installer # installer
'install_dependency': 'choose the variant of {dependency} to install', 'install_dependency': 'choose the variant of {dependency} to install',
'skip_conda': 'skip the conda environment check', 'skip_conda': 'skip the conda environment check',
# general # paths
'config_path': 'choose the config file to override defaults', 'config_path': 'choose the config file to override defaults',
'jobs_path': 'specify the directory to store jobs',
'source_paths': 'choose single or multiple source images or audios', 'source_paths': 'choose single or multiple source images or audios',
'target_path': 'choose single target image or video', 'target_path': 'choose single target image or video',
'output_path': 'specify the output image or video within a directory', 'output_path': 'specify the output image or video within a directory',
'jobs_path': 'specify the directory to store jobs', # face detector
# face analyser
'face_detector_model': 'choose the model responsible for detecting the faces', 'face_detector_model': 'choose the model responsible for detecting the faces',
'face_detector_size': 'specify the size of the frame provided to the face detector', 'face_detector_size': 'specify the frame size provided to the face detector',
'face_detector_angles': 'specify the angles to rotate the frame before detecting faces', 'face_detector_angles': 'specify the angles to rotate the frame before detecting faces',
'face_detector_score': 'filter the detected faces base on the confidence score', 'face_detector_score': 'filter the detected faces base on the confidence score',
# face landmarker
'face_landmarker_model': 'choose the model responsible for detecting the face landmarks', 'face_landmarker_model': 'choose the model responsible for detecting the face landmarks',
'face_landmarker_score': 'filter the detected face landmarks base on the confidence score', 'face_landmarker_score': 'filter the detected face landmarks base on the confidence score',
# face selector # face selector
'face_selector_mode': 'use reference based tracking or simple matching', 'face_selector_mode': 'use reference based tracking or simple matching',
'face_selector_order': 'specify the order of the detected faces', 'face_selector_order': 'specify the order of the detected faces',
'face_selector_age_start': 'filter the detected faces based the starting age',
'face_selector_age_end': 'filter the detected faces based the ending age',
'face_selector_gender': 'filter the detected faces based on their gender', 'face_selector_gender': 'filter the detected faces based on their gender',
'face_selector_age_start': 'filter the detected faces based on their age start',
'face_selector_age_end': 'filter the detected faces based on their age end',
'face_selector_race': 'filter the detected faces based on their race', 'face_selector_race': 'filter the detected faces based on their race',
'reference_face_position': 'specify the position used to create the reference face', 'reference_face_position': 'specify the position used to create the reference face',
'reference_face_distance': 'specify the desired similarity between the reference face and target face', 'reference_face_distance': 'specify the similarity between the reference face and target face',
'reference_frame_number': 'specify the frame used to create the reference face', 'reference_frame_number': 'specify the frame used to create the reference face',
# face mask # face masker
'face_mask_types': 'mix and match different face mask types (choices: {choices})', 'face_mask_types': 'mix and match different face mask types (choices: {choices})',
'face_mask_blur': 'specify the degree of blur applied the box mask', 'face_mask_blur': 'specify the degree of blur applied the box mask',
'face_mask_padding': 'apply top, right, bottom and left padding to the box mask', 'face_mask_padding': 'apply top, right, bottom and left padding to the box mask',
'face_mask_regions': 'choose the facial features used for the region mask (choices: {choices})', 'face_mask_regions': 'choose the facial features used for the region mask (choices: {choices})',
# frame extraction # frame extraction
'trim_frame_start': 'specify the the start frame of the target video', 'trim_frame_start': 'specify the starting frame of the target video',
'trim_frame_end': 'specify the the end frame of the target video', 'trim_frame_end': 'specify the ending frame of the target video',
'temp_frame_format': 'specify the temporary resources format', 'temp_frame_format': 'specify the temporary resources format',
'keep_temp': 'keep the temporary resources after processing', 'keep_temp': 'keep the temporary resources after processing',
# output creation # output creation
@ -134,11 +137,11 @@ WORDING : Dict[str, Any] =\
'output_video_fps': 'specify the video output fps based on the target video', 'output_video_fps': 'specify the video output fps based on the target video',
'skip_audio': 'omit the audio from the target video', 'skip_audio': 'omit the audio from the target video',
# processors # processors
'processors': 'load a single or multiple processors. (choices: {choices}, ...)', 'processors': 'load a single or multiple processors (choices: {choices}, ...)',
'age_modifier_model': 'choose the model responsible for aging the face', 'age_modifier_model': 'choose the model responsible for aging the face',
'age_modifier_direction': 'specify the direction in which the age should be modified', 'age_modifier_direction': 'specify the direction in which the age should be modified',
'expression_restorer_model': 'choose the model responsible for restoring the expression', 'expression_restorer_model': 'choose the model responsible for restoring the expression',
'expression_restorer_factor': 'restore factor of expression from target face', 'expression_restorer_factor': 'restore factor of expression from the target face',
'face_debugger_items': 'load a single or multiple processors (choices: {choices})', 'face_debugger_items': 'load a single or multiple processors (choices: {choices})',
'face_editor_model': 'choose the model responsible for editing the face', 'face_editor_model': 'choose the model responsible for editing the face',
'face_editor_eyebrow_direction': 'specify the eyebrow direction', 'face_editor_eyebrow_direction': 'specify the eyebrow direction',
@ -146,22 +149,22 @@ WORDING : Dict[str, Any] =\
'face_editor_eye_gaze_vertical': 'specify the vertical eye gaze', 'face_editor_eye_gaze_vertical': 'specify the vertical eye gaze',
'face_editor_eye_open_ratio': 'specify the ratio of eye opening', 'face_editor_eye_open_ratio': 'specify the ratio of eye opening',
'face_editor_lip_open_ratio': 'specify the ratio of lip opening', 'face_editor_lip_open_ratio': 'specify the ratio of lip opening',
'face_editor_mouth_grim': 'specify the mouth grim amount', 'face_editor_mouth_grim': 'specify the mouth grim',
'face_editor_mouth_pout': 'specify the mouth pout amount', 'face_editor_mouth_pout': 'specify the mouth pout',
'face_editor_mouth_purse': 'specify the mouth purse amount', 'face_editor_mouth_purse': 'specify the mouth purse',
'face_editor_mouth_smile': 'specify the mouth smile amount', 'face_editor_mouth_smile': 'specify the mouth smile',
'face_editor_mouth_position_horizontal': 'specify the mouth position horizontal amount', 'face_editor_mouth_position_horizontal': 'specify the horizontal mouth position',
'face_editor_mouth_position_vertical': 'specify the mouth position vertical amount', 'face_editor_mouth_position_vertical': 'specify the vertical mouth position',
'face_editor_head_pitch': 'specify the head pitch amount', 'face_editor_head_pitch': 'specify the head pitch',
'face_editor_head_yaw': 'specify the head yaw amount', 'face_editor_head_yaw': 'specify the head yaw',
'face_editor_head_roll': 'specify the head roll amount', 'face_editor_head_roll': 'specify the head roll',
'face_enhancer_model': 'choose the model responsible for enhancing the face', 'face_enhancer_model': 'choose the model responsible for enhancing the face',
'face_enhancer_blend': 'blend the enhanced into the previous face', 'face_enhancer_blend': 'blend the enhanced into the previous face',
'face_swapper_model': 'choose the model responsible for swapping the face', 'face_swapper_model': 'choose the model responsible for swapping the face',
'face_swapper_pixel_boost': 'choose the pixel boost resolution for the face swapper', 'face_swapper_pixel_boost': 'choose the pixel boost resolution for the face swapper',
'frame_colorizer_model': 'choose the model responsible for colorizing the frame', 'frame_colorizer_model': 'choose the model responsible for colorizing the frame',
'frame_colorizer_size': 'specify the frame size provided to the frame colorizer',
'frame_colorizer_blend': 'blend the colorized into the previous frame', 'frame_colorizer_blend': 'blend the colorized into the previous frame',
'frame_colorizer_size': 'specify the size of the frame provided to the frame colorizer',
'frame_enhancer_model': 'choose the model responsible for enhancing the frame', 'frame_enhancer_model': 'choose the model responsible for enhancing the frame',
'frame_enhancer_blend': 'blend the enhanced into the previous frame', 'frame_enhancer_blend': 'blend the enhanced into the previous frame',
'lip_syncer_model': 'choose the model responsible for syncing the lips', 'lip_syncer_model': 'choose the model responsible for syncing the lips',
@ -186,14 +189,15 @@ WORDING : Dict[str, Any] =\
'force_download': 'force automate downloads and exit', 'force_download': 'force automate downloads and exit',
# jobs # jobs
'job_id': 'specify the job id', 'job_id': 'specify the job id',
'job_status': 'specify the job status',
'step_index': 'specify the step index', 'step_index': 'specify the step index',
# job manager # job manager
'job_list': 'list jobs by status',
'job_create': 'create a drafted job', 'job_create': 'create a drafted job',
'job_submit': 'submit a drafted job to become a queued job', 'job_submit': 'submit a drafted job to become a queued job',
'job_submit_all': 'submit all drafted jobs to become a queued jobs', 'job_submit_all': 'submit all drafted jobs to become a queued jobs',
'job_delete': 'delete a drafted, queued, failed or completed job', 'job_delete': 'delete a drafted, queued, failed or completed job',
'job_delete_all': 'delete all drafted, queued, failed and completed jobs', 'job_delete_all': 'delete all drafted, queued, failed and completed jobs',
'job_list': 'list jobs by status',
'job_add_step': 'add a step to a drafted job', 'job_add_step': 'add a step to a drafted job',
'job_remix_step': 'remix a previous step from a drafted job', 'job_remix_step': 'remix a previous step from a drafted job',
'job_insert_step': 'insert a step to a drafted job', 'job_insert_step': 'insert a step to a drafted job',

View File

@ -24,6 +24,11 @@ def before_each() -> None:
init_jobs(get_test_jobs_directory()) init_jobs(get_test_jobs_directory())
@pytest.mark.skip()
def test_job_list() -> None:
pass
def test_job_create() -> None: def test_job_create() -> None:
commands = [ sys.executable, 'facefusion.py', 'job-create', 'test-job-create', '-j', get_test_jobs_directory() ] commands = [ sys.executable, 'facefusion.py', 'job-create', 'test-job-create', '-j', get_test_jobs_directory() ]

View File

@ -11,7 +11,7 @@ def test_has_execution_provider() -> None:
def test_multiple_execution_providers() -> None: def test_multiple_execution_providers() -> None:
execution_provider_with_options =\ execution_providers =\
[ [
('CUDAExecutionProvider', ('CUDAExecutionProvider',
{ {
@ -21,4 +21,4 @@ def test_multiple_execution_providers() -> None:
'CPUExecutionProvider' 'CPUExecutionProvider'
] ]
assert create_execution_providers('1', [ 'cpu', 'cuda' ]) == execution_provider_with_options assert create_execution_providers('1', [ 'cpu', 'cuda' ]) == execution_providers

View File

@ -2,7 +2,7 @@ from argparse import ArgumentParser
import pytest import pytest
from facefusion.program_helper import find_argument_group, validate_actions from facefusion.program_helper import find_argument_group, remove_args, validate_actions
def test_find_argument_group() -> None: def test_find_argument_group() -> None:
@ -38,3 +38,23 @@ def test_validate_actions() -> None:
action.default = args[action.dest] action.default = args[action.dest]
assert validate_actions(program) is False assert validate_actions(program) is False
def test_remove_args() -> None:
program = ArgumentParser()
program.add_argument('--test-1')
program.add_argument('--test-2')
program.add_argument('--test-3')
actions = [ action.dest for action in program._actions ]
assert 'test_1' in actions
assert 'test_2' in actions
assert 'test_3' in actions
program = remove_args(program, [ 'test_1', 'test_2' ])
actions = [ action.dest for action in program._actions ]
assert 'test_1' not in actions
assert 'test_2' not in actions
assert 'test_3' in actions