Download source/src/deg/client.py from gcoderw/DEG-5B-E2B-1018: direct link, hf CLI and curl.
- Browser
- Download file 6.38 kB
-
https://huggingface.co/gcoderw/DEG-5B-E2B-1018/resolve/main/source/src/deg/client.py
- Command line
-
hf download hf://gcoderw/DEG-5B-E2B-1018/source/src/deg/client.py
-
curl -L -o client.py https://huggingface.co/gcoderw/DEG-5B-E2B-1018/resolve/main/source/src/deg/client.py
6.38 kB
| """Python SDK for a deg server (stdlib only). | |
| ```python | |
| from deg.client import Deg | |
| client = Deg("http://127.0.0.1:8790") # base_url; "/v1" is appended if missing | |
| decision = client.decisions.create( # OpenAI Decisions API signature | |
| model="deg-latest", | |
| input="Order AB-1234 arrived broken. Please refund me.", | |
| questions=[ | |
| {"type": "choice", "name": "event", "instructions": "Which event is this?", | |
| "choices": [{"value": "refund_request"}, {"value": "shipping_issue"}]}, | |
| {"type": "extract", "name": "order_id", "instructions": "The order id."}, | |
| {"type": "generate", "name": "note", "instructions": "One-line note for the agent.", | |
| "max_length": 200}, | |
| ], | |
| ) | |
| decision.answers[0].choice, decision.answers[1].value, decision.answers[2].text | |
| client.systemone(state="...", questions={"urgent": {"type": "noul", "instructions": "..."}}) | |
| client.fill(context="...", schema={...}) # deg /v1/fill | |
| ``` | |
| Responses are :class:`Record` objects: plain ``dict`` subclasses whose keys are also | |
| attributes (``decision.answers[0].probability``), so they serialize as the wire JSON. | |
| HTTP errors raise :class:`DegAPIError` with ``status`` and the decoded ``body``. | |
| The stock ``openai`` SDK (>= 3.26) also works against the same server: | |
| ``OpenAI(base_url="http://127.0.0.1:8790/v1", api_key="unused").decisions.create(...)``. | |
| """ | |
| from __future__ import annotations | |
| import json | |
| import os | |
| import urllib.error | |
| import urllib.request | |
| from collections.abc import Iterable, Mapping | |
| from typing import Any | |
| DEFAULT_BASE_URL = "http://127.0.0.1:8790/v1" | |
| DEFAULT_MODEL = "deg-latest" | |
| class DegAPIError(RuntimeError): | |
| def __init__(self, status: int, body: Any) -> None: | |
| super().__init__(f"deg HTTP {status}: {json.dumps(body)[:500]}") | |
| self.status = status | |
| self.body = body | |
| class Record(dict): | |
| """A response object: a dict whose keys are also attributes (recursively).""" | |
| def __getattr__(self, name: str) -> Any: | |
| try: | |
| return self[name] | |
| except KeyError: | |
| raise AttributeError(name) from None | |
| def wrap(cls, value: Any) -> Any: | |
| if isinstance(value, dict): | |
| return cls({k: cls.wrap(v) for k, v in value.items()}) | |
| if isinstance(value, list): | |
| return [cls.wrap(v) for v in value] | |
| return value | |
| class Decisions: | |
| def __init__(self, client: Deg) -> None: | |
| self._client = client | |
| def create(self, *, input: str | Iterable[Mapping[str, Any]], # noqa: A002 -- OpenAI name | |
| questions: Iterable[Mapping[str, Any]], model: str = DEFAULT_MODEL, | |
| safety_identifier: str | None = None, options: Mapping[str, Any] | None = None, | |
| timeout: float | None = None) -> Record: | |
| """``POST /v1/decisions``, the OpenAI ``client.decisions.create`` signature (plus | |
| deg's request ``options``).""" | |
| body: dict[str, Any] = {"model": model, | |
| "input": input if isinstance(input, str) else list(input), | |
| "questions": list(questions)} | |
| if safety_identifier is not None: | |
| body["safety_identifier"] = safety_identifier | |
| if options is not None: | |
| body["options"] = dict(options) | |
| return self._client._post("/decisions", body, timeout) | |
| class Deg: | |
| def __init__(self, base_url: str | None = None, *, api_key: str | None = None, | |
| timeout: float = 300.0) -> None: | |
| url = (base_url or os.environ.get("DEG_BASE_URL") or DEFAULT_BASE_URL).rstrip("/") | |
| self.base_url = url if url.endswith("/v1") else url + "/v1" | |
| self._api_key = api_key if api_key is not None else os.environ.get("DEG_API_KEY") | |
| self.timeout = timeout | |
| self.decisions = Decisions(self) | |
| def __repr__(self) -> str: # never show the key | |
| return f"Deg({self.base_url!r})" | |
| def systemone(self, state: Any, questions: Mapping[str, Mapping[str, Any]], *, | |
| model: str = DEFAULT_MODEL, options: Mapping[str, Any] | None = None, | |
| timeout: float | None = None) -> Record: | |
| """``POST /v1/systemone`` (TypeSafe Jev request: state + questions by id).""" | |
| body: dict[str, Any] = {"model": model, "state": state, "questions": dict(questions)} | |
| if options is not None: | |
| body["options"] = dict(options) | |
| return self._post("/systemone", body, timeout) | |
| def fill(self, context: Any, schema: Mapping[str, Any], *, model: str = DEFAULT_MODEL, | |
| options: Mapping[str, Any] | None = None, timeout: float | None = None) -> Record: | |
| """``POST /v1/fill``: ``{model, value, meta, usage, plan}`` (SPEC.md §8).""" | |
| body: dict[str, Any] = {"context": context, "schema": dict(schema), "model": model} | |
| if options is not None: | |
| body["options"] = dict(options) | |
| return self._post("/fill", body, timeout) | |
| def models(self) -> Record: | |
| return self._request("GET", "/models", None, None) | |
| def health(self) -> Record: | |
| root = self.base_url[: -len("/v1")] | |
| return self._request("GET", "/health", None, None, base=root) | |
| def _post(self, path: str, body: dict[str, Any], timeout: float | None) -> Record: | |
| return self._request("POST", path, body, timeout) | |
| def _request(self, method: str, path: str, body: Any, timeout: float | None, | |
| base: str | None = None) -> Record: | |
| headers = {"Content-Type": "application/json", "Accept": "application/json"} | |
| if self._api_key: | |
| headers["Authorization"] = f"Bearer {self._api_key}" | |
| data = None if body is None else json.dumps(body, ensure_ascii=False).encode("utf-8") | |
| req = urllib.request.Request((base or self.base_url) + path, data=data, | |
| headers=headers, method=method) | |
| try: | |
| with urllib.request.urlopen(req, timeout=timeout or self.timeout) as resp: | |
| return Record.wrap(json.loads(resp.read())) | |
| except urllib.error.HTTPError as exc: | |
| raw = exc.read().decode("utf-8", "replace") | |
| try: | |
| err: Any = json.loads(raw) | |
| except json.JSONDecodeError: | |
| err = raw | |
| raise DegAPIError(exc.code, err) from None | |