feat(ml): generación de audio en ComfyUI (ACE-Step) — builder comfyui_build_audio_workflow + fetch_output_audio
Soporte nativo de audio texto->música/SFX en ComfyUI 0.26.0 capitalizado como funciones del registry: - comfyui_build_audio_workflow (pura): builder ACE-Step en API format. Cadena CheckpointLoaderSimple -> TextEncodeAceStepAudio + ConditioningZeroOut + EmptyAceStepLatentAudio -> ModelSamplingSD3 -> KSampler -> VAEDecodeAudio -> SaveAudio. Params seconds/seed/steps/cfg/shift/lyrics. Tags comfyui,audio,ace-step. - comfyui_fetch_output_audio (impura): baja el .flac/.wav/.mp3 del output (clave 'audio'). Hermana de comfyui_fetch_output_video, que no sirve para audio. Modelo ACE-Step v1 3.5B (Apache 2.0, abierto). Stable Audio Open 1.0 descartado por estar gated (HTTP 403) en HuggingFace. Cabe en 8GB con --lowvram. Verificado e2e: 2 .flac reales generados desde texto (4.0s y 8.0s, seeds distintos), duración exacta confirmada con ffprobe. Tests 6+5 verdes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
---
|
||||
name: comfyui_fetch_output_audio
|
||||
kind: function
|
||||
lang: py
|
||||
domain: ml
|
||||
version: "1.0.0"
|
||||
purity: impure
|
||||
signature: "def comfyui_fetch_output_audio(prompt_id: str, *, server: str = \"127.0.0.1:8188\", dest: str | None = None, outputs: dict | None = None, timeout: float = 120.0) -> dict"
|
||||
description: "Localiza y descarga el output de audio de un workflow ComfyUI a disco local. Hermana de comfyui_fetch_output_video / _image / _mesh pero para los nodos de audio (SaveAudio, SaveAudioMP3, SaveAudioOpus, SaveAudioAdvanced): esos exponen su salida en GET /history bajo la clave 'audio' con items {filename, subfolder, type}. Localiza el primer .flac/.wav/.mp3/.opus/.ogg/.m4a, lo baja via GET /view y opcionalmente lo escribe en dest. Acepta outputs= ya obtenido de comfyui_wait_result para evitar re-consultar /history. Impura: HTTP GET + escritura en disco, solo stdlib."
|
||||
tags: [comfyui, audio, fetch, ace-step, ml, download, workflow]
|
||||
uses_functions: []
|
||||
uses_types: []
|
||||
returns: []
|
||||
returns_optional: false
|
||||
error_type: error_go_core
|
||||
imports: []
|
||||
params:
|
||||
- name: prompt_id
|
||||
desc: "id devuelto por comfyui_submit_workflow, de un workflow cuyo nodo de audio (SaveAudio/SaveAudioMP3/...) ya termino (usa comfyui_wait_result antes si dudas). Se ignora si se pasa outputs."
|
||||
- name: server
|
||||
desc: "host:port del servidor ComfyUI sin esquema. keyword-only."
|
||||
- name: dest
|
||||
desc: "Ruta destino. Si None, escribe el basename del audio en el cwd. Si es un directorio existente (o termina en separador), escribe el basename dentro. Si es una ruta de archivo, escribe ahi. keyword-only."
|
||||
- name: outputs
|
||||
desc: "dict de outputs ya obtenido (el que devuelve comfyui_wait_result). Si se pasa, se busca el audio ahi y NO se consulta /history (evita una peticion de red extra). keyword-only."
|
||||
- name: timeout
|
||||
desc: "Timeout de cada peticion HTTP en segundos. keyword-only."
|
||||
output: "dict {ok, path, format, bytes, error}. path = ruta local del archivo de audio guardado, format = extension sin punto (ej. 'flac' o 'mp3'), bytes = bytes descargados. Si falla, ok=False y error explica (sin audio en los outputs, HTTP, conexion o escritura)."
|
||||
tested: true
|
||||
tests:
|
||||
- "test_is_audio_item_por_extension"
|
||||
- "test_find_saveaudio_flac_bajo_audio"
|
||||
- "test_find_saveaudiomp3_bajo_audio"
|
||||
- "test_find_prioriza_clave_audio"
|
||||
- "test_find_sin_audio_devuelve_none"
|
||||
test_file_path: "python/functions/ml/comfyui_fetch_output_audio_test.py"
|
||||
file_path: "python/functions/ml/comfyui_fetch_output_audio.py"
|
||||
---
|
||||
|
||||
## Ejemplo
|
||||
|
||||
```python
|
||||
import sys, os
|
||||
sys.path.insert(0, os.path.join(os.environ["HOME"], "fn_registry", "python", "functions"))
|
||||
from ml.comfyui_fetch_output_audio import comfyui_fetch_output_audio
|
||||
|
||||
# Tras comfyui_submit_workflow + comfyui_wait_result de un workflow de audio
|
||||
# (ACE-Step, Stable Audio), baja el .flac/.mp3 al disco.
|
||||
res = comfyui_fetch_output_audio("8a278988-8a94-4225-add3-88a406f7101c", dest="/tmp/audios")
|
||||
# res == {"ok": True, "path": "/tmp/audios/comfy_audio_00001_.flac",
|
||||
# "format": "flac", "bytes": 882000, "error": ""}
|
||||
|
||||
# Si ya tienes los outputs de comfyui_wait_result, pasalos y evita re-consultar /history:
|
||||
outputs = {"9": {"audio": [{"filename": "comfy_audio_00001_.flac", "subfolder": "audio", "type": "output"}]}}
|
||||
res2 = comfyui_fetch_output_audio("ignored", dest="/tmp/audios", outputs=outputs)
|
||||
```
|
||||
|
||||
Lánzalo con el python del venv (import de arriba o heredoc). Nota: `./fn run` directo no aplica porque la firma usa `*` (keyword-only), no soportado por el generador de runner de `fn run`.
|
||||
|
||||
## Cuando usarla
|
||||
|
||||
Después de generar audio con ComfyUI (música o SFX por texto con ACE-Step, o Stable
|
||||
Audio), cuando necesites el archivo `.flac`/`.wav`/`.mp3`/`.opus` real en disco (no
|
||||
solo su nombre): para reproducirlo, subirlo a un vault, o usarlo como asset de un
|
||||
juego. Es la hermana de `comfyui_fetch_output_video` (vídeo/animación),
|
||||
`comfyui_fetch_output_image` (imágenes) y `comfyui_fetch_output_mesh` (mallas 3D).
|
||||
El builder hermano es `comfyui_build_audio_workflow`.
|
||||
|
||||
## Gotchas
|
||||
|
||||
- Impura: hace HTTP GET a /history y /view y escribe en disco. Requiere el server
|
||||
vivo y que el prompt YA haya terminado (usa `comfyui_wait_result` antes, o pásale
|
||||
`outputs=`).
|
||||
- Los nodos SaveAudio* exponen el archivo bajo la clave `"audio"` de los outputs
|
||||
(no `"images"` como los de imagen/vídeo). Por eso `comfyui_fetch_output_video` NO
|
||||
sirve para audio: busca extensiones de vídeo y claves gifs/videos/images.
|
||||
- SaveAudio guarda `.flac` por defecto; SaveAudioMP3 `.mp3`, SaveAudioOpus `.opus`.
|
||||
La función cubre todas por extensión.
|
||||
- Toma el PRIMER archivo de audio que encuentra. Si un workflow exporta varios,
|
||||
baja solo uno; para los demás llama otra vez o usa GET /view con el filename concreto.
|
||||
- El history se purga al reiniciar el server: si el prompt ya no está, devuelve
|
||||
`ok=False`. Pasar `outputs=` evita esa consulta y el problema.
|
||||
- `dest` se interpreta: None -> cwd; directorio EXISTENTE -> dentro; ruta de archivo
|
||||
-> esa ruta. Un directorio que aún no existe se trata como ruta de archivo: créalo
|
||||
antes (o termina la ruta en separador).
|
||||
Reference in New Issue
Block a user