embed-client 0.0.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.
- embed_client/__init__.py +1 -0
- embed_client/async_client.py +180 -0
- embed_client/example_async_usage.py +94 -0
- embed_client/example_async_usage_ru.py +94 -0
- embed_client-0.0.1.dist-info/METADATA +9 -0
- embed_client-0.0.1.dist-info/RECORD +8 -0
- embed_client-0.0.1.dist-info/WHEEL +5 -0
- embed_client-0.0.1.dist-info/top_level.txt +1 -0
embed_client/__init__.py
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
|
@@ -0,0 +1,180 @@
|
|
1
|
+
"""
|
2
|
+
Async client for Embedding Service API (OpenAPI 3.0.2)
|
3
|
+
|
4
|
+
- 100% type-annotated
|
5
|
+
- English docstrings and examples
|
6
|
+
- Ready for PyPi
|
7
|
+
"""
|
8
|
+
|
9
|
+
from typing import Any, Dict, List, Optional, Union
|
10
|
+
import aiohttp
|
11
|
+
|
12
|
+
class EmbeddingServiceError(Exception):
|
13
|
+
"""Base exception for EmbeddingServiceAsyncClient."""
|
14
|
+
|
15
|
+
class EmbeddingServiceConnectionError(EmbeddingServiceError):
|
16
|
+
"""Raised when the service is unavailable or connection fails."""
|
17
|
+
|
18
|
+
class EmbeddingServiceHTTPError(EmbeddingServiceError):
|
19
|
+
"""Raised for HTTP errors (4xx, 5xx)."""
|
20
|
+
def __init__(self, status: int, message: str):
|
21
|
+
super().__init__(f"HTTP {status}: {message}")
|
22
|
+
self.status = status
|
23
|
+
self.message = message
|
24
|
+
|
25
|
+
class EmbeddingServiceAPIError(EmbeddingServiceError):
|
26
|
+
"""Raised for errors returned by the API in the response body."""
|
27
|
+
def __init__(self, error: Any):
|
28
|
+
super().__init__(f"API error: {error}")
|
29
|
+
self.error = error
|
30
|
+
|
31
|
+
class EmbeddingServiceAsyncClient:
|
32
|
+
"""
|
33
|
+
Asynchronous client for the Embedding Service API.
|
34
|
+
Args:
|
35
|
+
base_url (str): Base URL of the embedding service (e.g., "http://localhost").
|
36
|
+
port (int): Port of the embedding service (e.g., 8001).
|
37
|
+
Raises:
|
38
|
+
ValueError: If base_url or port is not provided.
|
39
|
+
"""
|
40
|
+
def __init__(self, base_url: str, port: int):
|
41
|
+
if not base_url:
|
42
|
+
raise ValueError("base_url must be provided.")
|
43
|
+
if port is None:
|
44
|
+
raise ValueError("port must be provided.")
|
45
|
+
self.base_url = base_url.rstrip("/")
|
46
|
+
self.port = port
|
47
|
+
self._session: Optional[aiohttp.ClientSession] = None
|
48
|
+
|
49
|
+
def _make_url(self, path: str, base_url: Optional[str] = None, port: Optional[int] = None) -> str:
|
50
|
+
url = (base_url or self.base_url).rstrip("/")
|
51
|
+
port_val = port if port is not None else self.port
|
52
|
+
return f"{url}:{port_val}{path}"
|
53
|
+
|
54
|
+
async def __aenter__(self):
|
55
|
+
self._session = aiohttp.ClientSession()
|
56
|
+
return self
|
57
|
+
|
58
|
+
async def __aexit__(self, exc_type, exc, tb):
|
59
|
+
if self._session:
|
60
|
+
await self._session.close()
|
61
|
+
self._session = None
|
62
|
+
|
63
|
+
async def health(self, base_url: Optional[str] = None, port: Optional[int] = None) -> Dict[str, Any]:
|
64
|
+
"""
|
65
|
+
Check the health of the service.
|
66
|
+
Args:
|
67
|
+
base_url (str, optional): Override base URL.
|
68
|
+
port (int, optional): Override port.
|
69
|
+
Returns:
|
70
|
+
dict: Health status and model info.
|
71
|
+
"""
|
72
|
+
url = self._make_url("/health", base_url, port)
|
73
|
+
try:
|
74
|
+
async with self._session.get(url) as resp:
|
75
|
+
await self._raise_for_status(resp)
|
76
|
+
return await resp.json()
|
77
|
+
except EmbeddingServiceHTTPError:
|
78
|
+
raise
|
79
|
+
except EmbeddingServiceConnectionError:
|
80
|
+
raise
|
81
|
+
except aiohttp.ClientConnectionError as e:
|
82
|
+
raise EmbeddingServiceConnectionError(f"Connection error: {e}") from e
|
83
|
+
except aiohttp.ClientResponseError as e:
|
84
|
+
raise EmbeddingServiceHTTPError(e.status, e.message) from e
|
85
|
+
except Exception as e:
|
86
|
+
raise EmbeddingServiceError(f"Unexpected error: {e}") from e
|
87
|
+
|
88
|
+
async def get_openapi_schema(self, base_url: Optional[str] = None, port: Optional[int] = None) -> Dict[str, Any]:
|
89
|
+
"""
|
90
|
+
Get the OpenAPI schema of the service.
|
91
|
+
Args:
|
92
|
+
base_url (str, optional): Override base URL.
|
93
|
+
port (int, optional): Override port.
|
94
|
+
Returns:
|
95
|
+
dict: OpenAPI schema.
|
96
|
+
"""
|
97
|
+
url = self._make_url("/openapi.json", base_url, port)
|
98
|
+
try:
|
99
|
+
async with self._session.get(url) as resp:
|
100
|
+
await self._raise_for_status(resp)
|
101
|
+
return await resp.json()
|
102
|
+
except EmbeddingServiceHTTPError:
|
103
|
+
raise
|
104
|
+
except EmbeddingServiceConnectionError:
|
105
|
+
raise
|
106
|
+
except aiohttp.ClientConnectionError as e:
|
107
|
+
raise EmbeddingServiceConnectionError(f"Connection error: {e}") from e
|
108
|
+
except aiohttp.ClientResponseError as e:
|
109
|
+
raise EmbeddingServiceHTTPError(e.status, e.message) from e
|
110
|
+
except Exception as e:
|
111
|
+
raise EmbeddingServiceError(f"Unexpected error: {e}") from e
|
112
|
+
|
113
|
+
async def get_commands(self, base_url: Optional[str] = None, port: Optional[int] = None) -> Dict[str, Any]:
|
114
|
+
"""
|
115
|
+
Get the list of available commands.
|
116
|
+
Args:
|
117
|
+
base_url (str, optional): Override base URL.
|
118
|
+
port (int, optional): Override port.
|
119
|
+
Returns:
|
120
|
+
dict: List of commands and their descriptions.
|
121
|
+
"""
|
122
|
+
url = self._make_url("/api/commands", base_url, port)
|
123
|
+
try:
|
124
|
+
async with self._session.get(url) as resp:
|
125
|
+
await self._raise_for_status(resp)
|
126
|
+
return await resp.json()
|
127
|
+
except EmbeddingServiceHTTPError:
|
128
|
+
raise
|
129
|
+
except EmbeddingServiceConnectionError:
|
130
|
+
raise
|
131
|
+
except aiohttp.ClientConnectionError as e:
|
132
|
+
raise EmbeddingServiceConnectionError(f"Connection error: {e}") from e
|
133
|
+
except aiohttp.ClientResponseError as e:
|
134
|
+
raise EmbeddingServiceHTTPError(e.status, e.message) from e
|
135
|
+
except Exception as e:
|
136
|
+
raise EmbeddingServiceError(f"Unexpected error: {e}") from e
|
137
|
+
|
138
|
+
async def cmd(self, command: str, params: Optional[Dict[str, Any]] = None, base_url: Optional[str] = None, port: Optional[int] = None) -> Dict[str, Any]:
|
139
|
+
"""
|
140
|
+
Execute a command via JSON-RPC protocol.
|
141
|
+
Args:
|
142
|
+
command (str): Command to execute (embed, models, health, help, config).
|
143
|
+
params (dict, optional): Parameters for the command.
|
144
|
+
base_url (str, optional): Override base URL.
|
145
|
+
port (int, optional): Override port.
|
146
|
+
Returns:
|
147
|
+
dict: Command execution result.
|
148
|
+
"""
|
149
|
+
url = self._make_url("/cmd", base_url, port)
|
150
|
+
payload = {"command": command}
|
151
|
+
if params is not None:
|
152
|
+
payload["params"] = params
|
153
|
+
try:
|
154
|
+
async with self._session.post(url, json=payload) as resp:
|
155
|
+
await self._raise_for_status(resp)
|
156
|
+
data = await resp.json()
|
157
|
+
# Обработка ошибок, возвращаемых сервером в теле ответа
|
158
|
+
if "error" in data:
|
159
|
+
raise EmbeddingServiceAPIError(data["error"])
|
160
|
+
return data
|
161
|
+
except EmbeddingServiceAPIError:
|
162
|
+
raise
|
163
|
+
except EmbeddingServiceHTTPError:
|
164
|
+
raise
|
165
|
+
except EmbeddingServiceConnectionError:
|
166
|
+
raise
|
167
|
+
except aiohttp.ClientConnectionError as e:
|
168
|
+
raise EmbeddingServiceConnectionError(f"Connection error: {e}") from e
|
169
|
+
except aiohttp.ClientResponseError as e:
|
170
|
+
raise EmbeddingServiceHTTPError(e.status, e.message) from e
|
171
|
+
except Exception as e:
|
172
|
+
raise EmbeddingServiceError(f"Unexpected error: {e}") from e
|
173
|
+
|
174
|
+
async def _raise_for_status(self, resp: aiohttp.ClientResponse):
|
175
|
+
try:
|
176
|
+
resp.raise_for_status()
|
177
|
+
except aiohttp.ClientResponseError as e:
|
178
|
+
raise EmbeddingServiceHTTPError(e.status, e.message) from e
|
179
|
+
|
180
|
+
# TODO: Add methods for /cmd, /api/commands, etc.
|
@@ -0,0 +1,94 @@
|
|
1
|
+
"""
|
2
|
+
Example usage of EmbeddingServiceAsyncClient.
|
3
|
+
|
4
|
+
This example demonstrates how to use the async client to check the health of the embedding service,
|
5
|
+
request embeddings, and handle all possible exceptions.
|
6
|
+
|
7
|
+
Run this script with:
|
8
|
+
python -m asyncio embed_client/example_async_usage.py --base-url http://localhost --port 8001
|
9
|
+
|
10
|
+
You can also set EMBED_CLIENT_BASE_URL and EMBED_CLIENT_PORT environment variables.
|
11
|
+
"""
|
12
|
+
|
13
|
+
import asyncio
|
14
|
+
import sys
|
15
|
+
import os
|
16
|
+
from embed_client.async_client import (
|
17
|
+
EmbeddingServiceAsyncClient,
|
18
|
+
EmbeddingServiceConnectionError,
|
19
|
+
EmbeddingServiceHTTPError,
|
20
|
+
EmbeddingServiceAPIError,
|
21
|
+
EmbeddingServiceError,
|
22
|
+
)
|
23
|
+
|
24
|
+
def get_params():
|
25
|
+
base_url = None
|
26
|
+
port = None
|
27
|
+
for i, arg in enumerate(sys.argv):
|
28
|
+
if arg in ("--base-url", "-b") and i + 1 < len(sys.argv):
|
29
|
+
base_url = sys.argv[i + 1]
|
30
|
+
if arg in ("--port", "-p") and i + 1 < len(sys.argv):
|
31
|
+
port = sys.argv[i + 1]
|
32
|
+
if not base_url:
|
33
|
+
base_url = os.environ.get("EMBED_CLIENT_BASE_URL")
|
34
|
+
if not port:
|
35
|
+
port = os.environ.get("EMBED_CLIENT_PORT")
|
36
|
+
if not base_url or not port:
|
37
|
+
print("Error: base_url and port must be provided via --base-url/--port arguments or EMBED_CLIENT_BASE_URL/EMBED_CLIENT_PORT environment variables.")
|
38
|
+
sys.exit(1)
|
39
|
+
return None, None
|
40
|
+
return base_url, int(port)
|
41
|
+
|
42
|
+
async def main():
|
43
|
+
base_url, port = get_params()
|
44
|
+
# Always use try/except to handle all possible errors
|
45
|
+
try:
|
46
|
+
async with EmbeddingServiceAsyncClient(base_url=base_url, port=port) as client:
|
47
|
+
# Check health
|
48
|
+
try:
|
49
|
+
health = await client.health()
|
50
|
+
print("Service health:", health)
|
51
|
+
except EmbeddingServiceConnectionError as e:
|
52
|
+
print("[Connection error]", e)
|
53
|
+
return
|
54
|
+
except EmbeddingServiceHTTPError as e:
|
55
|
+
print(f"[HTTP error] {e.status}: {e.message}")
|
56
|
+
return
|
57
|
+
except EmbeddingServiceError as e:
|
58
|
+
print("[Other error]", e)
|
59
|
+
return
|
60
|
+
|
61
|
+
# Request embeddings for a list of texts
|
62
|
+
texts = ["hello world", "test embedding"]
|
63
|
+
try:
|
64
|
+
result = await client.cmd("embed", params={"texts": texts})
|
65
|
+
vectors = result["result"]
|
66
|
+
print(f"Embeddings for {len(texts)} texts:")
|
67
|
+
for i, vec in enumerate(vectors):
|
68
|
+
print(f" Text: {texts[i]!r}\n Vector: {vec[:5]}... (total {len(vec)} dims)")
|
69
|
+
except EmbeddingServiceAPIError as e:
|
70
|
+
print("[API error]", e.error)
|
71
|
+
except EmbeddingServiceHTTPError as e:
|
72
|
+
print(f"[HTTP error] {e.status}: {e.message}")
|
73
|
+
except EmbeddingServiceConnectionError as e:
|
74
|
+
print("[Connection error]", e)
|
75
|
+
except EmbeddingServiceError as e:
|
76
|
+
print("[Other error]", e)
|
77
|
+
|
78
|
+
# Example: error handling for invalid command
|
79
|
+
try:
|
80
|
+
await client.cmd("not_a_command")
|
81
|
+
except EmbeddingServiceAPIError as e:
|
82
|
+
print("[API error for invalid command]", e.error)
|
83
|
+
|
84
|
+
# Example: error handling for empty texts
|
85
|
+
try:
|
86
|
+
await client.cmd("embed", params={"texts": []})
|
87
|
+
except EmbeddingServiceAPIError as e:
|
88
|
+
print("[API error for empty texts]", e.error)
|
89
|
+
|
90
|
+
except Exception as e:
|
91
|
+
print("[Unexpected error]", e)
|
92
|
+
|
93
|
+
if __name__ == "__main__":
|
94
|
+
asyncio.run(main())
|
@@ -0,0 +1,94 @@
|
|
1
|
+
"""
|
2
|
+
Example usage of EmbeddingServiceAsyncClient.
|
3
|
+
|
4
|
+
This example demonstrates how to use the async client to check the health of the embedding service,
|
5
|
+
request embeddings, and handle all possible exceptions.
|
6
|
+
|
7
|
+
Run this script with:
|
8
|
+
python -m asyncio embed_client/example_async_usage_ru.py --base-url http://localhost --port 8001
|
9
|
+
|
10
|
+
You can also set EMBED_CLIENT_BASE_URL and EMBED_CLIENT_PORT environment variables.
|
11
|
+
"""
|
12
|
+
|
13
|
+
import asyncio
|
14
|
+
import sys
|
15
|
+
import os
|
16
|
+
from embed_client.async_client import (
|
17
|
+
EmbeddingServiceAsyncClient,
|
18
|
+
EmbeddingServiceConnectionError,
|
19
|
+
EmbeddingServiceHTTPError,
|
20
|
+
EmbeddingServiceAPIError,
|
21
|
+
EmbeddingServiceError,
|
22
|
+
)
|
23
|
+
|
24
|
+
def get_params():
|
25
|
+
base_url = None
|
26
|
+
port = None
|
27
|
+
for i, arg in enumerate(sys.argv):
|
28
|
+
if arg in ("--base-url", "-b") and i + 1 < len(sys.argv):
|
29
|
+
base_url = sys.argv[i + 1]
|
30
|
+
if arg in ("--port", "-p") and i + 1 < len(sys.argv):
|
31
|
+
port = sys.argv[i + 1]
|
32
|
+
if not base_url:
|
33
|
+
base_url = os.environ.get("EMBED_CLIENT_BASE_URL")
|
34
|
+
if not port:
|
35
|
+
port = os.environ.get("EMBED_CLIENT_PORT")
|
36
|
+
if not base_url or not port:
|
37
|
+
print("Error: base_url and port must be provided via --base-url/--port arguments or EMBED_CLIENT_BASE_URL/EMBED_CLIENT_PORT environment variables.")
|
38
|
+
sys.exit(1)
|
39
|
+
return None, None
|
40
|
+
return base_url, int(port)
|
41
|
+
|
42
|
+
async def main():
|
43
|
+
base_url, port = get_params()
|
44
|
+
# Always use try/except to handle all possible errors
|
45
|
+
try:
|
46
|
+
async with EmbeddingServiceAsyncClient(base_url=base_url, port=port) as client:
|
47
|
+
# Check health
|
48
|
+
try:
|
49
|
+
health = await client.health()
|
50
|
+
print("Service health:", health)
|
51
|
+
except EmbeddingServiceConnectionError as e:
|
52
|
+
print("[Connection error]", e)
|
53
|
+
return
|
54
|
+
except EmbeddingServiceHTTPError as e:
|
55
|
+
print(f"[HTTP error] {e.status}: {e.message}")
|
56
|
+
return
|
57
|
+
except EmbeddingServiceError as e:
|
58
|
+
print("[Other error]", e)
|
59
|
+
return
|
60
|
+
|
61
|
+
# Request embeddings for a list of texts
|
62
|
+
texts = ["hello world", "test embedding"]
|
63
|
+
try:
|
64
|
+
result = await client.cmd("embed", params={"texts": texts})
|
65
|
+
vectors = result["result"]
|
66
|
+
print(f"Embeddings for {len(texts)} texts:")
|
67
|
+
for i, vec in enumerate(vectors):
|
68
|
+
print(f" Text: {texts[i]!r}\n Vector: {vec[:5]}... (total {len(vec)} dims)")
|
69
|
+
except EmbeddingServiceAPIError as e:
|
70
|
+
print("[API error]", e.error)
|
71
|
+
except EmbeddingServiceHTTPError as e:
|
72
|
+
print(f"[HTTP error] {e.status}: {e.message}")
|
73
|
+
except EmbeddingServiceConnectionError as e:
|
74
|
+
print("[Connection error]", e)
|
75
|
+
except EmbeddingServiceError as e:
|
76
|
+
print("[Other error]", e)
|
77
|
+
|
78
|
+
# Example: error handling for invalid command
|
79
|
+
try:
|
80
|
+
await client.cmd("not_a_command")
|
81
|
+
except EmbeddingServiceAPIError as e:
|
82
|
+
print("[API error for invalid command]", e.error)
|
83
|
+
|
84
|
+
# Example: error handling for empty texts
|
85
|
+
try:
|
86
|
+
await client.cmd("embed", params={"texts": []})
|
87
|
+
except EmbeddingServiceAPIError as e:
|
88
|
+
print("[API error for empty texts]", e.error)
|
89
|
+
|
90
|
+
except Exception as e:
|
91
|
+
print("[Unexpected error]", e)
|
92
|
+
|
93
|
+
if __name__ == "__main__":
|
94
|
+
asyncio.run(main())
|
@@ -0,0 +1,9 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: embed-client
|
3
|
+
Version: 0.0.1
|
4
|
+
Summary: Async client for Embedding Service API
|
5
|
+
Author: Your Name
|
6
|
+
Requires-Dist: aiohttp
|
7
|
+
Provides-Extra: test
|
8
|
+
Requires-Dist: pytest; extra == "test"
|
9
|
+
Requires-Dist: pytest-asyncio; extra == "test"
|
@@ -0,0 +1,8 @@
|
|
1
|
+
embed_client/__init__.py,sha256=Nqnn8clbgv-5l0PgxcTOldg8mkMKrFn4TvPL-rYUUGg,1
|
2
|
+
embed_client/async_client.py,sha256=HzvJ85Qh8fT-YHuam4YFW5Kbxx2hrbsOV8EzjbQ34Eg,7329
|
3
|
+
embed_client/example_async_usage.py,sha256=7j9Hro7-TjsKVC2vHUX2J1_-Rh3V9FxsOmsCdCV8KYM,3555
|
4
|
+
embed_client/example_async_usage_ru.py,sha256=kZXQcbEFkx9tWXoCq-AoyvvUY4aCuW1XqPVb1ADWeAM,3558
|
5
|
+
embed_client-0.0.1.dist-info/METADATA,sha256=GUuiN2owdcnNa7XqqZeEJo_G9oV8Z7ZoqcNUtn-Cuyo,252
|
6
|
+
embed_client-0.0.1.dist-info/WHEEL,sha256=Nw36Djuh_5VDukK0H78QzOX-_FQEo6V37m3nkm96gtU,91
|
7
|
+
embed_client-0.0.1.dist-info/top_level.txt,sha256=uG00A4d9o9DFrhiN7goObpeig72Pniby0E7UpDRgyXY,13
|
8
|
+
embed_client-0.0.1.dist-info/RECORD,,
|
@@ -0,0 +1 @@
|
|
1
|
+
embed_client
|