latentkit 0.1.1__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.
- latentkit/__init__.py +5 -0
- latentkit/_exceptions.py +52 -0
- latentkit/_stream.py +53 -0
- latentkit/_transport.py +113 -0
- latentkit/client.py +107 -0
- latentkit/resources/__init__.py +35 -0
- latentkit/resources/agents.py +86 -0
- latentkit/resources/audio.py +133 -0
- latentkit/resources/chat.py +102 -0
- latentkit/resources/completions.py +110 -0
- latentkit/resources/embeddings.py +61 -0
- latentkit/resources/image.py +69 -0
- latentkit/resources/queue.py +35 -0
- latentkit/resources/speech.py +61 -0
- latentkit/resources/video.py +57 -0
- latentkit/resources/vision.py +126 -0
- latentkit/types.py +16 -0
- latentkit-0.1.1.dist-info/METADATA +146 -0
- latentkit-0.1.1.dist-info/RECORD +20 -0
- latentkit-0.1.1.dist-info/WHEEL +4 -0
latentkit/__init__.py
ADDED
latentkit/_exceptions.py
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class LatentKitError(Exception):
|
|
7
|
+
"""Base exception for the Python SDK."""
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class LatentKitAPIError(LatentKitError):
|
|
11
|
+
"""Raised when the LatentKit API returns a non-2xx response."""
|
|
12
|
+
|
|
13
|
+
def __init__(self, status_code: int, body: Any) -> None:
|
|
14
|
+
self.status_code = status_code
|
|
15
|
+
self.body = body
|
|
16
|
+
self.code = _extract_code(body)
|
|
17
|
+
message = _extract_message(body)
|
|
18
|
+
if message:
|
|
19
|
+
super().__init__(f"LatentKit API error {status_code}: {message}")
|
|
20
|
+
else:
|
|
21
|
+
super().__init__(f"LatentKit API error {status_code}: {body!r}")
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _extract_message(body: Any) -> str | None:
|
|
25
|
+
if isinstance(body, str):
|
|
26
|
+
return body or None
|
|
27
|
+
if not isinstance(body, dict):
|
|
28
|
+
return None
|
|
29
|
+
for key in ("message", "detail", "error"):
|
|
30
|
+
value = body.get(key)
|
|
31
|
+
if isinstance(value, str) and value:
|
|
32
|
+
return value
|
|
33
|
+
nested = body.get("error")
|
|
34
|
+
if isinstance(nested, dict):
|
|
35
|
+
value = nested.get("message")
|
|
36
|
+
if isinstance(value, str) and value:
|
|
37
|
+
return value
|
|
38
|
+
return None
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _extract_code(body: Any) -> str | None:
|
|
42
|
+
if not isinstance(body, dict):
|
|
43
|
+
return None
|
|
44
|
+
value = body.get("code")
|
|
45
|
+
if isinstance(value, str) and value:
|
|
46
|
+
return value
|
|
47
|
+
nested = body.get("error")
|
|
48
|
+
if isinstance(nested, dict):
|
|
49
|
+
value = nested.get("code")
|
|
50
|
+
if isinstance(value, str) and value:
|
|
51
|
+
return value
|
|
52
|
+
return None
|
latentkit/_stream.py
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from collections.abc import AsyncIterator, Iterator
|
|
5
|
+
|
|
6
|
+
import httpx
|
|
7
|
+
|
|
8
|
+
from latentkit.types import StreamEvent
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def iter_sse_events(response: httpx.Response) -> Iterator[StreamEvent]:
|
|
12
|
+
buffer: list[str] = []
|
|
13
|
+
for line in response.iter_lines():
|
|
14
|
+
if line == "":
|
|
15
|
+
if buffer:
|
|
16
|
+
yield _parse_sse_event(buffer)
|
|
17
|
+
buffer = []
|
|
18
|
+
continue
|
|
19
|
+
buffer.append(line)
|
|
20
|
+
if buffer:
|
|
21
|
+
yield _parse_sse_event(buffer)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
async def aiter_sse_events(response: httpx.Response) -> AsyncIterator[StreamEvent]:
|
|
25
|
+
buffer: list[str] = []
|
|
26
|
+
async for line in response.aiter_lines():
|
|
27
|
+
if line == "":
|
|
28
|
+
if buffer:
|
|
29
|
+
yield _parse_sse_event(buffer)
|
|
30
|
+
buffer = []
|
|
31
|
+
continue
|
|
32
|
+
buffer.append(line)
|
|
33
|
+
if buffer:
|
|
34
|
+
yield _parse_sse_event(buffer)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _parse_sse_event(lines: list[str]) -> StreamEvent:
|
|
38
|
+
event_name: str | None = None
|
|
39
|
+
data_lines: list[str] = []
|
|
40
|
+
for raw_line in lines:
|
|
41
|
+
if raw_line.startswith("event:"):
|
|
42
|
+
event_name = raw_line.partition(":")[2].strip() or None
|
|
43
|
+
continue
|
|
44
|
+
if raw_line.startswith("data:"):
|
|
45
|
+
data_lines.append(raw_line.partition(":")[2].lstrip())
|
|
46
|
+
payload = "\n".join(data_lines)
|
|
47
|
+
if payload == "[DONE]":
|
|
48
|
+
return StreamEvent(data=payload, event=event_name or "done", is_done=True)
|
|
49
|
+
try:
|
|
50
|
+
parsed = json.loads(payload)
|
|
51
|
+
except json.JSONDecodeError:
|
|
52
|
+
parsed = payload
|
|
53
|
+
return StreamEvent(data=parsed, event=event_name)
|
latentkit/_transport.py
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import AsyncIterator, Iterator
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
import httpx
|
|
7
|
+
|
|
8
|
+
from latentkit._exceptions import LatentKitAPIError
|
|
9
|
+
from latentkit._stream import aiter_sse_events, iter_sse_events
|
|
10
|
+
from latentkit.types import JSONDict, StreamEvent
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def normalize_base_url(base_url: str) -> str:
|
|
14
|
+
raw = base_url.rstrip("/")
|
|
15
|
+
return raw if raw.endswith("/v1") else f"{raw}/v1"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def build_headers(api_key: str, extra_headers: dict[str, str] | None = None) -> dict[str, str]:
|
|
19
|
+
headers = {
|
|
20
|
+
"Authorization": f"Bearer {api_key}",
|
|
21
|
+
"Content-Type": "application/json",
|
|
22
|
+
}
|
|
23
|
+
if extra_headers:
|
|
24
|
+
headers.update(extra_headers)
|
|
25
|
+
return headers
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def request_json(
|
|
29
|
+
client: httpx.Client,
|
|
30
|
+
*,
|
|
31
|
+
method: str,
|
|
32
|
+
url: str,
|
|
33
|
+
headers: dict[str, str],
|
|
34
|
+
body: JSONDict | None = None,
|
|
35
|
+
) -> JSONDict:
|
|
36
|
+
request_kwargs: dict[str, Any] = {"headers": headers}
|
|
37
|
+
if body is not None:
|
|
38
|
+
request_kwargs["json"] = body
|
|
39
|
+
response = client.request(method, url, **request_kwargs)
|
|
40
|
+
return _decode_json_response(response)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
async def arequest_json(
|
|
44
|
+
client: httpx.AsyncClient,
|
|
45
|
+
*,
|
|
46
|
+
method: str,
|
|
47
|
+
url: str,
|
|
48
|
+
headers: dict[str, str],
|
|
49
|
+
body: JSONDict | None = None,
|
|
50
|
+
) -> JSONDict:
|
|
51
|
+
request_kwargs: dict[str, Any] = {"headers": headers}
|
|
52
|
+
if body is not None:
|
|
53
|
+
request_kwargs["json"] = body
|
|
54
|
+
response = await client.request(method, url, **request_kwargs)
|
|
55
|
+
return _decode_json_response(response)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def stream_events(
|
|
59
|
+
client: httpx.Client,
|
|
60
|
+
*,
|
|
61
|
+
method: str,
|
|
62
|
+
url: str,
|
|
63
|
+
headers: dict[str, str],
|
|
64
|
+
body: JSONDict | None = None,
|
|
65
|
+
) -> Iterator[StreamEvent]:
|
|
66
|
+
def generator() -> Iterator[StreamEvent]:
|
|
67
|
+
request_kwargs: dict[str, Any] = {"headers": {**headers, "Accept": "text/event-stream"}}
|
|
68
|
+
if body is not None:
|
|
69
|
+
request_kwargs["json"] = body
|
|
70
|
+
with client.stream(method, url, **request_kwargs) as response:
|
|
71
|
+
_ensure_success(response)
|
|
72
|
+
yield from iter_sse_events(response)
|
|
73
|
+
|
|
74
|
+
return generator()
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def astream_events(
|
|
78
|
+
client: httpx.AsyncClient,
|
|
79
|
+
*,
|
|
80
|
+
method: str,
|
|
81
|
+
url: str,
|
|
82
|
+
headers: dict[str, str],
|
|
83
|
+
body: JSONDict | None = None,
|
|
84
|
+
) -> AsyncIterator[StreamEvent]:
|
|
85
|
+
async def generator() -> AsyncIterator[StreamEvent]:
|
|
86
|
+
request_kwargs: dict[str, Any] = {"headers": {**headers, "Accept": "text/event-stream"}}
|
|
87
|
+
if body is not None:
|
|
88
|
+
request_kwargs["json"] = body
|
|
89
|
+
async with client.stream(method, url, **request_kwargs) as response:
|
|
90
|
+
_ensure_success(response)
|
|
91
|
+
async for event in aiter_sse_events(response):
|
|
92
|
+
yield event
|
|
93
|
+
|
|
94
|
+
return generator()
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def _decode_json_response(response: httpx.Response) -> JSONDict:
|
|
98
|
+
_ensure_success(response)
|
|
99
|
+
payload = response.json()
|
|
100
|
+
if not isinstance(payload, dict):
|
|
101
|
+
raise LatentKitAPIError(response.status_code, payload)
|
|
102
|
+
return payload
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def _ensure_success(response: httpx.Response) -> None:
|
|
106
|
+
if response.is_success:
|
|
107
|
+
return
|
|
108
|
+
body: Any
|
|
109
|
+
try:
|
|
110
|
+
body = response.json()
|
|
111
|
+
except Exception:
|
|
112
|
+
body = response.text
|
|
113
|
+
raise LatentKitAPIError(response.status_code, body)
|
latentkit/client.py
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
import httpx
|
|
6
|
+
|
|
7
|
+
from latentkit._transport import arequest_json, astream_events, build_headers, normalize_base_url, request_json, stream_events
|
|
8
|
+
from latentkit.resources.agents import AgentsResource, AsyncAgentsResource
|
|
9
|
+
from latentkit.resources.audio import AsyncTranscriptionResource, AsyncTranslationResource, TranscriptionResource, TranslationResource
|
|
10
|
+
from latentkit.resources.chat import AsyncChatResource, ChatResource
|
|
11
|
+
from latentkit.resources.completions import AsyncCompletionsResource, CompletionsResource
|
|
12
|
+
from latentkit.resources.embeddings import AsyncEmbeddingsResource, EmbeddingsResource
|
|
13
|
+
from latentkit.resources.image import AsyncImageResource, ImageResource
|
|
14
|
+
from latentkit.resources.queue import AsyncQueueResource, QueueResource
|
|
15
|
+
from latentkit.resources.speech import AsyncSpeechResource, SpeechResource
|
|
16
|
+
from latentkit.resources.video import AsyncVideoResource, VideoResource
|
|
17
|
+
from latentkit.resources.vision import AsyncVisionResource, VisionResource
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class LatentKit:
|
|
21
|
+
"""Synchronous Python client for LatentKit's canonical `/v1` API."""
|
|
22
|
+
|
|
23
|
+
def __init__(
|
|
24
|
+
self,
|
|
25
|
+
*,
|
|
26
|
+
api_key: str,
|
|
27
|
+
base_url: str = "https://ai.latentkit.com",
|
|
28
|
+
timeout: float = 120.0,
|
|
29
|
+
headers: dict[str, str] | None = None,
|
|
30
|
+
http_client: httpx.Client | None = None,
|
|
31
|
+
) -> None:
|
|
32
|
+
self._base_v1 = normalize_base_url(base_url)
|
|
33
|
+
self._headers = build_headers(api_key, headers)
|
|
34
|
+
self._owns_client = http_client is None
|
|
35
|
+
self._http = http_client or httpx.Client(timeout=timeout)
|
|
36
|
+
self.chat = ChatResource(self._request_json, self._stream_events, self._base_v1)
|
|
37
|
+
self.completions = CompletionsResource(self._request_json, self._stream_events, self._base_v1)
|
|
38
|
+
self.embeddings = EmbeddingsResource(self._request_json, self._base_v1)
|
|
39
|
+
self.image = ImageResource(self._request_json, self._base_v1)
|
|
40
|
+
self.speech = SpeechResource(self._request_json, self._base_v1)
|
|
41
|
+
self.transcription = TranscriptionResource(self._request_json, self._base_v1)
|
|
42
|
+
self.translation = TranslationResource(self._request_json, self._base_v1)
|
|
43
|
+
self.video = VideoResource(self._request_json, self._base_v1)
|
|
44
|
+
self.vision = VisionResource(self._request_json, self._stream_events, self._base_v1)
|
|
45
|
+
self.queue = QueueResource(self._request_json, self._base_v1)
|
|
46
|
+
self.agents = AgentsResource(self._request_json, self._stream_events, self._base_v1)
|
|
47
|
+
|
|
48
|
+
def _request_json(self, method: str, url: str, body: dict[str, Any] | None) -> dict[str, Any]:
|
|
49
|
+
return request_json(self._http, method=method, url=url, headers=self._headers, body=body)
|
|
50
|
+
|
|
51
|
+
def _stream_events(self, method: str, url: str, body: dict[str, Any] | None):
|
|
52
|
+
return stream_events(self._http, method=method, url=url, headers=self._headers, body=body)
|
|
53
|
+
|
|
54
|
+
def close(self) -> None:
|
|
55
|
+
if self._owns_client:
|
|
56
|
+
self._http.close()
|
|
57
|
+
|
|
58
|
+
def __enter__(self) -> LatentKit:
|
|
59
|
+
return self
|
|
60
|
+
|
|
61
|
+
def __exit__(self, *_exc: object) -> None:
|
|
62
|
+
self.close()
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class AsyncLatentKit:
|
|
66
|
+
"""Async Python client for LatentKit's canonical `/v1` API."""
|
|
67
|
+
|
|
68
|
+
def __init__(
|
|
69
|
+
self,
|
|
70
|
+
*,
|
|
71
|
+
api_key: str,
|
|
72
|
+
base_url: str = "https://ai.latentkit.com",
|
|
73
|
+
timeout: float = 120.0,
|
|
74
|
+
headers: dict[str, str] | None = None,
|
|
75
|
+
http_client: httpx.AsyncClient | None = None,
|
|
76
|
+
) -> None:
|
|
77
|
+
self._base_v1 = normalize_base_url(base_url)
|
|
78
|
+
self._headers = build_headers(api_key, headers)
|
|
79
|
+
self._owns_client = http_client is None
|
|
80
|
+
self._http = http_client or httpx.AsyncClient(timeout=timeout)
|
|
81
|
+
self.chat = AsyncChatResource(self._request_json, self._stream_events, self._base_v1)
|
|
82
|
+
self.completions = AsyncCompletionsResource(self._request_json, self._stream_events, self._base_v1)
|
|
83
|
+
self.embeddings = AsyncEmbeddingsResource(self._request_json, self._base_v1)
|
|
84
|
+
self.image = AsyncImageResource(self._request_json, self._base_v1)
|
|
85
|
+
self.speech = AsyncSpeechResource(self._request_json, self._base_v1)
|
|
86
|
+
self.transcription = AsyncTranscriptionResource(self._request_json, self._base_v1)
|
|
87
|
+
self.translation = AsyncTranslationResource(self._request_json, self._base_v1)
|
|
88
|
+
self.video = AsyncVideoResource(self._request_json, self._base_v1)
|
|
89
|
+
self.vision = AsyncVisionResource(self._request_json, self._stream_events, self._base_v1)
|
|
90
|
+
self.queue = AsyncQueueResource(self._request_json, self._base_v1)
|
|
91
|
+
self.agents = AsyncAgentsResource(self._request_json, self._stream_events, self._base_v1)
|
|
92
|
+
|
|
93
|
+
async def _request_json(self, method: str, url: str, body: dict[str, Any] | None) -> dict[str, Any]:
|
|
94
|
+
return await arequest_json(self._http, method=method, url=url, headers=self._headers, body=body)
|
|
95
|
+
|
|
96
|
+
def _stream_events(self, method: str, url: str, body: dict[str, Any] | None):
|
|
97
|
+
return astream_events(self._http, method=method, url=url, headers=self._headers, body=body)
|
|
98
|
+
|
|
99
|
+
async def close(self) -> None:
|
|
100
|
+
if self._owns_client:
|
|
101
|
+
await self._http.aclose()
|
|
102
|
+
|
|
103
|
+
async def __aenter__(self) -> AsyncLatentKit:
|
|
104
|
+
return self
|
|
105
|
+
|
|
106
|
+
async def __aexit__(self, *_exc: object) -> None:
|
|
107
|
+
await self.close()
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from latentkit.resources.agents import AgentsResource, AsyncAgentsResource
|
|
2
|
+
from latentkit.resources.audio import AsyncTranscriptionResource, AsyncTranslationResource, TranscriptionResource, TranslationResource
|
|
3
|
+
from latentkit.resources.chat import AsyncChatResource, ChatResource
|
|
4
|
+
from latentkit.resources.completions import AsyncCompletionsResource, CompletionsResource
|
|
5
|
+
from latentkit.resources.embeddings import AsyncEmbeddingsResource, EmbeddingsResource
|
|
6
|
+
from latentkit.resources.image import AsyncImageResource, ImageResource
|
|
7
|
+
from latentkit.resources.queue import AsyncQueueResource, QueueResource
|
|
8
|
+
from latentkit.resources.speech import AsyncSpeechResource, SpeechResource
|
|
9
|
+
from latentkit.resources.video import AsyncVideoResource, VideoResource
|
|
10
|
+
from latentkit.resources.vision import AsyncVisionResource, VisionResource
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"AgentsResource",
|
|
14
|
+
"AsyncAgentsResource",
|
|
15
|
+
"AsyncChatResource",
|
|
16
|
+
"AsyncCompletionsResource",
|
|
17
|
+
"AsyncEmbeddingsResource",
|
|
18
|
+
"AsyncImageResource",
|
|
19
|
+
"AsyncQueueResource",
|
|
20
|
+
"AsyncSpeechResource",
|
|
21
|
+
"AsyncTranscriptionResource",
|
|
22
|
+
"AsyncTranslationResource",
|
|
23
|
+
"AsyncVideoResource",
|
|
24
|
+
"AsyncVisionResource",
|
|
25
|
+
"ChatResource",
|
|
26
|
+
"CompletionsResource",
|
|
27
|
+
"EmbeddingsResource",
|
|
28
|
+
"ImageResource",
|
|
29
|
+
"QueueResource",
|
|
30
|
+
"SpeechResource",
|
|
31
|
+
"TranscriptionResource",
|
|
32
|
+
"TranslationResource",
|
|
33
|
+
"VideoResource",
|
|
34
|
+
"VisionResource",
|
|
35
|
+
]
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import AsyncIterator, Iterator
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
from latentkit.types import JSONDict, StreamEvent
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class AgentSessionsResource:
|
|
10
|
+
def __init__(self, request_json: Any, stream_events: Any, base_v1: str) -> None:
|
|
11
|
+
self._request_json = request_json
|
|
12
|
+
self._stream_events = stream_events
|
|
13
|
+
self._base = f"{base_v1}/agent/sessions"
|
|
14
|
+
|
|
15
|
+
def create(self, **payload: Any) -> JSONDict:
|
|
16
|
+
return self._request_json("POST", self._base, payload)
|
|
17
|
+
|
|
18
|
+
def run(self, session_id: str, *, stream: bool = False) -> JSONDict:
|
|
19
|
+
return self._request_json("POST", f"{self._base}/{session_id}/run", {"stream": stream})
|
|
20
|
+
|
|
21
|
+
def run_stream(self, session_id: str) -> Iterator[StreamEvent]:
|
|
22
|
+
return self._stream_events("POST", f"{self._base}/{session_id}/run", {"stream": True})
|
|
23
|
+
|
|
24
|
+
def input(self, session_id: str, *, message: str, policy_id: str | None = None) -> JSONDict:
|
|
25
|
+
return self._request_json(
|
|
26
|
+
"POST",
|
|
27
|
+
f"{self._base}/{session_id}/input",
|
|
28
|
+
{"message": message, "policy_id": policy_id},
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
def cancel(self, session_id: str) -> JSONDict:
|
|
32
|
+
return self._request_json("POST", f"{self._base}/{session_id}/cancel", None)
|
|
33
|
+
|
|
34
|
+
def retrieve(self, session_id: str) -> JSONDict:
|
|
35
|
+
return self._request_json("GET", f"{self._base}/{session_id}", None)
|
|
36
|
+
|
|
37
|
+
def steps(self, session_id: str) -> JSONDict:
|
|
38
|
+
return self._request_json("GET", f"{self._base}/{session_id}/steps", None)
|
|
39
|
+
|
|
40
|
+
def stream(self, session_id: str) -> Iterator[StreamEvent]:
|
|
41
|
+
return self._stream_events("GET", f"{self._base}/{session_id}/stream", None)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class AsyncAgentSessionsResource:
|
|
45
|
+
def __init__(self, request_json: Any, stream_events: Any, base_v1: str) -> None:
|
|
46
|
+
self._request_json = request_json
|
|
47
|
+
self._stream_events = stream_events
|
|
48
|
+
self._base = f"{base_v1}/agent/sessions"
|
|
49
|
+
|
|
50
|
+
async def create(self, **payload: Any) -> JSONDict:
|
|
51
|
+
return await self._request_json("POST", self._base, payload)
|
|
52
|
+
|
|
53
|
+
async def run(self, session_id: str, *, stream: bool = False) -> JSONDict:
|
|
54
|
+
return await self._request_json("POST", f"{self._base}/{session_id}/run", {"stream": stream})
|
|
55
|
+
|
|
56
|
+
def run_stream(self, session_id: str) -> AsyncIterator[StreamEvent]:
|
|
57
|
+
return self._stream_events("POST", f"{self._base}/{session_id}/run", {"stream": True})
|
|
58
|
+
|
|
59
|
+
async def input(self, session_id: str, *, message: str, policy_id: str | None = None) -> JSONDict:
|
|
60
|
+
return await self._request_json(
|
|
61
|
+
"POST",
|
|
62
|
+
f"{self._base}/{session_id}/input",
|
|
63
|
+
{"message": message, "policy_id": policy_id},
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
async def cancel(self, session_id: str) -> JSONDict:
|
|
67
|
+
return await self._request_json("POST", f"{self._base}/{session_id}/cancel", None)
|
|
68
|
+
|
|
69
|
+
async def retrieve(self, session_id: str) -> JSONDict:
|
|
70
|
+
return await self._request_json("GET", f"{self._base}/{session_id}", None)
|
|
71
|
+
|
|
72
|
+
async def steps(self, session_id: str) -> JSONDict:
|
|
73
|
+
return await self._request_json("GET", f"{self._base}/{session_id}/steps", None)
|
|
74
|
+
|
|
75
|
+
def stream(self, session_id: str) -> AsyncIterator[StreamEvent]:
|
|
76
|
+
return self._stream_events("GET", f"{self._base}/{session_id}/stream", None)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class AgentsResource:
|
|
80
|
+
def __init__(self, request_json: Any, stream_events: Any, base_v1: str) -> None:
|
|
81
|
+
self.sessions = AgentSessionsResource(request_json, stream_events, base_v1)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class AsyncAgentsResource:
|
|
85
|
+
def __init__(self, request_json: Any, stream_events: Any, base_v1: str) -> None:
|
|
86
|
+
self.sessions = AsyncAgentSessionsResource(request_json, stream_events, base_v1)
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from latentkit.types import JSONDict
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class TranscriptionResource:
|
|
9
|
+
def __init__(self, request_json: Any, base_v1: str) -> None:
|
|
10
|
+
self._request_json = request_json
|
|
11
|
+
self._url = f"{base_v1}/transcription"
|
|
12
|
+
|
|
13
|
+
def create(
|
|
14
|
+
self,
|
|
15
|
+
*,
|
|
16
|
+
audio: JSONDict | None = None,
|
|
17
|
+
input: Any = None,
|
|
18
|
+
language: str | None = None,
|
|
19
|
+
prompt: str | None = None,
|
|
20
|
+
response_format: str | None = None,
|
|
21
|
+
temperature: float | None = None,
|
|
22
|
+
response_profile: str | None = None,
|
|
23
|
+
extra_body: JSONDict | None = None,
|
|
24
|
+
) -> JSONDict:
|
|
25
|
+
body: JSONDict = {
|
|
26
|
+
"audio": audio,
|
|
27
|
+
"input": input,
|
|
28
|
+
"language": language,
|
|
29
|
+
"prompt": prompt,
|
|
30
|
+
"response_format": response_format,
|
|
31
|
+
"temperature": temperature,
|
|
32
|
+
}
|
|
33
|
+
if response_profile:
|
|
34
|
+
body["response_profile"] = response_profile
|
|
35
|
+
if extra_body:
|
|
36
|
+
body.update(extra_body)
|
|
37
|
+
return self._request_json("POST", self._url, body)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class AsyncTranscriptionResource:
|
|
41
|
+
def __init__(self, request_json: Any, base_v1: str) -> None:
|
|
42
|
+
self._request_json = request_json
|
|
43
|
+
self._url = f"{base_v1}/transcription"
|
|
44
|
+
|
|
45
|
+
async def create(
|
|
46
|
+
self,
|
|
47
|
+
*,
|
|
48
|
+
audio: JSONDict | None = None,
|
|
49
|
+
input: Any = None,
|
|
50
|
+
language: str | None = None,
|
|
51
|
+
prompt: str | None = None,
|
|
52
|
+
response_format: str | None = None,
|
|
53
|
+
temperature: float | None = None,
|
|
54
|
+
response_profile: str | None = None,
|
|
55
|
+
extra_body: JSONDict | None = None,
|
|
56
|
+
) -> JSONDict:
|
|
57
|
+
body: JSONDict = {
|
|
58
|
+
"audio": audio,
|
|
59
|
+
"input": input,
|
|
60
|
+
"language": language,
|
|
61
|
+
"prompt": prompt,
|
|
62
|
+
"response_format": response_format,
|
|
63
|
+
"temperature": temperature,
|
|
64
|
+
}
|
|
65
|
+
if response_profile:
|
|
66
|
+
body["response_profile"] = response_profile
|
|
67
|
+
if extra_body:
|
|
68
|
+
body.update(extra_body)
|
|
69
|
+
return await self._request_json("POST", self._url, body)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class TranslationResource:
|
|
73
|
+
def __init__(self, request_json: Any, base_v1: str) -> None:
|
|
74
|
+
self._request_json = request_json
|
|
75
|
+
self._url = f"{base_v1}/translation"
|
|
76
|
+
|
|
77
|
+
def create(
|
|
78
|
+
self,
|
|
79
|
+
*,
|
|
80
|
+
audio: JSONDict | None = None,
|
|
81
|
+
input: Any = None,
|
|
82
|
+
target_language: str | None = None,
|
|
83
|
+
prompt: str | None = None,
|
|
84
|
+
response_format: str | None = None,
|
|
85
|
+
temperature: float | None = None,
|
|
86
|
+
response_profile: str | None = None,
|
|
87
|
+
extra_body: JSONDict | None = None,
|
|
88
|
+
) -> JSONDict:
|
|
89
|
+
body: JSONDict = {
|
|
90
|
+
"audio": audio,
|
|
91
|
+
"input": input,
|
|
92
|
+
"target_language": target_language,
|
|
93
|
+
"prompt": prompt,
|
|
94
|
+
"response_format": response_format,
|
|
95
|
+
"temperature": temperature,
|
|
96
|
+
}
|
|
97
|
+
if response_profile:
|
|
98
|
+
body["response_profile"] = response_profile
|
|
99
|
+
if extra_body:
|
|
100
|
+
body.update(extra_body)
|
|
101
|
+
return self._request_json("POST", self._url, body)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
class AsyncTranslationResource:
|
|
105
|
+
def __init__(self, request_json: Any, base_v1: str) -> None:
|
|
106
|
+
self._request_json = request_json
|
|
107
|
+
self._url = f"{base_v1}/translation"
|
|
108
|
+
|
|
109
|
+
async def create(
|
|
110
|
+
self,
|
|
111
|
+
*,
|
|
112
|
+
audio: JSONDict | None = None,
|
|
113
|
+
input: Any = None,
|
|
114
|
+
target_language: str | None = None,
|
|
115
|
+
prompt: str | None = None,
|
|
116
|
+
response_format: str | None = None,
|
|
117
|
+
temperature: float | None = None,
|
|
118
|
+
response_profile: str | None = None,
|
|
119
|
+
extra_body: JSONDict | None = None,
|
|
120
|
+
) -> JSONDict:
|
|
121
|
+
body: JSONDict = {
|
|
122
|
+
"audio": audio,
|
|
123
|
+
"input": input,
|
|
124
|
+
"target_language": target_language,
|
|
125
|
+
"prompt": prompt,
|
|
126
|
+
"response_format": response_format,
|
|
127
|
+
"temperature": temperature,
|
|
128
|
+
}
|
|
129
|
+
if response_profile:
|
|
130
|
+
body["response_profile"] = response_profile
|
|
131
|
+
if extra_body:
|
|
132
|
+
body.update(extra_body)
|
|
133
|
+
return await self._request_json("POST", self._url, body)
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import AsyncIterator, Iterator
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
from latentkit.types import JSONDict, StreamEvent
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ChatResource:
|
|
10
|
+
def __init__(self, request_json: Any, stream_events: Any, base_v1: str) -> None:
|
|
11
|
+
self._request_json = request_json
|
|
12
|
+
self._stream_events = stream_events
|
|
13
|
+
self._url = f"{base_v1}/chat"
|
|
14
|
+
|
|
15
|
+
def create(
|
|
16
|
+
self,
|
|
17
|
+
*,
|
|
18
|
+
messages: list[dict[str, Any]],
|
|
19
|
+
max_tokens: int = 1000,
|
|
20
|
+
temperature: float = 0.7,
|
|
21
|
+
response_profile: str | None = None,
|
|
22
|
+
extra_body: JSONDict | None = None,
|
|
23
|
+
) -> JSONDict:
|
|
24
|
+
body: JSONDict = {
|
|
25
|
+
"messages": messages,
|
|
26
|
+
"max_tokens": max_tokens,
|
|
27
|
+
"temperature": temperature,
|
|
28
|
+
}
|
|
29
|
+
if response_profile:
|
|
30
|
+
body["response_profile"] = response_profile
|
|
31
|
+
if extra_body:
|
|
32
|
+
body.update(extra_body)
|
|
33
|
+
return self._request_json("POST", self._url, body)
|
|
34
|
+
|
|
35
|
+
def stream(
|
|
36
|
+
self,
|
|
37
|
+
*,
|
|
38
|
+
messages: list[dict[str, Any]],
|
|
39
|
+
max_tokens: int = 1000,
|
|
40
|
+
temperature: float = 0.7,
|
|
41
|
+
response_profile: str | None = None,
|
|
42
|
+
extra_body: JSONDict | None = None,
|
|
43
|
+
) -> Iterator[StreamEvent]:
|
|
44
|
+
body: JSONDict = {
|
|
45
|
+
"messages": messages,
|
|
46
|
+
"max_tokens": max_tokens,
|
|
47
|
+
"temperature": temperature,
|
|
48
|
+
"stream": True,
|
|
49
|
+
}
|
|
50
|
+
if response_profile:
|
|
51
|
+
body["response_profile"] = response_profile
|
|
52
|
+
if extra_body:
|
|
53
|
+
body.update(extra_body)
|
|
54
|
+
return self._stream_events("POST", self._url, body)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class AsyncChatResource:
|
|
58
|
+
def __init__(self, request_json: Any, stream_events: Any, base_v1: str) -> None:
|
|
59
|
+
self._request_json = request_json
|
|
60
|
+
self._stream_events = stream_events
|
|
61
|
+
self._url = f"{base_v1}/chat"
|
|
62
|
+
|
|
63
|
+
async def create(
|
|
64
|
+
self,
|
|
65
|
+
*,
|
|
66
|
+
messages: list[dict[str, Any]],
|
|
67
|
+
max_tokens: int = 1000,
|
|
68
|
+
temperature: float = 0.7,
|
|
69
|
+
response_profile: str | None = None,
|
|
70
|
+
extra_body: JSONDict | None = None,
|
|
71
|
+
) -> JSONDict:
|
|
72
|
+
body: JSONDict = {
|
|
73
|
+
"messages": messages,
|
|
74
|
+
"max_tokens": max_tokens,
|
|
75
|
+
"temperature": temperature,
|
|
76
|
+
}
|
|
77
|
+
if response_profile:
|
|
78
|
+
body["response_profile"] = response_profile
|
|
79
|
+
if extra_body:
|
|
80
|
+
body.update(extra_body)
|
|
81
|
+
return await self._request_json("POST", self._url, body)
|
|
82
|
+
|
|
83
|
+
def stream(
|
|
84
|
+
self,
|
|
85
|
+
*,
|
|
86
|
+
messages: list[dict[str, Any]],
|
|
87
|
+
max_tokens: int = 1000,
|
|
88
|
+
temperature: float = 0.7,
|
|
89
|
+
response_profile: str | None = None,
|
|
90
|
+
extra_body: JSONDict | None = None,
|
|
91
|
+
) -> AsyncIterator[StreamEvent]:
|
|
92
|
+
body: JSONDict = {
|
|
93
|
+
"messages": messages,
|
|
94
|
+
"max_tokens": max_tokens,
|
|
95
|
+
"temperature": temperature,
|
|
96
|
+
"stream": True,
|
|
97
|
+
}
|
|
98
|
+
if response_profile:
|
|
99
|
+
body["response_profile"] = response_profile
|
|
100
|
+
if extra_body:
|
|
101
|
+
body.update(extra_body)
|
|
102
|
+
return self._stream_events("POST", self._url, body)
|