djeli 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
djeli/__init__.py ADDED
@@ -0,0 +1,2 @@
1
+ from .client import Djeli, DjeliError
2
+ __all__ = ["Djeli", "DjeliError"]
djeli/client.py ADDED
@@ -0,0 +1,70 @@
1
+ import json
2
+ from typing import Iterator
3
+
4
+ import httpx
5
+
6
+ DEFAULT_BASE = "http://127.0.0.1:11435"
7
+
8
+
9
+ class DjeliError(Exception):
10
+ pass
11
+
12
+
13
+ class Djeli:
14
+ def __init__(self, base_url: str = DEFAULT_BASE, timeout: float = 300.0):
15
+ self.base_url = base_url.rstrip("/")
16
+ self.timeout = timeout
17
+
18
+ def models(self) -> list[dict]:
19
+ r = httpx.get(f"{self.base_url}/v1/models", timeout=10.0)
20
+ r.raise_for_status()
21
+ return r.json().get("data", [])
22
+
23
+ def chat(
24
+ self,
25
+ model: str,
26
+ messages: list[dict],
27
+ temperature: float = 0.7,
28
+ max_tokens: int = 1024,
29
+ stream: bool = False,
30
+ ):
31
+ payload = {
32
+ "model": model,
33
+ "messages": messages,
34
+ "temperature": temperature,
35
+ "max_tokens": max_tokens,
36
+ "stream": stream,
37
+ }
38
+ if not stream:
39
+ r = httpx.post(
40
+ f"{self.base_url}/v1/chat/completions",
41
+ json=payload,
42
+ timeout=self.timeout,
43
+ )
44
+ if r.status_code >= 400:
45
+ raise DjeliError(r.text)
46
+ return r.json()["choices"][0]["message"]["content"]
47
+ return self._stream(payload)
48
+
49
+ def _stream(self, payload: dict) -> Iterator[str]:
50
+ with httpx.stream(
51
+ "POST",
52
+ f"{self.base_url}/v1/chat/completions",
53
+ json=payload,
54
+ timeout=self.timeout,
55
+ ) as r:
56
+ if r.status_code >= 400:
57
+ raise DjeliError(r.read().decode())
58
+ for line in r.iter_lines():
59
+ if not line.startswith("data:"):
60
+ continue
61
+ data = line[5:].strip()
62
+ if data == "[DONE]" or not data:
63
+ continue
64
+ try:
65
+ chunk = json.loads(data)
66
+ content = chunk["choices"][0].get("delta", {}).get("content", "")
67
+ if content:
68
+ yield content
69
+ except (json.JSONDecodeError, KeyError, IndexError):
70
+ continue
@@ -0,0 +1,48 @@
1
+ Metadata-Version: 2.4
2
+ Name: djeli
3
+ Version: 0.1.0
4
+ Summary: Python client for the djeli local LLM server
5
+ License: MIT
6
+ Requires-Python: >=3.8
7
+ Description-Content-Type: text/markdown
8
+ Requires-Dist: httpx>=0.27
9
+
10
+ # djeli
11
+
12
+ Python client for the djeli local LLM server.
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ pip install djeli
18
+ ```
19
+
20
+ ## Usage
21
+
22
+ ```python
23
+ from djeli import Djeli
24
+
25
+ client = Djeli()
26
+ answer = client.chat(
27
+ model="qwen2.5-1.5b-instruct-q4_k_m",
28
+ messages=[{"role": "user", "content": "What is the capital of Kenya?"}],
29
+ )
30
+ print(answer)
31
+ ```
32
+
33
+ Requires a djeli serve process running on 127.0.0.1:11435.
34
+
35
+ ## API
36
+
37
+ . Djeli(base_url="http://127.0.0.1:11435", timeout=300.0)
38
+
39
+ . client.models() -> list[dict]
40
+
41
+ . client.chat(model, messages, temperature=0.7, max_tokens=1024, stream=False)
42
+
43
+ . DjeliError
44
+
45
+ ## License
46
+
47
+ ### MIT
48
+
@@ -0,0 +1,6 @@
1
+ djeli/__init__.py,sha256=piHAViyOIBBXM6O0CCc0zc5diIA-GOSKKoyGBrvomi8,71
2
+ djeli/client.py,sha256=o-sn9fiyp7ZV55TFkj_RCVUA0pFd14Ymhwht50X0owk,2101
3
+ djeli-0.1.0.dist-info/METADATA,sha256=kDw96V3L3UzCX7mEvaZFY_X0NHyK8XBAi0u8yuWGHRw,810
4
+ djeli-0.1.0.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
5
+ djeli-0.1.0.dist-info/top_level.txt,sha256=peDWrzPbS0Mbci30qVtICpHzKxEjh1tPpXhB7n_nguI,6
6
+ djeli-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (84.2.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1 @@
1
+ djeli