fix: drop stale per-request LoRA adapters before re-applying

The diffusers pipeline is cached/reused across image requests, so the adapters
_apply_loras added last time linger; re-loading the same fighter then raised
"Adapter name <x> already in use", and stale adapters from a different request
accumulated. Track the request adapters on the pipeline and delete them (plus a
defensive per-name delete) before re-loading, leaving acceleration adapters
(__accel__/__accel_2__) untouched.
Co-Authored-By: 's avatarClaude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RdMufYvtTbtGDWsiZVoXce
parent 3fb6c9b9
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
# Canonical product version for CoderAI — single source of truth. Both the API # Canonical product version for CoderAI — single source of truth. Both the API
# metadata and the admin web UI read from here. # metadata and the admin web UI read from here.
__version__ = "0.1.26" __version__ = "0.1.27"
# Configure the CUDA caching allocator BEFORE torch is imported anywhere. # Configure the CUDA caching allocator BEFORE torch is imported anywhere.
# expandable_segments lets the allocator return freed pages to the driver even # expandable_segments lets the allocator return freed pages to the driver even
......
...@@ -681,15 +681,35 @@ def _apply_loras(pipeline, loras): ...@@ -681,15 +681,35 @@ def _apply_loras(pipeline, loras):
# load_lora_weights below. Alias it before applying any adapter. # load_lora_weights below. Alias it before applying any adapter.
from codai.models.peft_compat import ensure_peft_awq_compat from codai.models.peft_compat import ensure_peft_awq_compat
ensure_peft_awq_compat() ensure_peft_awq_compat()
# The pipeline is cached and reused across requests, so the adapters we
# added last time linger. Re-loading the same fighter then fails with
# "Adapter name <x> already in use", and stale adapters from a different
# request would accumulate in VRAM. Drop the ones WE added previously
# (tracked by name) before re-applying — leaving any acceleration/turbo
# LoRA (a different adapter name, loaded elsewhere) untouched.
prev = list(getattr(pipeline, "_coderai_request_adapters", None) or [])
if prev:
try:
pipeline.delete_adapters(prev)
except Exception:
pass
pipeline._coderai_request_adapters = []
names = [] names = []
weights = [] weights = []
for i, lora in enumerate(loras): for i, lora in enumerate(loras):
name = lora.name or f"lora_{i}" name = lora.name or f"lora_{i}"
# Defensive: if this exact name somehow survived, drop it first so the
# load can't collide.
try:
pipeline.delete_adapters(name)
except Exception:
pass
pipeline.load_lora_weights(lora.model, adapter_name=name) pipeline.load_lora_weights(lora.model, adapter_name=name)
names.append(name) names.append(name)
weights.append(float(lora.weight if lora.weight is not None else 1.0)) weights.append(float(lora.weight if lora.weight is not None else 1.0))
if names: if names:
pipeline.set_adapters(names, weights) pipeline.set_adapters(names, weights)
pipeline._coderai_request_adapters = list(names)
_log.info("LoRA weights applied: %s", names) _log.info("LoRA weights applied: %s", names)
except Exception as e: except Exception as e:
_log.warning("Could not apply LoRA weights: %s", e) _log.warning("Could not apply LoRA weights: %s", e)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment