Arslan1997's picture
launching
528cb2d
Raw History Blame Contribute Delete
1.89 kB
"""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