Download runtime/kev/api.py from divyanshx11/JEVision: direct link, hf CLI and curl.
- Browser
- Download file 7.99 kB
-
https://huggingface.co/divyanshx11/JEVision/resolve/b7bd874404ee8ef5a9db6a0eac2f86e72b712938/runtime/kev/api.py
- Command line
-
hf download hf://divyanshx11/JEVision@b7bd874404ee8ef5a9db6a0eac2f86e72b712938/runtime/kev/api.py
-
curl -L -o api.py https://huggingface.co/divyanshx11/JEVision/resolve/b7bd874404ee8ef5a9db6a0eac2f86e72b712938/runtime/kev/api.py
7.99 kB
| """TypeSafe-compatible request/response shapes (POST /v1/systemone) mapped onto the single pointer primitive. | |
| Noul -> 2 options [false, true]; answer = p(true) | |
| Choice -> options 'name' or 'name: desc'; answer = argmax, probabilities by name, confidence | |
| Score -> options = ordered level descriptions; answer = expected level, legend, probabilities by index | |
| """ | |
| import json | |
| import re | |
| from datetime import datetime | |
| from typing import Any, Literal, Union | |
| from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator | |
| JSONContent = Union[str, dict, list, int, float, bool, None] | |
| MAX_OPTIONS = 255 | |
| MAX_IMAGES = 4 | |
| class Noul(BaseModel): | |
| type: Literal["noul"] | |
| instructions: JSONContent | |
| criteria: dict[str, JSONContent] | None = None | |
| class Choice(BaseModel): | |
| type: Literal["choice"] | |
| instructions: JSONContent | |
| criteria: dict[str, JSONContent] | |
| def _check(self): | |
| if not 1 <= len(self.criteria) <= MAX_OPTIONS: raise ValueError(f"criteria must have 1..{MAX_OPTIONS} options") | |
| return self | |
| class Score(BaseModel): | |
| type: Literal["score"] | |
| instructions: JSONContent | |
| criteria: list[JSONContent] = Field(min_length=2, max_length=MAX_OPTIONS) | |
| Question = Union[Noul, Choice, Score] | |
| class ImageInput(BaseModel): | |
| """One image sent with a request: an RFC 2397 data URL, PNG, JPEG or WebP, base64 payload (kev.media decodes and | |
| bounds it). The media type is accepted case-insensitively and stored normalized. A path, an http(s) URL or any other | |
| media type is refused here, before anything is fetched or decoded.""" | |
| data_url: str | |
| # an image error must never echo the rejected data URL: the input is the payload | |
| model_config = ConfigDict(hide_input_in_errors=True) | |
| def _normalize(cls, v: str) -> str: | |
| from .media import parse_data_url # lazy: kev.api is vendored into the Space, which takes no images | |
| mime, payload = parse_data_url(v) | |
| return f"data:{mime};base64,{payload}" | |
| class SystemOneRequest(BaseModel): | |
| # an image error raised while validating this model is rendered here, so the data URL stays hidden at this level too; | |
| # kev.serve drops `input` from the 422 body for the same errors | |
| model_config = ConfigDict(hide_input_in_errors=True) | |
| state: JSONContent | |
| model: str = "kev-latest" | |
| questions: dict[str, Question] = Field(min_length=1) | |
| images: list[ImageInput] | None = Field(default=None, min_length=1, max_length=MAX_IMAGES) # omitted or null = text-only | |
| def render(v: JSONContent, indent: int = 0) -> str: | |
| """Flatten str | object | array into text the model sees. Field names are kept as labels.""" | |
| pad = " " * indent | |
| if v is None: return "" | |
| if isinstance(v, (str, int, float, bool)): return str(v) | |
| if isinstance(v, list): return "\n".join(f"{pad}- {render(x, indent + 1).lstrip()}" for x in v) | |
| return "\n".join(f"{pad}{k}:\n{render(x, indent + 1)}" if isinstance(x, (dict, list)) else f"{pad}{k}: {render(x)}" for k, x in v.items()) | |
| def option_text(name: str, desc: JSONContent) -> str: | |
| return name if desc is None or desc == "" else f"{name}: {render(desc)}" | |
| MONTHS = "January|February|March|April|May|June|July|August|September|October|November|December" | |
| _DATE = re.compile(rf"\b(?:{MONTHS}) \d{{1,2}}, \d{{4}}\b|\b\d{{4}}-\d{{2}}-\d{{2}}\b") | |
| def date_facts(text: str) -> str: | |
| """Deterministic date arithmetic for the model: every pair of absolute dates found in `text`, as one sentence each | |
| ("August 3, 2026 is 12 days after July 22, 2026."). The model cannot subtract dates reliably (issue #8); it can use a | |
| stated day count. Returns "" when fewer than two dates are found. Dates are listed in order of first appearance.""" | |
| found = [] | |
| for m in _DATE.finditer(text): | |
| raw = m.group(0) | |
| try: d = datetime.strptime(raw, "%B %d, %Y") if "," in raw else datetime.strptime(raw, "%Y-%m-%d") | |
| except ValueError: continue | |
| if raw not in [r for r, _ in found]: found.append((raw, d)) | |
| facts = [] | |
| for i in range(len(found)): | |
| for j in range(i + 1, len(found)): | |
| n = (found[j][1] - found[i][1]).days | |
| facts.append(f"{found[j][0]} is {abs(n)} day{'s' if abs(n) != 1 else ''} {'after' if n > 0 else 'before'} {found[i][0]}." if n else f"{found[j][0]} is the same day as {found[i][0]}.") | |
| return " ".join(facts) | |
| def with_date_facts(state): | |
| """State with a `date_facts` field (object states) or an appended paragraph (string states) when two or more absolute | |
| dates appear. Opt-in preprocessing (KEV_DATE_FACTS=1 in kev.serve, --date_facts in kev.benchmark).""" | |
| facts = date_facts(render(state)) | |
| if not facts: return state | |
| if isinstance(state, dict): return {**state, "date_facts": facts} | |
| if isinstance(state, list): return state + [{"date_facts": facts}] | |
| return f"{state}\n\ndate_facts: {facts}" | |
| def question_keys(qtype: str, criteria) -> list[str]: | |
| """The keys a question's probabilities are reported under, in option order: the criteria names (choice), | |
| ["false", "true"] (noul), the level indices as strings (score). Labels, targets and anchors use the same keys.""" | |
| if qtype == "choice": return list(criteria) | |
| if qtype == "noul": return ["false", "true"] | |
| return [str(i) for i in range(len(criteria))] | |
| def to_record(req: SystemOneRequest): | |
| """-> internal record for encode(), plus per-question metadata ({"id", "type", "keys", "legend" for score}) to map | |
| probabilities back.""" | |
| qs, meta = [], [] | |
| for qid, q in req.questions.items(): | |
| m = {"id": qid, "type": q.type, "keys": question_keys(q.type, q.criteria)} | |
| if q.type == "noul": | |
| c = q.criteria or {} | |
| opts = [option_text("no", c.get("false")), option_text("yes", c.get("true"))] | |
| elif q.type == "choice": | |
| opts = [option_text(k, v) for k, v in q.criteria.items()] | |
| else: | |
| opts = [render(x) for x in q.criteria] | |
| m["legend"] = dict(zip(m["keys"], opts)) | |
| qs.append({"instr": render(q.instructions), "options": opts, "label": 0}); meta.append(m) | |
| return {"state": render(req.state), "questions": qs}, meta | |
| def choice_confidence(p: list[float]) -> float: | |
| K = len(p) | |
| return 1.0 if K == 1 else (max(p) - 1 / K) / (1 - 1 / K) | |
| def score_confidence(p: list[float]) -> float: | |
| """Approximation of TypeSafe's 'distance from the modal level' statistic (exact formula unpublished): | |
| 1 - E|level - mode| / (L - 1).""" | |
| L = len(p); mode = max(range(L), key=lambda i: p[i]) | |
| return 1.0 - sum(pi * abs(i - mode) for i, pi in enumerate(p)) / (L - 1) | |
| def r2(x: float) -> float: | |
| return round(float(x), 2) | |
| def to_answers(probs: list[list[float]], meta: list[dict]) -> dict[str, Any]: | |
| out = {} | |
| for p, m in zip(probs, meta): | |
| if m["type"] == "noul": | |
| out[m["id"]] = {"type": "noul", "noul": r2(p[1])} | |
| elif m["type"] == "choice": | |
| dist = {k: r2(v) for k, v in zip(m["keys"], p)} | |
| out[m["id"]] = {"type": "choice", "choice": m["keys"][max(range(len(p)), key=lambda i: p[i])], "confidence": r2(choice_confidence(p)), "probabilities": dist} | |
| else: | |
| score = sum(i * pi for i, pi in enumerate(p)) | |
| out[m["id"]] = {"type": "score", "score": r2(score), "legend": m["legend"], "probabilities": {str(i): r2(v) for i, v in enumerate(p)}, "confidence": r2(score_confidence(p))} | |
| return out | |
| def output_tokens(tok, answers: dict) -> int: | |
| """Billing-style figure: tokens of the serialised answers. Not a measure of generation (there is none).""" | |
| return len(tok(json.dumps(answers), add_special_tokens=False).input_ids) | |