"""The released app.py choice-scorer rendering, padding, and calibration.""" from __future__ import annotations import math from collections.abc import Sequence MAX_LENGTH = 256 TEMPERATURE = 2.35 def encode(tokenizer, state: str, question: str, option: str, max_length: int = MAX_LENGTH) -> list[int]: """Keep the question/option tail; truncate the state from its end, as upstream does.""" tail = tokenizer("\n\nQuestion:\n" + question + "\n\nOption:\n" + option, add_special_tokens=False)["input_ids"] if len(tail) >= max_length: return tail[-max_length:] head = tokenizer("State:\n" + state, add_special_tokens=False)["input_ids"] return head[: max_length - len(tail)] + tail def encode_options(tokenizer, state: str, question: str, options: Sequence[str]) -> list[list[int]]: if len(options) < 2: raise ValueError("the native app requires at least two options") if any(not option.strip() for option in options): raise ValueError("options must be nonempty") return [encode(tokenizer, state, question, option) for option in options] def pad_batch( sequences: Sequence[Sequence[int]], pad_id: int, length: int | None = None ) -> tuple[list[list[int]], list[list[int]]]: """Right-pad to the longest candidate (or fixed export length), with true token masks.""" if not sequences: raise ValueError("empty candidate batch") width = min(max(map(len, sequences)), MAX_LENGTH) if length is None else length if width > MAX_LENGTH or width < max(map(len, sequences)): raise ValueError("invalid padding length") ids = [list(row) + [pad_id] * (width - len(row)) for row in sequences] masks = [[1] * len(row) + [0] * (width - len(row)) for row in sequences] return ids, masks def softmax(logits: Sequence[float], temperature: float = TEMPERATURE) -> list[float]: if not logits or temperature <= 0: raise ValueError("need logits and a positive temperature") scaled = [float(value) / temperature for value in logits] peak = max(scaled) weights = [math.exp(value - peak) for value in scaled] total = sum(weights) return [weight / total for weight in weights] def choose(options: Sequence[str], logits: Sequence[float]) -> dict: if len(options) != len(logits): raise ValueError("one scalar logit is required per option") probabilities = softmax(logits) index = max(range(len(options)), key=probabilities.__getitem__) return {"selected_index": index, "selected_option": options[index], "probabilities": probabilities}