jevlite / typed_schema.py
eightman999's picture
Add JevLite PyTorch checkpoint and Core ML packages
580cc4b verified
Raw History Blame Contribute Delete
3.21 kB
"""The Jev interface, reimplemented.
A *state* (any JSON or text) plus N *typed questions*. One forward pass answers
all of them. Three primitive types, matching Jev:
noul - boolean criteria: {"true": desc, "false": desc}
choice - enum criteria: {label: desc, ...}
score - ordered scale criteria: [desc_0, desc_1, ...] labels are "0".."n-1"
Everything downstream reads questions through `iter_labels`, so adding a new
primitive means touching this file only.
"""
from __future__ import annotations
import json
from typing import Any
TYPES = ["noul", "choice", "score"]
TYPE_ID = {t: i for i, t in enumerate(TYPES)}
# A bare noul carries no criteria at all - the instruction is the statement and
# the labels are implicit. 10% of typed-decisions is shaped this way, so treat it
# as part of the format rather than as malformed input.
BARE_NOUL = [("false", "The statement does not hold."),
("true", "The statement holds.")]
def iter_labels(q: dict) -> list[tuple[str, str]]:
"""Normalize a question's criteria to an ordered [(label, description)] list.
`score` criteria arrive as an ordered list; its labels are the indices as
strings, which is how the gold distributions key them.
"""
crit = q.get("criteria")
if crit is None:
if q["type"] != "noul":
raise ValueError(
f"a {q['type']} question needs criteria - only noul may omit "
f"them: {q.get('instructions', '')[:80]!r}")
return list(BARE_NOUL)
if isinstance(crit, list): # score
return [(str(i), d) for i, d in enumerate(crit)]
if q["type"] == "noul": # pin order: false, true
return [(k, crit[k]) for k in ("false", "true") if k in crit]
return sorted(crit.items()) # choice - stable order
def state_to_text(state: Any) -> str:
if isinstance(state, str):
return state
return json.dumps(state, indent=1, sort_keys=True, ensure_ascii=False)
def label_text(label: str, desc: str) -> str:
return f"{label}: {desc}"
class Question(dict):
"""Convenience builder so you can define a schema in code.
>>> Question.choice("What should we do?", {"retry": "...", "stop": "..."})
"""
@staticmethod
def noul(instructions: str, true_desc: str = None,
false_desc: str = None) -> dict:
"""Descriptions are optional, matching the data: a bare noul carries no
criteria at all and the instruction is the statement being judged."""
q = {"type": "noul", "instructions": instructions}
if true_desc is not None or false_desc is not None:
q["criteria"] = {"true": true_desc or "The statement holds.",
"false": false_desc or "The statement does not hold."}
return q
@staticmethod
def choice(instructions: str, criteria: dict[str, str]) -> dict:
return {"type": "choice", "instructions": instructions, "criteria": criteria}
@staticmethod
def score(instructions: str, levels: list[str]) -> dict:
return {"type": "score", "instructions": instructions, "criteria": levels}