Images: preserve restored LoRAs through model load and never send hidden LoRAs
- The LoRA effect cleared the selection on every load->capable transition, which wiped adapters restored from a gallery recipe before the model finished loading. Track the previously-loaded family in a ref and clear only on a real family swap; keep the selection on the initial load and on unload. - Gate the generate payload's loras on loraCapable so a restored selection that is hidden (loaded model does not support LoRA) is never sent to the backend.
This commit is contained in:
parent
3c37299180
commit
e05c9cc947
1 changed files with 20 additions and 4 deletions
|
|
@ -985,18 +985,30 @@ export function ImagesPage({ active = true }: { active?: boolean }) {
|
|||
}, [images, hasMore, selectedId, quant]);
|
||||
|
||||
// Refresh the LoRA picker's suggestions when the loaded model (family) changes. A LoRA is
|
||||
// trained for a specific base family, so a model swap invalidates the current selection --
|
||||
// clear it (the user re-adds a suggestion or types a Hub repo id for the new family). We do
|
||||
// trained for a specific base family, so a real model SWAP invalidates the current selection
|
||||
// -- clear it then (the user re-adds a suggestion or types a Hub repo id for the new family).
|
||||
// But do NOT clear on the first load or an unload: a user can restore a saved recipe (which
|
||||
// sets loras) BEFORE the model finishes loading, and clearing on that load->capable
|
||||
// transition would silently drop the restored adapters. We track the previously-loaded
|
||||
// family in a ref and clear only when it changes to a different loaded family. We also do
|
||||
// NOT filter the selection against the discovered catalog: a valid pick can be a free-text
|
||||
// Hugging Face repo id that is not in the (often empty) curated list.
|
||||
const loraCapable = Boolean(status?.loaded && status?.supports_lora);
|
||||
const prevLoraFamilyRef = useRef<string | null | undefined>(undefined);
|
||||
useEffect(() => {
|
||||
if (!loraCapable) {
|
||||
// Options are gone with the model, but keep the selection: it may have just been
|
||||
// restored while the model is (re)loading. It is only SENT when loraCapable, and a
|
||||
// real family swap below clears it.
|
||||
setAvailableLoras([]);
|
||||
setLoras([]);
|
||||
return;
|
||||
}
|
||||
setLoras([]);
|
||||
const fam = status?.family ?? null;
|
||||
const prev = prevLoraFamilyRef.current;
|
||||
if (prev != null && prev !== fam) {
|
||||
setLoras([]);
|
||||
}
|
||||
prevLoraFamilyRef.current = fam;
|
||||
let cancelled = false;
|
||||
listDiffusionLoras(status?.family ?? undefined)
|
||||
.then((list) => {
|
||||
|
|
@ -1564,7 +1576,11 @@ export function ImagesPage({ active = true }: { active?: boolean }) {
|
|||
reference_images: condRefImages,
|
||||
// Drop empty (no id typed yet) and zero-weight rows, and trim hand-typed repo ids,
|
||||
// so the recipe records only adapters that actually applied. Empty -> omit entirely.
|
||||
// Gate on loraCapable: a restore can leave adapters in state while the loaded model
|
||||
// does not support LoRA (picker hidden), and sending them would fail generation with
|
||||
// no visible row to remove.
|
||||
loras: (() => {
|
||||
if (!loraCapable) return undefined;
|
||||
const active = loras
|
||||
.map((l) => ({ id: l.id.trim(), weight: l.weight }))
|
||||
.filter((l) => l.id && l.weight > 0);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue