AQ_Gemini_acstep15
One Gemini call that returns a whole song's metadata — lyrics, BPM, cover art, YouTube text
- image
- response_json
- tags
- lyrics
- seed
- bpm
- duration
- timesignature
- language
- keyscale
- coverImage
- title
- tagline
- headline
- yt_description
- yt_tags
- yt_title
- instruction
This is the node at the center of this pack's whole reason for existing. The author's own description of AQnodes is "mostly for llm calling and automatizing pulid multiface" - and the acestep family is the LLM half. Point this node at a song idea and it returns structured metadata ready to feed ACE-Step (the open-source diffusion music model - think of it as a text-to-audio Stable Diffusion for full songs), plus cover-art direction and YouTube upload text. If you've seen those "generate a full song, cover, and upload it" workflows, this is the brains.
What it produces
AQ_Gemini_acstep15 is AQ_Gemini, but opinionated. Instead of freeform text it forces the model to return a fixed JSON schema:
tags- a music style prompt (the primary control for genre, mood, instrumentation)lyrics- with ACE-Step's structure tags ([verse],[chorus],[inst]) and language codesseed,bpm,durationSeconds,timesignature,language,keyscalecoverImage- a 150–250 word art-direction prompt for the album covertitle,tagline,headline- text for the cover / thumbnailyt_description,yt_tags,yt_title- a full YouTube packaging kit
The craftsmanship is in the schema descriptions: the fields literally tell the model how to write an ACE-Step style prompt, how to format lyrics for its text encoder, typical BPM ranges by genre, and what a keyword-rich YouTube title looks like. That's why the output is so usable - the model is being instructed on the pipeline it's feeding.
How it works
The node streams generate_content via the google-genai stack. For non-gemma models it sets response_mime_type: application/json plus response_schema, so the API returns valid JSON that matches the schema. For gemma models it falls back to a prompt-level instruction. Then it parses the response and coerces every field to a typed output with sensible defaults: bpm→120, duration→120.0s, keyscale→C major, timesignature→"4", language→"en". The outputs are typed so they plug straight into downstream nodes - seed and bpm are INTs, duration a FLOAT, timesignature/language/keyscale COMBOs, everything else STRING. No API key → it returns empty strings with those defaults instead of erroring.
Inputs
gemini_api_key, model_selection (gemma-3 family, gemini-flash-latest/lite, 2.5 flash/pro, gemini-3 previews, or custom), custom_model, prompt (your song idea), system_message, temperature, top_p, seed (pass a seed to vary or reproduce metadata), and an optional image (a reference art to inspire the cover).
Outputs
The full 17: response_json, tags, lyrics, seed, bpm, duration, timesignature, language, keyscale, coverImage, title, tagline, headline, yt_description, yt_tags, yt_title, instruction.
Install
Part of AQnodes:
cd ComfyUI/custom_nodes
git clone https://github.com/2frames/ComfyUI-AQnodes
cd ComfyUI-AQnodes
pip install -r requirements.txt
or search "AQnodes" in ComfyUI Manager and restart.
Gotchas
Gemma models get prompt-based JSON rather than schema-enforced, so it's less reliable there - for strict output, pick a gemini model. And this is one node in a family because LLMs differ: AQ_OpenAI_acstep15 uses OpenAI's Responses API, AQ_openai_compatible works against any OpenAI-compatible endpoint, and AQ_parse_json_to_acestep turns arbitrary JSON into the same slots. If you're using any of them, the outputs feed ACE-Step's audio text encoder for the music, AQ_CoverPrompt for the cover, and an upload node for YouTube.
Inputs (9)
| Name | Type | Default | Description |
|---|---|---|---|
| gemini_api_key | STRING | — | |
| model_selection | COMBO | gemma-3-12b-it | 12 options: gemma-3-12b-it, gemma-3-1b-it, gemma-3-4b-it, gemma-3-27b-it, gemini-flash-latest, gemini-flash-lite-latest, +6 |
| custom_model | STRING | — | |
| prompt | STRING | — | |
| system_message | STRING | You are a helpful assistant. | — |
| temperature | FLOAT | 1.00-1–2 | — |
| top_p | FLOAT | 0.95-1–1 | — |
| seed | INT | 00–18446744073709550000 | — |
| imageopt | IMAGE | — |
Outputs (17)
| Name | Type | Description |
|---|---|---|
| response_json | STRING | — |
| tags | STRING | — |
| lyrics | STRING | — |
| seed | INT | — |
| bpm | INT | — |
| duration | FLOAT | — |
| timesignature | COMBO | — |
| language | COMBO | — |
| keyscale | COMBO | — |
| coverImage | STRING | — |
| title | STRING | — |
| tagline | STRING | — |
| headline | STRING | — |
| yt_description | STRING | — |
| yt_tags | STRING | — |
| yt_title | STRING | — |
| instruction | STRING | — |