diff --git a/facefusion/curl_builder.py b/facefusion/curl_builder.py index 41302dfc..b7252ed5 100644 --- a/facefusion/curl_builder.py +++ b/facefusion/curl_builder.py @@ -16,7 +16,7 @@ def chain(*commands : List[Command]) -> List[Command]: return list(itertools.chain(*commands)) -def head(url : str) -> List[Command]: +def ping(url : str) -> List[Command]: return [ '-I', url ] @@ -26,3 +26,7 @@ def download(url : str, download_file_path : str) -> List[Command]: def set_timeout(timeout : int) -> List[Command]: return [ '--connect-timeout', str(timeout) ] + + +def set_retry(retry : int) -> List[Command]: + return [ '--retry', str(retry) ] diff --git a/facefusion/download.py b/facefusion/download.py index 6878453c..8ba0c1e7 100644 --- a/facefusion/download.py +++ b/facefusion/download.py @@ -29,7 +29,8 @@ def conditional_download(download_directory_path : str, urls : List[str]) -> Non with tqdm(total = download_size, initial = initial_size, desc = translator.get('downloading'), unit = 'B', unit_scale = True, unit_divisor = 1024, ascii = ' =', disable = state_manager.get_item('log_level') in [ 'warn', 'error' ]) as progress: commands = curl_builder.chain( curl_builder.download(url, download_file_path), - curl_builder.set_timeout(5) + curl_builder.set_timeout(5), + curl_builder.set_retry(5) ) open_curl(commands) current_size = initial_size @@ -44,7 +45,7 @@ def conditional_download(download_directory_path : str, urls : List[str]) -> Non @lru_cache(maxsize = 64) def get_static_download_size(url : str) -> int: commands = curl_builder.chain( - curl_builder.head(url), + curl_builder.ping(url), curl_builder.set_timeout(5) ) process = open_curl(commands) @@ -62,7 +63,7 @@ def get_static_download_size(url : str) -> int: @lru_cache(maxsize = 64) def ping_static_url(url : str) -> bool: commands = curl_builder.chain( - curl_builder.head(url), + curl_builder.ping(url), curl_builder.set_timeout(5) ) process = open_curl(commands) diff --git a/facefusion/installer.py b/facefusion/installer.py index edbbd355..6cf76a80 100644 --- a/facefusion/installer.py +++ b/facefusion/installer.py @@ -13,6 +13,7 @@ from facefusion.common_helper import is_linux, is_windows LOCALS =\ { 'install_dependency': 'install the {dependency} package', + 'force_reinstall': 'force reinstall of packages', 'skip_conda': 'skip the conda environment check', 'conda_not_activated': 'conda is not activated' } @@ -26,13 +27,15 @@ if is_windows() or is_linux(): if is_windows(): ONNXRUNTIME_SET['directml'] = ('onnxruntime-directml', '1.23.0') if is_linux(): - ONNXRUNTIME_SET['rocm'] = ('onnxruntime-rocm', '1.21.0') + ONNXRUNTIME_SET['migraphx'] = ('onnxruntime-migraphx', '1.23.0') + ONNXRUNTIME_SET['rocm'] = ('onnxruntime_rocm', '1.22.1', '7.0.2') #type:ignore[assignment] def cli() -> None: signal.signal(signal.SIGINT, signal_exit) program = ArgumentParser(formatter_class = partial(HelpFormatter, max_help_position = 50)) program.add_argument('--onnxruntime', help = LOCALS.get('install_dependency').format(dependency = 'onnxruntime'), choices = ONNXRUNTIME_SET.keys(), required = True) + program.add_argument('--force-reinstall', help = LOCALS.get('force_reinstall'), action = 'store_true') program.add_argument('--skip-conda', help = LOCALS.get('skip_conda'), action = 'store_true') program.add_argument('-v', '--version', version = metadata.get('name') + ' ' + metadata.get('version'), action = 'version') run(program) @@ -45,7 +48,10 @@ def signal_exit(signum : int, frame : FrameType) -> None: def run(program : ArgumentParser) -> None: args = program.parse_args() has_conda = 'CONDA_PREFIX' in os.environ - onnxruntime_name, onnxruntime_version = ONNXRUNTIME_SET.get(args.onnxruntime) + commands = [ shutil.which('pip'), 'install' ] + + if args.force_reinstall: + commands.append('--force-reinstall') if not args.skip_conda and not has_conda: sys.stdout.write(LOCALS.get('conda_not_activated') + os.linesep) @@ -56,17 +62,21 @@ def run(program : ArgumentParser) -> None: for line in file.readlines(): __line__ = line.strip() if not __line__.startswith('onnxruntime'): - subprocess.call([ shutil.which('pip'), 'install', line, '--force-reinstall' ]) + commands.append(__line__) if args.onnxruntime == 'rocm': + onnxruntime_name, onnxruntime_version, rocm_version = ONNXRUNTIME_SET.get(args.onnxruntime) #type:ignore[misc] python_id = 'cp' + str(sys.version_info.major) + str(sys.version_info.minor) if python_id in [ 'cp310', 'cp312' ]: - wheel_name = 'onnxruntime_rocm-' + onnxruntime_version + '-' + python_id + '-' + python_id + '-linux_x86_64.whl' - wheel_url = 'https://repo.radeon.com/rocm/manylinux/rocm-rel-6.4/' + wheel_name - subprocess.call([ shutil.which('pip'), 'install', wheel_url, '--force-reinstall' ]) + wheel_name = onnxruntime_name + '-' + onnxruntime_version + '-' + python_id + '-' + python_id + '-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl' + wheel_url = 'https://repo.radeon.com/rocm/manylinux/rocm-rel-' + rocm_version + '/' + wheel_name + commands.append(wheel_url) else: - subprocess.call([ shutil.which('pip'), 'install', onnxruntime_name + '==' + onnxruntime_version, '--force-reinstall' ]) + onnxruntime_name, onnxruntime_version = ONNXRUNTIME_SET.get(args.onnxruntime) + commands.append(onnxruntime_name + '==' + onnxruntime_version) + + subprocess.call(commands) if args.onnxruntime == 'cuda' and has_conda: library_paths = [] @@ -97,4 +107,3 @@ def run(program : ArgumentParser) -> None: library_paths = list(dict.fromkeys([ library_path for library_path in library_paths if os.path.exists(library_path) ])) subprocess.call([ shutil.which('conda'), 'env', 'config', 'vars', 'set', 'PATH=' + os.pathsep.join(library_paths) ]) - diff --git a/facefusion/metadata.py b/facefusion/metadata.py index 462ebf2c..b0b68d6f 100644 --- a/facefusion/metadata.py +++ b/facefusion/metadata.py @@ -4,7 +4,7 @@ METADATA =\ { 'name': 'FaceFusion', 'description': 'Industry leading face manipulation platform', - 'version': '3.5.1', + 'version': '3.5.2', 'license': 'OpenRAIL-AS', 'author': 'Henry Ruhs', 'url': 'https://facefusion.io' diff --git a/facefusion/processors/choices.py b/facefusion/processors/choices.py deleted file mode 100755 index 86690583..00000000 --- a/facefusion/processors/choices.py +++ /dev/null @@ -1,27 +0,0 @@ -from facefusion.processors.modules.age_modifier.choices import age_modifier_direction_range, age_modifier_models # noqa: F401 -from facefusion.processors.modules.background_remover.choices import background_remover_color_range, background_remover_models # noqa: F401 -from facefusion.processors.modules.deep_swapper.choices import deep_swapper_models, deep_swapper_morph_range # noqa: F401 -from facefusion.processors.modules.expression_restorer.choices import expression_restorer_areas, expression_restorer_factor_range, expression_restorer_models # noqa: F401 -from facefusion.processors.modules.face_debugger.choices import face_debugger_items # noqa: F401 -from facefusion.processors.modules.face_editor.choices import ( # noqa: F401 - face_editor_eye_gaze_horizontal_range, - face_editor_eye_gaze_vertical_range, - face_editor_eye_open_ratio_range, - face_editor_eyebrow_direction_range, - face_editor_head_pitch_range, - face_editor_head_roll_range, - face_editor_head_yaw_range, - face_editor_lip_open_ratio_range, - face_editor_models, - face_editor_mouth_grim_range, - face_editor_mouth_position_horizontal_range, - face_editor_mouth_position_vertical_range, - face_editor_mouth_pout_range, - face_editor_mouth_purse_range, - face_editor_mouth_smile_range, -) -from facefusion.processors.modules.face_enhancer.choices import face_enhancer_blend_range, face_enhancer_models, face_enhancer_weight_range # noqa: F401 -from facefusion.processors.modules.face_swapper.choices import face_swapper_models, face_swapper_set, face_swapper_weight_range # noqa: F401 -from facefusion.processors.modules.frame_colorizer.choices import frame_colorizer_blend_range, frame_colorizer_models, frame_colorizer_sizes # noqa: F401 -from facefusion.processors.modules.frame_enhancer.choices import frame_enhancer_blend_range, frame_enhancer_models # noqa: F401 -from facefusion.processors.modules.lip_syncer.choices import lip_syncer_models, lip_syncer_weight_range # noqa: F401 diff --git a/facefusion/processors/modules/background_remover/core.py b/facefusion/processors/modules/background_remover/core.py index 17edecdf..1ce62788 100644 --- a/facefusion/processors/modules/background_remover/core.py +++ b/facefusion/processors/modules/background_remover/core.py @@ -421,7 +421,7 @@ def register_args(program : ArgumentParser) -> None: group_processors = find_argument_group(program, 'processors') if group_processors: group_processors.add_argument('--background-remover-model', help = translator.get('help.model', __package__), default = config.get_str_value('processors', 'background_remover_model', 'rmbg_2.0'), choices = background_remover_choices.background_remover_models) - group_processors.add_argument('--background-remover-color', help = translator.get('help.color', __package__), type = partial(sanitize_int_range, int_range = background_remover_choices.background_remover_color_range), default = config.get_int_list('processors', 'background_remover_color', '0 0 0 0'), nargs ='+') + group_processors.add_argument('--background-remover-color', help = translator.get('help.color', __package__), type = partial(sanitize_int_range, int_range = background_remover_choices.background_remover_color_range), default = config.get_int_list('processors', 'background_remover_color', '0 0 0 0'), nargs = '+') facefusion.jobs.job_store.register_step_keys([ 'background_remover_model', 'background_remover_color' ]) diff --git a/facefusion/processors/modules/expression_restorer/core.py b/facefusion/processors/modules/expression_restorer/core.py index 14c5c4ad..4892a18b 100755 --- a/facefusion/processors/modules/expression_restorer/core.py +++ b/facefusion/processors/modules/expression_restorer/core.py @@ -101,7 +101,7 @@ def register_args(program : ArgumentParser) -> None: if group_processors: group_processors.add_argument('--expression-restorer-model', help = translator.get('help.model', __package__), default = config.get_str_value('processors', 'expression_restorer_model', 'live_portrait'), choices = expression_restorer_choices.expression_restorer_models) group_processors.add_argument('--expression-restorer-factor', help = translator.get('help.factor', __package__), type = int, default = config.get_int_value('processors', 'expression_restorer_factor', '80'), choices = expression_restorer_choices.expression_restorer_factor_range, metavar = create_int_metavar(expression_restorer_choices.expression_restorer_factor_range)) - group_processors.add_argument('--expression-restorer-areas', help = translator.get('help.areas', __package__).format(choices = ', '.join(expression_restorer_choices.expression_restorer_areas)), default = config.get_str_list('processors', 'expression_restorer_areas', ' '.join(expression_restorer_choices.expression_restorer_areas)), choices = expression_restorer_choices.expression_restorer_areas, nargs ='+', metavar ='EXPRESSION_RESTORER_AREAS') + group_processors.add_argument('--expression-restorer-areas', help = translator.get('help.areas', __package__).format(choices = ', '.join(expression_restorer_choices.expression_restorer_areas)), default = config.get_str_list('processors', 'expression_restorer_areas', ' '.join(expression_restorer_choices.expression_restorer_areas)), choices = expression_restorer_choices.expression_restorer_areas, nargs = '+', metavar = 'EXPRESSION_RESTORER_AREAS') facefusion.jobs.job_store.register_step_keys([ 'expression_restorer_model', 'expression_restorer_factor', 'expression_restorer_areas' ]) diff --git a/facefusion/program.py b/facefusion/program.py index ab7760b1..8c8d8d25 100755 --- a/facefusion/program.py +++ b/facefusion/program.py @@ -269,7 +269,6 @@ def create_halt_on_error_program() -> ArgumentParser: def create_job_id_program() -> ArgumentParser: program = ArgumentParser(add_help = False) program.add_argument('job_id', help = translator.get('help.job_id')) - job_store.register_job_keys([ 'job_id' ]) return program diff --git a/requirements.txt b/requirements.txt index ba4947bd..032e39f0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,9 +1,9 @@ gradio-rangeslider==0.0.8 gradio==5.44.1 -numpy==2.3.4 +numpy==2.2.6 onnx==1.19.1 onnxruntime==1.23.2 opencv-python==4.12.0.88 -psutil==7.1.2 +psutil==7.1.3 tqdm==4.67.1 scipy==1.16.3 diff --git a/tests/test_curl_builder.py b/tests/test_curl_builder.py index ca0ec5b9..b0837284 100644 --- a/tests/test_curl_builder.py +++ b/tests/test_curl_builder.py @@ -1,7 +1,7 @@ from shutil import which from facefusion import metadata -from facefusion.curl_builder import chain, head, run +from facefusion.curl_builder import chain, ping, run, set_timeout def test_run() -> None: @@ -11,4 +11,7 @@ def test_run() -> None: def test_chain() -> None: - assert chain(head(metadata.get('url'))) == [ '-I', metadata.get('url') ] + assert chain( + ping(metadata.get('url')), + set_timeout(5) + ) == [ '-I', metadata.get('url'), '--connect-timeout', '5' ] diff --git a/tests/test_program_helper.py b/tests/test_program_helper.py index 92b64fb2..a2e85a10 100644 --- a/tests/test_program_helper.py +++ b/tests/test_program_helper.py @@ -1,8 +1,6 @@ from argparse import ArgumentParser -import pytest - -from facefusion.program_helper import find_argument_group, validate_actions +from facefusion.program_helper import find_argument_group, validate_actions, validate_args def test_find_argument_group() -> None: @@ -12,12 +10,26 @@ def test_find_argument_group() -> None: assert find_argument_group(program, 'test-1') assert find_argument_group(program, 'test-2') - assert find_argument_group(program, 'invalid') is None + assert find_argument_group(program, 'test-3') is None -@pytest.mark.skip() def test_validate_args() -> None: - pass + program = ArgumentParser() + program.add_argument('--test-1', default = 'test_1', choices = [ 'test_1', 'test_2' ]) + + assert validate_args(program) is True + + subparsers = program.add_subparsers() + sub_program = subparsers.add_parser('sub-command') + sub_program.add_argument('--test-2', default = 'test_2', choices = [ 'test_1', 'test_2' ]) + + assert validate_args(program) is True + + for action in sub_program._actions: + if action.dest == 'test_2': + action.default = 'test_3' + + assert validate_args(program) is False def test_validate_actions() -> None: