File size: 1,886 Bytes
528cb2d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
"""TypeSafe Jev: a System One classifier. It picks from options we define (with probabilities) and never
generates text, so it is the fast, cheap way to decide what a chat message needs.

API: POST {TYPESAFE_URL}/v1/systemone with {"state", "model", "questions"}; answers come back per
question id with "choice", "confidence" and "probabilities". https://docs.typesafe.ai/primitives/choice
"""

from dataclasses import dataclass

import httpx

from app.config import settings


class JevError(RuntimeError):
    pass


@dataclass
class Choice:
    choice: str
    confidence: float
    probabilities: dict[str, float]


def configured() -> bool:
    return bool(settings.typesafe_api_key)


def decide(state: str | dict, questions: dict[str, dict], timeout: float = 6.0) -> dict[str, Choice]:
    """Ask several Choice questions about one state in a single request (Jev evaluates them in parallel)."""
    if not configured():
        raise JevError("TYPESAFE_API_KEY is not set")
    body = {
        "state": state,
        "model": settings.typesafe_model,
        "questions": {qid: {"type": "choice", **q} for qid, q in questions.items()},
    }
    try:
        resp = httpx.post(f"{settings.typesafe_url.rstrip('/')}/v1/systemone", json=body, timeout=timeout,
                          headers={"Authorization": f"Bearer {settings.typesafe_api_key}"})
    except httpx.HTTPError as exc:
        raise JevError(f"Jev unreachable: {exc}") from exc
    if resp.status_code >= 400:
        raise JevError(f"Jev {resp.status_code}: {resp.text[:300]}")
    answers = resp.json().get("answers") or {}
    out = {}
    for qid in questions:
        a = answers.get(qid) or {}
        if "choice" not in a:
            raise JevError(f"Jev returned no answer for {qid}")
        out[qid] = Choice(a["choice"], float(a.get("confidence") or 0), a.get("probabilities") or {})
    return out