Spaces:
Paused
Paused
Update SwitcherAI/processors/frame/modules/face_swapper.py
Browse files
SwitcherAI/processors/frame/modules/face_swapper.py
CHANGED
|
@@ -13,17 +13,16 @@ from SwitcherAI.core import update_status
|
|
| 13 |
from SwitcherAI.face_analyser import get_one_face, get_many_faces, find_similar_faces
|
| 14 |
from SwitcherAI.face_reference import get_face_reference, set_face_reference
|
| 15 |
from SwitcherAI.typing import Face, Frame
|
| 16 |
-
from SwitcherAI.utilities import
|
| 17 |
|
| 18 |
FRAME_PROCESSOR = None
|
| 19 |
EMBEDDING_CONVERTER = None
|
| 20 |
THREAD_LOCK = threading.Lock()
|
| 21 |
NAME = 'FACEFUSION.FRAME_PROCESSOR.FACE_SWAPPER'
|
| 22 |
|
| 23 |
-
# Model configurations
|
| 24 |
MODEL_CONFIGS = {
|
| 25 |
'inswapper_128': {
|
| 26 |
-
'url': 'https://huggingface.co/ezioruan/inswapper_128.onnx/resolve/main/inswapper_128.onnx',
|
| 27 |
'path': '../.assets/models/inswapper_128.onnx',
|
| 28 |
'type': 'inswapper',
|
| 29 |
'size': (128, 128),
|
|
@@ -32,7 +31,6 @@ MODEL_CONFIGS = {
|
|
| 32 |
'requires_converter': False
|
| 33 |
},
|
| 34 |
'inswapper_128_fp16': {
|
| 35 |
-
'url': 'https://huggingface.co/ninjawick/webui-faceswap-unlocked/resolve/main/inswapper_128_fp16.onnx',
|
| 36 |
'path': '../.assets/models/inswapper_128_fp16.onnx',
|
| 37 |
'type': 'inswapper',
|
| 38 |
'size': (128, 128),
|
|
@@ -40,6 +38,15 @@ MODEL_CONFIGS = {
|
|
| 40 |
'standard_deviation': [1.0, 1.0, 1.0],
|
| 41 |
'requires_converter': False
|
| 42 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 43 |
}
|
| 44 |
|
| 45 |
# Default model - can be changed via globals
|
|
@@ -80,10 +87,13 @@ def get_frame_processor() -> Any:
|
|
| 80 |
model_priority.remove(current_model)
|
| 81 |
|
| 82 |
for model_name in model_priority:
|
|
|
|
|
|
|
|
|
|
| 83 |
try:
|
| 84 |
print(f"π Trying to load face swap model: {model_name}")
|
| 85 |
|
| 86 |
-
#
|
| 87 |
temp_config = MODEL_CONFIGS[model_name]
|
| 88 |
model_path = resolve_relative_path(temp_config['path'])
|
| 89 |
|
|
@@ -93,23 +103,14 @@ def get_frame_processor() -> Any:
|
|
| 93 |
else:
|
| 94 |
model_path_obj = model_path
|
| 95 |
|
| 96 |
-
# Check if model exists
|
| 97 |
if not model_path_obj.exists():
|
| 98 |
-
print(f"
|
| 99 |
-
|
| 100 |
-
if isinstance(download_directory_path, str):
|
| 101 |
-
download_directory_path = Path(download_directory_path)
|
| 102 |
-
download_directory_path.mkdir(parents=True, exist_ok=True)
|
| 103 |
-
|
| 104 |
-
download_urls = [temp_config['url']]
|
| 105 |
-
if temp_config.get('requires_converter', False):
|
| 106 |
-
download_urls.append(temp_config['converter_url'])
|
| 107 |
-
|
| 108 |
-
conditional_download(str(download_directory_path), download_urls)
|
| 109 |
|
| 110 |
# Verify model file size
|
| 111 |
if model_path_obj.stat().st_size < 1024: # Less than 1KB indicates corruption
|
| 112 |
-
print(f"β οΈ {model_name} appears corrupted, skipping...")
|
| 113 |
continue
|
| 114 |
|
| 115 |
# Try to load the model
|
|
@@ -125,44 +126,10 @@ def get_frame_processor() -> Any:
|
|
| 125 |
|
| 126 |
except Exception as e:
|
| 127 |
print(f"β Failed to load {model_name}: {e}")
|
| 128 |
-
|
| 129 |
-
# If protobuf parsing failed, delete the corrupted file and try to re-download
|
| 130 |
-
if "INVALID_PROTOBUF" in str(e) or "Protobuf parsing failed" in str(e):
|
| 131 |
-
print(f"ποΈ Deleting corrupted {model_name} file...")
|
| 132 |
-
try:
|
| 133 |
-
if model_path_obj.exists():
|
| 134 |
-
model_path_obj.unlink()
|
| 135 |
-
print(f"π₯ Re-downloading {model_name}...")
|
| 136 |
-
|
| 137 |
-
download_directory_path = resolve_relative_path('../.assets/models')
|
| 138 |
-
if isinstance(download_directory_path, str):
|
| 139 |
-
download_directory_path = Path(download_directory_path)
|
| 140 |
-
download_directory_path.mkdir(parents=True, exist_ok=True)
|
| 141 |
-
|
| 142 |
-
download_urls = [temp_config['url']]
|
| 143 |
-
if temp_config.get('requires_converter', False):
|
| 144 |
-
download_urls.append(temp_config['converter_url'])
|
| 145 |
-
|
| 146 |
-
conditional_download(str(download_directory_path), download_urls)
|
| 147 |
-
|
| 148 |
-
# Try loading again after re-download
|
| 149 |
-
if model_path_obj.exists() and model_path_obj.stat().st_size > 1024:
|
| 150 |
-
print(f"π Retrying {model_name} after re-download...")
|
| 151 |
-
FRAME_PROCESSOR = insightface.model_zoo.get_model(
|
| 152 |
-
str(model_path_obj),
|
| 153 |
-
providers=SwitcherAI.globals.execution_providers
|
| 154 |
-
)
|
| 155 |
-
# If successful, update the global setting and break
|
| 156 |
-
SwitcherAI.globals.face_swapper_model = model_name
|
| 157 |
-
print(f"β
Successfully loaded face swap model: {model_name}")
|
| 158 |
-
break
|
| 159 |
-
except Exception as retry_error:
|
| 160 |
-
print(f"β Retry failed for {model_name}: {retry_error}")
|
| 161 |
-
|
| 162 |
continue
|
| 163 |
|
| 164 |
if FRAME_PROCESSOR is None:
|
| 165 |
-
print("β All face swap models failed to load")
|
| 166 |
|
| 167 |
return FRAME_PROCESSOR
|
| 168 |
|
|
@@ -185,12 +152,11 @@ def get_embedding_converter() -> Any:
|
|
| 185 |
else:
|
| 186 |
converter_path_obj = converter_path
|
| 187 |
|
| 188 |
-
# Check if converter exists
|
| 189 |
if not converter_path_obj.exists():
|
| 190 |
-
print(f"
|
| 191 |
-
|
| 192 |
-
|
| 193 |
-
return None
|
| 194 |
|
| 195 |
EMBEDDING_CONVERTER = insightface.model_zoo.get_model(
|
| 196 |
str(converter_path_obj),
|
|
@@ -199,7 +165,7 @@ def get_embedding_converter() -> Any:
|
|
| 199 |
print("β
Embedding converter initialized")
|
| 200 |
|
| 201 |
except Exception as e:
|
| 202 |
-
print(f"
|
| 203 |
EMBEDDING_CONVERTER = None
|
| 204 |
|
| 205 |
return EMBEDDING_CONVERTER
|
|
@@ -213,24 +179,36 @@ def clear_frame_processor() -> None:
|
|
| 213 |
|
| 214 |
|
| 215 |
def pre_check() -> bool:
|
|
|
|
| 216 |
try:
|
| 217 |
-
download_directory_path = resolve_relative_path('../.assets/models')
|
| 218 |
-
|
| 219 |
-
# Ensure download directory exists
|
| 220 |
-
if isinstance(download_directory_path, str):
|
| 221 |
-
download_directory_path = Path(download_directory_path)
|
| 222 |
-
download_directory_path.mkdir(parents=True, exist_ok=True)
|
| 223 |
-
|
| 224 |
config = get_current_model_config()
|
| 225 |
|
| 226 |
-
#
|
| 227 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 228 |
|
| 229 |
-
#
|
| 230 |
if config.get('requires_converter', False):
|
| 231 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 232 |
|
| 233 |
-
|
| 234 |
return True
|
| 235 |
|
| 236 |
except Exception as e:
|
|
@@ -250,10 +228,15 @@ def pre_process() -> bool:
|
|
| 250 |
update_status(wording.get('select_image_or_video_target') + wording.get('exclamation_mark'), NAME)
|
| 251 |
return False
|
| 252 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 253 |
# Check if processor is available
|
| 254 |
processor = get_frame_processor()
|
| 255 |
if processor is None:
|
| 256 |
-
|
| 257 |
return False
|
| 258 |
|
| 259 |
return True
|
|
|
|
| 13 |
from SwitcherAI.face_analyser import get_one_face, get_many_faces, find_similar_faces
|
| 14 |
from SwitcherAI.face_reference import get_face_reference, set_face_reference
|
| 15 |
from SwitcherAI.typing import Face, Frame
|
| 16 |
+
from SwitcherAI.utilities import resolve_relative_path, is_image, is_video
|
| 17 |
|
| 18 |
FRAME_PROCESSOR = None
|
| 19 |
EMBEDDING_CONVERTER = None
|
| 20 |
THREAD_LOCK = threading.Lock()
|
| 21 |
NAME = 'FACEFUSION.FRAME_PROCESSOR.FACE_SWAPPER'
|
| 22 |
|
| 23 |
+
# Model configurations - local paths only
|
| 24 |
MODEL_CONFIGS = {
|
| 25 |
'inswapper_128': {
|
|
|
|
| 26 |
'path': '../.assets/models/inswapper_128.onnx',
|
| 27 |
'type': 'inswapper',
|
| 28 |
'size': (128, 128),
|
|
|
|
| 31 |
'requires_converter': False
|
| 32 |
},
|
| 33 |
'inswapper_128_fp16': {
|
|
|
|
| 34 |
'path': '../.assets/models/inswapper_128_fp16.onnx',
|
| 35 |
'type': 'inswapper',
|
| 36 |
'size': (128, 128),
|
|
|
|
| 38 |
'standard_deviation': [1.0, 1.0, 1.0],
|
| 39 |
'requires_converter': False
|
| 40 |
},
|
| 41 |
+
'simswap_256': {
|
| 42 |
+
'path': '../.assets/models/simswap_256.onnx',
|
| 43 |
+
'converter_path': '../.assets/models/simswap_256_converter.onnx',
|
| 44 |
+
'type': 'simswap',
|
| 45 |
+
'size': (256, 256),
|
| 46 |
+
'mean': [0.485, 0.456, 0.406],
|
| 47 |
+
'standard_deviation': [0.229, 0.224, 0.225],
|
| 48 |
+
'requires_converter': True
|
| 49 |
+
},
|
| 50 |
}
|
| 51 |
|
| 52 |
# Default model - can be changed via globals
|
|
|
|
| 87 |
model_priority.remove(current_model)
|
| 88 |
|
| 89 |
for model_name in model_priority:
|
| 90 |
+
if model_name not in MODEL_CONFIGS:
|
| 91 |
+
continue
|
| 92 |
+
|
| 93 |
try:
|
| 94 |
print(f"π Trying to load face swap model: {model_name}")
|
| 95 |
|
| 96 |
+
# Get model config
|
| 97 |
temp_config = MODEL_CONFIGS[model_name]
|
| 98 |
model_path = resolve_relative_path(temp_config['path'])
|
| 99 |
|
|
|
|
| 103 |
else:
|
| 104 |
model_path_obj = model_path
|
| 105 |
|
| 106 |
+
# Check if model exists locally
|
| 107 |
if not model_path_obj.exists():
|
| 108 |
+
print(f"β Model {model_name} not found at: {model_path_obj}")
|
| 109 |
+
continue
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 110 |
|
| 111 |
# Verify model file size
|
| 112 |
if model_path_obj.stat().st_size < 1024: # Less than 1KB indicates corruption
|
| 113 |
+
print(f"β οΈ {model_name} appears corrupted (file too small), skipping...")
|
| 114 |
continue
|
| 115 |
|
| 116 |
# Try to load the model
|
|
|
|
| 126 |
|
| 127 |
except Exception as e:
|
| 128 |
print(f"β Failed to load {model_name}: {e}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 129 |
continue
|
| 130 |
|
| 131 |
if FRAME_PROCESSOR is None:
|
| 132 |
+
print("β All face swap models failed to load. Please ensure models are present in .assets/models folder.")
|
| 133 |
|
| 134 |
return FRAME_PROCESSOR
|
| 135 |
|
|
|
|
| 152 |
else:
|
| 153 |
converter_path_obj = converter_path
|
| 154 |
|
| 155 |
+
# Check if converter exists locally
|
| 156 |
if not converter_path_obj.exists():
|
| 157 |
+
print(f"β Embedding converter not found at: {converter_path_obj}")
|
| 158 |
+
print("Please ensure the converter model is present in .assets/models folder.")
|
| 159 |
+
return None
|
|
|
|
| 160 |
|
| 161 |
EMBEDDING_CONVERTER = insightface.model_zoo.get_model(
|
| 162 |
str(converter_path_obj),
|
|
|
|
| 165 |
print("β
Embedding converter initialized")
|
| 166 |
|
| 167 |
except Exception as e:
|
| 168 |
+
print(f"β Failed to initialize embedding converter: {e}")
|
| 169 |
EMBEDDING_CONVERTER = None
|
| 170 |
|
| 171 |
return EMBEDDING_CONVERTER
|
|
|
|
| 179 |
|
| 180 |
|
| 181 |
def pre_check() -> bool:
|
| 182 |
+
"""Check if required models exist locally"""
|
| 183 |
try:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 184 |
config = get_current_model_config()
|
| 185 |
|
| 186 |
+
# Check main model path
|
| 187 |
+
model_path = resolve_relative_path(config['path'])
|
| 188 |
+
if isinstance(model_path, str):
|
| 189 |
+
model_path_obj = Path(model_path)
|
| 190 |
+
else:
|
| 191 |
+
model_path_obj = model_path
|
| 192 |
+
|
| 193 |
+
if not model_path_obj.exists():
|
| 194 |
+
print(f"β Main model not found at: {model_path_obj}")
|
| 195 |
+
print("Please ensure the model file is present in .assets/models folder.")
|
| 196 |
+
return False
|
| 197 |
|
| 198 |
+
# Check converter if needed
|
| 199 |
if config.get('requires_converter', False):
|
| 200 |
+
converter_path = resolve_relative_path(config['converter_path'])
|
| 201 |
+
if isinstance(converter_path, str):
|
| 202 |
+
converter_path_obj = Path(converter_path)
|
| 203 |
+
else:
|
| 204 |
+
converter_path_obj = converter_path
|
| 205 |
+
|
| 206 |
+
if not converter_path_obj.exists():
|
| 207 |
+
print(f"β Converter model not found at: {converter_path_obj}")
|
| 208 |
+
print("Please ensure the converter model file is present in .assets/models folder.")
|
| 209 |
+
return False
|
| 210 |
|
| 211 |
+
print("β
All required models found locally")
|
| 212 |
return True
|
| 213 |
|
| 214 |
except Exception as e:
|
|
|
|
| 228 |
update_status(wording.get('select_image_or_video_target') + wording.get('exclamation_mark'), NAME)
|
| 229 |
return False
|
| 230 |
|
| 231 |
+
# Check if required models exist locally
|
| 232 |
+
if not pre_check():
|
| 233 |
+
update_status("Required models not found in .assets/models folder", NAME)
|
| 234 |
+
return False
|
| 235 |
+
|
| 236 |
# Check if processor is available
|
| 237 |
processor = get_frame_processor()
|
| 238 |
if processor is None:
|
| 239 |
+
update_status("Face swap processor not available", NAME)
|
| 240 |
return False
|
| 241 |
|
| 242 |
return True
|