Files
ComfyUI-Ethanfel-Prompt-Bui…/docs/prompt-architecture-improvement-plan.md
T

557 lines
24 KiB
Markdown

# Prompt Architecture Improvement Plan
This is a working research note for organizing the prompt builder around the
routing map in `docs/prompt-pool-routing-map.md`.
## Current Branch Additions
The current branch adds two major surfaces:
- `SxCP Krea2 Resolution Selector` in `node_seed_resolution.py`, with README
notes.
- Expanded hardcore interaction/manual/action pools in
`categories/sexual_poses.json`,
`categories/expression_composition_pools.json`, `prompt_builder.py`, and
`krea_formatter.py`.
The map audit currently sees:
- 15 sexual pose subcategories.
- 94 sexual pose item templates.
- 23 expression pools.
- 24 composition pools.
- A new Krea2 resolution node with width/height/API aspect outputs.
## Architectural Finding
The project has a good functional map, but ownership is still mixed inside large
files:
- `prompt_builder.py` owns selection, character resolution, role graph logic,
camera adaptation, pair assembly, and some final string cleanup.
- `krea_formatter.py` owns metadata parsing, cast naturalization, sexual action
rewriting, POV rewriting, clothing cleanup, camera preservation, fallback
parsing, and final prose assembly.
- `sdxl_formatter.py` owns tag assembly and style/quality presets.
- `caption_naturalizer.py` owns training-caption prose.
- Category JSON files own scalable pool content, but Python still owns several
compatibility and role-graph decisions.
The biggest maintainability risk is not the number of pools. The risk is that
selection, semantic rewriting, and final text hygiene are too interleaved. When a
prompt has wrong text, it is easy to patch the wrong layer.
## First Refactor Boundary
Generic text hygiene now has one home:
- `prompt_hygiene.py`
It should only handle route-agnostic cleanup:
- whitespace and punctuation normalization;
- empty field-label removal;
- repeated trigger prefix cleanup;
- duplicate comma-list item removal;
- adjacent duplicate sentence cleanup;
- simple dangling connector cleanup.
It must not make semantic decisions such as sexual action positioning, POV
geometry, clothing state, or model-specific tag weighting. Those stay in the
route-specific owner. It also preserves ordinary words such as `composition`
inside normal sentences; empty field-label cleanup is limited to standalone
labels.
Formatter input/fallback parsing now has one home:
- `formatter_input.py`
It owns route-neutral parsing shared by Krea2, SDXL, and natural-caption
routes:
- whitespace and punctuation normalization before formatter parsing;
- JSON row detection from `metadata_json` or source text;
- trigger-prefix stripping with route-specific trigger candidate lists;
- `Avoid:` positive/negative splitting for fallback text;
- the shared prompt field-label inventory and extraction such as `Setting:`,
`Sexual scene:`, `Camera control:`, or `Composition:`;
- fallback field-label stripping for tag/text routes that need label-free body
text;
- row-value fallback from metadata fields to labeled prompt text.
It must not make formatter-style decisions. Krea prose, SDXL tags, and training
caption sentence shape stay in their formatter modules.
Shared hardcore phrase cleanup now has one home:
- `hardcore_text_cleanup.py`
It owns environment-anchor normalization used by both prompt generation and
Krea formatting, including malformed surface joins and bed/sheet/couch anchors
that should become model-neutral body-support language. It must stay
route-neutral: no Krea prose, no SDXL tags, and no category selection logic.
Current integration points:
- `prompt_builder.build_prompt`
- `prompt_builder.build_insta_of_pair`
- `krea_formatter.format_krea2_prompt`
- `sdxl_formatter.format_sdxl_prompt`
- `caption_naturalizer.naturalize_caption`
## Target Organization
### Generation Layer
Owner: `prompt_builder.py` plus `categories/*.json`.
Keep here:
- category/subcategory/item selection;
- seed axis routing;
- character slot/profile resolution;
- scene/expression/composition pool selection;
- role graph creation from structured category axes;
- metadata row construction.
Move or isolate later:
- pair assembly helpers that still live in `prompt_builder.py`.
Already isolated:
- JSON category loading, subcategory normalization, named scene/expression/
composition pool loading, cast compatibility filtering, exact subcategory
lookup, and inheritance-based pool merging live in `category_library.py`.
- object-style item-template metadata extraction, action/position family
normalization, position-key normalization, and metadata audit errors live in
`category_template_metadata.py`.
- category/cast route preset schemas, config JSON builders, choice lists, and
parsers live in `category_cast_config.py`; `prompt_builder.py` keeps public
delegate wrappers for existing nodes and tests.
- ethnicity/filter choices, advanced filter JSON, ethnicity-list JSON, filter
parsing, and ethnicity normalization live in `filter_config.py`; character
routes and builder filters use `prompt_builder.py` delegate wrappers.
- character choice lists, descriptor detail/presence/slot-seed normalization,
characteristic-list JSON builders/parsers, eye labels, hair config
builders/parsers, and hair phrase helpers live in `character_config.py`;
`prompt_builder.py` still resolves full character slots.
- character manual-detail config, profile name/path policy, profile JSON
normalization, descriptor assembly, save/load/rename/delete operations,
fallback profile loading, and context override application live in
`character_profile.py`; `prompt_builder.py` only bridges generated slot rows
into profile saves.
- generation profile presets, override normalization, trigger policy, and
profile config parsing live in `generation_profile_config.py`;
`prompt_builder.py` keeps public delegate wrappers.
- location/composition config presets, themed location packs, custom
location/composition entry parsing, merge behavior, and config parsing live
in `location_config.py`; `prompt_builder.py` still applies selected configs
to rows.
- hardcore position/action-filter choices, selected-position normalization,
config JSON builders/parsers, focus-policy toggles, subcategory allow-list
policy, position-key detection, category filtering, and item-template/axis
filtering live in `hardcore_position_config.py`.
- hardcore configured-cast role graph generation lives in
`hardcore_role_graphs.py`; `prompt_builder.py` selects item/axis metadata and
then asks that module for the source role graph.
- fallback role graph wording lives in `hardcore_role_fallback.py`, covering
solo rows, women-only rows, men-only rows, mixed group fallbacks, and support
partner sentences.
- interaction-style role graph wording lives in `hardcore_role_interaction.py`,
covering foreplay, manual stimulation, body worship, clothing transitions,
dominant guidance, camera performance, aftercare, and group coordination.
- outercourse-specific role graph wording has started moving into action-family
modules; `hardcore_role_outercourse.py` owns boobjob, testicle-sucking,
penis-licking, handjob, and footjob body geometry.
- oral-specific role graph wording lives in `hardcore_role_oral.py`, including
direct POV viewer phrasing for kneeling, face-sitting, sixty-nine,
edge-supported, side-lying, chair, standing, and reclining oral positions.
- penetration-specific role graph wording lives in
`hardcore_role_penetration.py`, covering the main vaginal penetration
position families while Krea POV rewriting keeps first-person geometry stable.
- anal/double-contact role graph wording lives in `hardcore_role_anal.py`,
covering rear-entry anal variants and front/back double-contact source
geometry.
- climax role graph wording lives in `hardcore_role_climax.py`, covering
ejaculation aftermath placement for face/body/ass, lap, open-thigh,
side-lying, and front/back group layouts.
- camera option schema, orbit/Qwen translation, config parsing, camera
directive text, and camera caption text live in `camera_config.py`;
camera-scene prose lives in `scene_camera_adapters.py`; row-level camera
insertion, contextual coworking composition mutation, subject-kind detection,
and POV suppression live in `row_camera.py`.
- shared hardcore environment-anchor cleanup lives in
`hardcore_text_cleanup.py` and normalizes malformed pool joins before metadata
reaches formatter routes.
- shared hardcore action metadata lives in `hardcore_action_metadata.py`; custom
rows now emit `action_family`, `position_family`, `position_key`, and
`position_keys` so formatter routing and debugging do less keyword guessing.
Krea, SDXL, and training-caption routes consume these fields when present.
- shared row route metadata readers live in `route_metadata.py`, covering
normalized action family, position family/keys, and route-specific formatter
hints for Krea, SDXL, and training-caption routes. Position keys are strict
by default, while SDXL can opt into legacy unknown key tags for compatibility.
- final row and pair text normalization lives in `row_normalization.py`,
covering trigger prepending, extra-positive append, negative merge/dedupe,
caption-part joining, embedded soft/hard row output synchronization, and row
sanitation before metadata leaves generation. It also copies side-specific
pair metadata, such as soft partner styling and hardcore clothing/detail
state, onto the embedded soft/hard rows.
### Pair / Adapter Layer
Owner today: `build_insta_of_pair`.
Keep here:
- pair route sequencing;
- top-level continuity option handoff between row, camera, clothing, and output
adapters.
Already isolated:
- Insta/OF option normalization, softcore category/outfit/pose pools, partner
outfit pools, clothing-continuity labels, negatives, and hardcore cast count
policy live in `pair_options.py`; `prompt_builder.py` keeps public delegate
wrappers for existing nodes and tests.
- soft/hard row creation lives in `pair_rows.py`, including softcore expression
override resolution, Woman A slot context application, soft outfit/pose
overrides, POV row fields, and hardcore row creation.
- pair-level cast/display context lives in `pair_cast.py`, including shared
descriptors, same-cast softcore descriptor text, partner styling, platform and
level labels, softcore cast presence text, and hard cast summary text.
- pair-level camera routing lives in `pair_camera.py`, including soft/hard
camera config selection, same-as-softcore mode, camera-detail override,
same-room hard scene continuity, camera-aware composition mutation, POV camera
suppression, and row/root camera metadata synchronization.
- pair-level hardcore clothing continuity lives in `pair_clothing.py`,
including action-aware body-access flags, conflicting outfit-piece cleanup,
default visible-men clothing, character-clothing override handling, and final
root clothing-state assembly.
- final pair output assembly lives in `pair_output.py`, including soft/hard
prompt strings, trigger preservation, negatives, captions, and root metadata
shape; the final cleanup step is delegated to `row_normalization.py`.
Embedded soft/hard rows are synchronized to the final pair prompt, caption,
and negative outputs during normalization so serialized pair metadata does
not carry stale standalone row text. Side-specific structured fields are
synchronized there too, including soft partner styling and hardcore clothing
continuity metadata.
### Krea2 Formatter Path
Owner: `krea_formatter.py`.
Keep here:
- Krea prose style;
- Krea route orchestration;
- camera-scene preservation;
- fallback text parsing.
Already isolated:
- `krea_cast.py` owns cast descriptor parsing, cast labels, cast prose, label
joining, natural cast descriptor text, and label replacement for formatter
routes, including the caption naturalizer's cast metadata path.
- `krea_clothing.py` owns clothing-state cleanup and action-aware body-access
wording for formatter routes.
- `krea_action_context.py` owns shared action-family predicates, axis context
text, climax detection, and detail-density normalization used by action and
POV formatter routes.
- `hardcore_action_metadata.py` owns shared action-family constants,
normalization, and inference used by the builder and Krea formatter route.
- `krea_pov.py` owns POV labels, POV label filtering, and POV camera/composition
support text.
- `krea_detail.py` owns generic detail-clause splitting, deduping, joining, and
density limiting for Krea action prose.
- `krea_action_positions.py` owns non-POV pose anchors, body-arrangement text,
rear-entry detection, and action-position phrasing.
- `krea_action_details.py` owns non-climax item/detail cleanup for foreplay,
outercourse, oral, penetration, toy/double-contact, and anchor dedupe paths.
- `krea_action_climax.py` owns climax-specific role/detail cleanup and aftermath
view dedupe.
- `krea_action_dispatch.py` owns non-POV role normalization, action-family
classification, and family-specific detail cleanup.
- `krea_actions.py` owns final non-POV hardcore action sentence assembly.
- `krea_pov_actions.py` owns POV hardcore action sentence rewriting,
first-person body geometry, and selected-position-axis priority before loose
context fallback.
- `formatter_input.py` owns shared metadata/source JSON detection, trigger
stripping, the shared prompt field-label inventory, prompt-field extraction,
`Avoid:` splitting, and row-value fallback for Krea, SDXL, and caption
routes.
- `route_metadata.py` owns shared row-level action-family, position-family,
position-key, and formatter-hint reads so formatter routes do not normalize
these fields independently.
Improve later:
- keep adding route-level smoke fixtures when new metadata fields start
influencing formatter output;
### SDXL Formatter Path
Owner: `sdxl_formatter.py`.
Keep here:
- trigger behavior;
- style and quality presets;
- tag ordering;
- weighted explicit tags;
- negative-prompt assembly.
- metadata-family tag hints from `action_family`, `position_family`, and
`position_keys`.
- shared row route metadata reads from `route_metadata.py`.
- shared formatter input parsing from `formatter_input.py`.
- style presets, quality presets, default negative prompt, and action/position
family tag hints from `sdxl_presets.py`.
- formatter profiles for manual controls, Pony flat-vector, SDXL photo, and
plain flat-vector styles live in `sdxl_presets.py` and are exposed by
`SxCP SDXL Formatter`.
- fallback field-label cleanup delegates to `formatter_input.py`.
Improve later:
- add route-level fixtures for any new SDXL model profile that needs different
tag ordering.
### Naturalizer Path
Owner: `caption_naturalizer.py`.
Keep here:
- natural sentence caption assembly;
- training-caption trigger behavior;
- style-tail policy from `caption_policy.py`.
- metadata-family action labels from `action_family` and `position_family` via
`caption_policy.py`.
- shared row route metadata reads from `route_metadata.py`.
- shared formatter input parsing from `formatter_input.py`.
- shared cast descriptor parsing and label replacement from `krea_cast.py`.
- caption detail-level/style-policy normalization, clothing cleanup, and
composition cleanup from `caption_policy.py`.
- caption profiles for manual controls, concise training captions, dense
training captions, and browsing captions live in `caption_policy.py` and are
exposed by `SxCP Caption Naturalizer`.
Improve later:
- add more caption profiles if a new training or browsing workflow needs a
distinct default.
### Category JSON Path
Owner: `categories/*.json`.
Keep here:
- scalable prompt pool content;
- named scene/expression/composition pools;
- item templates and axes;
- direct category-specific wording.
- optional object-style item templates with route metadata such as
`action_family`, `action_type`, `position_family`, `family`, `position_key`,
`position_keys`, and `formatter_hint`; string templates remain valid and fall
back to Python inference. Normalized formatter hints are routed into Krea,
SDXL, and caption naturalization through `all` plus the matching formatter
route only.
Improve later:
- keep `tools/prompt_map_audit.py` passing; it now checks referenced
expression/composition/scene pools, item-template axes, and object-template
metadata values for both string and object templates.
### Node / UI Path
Owner: `__init__.py`, `node_builder.py`, `node_seed_resolution.py`,
`node_camera.py`, `node_character.py`, `node_hardcore_position.py`,
`node_formatter.py`, `node_insta.py`, `node_route_config.py`,
`node_profile_filter.py`, `loop_nodes.py`, `web/*.js`.
Keep here:
- ComfyUI node input/output declarations;
- widget behavior;
- button actions;
- dynamic input slots.
- direct and config-driven builder node declarations in `node_builder.py`.
- seed and resolution utility node declarations in `node_seed_resolution.py`.
- camera utility node declarations in `node_camera.py`.
- character pool, slot, and profile node declarations in `node_character.py`.
- hardcore position pool/filter node declarations in
`node_hardcore_position.py`.
- caption/Krea2/SDXL formatter node declarations in `node_formatter.py`.
- Insta/OF options and prompt-pair node declarations in `node_insta.py`.
- route/category/location/composition/cast config node declarations in
`node_route_config.py`.
- profile/filter/ethnicity-list node declarations in `node_profile_filter.py`.
Already isolated:
- direct and config-driven prompt builder nodes live in `node_builder.py`, with
registration maps imported by `__init__.py`.
- seed axis salts/aliases, seed mode choices, lock builders, seed config
parsing, row seed math, and deterministic axis RNG live in `seed_config.py`;
seed/global-seed/seed-locker nodes live in `node_seed_resolution.py`, with
registration maps imported by `__init__.py`.
- SDXL/Krea2 resolution utility nodes live in `node_seed_resolution.py`, with
registration maps imported by `__init__.py`.
- camera/orbit/Qwen translator utility nodes live in `node_camera.py`, using
`camera_config.py` for option lists and JSON builders, with registration maps
imported by `__init__.py`.
- hair, age/body/eyes/clothing pools, manual character details, character
slots, and profile save/load nodes live in `node_character.py`, with
registration maps imported by `__init__.py`.
- hardcore position pool and action filter nodes live in
`node_hardcore_position.py`, with registration maps imported by
`__init__.py`.
- caption naturalizer, Krea2 formatter, and SDXL formatter nodes live in
`node_formatter.py`, with registration maps imported by `__init__.py`.
- Insta/OF options and dual prompt-pair nodes live in `node_insta.py`, with
registration maps imported by `__init__.py`.
- category preset, location/composition pool, location theme, and cast config
utility nodes live in `node_route_config.py`, with registration maps imported
by `__init__.py`.
- generation profile, advanced filter, and ethnicity list utility nodes live in
`node_profile_filter.py`, with registration maps imported by `__init__.py`.
- index-switch constants, index-base normalization, missing-input behavior,
route-output selection, status text, and lazy-input selection live in
`index_switch_policy.py`; `loop_nodes.py` keeps the ComfyUI node wrapper and
accumulator/loop runtime logic.
- profile-save and accumulator server payload handling lives in
`server_routes.py`; `__init__.py` only wires those pure handlers to ComfyUI
JSON responses, and `tools/prompt_smoke.py` covers the handlers without
importing ComfyUI.
Improve later:
- split remaining large node classes into files by family;
- keep node display names, return names, and docs in sync through the audit
helper;
- add more endpoint tests when new server routes are introduced.
## Path-Specific Improvements
### Prompt Builder
Near-term:
- Add final row hygiene already done through `prompt_hygiene.py`.
- Add a metadata smoke checker for representative generated rows and static
formatter fixtures through `tools/prompt_smoke.py`.
- Normalize every row with one function before JSON serialization.
Medium-term:
- Extract category loading and role graph logic.
- Convert keyword-heavy interaction filtering to template metadata.
### Insta/OF Pair
Near-term:
- Normalize pair metadata with one helper, including embedded row prompt,
caption, negative, and side-specific metadata synchronization.
- Confirm pair prompts, captions, and soft/hard rows carry the same sanitized
scene/camera/clothing fields.
- Keep same-room pair continuity synchronized in both assembled prompt text and
`hardcore_row.scene_text`; `tools/prompt_smoke.py` covers this drift case.
Medium-term:
- Make pair camera and clothing phases explicit subfunctions.
- Add smoke fixtures for same-cast, POV man, explicit nude, and different-camera
modes.
### Krea2
Near-term:
- Add final prose hygiene already done through `prompt_hygiene.py`.
- Add smoke coverage through `tools/prompt_smoke.py` for metadata-driven Krea2
formatting across built-in rows, hardcore rows, same-cast pairs, and POV
pairs.
- Cover camera-scene preservation through `tools/prompt_smoke.py` for single
rows, split soft/hard pair cameras, and POV camera-scene routing.
- Cover config-node routing through `tools/prompt_smoke.py` for category, cast,
generation profile, seed lock, camera, location theme, and composition config.
- Cover close foreplay and POV penetration Krea routes so raw labels, invalid
surface grammar, normal third-person camera text, and composition punctuation
drift are caught.
- Cover POV outercourse, oral, penetration, anal, and front/back double-contact
Krea routes so selected position geometry stays synchronized with metadata.
- Cover generated climax routes through Krea, SDXL, and natural caption outputs
so source aftermath placement and formatter details cannot drift apart.
- Cover generated interaction routes through Krea, SDXL, and natural caption
outputs so source contact/guidance/presentation wording stays metadata-driven.
- Cover generated fallback role routes through Krea, SDXL, and natural caption
outputs so solo and same-sex paths do not remain untested edge behavior.
Medium-term:
- Dispatch action rewriting by action family.
- Continue splitting remaining Krea semantic helpers into smaller modules.
### SDXL
Near-term:
- Add final tag hygiene already done through `prompt_hygiene.py`.
- Add smoke tests for trigger preservation and duplicate tag removal through
`tools/prompt_smoke.py`.
Medium-term:
- Make style/quality presets data-driven.
### Naturalizer
Near-term:
- Add final prose hygiene already done through `prompt_hygiene.py`.
- Verify training captions keep trigger exactly once through
`tools/prompt_smoke.py`.
Medium-term:
- Add caption profiles for training and browsing use cases.
### Camera / Scene
Near-term:
- Keep Qwen/orbit as camera source.
- Keep scene-camera adapters scoped by location family.
- Use the memory note in
`/home/ethanfel/.codex/memories/scene-camera-system.md` when editing POV.
- Keep `scene_camera_adapters.py` as the owner for location-aware camera prose;
add new location families there one at a time.
- Keep `row_camera.py` as the owner for inserting camera/scene directives into
generated rows, including POV suppression of normal third-person camera text.
Medium-term:
- Build new adapters one location family at a time.
## Invariants To Preserve
- Metadata is the preferred formatter input.
- Prompt Builder should output structured rows even if raw prompt text is rough.
- Krea should fix prose and semantic action readability, not category selection.
- SDXL should produce tag-style output and preserve model triggers as requested.
- Naturalizer should output training-friendly captions without changing the
selected content.
- Generic cleanup belongs in `prompt_hygiene.py`; semantic cleanup belongs in
the owning route.
## Recommended Next Passes
1. Continue splitting remaining `__init__.py` node classes by family after
behavior is covered by smoke checks.
2. Continue splitting the internals of `hardcore_role_graphs.py` by action
family once generated edge cases are covered by smoke fixtures.
3. Add more route-level smoke fixtures for generated edge cases that are not
covered by the current static Krea/SDXL/caption metadata fixtures.