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:
@@ -46,6 +46,7 @@ reproducibility_audit: [Audit] # one entry per service
|
|||||||
| `model.revision` | string \| null | no | SHA when known |
|
| `model.revision` | string \| null | no | SHA when known |
|
||||||
| `model.image` | string | yes | container image ref this is hosted from |
|
| `model.image` | string | yes | container image ref this is hosted from |
|
||||||
| `fields` | list[Field] | no | request parameters; empty for catalog-deferred |
|
| `fields` | list[Field] | no | request parameters; empty for catalog-deferred |
|
||||||
|
| `section_groups` | list[SectionGroup] | no | named groups for progressive disclosure; consumers render fields under tabs/accordions per group. SectionGroup = `{id, label, hint?}`. Field.section refs must resolve here. |
|
||||||
| `response.type` | enum: audio, image, video, text, json, file | yes | renderer dispatch (closed vocabulary) |
|
| `response.type` | enum: audio, image, video, text, json, file | yes | renderer dispatch (closed vocabulary) |
|
||||||
| `response.mime` | string | no | static response MIME (raw-bytes wire) |
|
| `response.mime` | string | no | static response MIME (raw-bytes wire) |
|
||||||
| `response.mime_from_field` | string | no | name of a field whose value determines the MIME (raw-bytes wire) |
|
| `response.mime_from_field` | string | no | name of a field whose value determines the MIME (raw-bytes wire) |
|
||||||
@@ -95,6 +96,7 @@ Same change-management as field types.
|
|||||||
| Add a new service | nothing |
|
| Add a new service | nothing |
|
||||||
| Add a non-required field to an existing service | service `version:` |
|
| Add a non-required field to an existing service | service `version:` |
|
||||||
| Add an optional key to the `response:` schema (e.g. audio_field, timestamps_field) | nothing — additive, backward-compatible |
|
| Add an optional key to the `response:` schema (e.g. audio_field, timestamps_field) | nothing — additive, backward-compatible |
|
||||||
|
| Add an optional key to a Field (e.g. section) or to Service (e.g. section_groups) | nothing — additive, backward-compatible |
|
||||||
| Change a field's type, range, or default | service `version:` |
|
| Change a field's type, range, or default | service `version:` |
|
||||||
| Remove a service | service `version:` (sentinel: removed=true), then drop in next catalog_version bump |
|
| Remove a service | service `version:` (sentinel: removed=true), then drop in next catalog_version bump |
|
||||||
| Add a new entry to the field-type vocabulary | `catalog_version:` |
|
| Add a new entry to the field-type vocabulary | `catalog_version:` |
|
||||||
|
|||||||
@@ -218,6 +218,18 @@
|
|||||||
],
|
],
|
||||||
"default": null,
|
"default": null,
|
||||||
"title": "Accepted Types"
|
"title": "Accepted Types"
|
||||||
|
},
|
||||||
|
"section": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"default": null,
|
||||||
|
"title": "Section"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
@@ -425,6 +437,38 @@
|
|||||||
"title": "CatalogResponse",
|
"title": "CatalogResponse",
|
||||||
"type": "object"
|
"type": "object"
|
||||||
},
|
},
|
||||||
|
"CatalogSectionGroup": {
|
||||||
|
"additionalProperties": false,
|
||||||
|
"description": "A named group of fields, for progressive disclosure in form rendering.\n\nServices with many fields (ace-step has 27) declare section_groups and\ntag each field with a `section: <id>`. Consumers render fields grouped\nunder tabs / accordions / etc. Fields without a section go into an\nimplicit 'main' group rendered first.",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"title": "Id",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"label": {
|
||||||
|
"title": "Label",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"hint": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"default": null,
|
||||||
|
"title": "Hint"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"id",
|
||||||
|
"label"
|
||||||
|
],
|
||||||
|
"title": "CatalogSectionGroup",
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
"CatalogService": {
|
"CatalogService": {
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"properties": {
|
"properties": {
|
||||||
@@ -502,6 +546,13 @@
|
|||||||
"title": "Fields",
|
"title": "Fields",
|
||||||
"type": "array"
|
"type": "array"
|
||||||
},
|
},
|
||||||
|
"section_groups": {
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/$defs/CatalogSectionGroup"
|
||||||
|
},
|
||||||
|
"title": "Section Groups",
|
||||||
|
"type": "array"
|
||||||
|
},
|
||||||
"response": {
|
"response": {
|
||||||
"$ref": "#/$defs/CatalogResponse"
|
"$ref": "#/$defs/CatalogResponse"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -752,7 +752,7 @@ services:
|
|||||||
Apache-2.0 hybrid diffusion+LLM music generation. Multi-minute lyric-aware
|
Apache-2.0 hybrid diffusion+LLM music generation. Multi-minute lyric-aware
|
||||||
songs with vocals + instrumentation.
|
songs with vocals + instrumentation.
|
||||||
category: music
|
category: music
|
||||||
version: 1
|
version: 2
|
||||||
host: irv-ml1
|
host: irv-ml1
|
||||||
endpoint: http://10.100.79.3:8210/generate
|
endpoint: http://10.100.79.3:8210/generate
|
||||||
method: POST
|
method: POST
|
||||||
@@ -761,120 +761,184 @@ services:
|
|||||||
id: ace-step/ACE-Step
|
id: ace-step/ACE-Step
|
||||||
revision: main
|
revision: main
|
||||||
image: local/ace-step:v1
|
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:
|
fields:
|
||||||
- name: prompt
|
- name: prompt
|
||||||
type: textarea
|
type: textarea
|
||||||
label: Musical Prompt
|
label: Musical Prompt
|
||||||
required: true
|
required: true
|
||||||
|
section: basic
|
||||||
description: Style/mood/instrumentation, e.g. "uplifting pop with synth leads".
|
description: Style/mood/instrumentation, e.g. "uplifting pop with synth leads".
|
||||||
- name: lyrics
|
- name: lyrics
|
||||||
type: textarea
|
type: textarea
|
||||||
label: Lyrics
|
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
|
- name: audio_duration
|
||||||
type: slider
|
type: slider
|
||||||
min: 5.0
|
min: 5.0
|
||||||
max: 600.0
|
max: 600.0
|
||||||
default: 30.0
|
default: 30.0
|
||||||
label: Duration (seconds)
|
label: Duration (seconds)
|
||||||
- name: audio_format
|
section: basic
|
||||||
type: select
|
|
||||||
options: [wav, mp3, flac]
|
|
||||||
default: wav
|
|
||||||
- name: infer_step
|
- name: infer_step
|
||||||
type: number
|
type: number
|
||||||
default: 20
|
default: 20
|
||||||
label: Inference Steps
|
label: Inference Steps
|
||||||
|
section: generation
|
||||||
- name: guidance_scale
|
- name: guidance_scale
|
||||||
type: slider
|
type: slider
|
||||||
min: 1.0
|
min: 1.0
|
||||||
max: 15.0
|
max: 15.0
|
||||||
default: 7.5
|
default: 7.5
|
||||||
|
section: generation
|
||||||
- name: scheduler_type
|
- name: scheduler_type
|
||||||
type: select
|
type: select
|
||||||
options: [linear, squared, sqrt]
|
options: [linear, squared, sqrt]
|
||||||
default: linear
|
default: linear
|
||||||
|
section: generation
|
||||||
- name: cfg_type
|
- name: cfg_type
|
||||||
type: select
|
type: select
|
||||||
options: [none, cfg, cfg_rw]
|
options: [none, cfg, cfg_rw]
|
||||||
default: cfg
|
default: cfg
|
||||||
|
section: generation
|
||||||
- name: omega_scale
|
- name: omega_scale
|
||||||
type: slider
|
type: slider
|
||||||
min: 0.0
|
min: 0.0
|
||||||
max: 1.0
|
max: 1.0
|
||||||
default: 0.5
|
default: 0.5
|
||||||
|
section: generation
|
||||||
- name: actual_seeds
|
- name: actual_seeds
|
||||||
type: json
|
type: json
|
||||||
label: Seeds
|
label: Seeds
|
||||||
default: [42]
|
default: [42]
|
||||||
|
section: generation
|
||||||
- name: guidance_interval
|
- name: guidance_interval
|
||||||
type: slider
|
type: slider
|
||||||
min: 0.0
|
min: 0.0
|
||||||
max: 1.0
|
max: 1.0
|
||||||
default: 0.0
|
default: 0.0
|
||||||
|
section: conditioning
|
||||||
- name: guidance_interval_decay
|
- name: guidance_interval_decay
|
||||||
type: slider
|
type: slider
|
||||||
min: 0.0
|
min: 0.0
|
||||||
max: 1.0
|
max: 1.0
|
||||||
default: 1.0
|
default: 1.0
|
||||||
|
section: conditioning
|
||||||
- name: min_guidance_scale
|
- name: min_guidance_scale
|
||||||
type: slider
|
type: slider
|
||||||
min: 0.0
|
min: 0.0
|
||||||
max: 10.0
|
max: 10.0
|
||||||
default: 1.0
|
default: 1.0
|
||||||
|
section: conditioning
|
||||||
- name: use_erg_tag
|
- name: use_erg_tag
|
||||||
type: bool
|
type: bool
|
||||||
default: false
|
default: false
|
||||||
|
section: conditioning
|
||||||
- name: use_erg_lyric
|
- name: use_erg_lyric
|
||||||
type: bool
|
type: bool
|
||||||
default: false
|
default: false
|
||||||
|
section: conditioning
|
||||||
- name: use_erg_diffusion
|
- name: use_erg_diffusion
|
||||||
type: bool
|
type: bool
|
||||||
default: false
|
default: false
|
||||||
|
section: conditioning
|
||||||
- name: oss_steps
|
- name: oss_steps
|
||||||
type: json
|
type: json
|
||||||
default: []
|
default: []
|
||||||
|
section: conditioning
|
||||||
- name: guidance_scale_text
|
- name: guidance_scale_text
|
||||||
type: slider
|
type: slider
|
||||||
min: 0.0
|
min: 0.0
|
||||||
max: 15.0
|
max: 15.0
|
||||||
default: 0.0
|
default: 0.0
|
||||||
|
section: conditioning
|
||||||
- name: guidance_scale_lyric
|
- name: guidance_scale_lyric
|
||||||
type: slider
|
type: slider
|
||||||
min: 0.0
|
min: 0.0
|
||||||
max: 15.0
|
max: 15.0
|
||||||
default: 0.0
|
default: 0.0
|
||||||
|
section: conditioning
|
||||||
- name: audio2audio_enable
|
- name: audio2audio_enable
|
||||||
type: bool
|
type: bool
|
||||||
default: false
|
default: false
|
||||||
|
section: a2a
|
||||||
- name: ref_audio_strength
|
- name: ref_audio_strength
|
||||||
type: slider
|
type: slider
|
||||||
min: 0.0
|
min: 0.0
|
||||||
max: 1.0
|
max: 1.0
|
||||||
default: 0.5
|
default: 0.5
|
||||||
|
section: a2a
|
||||||
- name: ref_audio_input
|
- name: ref_audio_input
|
||||||
type: text
|
type: text
|
||||||
label: Reference Audio Path
|
label: Reference Audio Path
|
||||||
optional: true
|
optional: true
|
||||||
|
section: a2a
|
||||||
- name: lora_name_or_path
|
- name: lora_name_or_path
|
||||||
type: text
|
type: text
|
||||||
label: LoRA Repo/Path
|
label: LoRA Repo/Path
|
||||||
optional: true
|
optional: true
|
||||||
|
section: lora
|
||||||
- name: lora_weight
|
- name: lora_weight
|
||||||
type: slider
|
type: slider
|
||||||
min: 0.0
|
min: 0.0
|
||||||
max: 2.0
|
max: 2.0
|
||||||
default: 1.0
|
default: 1.0
|
||||||
|
section: lora
|
||||||
|
- name: audio_format
|
||||||
|
type: select
|
||||||
|
options: [wav, mp3, flac]
|
||||||
|
default: wav
|
||||||
|
section: output
|
||||||
- name: bf16
|
- name: bf16
|
||||||
type: bool
|
type: bool
|
||||||
default: true
|
default: true
|
||||||
|
section: output
|
||||||
- name: torch_compile
|
- name: torch_compile
|
||||||
type: bool
|
type: bool
|
||||||
default: false
|
default: false
|
||||||
|
section: output
|
||||||
- name: device_id
|
- name: device_id
|
||||||
type: number
|
type: number
|
||||||
default: 0
|
default: 0
|
||||||
label: GPU Device Index
|
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:
|
response:
|
||||||
type: audio
|
type: audio
|
||||||
mime_from_field: audio_format
|
mime_from_field: audio_format
|
||||||
|
|||||||
Reference in New Issue
Block a user