53 lines
1.9 KiB
Python
53 lines
1.9 KiB
Python
"""Contract between prompt orchestration and a conditioning implementation."""
|
|
|
|
import re
|
|
from abc import ABC, abstractmethod
|
|
from dataclasses import dataclass
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class EncoderCapabilities:
|
|
breaks: bool
|
|
scheduling: bool
|
|
normalization: bool
|
|
|
|
|
|
class PromptEncoder(ABC):
|
|
"""Return (conditioning tensor, complete metadata) without retaining state.
|
|
|
|
Implementations own tokenization, weighting, segmentation and the metadata
|
|
required by the consuming model. Nodes own parsing, caching and schedules.
|
|
"""
|
|
|
|
name: str
|
|
capabilities: EncoderCapabilities
|
|
|
|
@abstractmethod
|
|
def matches(self, clip, streams):
|
|
"""Whether the encoder/model contract supports these token streams."""
|
|
|
|
def validate_request(self, text="", *, normalization=False, scheduled=False):
|
|
if re.search(r"\bBREAK\b", text) and not self.capabilities.breaks:
|
|
raise ValueError(f"{self.name} BREAK is not supported. Use an unsplit prompt.")
|
|
if scheduled and not self.capabilities.scheduling:
|
|
raise ValueError(
|
|
f"{self.name} scheduling/alternation is not supported. Use a static prompt."
|
|
)
|
|
if normalization and not self.capabilities.normalization:
|
|
raise ValueError(
|
|
f"{self.name} normalization is not supported. Disable normalization."
|
|
)
|
|
|
|
def validate_schedule_metadata(self, metadata):
|
|
# The shared hook swaps the embedding tensor only. pooled_output is
|
|
# permitted for compatibility but stays pinned to the first prompt.
|
|
if set(metadata) - {"pooled_output"}:
|
|
raise ValueError(
|
|
"Prompt scheduling cannot swap this encoder's auxiliary "
|
|
"conditioning fields yet. Use a static prompt."
|
|
)
|
|
|
|
@abstractmethod
|
|
def encode(self, clip, text, normalization=False, debug=False):
|
|
"""Encode text after validating supported operations; preserve metadata."""
|