From 86b3a5d2d16f7ea85e04c68e2988edfa6238e070 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 28 Jun 2026 04:31:35 +0000 Subject: [PATCH] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- .../core/inference/diffusion_engine_router.py | 1 - .../core/inference/diffusion_families.py | 6 ++- .../backend/core/inference/sd_cpp_backend.py | 47 +++++++++++++------ .../backend/core/inference/sd_cpp_engine.py | 12 ++++- studio/backend/models/inference.py | 4 +- studio/backend/routes/inference.py | 4 +- .../tests/test_diffusion_engine_router.py | 6 ++- studio/backend/tests/test_diffusion_routes.py | 15 ++++-- studio/backend/tests/test_sd_cpp_backend.py | 23 +++++++-- 9 files changed, 82 insertions(+), 36 deletions(-) diff --git a/studio/backend/core/inference/diffusion_engine_router.py b/studio/backend/core/inference/diffusion_engine_router.py index 661c27ab80..60aa14bc9e 100644 --- a/studio/backend/core/inference/diffusion_engine_router.py +++ b/studio/backend/core/inference/diffusion_engine_router.py @@ -56,7 +56,6 @@ def get_active_diffusion_engine() -> Any: """The engine object the active selection points at (defaults to diffusers).""" if _active_engine_name == ENGINE_SD_CPP: from core.inference.sd_cpp_backend import get_sd_cpp_backend - return get_sd_cpp_backend() from core.inference.diffusion import get_diffusion_backend diff --git a/studio/backend/core/inference/diffusion_families.py b/studio/backend/core/inference/diffusion_families.py index 0cf7d3988a..b1f3be98a4 100644 --- a/studio/backend/core/inference/diffusion_families.py +++ b/studio/backend/core/inference/diffusion_families.py @@ -108,7 +108,11 @@ _FAMILIES: tuple[DiffusionFamily, ...] = ( # The Qwen2.5-VL text encoder as a Q4_K_M GGUF keeps the CPU RAM win (the # bf16 safetensors encoder is ~15 GB). sd-cli's --qwen2vl is an alias of --llm. sd_cpp_text_encoders = ( - ("unsloth/Qwen2.5-VL-7B-Instruct-GGUF", "Qwen2.5-VL-7B-Instruct-Q4_K_M.gguf", "qwen2vl"), + ( + "unsloth/Qwen2.5-VL-7B-Instruct-GGUF", + "Qwen2.5-VL-7B-Instruct-Q4_K_M.gguf", + "qwen2vl", + ), ), ), DiffusionFamily( diff --git a/studio/backend/core/inference/sd_cpp_backend.py b/studio/backend/core/inference/sd_cpp_backend.py index 5680f52d37..5838566c3d 100644 --- a/studio/backend/core/inference/sd_cpp_backend.py +++ b/studio/backend/core/inference/sd_cpp_backend.py @@ -141,7 +141,9 @@ def _estimate_eta(total_steps: int, step: int, first_step_at: float, now: float) return max(0.0, (total_steps - step) * per_step) -def _map_guidance(fam: DiffusionFamily, guidance: Optional[float]) -> tuple[Optional[float], Optional[float]]: +def _map_guidance( + fam: DiffusionFamily, guidance: Optional[float] +) -> tuple[Optional[float], Optional[float]]: """(cfg_scale, guidance) for sd-cli from the single diffusers ``guidance`` value. FLUX families take a distilled embedded ``--guidance``; everyone else uses real @@ -309,12 +311,13 @@ class SdCppDiffusionBackend: specs.append((terepo, tefile, kind)) return specs - def _set_expected_bytes(self, assets: list[tuple[str, str, str]], hf_token: Optional[str]) -> None: + def _set_expected_bytes( + self, assets: list[tuple[str, str, str]], hf_token: Optional[str] + ) -> None: """Best-effort total download size for the progress bar (0 if unknown).""" total = 0 try: from huggingface_hub import HfApi - api = HfApi(token = hf_token) for repo, fn, _ in assets: if Path(repo).expanduser().exists(): @@ -402,9 +405,7 @@ class SdCppDiffusionBackend: else: seed = int(seed) cfg_scale, flux_guidance = _map_guidance(state.family, guidance) - vae_extra = ( - ["--vae-format", state.vae_format] if state.vae_format else None - ) + vae_extra = ["--vae-format", state.vae_format] if state.vae_format else None self._gen = _SdGen(total_steps = int(steps)) images = [] @@ -461,14 +462,18 @@ class SdCppDiffusionBackend: gen.step = min(int(a), gen.total_steps) if gen.first_step_at == 0.0: gen.first_step_at = now - gen.eta_seconds = _estimate_eta( - gen.total_steps, gen.step, gen.first_step_at, now - ) + gen.eta_seconds = _estimate_eta(gen.total_steps, gen.step, gen.first_step_at, now) def generate_progress(self) -> dict[str, Any]: gen = self._gen if gen is None or gen.total_steps <= 0: - return {"active": False, "step": 0, "total_steps": 0, "fraction": 0.0, "eta_seconds": None} + return { + "active": False, + "step": 0, + "total_steps": 0, + "fraction": 0.0, + "eta_seconds": None, + } return { "active": True, "step": gen.step, @@ -493,11 +498,23 @@ class SdCppDiffusionBackend: state = self._state if state is None: return { - "loaded": False, "repo_id": None, "family": None, "base_repo": None, - "device": None, "dtype": None, "cpu_offload": False, "offload_policy": None, - "vae_tiling": False, "memory_mode": None, "speed_mode": None, "speed_optims": [], - "text_encoder_quant": None, "transformer_quant": None, "attention_backend": None, - "transformer_cache": None, "engine": "sd_cpp", + "loaded": False, + "repo_id": None, + "family": None, + "base_repo": None, + "device": None, + "dtype": None, + "cpu_offload": False, + "offload_policy": None, + "vae_tiling": False, + "memory_mode": None, + "speed_mode": None, + "speed_optims": [], + "text_encoder_quant": None, + "transformer_quant": None, + "attention_backend": None, + "transformer_cache": None, + "engine": "sd_cpp", } return { "loaded": True, diff --git a/studio/backend/core/inference/sd_cpp_engine.py b/studio/backend/core/inference/sd_cpp_engine.py index 3fe64f2cb8..399b1ffbdc 100644 --- a/studio/backend/core/inference/sd_cpp_engine.py +++ b/studio/backend/core/inference/sd_cpp_engine.py @@ -250,7 +250,11 @@ class SdCppEngine: extra_args = merged_extra, ) return self._run( - cmd, output_path, timeout = timeout, env = env, on_log = on_log, + cmd, + output_path, + timeout = timeout, + env = env, + on_log = on_log, cancel_event = cancel_event, ) @@ -275,7 +279,11 @@ class SdCppEngine: extra_args = extra_args, ) return self._run( - cmd, output_path, timeout = timeout, env = env, on_log = on_log, + cmd, + output_path, + timeout = timeout, + env = env, + on_log = on_log, cancel_event = cancel_event, ) diff --git a/studio/backend/models/inference.py b/studio/backend/models/inference.py index f2f6e133ed..db05fdc6f1 100644 --- a/studio/backend/models/inference.py +++ b/studio/backend/models/inference.py @@ -1904,9 +1904,7 @@ class DiffusionStatusResponse(BaseModel): "_native_cudnn), or null for the default SDPA", ) transformer_cache: Optional[str] = Field(None, description = "Step cache engaged: fbcache | null") - engine: Optional[str] = Field( - None, description = "Active diffusion engine: diffusers | sd_cpp" - ) + engine: Optional[str] = Field(None, description = "Active diffusion engine: diffusers | sd_cpp") fallback_reason: Optional[str] = Field( None, description = "Why diffusers was chosen over the native sd.cpp engine (null when none)", diff --git a/studio/backend/routes/inference.py b/studio/backend/routes/inference.py index 6bcee0dd7d..1bad4c48be 100644 --- a/studio/backend/routes/inference.py +++ b/studio/backend/routes/inference.py @@ -10076,9 +10076,7 @@ async def load_diffusion_model( # Pick the engine for this host (diffusers on GPU, native sd.cpp with no GPU), # installing the sd-cli binary if needed -- all BEFORE evicting chat, so a # native fallback never strands a half-loaded state. - engine = await asyncio.to_thread( - select_and_activate_engine, fam, hf_token = request.hf_token - ) + engine = await asyncio.to_thread(select_and_activate_engine, fam, hf_token = request.hf_token) # Now take the GPU from the chat backend, then kick the (slow) load onto a # background thread and return at once — the client polls images/load-progress. await asyncio.to_thread(acquire_for, DIFFUSION) diff --git a/studio/backend/tests/test_diffusion_engine_router.py b/studio/backend/tests/test_diffusion_engine_router.py index 702abd1cc4..2fe4b197bc 100644 --- a/studio/backend/tests/test_diffusion_engine_router.py +++ b/studio/backend/tests/test_diffusion_engine_router.py @@ -28,7 +28,8 @@ def _clean_env_and_state(monkeypatch): # A light status-capable stub so neither selection nor active_status() imports the # heavy diffusers/sd.cpp backends; the active engine NAME comes from module state. monkeypatch.setattr( - r, "get_active_diffusion_engine", + r, + "get_active_diffusion_engine", lambda: SimpleNamespace(status = lambda: {"loaded": False, "repo_id": None}), ) yield @@ -36,7 +37,8 @@ def _clean_env_and_state(monkeypatch): def _set_device(monkeypatch, backend): monkeypatch.setattr( - r, "resolve_diffusion_device_target", + r, + "resolve_diffusion_device_target", lambda: SimpleNamespace(backend = backend, device = backend), ) diff --git a/studio/backend/tests/test_diffusion_routes.py b/studio/backend/tests/test_diffusion_routes.py index 4e0e20afb9..0569cf1385 100644 --- a/studio/backend/tests/test_diffusion_routes.py +++ b/studio/backend/tests/test_diffusion_routes.py @@ -123,11 +123,13 @@ def client(monkeypatch, tmp_path): # Delegate to whatever get_diffusion_backend currently returns, so per-test # re-patches of the backend still flow through the routes. monkeypatch.setattr( - engine_router, "select_and_activate_engine", + engine_router, + "select_and_activate_engine", lambda fam, **kw: diffusion_module.get_diffusion_backend(), ) monkeypatch.setattr( - engine_router, "get_active_diffusion_engine", + engine_router, + "get_active_diffusion_engine", lambda: diffusion_module.get_diffusion_backend(), ) monkeypatch.setattr(engine_router, "_active_engine_name", "diffusers") @@ -450,8 +452,10 @@ def test_load_routes_to_sd_cpp_on_cpu(monkeypatch, tmp_path): import core.inference.sd_cpp_backend as sd_backend for e in ( - "UNSLOTH_DIFFUSION_ENGINE", "UNSLOTH_DIFFUSION_SD_CPP", - "UNSLOTH_DIFFUSION_SD_CPP_MPS", "UNSLOTH_DIFFUSION_SD_CPP_INSTALL", + "UNSLOTH_DIFFUSION_ENGINE", + "UNSLOTH_DIFFUSION_SD_CPP", + "UNSLOTH_DIFFUSION_SD_CPP_MPS", + "UNSLOTH_DIFFUSION_SD_CPP_INSTALL", ): monkeypatch.delenv(e, raising = False) @@ -459,7 +463,8 @@ def test_load_routes_to_sd_cpp_on_cpu(monkeypatch, tmp_path): monkeypatch.setattr(diffusion_module, "get_diffusion_backend", lambda: validator) # Force the router's decision inputs: CPU device + an available binary. monkeypatch.setattr( - engine_router, "resolve_diffusion_device_target", + engine_router, + "resolve_diffusion_device_target", lambda: SimpleNamespace(backend = "cpu", device = "cpu"), ) monkeypatch.setattr(engine_router, "ensure_sd_cpp_binary", lambda **_: "/x/sd-cli") diff --git a/studio/backend/tests/test_sd_cpp_backend.py b/studio/backend/tests/test_sd_cpp_backend.py index 07be7b0539..3d0f3f4691 100644 --- a/studio/backend/tests/test_sd_cpp_backend.py +++ b/studio/backend/tests/test_sd_cpp_backend.py @@ -24,7 +24,12 @@ from core.inference.sd_cpp_engine import SdCppCancelled class _FakeEngine: """Stands in for SdCppEngine: writes a 1x1 PNG and records the args.""" - def __init__(self, *, fail=None, cancel_on_call=False): + def __init__( + self, + *, + fail = None, + cancel_on_call = False, + ): self.calls = [] self.fail = fail self.cancel_on_call = cancel_on_call @@ -35,7 +40,15 @@ class _FakeEngine: def version(self, **_): return "fake sd-cli" - def generate(self, files, params, *, output_path, cancel_event=None, **kw): + def generate( + self, + files, + params, + *, + output_path, + cancel_event = None, + **kw, + ): self.calls.append((files, params, output_path, kw)) if self.cancel_on_call and cancel_event is not None: cancel_event.set() @@ -49,7 +62,7 @@ class _FakeEngine: return Path(output_path) -def _loaded_backend(fam_name="z-image", engine=None): +def _loaded_backend(fam_name = "z-image", engine = None): b = SdCppDiffusionBackend(engine = engine or _FakeEngine()) fam = detect_family(fam_name) b._state = bk._SdState( @@ -57,7 +70,9 @@ def _loaded_backend(fam_name="z-image", engine=None): base_repo = fam.base_repo, family = fam, device = "cpu", - files = SdCppModelFiles(diffusion_model = "/m/z.gguf", vae = "/m/vae.safetensors", llm = "/m/llm.safetensors"), + files = SdCppModelFiles( + diffusion_model = "/m/z.gguf", vae = "/m/vae.safetensors", llm = "/m/llm.safetensors" + ), vae_format = fam.sd_cpp_vae_format, ) return b