diff --git a/facefusion/apis/core.py b/facefusion/apis/core.py index 4f59ba89..d8ca2f2c 100644 --- a/facefusion/apis/core.py +++ b/facefusion/apis/core.py @@ -1,3 +1,6 @@ +from types import ModuleType +from typing import List + from starlette.applications import Starlette from starlette.middleware import Middleware from starlette.middleware.cors import CORSMiddleware @@ -11,6 +14,19 @@ from facefusion.apis.endpoints.session import create_session, destroy_session, g from facefusion.apis.endpoints.state import get_state, set_state from facefusion.apis.endpoints.stream import delete_stream, post_stream, websocket_stream from facefusion.apis.middlewares.session import create_session_guard +from facefusion.libraries import aom as aom_module, datachannel as datachannel_module, opus as opus_module, vpx as vpx_module + + +def get_common_modules() -> List[ModuleType]: + return [ aom_module, datachannel_module, opus_module, vpx_module ] + + +def pre_check() -> bool: + for common_module in get_common_modules(): + if not common_module.pre_check(): + return False + + return True def create_api() -> Starlette: diff --git a/facefusion/content_analyser.py b/facefusion/content_analyser.py index fbc7e47a..eed188a9 100644 --- a/facefusion/content_analyser.py +++ b/facefusion/content_analyser.py @@ -1,16 +1,14 @@ from functools import lru_cache -from typing import List, Tuple +from typing import Tuple import numpy from tqdm import tqdm from facefusion import inference_manager, state_manager, translator -from facefusion.common_helper import is_macos from facefusion.download import conditional_download_hashes, conditional_download_sources, resolve_download_url -from facefusion.execution import has_execution_provider from facefusion.filesystem import resolve_relative_path from facefusion.thread_helper import conditional_thread_semaphore -from facefusion.types import Detection, DownloadScope, DownloadSet, ExecutionProvider, Fps, InferencePool, ModelSet, VisionFrame +from facefusion.types import Detection, DownloadScope, DownloadSet, Fps, InferencePool, ModelSet, VisionFrame from facefusion.vision import detect_video_fps, fit_contain_frame, read_image, read_video_frame STREAM_COUNTER = 0 @@ -119,12 +117,6 @@ def clear_inference_pool() -> None: inference_manager.clear_inference_pool(__name__, model_names) -def resolve_execution_providers() -> List[ExecutionProvider]: - if is_macos() and has_execution_provider('coreml'): - return [ 'cpu' ] - return state_manager.get_item('execution_providers') - - def collect_model_downloads() -> Tuple[DownloadSet, DownloadSet]: model_set = create_static_model_set('full') model_hash_set = {} diff --git a/facefusion/core.py b/facefusion/core.py index 663a3b6f..33471f72 100755 --- a/facefusion/core.py +++ b/facefusion/core.py @@ -7,8 +7,8 @@ from time import time import uvicorn -from facefusion import args_helper, benchmarker, cli_helper, content_analyser, face_classifier, face_detector, face_landmarker, face_masker, face_recognizer, hash_helper, logger, state_manager, translator, voice_extractor -from facefusion.apis.core import create_api +import facefusion.apis.core +from facefusion import args_helper, benchmarker, cli_helper, content_analyser, hash_helper, logger, state_manager, translator from facefusion.args_helper import apply_args from facefusion.download import conditional_download_hashes, conditional_download_sources from facefusion.exit_helper import hard_exit, signal_exit @@ -16,7 +16,6 @@ from facefusion.filesystem import get_file_extension, has_audio, has_image, has_ from facefusion.filesystem import get_file_name, resolve_file_paths, resolve_file_pattern from facefusion.jobs import job_helper, job_manager, job_runner from facefusion.jobs.job_list import compose_job_list -from facefusion.libraries import aom as aom_module, datachannel as datachannel_module, opus as opus_module, vpx as vpx_module from facefusion.processors.core import get_processors_modules from facefusion.program import create_program from facefusion.program_helper import validate_args @@ -55,11 +54,11 @@ def route(args : Args) -> None: benchmarker.render() if state_manager.get_item('command') == 'api': - if not common_pre_check() or not processors_pre_check(): + if not common_pre_check() or not processors_pre_check() or not facefusion.apis.core.pre_check(): hard_exit(2) logger.info(translator.get('api_started').format(host = state_manager.get_item('api_host'), port = state_manager.get_item('api_port')), __name__) - uvicorn.run(create_api(), host = state_manager.get_item('api_host'), port = state_manager.get_item('api_port')) + uvicorn.run(facefusion.apis.core.create_api(), host = state_manager.get_item('api_host'), port = state_manager.get_item('api_port')) hard_exit(1) 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' ]: @@ -103,25 +102,9 @@ def pre_check() -> bool: def common_pre_check() -> bool: - common_modules =\ - [ - aom_module, - datachannel_module, - content_analyser, - face_classifier, - face_detector, - face_landmarker, - face_masker, - face_recognizer, - opus_module, - voice_extractor, - vpx_module - ] - content_analyser_content = inspect.getsource(content_analyser).encode() - content_analyser_hash = hash_helper.create_hash(content_analyser_content) - return all(module.pre_check() for module in common_modules) and content_analyser_hash == '320ef969' + return hash_helper.create_hash(content_analyser_content) == 'a0a5ae57' def processors_pre_check() -> bool: @@ -132,22 +115,19 @@ def processors_pre_check() -> bool: def force_download() -> ErrorCode: - common_modules =\ - [ - content_analyser, - face_classifier, - face_detector, - face_landmarker, - face_masker, - face_recognizer, - voice_extractor - ] + download_scope = state_manager.get_item('download_scope') available_processors = [ get_file_name(file_path) for file_path in resolve_file_paths('facefusion/processors/modules') ] processor_modules = get_processors_modules(available_processors) + common_modules = [] + + for processor_module in processor_modules: + for common_module in processor_module.get_common_modules(): + if common_module not in common_modules: + common_modules.append(common_module) for module in common_modules + processor_modules: if hasattr(module, 'create_static_model_set'): - for model in module.create_static_model_set(state_manager.get_item('download_scope')).values(): + for model in module.create_static_model_set(download_scope).values(): model_hash_set = model.get('hashes') model_source_set = model.get('sources') diff --git a/facefusion/inference_manager.py b/facefusion/inference_manager.py index 3f9d8ce2..0741bf20 100644 --- a/facefusion/inference_manager.py +++ b/facefusion/inference_manager.py @@ -1,5 +1,6 @@ import importlib import random +from functools import lru_cache from time import sleep, time from typing import List @@ -12,7 +13,7 @@ from facefusion.execution import create_inference_providers, has_execution_provi from facefusion.exit_helper import fatal_exit from facefusion.filesystem import get_file_name, is_file from facefusion.time_helper import calculate_end_time -from facefusion.types import DownloadSet, ExecutionProvider, InferencePool, InferencePoolSet +from facefusion.types import DownloadSet, ExecutionProvider, InferencePool, InferencePoolSet, InferenceProvider INFERENCE_POOL_SET : InferencePoolSet =\ { @@ -25,7 +26,7 @@ def get_inference_pool(module_name : str, model_names : List[str], model_source_ while process_manager.is_checking(): sleep(0.5) execution_device_ids = state_manager.get_item('execution_device_ids') - execution_providers = resolve_execution_providers(module_name) + execution_providers = state_manager.get_item('execution_providers') app_context = detect_app_context() for execution_device_id in execution_device_ids: @@ -36,26 +37,27 @@ def get_inference_pool(module_name : str, model_names : List[str], model_source_ if app_context == 'api' and INFERENCE_POOL_SET.get('cli').get(inference_context): INFERENCE_POOL_SET['api'][inference_context] = INFERENCE_POOL_SET.get('cli').get(inference_context) if not INFERENCE_POOL_SET.get(app_context).get(inference_context): - INFERENCE_POOL_SET[app_context][inference_context] = create_inference_pool(model_source_set, execution_device_id, execution_providers) + inference_providers = resolve_static_inference_providers(module_name, execution_device_id) + INFERENCE_POOL_SET[app_context][inference_context] = create_inference_pool(model_source_set, inference_providers) current_inference_context = get_inference_context(module_name, model_names, random.choice(execution_device_ids), execution_providers) return INFERENCE_POOL_SET.get(app_context).get(current_inference_context) -def create_inference_pool(model_source_set : DownloadSet, execution_device_id : int, execution_providers : List[ExecutionProvider]) -> InferencePool: +def create_inference_pool(model_source_set : DownloadSet, inference_providers : List[InferenceProvider]) -> InferencePool: inference_pool : InferencePool = {} for model_name in model_source_set.keys(): model_path = model_source_set.get(model_name).get('path') if is_file(model_path): - inference_pool[model_name] = create_inference_session(model_path, execution_device_id, execution_providers) + inference_pool[model_name] = create_inference_session(model_path, inference_providers) return inference_pool def clear_inference_pool(module_name : str, model_names : List[str]) -> None: execution_device_ids = state_manager.get_item('execution_device_ids') - execution_providers = resolve_execution_providers(module_name) + execution_providers = state_manager.get_item('execution_providers') app_context = detect_app_context() if is_windows() and has_execution_provider('directml'): @@ -67,12 +69,11 @@ def clear_inference_pool(module_name : str, model_names : List[str]) -> None: del INFERENCE_POOL_SET[app_context][inference_context] -def create_inference_session(model_path : str, execution_device_id : int, execution_providers : List[ExecutionProvider]) -> InferenceSession: +def create_inference_session(model_path : str, inference_providers : List[InferenceProvider]) -> InferenceSession: model_file_name = get_file_name(model_path) start_time = time() try: - inference_providers = create_inference_providers(execution_device_id, execution_providers) inference_session = InferenceSession(model_path, providers = inference_providers) logger.debug(translator.get('loading_model_succeeded').format(model_name = model_file_name, seconds = calculate_end_time(start_time)), __name__) return inference_session @@ -87,9 +88,15 @@ def get_inference_context(module_name : str, model_names : List[str], execution_ return inference_context -def resolve_execution_providers(module_name : str) -> List[ExecutionProvider]: +@lru_cache() +def resolve_static_inference_providers(module_name : str, execution_device_id : int) -> List[InferenceProvider]: module = importlib.import_module(module_name) + execution_providers = state_manager.get_item('execution_providers') - if hasattr(module, 'resolve_execution_providers'): - return getattr(module, 'resolve_execution_providers')() - return state_manager.get_item('execution_providers') + if hasattr(module, 'resolve_inference_providers'): + inference_providers = getattr(module, 'resolve_inference_providers')() + + if inference_providers: + return inference_providers + + return create_inference_providers(execution_device_id, execution_providers)