Rebase the DSL text encoder on comfy.sd1_clip.SDClipModel and comfy.clip_model.CLIPTextModel_, replacing the old HuggingFace transformers CLIPTextModel/CLIPTextTransformer/CLIPTextEmbeddings subclasses (which are no longer how ComfyUI implements CLIP). Structure: - Merge lib/action/ into lib/actions/; drop lib/fun_clip_stuff.py and the bundled clip_config*.json (comfy ships its own) - Convert all custom_nodes.KepPromptLang.* absolute imports to relative imports so installs via Manager work regardless of install directory name Encoder: - PromptLangSDClipModel overrides encode_token_weights to walk the segment/action tree, assemble [B, seq, hidden] embeds, and call self.transformer(None, mask, embeds=..., num_tokens=...) - posScale / postPos are supported without patching the transformer by pre-baking the delta (modified - default) into embeds, so the transformer's inline add yields the modified position embedding - Drop the unused empty-baseline batch that was prepended and then sliced off; halves the per-encode forward pass for single prompts Actions: - Fix copy-pasted broken __repr__ / depth_repr across sum/diff/avg/ slerp that referenced fields that didn't exist - Fix NameError in AverageAction._validate_args (start_arg_token_length) - Fix class-level mutable state in RandAction - Unify _parse_scalar / _parse_scalar_weight / _parse_int into a single parse_numeric_arg helper in action_utils.py - Share add_with_broadcast between SumAction and DiffAction - Convert PostModifiers from TypedDict to dataclass (attribute access catches typos that .get() on string keys hides) Drop the two _exp-pooler / _exp-pooledAvg actions: they recursively invoked the HF CLIPTextTransformer and would need a rework to fit the current CLIPTextModel_ interface. They were experimental and not documented as stable. BuildGif node: - Collapse the 10-positional-arg _save_* helpers onto a small _SaveContext dataclass - Stop mutating the input arg semantics (split_every_val was reassigned to len(images) when -1) Tests: - Add pytest suite covering the parser (grammar, nesting, errors) and every action (embedding math, shape, modifier payloads) - conftest stubs ComfyUI at collection time so tests don't need a real ComfyUI install Drop the broken test_files/ scripts (CI helpers, not a test suite) and regenerate the README from tools/build_docs.py.
42 lines
1.6 KiB
Python
42 lines
1.6 KiB
Python
from lark import Token
|
|
|
|
from comfy.sd1_clip import SDTokenizer
|
|
|
|
from .prompt_segment import PromptSegment
|
|
|
|
|
|
def flatten_tree(tree):
|
|
if isinstance(tree, Token):
|
|
return [str(tree)]
|
|
return [str(tree.data)] + sum([flatten_tree(child) for child in tree.children], [])
|
|
|
|
|
|
def build_prompt_segment(text: str, tokenizer: SDTokenizer) -> PromptSegment:
|
|
"""Tokenize a chunk of plain text into a PromptSegment, expanding `embedding:NAME` refs to tensors."""
|
|
tokens = []
|
|
for word in text.split(" "):
|
|
if word.startswith(tokenizer.embedding_identifier) and tokenizer.embedding_directory is not None:
|
|
embedding_name = word[len(tokenizer.embedding_identifier):].strip("\n")
|
|
embedding, leftover = tokenizer._try_get_embedding(embedding_name)
|
|
if embedding is None:
|
|
print(f"warning, embedding:{embedding_name} does not exist, ignoring")
|
|
elif embedding.shape[1] != tokenizer.embedding_size:
|
|
print(
|
|
f"warning, embedding:{embedding_name} has size {embedding.shape[1]}, "
|
|
f"expected {tokenizer.embedding_size}, ignoring"
|
|
)
|
|
else:
|
|
if len(embedding.shape) == 1:
|
|
tokens.append(embedding)
|
|
else:
|
|
tokens.extend(embedding)
|
|
|
|
if leftover != "":
|
|
word = leftover
|
|
else:
|
|
continue
|
|
# Strip the SOT/EOT bracketing tokens added by the underlying CLIP tokenizer.
|
|
tokens.extend(tokenizer.tokenizer(word)["input_ids"][1:-1])
|
|
|
|
return PromptSegment(text, tokens)
|