Files
olivv-cs-ComfyUI-FunPack/modules/conditioning/prompt_enhancer/__init__.py
T
Claude 3adebb731f Rename FunPack to FunUI (5.0.3 Classy Chopper): /fun endpoint, wink logo, load-time migration of old names
Old project/workflow names and browser settings migrate on load; /funpack redirects to /fun.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016acRss69eH1235eRdFTZHY
2026-10-25 13:11:03 +00:00

55 lines
2.6 KiB
Python

"""Prompt enhancer: a language model rewrites the finished prompt before it is
encoded. A node-only module, with a small readout route for the Composer.
Sits after shortcut expansion and `$variables` (the app resolves both before the
text reaches the pipeline), so the model is handed exactly the text that would
otherwise have been encoded. Off by default. Every failure hands the ORIGINAL
prompt on and says so in the log: a rewrite that did not happen must never empty
the prompt.
One generation per scene -- v5 runs a scene per generation, so a multi-scene
project is never rewritten as one blob and re-split.
Whether a given text encoder writes sensible prose is an open question per model
(H3's conditioning checkpoint has no trained decoder head; Gemma3/Qwen3 do). v4's
result: confirmed working on Gemma3-12B. v5 on a rental: works with Gemma 4 E4B (a real rewrite in 2.5 s); H3's own encoder writes no prose, so there the run keeps your prompt and says why. On H3, pick a chat encoder (Gemma 4) in Composer > Enhance > Encoder: verified end to end.
"""
from .nodes import RUNS, FunUIEnhancePrompt
ID = "conditioning_prompt_enhancer"
TITLE = "Prompt enhancer"
STAGE = "conditioning"
CATEGORY = "conditioning"
STATUS = "experimental"
NODES = [FunUIEnhancePrompt]
def routes(table, base, web):
@table.get(base + "/defaults")
async def _defaults(_req):
"""What an empty field means, so the Composer can show it."""
from . import enhance
return web.json_response({"instructions": enhance.SYSTEM_PROMPT,
"reference_intro": enhance.REFERENCE_INTRO})
@table.get(base + "/runs")
async def _runs(req):
"""The last runs' rewrites, newest last. `?prompt_id=` narrows to one run."""
want = req.rel_url.query.get("prompt_id")
runs = [r for r in RUNS if not want or r["prompt_id"] == want]
return web.json_response({"runs": runs})
@table.get(base + "/encoders")
async def _encoders(_req):
"""Encoder files and families the Enhance panel can offer (read fresh: files come and go)."""
try:
from ...loaders.clip import nodes as clip_nodes
return web.json_response({"files": clip_nodes.encoder_files(), "families": clip_nodes.clip_types()})
except Exception as exc: # noqa: BLE001 -- the CLIP loader module is another module; its absence empties the picker, not the panel
return web.json_response({"files": [], "families": [], "why": f"the CLIP loader module is not available: {exc}"})
PROVIDES = {"routes": routes}