cua-s1-forms-coreml / preprocessing.py
alexwengg's picture
Add CUA-S1-FORMS FP16 Core ML conversion and verified artifacts (#1)
ca2113d
Raw
History Blame Contribute Delete
2.12 kB
"""Host-side UTF-8 byte encoding for the fixed-shape Core ML interface."""
from __future__ import annotations
from dataclasses import dataclass
import numpy as np
@dataclass(frozen=True)
class InputLimits:
context_bytes: int = 224
option_bytes: int = 96
max_options: int = 32
def __post_init__(self):
if self.context_bytes < 1 or self.option_bytes < 1 or self.max_options < 2:
raise ValueError("Positive byte limits and at least two option slots are required")
def byte_ids(text: str, length: int) -> np.ndarray:
"""Match upstream: truncate UTF-8 bytes, offset byte values by one, zero-pad."""
data = text.encode("utf-8", errors="replace")[:length]
return np.frombuffer(data, dtype=np.uint8).astype(np.int32) + 1
def prepare_inputs(context: str, options: list[str] | tuple[str, ...], limits: InputLimits) -> dict[str, np.ndarray]:
"""Encode one decision; options are never silently removed to fit the model."""
if not isinstance(context, str) or not context:
raise ValueError("context must be a nonempty string")
if not isinstance(options, (list, tuple)) or len(options) < 2:
raise ValueError("At least two options are required")
if len(options) > limits.max_options:
raise ValueError(f"{len(options)} options exceed {limits.max_options}; re-export with a larger --max-options")
if any(not isinstance(option, str) or not option for option in options):
raise ValueError("Options must be nonempty strings")
context_ids = np.zeros((1, limits.context_bytes), dtype=np.int32)
option_ids = np.zeros((1, limits.max_options, limits.option_bytes), dtype=np.int32)
option_mask = np.zeros((1, limits.max_options), dtype=np.int32)
tokens = byte_ids(context, limits.context_bytes)
context_ids[0, : len(tokens)] = tokens
for index, option in enumerate(options):
tokens = byte_ids(option, limits.option_bytes)
option_ids[0, index, : len(tokens)] = tokens
option_mask[0, : len(options)] = 1
return {"context_ids": context_ids, "option_ids": option_ids, "option_mask": option_mask}