fix: Resolve circular import between core and face_swapper

Refactors the usage of the update_status function to break a
circular import dependency.

- In modules/processors/frame/face_swapper.py:
  - Removed direct import of update_status from modules.core.
  - Modified pre_start(), process_image(), and process_video()
    to accept update_status as a Callable parameter
    (status_fn_callback).
  - Internal calls now use this passed callback.
- In modules/core.py:
  - Updated the calls to pre_start(), process_image(), and
    process_video() for frame processors (specifically face_swapper)
    to pass the core.update_status function as the
    status_fn_callback argument.

This change ensures that face_swapper.py no longer needs to import
modules.core directly for status updates, resolving the ImportError.
pull/1298/head
google-labs-jules[bot] 2025-06-18 16:53:21 +00:00
parent d7139d5c6e
commit 8a03fccb59
2 changed files with 21 additions and 16 deletions

View File

@ -176,9 +176,12 @@ def update_status(message: str, scope: str = 'DLC.CORE') -> None:
ui.update_status(message)
def start() -> None:
for frame_processor in get_frame_processors_modules(modules.globals.frame_processors):
if not frame_processor.pre_start():
return
# Note: pre_start is called in run() before start() now.
# If it were to be called here, it would also need the status_fn_callback.
# For example:
# for frame_processor in get_frame_processors_modules(modules.globals.frame_processors):
# if not frame_processor.pre_start(status_fn_callback=update_status): # If pre_start was here
# return
update_status('Processing...')
# process image to image
if has_image_extension(modules.globals.target_path):
@ -190,7 +193,7 @@ def start() -> None:
print("Error copying file:", str(e))
for frame_processor in get_frame_processors_modules(modules.globals.frame_processors):
update_status('Progressing...', frame_processor.NAME)
frame_processor.process_image(modules.globals.source_path, modules.globals.output_path, modules.globals.output_path)
frame_processor.process_image(modules.globals.source_path, modules.globals.output_path, modules.globals.output_path, status_fn_callback=update_status)
release_resources()
if is_image(modules.globals.target_path):
update_status('Processing to image succeed!')
@ -210,7 +213,7 @@ def start() -> None:
temp_frame_paths = get_temp_frame_paths(modules.globals.target_path)
for frame_processor in get_frame_processors_modules(modules.globals.frame_processors):
update_status('Progressing...', frame_processor.NAME)
frame_processor.process_video(modules.globals.source_path, temp_frame_paths)
frame_processor.process_video(modules.globals.source_path, temp_frame_paths, status_fn_callback=update_status)
release_resources()
# handles fps
if modules.globals.keep_fps:
@ -249,7 +252,9 @@ def run() -> None:
if not pre_check():
return
for frame_processor in get_frame_processors_modules(modules.globals.frame_processors):
if not frame_processor.pre_check():
if not frame_processor.pre_check(): # pre_check in face_swapper does not use update_status
return
if hasattr(frame_processor, 'pre_start') and not frame_processor.pre_start(status_fn_callback=update_status): # Pass callback here
return
limit_resources()
if modules.globals.headless:

View File

@ -1,4 +1,4 @@
from typing import Any, List, Optional, Tuple
from typing import Any, List, Optional, Tuple, Callable # Added Callable
import cv2
import insightface
import threading
@ -6,7 +6,7 @@ import numpy as np
import modules.globals
import logging
import modules.processors.frame.core
from modules.core import update_status
# from modules.core import update_status # Removed import
from modules.face_analyser import get_one_face, get_many_faces, default_source_face
from modules.typing import Face, Frame
from modules.hair_segmenter import segment_hair
@ -63,19 +63,19 @@ def pre_check() -> bool:
return True
def pre_start() -> bool:
def pre_start(status_fn_callback: Callable[[str, str], None]) -> bool:
if not modules.globals.map_faces and not is_image(modules.globals.source_path):
update_status("Select an image for source path.", NAME)
status_fn_callback("Select an image for source path.", NAME)
return False
elif not modules.globals.map_faces and not get_one_face(
cv2.imread(modules.globals.source_path)
):
update_status("No face in source path detected.", NAME)
status_fn_callback("No face in source path detected.", NAME)
return False
if not is_image(modules.globals.target_path) and not is_video(
modules.globals.target_path
):
update_status("Select an image or video for target path.", NAME)
status_fn_callback("Select an image or video for target path.", NAME)
return False
return True
@ -569,7 +569,7 @@ def process_frames(
progress.update(1)
def process_image(source_path: str, target_path: str, output_path: str) -> None:
def process_image(source_path: str, target_path: str, output_path: str, status_fn_callback: Callable[[str, str], None]) -> None:
source_img = cv2.imread(source_path)
if source_img is None:
logging.error(f"Failed to read source image from {source_path}")
@ -593,7 +593,7 @@ def process_image(source_path: str, target_path: str, output_path: str) -> None:
result = process_frame(source_face_obj, source_img, original_target_frame)
else:
if modules.globals.many_faces:
update_status(
status_fn_callback(
"Many faces enabled. Using first source image. Progressing...", NAME
)
result = process_frame_v2(source_img, original_target_frame, target_path)
@ -604,11 +604,11 @@ def process_image(source_path: str, target_path: str, output_path: str) -> None:
logging.error(f"Processing image {target_path} failed, result was None.")
def process_video(source_path: str, temp_frame_paths: List[str]) -> None:
def process_video(source_path: str, temp_frame_paths: List[str], status_fn_callback: Callable[[str, str], None]) -> None:
reset_tracker_state() # Ensure fresh state for each video processing
if modules.globals.map_faces and modules.globals.many_faces:
update_status(
status_fn_callback(
"Many faces enabled. Using first source image. Progressing...", NAME
)
modules.processors.frame.core.process_video(