semantic-router 0.1.0.dev2__tar.gz → 0.1.0.dev4__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.
- {semantic_router-0.1.0.dev2 → semantic_router-0.1.0.dev4}/LICENSE +1 -1
- {semantic_router-0.1.0.dev2 → semantic_router-0.1.0.dev4}/PKG-INFO +12 -10
- {semantic_router-0.1.0.dev2 → semantic_router-0.1.0.dev4}/pyproject.toml +10 -10
- {semantic_router-0.1.0.dev2 → semantic_router-0.1.0.dev4}/semantic_router/__init__.py +1 -1
- {semantic_router-0.1.0.dev2 → semantic_router-0.1.0.dev4}/semantic_router/encoders/aurelio.py +1 -1
- {semantic_router-0.1.0.dev2 → semantic_router-0.1.0.dev4}/semantic_router/encoders/base.py +2 -2
- {semantic_router-0.1.0.dev2 → semantic_router-0.1.0.dev4}/semantic_router/encoders/bedrock.py +37 -11
- {semantic_router-0.1.0.dev2 → semantic_router-0.1.0.dev4}/semantic_router/encoders/clip.py +3 -2
- {semantic_router-0.1.0.dev2 → semantic_router-0.1.0.dev4}/semantic_router/encoders/cohere.py +1 -1
- {semantic_router-0.1.0.dev2 → semantic_router-0.1.0.dev4}/semantic_router/encoders/fastembed.py +1 -1
- {semantic_router-0.1.0.dev2 → semantic_router-0.1.0.dev4}/semantic_router/encoders/huggingface.py +5 -3
- {semantic_router-0.1.0.dev2 → semantic_router-0.1.0.dev4}/semantic_router/encoders/mistral.py +1 -1
- {semantic_router-0.1.0.dev2 → semantic_router-0.1.0.dev4}/semantic_router/encoders/openai.py +9 -9
- {semantic_router-0.1.0.dev2 → semantic_router-0.1.0.dev4}/semantic_router/encoders/vit.py +4 -3
- {semantic_router-0.1.0.dev2 → semantic_router-0.1.0.dev4}/semantic_router/index/base.py +77 -10
- {semantic_router-0.1.0.dev2 → semantic_router-0.1.0.dev4}/semantic_router/index/pinecone.py +21 -16
- {semantic_router-0.1.0.dev2 → semantic_router-0.1.0.dev4}/semantic_router/index/postgres.py +3 -2
- {semantic_router-0.1.0.dev2 → semantic_router-0.1.0.dev4}/semantic_router/index/qdrant.py +2 -2
- {semantic_router-0.1.0.dev2 → semantic_router-0.1.0.dev4}/semantic_router/llms/base.py +3 -1
- {semantic_router-0.1.0.dev2 → semantic_router-0.1.0.dev4}/semantic_router/llms/cohere.py +1 -1
- {semantic_router-0.1.0.dev2 → semantic_router-0.1.0.dev4}/semantic_router/llms/llamacpp.py +1 -3
- {semantic_router-0.1.0.dev2 → semantic_router-0.1.0.dev4}/semantic_router/llms/mistral.py +1 -3
- {semantic_router-0.1.0.dev2 → semantic_router-0.1.0.dev4}/semantic_router/llms/ollama.py +5 -10
- {semantic_router-0.1.0.dev2 → semantic_router-0.1.0.dev4}/semantic_router/llms/openai.py +9 -10
- {semantic_router-0.1.0.dev2 → semantic_router-0.1.0.dev4}/semantic_router/llms/openrouter.py +8 -8
- {semantic_router-0.1.0.dev2 → semantic_router-0.1.0.dev4}/semantic_router/llms/zure.py +5 -6
- {semantic_router-0.1.0.dev2 → semantic_router-0.1.0.dev4}/semantic_router/route.py +2 -7
- {semantic_router-0.1.0.dev2 → semantic_router-0.1.0.dev4}/semantic_router/routers/base.py +50 -19
- {semantic_router-0.1.0.dev2 → semantic_router-0.1.0.dev4}/semantic_router/routers/hybrid.py +7 -7
- {semantic_router-0.1.0.dev2 → semantic_router-0.1.0.dev4}/semantic_router/routers/semantic.py +0 -2
- {semantic_router-0.1.0.dev2 → semantic_router-0.1.0.dev4}/semantic_router/schema.py +20 -7
- semantic_router-0.1.0.dev4/semantic_router/utils/__init__.py +0 -0
- {semantic_router-0.1.0.dev2 → semantic_router-0.1.0.dev4}/semantic_router/utils/function_call.py +1 -1
- {semantic_router-0.1.0.dev2 → semantic_router-0.1.0.dev4}/README.md +0 -0
- {semantic_router-0.1.0.dev2 → semantic_router-0.1.0.dev4}/semantic_router/encoders/__init__.py +0 -0
- {semantic_router-0.1.0.dev2 → semantic_router-0.1.0.dev4}/semantic_router/encoders/bm25.py +0 -0
- {semantic_router-0.1.0.dev2 → semantic_router-0.1.0.dev4}/semantic_router/encoders/google.py +0 -0
- {semantic_router-0.1.0.dev2 → semantic_router-0.1.0.dev4}/semantic_router/encoders/tfidf.py +0 -0
- {semantic_router-0.1.0.dev2 → semantic_router-0.1.0.dev4}/semantic_router/encoders/zure.py +0 -0
- {semantic_router-0.1.0.dev2 → semantic_router-0.1.0.dev4}/semantic_router/index/__init__.py +0 -0
- {semantic_router-0.1.0.dev2 → semantic_router-0.1.0.dev4}/semantic_router/index/hybrid_local.py +0 -0
- {semantic_router-0.1.0.dev2 → semantic_router-0.1.0.dev4}/semantic_router/index/local.py +0 -0
- {semantic_router-0.1.0.dev2 → semantic_router-0.1.0.dev4}/semantic_router/linear.py +0 -0
- {semantic_router-0.1.0.dev2 → semantic_router-0.1.0.dev4}/semantic_router/llms/__init__.py +0 -0
- {semantic_router-0.1.0.dev2 → semantic_router-0.1.0.dev4}/semantic_router/llms/grammars/json.gbnf +0 -0
- /semantic_router-0.1.0.dev2/semantic_router/utils/__init__.py → /semantic_router-0.1.0.dev4/semantic_router/py.typed +0 -0
- {semantic_router-0.1.0.dev2 → semantic_router-0.1.0.dev4}/semantic_router/routers/__init__.py +0 -0
- {semantic_router-0.1.0.dev2 → semantic_router-0.1.0.dev4}/semantic_router/utils/defaults.py +0 -0
- {semantic_router-0.1.0.dev2 → semantic_router-0.1.0.dev4}/semantic_router/utils/llm.py +0 -0
- {semantic_router-0.1.0.dev2 → semantic_router-0.1.0.dev4}/semantic_router/utils/logger.py +0 -0
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: semantic-router
|
|
3
|
-
Version: 0.1.0.
|
|
3
|
+
Version: 0.1.0.dev4
|
|
4
4
|
Summary: Super fast semantic router for AI decision making
|
|
5
5
|
License: MIT
|
|
6
6
|
Author: Aurelio AI
|
|
7
7
|
Author-email: hello@aurelio.ai
|
|
8
|
-
Requires-Python: >=3.9,<3.
|
|
8
|
+
Requires-Python: >=3.9,<3.14
|
|
9
9
|
Classifier: License :: OSI Approved :: MIT License
|
|
10
10
|
Classifier: Programming Language :: Python :: 3
|
|
11
11
|
Classifier: Programming Language :: Python :: 3.9
|
|
12
12
|
Classifier: Programming Language :: Python :: 3.10
|
|
13
13
|
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
14
16
|
Provides-Extra: bedrock
|
|
15
17
|
Provides-Extra: cohere
|
|
16
18
|
Provides-Extra: docs
|
|
@@ -30,17 +32,17 @@ Requires-Dist: botocore (>=1.34.110,<2.0.0) ; extra == "bedrock"
|
|
|
30
32
|
Requires-Dist: cohere (>=5.9.4,<6.00) ; extra == "cohere"
|
|
31
33
|
Requires-Dist: colorama (>=0.4.6,<0.5.0)
|
|
32
34
|
Requires-Dist: colorlog (>=6.8.0,<7.0.0)
|
|
33
|
-
Requires-Dist: fastembed (>=0.3.0,<0.4.0) ; extra == "fastembed"
|
|
35
|
+
Requires-Dist: fastembed (>=0.3.0,<0.4.0) ; (python_version < "3.13") and (extra == "fastembed")
|
|
34
36
|
Requires-Dist: google-cloud-aiplatform (>=1.45.0,<2.0.0) ; extra == "google"
|
|
35
|
-
Requires-Dist: llama-cpp-python (>=0.2.28,<0.2.86) ; extra == "local"
|
|
37
|
+
Requires-Dist: llama-cpp-python (>=0.2.28,<0.2.86) ; (python_version < "3.13") and (extra == "local")
|
|
36
38
|
Requires-Dist: mistralai (>=0.0.12,<0.1.0) ; extra == "mistralai"
|
|
37
39
|
Requires-Dist: numpy (>=1.25.2,<2.0.0)
|
|
38
40
|
Requires-Dist: openai (>=1.10.0,<2.0.0)
|
|
39
|
-
Requires-Dist: pillow (>=10.2.0,<11.0.0) ; extra == "vision"
|
|
41
|
+
Requires-Dist: pillow (>=10.2.0,<11.0.0) ; (python_version < "3.13") and (extra == "vision")
|
|
40
42
|
Requires-Dist: pinecone (>=5.0.0) ; extra == "pinecone"
|
|
41
43
|
Requires-Dist: pinecone-text (>=0.7.1,<0.10.0) ; extra == "hybrid"
|
|
42
44
|
Requires-Dist: psycopg2-binary (>=2.9.9,<3.0.0)
|
|
43
|
-
Requires-Dist: pydantic (>=2.
|
|
45
|
+
Requires-Dist: pydantic (>=2.10.2,<3.0.0)
|
|
44
46
|
Requires-Dist: pyyaml (>=6.0.1,<7.0.0)
|
|
45
47
|
Requires-Dist: qdrant-client (>=1.11.1,<2.0.0) ; extra == "qdrant"
|
|
46
48
|
Requires-Dist: regex (>=2023.12.25)
|
|
@@ -48,11 +50,11 @@ Requires-Dist: requests-mock (>=1.12.1,<2.0.0)
|
|
|
48
50
|
Requires-Dist: sphinx (>=7.0.0,<8.0.0) ; extra == "docs"
|
|
49
51
|
Requires-Dist: sphinxawesome-theme (>=5.2.0,<6.0.0) ; extra == "docs"
|
|
50
52
|
Requires-Dist: tiktoken (>=0.6.0,<1.0.0)
|
|
51
|
-
Requires-Dist: tokenizers (>=0.19) ; extra == "local"
|
|
52
|
-
Requires-Dist: torch (>=2.1.0,<2.6.0) ; extra == "local" or extra == "vision"
|
|
53
|
-
Requires-Dist: torchvision (>=0.17.0,<0.18.0) ; extra == "vision"
|
|
53
|
+
Requires-Dist: tokenizers (>=0.19) ; (python_version < "3.13") and (extra == "local")
|
|
54
|
+
Requires-Dist: torch (>=2.1.0,<2.6.0) ; (python_version < "3.13") and (extra == "local" or extra == "vision")
|
|
55
|
+
Requires-Dist: torchvision (>=0.17.0,<0.18.0) ; (python_version < "3.13") and (extra == "vision")
|
|
54
56
|
Requires-Dist: tornado (>=6.4.2,<7.0.0)
|
|
55
|
-
Requires-Dist: transformers (>=4.36.2) ; extra == "local" or extra == "vision"
|
|
57
|
+
Requires-Dist: transformers (>=4.36.2) ; (python_version < "3.13") and (extra == "local" or extra == "vision")
|
|
56
58
|
Description-Content-Type: text/markdown
|
|
57
59
|
|
|
58
60
|
[](https://aurelio.ai)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "semantic-router"
|
|
3
|
-
version = "0.1.0.
|
|
3
|
+
version = "0.1.0.dev4"
|
|
4
4
|
description = "Super fast semantic router for AI decision making"
|
|
5
5
|
authors = ["Aurelio AI <hello@aurelio.ai>"]
|
|
6
6
|
readme = "README.md"
|
|
@@ -8,8 +8,8 @@ packages = [{include = "semantic_router"}]
|
|
|
8
8
|
license = "MIT"
|
|
9
9
|
|
|
10
10
|
[tool.poetry.dependencies]
|
|
11
|
-
python = ">=3.9,<3.
|
|
12
|
-
pydantic = "^2.
|
|
11
|
+
python = ">=3.9,<3.14"
|
|
12
|
+
pydantic = "^2.10.2"
|
|
13
13
|
openai = ">=1.10.0,<2.0.0"
|
|
14
14
|
cohere = {version = ">=5.9.4,<6.00", optional = true}
|
|
15
15
|
mistralai= {version = ">=0.0.12,<0.1.0", optional = true}
|
|
@@ -18,15 +18,15 @@ colorlog = "^6.8.0"
|
|
|
18
18
|
pyyaml = "^6.0.1"
|
|
19
19
|
aurelio-sdk = {version = "^0.0.16"}
|
|
20
20
|
pinecone-text = {version = ">=0.7.1,<0.10.0", optional = true}
|
|
21
|
-
torch = {version = ">=2.1.0,<2.6.0", optional = true}
|
|
22
|
-
transformers = {version = ">=4.36.2", optional = true}
|
|
23
|
-
tokenizers = {version = ">=0.19", optional = true}
|
|
24
|
-
llama-cpp-python = {version = ">=0.2.28,<0.2.86", optional = true}
|
|
21
|
+
torch = {version = ">=2.1.0,<2.6.0", optional = true, python = "<3.13" }
|
|
22
|
+
transformers = {version = ">=4.36.2", optional = true, python = "<3.13" }
|
|
23
|
+
tokenizers = {version = ">=0.19", optional = true, python = "<3.13" }
|
|
24
|
+
llama-cpp-python = {version = ">=0.2.28,<0.2.86", optional = true, python = "<3.13" }
|
|
25
25
|
colorama = "^0.4.6"
|
|
26
26
|
pinecone = {version=">=5.0.0", optional = true}
|
|
27
27
|
regex = ">=2023.12.25"
|
|
28
|
-
torchvision = { version = ">=0.17.0,<0.18.0", optional = true}
|
|
29
|
-
pillow = { version = ">=10.2.0,<11.0.0", optional = true}
|
|
28
|
+
torchvision = { version = ">=0.17.0,<0.18.0", optional = true, python = "<3.13" }
|
|
29
|
+
pillow = { version = ">=10.2.0,<11.0.0", optional = true, python = "<3.13" }
|
|
30
30
|
tiktoken = ">=0.6.0,<1.0.0"
|
|
31
31
|
qdrant-client = {version = "^1.11.1", optional = true}
|
|
32
32
|
google-cloud-aiplatform = {version = "^1.45.0", optional = true}
|
|
@@ -34,7 +34,7 @@ requests-mock = "^1.12.1"
|
|
|
34
34
|
boto3 = { version = "^1.34.98", optional = true }
|
|
35
35
|
botocore = {version = "^1.34.110", optional = true}
|
|
36
36
|
aiohttp = "^3.10.11"
|
|
37
|
-
fastembed = {version = "^0.3.0", optional = true}
|
|
37
|
+
fastembed = {version = "^0.3.0", optional = true, python = "<3.13" }
|
|
38
38
|
psycopg2-binary = {version = "^2.9.9", optional = true}
|
|
39
39
|
sphinx = {version = "^7.0.0", optional = true}
|
|
40
40
|
sphinxawesome-theme = {version = "^5.2.0", optional = true}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from typing import Any, Coroutine, List, Optional
|
|
2
2
|
|
|
3
|
-
from pydantic
|
|
3
|
+
from pydantic import BaseModel, Field, field_validator
|
|
4
4
|
import numpy as np
|
|
5
5
|
|
|
6
6
|
from semantic_router.schema import SparseEmbedding
|
|
@@ -14,7 +14,7 @@ class DenseEncoder(BaseModel):
|
|
|
14
14
|
class Config:
|
|
15
15
|
arbitrary_types_allowed = True
|
|
16
16
|
|
|
17
|
-
@
|
|
17
|
+
@field_validator("score_threshold")
|
|
18
18
|
def set_score_threshold(cls, v):
|
|
19
19
|
return float(v) if v is not None else None
|
|
20
20
|
|
{semantic_router-0.1.0.dev2 → semantic_router-0.1.0.dev4}/semantic_router/encoders/bedrock.py
RENAMED
|
@@ -17,7 +17,7 @@ Classes:
|
|
|
17
17
|
"""
|
|
18
18
|
|
|
19
19
|
import json
|
|
20
|
-
from typing import List, Optional, Any
|
|
20
|
+
from typing import Dict, List, Optional, Any, Union
|
|
21
21
|
import os
|
|
22
22
|
from time import sleep
|
|
23
23
|
import tiktoken
|
|
@@ -138,11 +138,14 @@ class BedrockEncoder(DenseEncoder):
|
|
|
138
138
|
) from err
|
|
139
139
|
return bedrock_client
|
|
140
140
|
|
|
141
|
-
def __call__(
|
|
141
|
+
def __call__(
|
|
142
|
+
self, docs: List[Union[str, Dict]], model_kwargs: Optional[Dict] = None
|
|
143
|
+
) -> List[List[float]]:
|
|
142
144
|
"""Generates embeddings for the given documents.
|
|
143
145
|
|
|
144
146
|
Args:
|
|
145
147
|
docs: A list of strings representing the documents to embed.
|
|
148
|
+
model_kwargs: A dictionary of model-specific inference parameters.
|
|
146
149
|
|
|
147
150
|
Returns:
|
|
148
151
|
A list of lists, where each inner list contains the embedding values for a
|
|
@@ -168,13 +171,29 @@ class BedrockEncoder(DenseEncoder):
|
|
|
168
171
|
embeddings = []
|
|
169
172
|
if self.name and "amazon" in self.name:
|
|
170
173
|
for doc in docs:
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
174
|
+
|
|
175
|
+
embedding_body = {}
|
|
176
|
+
|
|
177
|
+
if isinstance(doc, dict):
|
|
178
|
+
embedding_body["inputText"] = doc.get("text")
|
|
179
|
+
embedding_body["inputImage"] = doc.get(
|
|
180
|
+
"image"
|
|
181
|
+
) # expects a base64-encoded image
|
|
182
|
+
else:
|
|
183
|
+
embedding_body["inputText"] = doc
|
|
184
|
+
|
|
185
|
+
# Add model-specific inference parameters
|
|
186
|
+
if model_kwargs:
|
|
187
|
+
embedding_body = embedding_body | model_kwargs
|
|
188
|
+
|
|
189
|
+
# Clean up null values
|
|
190
|
+
embedding_body = {k: v for k, v in embedding_body.items() if v}
|
|
191
|
+
|
|
192
|
+
# Format payload
|
|
193
|
+
embedding_body_payload: str = json.dumps(embedding_body)
|
|
194
|
+
|
|
176
195
|
response = self.client.invoke_model(
|
|
177
|
-
body=
|
|
196
|
+
body=embedding_body_payload,
|
|
178
197
|
modelId=self.name,
|
|
179
198
|
accept="application/json",
|
|
180
199
|
contentType="application/json",
|
|
@@ -184,9 +203,16 @@ class BedrockEncoder(DenseEncoder):
|
|
|
184
203
|
elif self.name and "cohere" in self.name:
|
|
185
204
|
chunked_docs = self.chunk_strings(docs)
|
|
186
205
|
for chunk in chunked_docs:
|
|
187
|
-
chunk =
|
|
188
|
-
|
|
189
|
-
|
|
206
|
+
chunk = {"texts": chunk, "input_type": self.input_type}
|
|
207
|
+
|
|
208
|
+
# Add model-specific inference parameters
|
|
209
|
+
# Note: if specified, input_type will be overwritten by model_kwargs
|
|
210
|
+
if model_kwargs:
|
|
211
|
+
chunk = chunk | model_kwargs
|
|
212
|
+
|
|
213
|
+
# Format payload
|
|
214
|
+
chunk = json.dumps(chunk)
|
|
215
|
+
|
|
190
216
|
response = self.client.invoke_model(
|
|
191
217
|
body=chunk,
|
|
192
218
|
modelId=self.name,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from typing import Any, List, Optional
|
|
2
2
|
|
|
3
3
|
import numpy as np
|
|
4
|
-
from pydantic
|
|
4
|
+
from pydantic import PrivateAttr
|
|
5
5
|
from typing import Dict
|
|
6
6
|
from semantic_router.encoders import DenseEncoder
|
|
7
7
|
|
|
@@ -9,7 +9,6 @@ from semantic_router.encoders import DenseEncoder
|
|
|
9
9
|
class CLIPEncoder(DenseEncoder):
|
|
10
10
|
name: str = "openai/clip-vit-base-patch16"
|
|
11
11
|
type: str = "huggingface"
|
|
12
|
-
score_threshold: float = 0.2
|
|
13
12
|
tokenizer_kwargs: Dict = {}
|
|
14
13
|
processor_kwargs: Dict = {}
|
|
15
14
|
model_kwargs: Dict = {}
|
|
@@ -21,6 +20,8 @@ class CLIPEncoder(DenseEncoder):
|
|
|
21
20
|
_Image: Any = PrivateAttr()
|
|
22
21
|
|
|
23
22
|
def __init__(self, **data):
|
|
23
|
+
if data.get("score_threshold") is None:
|
|
24
|
+
data["score_threshold"] = 0.2
|
|
24
25
|
super().__init__(**data)
|
|
25
26
|
self._tokenizer, self._processor, self._model = self._initialize_hf_model()
|
|
26
27
|
|
{semantic_router-0.1.0.dev2 → semantic_router-0.1.0.dev4}/semantic_router/encoders/huggingface.py
RENAMED
|
@@ -25,7 +25,7 @@ import time
|
|
|
25
25
|
import os
|
|
26
26
|
from typing import Any, List, Optional, Dict
|
|
27
27
|
|
|
28
|
-
from pydantic
|
|
28
|
+
from pydantic import PrivateAttr
|
|
29
29
|
|
|
30
30
|
from semantic_router.encoders import DenseEncoder
|
|
31
31
|
from semantic_router.utils.logger import logger
|
|
@@ -34,7 +34,6 @@ from semantic_router.utils.logger import logger
|
|
|
34
34
|
class HuggingFaceEncoder(DenseEncoder):
|
|
35
35
|
name: str = "sentence-transformers/all-MiniLM-L6-v2"
|
|
36
36
|
type: str = "huggingface"
|
|
37
|
-
score_threshold: float = 0.5
|
|
38
37
|
tokenizer_kwargs: Dict = {}
|
|
39
38
|
model_kwargs: Dict = {}
|
|
40
39
|
device: Optional[str] = None
|
|
@@ -43,6 +42,8 @@ class HuggingFaceEncoder(DenseEncoder):
|
|
|
43
42
|
_torch: Any = PrivateAttr()
|
|
44
43
|
|
|
45
44
|
def __init__(self, **data):
|
|
45
|
+
if data.get("score_threshold") is None:
|
|
46
|
+
data["score_threshold"] = 0.5
|
|
46
47
|
super().__init__(**data)
|
|
47
48
|
self._tokenizer, self._model = self._initialize_hf_model()
|
|
48
49
|
|
|
@@ -153,7 +154,6 @@ class HFEndpointEncoder(DenseEncoder):
|
|
|
153
154
|
name: str = "hugging_face_custom_endpoint"
|
|
154
155
|
huggingface_url: Optional[str] = None
|
|
155
156
|
huggingface_api_key: Optional[str] = None
|
|
156
|
-
score_threshold: float = 0.8
|
|
157
157
|
|
|
158
158
|
def __init__(
|
|
159
159
|
self,
|
|
@@ -180,6 +180,8 @@ class HFEndpointEncoder(DenseEncoder):
|
|
|
180
180
|
"""
|
|
181
181
|
huggingface_url = huggingface_url or os.getenv("HF_API_URL")
|
|
182
182
|
huggingface_api_key = huggingface_api_key or os.getenv("HF_API_KEY")
|
|
183
|
+
if score_threshold is None:
|
|
184
|
+
score_threshold = 0.8
|
|
183
185
|
|
|
184
186
|
super().__init__(name=name, score_threshold=score_threshold) # type: ignore
|
|
185
187
|
|
{semantic_router-0.1.0.dev2 → semantic_router-0.1.0.dev4}/semantic_router/encoders/openai.py
RENAMED
|
@@ -2,7 +2,7 @@ from asyncio import sleep as asleep
|
|
|
2
2
|
import os
|
|
3
3
|
from time import sleep
|
|
4
4
|
from typing import Any, List, Optional, Union
|
|
5
|
-
from pydantic
|
|
5
|
+
from pydantic import PrivateAttr
|
|
6
6
|
|
|
7
7
|
import openai
|
|
8
8
|
from openai import OpenAIError
|
|
@@ -36,8 +36,8 @@ model_configs = {
|
|
|
36
36
|
|
|
37
37
|
|
|
38
38
|
class OpenAIEncoder(DenseEncoder):
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
_client: Optional[openai.Client] = PrivateAttr(default=None)
|
|
40
|
+
_async_client: Optional[openai.AsyncClient] = PrivateAttr(default=None)
|
|
41
41
|
dimensions: Union[int, NotGiven] = NotGiven()
|
|
42
42
|
token_limit: int = 8192 # default value, should be replaced by config
|
|
43
43
|
_token_encoder: Any = PrivateAttr()
|
|
@@ -77,10 +77,10 @@ class OpenAIEncoder(DenseEncoder):
|
|
|
77
77
|
if max_retries is not None:
|
|
78
78
|
self.max_retries = max_retries
|
|
79
79
|
try:
|
|
80
|
-
self.
|
|
80
|
+
self._client = openai.Client(
|
|
81
81
|
base_url=base_url, api_key=api_key, organization=openai_org_id
|
|
82
82
|
)
|
|
83
|
-
self.
|
|
83
|
+
self._async_client = openai.AsyncClient(
|
|
84
84
|
base_url=base_url, api_key=api_key, organization=openai_org_id
|
|
85
85
|
)
|
|
86
86
|
except Exception as e:
|
|
@@ -103,7 +103,7 @@ class OpenAIEncoder(DenseEncoder):
|
|
|
103
103
|
False and a document exceeds the token limit, an error will be
|
|
104
104
|
raised.
|
|
105
105
|
:return: List of embeddings for each document."""
|
|
106
|
-
if self.
|
|
106
|
+
if self._client is None:
|
|
107
107
|
raise ValueError("OpenAI client is not initialized.")
|
|
108
108
|
embeds = None
|
|
109
109
|
|
|
@@ -114,7 +114,7 @@ class OpenAIEncoder(DenseEncoder):
|
|
|
114
114
|
# Exponential backoff
|
|
115
115
|
for j in range(self.max_retries + 1):
|
|
116
116
|
try:
|
|
117
|
-
embeds = self.
|
|
117
|
+
embeds = self._client.embeddings.create(
|
|
118
118
|
input=docs,
|
|
119
119
|
model=self.name,
|
|
120
120
|
dimensions=self.dimensions,
|
|
@@ -160,7 +160,7 @@ class OpenAIEncoder(DenseEncoder):
|
|
|
160
160
|
return text
|
|
161
161
|
|
|
162
162
|
async def acall(self, docs: List[str], truncate: bool = True) -> List[List[float]]:
|
|
163
|
-
if self.
|
|
163
|
+
if self._async_client is None:
|
|
164
164
|
raise ValueError("OpenAI async client is not initialized.")
|
|
165
165
|
embeds = None
|
|
166
166
|
|
|
@@ -171,7 +171,7 @@ class OpenAIEncoder(DenseEncoder):
|
|
|
171
171
|
# Exponential backoff
|
|
172
172
|
for j in range(self.max_retries + 1):
|
|
173
173
|
try:
|
|
174
|
-
embeds = await self.
|
|
174
|
+
embeds = await self._async_client.embeddings.create(
|
|
175
175
|
input=docs,
|
|
176
176
|
model=self.name,
|
|
177
177
|
dimensions=self.dimensions,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
from typing import Any, List, Optional
|
|
1
|
+
from typing import Any, Dict, List, Optional
|
|
2
2
|
|
|
3
|
-
from pydantic
|
|
3
|
+
from pydantic import PrivateAttr
|
|
4
4
|
|
|
5
5
|
from semantic_router.encoders import DenseEncoder
|
|
6
6
|
|
|
@@ -8,7 +8,6 @@ from semantic_router.encoders import DenseEncoder
|
|
|
8
8
|
class VitEncoder(DenseEncoder):
|
|
9
9
|
name: str = "google/vit-base-patch16-224"
|
|
10
10
|
type: str = "huggingface"
|
|
11
|
-
score_threshold: float = 0.5
|
|
12
11
|
processor_kwargs: Dict = {}
|
|
13
12
|
model_kwargs: Dict = {}
|
|
14
13
|
device: Optional[str] = None
|
|
@@ -19,6 +18,8 @@ class VitEncoder(DenseEncoder):
|
|
|
19
18
|
_Image: Any = PrivateAttr()
|
|
20
19
|
|
|
21
20
|
def __init__(self, **data):
|
|
21
|
+
if data.get("score_threshold") is None:
|
|
22
|
+
data["score_threshold"] = 0.5
|
|
22
23
|
super().__init__(**data)
|
|
23
24
|
self._processor, self._model = self._initialize_hf_model()
|
|
24
25
|
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
import time
|
|
1
3
|
from typing import Any, List, Optional, Tuple, Union, Dict
|
|
2
4
|
import json
|
|
3
5
|
|
|
4
6
|
import numpy as np
|
|
5
|
-
from pydantic
|
|
7
|
+
from pydantic import BaseModel
|
|
6
8
|
|
|
7
9
|
from semantic_router.schema import ConfigParameter, SparseEmbedding, Utterance
|
|
8
10
|
from semantic_router.route import Route
|
|
@@ -157,26 +159,91 @@ class BaseIndex(BaseModel):
|
|
|
157
159
|
logger.warning("This method should be implemented by subclasses.")
|
|
158
160
|
self.index = None
|
|
159
161
|
|
|
160
|
-
def
|
|
161
|
-
"""
|
|
162
|
-
Read the hash of the previously written index.
|
|
162
|
+
def _read_config(self, field: str, scope: str | None = None) -> ConfigParameter:
|
|
163
|
+
"""Read a config parameter from the index.
|
|
163
164
|
|
|
164
|
-
|
|
165
|
+
:param field: The field to read.
|
|
166
|
+
:type field: str
|
|
167
|
+
:param scope: The scope to read.
|
|
168
|
+
:type scope: str | None
|
|
169
|
+
:return: The config parameter that was read.
|
|
170
|
+
:rtype: ConfigParameter
|
|
165
171
|
"""
|
|
166
172
|
logger.warning("This method should be implemented by subclasses.")
|
|
167
173
|
return ConfigParameter(
|
|
168
|
-
field=
|
|
174
|
+
field=field,
|
|
169
175
|
value="",
|
|
170
|
-
|
|
176
|
+
scope=scope,
|
|
171
177
|
)
|
|
172
178
|
|
|
173
|
-
def
|
|
179
|
+
def _read_hash(self) -> ConfigParameter:
|
|
180
|
+
"""Read the hash of the previously written index.
|
|
181
|
+
|
|
182
|
+
:return: The config parameter that was read.
|
|
183
|
+
:rtype: ConfigParameter
|
|
174
184
|
"""
|
|
175
|
-
|
|
185
|
+
return self._read_config(field="sr_hash")
|
|
176
186
|
|
|
177
|
-
|
|
187
|
+
def _write_config(self, config: ConfigParameter) -> ConfigParameter:
|
|
188
|
+
"""Write a config parameter to the index.
|
|
189
|
+
|
|
190
|
+
:param config: The config parameter to write.
|
|
191
|
+
:type config: ConfigParameter
|
|
192
|
+
:return: The config parameter that was written.
|
|
193
|
+
:rtype: ConfigParameter
|
|
178
194
|
"""
|
|
179
195
|
logger.warning("This method should be implemented by subclasses.")
|
|
196
|
+
return config
|
|
197
|
+
|
|
198
|
+
def lock(
|
|
199
|
+
self, value: bool, wait: int = 0, scope: str | None = None
|
|
200
|
+
) -> ConfigParameter:
|
|
201
|
+
"""Lock/unlock the index for a given scope (if applicable). If index
|
|
202
|
+
already locked/unlocked, raises ValueError.
|
|
203
|
+
|
|
204
|
+
:param scope: The scope to lock.
|
|
205
|
+
:type scope: str | None
|
|
206
|
+
:param wait: The number of seconds to wait for the index to be unlocked, if
|
|
207
|
+
set to 0, will raise an error if index is already locked/unlocked.
|
|
208
|
+
:type wait: int
|
|
209
|
+
:return: The config parameter that was locked.
|
|
210
|
+
:rtype: ConfigParameter
|
|
211
|
+
"""
|
|
212
|
+
start_time = datetime.now()
|
|
213
|
+
while True:
|
|
214
|
+
if self._is_locked(scope=scope) != value:
|
|
215
|
+
# in this case, we can set the lock value
|
|
216
|
+
break
|
|
217
|
+
if (datetime.now() - start_time).total_seconds() < wait:
|
|
218
|
+
# wait for 2.5 seconds before checking again
|
|
219
|
+
time.sleep(2.5)
|
|
220
|
+
else:
|
|
221
|
+
raise ValueError(
|
|
222
|
+
f"Index is already {'locked' if value else 'unlocked'}."
|
|
223
|
+
)
|
|
224
|
+
lock_param = ConfigParameter(
|
|
225
|
+
field="sr_lock",
|
|
226
|
+
value=str(value),
|
|
227
|
+
scope=scope,
|
|
228
|
+
)
|
|
229
|
+
self._write_config(lock_param)
|
|
230
|
+
return lock_param
|
|
231
|
+
|
|
232
|
+
def _is_locked(self, scope: str | None = None) -> bool:
|
|
233
|
+
"""Check if the index is locked for a given scope (if applicable).
|
|
234
|
+
|
|
235
|
+
:param scope: The scope to check.
|
|
236
|
+
:type scope: str | None
|
|
237
|
+
:return: True if the index is locked, False otherwise.
|
|
238
|
+
:rtype: bool
|
|
239
|
+
"""
|
|
240
|
+
lock_config = self._read_config(field="sr_lock", scope=scope)
|
|
241
|
+
if lock_config.value == "True":
|
|
242
|
+
return True
|
|
243
|
+
elif lock_config.value == "False" or not lock_config.value:
|
|
244
|
+
return False
|
|
245
|
+
else:
|
|
246
|
+
raise ValueError(f"Invalid lock value: {lock_config.value}")
|
|
180
247
|
|
|
181
248
|
def _get_all(self, prefix: Optional[str] = None, include_metadata: bool = False):
|
|
182
249
|
"""
|
|
@@ -8,7 +8,7 @@ import json
|
|
|
8
8
|
from typing import Any, Dict, List, Optional, Union, Tuple
|
|
9
9
|
|
|
10
10
|
import numpy as np
|
|
11
|
-
from pydantic
|
|
11
|
+
from pydantic import BaseModel, Field
|
|
12
12
|
|
|
13
13
|
from semantic_router.index.base import BaseIndex
|
|
14
14
|
from semantic_router.schema import ConfigParameter, SparseEmbedding
|
|
@@ -405,39 +405,43 @@ class PineconeIndex(BaseIndex):
|
|
|
405
405
|
route_names = [result["metadata"]["sr_route"] for result in results["matches"]]
|
|
406
406
|
return np.array(scores), route_names
|
|
407
407
|
|
|
408
|
-
def
|
|
408
|
+
def _read_config(self, field: str, scope: str | None = None) -> ConfigParameter:
|
|
409
|
+
scope = scope or self.namespace
|
|
409
410
|
if self.index is None:
|
|
410
411
|
return ConfigParameter(
|
|
411
|
-
field=
|
|
412
|
+
field=field,
|
|
412
413
|
value="",
|
|
413
|
-
|
|
414
|
+
scope=scope,
|
|
414
415
|
)
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
ids=[
|
|
416
|
+
config_id = f"{field}#{scope}"
|
|
417
|
+
config_record = self.index.fetch(
|
|
418
|
+
ids=[config_id],
|
|
418
419
|
namespace="sr_config",
|
|
419
420
|
)
|
|
420
|
-
if
|
|
421
|
+
if config_record["vectors"]:
|
|
421
422
|
return ConfigParameter(
|
|
422
|
-
field=
|
|
423
|
-
value=
|
|
424
|
-
created_at=
|
|
425
|
-
|
|
423
|
+
field=field,
|
|
424
|
+
value=config_record["vectors"][config_id]["metadata"]["value"],
|
|
425
|
+
created_at=config_record["vectors"][config_id]["metadata"][
|
|
426
|
+
"created_at"
|
|
427
|
+
],
|
|
428
|
+
scope=scope,
|
|
426
429
|
)
|
|
427
430
|
else:
|
|
428
|
-
logger.warning("Configuration for
|
|
431
|
+
logger.warning(f"Configuration for {field} parameter not found in index.")
|
|
429
432
|
return ConfigParameter(
|
|
430
|
-
field=
|
|
433
|
+
field=field,
|
|
431
434
|
value="",
|
|
432
|
-
|
|
435
|
+
scope=scope,
|
|
433
436
|
)
|
|
434
437
|
|
|
435
|
-
def _write_config(self, config: ConfigParameter) ->
|
|
438
|
+
def _write_config(self, config: ConfigParameter) -> ConfigParameter:
|
|
436
439
|
"""Method to write a config parameter to the remote Pinecone index.
|
|
437
440
|
|
|
438
441
|
:param config: The config parameter to write to the index.
|
|
439
442
|
:type config: ConfigParameter
|
|
440
443
|
"""
|
|
444
|
+
config.scope = config.scope or self.namespace
|
|
441
445
|
if self.index is None:
|
|
442
446
|
raise ValueError("Index has not been initialized.")
|
|
443
447
|
if self.dimensions is None:
|
|
@@ -446,6 +450,7 @@ class PineconeIndex(BaseIndex):
|
|
|
446
450
|
vectors=[config.to_pinecone(dimensions=self.dimensions)],
|
|
447
451
|
namespace="sr_config",
|
|
448
452
|
)
|
|
453
|
+
return config
|
|
449
454
|
|
|
450
455
|
async def aquery(
|
|
451
456
|
self,
|
|
@@ -103,7 +103,6 @@ class PostgresIndex(BaseIndex):
|
|
|
103
103
|
connection_string: Optional[str] = None
|
|
104
104
|
index_prefix: str = "semantic_router_"
|
|
105
105
|
index_name: str = "index"
|
|
106
|
-
dimensions: int = 1536
|
|
107
106
|
metric: Metric = Metric.COSINE
|
|
108
107
|
namespace: Optional[str] = ""
|
|
109
108
|
conn: Optional["psycopg2.extensions.connection"] = None
|
|
@@ -115,9 +114,9 @@ class PostgresIndex(BaseIndex):
|
|
|
115
114
|
connection_string: Optional[str] = None,
|
|
116
115
|
index_prefix: str = "semantic_router_",
|
|
117
116
|
index_name: str = "index",
|
|
118
|
-
dimensions: int = 1536,
|
|
119
117
|
metric: Metric = Metric.COSINE,
|
|
120
118
|
namespace: Optional[str] = "",
|
|
119
|
+
dimensions: int | None = None,
|
|
121
120
|
):
|
|
122
121
|
"""
|
|
123
122
|
Initializes the Postgres index with the specified parameters.
|
|
@@ -135,6 +134,8 @@ class PostgresIndex(BaseIndex):
|
|
|
135
134
|
:param namespace: An optional namespace for the index.
|
|
136
135
|
:type namespace: Optional[str]
|
|
137
136
|
"""
|
|
137
|
+
if dimensions is None:
|
|
138
|
+
dimensions = 1536
|
|
138
139
|
super().__init__()
|
|
139
140
|
# try and import psycopg2
|
|
140
141
|
try:
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from typing import Any, Dict, List, Optional, Tuple, Union
|
|
2
2
|
|
|
3
3
|
import numpy as np
|
|
4
|
-
from pydantic
|
|
4
|
+
from pydantic import Field
|
|
5
5
|
|
|
6
6
|
from semantic_router.index.base import BaseIndex
|
|
7
7
|
from semantic_router.schema import ConfigParameter, Metric, SparseEmbedding, Utterance
|
|
@@ -40,7 +40,7 @@ class QdrantIndex(BaseIndex):
|
|
|
40
40
|
default=6334,
|
|
41
41
|
description="Port of the gRPC interface.",
|
|
42
42
|
)
|
|
43
|
-
prefer_grpc: bool = Field(
|
|
43
|
+
prefer_grpc: Optional[bool] = Field(
|
|
44
44
|
default=None,
|
|
45
45
|
description="Whether to use gPRC interface whenever possible in methods",
|
|
46
46
|
)
|