Skip to content

Build: import & manage Stable Audio 3 LoRA finetunes (gated on #44 / ADR-0028) #66

Description

@brxs

Problem

The spike #44 proved that a Stable Audio 3 LoRA finetune can run through
LSDJ's MLX inference path: a real public adapter
(motiftechnologies/stable-audio-3-maqam-lora) merged into the medium DiT at load
time produced measurably different audio through LSDJ's own subprocess invocation,
with a bit-exact bypass at strength 0. See
docs/spike-sa3-lora.md.

This issue is the build: let users import and manage SA3 LoRA adapters in-app,
the #43-style integration (HF repo-id + local import, "any source, warn +
validate", registry/UI), wired into the generate pipeline.

Gated on

  • Spike: enable Stable Audio 3 LoRA finetunes through the MLX inference path #44 spike recommendation: Path 1 — merge the adapter into the DiT weights at
    load time, via a new --lora flag on sa3_mlx.py (the spike's PoC patch, an
    upstream contribution). Do not start until the spike PoC is in place.
  • ADR-0028 — the trust boundary (safetensors only, never pickle) and the
    merge-on-the-spawned-subprocess approach. Build to that decision.

Scope

  • Import sources (mirror Add an in-app model manager: download Magenta + Stable Audio models from a settings overlay #43's model manager, src-tauri/src/models.rs +
    settings drawer): a HuggingFace repo-id and a local folder / .safetensors.
    "Any source, warn + validate."
  • Validation at import (the trust boundary):
    • Accept .safetensors only; refuse .ckpt/.pt/.pth/.bin with a clear
      message (they are unpickled by torch.load and can execute code).
    • Recognise both conventions: SA3-native (config in safetensors metadata) and
      PEFT (sibling adapter_config.json).
    • Infer rank/alpha/adapter_type; verify the adapter's base matches the
      target DiT (small vs medium) and that its layer keys/shapes resolve, warning on
      any skipped layers rather than corrupting weights.
  • Runtime wiring: thread the selected adapter(s) + strength into
    backend/lsdj/sa3.py's generate argv (--lora / --lora-strength) and the
    /api/generate contract; per-deck / per-kind selection. The
    optimized/mlx/models/defs/lora_merge.py merge module already covers all nine
    adapter types.
  • Lifecycle / registry: a LoRA is small and rides a base — track
    adapters-grouped-by-base (many LoRAs over one base), with install / list /
    delete mirroring the Add an in-app model manager: download Magenta + Stable Audio models from a settings overlay #43 manager. A per-deck strength knob maps to
    --lora-strength.
  • UI: choose adapter(s) + strength in the generate UI; surface base
    compatibility; reflect install progress like the Add an in-app model manager: download Magenta + Stable Audio models from a settings overlay #43 manager.
  • Upstream: contribute the spike's lora_merge.py + --lora flag to
    Stability-AI/stable-audio-3. If/when upstream lands native MLX LoRA, drop ours
    and bump sa3-pin.json (ADR-0012's upgrade path).

Acceptance criteria

  • An SA3 LoRA can be imported in-app (HF id + local) and applied to a generation
    from the UI, audibly changing output; strength is adjustable; strength 0 is a
    bypass.
  • Pickle adapters are refused; non-matching-base adapters are rejected at import
    with a clear reason.
  • The registry persists installed adapters grouped by base and survives restart.
  • just check green; a hardware/UX checklist in docs/ for the parts tests can't
    cover (per CLAUDE.md).

Out of scope

  • SA3 LoRA training (upstream stable-audio-tools / stable-audio-3).
  • Magenta finetunes — still upstream-blocked ("coming soon"); see the spike's
    revisit trigger.
  • -xs adapter SVD-bases performance on the medium DiT (bases are recomputed
    at load) may warrant a measure-and-cache sub-task.

Risks

  • An upstream rebase of the pinned MLX fork could rename layers and break the merge
    name-mapping — mitigated by the pinned commit + the spike's captured patch +
    skip-unknown-layers.
  • -xs SVD recompute cost on medium.
  • Base/adapter mismatch is a UX footgun — validate hard at import.

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions