Download runtime/glance_runtime/schema.py from bpHigh/glance-0.1: direct link, hf CLI and curl.
- Browser
- Download file 5.96 kB
-
https://huggingface.co/bpHigh/glance-0.1/resolve/main/runtime/glance_runtime/schema.py
- Command line
-
hf download hf://bpHigh/glance-0.1/runtime/glance_runtime/schema.py
-
curl -L -o schema.py https://huggingface.co/bpHigh/glance-0.1/resolve/main/runtime/glance_runtime/schema.py
5.96 kB
| """Decisions, questions and the ``/v1/systemone`` wire format. | |
| A *decision* is a state (text, JSON or a list) plus optional images and one or more typed | |
| questions. Each question has an ordered list of labels: | |
| * ``choice``: labels are the option names; ``definitions`` holds each option's criterion. | |
| * ``score``: labels are the level descriptions, index = level (2 to 10 levels). | |
| * ``noul``: labels are always ``["no", "yes"]``; ``definitions`` holds the | |
| ``[false, true]`` criteria when given. | |
| Requests carry ``state``, ``questions`` and optionally ``images`` (``data:`` URLs); responses | |
| carry one answer per question with ``probabilities`` (choice, score) or ``noul`` (the yes | |
| probability). | |
| """ | |
| from __future__ import annotations | |
| import math | |
| from dataclasses import dataclass, field | |
| from typing import Any | |
| QUESTION_TYPES = ("choice", "score", "noul") | |
| NOUL_LABELS = ["no", "yes"] | |
| MAX_CHOICE_OPTIONS = 255 | |
| MIN_SCORE_LEVELS, MAX_SCORE_LEVELS = 2, 10 | |
| MAX_IMAGES = 8 | |
| class SchemaError(ValueError): | |
| """A request that does not follow the schema.""" | |
| def normalise(values: list[float]) -> list[float]: | |
| total = float(sum(values)) | |
| return [float(v) / total for v in values] | |
| class Question: | |
| type: str | |
| instructions: str | |
| labels: list[str] | |
| definitions: list[str | None] | None = None | |
| def validate(self) -> None: | |
| if self.type not in QUESTION_TYPES: | |
| raise SchemaError(f"unknown question type {self.type!r}") | |
| if not isinstance(self.instructions, str): | |
| raise SchemaError("instructions must be a string") | |
| n = len(self.labels) | |
| if self.type == "noul": | |
| if self.labels != NOUL_LABELS: | |
| raise SchemaError(f"noul labels must be {NOUL_LABELS}, got {self.labels}") | |
| elif self.type == "choice": | |
| if not 2 <= n <= MAX_CHOICE_OPTIONS: | |
| raise SchemaError(f"choice needs 2-{MAX_CHOICE_OPTIONS} options, got {n}") | |
| if len(set(self.labels)) != n: | |
| raise SchemaError("choice labels must be unique") | |
| elif not MIN_SCORE_LEVELS <= n <= MAX_SCORE_LEVELS: | |
| raise SchemaError(f"score needs {MIN_SCORE_LEVELS}-{MAX_SCORE_LEVELS} levels, got {n}") | |
| if any(not isinstance(label, str) or not label for label in self.labels): | |
| raise SchemaError("labels must be non-empty strings") | |
| if self.definitions is not None and len(self.definitions) != n: | |
| raise SchemaError("definitions must align with labels") | |
| def from_wire(cls, q: dict[str, Any]) -> "Question": | |
| qtype = q.get("type") | |
| instructions = q.get("instructions", "") or "" | |
| criteria = q.get("criteria") | |
| if qtype == "choice": | |
| if isinstance(criteria, dict): | |
| labels = [str(k) for k in criteria] | |
| definitions = [None if v is None else str(v) for v in criteria.values()] | |
| elif isinstance(criteria, list): | |
| labels, definitions = [str(c) for c in criteria], None | |
| else: | |
| raise SchemaError("choice question needs criteria") | |
| question = cls("choice", instructions, labels, definitions) | |
| elif qtype == "score": | |
| if not isinstance(criteria, list): | |
| raise SchemaError("score question needs a list of levels") | |
| question = cls("score", instructions, [str(c) for c in criteria], None) | |
| elif qtype == "noul": | |
| definitions = None | |
| if isinstance(criteria, dict): | |
| definitions = [criteria.get("false"), criteria.get("true")] | |
| question = cls("noul", instructions, list(NOUL_LABELS), definitions) | |
| else: | |
| raise SchemaError(f"unknown question type {qtype!r}") | |
| question.validate() | |
| return question | |
| class Decision: | |
| """One state with its typed questions.""" | |
| id: str | |
| state: Any | |
| questions: dict[str, Question] | |
| images: list[dict[str, Any]] = field(default_factory=list) | |
| def validate(self) -> None: | |
| if not isinstance(self.state, (str, dict, list)): | |
| raise SchemaError("state must be a string, object or list") | |
| if not self.questions: | |
| raise SchemaError("a decision needs at least one question") | |
| for name, q in self.questions.items(): | |
| if not name: | |
| raise SchemaError("question names must be non-empty") | |
| q.validate() | |
| if len(self.images) > MAX_IMAGES: | |
| raise SchemaError(f"at most {MAX_IMAGES} images per request") | |
| def choice_confidence(probs: list[float]) -> float: | |
| """(p_max - 1/n) / (1 - 1/n): 0 for a uniform distribution, 1 for a certain one.""" | |
| n = len(probs) | |
| return (max(probs) - 1.0 / n) / (1.0 - 1.0 / n) | |
| def score_confidence(probs: list[float]) -> float: | |
| """1 - (probability-weighted distance from the peak level) / (same for a uniform distribution).""" | |
| n = len(probs) | |
| peak = max(range(n), key=lambda i: probs[i]) | |
| spread = sum(p * abs(i - peak) for i, p in enumerate(probs)) | |
| uniform = sum(abs(i - peak) for i in range(n)) / n | |
| return 1.0 - spread / uniform if uniform else 1.0 | |
| def make_answer(question: Question, probs: list[float]) -> dict[str, Any]: | |
| """Format a distribution over ``question.labels`` as a ``/v1/systemone`` answer.""" | |
| probs = normalise(probs) | |
| if question.type == "noul": | |
| return {"type": "noul", "noul": probs[1]} | |
| if question.type == "choice": | |
| best = max(range(len(probs)), key=lambda i: probs[i]) | |
| return {"type": "choice", "choice": question.labels[best], | |
| "probabilities": dict(zip(question.labels, probs)), | |
| "confidence": choice_confidence(probs)} | |
| expected = sum(i * p for i, p in enumerate(probs)) | |
| return {"type": "score", "score": expected, "confidence": score_confidence(probs), | |
| "probabilities": {str(i): p for i, p in enumerate(probs)}} | |