diff --git a/docs/source/conf.py b/docs/source/conf.py index f7912551889e25c84bb42a3854055d0fe21ccd07..a16c1325337ff130dc52e8600f424db4e04a86b9 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -15,7 +15,7 @@ sys.path.insert(0, os.path.abspath("../..")) # Source code dir relative to this project = "Semantic Router" copyright = "2025, Aurelio AI" author = "Aurelio AI" -release = "0.1.0.dev9" +release = "0.1.0.dev10" # -- General configuration --------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration diff --git a/pyproject.toml b/pyproject.toml index c8d93b34ec82517caf495aa0d7d9c260512b7905..0ecc83a33d12b87514f60efa5946bdda4158e527 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "semantic-router" -version = "0.1.0.dev9" +version = "0.1.0.dev10" description = "Super fast semantic router for AI decision making" authors = ["Aurelio AI <hello@aurelio.ai>"] readme = "README.md" diff --git a/semantic_router/__init__.py b/semantic_router/__init__.py index 1074546f1eb83b2f7f7650b4f35bdeb47d30a143..d9d8cba5af2fe6fdb0da5080315fc59915e9744f 100644 --- a/semantic_router/__init__.py +++ b/semantic_router/__init__.py @@ -3,4 +3,4 @@ from semantic_router.routers import HybridRouter, RouterConfig, SemanticRouter __all__ = ["SemanticRouter", "HybridRouter", "Route", "RouterConfig"] -__version__ = "0.1.0.dev9" +__version__ = "0.1.0.dev10" diff --git a/semantic_router/index/pinecone.py b/semantic_router/index/pinecone.py index 6f1b4d51f1a54b79d17d284cdfc41c8efd2225f6..62f5ac2212177c79407d55c95cbaabaa0d4544a0 100644 --- a/semantic_router/index/pinecone.py +++ b/semantic_router/index/pinecone.py @@ -202,6 +202,20 @@ class PineconeIndex(BaseIndex): return Pinecone(**pinecone_args) + def _calculate_index_host(self): + if self.index_host and self.base_url: + if "api.pinecone.io" in self.base_url: + if not self.index_host.startswith("http"): + self.index_host = f"https://{self.index_host}" + else: + if "http" not in self.index_host: + self.index_host = f"http://{self.base_url.split(':')[-2].strip('/')}:{self.index_host.split(':')[-1]}" + elif not self.index_host.startswith("http://"): + if "localhost" in self.index_host: + self.index_host = f"http://{self.base_url.split(':')[-2].strip('/')}:{self.index_host.split(':')[-1]}" + else: + self.index_host = f"http://{self.index_host}" + def _init_index(self, force_create: bool = False) -> Union[Any, None]: """Initializing the index can be done after the object has been created to allow for the user to set the dimensions and other parameters. @@ -215,58 +229,59 @@ class PineconeIndex(BaseIndex): dimensions are not given (which will raise an error). :type force_create: bool, optional """ - index_exists = self.index_name in self.client.list_indexes().names() dimensions_given = self.dimensions is not None - if dimensions_given and not index_exists: - # if the index doesn't exist and we have dimension value - # we create the index - self.client.create_index( - name=self.index_name, - dimension=self.dimensions, - metric=self.metric, - spec=self.ServerlessSpec(cloud=self.cloud, region=self.region), - ) - # wait for index to be created - while not self.client.describe_index(self.index_name).status["ready"]: - time.sleep(1) - index = self.client.Index(self.index_name) - time.sleep(0.5) - elif index_exists: + if self.index is None: + index_exists = self.index_name in self.client.list_indexes().names() + if dimensions_given and not index_exists: + # if the index doesn't exist and we have dimension value + # we create the index + self.client.create_index( + name=self.index_name, + dimension=self.dimensions, + metric=self.metric, + spec=self.ServerlessSpec(cloud=self.cloud, region=self.region), + ) + # wait for index to be created + while not self.client.describe_index(self.index_name).status["ready"]: + time.sleep(0.2) + index = self.client.Index(self.index_name) + self.index = index + time.sleep(0.2) + elif index_exists: + # if the index exists we just return it + # index = self.client.Index(self.index_name) + + self.index_host = self.client.describe_index(self.index_name).host + self._calculate_index_host() + index = self.client.Index(self.index_name, host=self.index_host) + self.index = index + + # grab the dimensions from the index + self.dimensions = index.describe_index_stats()["dimension"] + elif force_create and not dimensions_given: + raise ValueError( + "Cannot create an index without specifying the dimensions." + ) + else: + # if the index doesn't exist and we don't have the dimensions + # we return None + logger.warning( + "Index could not be initialized. Init parameters: " + f"{self.index_name=}, {self.dimensions=}, {self.metric=}, " + f"{self.cloud=}, {self.region=}, {self.host=}, {self.namespace=}, " + f"{force_create=}" + ) + index = None + else: + index = self.index + if self.index is not None and self.host == "": # if the index exists we just return it self.index_host = self.client.describe_index(self.index_name).host if self.index_host and self.base_url: - if "api.pinecone.io" in self.base_url: - if not self.index_host.startswith("http"): - self.index_host = f"https://{self.index_host}" - else: - if "http" not in self.index_host: - self.index_host = f"http://{self.base_url.split(':')[-2].strip('/')}:{self.index_host.split(':')[-1]}" - elif not self.index_host.startswith("http://"): - if "localhost" in self.index_host: - self.index_host = f"http://{self.base_url.split(':')[-2].strip('/')}:{self.index_host.split(':')[-1]}" - else: - self.index_host = f"http://{self.index_host}" + self._calculate_index_host() index = self.client.Index(self.index_name, host=self.index_host) self.host = self.index_host - # grab the dimensions from the index - self.dimensions = index.describe_index_stats()["dimension"] - elif force_create and not dimensions_given: - raise ValueError( - "Cannot create an index without specifying the dimensions." - ) - else: - # if the index doesn't exist and we don't have the dimensions - # we return None - logger.warning( - "Index could not be initialized. Init parameters: " - f"{self.index_name=}, {self.dimensions=}, {self.metric=}, " - f"{self.cloud=}, {self.region=}, {self.host=}, {self.namespace=}, " - f"{force_create=}" - ) - index = None - if index is not None: - self.host = self.client.describe_index(self.index_name)["host"] return index async def _init_async_index(self, force_create: bool = False): diff --git a/semantic_router/routers/base.py b/semantic_router/routers/base.py index fd7379557367adfed1f93133f305a9513f398c02..ca3545fecc95857bf5d1a2fe076c15f3fe5776bd 100644 --- a/semantic_router/routers/base.py +++ b/semantic_router/routers/base.py @@ -397,6 +397,9 @@ class BaseRouter(BaseModel): self.index.dimensions = dims # now init index if isinstance(self.index, PineconeIndex): + # _init_index will not create index if already exists — it will also check + # for required attributes like self.index.host and self.index.dimensions and + # fetch them if not set self.index.index = self.index._init_index(force_create=True) # run auto sync if active diff --git a/tests/unit/test_router.py b/tests/unit/test_router.py index 341909d58fe7369015f27f1f173e7339c3343bff..4270fb6e8c76716188d9bdf5b90d1d82a0d59350 100644 --- a/tests/unit/test_router.py +++ b/tests/unit/test_router.py @@ -93,9 +93,7 @@ def init_index( index_name = TEST_ID if not index_name else f"{TEST_ID}-{index_name.lower()}" index = index_cls( - index_name=index_name, - dimensions=dimensions, - # namespace=namespace + index_name=index_name, dimensions=dimensions, namespace=namespace ) else: index = index_cls()