vectorizer-sdk 3.0.0__tar.gz → 3.0.3__tar.gz
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.
- {vectorizer_sdk-3.0.0/vectorizer_sdk.egg-info → vectorizer_sdk-3.0.3}/PKG-INFO +1 -1
- {vectorizer_sdk-3.0.0 → vectorizer_sdk-3.0.3}/pyproject.toml +110 -110
- {vectorizer_sdk-3.0.0 → vectorizer_sdk-3.0.3}/utils/http_client.py +9 -1
- {vectorizer_sdk-3.0.0 → vectorizer_sdk-3.0.3}/vectorizer/_base.py +19 -1
- {vectorizer_sdk-3.0.0 → vectorizer_sdk-3.0.3}/vectorizer/auth.py +27 -1
- {vectorizer_sdk-3.0.0 → vectorizer_sdk-3.0.3}/vectorizer/client.py +10 -1
- {vectorizer_sdk-3.0.0 → vectorizer_sdk-3.0.3}/vectorizer/vectors.py +47 -0
- {vectorizer_sdk-3.0.0 → vectorizer_sdk-3.0.3/vectorizer_sdk.egg-info}/PKG-INFO +1 -1
- {vectorizer_sdk-3.0.0 → vectorizer_sdk-3.0.3}/LICENSE +0 -0
- {vectorizer_sdk-3.0.0 → vectorizer_sdk-3.0.3}/README.md +0 -0
- {vectorizer_sdk-3.0.0 → vectorizer_sdk-3.0.3}/rpc/__init__.py +0 -0
- {vectorizer_sdk-3.0.0 → vectorizer_sdk-3.0.3}/rpc/_codec.py +0 -0
- {vectorizer_sdk-3.0.0 → vectorizer_sdk-3.0.3}/rpc/async_client.py +0 -0
- {vectorizer_sdk-3.0.0 → vectorizer_sdk-3.0.3}/rpc/commands.py +0 -0
- {vectorizer_sdk-3.0.0 → vectorizer_sdk-3.0.3}/rpc/endpoint.py +0 -0
- {vectorizer_sdk-3.0.0 → vectorizer_sdk-3.0.3}/rpc/pool.py +0 -0
- {vectorizer_sdk-3.0.0 → vectorizer_sdk-3.0.3}/rpc/sync_client.py +0 -0
- {vectorizer_sdk-3.0.0 → vectorizer_sdk-3.0.3}/rpc/types.py +0 -0
- {vectorizer_sdk-3.0.0 → vectorizer_sdk-3.0.3}/setup.cfg +0 -0
- {vectorizer_sdk-3.0.0 → vectorizer_sdk-3.0.3}/tests/test_client_integration.py +0 -0
- {vectorizer_sdk-3.0.0 → vectorizer_sdk-3.0.3}/tests/test_discovery.py +0 -0
- {vectorizer_sdk-3.0.0 → vectorizer_sdk-3.0.3}/tests/test_exceptions.py +0 -0
- {vectorizer_sdk-3.0.0 → vectorizer_sdk-3.0.3}/tests/test_file_operations.py +0 -0
- {vectorizer_sdk-3.0.0 → vectorizer_sdk-3.0.3}/tests/test_file_upload.py +0 -0
- {vectorizer_sdk-3.0.0 → vectorizer_sdk-3.0.3}/tests/test_graph.py +0 -0
- {vectorizer_sdk-3.0.0 → vectorizer_sdk-3.0.3}/tests/test_http_client.py +0 -0
- {vectorizer_sdk-3.0.0 → vectorizer_sdk-3.0.3}/tests/test_intelligent_search.py +0 -0
- {vectorizer_sdk-3.0.0 → vectorizer_sdk-3.0.3}/tests/test_mock_transport.py +0 -0
- {vectorizer_sdk-3.0.0 → vectorizer_sdk-3.0.3}/tests/test_models.py +0 -0
- {vectorizer_sdk-3.0.0 → vectorizer_sdk-3.0.3}/tests/test_qdrant_advanced.py +0 -0
- {vectorizer_sdk-3.0.0 → vectorizer_sdk-3.0.3}/tests/test_routing.py +0 -0
- {vectorizer_sdk-3.0.0 → vectorizer_sdk-3.0.3}/tests/test_sdk_comprehensive.py +0 -0
- {vectorizer_sdk-3.0.0 → vectorizer_sdk-3.0.3}/tests/test_simple.py +0 -0
- {vectorizer_sdk-3.0.0 → vectorizer_sdk-3.0.3}/tests/test_umicp.py +0 -0
- {vectorizer_sdk-3.0.0 → vectorizer_sdk-3.0.3}/tests/test_validation.py +0 -0
- {vectorizer_sdk-3.0.0 → vectorizer_sdk-3.0.3}/utils/__init__.py +0 -0
- {vectorizer_sdk-3.0.0 → vectorizer_sdk-3.0.3}/utils/transport.py +0 -0
- {vectorizer_sdk-3.0.0 → vectorizer_sdk-3.0.3}/utils/umicp_client.py +0 -0
- {vectorizer_sdk-3.0.0 → vectorizer_sdk-3.0.3}/utils/validation.py +0 -0
- {vectorizer_sdk-3.0.0 → vectorizer_sdk-3.0.3}/vectorizer/__init__.py +0 -0
- {vectorizer_sdk-3.0.0 → vectorizer_sdk-3.0.3}/vectorizer/admin.py +0 -0
- {vectorizer_sdk-3.0.0 → vectorizer_sdk-3.0.3}/vectorizer/collections.py +0 -0
- {vectorizer_sdk-3.0.0 → vectorizer_sdk-3.0.3}/vectorizer/graph.py +0 -0
- {vectorizer_sdk-3.0.0 → vectorizer_sdk-3.0.3}/vectorizer/search.py +0 -0
- {vectorizer_sdk-3.0.0 → vectorizer_sdk-3.0.3}/vectorizer_sdk.egg-info/SOURCES.txt +0 -0
- {vectorizer_sdk-3.0.0 → vectorizer_sdk-3.0.3}/vectorizer_sdk.egg-info/dependency_links.txt +0 -0
- {vectorizer_sdk-3.0.0 → vectorizer_sdk-3.0.3}/vectorizer_sdk.egg-info/entry_points.txt +0 -0
- {vectorizer_sdk-3.0.0 → vectorizer_sdk-3.0.3}/vectorizer_sdk.egg-info/requires.txt +0 -0
- {vectorizer_sdk-3.0.0 → vectorizer_sdk-3.0.3}/vectorizer_sdk.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: vectorizer_sdk
|
|
3
|
-
Version: 3.0.
|
|
3
|
+
Version: 3.0.3
|
|
4
4
|
Summary: Python SDK for Vectorizer - Semantic search, vector operations, and the VectorizerRPC binary transport (default in v3.x)
|
|
5
5
|
Author-email: HiveLLM Team <team@hivellm.org>
|
|
6
6
|
License: Apache-2.0
|
|
@@ -1,110 +1,110 @@
|
|
|
1
|
-
[build-system]
|
|
2
|
-
requires = ["setuptools>=61.0", "wheel"]
|
|
3
|
-
build-backend = "setuptools.build_meta"
|
|
4
|
-
|
|
5
|
-
[project]
|
|
6
|
-
name = "vectorizer_sdk"
|
|
7
|
-
version = "3.0.
|
|
8
|
-
description = "Python SDK for Vectorizer - Semantic search, vector operations, and the VectorizerRPC binary transport (default in v3.x)"
|
|
9
|
-
readme = "README.md"
|
|
10
|
-
requires-python = ">=3.8"
|
|
11
|
-
license = {text = "Apache-2.0"}
|
|
12
|
-
authors = [
|
|
13
|
-
{name = "HiveLLM Team", email = "team@hivellm.org"}
|
|
14
|
-
]
|
|
15
|
-
keywords = [
|
|
16
|
-
"vectorizer",
|
|
17
|
-
"semantic-search",
|
|
18
|
-
"embeddings",
|
|
19
|
-
"machine-learning",
|
|
20
|
-
"ai",
|
|
21
|
-
"search",
|
|
22
|
-
"vectors",
|
|
23
|
-
"similarity",
|
|
24
|
-
"hivellm",
|
|
25
|
-
"umicp"
|
|
26
|
-
]
|
|
27
|
-
classifiers = [
|
|
28
|
-
"Development Status :: 5 - Production/Stable",
|
|
29
|
-
"Intended Audience :: Developers",
|
|
30
|
-
"Operating System :: OS Independent",
|
|
31
|
-
"Programming Language :: Python :: 3",
|
|
32
|
-
"Programming Language :: Python :: 3.8",
|
|
33
|
-
"Programming Language :: Python :: 3.9",
|
|
34
|
-
"Programming Language :: Python :: 3.10",
|
|
35
|
-
"Programming Language :: Python :: 3.11",
|
|
36
|
-
"Programming Language :: Python :: 3.12",
|
|
37
|
-
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
38
|
-
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
39
|
-
"Topic :: Text Processing :: Indexing",
|
|
40
|
-
"Topic :: Internet :: WWW/HTTP :: Dynamic Content",
|
|
41
|
-
]
|
|
42
|
-
|
|
43
|
-
dependencies = [
|
|
44
|
-
"aiohttp>=3.10.0",
|
|
45
|
-
"msgpack>=1.1.0",
|
|
46
|
-
]
|
|
47
|
-
|
|
48
|
-
[project.optional-dependencies]
|
|
49
|
-
umicp = [
|
|
50
|
-
"umicp-python>=0.1.3",
|
|
51
|
-
]
|
|
52
|
-
dev = [
|
|
53
|
-
"pytest>=8.0.0",
|
|
54
|
-
"pytest-asyncio>=0.24.0",
|
|
55
|
-
"pytest-cov>=5.0.0",
|
|
56
|
-
"black>=25.0.0",
|
|
57
|
-
"isort>=5.13.0",
|
|
58
|
-
"flake8>=7.0.0",
|
|
59
|
-
"mypy>=1.11.0",
|
|
60
|
-
"pre-commit>=4.0.0",
|
|
61
|
-
]
|
|
62
|
-
docs = [
|
|
63
|
-
"sphinx>=7.0.0",
|
|
64
|
-
"sphinx-rtd-theme>=2.0.0",
|
|
65
|
-
"myst-parser>=3.0.0",
|
|
66
|
-
]
|
|
67
|
-
test = [
|
|
68
|
-
"pytest>=8.0.0",
|
|
69
|
-
"pytest-asyncio>=0.24.0",
|
|
70
|
-
"pytest-cov>=5.0.0",
|
|
71
|
-
"httpx>=0.27.0",
|
|
72
|
-
]
|
|
73
|
-
|
|
74
|
-
[project.urls]
|
|
75
|
-
Homepage = "https://github.com/hivellm/vectorizer"
|
|
76
|
-
Documentation = "https://github.com/hivellm/vectorizer/tree/main/docs"
|
|
77
|
-
Repository = "https://github.com/hivellm/vectorizer"
|
|
78
|
-
Issues = "https://github.com/hivellm/vectorizer/issues"
|
|
79
|
-
|
|
80
|
-
[project.scripts]
|
|
81
|
-
vectorizer-cli = "cli:main"
|
|
82
|
-
|
|
83
|
-
[tool.setuptools.packages.find]
|
|
84
|
-
include = ["*"]
|
|
85
|
-
exclude = ["tests*", "examples*", "docs*"]
|
|
86
|
-
|
|
87
|
-
[tool.setuptools.package-data]
|
|
88
|
-
"*" = ["py.typed"]
|
|
89
|
-
|
|
90
|
-
[tool.pytest.ini_options]
|
|
91
|
-
asyncio_mode = "auto"
|
|
92
|
-
testpaths = ["tests"]
|
|
93
|
-
python_files = ["test_*.py"]
|
|
94
|
-
python_classes = ["Test*"]
|
|
95
|
-
python_functions = ["test_*"]
|
|
96
|
-
|
|
97
|
-
[tool.black]
|
|
98
|
-
line-length = 100
|
|
99
|
-
target-version = ['py38', 'py39', 'py310', 'py311', 'py312']
|
|
100
|
-
|
|
101
|
-
[tool.isort]
|
|
102
|
-
profile = "black"
|
|
103
|
-
line_length = 100
|
|
104
|
-
|
|
105
|
-
[tool.mypy]
|
|
106
|
-
python_version = "3.8"
|
|
107
|
-
warn_return_any = true
|
|
108
|
-
warn_unused_configs = true
|
|
109
|
-
disallow_untyped_defs = false
|
|
110
|
-
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "vectorizer_sdk"
|
|
7
|
+
version = "3.0.3"
|
|
8
|
+
description = "Python SDK for Vectorizer - Semantic search, vector operations, and the VectorizerRPC binary transport (default in v3.x)"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.8"
|
|
11
|
+
license = {text = "Apache-2.0"}
|
|
12
|
+
authors = [
|
|
13
|
+
{name = "HiveLLM Team", email = "team@hivellm.org"}
|
|
14
|
+
]
|
|
15
|
+
keywords = [
|
|
16
|
+
"vectorizer",
|
|
17
|
+
"semantic-search",
|
|
18
|
+
"embeddings",
|
|
19
|
+
"machine-learning",
|
|
20
|
+
"ai",
|
|
21
|
+
"search",
|
|
22
|
+
"vectors",
|
|
23
|
+
"similarity",
|
|
24
|
+
"hivellm",
|
|
25
|
+
"umicp"
|
|
26
|
+
]
|
|
27
|
+
classifiers = [
|
|
28
|
+
"Development Status :: 5 - Production/Stable",
|
|
29
|
+
"Intended Audience :: Developers",
|
|
30
|
+
"Operating System :: OS Independent",
|
|
31
|
+
"Programming Language :: Python :: 3",
|
|
32
|
+
"Programming Language :: Python :: 3.8",
|
|
33
|
+
"Programming Language :: Python :: 3.9",
|
|
34
|
+
"Programming Language :: Python :: 3.10",
|
|
35
|
+
"Programming Language :: Python :: 3.11",
|
|
36
|
+
"Programming Language :: Python :: 3.12",
|
|
37
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
38
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
39
|
+
"Topic :: Text Processing :: Indexing",
|
|
40
|
+
"Topic :: Internet :: WWW/HTTP :: Dynamic Content",
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
dependencies = [
|
|
44
|
+
"aiohttp>=3.10.0",
|
|
45
|
+
"msgpack>=1.1.0",
|
|
46
|
+
]
|
|
47
|
+
|
|
48
|
+
[project.optional-dependencies]
|
|
49
|
+
umicp = [
|
|
50
|
+
"umicp-python>=0.1.3",
|
|
51
|
+
]
|
|
52
|
+
dev = [
|
|
53
|
+
"pytest>=8.0.0",
|
|
54
|
+
"pytest-asyncio>=0.24.0",
|
|
55
|
+
"pytest-cov>=5.0.0",
|
|
56
|
+
"black>=25.0.0",
|
|
57
|
+
"isort>=5.13.0",
|
|
58
|
+
"flake8>=7.0.0",
|
|
59
|
+
"mypy>=1.11.0",
|
|
60
|
+
"pre-commit>=4.0.0",
|
|
61
|
+
]
|
|
62
|
+
docs = [
|
|
63
|
+
"sphinx>=7.0.0",
|
|
64
|
+
"sphinx-rtd-theme>=2.0.0",
|
|
65
|
+
"myst-parser>=3.0.0",
|
|
66
|
+
]
|
|
67
|
+
test = [
|
|
68
|
+
"pytest>=8.0.0",
|
|
69
|
+
"pytest-asyncio>=0.24.0",
|
|
70
|
+
"pytest-cov>=5.0.0",
|
|
71
|
+
"httpx>=0.27.0",
|
|
72
|
+
]
|
|
73
|
+
|
|
74
|
+
[project.urls]
|
|
75
|
+
Homepage = "https://github.com/hivellm/vectorizer"
|
|
76
|
+
Documentation = "https://github.com/hivellm/vectorizer/tree/main/docs"
|
|
77
|
+
Repository = "https://github.com/hivellm/vectorizer"
|
|
78
|
+
Issues = "https://github.com/hivellm/vectorizer/issues"
|
|
79
|
+
|
|
80
|
+
[project.scripts]
|
|
81
|
+
vectorizer-cli = "cli:main"
|
|
82
|
+
|
|
83
|
+
[tool.setuptools.packages.find]
|
|
84
|
+
include = ["*"]
|
|
85
|
+
exclude = ["tests*", "examples*", "docs*"]
|
|
86
|
+
|
|
87
|
+
[tool.setuptools.package-data]
|
|
88
|
+
"*" = ["py.typed"]
|
|
89
|
+
|
|
90
|
+
[tool.pytest.ini_options]
|
|
91
|
+
asyncio_mode = "auto"
|
|
92
|
+
testpaths = ["tests"]
|
|
93
|
+
python_files = ["test_*.py"]
|
|
94
|
+
python_classes = ["Test*"]
|
|
95
|
+
python_functions = ["test_*"]
|
|
96
|
+
|
|
97
|
+
[tool.black]
|
|
98
|
+
line-length = 100
|
|
99
|
+
target-version = ['py38', 'py39', 'py310', 'py311', 'py312']
|
|
100
|
+
|
|
101
|
+
[tool.isort]
|
|
102
|
+
profile = "black"
|
|
103
|
+
line_length = 100
|
|
104
|
+
|
|
105
|
+
[tool.mypy]
|
|
106
|
+
python_version = "3.8"
|
|
107
|
+
warn_return_any = true
|
|
108
|
+
warn_unused_configs = true
|
|
109
|
+
disallow_untyped_defs = false
|
|
110
|
+
|
|
@@ -53,7 +53,15 @@ class HTTPClient:
|
|
|
53
53
|
if self._session is None or self._session.closed:
|
|
54
54
|
headers = {"Content-Type": "application/json"}
|
|
55
55
|
if self.api_key:
|
|
56
|
-
|
|
56
|
+
# JWT shape → `Authorization: Bearer`; anything else
|
|
57
|
+
# (raw API keys from `POST /auth/keys`) → `X-API-Key`.
|
|
58
|
+
# Server middleware won't fall back Bearer → api_key,
|
|
59
|
+
# so routing has to happen client-side.
|
|
60
|
+
parts = self.api_key.split(".")
|
|
61
|
+
if len(parts) == 3 and all(p for p in parts):
|
|
62
|
+
headers["Authorization"] = f"Bearer {self.api_key}"
|
|
63
|
+
else:
|
|
64
|
+
headers["X-API-Key"] = self.api_key
|
|
57
65
|
|
|
58
66
|
timeout_config = aiohttp.ClientTimeout(total=self.timeout)
|
|
59
67
|
self._session = aiohttp.ClientSession(
|
|
@@ -112,6 +112,22 @@ class RestTransport(Transport):
|
|
|
112
112
|
await self._http.close()
|
|
113
113
|
|
|
114
114
|
|
|
115
|
+
def _looks_like_jwt(token: str) -> bool:
|
|
116
|
+
"""Cheap JWT shape sniff: three non-empty base64url-encoded segments
|
|
117
|
+
joined by ``.``. Raw Vectorizer API keys (from ``POST /auth/keys``)
|
|
118
|
+
are a single alphanumeric string and fail this check, so they get
|
|
119
|
+
routed to ``X-API-Key`` rather than ``Authorization: Bearer``.
|
|
120
|
+
|
|
121
|
+
The server's auth middleware treats every ``Bearer`` string as a
|
|
122
|
+
JWT and never falls back to the API-key validator, so sending a
|
|
123
|
+
raw key under ``Bearer`` silently 401s. This sniff keeps the public
|
|
124
|
+
``api_key`` config field unchanged while routing each credential
|
|
125
|
+
down the header the server actually accepts.
|
|
126
|
+
"""
|
|
127
|
+
parts = token.split(".")
|
|
128
|
+
return len(parts) == 3 and all(p for p in parts)
|
|
129
|
+
|
|
130
|
+
|
|
115
131
|
@dataclass
|
|
116
132
|
class AuthState:
|
|
117
133
|
"""Bearer-token + API-key state shared across surface clients."""
|
|
@@ -121,7 +137,9 @@ class AuthState:
|
|
|
121
137
|
def headers(self) -> dict:
|
|
122
138
|
if not self.api_key:
|
|
123
139
|
return {}
|
|
124
|
-
|
|
140
|
+
if _looks_like_jwt(self.api_key):
|
|
141
|
+
return {"Authorization": f"Bearer {self.api_key}"}
|
|
142
|
+
return {"X-API-Key": self.api_key}
|
|
125
143
|
|
|
126
144
|
|
|
127
145
|
@dataclass
|
|
@@ -22,7 +22,8 @@ class AuthClient(_ApiBase):
|
|
|
22
22
|
|
|
23
23
|
from vectorizer import RestTransport, AuthClient
|
|
24
24
|
auth = AuthClient(RestTransport("http://localhost:15002"), api_key="sk-...")
|
|
25
|
-
print(auth.headers()) #
|
|
25
|
+
print(auth.headers()) # raw API key → {"X-API-Key": "sk-..."}
|
|
26
|
+
# # JWT → {"Authorization": "Bearer <jwt>"}
|
|
26
27
|
|
|
27
28
|
In the :class:`vectorizer.VectorizerClient` facade this is the
|
|
28
29
|
surface that owns the API key and surfaces it via :attr:`api_key`
|
|
@@ -47,3 +48,28 @@ class AuthClient(_ApiBase):
|
|
|
47
48
|
def set_api_key(self, api_key: Optional[str]) -> None:
|
|
48
49
|
"""Replace the current API key — affects future request headers."""
|
|
49
50
|
self._auth.api_key = api_key
|
|
51
|
+
|
|
52
|
+
async def login(self, username: str, password: str) -> str:
|
|
53
|
+
"""Exchange ``(username, password)`` for a JWT via
|
|
54
|
+
``POST /auth/login`` and return the raw ``access_token``.
|
|
55
|
+
|
|
56
|
+
The token is **not** stored on ``self`` — to use it for
|
|
57
|
+
subsequent requests, call :meth:`set_api_key` with the token
|
|
58
|
+
(``AuthState.headers`` sniffs the JWT shape and routes it onto
|
|
59
|
+
``Authorization: Bearer …`` automatically).
|
|
60
|
+
|
|
61
|
+
When the server runs with ``auth.enabled: false`` this
|
|
62
|
+
endpoint returns 404 — dev servers without auth don't need
|
|
63
|
+
to call :meth:`login` at all.
|
|
64
|
+
"""
|
|
65
|
+
data = await self._transport.post(
|
|
66
|
+
"/auth/login",
|
|
67
|
+
{"username": username, "password": password},
|
|
68
|
+
)
|
|
69
|
+
token = data.get("access_token") if isinstance(data, dict) else None
|
|
70
|
+
if not isinstance(token, str) or not token:
|
|
71
|
+
raise ValueError(
|
|
72
|
+
"login response missing `access_token`; server payload: "
|
|
73
|
+
f"{data!r}"
|
|
74
|
+
)
|
|
75
|
+
return token
|
|
@@ -274,7 +274,16 @@ class VectorizerClient:
|
|
|
274
274
|
if self._session is None or self._session.closed:
|
|
275
275
|
headers = {}
|
|
276
276
|
if self.api_key:
|
|
277
|
-
|
|
277
|
+
# Route JWTs to `Authorization: Bearer` and raw API
|
|
278
|
+
# keys to `X-API-Key`. Server middleware treats
|
|
279
|
+
# every Bearer string as a JWT and won't fall back
|
|
280
|
+
# to the API-key validator — sending a raw key as
|
|
281
|
+
# Bearer silently 401s on every gated route.
|
|
282
|
+
from ._base import _looks_like_jwt
|
|
283
|
+
if _looks_like_jwt(self.api_key):
|
|
284
|
+
headers["Authorization"] = f"Bearer {self.api_key}"
|
|
285
|
+
else:
|
|
286
|
+
headers["X-API-Key"] = self.api_key
|
|
278
287
|
|
|
279
288
|
timeout = aiohttp.ClientTimeout(total=self.timeout)
|
|
280
289
|
self._session = aiohttp.ClientSession(
|
|
@@ -112,6 +112,15 @@ class VectorsClient(_ApiBase):
|
|
|
112
112
|
"""
|
|
113
113
|
Get a specific vector by ID.
|
|
114
114
|
|
|
115
|
+
.. warning::
|
|
116
|
+
**Server caveat (observed on ``hivehub/vectorizer:3.0.x``):**
|
|
117
|
+
this endpoint currently returns HTTP 200 with a synthetic
|
|
118
|
+
uniform-vector payload (``[0.1, 0.1, ...]``) even for ids
|
|
119
|
+
that don't exist. Callers that need real miss detection
|
|
120
|
+
should probe via :meth:`list_vectors` or search and not
|
|
121
|
+
trust a successful response as proof of existence until
|
|
122
|
+
the server fix ships.
|
|
123
|
+
|
|
115
124
|
Args:
|
|
116
125
|
collection: Collection name
|
|
117
126
|
vector_id: Vector ID
|
|
@@ -125,6 +134,44 @@ class VectorsClient(_ApiBase):
|
|
|
125
134
|
ServerError: If service returns error
|
|
126
135
|
"""
|
|
127
136
|
return await self._transport.get(f"/collections/{collection}/vectors/{vector_id}")
|
|
137
|
+
|
|
138
|
+
async def insert_text_batch(
|
|
139
|
+
self,
|
|
140
|
+
collection: str,
|
|
141
|
+
texts: List[Dict[str, Any]],
|
|
142
|
+
) -> Dict[str, Any]:
|
|
143
|
+
"""Insert a batch of **texts** into a collection. The server
|
|
144
|
+
embeds each entry with the collection's configured provider
|
|
145
|
+
(BM25 default, FastEmbed ONNX when selected in ``config.yml``).
|
|
146
|
+
|
|
147
|
+
Wire contract: ``POST /insert_texts`` with
|
|
148
|
+
``{"collection": ..., "texts": [...]}`` payload. The collection
|
|
149
|
+
is a top-level JSON field, **not** a path segment.
|
|
150
|
+
|
|
151
|
+
Per-entry ``id``: the server **reassigns** every inserted
|
|
152
|
+
vector a server-generated UUID. The original client id
|
|
153
|
+
round-trips on the response as ``client_id``. Callers that
|
|
154
|
+
need idempotency by client id should key off the returned
|
|
155
|
+
``results[].client_id``, not the server-assigned UUID.
|
|
156
|
+
|
|
157
|
+
Distinct from :meth:`insert_texts` on this class, which takes
|
|
158
|
+
:class:`Vector` objects with pre-computed embeddings and hits
|
|
159
|
+
the raw-vector write path.
|
|
160
|
+
|
|
161
|
+
Args:
|
|
162
|
+
collection: Collection name.
|
|
163
|
+
texts: Entries of shape
|
|
164
|
+
``{"id": "...", "text": "...", "metadata": {...}}``.
|
|
165
|
+
|
|
166
|
+
Returns:
|
|
167
|
+
Raw ``/insert_texts`` response dict with fields
|
|
168
|
+
``collection``, ``count``, ``inserted``, ``failed``,
|
|
169
|
+
``results``.
|
|
170
|
+
"""
|
|
171
|
+
if not texts:
|
|
172
|
+
raise ValidationError("texts list cannot be empty")
|
|
173
|
+
payload = {"collection": collection, "texts": texts}
|
|
174
|
+
return await self._transport.post("/insert_texts", data=payload)
|
|
128
175
|
async def delete_vectors(self, collection: str, vector_ids: List[str]) -> bool:
|
|
129
176
|
"""
|
|
130
177
|
Delete vectors from a collection.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: vectorizer_sdk
|
|
3
|
-
Version: 3.0.
|
|
3
|
+
Version: 3.0.3
|
|
4
4
|
Summary: Python SDK for Vectorizer - Semantic search, vector operations, and the VectorizerRPC binary transport (default in v3.x)
|
|
5
5
|
Author-email: HiveLLM Team <team@hivellm.org>
|
|
6
6
|
License: Apache-2.0
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|