Claude 3dddbe1671 Add proj, reject, renorm, noise, nearest actions and lerp alias
proj(a|b)    - project a onto the (mean, unit) direction of b
reject(a|b)  - a minus that projection (orthogonal component)
renorm(a|ref)- rescale a so each token's L2 norm matches ref's mean L2
noise(a|std) - a + N(0, std)
nearest(e|k) - snap mean(e) to its k nearest vocab tokens (cosine sim)
lerp(a|b|t)  - alias for avg(a|b|t)

All follow the existing MultiArgAction pattern; nearest reuses the
embedding-weight cosine machinery the Inspect node uses. Nine new
tests cover the math invariants (proj+reject reconstructs input,
reject is orthogonal to b, renorm matches ref norm, noise(_, 0) is
identity, nearest of a single token returns that token).

Relax MultiArgAction/SingleArgAction __init__ type hints to List
since SegOrAction now includes WeightedGroup and the Union isn't
importable in base.py without a cycle.
2026-04-12 06:02:00 +00:00
2023-08-19 18:44:41 -07:00

KepPromptLang

A small DSL for ComfyUI that lets you do math on CLIP token embeddings before they're fed into the text transformer.

sum(diff(king|man)|woman)
norm(sum(cat | dog | horse | parrot))
A slerp(cat|dog|0.5) is happy

Install

Clone into ComfyUI/custom_nodes/:

cd ComfyUI/custom_nodes
git clone <repo-url> KepPromptLang
pip install -r KepPromptLang/requirements.txt

Usage

  1. Add a Special CLIP Loader node and feed it the CLIP output from your Load Checkpoint.
  2. Pass the wrapped CLIP into a standard CLIP Text Encode node.
  3. Use the DSL syntax in your prompt.

To debug what your DSL is doing, add a PromptLang Inspect node — it shows the per-slot weight, L2 norm, and nearest-vocab words for the resolved embeddings.

See examples/WIP_Example_workflow.json for a working workflow.

Example

Syntax

Element Syntax Example
Plain word alphanumeric (with ,_.-) cat, dog_face
Quoted string single or double quotes "hello world", 'it\'s sunny'
Weighted (text:weight) or emph(text|weight) (cat:1.3), emph(cat|1.3)
Embedding (textual inversion) embedding:NAME embedding:face_vector
Function name(arg | arg | ...) sum(king | woman)

Arguments inside a function are separated by |. Each arg can itself be plain text, an embedding, a quoted string, or another function call.

Quick examples

  • Average two prompts: avg(The cat is | The dog is | 0.5)
  • Normalize a sum: norm(sum(cat | dog | horse))
  • King − Man + Woman: sum(diff(king|man)|woman) (or sum(king | neg(man) | woman))
  • Negate an embedding: neg(embedding:body_vector)

Functions

Display Name Action Name Description Usage Examples
Average avg Performs a weighted average between two segments or actions. The recommended weight is 0 - 1.
  • avg(The cat is|The dog is|0.5)
  • avg(Cat|Dog|0.5)
Difference diff Subtracts the segments in the order they are given. The first segment is subtracted from the second, then the third from the result, and so on.
  • diff(The cat is|The dog is)
  • diff(Cat|Dog)
  • sum(diff(king|man)|woman)
Multiply mult Multiplies the provided segments or actions by the multiplier.
  • mult(The cat is|2.5)
  • mult(Cat|-1)
Nearest Vocab nearest Snaps a computed vector to the k nearest real vocabulary tokens (by cosine similarity), returning their embeddings concatenated. The input is mean-pooled before lookup.
  • nearest(sum(diff(king|man)|woman))
  • nearest(sum(red|blue)|3)
Negate neg Negates the provided segments or actions.
  • neg(cat)
  • sum(king|neg(man)|women)
Noise noise Adds Gaussian noise (mean 0, given std) to the embeddings of the first argument.
  • A noise(cat|0.05) on a sunny day
Normalize norm Normalizes the provided segments or actions.
  • norm(cat)
  • sum(cat|norm(sum(tiger|fish)))
Positional Embedding Scale posScale Scales (multiplies) the positional embeddings of the provided segments or actions by the multiplier.
  • A posScale(cat|1.5) on a rainy day
Ignore Positional Embeddings postPos Prevents positional embeddings from being applied to the provided segments or actions.
  • A postPos(cat) on a rainy day
Project proj Projects the first argument onto the direction of the second (mean, unit-normalized).
  • proj(king|gender)
  • diff(style|proj(style|photorealistic))
Random Embedding rand Returns a random embedding of the specified token length, with the values optionally bounded by the second and third arguments.
  • A rand(1) cat
  • A rand(1|-1|1) cat
Reject reject Removes the component of the first argument along the direction of the second (a - proj(a|b)).
  • reject(anime girl|anime)
Renormalize renorm Rescales the first argument so each token's L2 norm matches the (mean) L2 norm of the reference.
  • renorm(sum(king|neg(man)|woman)|queen)
Scale Dimensions scaleDims Scales the specified dimensions of the input embeddings by the specified amount
  • The scaleDims(cat|4,1.5|76,1.2) is happy
Set Dimensions setDims Sets the specified dimensions of the input embeddings to the specified value
  • The setDims(cat|4, -0.01253|76, 1.2) is happy
Slerp slerp Performs a slerp (interpolation) between two segments or actions, with the given weight. The recommended weight is 0 - 1.
  • The slerp(cat|dog|0.5) is happy
Sum sum Adds the embeddings of the provided segments or actions.
  • A happy sum(cat|dog|shark)

lerp(a|b|t) is also accepted as an alias for avg(a|b|t).

Regenerate the table with python tools/build_docs.py.

Development

Tests are pytest-based and don't require ComfyUI:

pip install -e ".[dev]"
python -m pytest

Compatibility

  • SD1.x (CLIP-L) and SDXL (CLIP-L + CLIP-G).
  • SD2 is not supported.
  • Two pooler-output actions (_exp-pooler, _exp-pooledAvg) from earlier versions were experimental and have been removed; they relied on direct HuggingFace transformer access that is no longer how ComfyUI structures its CLIP encoders.
S
Description
No description provided
Readme
46 MiB
Languages
Python 100%