Spaces:
Running on Zero
Running on Zero
Download jeeves_src/inference/api.py from hugging-apps/jeeves-9b: direct link, hf CLI and curl.
- Browser
- Download file 5.4 kB
-
https://huggingface.co/spaces/hugging-apps/jeeves-9b/resolve/main/jeeves_src/inference/api.py
- Command line
-
hf download hf://spaces/hugging-apps/jeeves-9b/jeeves_src/inference/api.py
-
curl -L -o api.py https://huggingface.co/spaces/hugging-apps/jeeves-9b/resolve/main/jeeves_src/inference/api.py
5.4 kB
| from __future__ import annotations | |
| import json | |
| from typing import Any | |
| from inference.types import Options, Result | |
| from prep.format import CHOICE, NOUL, QUESTION_TYPES, DataFormat, Question | |
| MAX_OPTIONS = 255 | |
| MODEL_ID = "jeeves-latest" | |
| def parse_options(raw: Any, defaults: Options) -> Options: | |
| if raw is None: | |
| return defaults | |
| if not isinstance(raw, dict): | |
| raise ValueError("options must be an object") | |
| unknown = set(raw) - {"think", "max_think", "nothink_threshold", "return_reasoning"} | |
| if unknown: | |
| raise ValueError(f"unknown options: {sorted(unknown)}") | |
| think = raw.get("think", defaults.think) | |
| max_think = raw.get("max_think", defaults.max_think) | |
| threshold = raw.get("nothink_threshold", defaults.nothink_threshold) | |
| reasoning = raw.get("return_reasoning", defaults.return_reasoning) | |
| if not isinstance(think, bool) or not isinstance(reasoning, bool): | |
| raise ValueError("think and return_reasoning must be booleans") | |
| if isinstance(max_think, bool) or not isinstance(max_think, int) or max_think < 0: | |
| raise ValueError("max_think must be a non-negative integer") | |
| if threshold is not None and (isinstance(threshold, bool) or not isinstance(threshold, (int, float)) or not 0 <= threshold <= 1): | |
| raise ValueError("nothink_threshold must be null or a number in [0, 1]") | |
| return Options(think=think, max_think=max_think, nothink_threshold=None if threshold is None else float(threshold), | |
| return_reasoning=reasoning) | |
| def parse_question(qid: str, raw: Any) -> Question: | |
| if not isinstance(raw, dict): | |
| raise ValueError(f"question {qid!r} must be an object") | |
| kind = raw.get("type") | |
| if kind not in QUESTION_TYPES: | |
| raise ValueError(f"question {qid!r}: type must be one of {list(QUESTION_TYPES)}") | |
| unknown = set(raw) - {"type", "instructions", "criteria"} | |
| if unknown: | |
| raise ValueError(f"question {qid!r}: unknown fields {sorted(unknown)}") | |
| criteria = raw.get("criteria") | |
| if kind == CHOICE and not (isinstance(criteria, dict) and 1 <= len(criteria) <= MAX_OPTIONS): | |
| raise ValueError(f"question {qid!r}: choice criteria must be an object with 1..{MAX_OPTIONS} options") | |
| if kind == NOUL and criteria is not None and not (isinstance(criteria, dict) and set(criteria) <= {"true", "false"}): | |
| raise ValueError(f"question {qid!r}: noul criteria may only describe true and false") | |
| if kind not in (CHOICE, NOUL) and not (isinstance(criteria, list) and 1 <= len(criteria) <= MAX_OPTIONS): | |
| raise ValueError(f"question {qid!r}: score criteria must be a list of 1..{MAX_OPTIONS} levels") | |
| return Question(id=qid, type=kind, instructions=raw.get("instructions"), criteria=criteria, label=0) | |
| def parse_request(body: Any, defaults: Options) -> tuple[DataFormat, str, Options]: | |
| if not isinstance(body, dict): | |
| raise ValueError("request body must be a JSON object") | |
| if "state" not in body: | |
| raise ValueError("state is required") | |
| questions = body.get("questions") | |
| if not isinstance(questions, dict) or not questions: | |
| raise ValueError("questions must be a non-empty object") | |
| model = body.get("model", MODEL_ID) | |
| if not isinstance(model, str): | |
| raise ValueError("model must be a string") | |
| record = DataFormat(state=body["state"], questions=[parse_question(str(k), v) for k, v in questions.items()]) | |
| return record, model, parse_options(body.get("options"), defaults) | |
| def r2(x: float) -> float: | |
| return round(float(x), 2) | |
| 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: | |
| if len(p) == 1: | |
| return 1.0 | |
| mode = max(range(len(p)), key=lambda i: p[i]) | |
| return 1.0 - sum(pi * abs(i - mode) for i, pi in enumerate(p)) / (len(p) - 1) | |
| def answer(q: Question, p: list[float]) -> dict: | |
| if q.type == NOUL: | |
| return {"type": NOUL, "noul": r2(p[1])} | |
| if q.type == CHOICE: | |
| keys = q.keys() | |
| return {"type": CHOICE, "choice": keys[max(range(len(p)), key=lambda i: p[i])], "confidence": r2(choice_confidence(p)), | |
| "probabilities": {k: r2(v) for k, v in zip(keys, p)}} | |
| return {"type": "score", "score": r2(sum(i * pi for i, pi in enumerate(p))), "legend": dict(zip(q.keys(), q.options())), | |
| "probabilities": {str(i): r2(v) for i, v in enumerate(p)}, "confidence": r2(score_confidence(p))} | |
| def response(record: DataFormat, model: str, opts: Options, results: list[Result], tok, latency_ms: float) -> dict: | |
| answers = {q.id: answer(q, r.probs) for q, r in zip(record.questions, results)} | |
| out = {"model": model, "answers": answers, | |
| "usage": {"input_tokens": sum(r.prompt_tokens for r in results), | |
| "output_tokens": len(tok(json.dumps(answers), add_special_tokens=False).input_ids), | |
| "reasoning_tokens": sum(len(r.chain) for r in results)}, | |
| "latency_ms": round(latency_ms, 1)} | |
| if opts.return_reasoning: | |
| out["reasoning"] = {q.id: {"thought": r.thought, "closed": r.closed, "tokens": len(r.chain), | |
| "text": tok.decode([t for t in r.chain if t != tok.convert_tokens_to_ids("</think>")])} | |
| for q, r in zip(record.questions, results)} | |
| return out | |