catalog-contract: section_groups + Field.section for progressive disclosure; ace-step v2

asset_engine consumer (althing thread 01KRCJF7NGMXYE9F62Q1A6KFD4)
needed structure for ace-step's 27-field form. Two additive Pydantic
changes — backward-compatible, no catalog_version bump per the
policy table:

  - CatalogField.section: str | None = None
  - CatalogService.section_groups: list[CatalogSectionGroup] = []
  - new CatalogSectionGroup model: {id, label, hint?}

Validator: every Field.section value must reference a declared
section_groups[].id within the same service; section_groups[].id
values are unique. CATALOG-CONTRACT.md updated with both the new
service-fields row and a versioning-policy row covering
"add optional Field/Service keys -> no bump."

ace-step entry rewritten to use the new schema:
  - bumped version 1 -> 2
  - declared 6 section groups (basic / generation / conditioning /
    a2a / lora / output) with hints
  - tagged every field with a section
  - added previously-missing checkpoint_path (required: true,
    default: "/app/checkpoints" — the container's mount path).
    Wrapper-side cleanup (default in infer-api.py) queued as
    follow-up.
  - changed lyrics from optional: true -> required: true with
    default "" to match upstream's `lyrics: str` shape (empty
    string satisfies it).

JSON Schema regenerated.

Pydantic-model side of this change lives in asset_engine at
src/asset_engine/catalog.py — committed there separately.
This commit is contained in:
vh
2026-05-11 15:33:08 -07:00
parent 4089990c17
commit 52803d87f8
3 changed files with 123 additions and 6 deletions
+70 -6
View File
@@ -752,7 +752,7 @@ services:
Apache-2.0 hybrid diffusion+LLM music generation. Multi-minute lyric-aware
songs with vocals + instrumentation.
category: music
version: 1
version: 2
host: irv-ml1
endpoint: http://10.100.79.3:8210/generate
method: POST
@@ -761,120 +761,184 @@ services:
id: ace-step/ACE-Step
revision: main
image: local/ace-step:v1
section_groups:
- id: basic
label: Basic
hint: "Prompt + lyrics + duration. The 80% case."
- id: generation
label: Generation
hint: "Sampler steps, guidance, scheduler, seed."
- id: conditioning
label: Conditioning
hint: "ERG flags, OSS schedule, guidance shape."
- id: a2a
label: "Audio → Audio"
hint: "Generate from a reference clip."
- id: lora
label: LoRA
hint: "Adapter weights."
- id: output
label: Output
hint: "Format and device."
fields:
- name: prompt
type: textarea
label: Musical Prompt
required: true
section: basic
description: Style/mood/instrumentation, e.g. "uplifting pop with synth leads".
- name: lyrics
type: textarea
label: Lyrics
optional: true
required: true
default: ""
section: basic
description: >
Required by the upstream Pydantic model (`lyrics: str`) but empty
string is a valid value (instrumental). Default '' so the inference
client always sends a string.
- name: audio_duration
type: slider
min: 5.0
max: 600.0
default: 30.0
label: Duration (seconds)
- name: audio_format
type: select
options: [wav, mp3, flac]
default: wav
section: basic
- name: infer_step
type: number
default: 20
label: Inference Steps
section: generation
- name: guidance_scale
type: slider
min: 1.0
max: 15.0
default: 7.5
section: generation
- name: scheduler_type
type: select
options: [linear, squared, sqrt]
default: linear
section: generation
- name: cfg_type
type: select
options: [none, cfg, cfg_rw]
default: cfg
section: generation
- name: omega_scale
type: slider
min: 0.0
max: 1.0
default: 0.5
section: generation
- name: actual_seeds
type: json
label: Seeds
default: [42]
section: generation
- name: guidance_interval
type: slider
min: 0.0
max: 1.0
default: 0.0
section: conditioning
- name: guidance_interval_decay
type: slider
min: 0.0
max: 1.0
default: 1.0
section: conditioning
- name: min_guidance_scale
type: slider
min: 0.0
max: 10.0
default: 1.0
section: conditioning
- name: use_erg_tag
type: bool
default: false
section: conditioning
- name: use_erg_lyric
type: bool
default: false
section: conditioning
- name: use_erg_diffusion
type: bool
default: false
section: conditioning
- name: oss_steps
type: json
default: []
section: conditioning
- name: guidance_scale_text
type: slider
min: 0.0
max: 15.0
default: 0.0
section: conditioning
- name: guidance_scale_lyric
type: slider
min: 0.0
max: 15.0
default: 0.0
section: conditioning
- name: audio2audio_enable
type: bool
default: false
section: a2a
- name: ref_audio_strength
type: slider
min: 0.0
max: 1.0
default: 0.5
section: a2a
- name: ref_audio_input
type: text
label: Reference Audio Path
optional: true
section: a2a
- name: lora_name_or_path
type: text
label: LoRA Repo/Path
optional: true
section: lora
- name: lora_weight
type: slider
min: 0.0
max: 2.0
default: 1.0
section: lora
- name: audio_format
type: select
options: [wav, mp3, flac]
default: wav
section: output
- name: bf16
type: bool
default: true
section: output
- name: torch_compile
type: bool
default: false
section: output
- name: device_id
type: number
default: 0
label: GPU Device Index
section: output
- name: checkpoint_path
type: text
label: Checkpoint Path
required: true
default: /app/checkpoints
section: output
description: >
Required by the upstream wrapper (`infer-api.py:29`, no default in
the Pydantic model). The container always mounts checkpoints at
/app/checkpoints, so the catalog default works out-of-the-box.
Only override if you've mounted an alternate checkpoint path.
Wrapper-side cleanup queued — once the upstream model defaults this,
the catalog field will become optional or be dropped entirely.
response:
type: audio
mime_from_field: audio_format