semantic-router 0.1.0.dev0__tar.gz → 0.1.0.dev2__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.dev0 → semantic_router-0.1.0.dev2}/PKG-INFO +5 -5
- {semantic_router-0.1.0.dev0 → semantic_router-0.1.0.dev2}/pyproject.toml +7 -6
- semantic_router-0.1.0.dev2/semantic_router/__init__.py +6 -0
- {semantic_router-0.1.0.dev0 → semantic_router-0.1.0.dev2}/semantic_router/encoders/__init__.py +10 -5
- semantic_router-0.1.0.dev2/semantic_router/encoders/aurelio.py +47 -0
- semantic_router-0.1.0.dev2/semantic_router/encoders/base.py +53 -0
- {semantic_router-0.1.0.dev0 → semantic_router-0.1.0.dev2}/semantic_router/encoders/bedrock.py +3 -3
- {semantic_router-0.1.0.dev0 → semantic_router-0.1.0.dev2}/semantic_router/encoders/bm25.py +26 -20
- {semantic_router-0.1.0.dev0 → semantic_router-0.1.0.dev2}/semantic_router/encoders/clip.py +2 -2
- {semantic_router-0.1.0.dev0 → semantic_router-0.1.0.dev2}/semantic_router/encoders/cohere.py +2 -2
- {semantic_router-0.1.0.dev0 → semantic_router-0.1.0.dev2}/semantic_router/encoders/fastembed.py +2 -2
- {semantic_router-0.1.0.dev0 → semantic_router-0.1.0.dev2}/semantic_router/encoders/google.py +3 -3
- {semantic_router-0.1.0.dev0 → semantic_router-0.1.0.dev2}/semantic_router/encoders/huggingface.py +4 -4
- {semantic_router-0.1.0.dev0 → semantic_router-0.1.0.dev2}/semantic_router/encoders/mistral.py +2 -2
- {semantic_router-0.1.0.dev0 → semantic_router-0.1.0.dev2}/semantic_router/encoders/openai.py +2 -2
- {semantic_router-0.1.0.dev0 → semantic_router-0.1.0.dev2}/semantic_router/encoders/tfidf.py +24 -11
- {semantic_router-0.1.0.dev0 → semantic_router-0.1.0.dev2}/semantic_router/encoders/vit.py +2 -2
- {semantic_router-0.1.0.dev0 → semantic_router-0.1.0.dev2}/semantic_router/encoders/zure.py +2 -2
- {semantic_router-0.1.0.dev0 → semantic_router-0.1.0.dev2}/semantic_router/index/__init__.py +4 -0
- {semantic_router-0.1.0.dev0 → semantic_router-0.1.0.dev2}/semantic_router/index/base.py +4 -2
- semantic_router-0.1.0.dev2/semantic_router/index/hybrid_local.py +212 -0
- {semantic_router-0.1.0.dev0 → semantic_router-0.1.0.dev2}/semantic_router/index/local.py +27 -11
- {semantic_router-0.1.0.dev0 → semantic_router-0.1.0.dev2}/semantic_router/index/pinecone.py +63 -28
- {semantic_router-0.1.0.dev0 → semantic_router-0.1.0.dev2}/semantic_router/index/postgres.py +17 -5
- {semantic_router-0.1.0.dev0 → semantic_router-0.1.0.dev2}/semantic_router/index/qdrant.py +3 -1
- semantic_router-0.1.0.dev2/semantic_router/routers/__init__.py +10 -0
- semantic_router-0.1.0.dev0/semantic_router/layer.py → semantic_router-0.1.0.dev2/semantic_router/routers/base.py +268 -219
- semantic_router-0.1.0.dev2/semantic_router/routers/hybrid.py +254 -0
- semantic_router-0.1.0.dev2/semantic_router/routers/semantic.py +87 -0
- {semantic_router-0.1.0.dev0 → semantic_router-0.1.0.dev2}/semantic_router/schema.py +65 -0
- semantic_router-0.1.0.dev0/semantic_router/__init__.py +0 -7
- semantic_router-0.1.0.dev0/semantic_router/encoders/base.py +0 -22
- semantic_router-0.1.0.dev0/semantic_router/hybrid_layer.py +0 -220
- {semantic_router-0.1.0.dev0 → semantic_router-0.1.0.dev2}/LICENSE +0 -0
- {semantic_router-0.1.0.dev0 → semantic_router-0.1.0.dev2}/README.md +0 -0
- {semantic_router-0.1.0.dev0 → semantic_router-0.1.0.dev2}/semantic_router/linear.py +0 -0
- {semantic_router-0.1.0.dev0 → semantic_router-0.1.0.dev2}/semantic_router/llms/__init__.py +0 -0
- {semantic_router-0.1.0.dev0 → semantic_router-0.1.0.dev2}/semantic_router/llms/base.py +0 -0
- {semantic_router-0.1.0.dev0 → semantic_router-0.1.0.dev2}/semantic_router/llms/cohere.py +0 -0
- {semantic_router-0.1.0.dev0 → semantic_router-0.1.0.dev2}/semantic_router/llms/grammars/json.gbnf +0 -0
- {semantic_router-0.1.0.dev0 → semantic_router-0.1.0.dev2}/semantic_router/llms/llamacpp.py +0 -0
- {semantic_router-0.1.0.dev0 → semantic_router-0.1.0.dev2}/semantic_router/llms/mistral.py +0 -0
- {semantic_router-0.1.0.dev0 → semantic_router-0.1.0.dev2}/semantic_router/llms/ollama.py +0 -0
- {semantic_router-0.1.0.dev0 → semantic_router-0.1.0.dev2}/semantic_router/llms/openai.py +0 -0
- {semantic_router-0.1.0.dev0 → semantic_router-0.1.0.dev2}/semantic_router/llms/openrouter.py +0 -0
- {semantic_router-0.1.0.dev0 → semantic_router-0.1.0.dev2}/semantic_router/llms/zure.py +0 -0
- {semantic_router-0.1.0.dev0 → semantic_router-0.1.0.dev2}/semantic_router/route.py +0 -0
- {semantic_router-0.1.0.dev0 → semantic_router-0.1.0.dev2}/semantic_router/utils/__init__.py +0 -0
- {semantic_router-0.1.0.dev0 → semantic_router-0.1.0.dev2}/semantic_router/utils/defaults.py +0 -0
- {semantic_router-0.1.0.dev0 → semantic_router-0.1.0.dev2}/semantic_router/utils/function_call.py +0 -0
- {semantic_router-0.1.0.dev0 → semantic_router-0.1.0.dev2}/semantic_router/utils/llm.py +0 -0
- {semantic_router-0.1.0.dev0 → semantic_router-0.1.0.dev2}/semantic_router/utils/logger.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: semantic-router
|
|
3
|
-
Version: 0.1.0.
|
|
3
|
+
Version: 0.1.0.dev2
|
|
4
4
|
Summary: Super fast semantic router for AI decision making
|
|
5
5
|
License: MIT
|
|
6
6
|
Author: Aurelio AI
|
|
@@ -21,10 +21,10 @@ Provides-Extra: local
|
|
|
21
21
|
Provides-Extra: mistralai
|
|
22
22
|
Provides-Extra: pinecone
|
|
23
23
|
Provides-Extra: postgres
|
|
24
|
-
Provides-Extra: processing
|
|
25
24
|
Provides-Extra: qdrant
|
|
26
25
|
Provides-Extra: vision
|
|
27
|
-
Requires-Dist: aiohttp (>=3.
|
|
26
|
+
Requires-Dist: aiohttp (>=3.10.11,<4.0.0)
|
|
27
|
+
Requires-Dist: aurelio-sdk (>=0.0.16,<0.0.17)
|
|
28
28
|
Requires-Dist: boto3 (>=1.34.98,<2.0.0) ; extra == "bedrock"
|
|
29
29
|
Requires-Dist: botocore (>=1.34.110,<2.0.0) ; extra == "bedrock"
|
|
30
30
|
Requires-Dist: cohere (>=5.9.4,<6.00) ; extra == "cohere"
|
|
@@ -33,14 +33,13 @@ Requires-Dist: colorlog (>=6.8.0,<7.0.0)
|
|
|
33
33
|
Requires-Dist: fastembed (>=0.3.0,<0.4.0) ; extra == "fastembed"
|
|
34
34
|
Requires-Dist: google-cloud-aiplatform (>=1.45.0,<2.0.0) ; extra == "google"
|
|
35
35
|
Requires-Dist: llama-cpp-python (>=0.2.28,<0.2.86) ; extra == "local"
|
|
36
|
-
Requires-Dist: matplotlib (>=3.8.3,<4.0.0) ; extra == "processing"
|
|
37
36
|
Requires-Dist: mistralai (>=0.0.12,<0.1.0) ; extra == "mistralai"
|
|
38
37
|
Requires-Dist: numpy (>=1.25.2,<2.0.0)
|
|
39
38
|
Requires-Dist: openai (>=1.10.0,<2.0.0)
|
|
40
39
|
Requires-Dist: pillow (>=10.2.0,<11.0.0) ; extra == "vision"
|
|
41
40
|
Requires-Dist: pinecone (>=5.0.0) ; extra == "pinecone"
|
|
42
41
|
Requires-Dist: pinecone-text (>=0.7.1,<0.10.0) ; extra == "hybrid"
|
|
43
|
-
Requires-Dist: psycopg2 (>=2.9.9,<3.0.0)
|
|
42
|
+
Requires-Dist: psycopg2-binary (>=2.9.9,<3.0.0)
|
|
44
43
|
Requires-Dist: pydantic (>=2.5.3,<3.0.0)
|
|
45
44
|
Requires-Dist: pyyaml (>=6.0.1,<7.0.0)
|
|
46
45
|
Requires-Dist: qdrant-client (>=1.11.1,<2.0.0) ; extra == "qdrant"
|
|
@@ -52,6 +51,7 @@ Requires-Dist: tiktoken (>=0.6.0,<1.0.0)
|
|
|
52
51
|
Requires-Dist: tokenizers (>=0.19) ; extra == "local"
|
|
53
52
|
Requires-Dist: torch (>=2.1.0,<2.6.0) ; extra == "local" or extra == "vision"
|
|
54
53
|
Requires-Dist: torchvision (>=0.17.0,<0.18.0) ; extra == "vision"
|
|
54
|
+
Requires-Dist: tornado (>=6.4.2,<7.0.0)
|
|
55
55
|
Requires-Dist: transformers (>=4.36.2) ; extra == "local" or extra == "vision"
|
|
56
56
|
Description-Content-Type: text/markdown
|
|
57
57
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "semantic-router"
|
|
3
|
-
version = "0.1.0.
|
|
3
|
+
version = "0.1.0.dev2"
|
|
4
4
|
description = "Super fast semantic router for AI decision making"
|
|
5
5
|
authors = ["Aurelio AI <hello@aurelio.ai>"]
|
|
6
6
|
readme = "README.md"
|
|
@@ -16,6 +16,7 @@ mistralai= {version = ">=0.0.12,<0.1.0", optional = true}
|
|
|
16
16
|
numpy = "^1.25.2"
|
|
17
17
|
colorlog = "^6.8.0"
|
|
18
18
|
pyyaml = "^6.0.1"
|
|
19
|
+
aurelio-sdk = {version = "^0.0.16"}
|
|
19
20
|
pinecone-text = {version = ">=0.7.1,<0.10.0", optional = true}
|
|
20
21
|
torch = {version = ">=2.1.0,<2.6.0", optional = true}
|
|
21
22
|
transformers = {version = ">=4.36.2", optional = true}
|
|
@@ -27,24 +28,23 @@ regex = ">=2023.12.25"
|
|
|
27
28
|
torchvision = { version = ">=0.17.0,<0.18.0", optional = true}
|
|
28
29
|
pillow = { version = ">=10.2.0,<11.0.0", optional = true}
|
|
29
30
|
tiktoken = ">=0.6.0,<1.0.0"
|
|
30
|
-
matplotlib = { version = "^3.8.3", optional = true}
|
|
31
31
|
qdrant-client = {version = "^1.11.1", optional = true}
|
|
32
32
|
google-cloud-aiplatform = {version = "^1.45.0", optional = true}
|
|
33
33
|
requests-mock = "^1.12.1"
|
|
34
34
|
boto3 = { version = "^1.34.98", optional = true }
|
|
35
35
|
botocore = {version = "^1.34.110", optional = true}
|
|
36
|
-
aiohttp = "^3.
|
|
36
|
+
aiohttp = "^3.10.11"
|
|
37
37
|
fastembed = {version = "^0.3.0", optional = true}
|
|
38
|
-
psycopg2 = {version = "^2.9.9", optional = true}
|
|
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}
|
|
41
|
+
tornado = {version = "^6.4.2", optional = true}
|
|
41
42
|
|
|
42
43
|
[tool.poetry.extras]
|
|
43
44
|
hybrid = ["pinecone-text"]
|
|
44
45
|
local = ["torch", "transformers", "tokenizers", "huggingface-hub", "llama-cpp-python"]
|
|
45
46
|
pinecone = ["pinecone"]
|
|
46
47
|
vision = ["torch", "torchvision", "transformers", "pillow"]
|
|
47
|
-
processing = ["matplotlib"]
|
|
48
48
|
mistralai = ["mistralai"]
|
|
49
49
|
qdrant = ["qdrant-client"]
|
|
50
50
|
google = ["google-cloud-aiplatform"]
|
|
@@ -57,10 +57,11 @@ cohere = ["cohere"]
|
|
|
57
57
|
[tool.poetry.group.dev.dependencies]
|
|
58
58
|
ipykernel = "^6.25.0"
|
|
59
59
|
ruff = "^0.1.5"
|
|
60
|
-
pytest = "^
|
|
60
|
+
pytest = "^8.2"
|
|
61
61
|
pytest-mock = "^3.12.0"
|
|
62
62
|
pytest-cov = "^4.1.0"
|
|
63
63
|
pytest-xdist = "^3.5.0"
|
|
64
|
+
pytest-asyncio = "^0.24.0"
|
|
64
65
|
mypy = "^1.7.1"
|
|
65
66
|
types-pyyaml = "^6.0.12.12"
|
|
66
67
|
types-requests = "^2.31.0"
|
{semantic_router-0.1.0.dev0 → semantic_router-0.1.0.dev2}/semantic_router/encoders/__init__.py
RENAMED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from typing import List, Optional
|
|
2
2
|
|
|
3
|
-
from semantic_router.encoders.
|
|
3
|
+
from semantic_router.encoders.aurelio import AurelioSparseEncoder
|
|
4
|
+
from semantic_router.encoders.base import DenseEncoder, SparseEncoder
|
|
4
5
|
from semantic_router.encoders.bedrock import BedrockEncoder
|
|
5
6
|
from semantic_router.encoders.bm25 import BM25Encoder
|
|
6
7
|
from semantic_router.encoders.clip import CLIPEncoder
|
|
@@ -14,10 +15,12 @@ from semantic_router.encoders.openai import OpenAIEncoder
|
|
|
14
15
|
from semantic_router.encoders.tfidf import TfidfEncoder
|
|
15
16
|
from semantic_router.encoders.vit import VitEncoder
|
|
16
17
|
from semantic_router.encoders.zure import AzureOpenAIEncoder
|
|
17
|
-
from semantic_router.schema import EncoderType
|
|
18
|
+
from semantic_router.schema import EncoderType, SparseEmbedding
|
|
18
19
|
|
|
19
20
|
__all__ = [
|
|
20
|
-
"
|
|
21
|
+
"AurelioSparseEncoder",
|
|
22
|
+
"DenseEncoder",
|
|
23
|
+
"SparseEncoder",
|
|
21
24
|
"AzureOpenAIEncoder",
|
|
22
25
|
"CohereEncoder",
|
|
23
26
|
"OpenAIEncoder",
|
|
@@ -37,7 +40,7 @@ __all__ = [
|
|
|
37
40
|
class AutoEncoder:
|
|
38
41
|
type: EncoderType
|
|
39
42
|
name: Optional[str]
|
|
40
|
-
model:
|
|
43
|
+
model: DenseEncoder | SparseEncoder
|
|
41
44
|
|
|
42
45
|
def __init__(self, type: str, name: Optional[str]):
|
|
43
46
|
self.type = EncoderType(type)
|
|
@@ -49,6 +52,8 @@ class AutoEncoder:
|
|
|
49
52
|
self.model = CohereEncoder(name=name)
|
|
50
53
|
elif self.type == EncoderType.OPENAI:
|
|
51
54
|
self.model = OpenAIEncoder(name=name)
|
|
55
|
+
elif self.type == EncoderType.AURELIO:
|
|
56
|
+
self.model = AurelioSparseEncoder(name=name)
|
|
52
57
|
elif self.type == EncoderType.BM25:
|
|
53
58
|
if name is None:
|
|
54
59
|
name = "bm25"
|
|
@@ -74,5 +79,5 @@ class AutoEncoder:
|
|
|
74
79
|
else:
|
|
75
80
|
raise ValueError(f"Encoder type '{type}' not supported")
|
|
76
81
|
|
|
77
|
-
def __call__(self, texts: List[str]) -> List[List[float]]:
|
|
82
|
+
def __call__(self, texts: List[str]) -> List[List[float]] | List[SparseEmbedding]:
|
|
78
83
|
return self.model(texts)
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from typing import Any, List, Optional
|
|
3
|
+
from pydantic.v1 import Field
|
|
4
|
+
|
|
5
|
+
from aurelio_sdk import AurelioClient, AsyncAurelioClient, EmbeddingResponse
|
|
6
|
+
|
|
7
|
+
from semantic_router.encoders.base import SparseEncoder
|
|
8
|
+
from semantic_router.schema import SparseEmbedding
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class AurelioSparseEncoder(SparseEncoder):
|
|
12
|
+
model: Optional[Any] = None
|
|
13
|
+
client: AurelioClient = Field(default_factory=AurelioClient, exclude=True)
|
|
14
|
+
async_client: AsyncAurelioClient = Field(
|
|
15
|
+
default_factory=AsyncAurelioClient, exclude=True
|
|
16
|
+
)
|
|
17
|
+
type: str = "sparse"
|
|
18
|
+
|
|
19
|
+
def __init__(
|
|
20
|
+
self,
|
|
21
|
+
name: str | None = None,
|
|
22
|
+
api_key: Optional[str] = None,
|
|
23
|
+
):
|
|
24
|
+
if name is None:
|
|
25
|
+
name = "bm25"
|
|
26
|
+
super().__init__(name=name)
|
|
27
|
+
if api_key is None:
|
|
28
|
+
api_key = os.getenv("AURELIO_API_KEY")
|
|
29
|
+
if api_key is None:
|
|
30
|
+
raise ValueError("AURELIO_API_KEY environment variable is not set.")
|
|
31
|
+
self.client = AurelioClient(api_key=api_key)
|
|
32
|
+
self.async_client = AsyncAurelioClient(api_key=api_key)
|
|
33
|
+
|
|
34
|
+
def __call__(self, docs: list[str]) -> list[SparseEmbedding]:
|
|
35
|
+
res: EmbeddingResponse = self.client.embedding(input=docs, model=self.name)
|
|
36
|
+
embeds = [SparseEmbedding.from_aurelio(r.embedding) for r in res.data]
|
|
37
|
+
return embeds
|
|
38
|
+
|
|
39
|
+
async def acall(self, docs: list[str]) -> list[SparseEmbedding]:
|
|
40
|
+
res: EmbeddingResponse = await self.async_client.embedding(
|
|
41
|
+
input=docs, model=self.name
|
|
42
|
+
)
|
|
43
|
+
embeds = [SparseEmbedding.from_aurelio(r.embedding) for r in res.data]
|
|
44
|
+
return embeds
|
|
45
|
+
|
|
46
|
+
def fit(self, docs: List[str]):
|
|
47
|
+
raise NotImplementedError("AurelioSparseEncoder does not support fit.")
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
from typing import Any, Coroutine, List, Optional
|
|
2
|
+
|
|
3
|
+
from pydantic.v1 import BaseModel, Field, validator
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
6
|
+
from semantic_router.schema import SparseEmbedding
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class DenseEncoder(BaseModel):
|
|
10
|
+
name: str
|
|
11
|
+
score_threshold: Optional[float] = None
|
|
12
|
+
type: str = Field(default="base")
|
|
13
|
+
|
|
14
|
+
class Config:
|
|
15
|
+
arbitrary_types_allowed = True
|
|
16
|
+
|
|
17
|
+
@validator("score_threshold", pre=True, always=True)
|
|
18
|
+
def set_score_threshold(cls, v):
|
|
19
|
+
return float(v) if v is not None else None
|
|
20
|
+
|
|
21
|
+
def __call__(self, docs: List[Any]) -> List[List[float]]:
|
|
22
|
+
raise NotImplementedError("Subclasses must implement this method")
|
|
23
|
+
|
|
24
|
+
def acall(self, docs: List[Any]) -> Coroutine[Any, Any, List[List[float]]]:
|
|
25
|
+
raise NotImplementedError("Subclasses must implement this method")
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class SparseEncoder(BaseModel):
|
|
29
|
+
name: str
|
|
30
|
+
type: str = Field(default="base")
|
|
31
|
+
|
|
32
|
+
class Config:
|
|
33
|
+
arbitrary_types_allowed = True
|
|
34
|
+
|
|
35
|
+
def __call__(self, docs: List[str]) -> List[SparseEmbedding]:
|
|
36
|
+
raise NotImplementedError("Subclasses must implement this method")
|
|
37
|
+
|
|
38
|
+
async def acall(self, docs: List[str]) -> list[SparseEmbedding]:
|
|
39
|
+
raise NotImplementedError("Subclasses must implement this method")
|
|
40
|
+
|
|
41
|
+
def _array_to_sparse_embeddings(
|
|
42
|
+
self, sparse_arrays: np.ndarray
|
|
43
|
+
) -> List[SparseEmbedding]:
|
|
44
|
+
"""Consumes several sparse vectors containing zero-values and returns a compact array."""
|
|
45
|
+
if sparse_arrays.ndim != 2:
|
|
46
|
+
raise ValueError(f"Expected a 2D array, got a {sparse_arrays.ndim}D array.")
|
|
47
|
+
# get coordinates of non-zero values
|
|
48
|
+
coords = np.nonzero(sparse_arrays)
|
|
49
|
+
# create compact array
|
|
50
|
+
compact_array = np.array([coords[0], coords[1], sparse_arrays[coords]]).T
|
|
51
|
+
arr_range = range(compact_array[:, 0].max().astype(int) + 1)
|
|
52
|
+
arrs = [compact_array[compact_array[:, 0] == i, :][:, 1:3] for i in arr_range]
|
|
53
|
+
return [SparseEmbedding.from_compact_array(arr) for arr in arrs]
|
{semantic_router-0.1.0.dev0 → semantic_router-0.1.0.dev2}/semantic_router/encoders/bedrock.py
RENAMED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""
|
|
2
2
|
This module provides the BedrockEncoder class for generating embeddings using Amazon's Bedrock Platform.
|
|
3
3
|
|
|
4
|
-
The BedrockEncoder class is a subclass of
|
|
4
|
+
The BedrockEncoder class is a subclass of DenseEncoder and utilizes the TextEmbeddingModel from the
|
|
5
5
|
Amazon's Bedrock Platform to generate embeddings for given documents. It requires an AWS Access Key ID
|
|
6
6
|
and AWS Secret Access Key and supports customization of the pre-trained model, score threshold, and region.
|
|
7
7
|
|
|
@@ -21,12 +21,12 @@ from typing import List, Optional, Any
|
|
|
21
21
|
import os
|
|
22
22
|
from time import sleep
|
|
23
23
|
import tiktoken
|
|
24
|
-
from semantic_router.encoders import
|
|
24
|
+
from semantic_router.encoders import DenseEncoder
|
|
25
25
|
from semantic_router.utils.defaults import EncoderDefault
|
|
26
26
|
from semantic_router.utils.logger import logger
|
|
27
27
|
|
|
28
28
|
|
|
29
|
-
class BedrockEncoder(
|
|
29
|
+
class BedrockEncoder(DenseEncoder):
|
|
30
30
|
client: Any = None
|
|
31
31
|
type: str = "bedrock"
|
|
32
32
|
input_type: Optional[str] = "search_query"
|
|
@@ -1,21 +1,24 @@
|
|
|
1
1
|
from typing import Any, Dict, List, Optional
|
|
2
2
|
|
|
3
|
-
from semantic_router.encoders import
|
|
3
|
+
from semantic_router.encoders.tfidf import TfidfEncoder
|
|
4
4
|
from semantic_router.utils.logger import logger
|
|
5
|
+
from semantic_router.schema import SparseEmbedding
|
|
6
|
+
from semantic_router.route import Route
|
|
5
7
|
|
|
6
8
|
|
|
7
|
-
class BM25Encoder(
|
|
9
|
+
class BM25Encoder(TfidfEncoder):
|
|
8
10
|
model: Optional[Any] = None
|
|
9
11
|
idx_mapping: Optional[Dict[int, int]] = None
|
|
10
12
|
type: str = "sparse"
|
|
11
13
|
|
|
12
14
|
def __init__(
|
|
13
15
|
self,
|
|
14
|
-
name: str =
|
|
15
|
-
score_threshold: float = 0.82,
|
|
16
|
+
name: str | None = None,
|
|
16
17
|
use_default_params: bool = True,
|
|
17
18
|
):
|
|
18
|
-
|
|
19
|
+
if name is None:
|
|
20
|
+
name = "bm25"
|
|
21
|
+
super().__init__(name=name)
|
|
19
22
|
try:
|
|
20
23
|
from pinecone_text.sparse import BM25Encoder as encoder
|
|
21
24
|
except ImportError:
|
|
@@ -32,6 +35,7 @@ class BM25Encoder(BaseEncoder):
|
|
|
32
35
|
self._set_idx_mapping()
|
|
33
36
|
|
|
34
37
|
def _set_idx_mapping(self):
|
|
38
|
+
# TODO JB: this is training the model somehow - not sure how...
|
|
35
39
|
params = self.model.get_params()
|
|
36
40
|
doc_freq = params["doc_freq"]
|
|
37
41
|
if isinstance(doc_freq, dict):
|
|
@@ -40,8 +44,20 @@ class BM25Encoder(BaseEncoder):
|
|
|
40
44
|
else:
|
|
41
45
|
raise TypeError("Expected a dictionary for 'doc_freq'")
|
|
42
46
|
|
|
43
|
-
def
|
|
44
|
-
|
|
47
|
+
def fit(self, routes: List[Route]):
|
|
48
|
+
"""Trains the encoder weights on the provided routes.
|
|
49
|
+
|
|
50
|
+
:param routes: List of routes to train the encoder on.
|
|
51
|
+
:type routes: List[Route]
|
|
52
|
+
"""
|
|
53
|
+
self._fit_validate(routes=routes)
|
|
54
|
+
if self.model is None:
|
|
55
|
+
raise ValueError("Model is not initialized.")
|
|
56
|
+
utterances = [utterance for route in routes for utterance in route.utterances]
|
|
57
|
+
self.model.fit(corpus=utterances)
|
|
58
|
+
|
|
59
|
+
def __call__(self, docs: List[str]) -> list[SparseEmbedding]:
|
|
60
|
+
if self.model is None:
|
|
45
61
|
raise ValueError("Model or index mapping is not initialized.")
|
|
46
62
|
if len(docs) == 1:
|
|
47
63
|
sparse_dicts = self.model.encode_queries(docs)
|
|
@@ -50,18 +66,8 @@ class BM25Encoder(BaseEncoder):
|
|
|
50
66
|
else:
|
|
51
67
|
raise ValueError("No documents to encode.")
|
|
52
68
|
|
|
53
|
-
embeds = [
|
|
69
|
+
embeds = []
|
|
54
70
|
for i, output in enumerate(sparse_dicts):
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
for idx, val in zip(indices, values):
|
|
58
|
-
if idx in self.idx_mapping:
|
|
59
|
-
position = self.idx_mapping[idx]
|
|
60
|
-
embeds[i][position] = val
|
|
71
|
+
if isinstance(output, dict):
|
|
72
|
+
embeds.append(SparseEmbedding.from_pinecone_dict(output))
|
|
61
73
|
return embeds
|
|
62
|
-
|
|
63
|
-
def fit(self, docs: List[str]):
|
|
64
|
-
if self.model is None:
|
|
65
|
-
raise ValueError("Model is not initialized.")
|
|
66
|
-
self.model.fit(docs)
|
|
67
|
-
self._set_idx_mapping()
|
|
@@ -3,10 +3,10 @@ from typing import Any, List, Optional
|
|
|
3
3
|
import numpy as np
|
|
4
4
|
from pydantic.v1 import PrivateAttr
|
|
5
5
|
from typing import Dict
|
|
6
|
-
from semantic_router.encoders import
|
|
6
|
+
from semantic_router.encoders import DenseEncoder
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
class CLIPEncoder(
|
|
9
|
+
class CLIPEncoder(DenseEncoder):
|
|
10
10
|
name: str = "openai/clip-vit-base-patch16"
|
|
11
11
|
type: str = "huggingface"
|
|
12
12
|
score_threshold: float = 0.2
|
{semantic_router-0.1.0.dev0 → semantic_router-0.1.0.dev2}/semantic_router/encoders/cohere.py
RENAMED
|
@@ -3,11 +3,11 @@ from typing import Any, List, Optional
|
|
|
3
3
|
|
|
4
4
|
from pydantic.v1 import PrivateAttr
|
|
5
5
|
|
|
6
|
-
from semantic_router.encoders import
|
|
6
|
+
from semantic_router.encoders import DenseEncoder
|
|
7
7
|
from semantic_router.utils.defaults import EncoderDefault
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
class CohereEncoder(
|
|
10
|
+
class CohereEncoder(DenseEncoder):
|
|
11
11
|
_client: Any = PrivateAttr()
|
|
12
12
|
_embed_type: Any = PrivateAttr()
|
|
13
13
|
type: str = "cohere"
|
{semantic_router-0.1.0.dev0 → semantic_router-0.1.0.dev2}/semantic_router/encoders/fastembed.py
RENAMED
|
@@ -3,10 +3,10 @@ from typing import Any, List, Optional
|
|
|
3
3
|
import numpy as np
|
|
4
4
|
from pydantic.v1 import PrivateAttr
|
|
5
5
|
|
|
6
|
-
from semantic_router.encoders import
|
|
6
|
+
from semantic_router.encoders import DenseEncoder
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
class FastEmbedEncoder(
|
|
9
|
+
class FastEmbedEncoder(DenseEncoder):
|
|
10
10
|
type: str = "fastembed"
|
|
11
11
|
name: str = "BAAI/bge-small-en-v1.5"
|
|
12
12
|
max_length: int = 512
|
{semantic_router-0.1.0.dev0 → semantic_router-0.1.0.dev2}/semantic_router/encoders/google.py
RENAMED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""
|
|
2
2
|
This module provides the GoogleEncoder class for generating embeddings using Google's AI Platform.
|
|
3
3
|
|
|
4
|
-
The GoogleEncoder class is a subclass of
|
|
4
|
+
The GoogleEncoder class is a subclass of DenseEncoder and utilizes the TextEmbeddingModel from the
|
|
5
5
|
Google AI Platform to generate embeddings for given documents. It requires a Google Cloud project ID
|
|
6
6
|
and supports customization of the pre-trained model, score threshold, location, and API endpoint.
|
|
7
7
|
|
|
@@ -19,11 +19,11 @@ Classes:
|
|
|
19
19
|
import os
|
|
20
20
|
from typing import Any, List, Optional
|
|
21
21
|
|
|
22
|
-
from semantic_router.encoders import
|
|
22
|
+
from semantic_router.encoders import DenseEncoder
|
|
23
23
|
from semantic_router.utils.defaults import EncoderDefault
|
|
24
24
|
|
|
25
25
|
|
|
26
|
-
class GoogleEncoder(
|
|
26
|
+
class GoogleEncoder(DenseEncoder):
|
|
27
27
|
"""GoogleEncoder class for generating embeddings using Google's AI Platform.
|
|
28
28
|
|
|
29
29
|
Attributes:
|
{semantic_router-0.1.0.dev0 → semantic_router-0.1.0.dev2}/semantic_router/encoders/huggingface.py
RENAMED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""
|
|
2
2
|
This module provides the HFEndpointEncoder class to embeddings models using Huggingface's endpoint.
|
|
3
3
|
|
|
4
|
-
The HFEndpointEncoder class is a subclass of
|
|
4
|
+
The HFEndpointEncoder class is a subclass of DenseEncoder and utilizes a specified Huggingface
|
|
5
5
|
endpoint to generate embeddings for given documents. It requires the URL of the Huggingface
|
|
6
6
|
API endpoint and an API key for authentication. The class supports customization of the score
|
|
7
7
|
threshold for filtering or processing the embeddings.
|
|
@@ -27,11 +27,11 @@ from typing import Any, List, Optional, Dict
|
|
|
27
27
|
|
|
28
28
|
from pydantic.v1 import PrivateAttr
|
|
29
29
|
|
|
30
|
-
from semantic_router.encoders import
|
|
30
|
+
from semantic_router.encoders import DenseEncoder
|
|
31
31
|
from semantic_router.utils.logger import logger
|
|
32
32
|
|
|
33
33
|
|
|
34
|
-
class HuggingFaceEncoder(
|
|
34
|
+
class HuggingFaceEncoder(DenseEncoder):
|
|
35
35
|
name: str = "sentence-transformers/all-MiniLM-L6-v2"
|
|
36
36
|
type: str = "huggingface"
|
|
37
37
|
score_threshold: float = 0.5
|
|
@@ -140,7 +140,7 @@ class HuggingFaceEncoder(BaseEncoder):
|
|
|
140
140
|
return self._torch.max(token_embeddings, 1)[0]
|
|
141
141
|
|
|
142
142
|
|
|
143
|
-
class HFEndpointEncoder(
|
|
143
|
+
class HFEndpointEncoder(DenseEncoder):
|
|
144
144
|
"""
|
|
145
145
|
A class to encode documents using a Hugging Face transformer model endpoint.
|
|
146
146
|
|
{semantic_router-0.1.0.dev0 → semantic_router-0.1.0.dev2}/semantic_router/encoders/mistral.py
RENAMED
|
@@ -6,11 +6,11 @@ from typing import Any, List, Optional
|
|
|
6
6
|
|
|
7
7
|
from pydantic.v1 import PrivateAttr
|
|
8
8
|
|
|
9
|
-
from semantic_router.encoders import
|
|
9
|
+
from semantic_router.encoders import DenseEncoder
|
|
10
10
|
from semantic_router.utils.defaults import EncoderDefault
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
class MistralEncoder(
|
|
13
|
+
class MistralEncoder(DenseEncoder):
|
|
14
14
|
"""Class to encode text using MistralAI"""
|
|
15
15
|
|
|
16
16
|
_client: Any = PrivateAttr()
|
{semantic_router-0.1.0.dev0 → semantic_router-0.1.0.dev2}/semantic_router/encoders/openai.py
RENAMED
|
@@ -10,7 +10,7 @@ from openai._types import NotGiven
|
|
|
10
10
|
from openai.types import CreateEmbeddingResponse
|
|
11
11
|
import tiktoken
|
|
12
12
|
|
|
13
|
-
from semantic_router.encoders import
|
|
13
|
+
from semantic_router.encoders import DenseEncoder
|
|
14
14
|
from semantic_router.schema import EncoderInfo
|
|
15
15
|
from semantic_router.utils.defaults import EncoderDefault
|
|
16
16
|
from semantic_router.utils.logger import logger
|
|
@@ -35,7 +35,7 @@ model_configs = {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
|
|
38
|
-
class OpenAIEncoder(
|
|
38
|
+
class OpenAIEncoder(DenseEncoder):
|
|
39
39
|
client: Optional[openai.Client]
|
|
40
40
|
async_client: Optional[openai.AsyncClient]
|
|
41
41
|
dimensions: Union[int, NotGiven] = NotGiven()
|
|
@@ -3,24 +3,25 @@ from collections import Counter
|
|
|
3
3
|
from typing import Dict, List
|
|
4
4
|
|
|
5
5
|
import numpy as np
|
|
6
|
-
from numpy import ndarray
|
|
7
|
-
from numpy.linalg import norm
|
|
8
6
|
|
|
9
|
-
from semantic_router.encoders import
|
|
7
|
+
from semantic_router.encoders import SparseEncoder
|
|
10
8
|
from semantic_router.route import Route
|
|
9
|
+
from semantic_router.schema import SparseEmbedding
|
|
11
10
|
|
|
12
11
|
|
|
13
|
-
class TfidfEncoder(
|
|
14
|
-
idf: ndarray = np.array([])
|
|
12
|
+
class TfidfEncoder(SparseEncoder):
|
|
13
|
+
idf: np.ndarray = np.array([])
|
|
14
|
+
# TODO: add option to use default params like with BM25Encoder
|
|
15
15
|
word_index: Dict = {}
|
|
16
16
|
|
|
17
|
-
def __init__(self, name: str
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
def __init__(self, name: str | None = None):
|
|
18
|
+
if name is None:
|
|
19
|
+
name = "tfidf"
|
|
20
|
+
super().__init__(name=name)
|
|
20
21
|
self.word_index = {}
|
|
21
22
|
self.idf = np.array([])
|
|
22
23
|
|
|
23
|
-
def __call__(self, docs: List[str]) ->
|
|
24
|
+
def __call__(self, docs: List[str]) -> list[SparseEmbedding]:
|
|
24
25
|
if len(self.word_index) == 0 or self.idf.size == 0:
|
|
25
26
|
raise ValueError("Vectorizer is not initialized.")
|
|
26
27
|
if len(docs) == 0:
|
|
@@ -29,16 +30,28 @@ class TfidfEncoder(BaseEncoder):
|
|
|
29
30
|
docs = [self._preprocess(doc) for doc in docs]
|
|
30
31
|
tf = self._compute_tf(docs)
|
|
31
32
|
tfidf = tf * self.idf
|
|
32
|
-
return
|
|
33
|
+
return self._array_to_sparse_embeddings(tfidf)
|
|
33
34
|
|
|
34
35
|
def fit(self, routes: List[Route]):
|
|
36
|
+
"""Trains the encoder weights on the provided routes.
|
|
37
|
+
|
|
38
|
+
:param routes: List of routes to train the encoder on.
|
|
39
|
+
:type routes: List[Route]
|
|
40
|
+
"""
|
|
41
|
+
self._fit_validate(routes=routes)
|
|
35
42
|
docs = []
|
|
36
43
|
for route in routes:
|
|
37
44
|
for doc in route.utterances:
|
|
38
45
|
docs.append(self._preprocess(doc)) # type: ignore
|
|
39
46
|
self.word_index = self._build_word_index(docs)
|
|
47
|
+
if len(self.word_index) == 0:
|
|
48
|
+
raise ValueError(f"Too little data to fit {self.__class__.__name__}.")
|
|
40
49
|
self.idf = self._compute_idf(docs)
|
|
41
50
|
|
|
51
|
+
def _fit_validate(self, routes: List[Route]):
|
|
52
|
+
if not isinstance(routes, list) or not isinstance(routes[0], Route):
|
|
53
|
+
raise TypeError("`routes` parameter must be a list of Route objects.")
|
|
54
|
+
|
|
42
55
|
def _build_word_index(self, docs: List[str]) -> Dict:
|
|
43
56
|
words = set()
|
|
44
57
|
for doc in docs:
|
|
@@ -57,7 +70,7 @@ class TfidfEncoder(BaseEncoder):
|
|
|
57
70
|
if word in self.word_index:
|
|
58
71
|
tf[i, self.word_index[word]] = count
|
|
59
72
|
# L2 normalization
|
|
60
|
-
tf = tf / norm(tf, axis=1, keepdims=True)
|
|
73
|
+
tf = tf / np.linalg.norm(tf, axis=1, keepdims=True)
|
|
61
74
|
return tf
|
|
62
75
|
|
|
63
76
|
def _compute_idf(self, docs: List[str]) -> np.ndarray:
|
|
@@ -2,10 +2,10 @@ from typing import Any, List, Optional, Dict
|
|
|
2
2
|
|
|
3
3
|
from pydantic.v1 import PrivateAttr
|
|
4
4
|
|
|
5
|
-
from semantic_router.encoders import
|
|
5
|
+
from semantic_router.encoders import DenseEncoder
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
class VitEncoder(
|
|
8
|
+
class VitEncoder(DenseEncoder):
|
|
9
9
|
name: str = "google/vit-base-patch16-224"
|
|
10
10
|
type: str = "huggingface"
|
|
11
11
|
score_threshold: float = 0.5
|
|
@@ -8,12 +8,12 @@ from openai._types import NotGiven
|
|
|
8
8
|
from openai import OpenAIError
|
|
9
9
|
from openai.types import CreateEmbeddingResponse
|
|
10
10
|
|
|
11
|
-
from semantic_router.encoders import
|
|
11
|
+
from semantic_router.encoders import DenseEncoder
|
|
12
12
|
from semantic_router.utils.defaults import EncoderDefault
|
|
13
13
|
from semantic_router.utils.logger import logger
|
|
14
14
|
|
|
15
15
|
|
|
16
|
-
class AzureOpenAIEncoder(
|
|
16
|
+
class AzureOpenAIEncoder(DenseEncoder):
|
|
17
17
|
client: Optional[openai.AzureOpenAI] = None
|
|
18
18
|
async_client: Optional[openai.AsyncAzureOpenAI] = None
|
|
19
19
|
dimensions: Union[int, NotGiven] = NotGiven()
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
from semantic_router.index.base import BaseIndex
|
|
2
|
+
from semantic_router.index.hybrid_local import HybridLocalIndex
|
|
2
3
|
from semantic_router.index.local import LocalIndex
|
|
3
4
|
from semantic_router.index.pinecone import PineconeIndex
|
|
5
|
+
from semantic_router.index.postgres import PostgresIndex
|
|
4
6
|
from semantic_router.index.qdrant import QdrantIndex
|
|
5
7
|
|
|
6
8
|
__all__ = [
|
|
7
9
|
"BaseIndex",
|
|
10
|
+
"HybridLocalIndex",
|
|
8
11
|
"LocalIndex",
|
|
9
12
|
"QdrantIndex",
|
|
10
13
|
"PineconeIndex",
|
|
14
|
+
"PostgresIndex",
|
|
11
15
|
]
|
|
@@ -4,7 +4,7 @@ import json
|
|
|
4
4
|
import numpy as np
|
|
5
5
|
from pydantic.v1 import BaseModel
|
|
6
6
|
|
|
7
|
-
from semantic_router.schema import ConfigParameter, Utterance
|
|
7
|
+
from semantic_router.schema import ConfigParameter, SparseEmbedding, Utterance
|
|
8
8
|
from semantic_router.route import Route
|
|
9
9
|
from semantic_router.utils.logger import logger
|
|
10
10
|
|
|
@@ -18,12 +18,12 @@ class BaseIndex(BaseModel):
|
|
|
18
18
|
|
|
19
19
|
# You can define common attributes here if there are any.
|
|
20
20
|
# For example, a placeholder for the index attribute:
|
|
21
|
-
index: Optional[Any] = None
|
|
22
21
|
routes: Optional[np.ndarray] = None
|
|
23
22
|
utterances: Optional[np.ndarray] = None
|
|
24
23
|
dimensions: Union[int, None] = None
|
|
25
24
|
type: str = "base"
|
|
26
25
|
init_async_index: bool = False
|
|
26
|
+
index: Optional[Any] = None
|
|
27
27
|
|
|
28
28
|
def add(
|
|
29
29
|
self,
|
|
@@ -108,6 +108,7 @@ class BaseIndex(BaseModel):
|
|
|
108
108
|
vector: np.ndarray,
|
|
109
109
|
top_k: int = 5,
|
|
110
110
|
route_filter: Optional[List[str]] = None,
|
|
111
|
+
sparse_vector: dict[int, float] | SparseEmbedding | None = None,
|
|
111
112
|
) -> Tuple[np.ndarray, List[str]]:
|
|
112
113
|
"""
|
|
113
114
|
Search the index for the query_vector and return top_k results.
|
|
@@ -120,6 +121,7 @@ class BaseIndex(BaseModel):
|
|
|
120
121
|
vector: np.ndarray,
|
|
121
122
|
top_k: int = 5,
|
|
122
123
|
route_filter: Optional[List[str]] = None,
|
|
124
|
+
sparse_vector: dict[int, float] | SparseEmbedding | None = None,
|
|
123
125
|
) -> Tuple[np.ndarray, List[str]]:
|
|
124
126
|
"""
|
|
125
127
|
Search the index for the query_vector and return top_k results.
|