semantic-router 0.1.0.dev1__tar.gz → 0.1.0.dev3__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.
Files changed (52) hide show
  1. {semantic_router-0.1.0.dev1 → semantic_router-0.1.0.dev3}/LICENSE +1 -1
  2. {semantic_router-0.1.0.dev1 → semantic_router-0.1.0.dev3}/PKG-INFO +16 -14
  3. {semantic_router-0.1.0.dev1 → semantic_router-0.1.0.dev3}/pyproject.toml +16 -15
  4. semantic_router-0.1.0.dev3/semantic_router/__init__.py +6 -0
  5. {semantic_router-0.1.0.dev1 → semantic_router-0.1.0.dev3}/semantic_router/encoders/__init__.py +10 -5
  6. semantic_router-0.1.0.dev3/semantic_router/encoders/aurelio.py +47 -0
  7. semantic_router-0.1.0.dev3/semantic_router/encoders/base.py +53 -0
  8. {semantic_router-0.1.0.dev1 → semantic_router-0.1.0.dev3}/semantic_router/encoders/bedrock.py +3 -3
  9. {semantic_router-0.1.0.dev1 → semantic_router-0.1.0.dev3}/semantic_router/encoders/bm25.py +26 -20
  10. {semantic_router-0.1.0.dev1 → semantic_router-0.1.0.dev3}/semantic_router/encoders/clip.py +5 -4
  11. {semantic_router-0.1.0.dev1 → semantic_router-0.1.0.dev3}/semantic_router/encoders/cohere.py +3 -3
  12. {semantic_router-0.1.0.dev1 → semantic_router-0.1.0.dev3}/semantic_router/encoders/fastembed.py +3 -3
  13. {semantic_router-0.1.0.dev1 → semantic_router-0.1.0.dev3}/semantic_router/encoders/google.py +3 -3
  14. {semantic_router-0.1.0.dev1 → semantic_router-0.1.0.dev3}/semantic_router/encoders/huggingface.py +9 -7
  15. {semantic_router-0.1.0.dev1 → semantic_router-0.1.0.dev3}/semantic_router/encoders/mistral.py +3 -3
  16. {semantic_router-0.1.0.dev1 → semantic_router-0.1.0.dev3}/semantic_router/encoders/openai.py +11 -11
  17. {semantic_router-0.1.0.dev1 → semantic_router-0.1.0.dev3}/semantic_router/encoders/tfidf.py +24 -11
  18. {semantic_router-0.1.0.dev1 → semantic_router-0.1.0.dev3}/semantic_router/encoders/vit.py +6 -5
  19. {semantic_router-0.1.0.dev1 → semantic_router-0.1.0.dev3}/semantic_router/encoders/zure.py +2 -2
  20. {semantic_router-0.1.0.dev1 → semantic_router-0.1.0.dev3}/semantic_router/index/__init__.py +4 -0
  21. {semantic_router-0.1.0.dev1 → semantic_router-0.1.0.dev3}/semantic_router/index/base.py +5 -3
  22. semantic_router-0.1.0.dev3/semantic_router/index/hybrid_local.py +212 -0
  23. {semantic_router-0.1.0.dev1 → semantic_router-0.1.0.dev3}/semantic_router/index/local.py +27 -11
  24. {semantic_router-0.1.0.dev1 → semantic_router-0.1.0.dev3}/semantic_router/index/pinecone.py +64 -29
  25. {semantic_router-0.1.0.dev1 → semantic_router-0.1.0.dev3}/semantic_router/index/postgres.py +20 -7
  26. {semantic_router-0.1.0.dev1 → semantic_router-0.1.0.dev3}/semantic_router/index/qdrant.py +5 -3
  27. {semantic_router-0.1.0.dev1 → semantic_router-0.1.0.dev3}/semantic_router/llms/base.py +3 -1
  28. {semantic_router-0.1.0.dev1 → semantic_router-0.1.0.dev3}/semantic_router/llms/cohere.py +1 -1
  29. {semantic_router-0.1.0.dev1 → semantic_router-0.1.0.dev3}/semantic_router/llms/llamacpp.py +1 -3
  30. {semantic_router-0.1.0.dev1 → semantic_router-0.1.0.dev3}/semantic_router/llms/mistral.py +1 -3
  31. {semantic_router-0.1.0.dev1 → semantic_router-0.1.0.dev3}/semantic_router/llms/ollama.py +5 -10
  32. {semantic_router-0.1.0.dev1 → semantic_router-0.1.0.dev3}/semantic_router/llms/openai.py +9 -10
  33. {semantic_router-0.1.0.dev1 → semantic_router-0.1.0.dev3}/semantic_router/llms/openrouter.py +8 -8
  34. {semantic_router-0.1.0.dev1 → semantic_router-0.1.0.dev3}/semantic_router/llms/zure.py +5 -6
  35. {semantic_router-0.1.0.dev1 → semantic_router-0.1.0.dev3}/semantic_router/route.py +2 -7
  36. semantic_router-0.1.0.dev3/semantic_router/routers/__init__.py +10 -0
  37. semantic_router-0.1.0.dev1/semantic_router/layer.py → semantic_router-0.1.0.dev3/semantic_router/routers/base.py +267 -218
  38. semantic_router-0.1.0.dev3/semantic_router/routers/hybrid.py +254 -0
  39. semantic_router-0.1.0.dev3/semantic_router/routers/semantic.py +87 -0
  40. {semantic_router-0.1.0.dev1 → semantic_router-0.1.0.dev3}/semantic_router/schema.py +77 -2
  41. {semantic_router-0.1.0.dev1 → semantic_router-0.1.0.dev3}/semantic_router/utils/function_call.py +1 -1
  42. semantic_router-0.1.0.dev1/semantic_router/__init__.py +0 -7
  43. semantic_router-0.1.0.dev1/semantic_router/encoders/base.py +0 -22
  44. semantic_router-0.1.0.dev1/semantic_router/hybrid_layer.py +0 -220
  45. {semantic_router-0.1.0.dev1 → semantic_router-0.1.0.dev3}/README.md +0 -0
  46. {semantic_router-0.1.0.dev1 → semantic_router-0.1.0.dev3}/semantic_router/linear.py +0 -0
  47. {semantic_router-0.1.0.dev1 → semantic_router-0.1.0.dev3}/semantic_router/llms/__init__.py +0 -0
  48. {semantic_router-0.1.0.dev1 → semantic_router-0.1.0.dev3}/semantic_router/llms/grammars/json.gbnf +0 -0
  49. {semantic_router-0.1.0.dev1 → semantic_router-0.1.0.dev3}/semantic_router/utils/__init__.py +0 -0
  50. {semantic_router-0.1.0.dev1 → semantic_router-0.1.0.dev3}/semantic_router/utils/defaults.py +0 -0
  51. {semantic_router-0.1.0.dev1 → semantic_router-0.1.0.dev3}/semantic_router/utils/llm.py +0 -0
  52. {semantic_router-0.1.0.dev1 → semantic_router-0.1.0.dev3}/semantic_router/utils/logger.py +0 -0
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2023 Aurelio AI
3
+ Copyright (c) 2024 Aurelio AI
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -1,16 +1,18 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: semantic-router
3
- Version: 0.1.0.dev1
3
+ Version: 0.1.0.dev3
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.13
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
@@ -21,27 +23,26 @@ Provides-Extra: local
21
23
  Provides-Extra: mistralai
22
24
  Provides-Extra: pinecone
23
25
  Provides-Extra: postgres
24
- Provides-Extra: processing
25
26
  Provides-Extra: qdrant
26
27
  Provides-Extra: vision
27
- Requires-Dist: aiohttp (>=3.9.5,<4.0.0)
28
+ Requires-Dist: aiohttp (>=3.10.11,<4.0.0)
29
+ Requires-Dist: aurelio-sdk (>=0.0.16,<0.0.17)
28
30
  Requires-Dist: boto3 (>=1.34.98,<2.0.0) ; extra == "bedrock"
29
31
  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"
36
- Requires-Dist: matplotlib (>=3.8.3,<4.0.0) ; extra == "processing"
37
+ Requires-Dist: llama-cpp-python (>=0.2.28,<0.2.86) ; (python_version < "3.13") and (extra == "local")
37
38
  Requires-Dist: mistralai (>=0.0.12,<0.1.0) ; extra == "mistralai"
38
39
  Requires-Dist: numpy (>=1.25.2,<2.0.0)
39
40
  Requires-Dist: openai (>=1.10.0,<2.0.0)
40
- 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")
41
42
  Requires-Dist: pinecone (>=5.0.0) ; extra == "pinecone"
42
43
  Requires-Dist: pinecone-text (>=0.7.1,<0.10.0) ; extra == "hybrid"
43
- Requires-Dist: psycopg2 (>=2.9.9,<3.0.0) ; extra == "postgres"
44
- Requires-Dist: pydantic (>=2.5.3,<3.0.0)
44
+ Requires-Dist: psycopg2-binary (>=2.9.9,<3.0.0)
45
+ Requires-Dist: pydantic (>=2.10.2,<3.0.0)
45
46
  Requires-Dist: pyyaml (>=6.0.1,<7.0.0)
46
47
  Requires-Dist: qdrant-client (>=1.11.1,<2.0.0) ; extra == "qdrant"
47
48
  Requires-Dist: regex (>=2023.12.25)
@@ -49,10 +50,11 @@ Requires-Dist: requests-mock (>=1.12.1,<2.0.0)
49
50
  Requires-Dist: sphinx (>=7.0.0,<8.0.0) ; extra == "docs"
50
51
  Requires-Dist: sphinxawesome-theme (>=5.2.0,<6.0.0) ; extra == "docs"
51
52
  Requires-Dist: tiktoken (>=0.6.0,<1.0.0)
52
- Requires-Dist: tokenizers (>=0.19) ; extra == "local"
53
- Requires-Dist: torch (>=2.1.0,<2.6.0) ; extra == "local" or extra == "vision"
54
- Requires-Dist: torchvision (>=0.17.0,<0.18.0) ; extra == "vision"
55
- Requires-Dist: transformers (>=4.36.2) ; extra == "local" or 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")
56
+ Requires-Dist: tornado (>=6.4.2,<7.0.0)
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
  [![Semantic Router](https://i.ibb.co.com/g423grt/semantic-router-banner.png)](https://aurelio.ai)
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "semantic-router"
3
- version = "0.1.0.dev1"
3
+ version = "0.1.0.dev3"
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,43 +8,43 @@ packages = [{include = "semantic_router"}]
8
8
  license = "MIT"
9
9
 
10
10
  [tool.poetry.dependencies]
11
- python = ">=3.9,<3.13"
12
- pydantic = "^2.5.3"
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}
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
- torch = {version = ">=2.1.0,<2.6.0", optional = true}
21
- transformers = {version = ">=4.36.2", optional = true}
22
- tokenizers = {version = ">=0.19", optional = true}
23
- 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" }
24
25
  colorama = "^0.4.6"
25
26
  pinecone = {version=">=5.0.0", optional = true}
26
27
  regex = ">=2023.12.25"
27
- torchvision = { version = ">=0.17.0,<0.18.0", optional = true}
28
- 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" }
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.9.5"
37
- fastembed = {version = "^0.3.0", optional = true}
38
- psycopg2 = {version = "^2.9.9", optional = true}
36
+ aiohttp = "^3.10.11"
37
+ fastembed = {version = "^0.3.0", optional = true, python = "<3.13" }
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 = "^7.4.3"
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"
@@ -0,0 +1,6 @@
1
+ from semantic_router.routers import RouterConfig, SemanticRouter, HybridRouter
2
+ from semantic_router.route import Route
3
+
4
+ __all__ = ["SemanticRouter", "HybridRouter", "Route", "RouterConfig"]
5
+
6
+ __version__ = "0.1.0.dev3"
@@ -1,6 +1,7 @@
1
1
  from typing import List, Optional
2
2
 
3
- from semantic_router.encoders.base import BaseEncoder
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
- "BaseEncoder",
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: BaseEncoder
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 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 import BaseModel, Field, 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
+ @field_validator("score_threshold")
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]
@@ -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 BaseEncoder and utilizes the TextEmbeddingModel from the
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 BaseEncoder
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(BaseEncoder):
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 BaseEncoder
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(BaseEncoder):
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 = "bm25",
15
- score_threshold: float = 0.82,
16
+ name: str | None = None,
16
17
  use_default_params: bool = True,
17
18
  ):
18
- super().__init__(name=name, score_threshold=score_threshold)
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 __call__(self, docs: List[str]) -> List[List[float]]:
44
- if self.model is None or self.idx_mapping is None:
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 = [[0.0] * len(self.idx_mapping)] * len(docs)
69
+ embeds = []
54
70
  for i, output in enumerate(sparse_dicts):
55
- indices = output["indices"]
56
- values = output["values"]
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()
@@ -1,15 +1,14 @@
1
1
  from typing import Any, List, Optional
2
2
 
3
3
  import numpy as np
4
- from pydantic.v1 import PrivateAttr
4
+ from pydantic import PrivateAttr
5
5
  from typing import Dict
6
- from semantic_router.encoders import BaseEncoder
6
+ from semantic_router.encoders import DenseEncoder
7
7
 
8
8
 
9
- class CLIPEncoder(BaseEncoder):
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(BaseEncoder):
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
 
@@ -1,13 +1,13 @@
1
1
  import os
2
2
  from typing import Any, List, Optional
3
3
 
4
- from pydantic.v1 import PrivateAttr
4
+ from pydantic import PrivateAttr
5
5
 
6
- from semantic_router.encoders import BaseEncoder
6
+ from semantic_router.encoders import DenseEncoder
7
7
  from semantic_router.utils.defaults import EncoderDefault
8
8
 
9
9
 
10
- class CohereEncoder(BaseEncoder):
10
+ class CohereEncoder(DenseEncoder):
11
11
  _client: Any = PrivateAttr()
12
12
  _embed_type: Any = PrivateAttr()
13
13
  type: str = "cohere"
@@ -1,12 +1,12 @@
1
1
  from typing import Any, List, Optional
2
2
 
3
3
  import numpy as np
4
- from pydantic.v1 import PrivateAttr
4
+ from pydantic import PrivateAttr
5
5
 
6
- from semantic_router.encoders import BaseEncoder
6
+ from semantic_router.encoders import DenseEncoder
7
7
 
8
8
 
9
- class FastEmbedEncoder(BaseEncoder):
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
@@ -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 BaseEncoder and utilizes the TextEmbeddingModel from the
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 BaseEncoder
22
+ from semantic_router.encoders import DenseEncoder
23
23
  from semantic_router.utils.defaults import EncoderDefault
24
24
 
25
25
 
26
- class GoogleEncoder(BaseEncoder):
26
+ class GoogleEncoder(DenseEncoder):
27
27
  """GoogleEncoder class for generating embeddings using Google's AI Platform.
28
28
 
29
29
  Attributes:
@@ -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 BaseEncoder and utilizes a specified Huggingface
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.
@@ -25,16 +25,15 @@ import time
25
25
  import os
26
26
  from typing import Any, List, Optional, Dict
27
27
 
28
- from pydantic.v1 import PrivateAttr
28
+ from pydantic import PrivateAttr
29
29
 
30
- from semantic_router.encoders import BaseEncoder
30
+ from semantic_router.encoders import DenseEncoder
31
31
  from semantic_router.utils.logger import logger
32
32
 
33
33
 
34
- class HuggingFaceEncoder(BaseEncoder):
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(BaseEncoder):
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
 
@@ -140,7 +141,7 @@ class HuggingFaceEncoder(BaseEncoder):
140
141
  return self._torch.max(token_embeddings, 1)[0]
141
142
 
142
143
 
143
- class HFEndpointEncoder(BaseEncoder):
144
+ class HFEndpointEncoder(DenseEncoder):
144
145
  """
145
146
  A class to encode documents using a Hugging Face transformer model endpoint.
146
147
 
@@ -153,7 +154,6 @@ class HFEndpointEncoder(BaseEncoder):
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(BaseEncoder):
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
 
@@ -4,13 +4,13 @@ import os
4
4
  from time import sleep
5
5
  from typing import Any, List, Optional
6
6
 
7
- from pydantic.v1 import PrivateAttr
7
+ from pydantic import PrivateAttr
8
8
 
9
- from semantic_router.encoders import BaseEncoder
9
+ from semantic_router.encoders import DenseEncoder
10
10
  from semantic_router.utils.defaults import EncoderDefault
11
11
 
12
12
 
13
- class MistralEncoder(BaseEncoder):
13
+ class MistralEncoder(DenseEncoder):
14
14
  """Class to encode text using MistralAI"""
15
15
 
16
16
  _client: Any = PrivateAttr()