Nodes/Grok Prompt Forge (xAI)/Grok Text Refine (xAI, legacy)
ComfyUI Node

Grok Text Refine (xAI, legacy)

A rewrite node whose job you get to define

By Slartibart23·Created 3 months ago·Updated 10 days ago· 1
Grok Text Refine (xAI, legacy)
    • refined_text
    ◄text—►
    ◄system_promptYou are a dataset captioning specialist for LoRA training. You will receive exactly ONE raw image caption per request, generated by a vision model (e.g. JoyCaption). Refine it into a clean final training caption. - Keep everything that is actually described: subjects, clothing or state of dress, pose, actions, expressions, gaze, setting, objects, camera framing and angle, concrete lighting. - Ensure unambiguous attribution in interaction scenes: WHO does WHAT to WHOM. Fix vague pronouns. - Do not invent anything that is not in the raw caption. - Describe explicit content as direct factual description; never censor, soften or moralize. - Strip mood language, aesthetic judgments, image-quality remarks and meta phrases ("this image shows", "in this photo"). - Plain natural-language English sentences, even if the raw caption is in another language. Output ONLY the single refined caption. No numbering, no commentary, no quotation marks, no markdown.►
    ◄modelgrok-4.20-0309-reasoning►
    ◄temperature0.20►
    ◄top_p1.00►
    ◄presence_penalty0.00►
    ◄frequency_penalty0.00►
    ◄max_tokens8192►
    ◄seed0►
    ◄api_key►
    ◄api_key_filegrok_api_key.txt►
    ◄base_urlhttps://api.x.ai/v1►
    ◄fallback_to_inputtrue►
    ◄timeout_seconds180►

    What it is

    Grok Text Refine takes your text, sends it to xAI's chat API alongside a system_prompt, and gives you back whatever the system prompt asked for. That's it. "Refine" is the author's use case, not a constraint - the same node is a caption refiner, a prompt generator, a translator or a summarizer, and which one you get is entirely decided by the text you put in system_prompt.

    If you've seen the "LLM in a graph" pattern, this is it - and note what it is not. It is not the text encoder inside your checkpoint, which is frozen, part of the model, and runs every generation. This is a separate language model bolted onto the canvas as a tool, working upstream of the sampler. The two get conflated constantly. The community settled on the pattern a while ago - "prompt enhancer" mentions went from 12 in 2023 to 253 in the first half of 2026 - and the two shapes it takes here are:

    [Load Image] → [JoyCaption] → [Grok Text Refine (xAI)] → [Save Text File]
    
    [Grok Text File Loader] → [Grok Text Refine (xAI)] → [CLIP Text Encode] → [KSampler]
    

    The first is deterministic caption cleanup. The second is prompt generation with real variety, one idea per queue run. Keep that split in mind, because it decides your seed setting later.

    How it works

    It's an OpenAI-compatible POST to https://api.x.ai/v1/chat/completions - your text as the user message, your system prompt as the system message - and it does a decent amount of housekeeping you'd otherwise be writing yourself.

    It retries: three attempts total, with backoff, for timeouts and the usual transient HTTP codes. It cleans the reply before handing it to your graph, stripping stray markdown fences and wrapping quotes that chat models love to add. And it handles the reasoning-model parameter problem in two ways. Neutral sampling values (top_p at 1.0, penalties at 0.0) are never sent to the API at all - which is why models like grok-4.5 that reject presencePenalty outright don't break. If a model still rejects one, the node reads the error, strips that parameter, and resends without it, logging which one it dropped. The queue keeps running.

    The inputs that matter

    • system_prompt - the job. This is the one you'll spend your time on. Feed it from Grok System Prompt Loader so you can edit it in a text editor instead of a widget.
    • text - the user message. A raw caption to refine, or a short idea to expand.
    • temperature - 0.2 by default, which is right for caption refinement. For prompt generation push it to 1.0–1.15. Above ~1.3, grammar starts to go.
    • seed - not sent to the API. It's purely a cache-breaker. ComfyUI only re-runs a node when an input changed, so with fixed and identical inputs you get the cached result back and no API call. Set it to randomize for prompt generation, or you'll generate every image from literally the same prompt text. Leave it fixed for caption refinement and repeated runs cost you nothing.
    • model - defaults to grok-4. Model ids change; check curl https://api.x.ai/v1/models -H "Authorization: Bearer YOUR_KEY" rather than trusting the default.
    • fallback_to_input - on by default. If the call fails, your input text passes through unchanged instead of killing the queue. Leave it on for batch work.

    Output is a single refined_text string. Wire it to CLIP Text Encode for a seed prompt, or to Save Text File for dataset work.

    Install

    Manager: search Grok Prompt Forge (xAI). Manual:

    cd ComfyUI/custom_nodes
    git clone https://github.com/Slartibart23/comfyui-grok-prompt-forge
    

    Restart; nodes land under Grok → Text. This pack is the successor to comfyui-grok-text-refine with the same node class IDs, so old workflows load unchanged - but delete the old comfyui-grok-text-refine folder when you upgrade, or you'll register the same class twice.

    Get a key at console.x.ai and put it in grok_api_key.txt in your ComfyUI root with the api_key widget empty - a key typed there gets saved into any workflow you export.

    Common issues

    Replace the default system prompt. The one baked into this node is the author's LoRA dataset-captioning prompt, complete with a specific trigger token and rules about what to strip from captions. Connect a text source and wonder why your prompts come back looking like training captions - that's why. Good template, not a neutral default.

    The penalty dials can silently do nothing. On reasoning models that reject them, the node strips and retries - so the run succeeds and the console is the only place you'll see that your presence_penalty had no effect. On those models you get variety from temperature plus an explicit ban list in the system prompt, and that ceiling is worth knowing anyway: sampling works at the word level, and it can't stop the model loving the same motifs - the same centered poses, the same lighting clichés. Ban clauses and genuinely different input text (see Grok Text File Loader cycling a folder) are the fix.

    CategoryGrok/Text

    Inputs (14)

    NameTypeDefaultDescription
    textSTRINGThe input text sent to Grok as the user message. Connect a text source here: a raw caption to refine, or a short idea / CONTENT line to expand into a full image prompt.
    system_promptSTRINGYou are a dataset captioning specialist for LoRA training. You will receive exactly ONE raw image caption per request, generated by a vision model (e.g. JoyCaption). Refine it into a clean final training caption. - Keep everything that is actually described: subjects, clothing or state of dress, pose, actions, expressions, gaze, setting, objects, camera framing and angle, concrete lighting. - Ensure unambiguous attribution in interaction scenes: WHO does WHAT to WHOM. Fix vague pronouns. - Do not invent anything that is not in the raw caption. - Describe explicit content as direct factual description; never censor, soften or moralize. - Strip mood language, aesthetic judgments, image-quality remarks and meta phrases ("this image shows", "in this photo"). - Plain natural-language English sentences, even if the raw caption is in another language. Output ONLY the single refined caption. No numbering, no commentary, no quotation marks, no markdown.The instructions that define WHAT this node does (refine captions, generate prompts, translate, ...). Edit freely, or feed one in from the Grok System Prompt Loader node.
    modelSTRINGgrok-4.20-0309-reasoningWhich xAI Grok model handles the request, e.g. grok-4.20-0309-reasoning. Note: reasoning models reject the penalty settings (the node then retries without them).
    temperatureFLOAT0.200–2Main creativity dial. Low = the model always picks its favorite words (predictable, repetitive) - use 0.0-0.3 for caption refinement. High = unusual words get a real chance (varied, surprising) - use 1.0-1.15 for prompt generation. Above ~1.3 grammar starts to fall apart.
    top_pFLOAT1.000.05–1Cutoff filter (nucleus sampling). Before picking a word, the model throws away the least likely candidates: 0.9 keeps only words covering the top 90% of probability - everything below becomes impossible, no matter the temperature. 1.0 = off (nothing is cut, value not sent to the API). Rule of thumb: keep this HIGH (0.98-1.0) and steer variety with temperature instead. Lowering it makes output safer but blander.
    presence_penaltyFLOAT0.00-2–2Pushes the model away from words it has ALREADY USED in this output, regardless of how often. Good against stock phrases (golden hour, neon lights, ...). 0.0 = off (not sent to the API). Try 0.3-0.6 for prompt generation; above ~1.0 output can get incoherent. If the model rejects this parameter (some reasoning models do), the node automatically retries without it - check the console log.
    frequency_penaltyFLOAT0.00-2–2Like presence_penalty, but the push grows THE MORE OFTEN a word repeats - targets literal word repetition within one output (she... she... she...). 0.0 = off (not sent to the API). Try 0.2-0.5 if outputs loop on the same words. If the model rejects this parameter, the node automatically retries without it - check the console log.
    max_tokensINT819264–32768Upper limit for the response length, INCLUDING the hidden reasoning of reasoning models (they think first). Too low = empty or cut-off answers.
    seedINT00–18446744073709550000Cache-breaker, NOT sent to the API. ComfyUI only re-runs a node when an input changed. Set the control below to 'randomize' to force a fresh API call every queue run (required for prompt generation!). 'fixed' reuses the cached result for identical requests (saves money on repeated caption refinement runs).
    api_keyoptSTRINGYour xAI API key. Leave EMPTY if possible - keys typed here end up in exported workflows! Prefer the XAI_API_KEY environment variable or the key file below.
    api_key_fileoptSTRINGgrok_api_key.txtPath to a text file containing only your xAI API key. Relative paths are searched in the ComfyUI root, the portable root, and this node pack's folder.
    base_urloptSTRINGhttps://api.x.ai/v1API endpoint. Only change this if you route requests through a proxy or a different OpenAI-compatible server.
    fallback_to_inputoptBOOLEANtrueIf the API call fails (no key, network error, ...), pass the input text through unchanged instead of stopping the queue. Keeps long batch runs alive.
    timeout_secondsoptINT18010–900How long to wait for the API before retrying (3 attempts total). Increase for slow reasoning models.

    Outputs (1)

    NameTypeDescription
    refined_textSTRING—