Download runtime/jevlike/types.py from Cem13/kodama-vision: direct link, hf CLI and curl.
- Browser
- Download file 4.4 kB
-
https://huggingface.co/Cem13/kodama-vision/resolve/main/runtime/jevlike/types.py
- Command line
-
hf download hf://Cem13/kodama-vision/runtime/jevlike/types.py
-
curl -L -o types.py https://huggingface.co/Cem13/kodama-vision/resolve/main/runtime/jevlike/types.py
4.4 kB
| """Shared question and record types. | |
| Public API types (Choice, Score, Noul) mirror Jev/Laya. Internally every question is | |
| normalized to a `Question` with an ordered list of `Option`s so the data pipeline, the | |
| serializer and the model all speak one format. Nothing here depends on torch. | |
| """ | |
| from __future__ import annotations | |
| import json | |
| from dataclasses import dataclass, field | |
| from typing import Literal, Union | |
| QType = Literal["choice", "score", "noul"] | |
| QTYPES: tuple[QType, ...] = ("choice", "score", "noul") | |
| # ---------------------------------------------------------------- public API types | |
| class Choice: | |
| """Pick one of several unordered options. criteria: {key: description} or [key, ...].""" | |
| instructions: str | |
| criteria: Union[dict[str, str], list[str]] | |
| class Score: | |
| """Place the state on an ordered scale. criteria: level descriptions, lowest first (2-10).""" | |
| instructions: str | |
| criteria: list[str] | |
| class Noul: | |
| """Probability that the statement in `instructions` holds for the state.""" | |
| instructions: str | |
| PublicQuestion = Union[Choice, Score, Noul] | |
| # ---------------------------------------------------------------- normalized form | |
| class Option: | |
| key: str # short label, e.g. "billing"; for score levels the level index as str | |
| text: str # description; may be "" when the key says it all | |
| class Question: | |
| type: QType | |
| instructions: str | |
| options: list[Option] = field(default_factory=list) # empty for noul | |
| def n_options(self) -> int: | |
| """Number of scored options; noul is scored as two options (false, true).""" | |
| return 2 if self.type == "noul" else len(self.options) | |
| def from_public(cls, q: PublicQuestion) -> "Question": | |
| if isinstance(q, Choice): | |
| items = q.criteria.items() if isinstance(q.criteria, dict) else ((k, "") for k in q.criteria) | |
| return cls("choice", q.instructions, [Option(str(k), str(v)) for k, v in items]) | |
| if isinstance(q, Score): | |
| return cls("score", q.instructions, [Option(str(i), t) for i, t in enumerate(q.criteria)]) | |
| if isinstance(q, Noul): | |
| return cls("noul", q.instructions, []) | |
| raise TypeError(f"not a question type: {type(q).__name__}") | |
| def validate(self) -> None: | |
| assert self.type in QTYPES, self.type | |
| if self.type == "noul": | |
| assert not self.options, "noul questions have no options" | |
| elif self.type == "score": | |
| assert 2 <= len(self.options) <= 10, "score needs 2-10 levels" | |
| else: | |
| assert 2 <= len(self.options) <= 255, "choice needs 2-255 options" | |
| keys = [o.key for o in self.options] | |
| assert len(set(keys)) == len(keys), "choice keys must be unique" | |
| # ---------------------------------------------------------------- training record | |
| class Record: | |
| """One (state, question, gold answer) training/eval example = one JSONL line. | |
| label: index into question.options for choice/score; 0 (false) or 1 (true) for noul. | |
| """ | |
| id: str | |
| source: str # dataset of origin, e.g. "ag_news" | |
| state: str | |
| question: Question | |
| label: int | |
| def validate(self) -> None: | |
| self.question.validate() | |
| assert 0 <= self.label < self.question.n_options, (self.id, self.label) | |
| assert self.state.strip(), self.id | |
| def to_json(self) -> str: | |
| q = self.question | |
| return json.dumps({ | |
| "id": self.id, "source": self.source, "state": self.state, | |
| "type": q.type, "instructions": q.instructions, | |
| "options": [{"key": o.key, "text": o.text} for o in q.options], | |
| "label": self.label, | |
| }, ensure_ascii=False) | |
| def from_json(cls, line: str) -> "Record": | |
| d = json.loads(line) | |
| q = Question(d["type"], d["instructions"], [Option(o["key"], o["text"]) for o in d["options"]]) | |
| return cls(d["id"], d["source"], d["state"], q, int(d["label"])) | |
| def read_jsonl(path: str) -> list[Record]: | |
| with open(path, encoding="utf-8") as f: | |
| return [Record.from_json(line) for line in f if line.strip()] | |
| def write_jsonl(path: str, records: list[Record]) -> None: | |
| with open(path, "w", encoding="utf-8") as f: | |
| for r in records: | |
| f.write(r.to_json() + "\n") | |