Files

56 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,
"styles": enhance.STYLES})
@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}