From 1efc9958c84eeb596d4b80b9033200109550a6d3 Mon Sep 17 00:00:00 2001 From: Abdusshh Date: Tue, 31 Dec 2024 21:08:21 +0300 Subject: [PATCH 01/13] Add upstash_vector dependancy --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index b12913a036..c956e97cff 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -165,6 +165,7 @@ module = [ "textract.*", "timeout_decorator.*", "torch.*", + "upstash_vector.*", "uvicorn.*", "vertexai.*", "voyageai.*", From d13b4a61ba1abfc061074097380d11308e0cee83 Mon Sep 17 00:00:00 2001 From: Abdusshh Date: Tue, 31 Dec 2024 21:08:48 +0300 Subject: [PATCH 02/13] Create upstash vector class --- phi/vectordb/upstash/upstash.py | 310 ++++++++++++++++++++++++++++++++ 1 file changed, 310 insertions(+) create mode 100644 phi/vectordb/upstash/upstash.py diff --git a/phi/vectordb/upstash/upstash.py b/phi/vectordb/upstash/upstash.py new file mode 100644 index 0000000000..341c294bf0 --- /dev/null +++ b/phi/vectordb/upstash/upstash.py @@ -0,0 +1,310 @@ +from typing import Optional, Dict, List, Any, Union + +try: + from upstash_vector import Index, Vector + from upstash_vector.types import InfoResult +except ImportError: + raise ImportError( + "The `upstash-vector` package is not installed, please install using `pip install upstash-vector`" + ) + +from phi.document import Document +from phi.embedder import Embedder +from phi.vectordb.base import VectorDb +from phi.utils.log import logger +from phi.reranker.base import Reranker + + +DEFAULT_NAMESPACE = "" + +class Upstash(VectorDb): + """A class representing an Upstash Vector database. + + Args: + url (str): The Upstash Vector database URL. + token (str): The Upstash Vector API token. + retries (Optional[int], optional): Number of retry attempts for operations. Defaults to 3. + retry_interval (Optional[float], optional): Time interval between retries in seconds. Defaults to 1.0. + dimension (Optional[int], optional): The dimension of the embeddings. Defaults to None. + embedder (Optional[Embedder], optional): The embedder to use. Defaults to OpenAIEmbedder. + namespace (Optional[str], optional): The namespace to use. Defaults to DEFAULT_NAMESPACE. + reranker (Optional[Reranker], optional): The reranker to use. Defaults to None. + **kwargs: Additional keyword arguments. + + Attributes: + url (str): The Upstash Vector database URL. + token (str): The Upstash Vector API token. + retries (int): Number of retry attempts. + retry_interval (float): Time interval between retries. + dimension (Optional[int]): The dimension of the embeddings. + namespace (str): The namespace to use. + embedder (Embedder): The embedder instance. + reranker (Optional[Reranker]): The reranker instance. + kwargs (Dict[str, Any]): Additional keyword arguments. + """ + + def __init__( + self, + url: str, + token: str, + retries: Optional[int] = 3, + retry_interval: Optional[float] = 1.0, + dimension: Optional[int] = None, + embedder: Optional[Embedder] = None, + namespace: Optional[str] = DEFAULT_NAMESPACE, + reranker: Optional[Reranker] = None, + **kwargs, + ): + self._index = None + self.url: str = url + self.token: str = token + self.retries: int = retries + self.retry_interval: float = retry_interval + self.dimension: Optional[int] = dimension + self.namespace: str = namespace + self.kwargs: Dict[str, Any] = kwargs + + # Initialize embedder for embedding the document contents + _embedder = embedder + if _embedder is None: + from phi.embedder.openai import OpenAIEmbedder + _embedder = OpenAIEmbedder(dimensions=self.dimension) + self.embedder: Embedder = _embedder + self.reranker: Optional[Reranker] = reranker + + @property + def index(self) -> Index: + """The Upstash Vector index. + + Returns: + upstash_vector.Index: The Upstash Vector index. + + """ + if self._index is None: + self._index = Index( + url=self.url, + token=self.token, + retries=self.retries, + retry_interval=self.retry_interval, + ) + + index_dimension = self._index.info().dimension + if index_dimension != self.dimension: + raise ValueError( + f"Index dimension {index_dimension} does not match provided dimension {self.dimension}" + ) + return self._index + + def exists(self) -> bool: + """Check if the index exists. + + Returns: + bool: True if the index exists, False otherwise. + + """ + try: + self.index.info() + return True + except Exception: + return False + + def create(self) -> None: + """You can create indexes in Upstash Console.""" + logger.info("You can create indexes in Upstash Console.") + pass + + def drop(self) -> None: + """You can drop indexes in Upstash Console.""" + logger.info("You can drop indexes in Upstash Console.") + pass + + def drop_namespace(self, namespace: Optional[str] = None) -> None: + """Delete a namespace from the index. + + Args: + namespace (Optional[str], optional): The namespace to drop. Defaults to None, which uses the instance namespace. + """ + _namespace = self.namespace if namespace is None else namespace + if self.namespace_exists(_namespace): + self.index.delete_namespace(_namespace) + else: + logger.error(f"Namespace {_namespace} does not exist.") + + def get_namespaces(self) -> List[str]: + """Get all namespaces in the index. + + Returns: + List[str]: A list of namespaces. + + """ + return self.index.list_namespaces() + + def doc_exists(self, document: Document) -> bool: + """Check if a document exists in the index. + + Args: + document (Document): The document to check. + + Returns: + bool: True if the document exists, False otherwise. + + """ + response = self.index.fetch(ids=[document.id]) + return len(response) > 0 + + def name_exists(self, name: str) -> bool: + """You can check if an index exists in Upstash Console. + + Args: + name (str): The name of the index to check. + + Returns: + bool: True if the index exists, False otherwise. (Name is not used.) + """ + logger.info("You can check if an index exists in Upstash Console.") + return self.exists() + + def namespace_exists(self, namespace: str) -> bool: + """Check if an namespace exists. + + Args: + namespace (str): The name of the namespace to check. + + Returns: + bool: True if the namespace exists, False otherwise. + + """ + namespaces = self.index.list_namespaces() + return namespace in namespaces + + def upsert( + self, + documents: List[Document], + filters: Optional[Dict[str, Any]] = None, + namespace: Optional[str] = None + ) -> None: + """Upsert documents into the index. + + Args: + documents (List[Document]): The documents to upsert. + filters (Optional[Dict[str, Any]], optional): The filters for the upsert. Defaults to None. + namespace (Optional[str], optional): The namespace for the documents. Defaults to None, which uses the instance namespace. + """ + _namespace = self.namespace if namespace is None else namespace + vectors = [] + for document in documents: + document.embed(embedder=self.embedder) + document.meta_data["text"] = document.content + data_to_upsert = Vector( + id=document.id, + vector=document.embedding, + metadata=document.meta_data, + data=document.content + ) + vectors.append(data_to_upsert) + + self.index.upsert(vectors, namespace=_namespace) + + def upsert_available(self) -> bool: + """Check if upsert operation is available. + + Returns: + True + + """ + return True + + def insert(self, documents: List[Document], filters: Optional[Dict[str, Any]] = None) -> None: + """Insert documents into the index. + + This method is not supported by Upstash. Use `upsert` instead. + + Args: + documents (List[Document]): The documents to insert. + filters (Optional[Dict[str, Any]], optional): The filters for the insert. Defaults to None. + + Raises: + NotImplementedError: This method is not supported by Upstash. + + """ + raise NotImplementedError("Upstash does not support insert operations. Use upsert instead.") + + def search(self, + query: str, + limit: int = 5, + filters: Optional[str] = "", + namespace: Optional[str] = None, + ) -> List[Document]: + """Search for documents in the index. + + Args: + query (str): The query string to search for. + limit (int, optional): Maximum number of results to return. Defaults to 5. + filters (Optional[str], optional): Metadata filters for the search. Defaults to "". + namespace (Optional[str], optional): The namespace to search in. Defaults to None, which uses the instance namespace. + include_data (Optional[bool], optional): Whether to include document data in results. Defaults to False. + include_metadata (Optional[bool], optional): Whether to include metadata in results. Defaults to False. + include_vectors (Optional[bool], optional): Whether to include vectors in results. Defaults to False. + + Returns: + List[Document]: List of matching documents. + """ + _namespace = self.namespace if namespace is None else namespace + dense_embedding = self.embedder.get_embedding(query) + + if dense_embedding is None: + logger.error(f"Error getting embedding for Query: {query}") + return [] + + response = self.index.query( + vector=dense_embedding, + namespace=_namespace, + top_k=limit, + filter=filters, + include_data=True, + include_metadata=True, + include_vectors=True + ) + + search_results = [ + Document( + content=result.data, + id=result.id, + meta_data=result.metadata, + embedding=result.vector, + ) + for result in response + ] + + if self.reranker: + search_results = self.reranker.rerank(query=query, documents=search_results) + + return search_results + + def delete(self, namespace: Optional[str] = None, delete_all: bool = False) -> bool: + """Clear the index. + + Args: + namespace (Optional[str], optional): The namespace to clear. Defaults to None, which uses the instance namespace. + delete_all (bool, optional): Whether to delete all documents in the index. Defaults to False. + + Returns: + bool: True if the index was deleted, False otherwise. + """ + _namespace = self.namespace if namespace is None else namespace + return self.index.reset(namespace=_namespace, all=delete_all) + + def get_index_info(self) -> InfoResult: + """Get information about the index. + + Returns: + InfoResult: Information about the index including size, vector count, etc. + """ + return self.index.info() + + def optimize(self) -> None: + """Optimize the index. + + This method is empty as Upstash automatically optimizes indexes. + """ + pass \ No newline at end of file From eb59269ed3373de95aaaac0dfa395e80a73fdde8 Mon Sep 17 00:00:00 2001 From: Abdusshh Date: Tue, 31 Dec 2024 21:09:08 +0300 Subject: [PATCH 03/13] Import upstash vector class --- phi/vectordb/upstash/__init__.py | 1 + 1 file changed, 1 insertion(+) create mode 100644 phi/vectordb/upstash/__init__.py diff --git a/phi/vectordb/upstash/__init__.py b/phi/vectordb/upstash/__init__.py new file mode 100644 index 0000000000..e2506ee765 --- /dev/null +++ b/phi/vectordb/upstash/__init__.py @@ -0,0 +1 @@ +from phi.vectordb.upstash.upstash import Upstash From dfbf04bd88f1d609e04e676d299e229c1bd81207 Mon Sep 17 00:00:00 2001 From: Abdusshh Date: Tue, 31 Dec 2024 21:09:26 +0300 Subject: [PATCH 04/13] Add recipe for using upstash vector --- cookbook/vectordb/upstash.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 cookbook/vectordb/upstash.py diff --git a/cookbook/vectordb/upstash.py b/cookbook/vectordb/upstash.py new file mode 100644 index 0000000000..eba01b796e --- /dev/null +++ b/cookbook/vectordb/upstash.py @@ -0,0 +1,29 @@ +# install upstash-vector - `pip install upstash-vector` + +from phi.agent import Agent +from phi.knowledge.pdf import PDFUrlKnowledgeBase +from phi.vectordb.upstash import Upstash +from phi.embedder.openai import OpenAIEmbedder + +# OPENAI_API_KEY must be set in the environment +VECTOR_DB_DIMENSION = 1536 + +# Initialize Upstash DB +vector_db = Upstash( + url="UPSTASH_VECTOR_REST_URL", + token="UPSTASH_VECTOR_REST_TOKEN", + dimension=VECTOR_DB_DIMENSION, + embedder=OpenAIEmbedder(dimensions=VECTOR_DB_DIMENSION), +) + +# Create a new PDFUrlKnowledgeBase +knowledge_base = PDFUrlKnowledgeBase( + urls=["https://phi-public.s3.amazonaws.com/recipes/ThaiRecipes.pdf"], + vector_db=vector_db, +) + +knowledge_base.load(recreate=False, upsert=True) # Comment out after first run + +# Create and use the agent +agent = Agent(knowledge_base=knowledge_base, use_tools=True, show_tool_calls=True) +agent.print_response("What are some tips for cooking glass noodles?", markdown=True) \ No newline at end of file From c8f751d0f4dd164c3cb3d7e1f02ef7c383f1beed Mon Sep 17 00:00:00 2001 From: Abdusshh Date: Tue, 31 Dec 2024 21:10:03 +0300 Subject: [PATCH 05/13] Format upstash vector recipe --- cookbook/vectordb/upstash.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cookbook/vectordb/upstash.py b/cookbook/vectordb/upstash.py index eba01b796e..9f316fe22c 100644 --- a/cookbook/vectordb/upstash.py +++ b/cookbook/vectordb/upstash.py @@ -10,7 +10,7 @@ # Initialize Upstash DB vector_db = Upstash( - url="UPSTASH_VECTOR_REST_URL", + url="UPSTASH_VECTOR_REST_URL", token="UPSTASH_VECTOR_REST_TOKEN", dimension=VECTOR_DB_DIMENSION, embedder=OpenAIEmbedder(dimensions=VECTOR_DB_DIMENSION), @@ -26,4 +26,4 @@ # Create and use the agent agent = Agent(knowledge_base=knowledge_base, use_tools=True, show_tool_calls=True) -agent.print_response("What are some tips for cooking glass noodles?", markdown=True) \ No newline at end of file +agent.print_response("What are some tips for cooking glass noodles?", markdown=True) From f0daac9d8f7db3e1da08aff2eaf89e9d08881154 Mon Sep 17 00:00:00 2001 From: Abdusshh Date: Tue, 31 Dec 2024 21:10:42 +0300 Subject: [PATCH 06/13] Format upstash vector class --- phi/vectordb/upstash/upstash.py | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/phi/vectordb/upstash/upstash.py b/phi/vectordb/upstash/upstash.py index 341c294bf0..c807f2c97f 100644 --- a/phi/vectordb/upstash/upstash.py +++ b/phi/vectordb/upstash/upstash.py @@ -17,6 +17,7 @@ DEFAULT_NAMESPACE = "" + class Upstash(VectorDb): """A class representing an Upstash Vector database. @@ -68,6 +69,7 @@ def __init__( _embedder = embedder if _embedder is None: from phi.embedder.openai import OpenAIEmbedder + _embedder = OpenAIEmbedder(dimensions=self.dimension) self.embedder: Embedder = _embedder self.reranker: Optional[Reranker] = reranker @@ -178,10 +180,7 @@ def namespace_exists(self, namespace: str) -> bool: return namespace in namespaces def upsert( - self, - documents: List[Document], - filters: Optional[Dict[str, Any]] = None, - namespace: Optional[str] = None + self, documents: List[Document], filters: Optional[Dict[str, Any]] = None, namespace: Optional[str] = None ) -> None: """Upsert documents into the index. @@ -196,15 +195,12 @@ def upsert( document.embed(embedder=self.embedder) document.meta_data["text"] = document.content data_to_upsert = Vector( - id=document.id, - vector=document.embedding, - metadata=document.meta_data, - data=document.content + id=document.id, vector=document.embedding, metadata=document.meta_data, data=document.content ) vectors.append(data_to_upsert) self.index.upsert(vectors, namespace=_namespace) - + def upsert_available(self) -> bool: """Check if upsert operation is available. @@ -229,9 +225,10 @@ def insert(self, documents: List[Document], filters: Optional[Dict[str, Any]] = """ raise NotImplementedError("Upstash does not support insert operations. Use upsert instead.") - def search(self, - query: str, - limit: int = 5, + def search( + self, + query: str, + limit: int = 5, filters: Optional[str] = "", namespace: Optional[str] = None, ) -> List[Document]: @@ -263,7 +260,7 @@ def search(self, filter=filters, include_data=True, include_metadata=True, - include_vectors=True + include_vectors=True, ) search_results = [ @@ -307,4 +304,4 @@ def optimize(self) -> None: This method is empty as Upstash automatically optimizes indexes. """ - pass \ No newline at end of file + pass From c5ee841a086ec58dab3ce7a74cb918183737ef61 Mon Sep 17 00:00:00 2001 From: Abdusshh Date: Tue, 31 Dec 2024 21:27:44 +0300 Subject: [PATCH 07/13] Validate upstash vector --- phi/vectordb/upstash/upstash.py | 74 ++++++++++++++++++++++----------- 1 file changed, 49 insertions(+), 25 deletions(-) diff --git a/phi/vectordb/upstash/upstash.py b/phi/vectordb/upstash/upstash.py index c807f2c97f..72f737c8d4 100644 --- a/phi/vectordb/upstash/upstash.py +++ b/phi/vectordb/upstash/upstash.py @@ -1,4 +1,4 @@ -from typing import Optional, Dict, List, Any, Union +from typing import Optional, Dict, List, Any try: from upstash_vector import Index, Vector @@ -56,13 +56,13 @@ def __init__( reranker: Optional[Reranker] = None, **kwargs, ): - self._index = None + self._index: Optional[Index] = None self.url: str = url self.token: str = token - self.retries: int = retries - self.retry_interval: float = retry_interval + self.retries: int = retries if retries is not None else 3 + self.retry_interval: float = retry_interval if retry_interval is not None else 1.0 self.dimension: Optional[int] = dimension - self.namespace: str = namespace + self.namespace: str = namespace if namespace is not None else DEFAULT_NAMESPACE self.kwargs: Dict[str, Any] = kwargs # Initialize embedder for embedding the document contents @@ -89,9 +89,15 @@ def index(self) -> Index: retries=self.retries, retry_interval=self.retry_interval, ) - - index_dimension = self._index.info().dimension - if index_dimension != self.dimension: + if self._index is None: + raise ValueError("Failed to initialize Upstash index") + + info = self._index.info() + if info is None: + raise ValueError("Failed to get index info") + + index_dimension = info.dimension + if self.dimension is not None and index_dimension != self.dimension: raise ValueError( f"Index dimension {index_dimension} does not match provided dimension {self.dimension}" ) @@ -151,7 +157,11 @@ def doc_exists(self, document: Document) -> bool: bool: True if the document exists, False otherwise. """ - response = self.index.fetch(ids=[document.id]) + if document.id is None: + logger.error("Document ID cannot be None") + return False + documents_to_fetch = [document.id] + response = self.index.fetch(ids=documents_to_fetch) return len(response) > 0 def name_exists(self, name: str) -> bool: @@ -193,12 +203,20 @@ def upsert( vectors = [] for document in documents: document.embed(embedder=self.embedder) + if document.id is None or document.embedding is None: + logger.error(f"Document ID and embedding must not be None. Skipping document with content: {document.content[:100]}...") + continue + document.meta_data["text"] = document.content data_to_upsert = Vector( id=document.id, vector=document.embedding, metadata=document.meta_data, data=document.content ) vectors.append(data_to_upsert) + if not vectors: + logger.warning("No valid documents to upsert") + return + self.index.upsert(vectors, namespace=_namespace) def upsert_available(self) -> bool: @@ -229,7 +247,7 @@ def search( self, query: str, limit: int = 5, - filters: Optional[str] = "", + filters: Optional[Dict[str, Any]] = None, namespace: Optional[str] = None, ) -> List[Document]: """Search for documents in the index. @@ -237,11 +255,8 @@ def search( Args: query (str): The query string to search for. limit (int, optional): Maximum number of results to return. Defaults to 5. - filters (Optional[str], optional): Metadata filters for the search. Defaults to "". + filters (Optional[Dict[str, Any]], optional): Metadata filters for the search. namespace (Optional[str], optional): The namespace to search in. Defaults to None, which uses the instance namespace. - include_data (Optional[bool], optional): Whether to include document data in results. Defaults to False. - include_metadata (Optional[bool], optional): Whether to include metadata in results. Defaults to False. - include_vectors (Optional[bool], optional): Whether to include vectors in results. Defaults to False. Returns: List[Document]: List of matching documents. @@ -253,25 +268,33 @@ def search( logger.error(f"Error getting embedding for Query: {query}") return [] + filter_str = "" if filters is None else str(filters) + response = self.index.query( vector=dense_embedding, namespace=_namespace, top_k=limit, - filter=filters, + filter=filter_str, include_data=True, include_metadata=True, include_vectors=True, ) - search_results = [ - Document( - content=result.data, - id=result.id, - meta_data=result.metadata, - embedding=result.vector, - ) - for result in response - ] + if response is None: + logger.info(f"No results found for query: {query}") + return [] + + search_results = [] + for result in response: + if result.data is not None and result.id is not None and result.vector is not None: + search_results.append( + Document( + content=result.data, + id=result.id, + meta_data=result.metadata or {}, + embedding=result.vector, + ) + ) if self.reranker: search_results = self.reranker.rerank(query=query, documents=search_results) @@ -289,7 +312,8 @@ def delete(self, namespace: Optional[str] = None, delete_all: bool = False) -> b bool: True if the index was deleted, False otherwise. """ _namespace = self.namespace if namespace is None else namespace - return self.index.reset(namespace=_namespace, all=delete_all) + response = self.index.reset(namespace=_namespace, all=delete_all) + return True if response.lower().strip() == "success" else False def get_index_info(self) -> InfoResult: """Get information about the index. From 7f5252d76f45b59783ca7d037041641002002ae7 Mon Sep 17 00:00:00 2001 From: Abdusshh Date: Tue, 31 Dec 2024 21:28:36 +0300 Subject: [PATCH 08/13] Reformat upstash vector after validation --- phi/vectordb/upstash/upstash.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/phi/vectordb/upstash/upstash.py b/phi/vectordb/upstash/upstash.py index 72f737c8d4..9b9d8f5224 100644 --- a/phi/vectordb/upstash/upstash.py +++ b/phi/vectordb/upstash/upstash.py @@ -95,7 +95,7 @@ def index(self) -> Index: info = self._index.info() if info is None: raise ValueError("Failed to get index info") - + index_dimension = info.dimension if self.dimension is not None and index_dimension != self.dimension: raise ValueError( @@ -204,9 +204,11 @@ def upsert( for document in documents: document.embed(embedder=self.embedder) if document.id is None or document.embedding is None: - logger.error(f"Document ID and embedding must not be None. Skipping document with content: {document.content[:100]}...") + logger.error( + f"Document ID and embedding must not be None. Skipping document with content: {document.content[:100]}..." + ) continue - + document.meta_data["text"] = document.content data_to_upsert = Vector( id=document.id, vector=document.embedding, metadata=document.meta_data, data=document.content @@ -269,7 +271,7 @@ def search( return [] filter_str = "" if filters is None else str(filters) - + response = self.index.query( vector=dense_embedding, namespace=_namespace, From 36c4c59a2a3dda51080728213347f6380ef2f42c Mon Sep 17 00:00:00 2001 From: Abdusshh Date: Mon, 6 Jan 2025 16:02:17 +0300 Subject: [PATCH 09/13] Remove redundant comments --- phi/vectordb/upstash/upstash.py | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/phi/vectordb/upstash/upstash.py b/phi/vectordb/upstash/upstash.py index 9b9d8f5224..46cb9cdbf0 100644 --- a/phi/vectordb/upstash/upstash.py +++ b/phi/vectordb/upstash/upstash.py @@ -31,17 +31,6 @@ class Upstash(VectorDb): namespace (Optional[str], optional): The namespace to use. Defaults to DEFAULT_NAMESPACE. reranker (Optional[Reranker], optional): The reranker to use. Defaults to None. **kwargs: Additional keyword arguments. - - Attributes: - url (str): The Upstash Vector database URL. - token (str): The Upstash Vector API token. - retries (int): Number of retry attempts. - retry_interval (float): Time interval between retries. - dimension (Optional[int]): The dimension of the embeddings. - namespace (str): The namespace to use. - embedder (Embedder): The embedder instance. - reranker (Optional[Reranker]): The reranker instance. - kwargs (Dict[str, Any]): Additional keyword arguments. """ def __init__( From 09e3f011e4f7de6c9754ced15c70b14852b8555a Mon Sep 17 00:00:00 2001 From: Abdusshh Date: Tue, 7 Jan 2025 08:57:50 +0300 Subject: [PATCH 10/13] Update logger messages for index creation and deletion --- phi/vectordb/upstash/upstash.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/phi/vectordb/upstash/upstash.py b/phi/vectordb/upstash/upstash.py index 46cb9cdbf0..227617bbcb 100644 --- a/phi/vectordb/upstash/upstash.py +++ b/phi/vectordb/upstash/upstash.py @@ -107,12 +107,12 @@ def exists(self) -> bool: def create(self) -> None: """You can create indexes in Upstash Console.""" - logger.info("You can create indexes in Upstash Console.") + logger.info("Indexes can only be created through the Upstash Console. Please create an index before using this vector database.") pass def drop(self) -> None: """You can drop indexes in Upstash Console.""" - logger.info("You can drop indexes in Upstash Console.") + logger.info("Indexes can only be dropped through the Upstash Console. Make sure you have an existing index before performing operations.") pass def drop_namespace(self, namespace: Optional[str] = None) -> None: From e5836a5ae1eeefc56957f6865bfc7cb7aa243b78 Mon Sep 17 00:00:00 2001 From: Abdusshh Date: Tue, 7 Jan 2025 08:58:10 +0300 Subject: [PATCH 11/13] Add docstring to explain how to use Upstash locally --- cookbook/vectordb/upstash.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cookbook/vectordb/upstash.py b/cookbook/vectordb/upstash.py index 9f316fe22c..4596df3af0 100644 --- a/cookbook/vectordb/upstash.py +++ b/cookbook/vectordb/upstash.py @@ -8,6 +8,11 @@ # OPENAI_API_KEY must be set in the environment VECTOR_DB_DIMENSION = 1536 +# How to connect to an Upstash Vector index +# - Create a new index in Upstash Console with the correct dimension +# - Fetch the URL and token from Upstash Console +# - Replace the values below or use environment variables + # Initialize Upstash DB vector_db = Upstash( url="UPSTASH_VECTOR_REST_URL", From 6d1c18ff3aeceaa7d060308964ff304e01d6f04c Mon Sep 17 00:00:00 2001 From: Abdusshh Date: Thu, 30 Jan 2025 17:03:00 +0300 Subject: [PATCH 12/13] chore: refactor comment --- cookbook/vectordb/upstash.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cookbook/vectordb/upstash.py b/cookbook/vectordb/upstash.py index 4596df3af0..46ce94f475 100644 --- a/cookbook/vectordb/upstash.py +++ b/cookbook/vectordb/upstash.py @@ -27,7 +27,8 @@ vector_db=vector_db, ) -knowledge_base.load(recreate=False, upsert=True) # Comment out after first run +# Load the knowledge base - after first run, comment out +knowledge_base.load(recreate=False, upsert=True) # Create and use the agent agent = Agent(knowledge_base=knowledge_base, use_tools=True, show_tool_calls=True) From e570530373fc6f681dc658eee87756a9462f9be8 Mon Sep 17 00:00:00 2001 From: Abdusshh Date: Thu, 30 Jan 2025 17:07:04 +0300 Subject: [PATCH 13/13] chore: remove upstash-vector from pyproject.toml file --- pyproject.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index c956e97cff..b12913a036 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -165,7 +165,6 @@ module = [ "textract.*", "timeout_decorator.*", "torch.*", - "upstash_vector.*", "uvicorn.*", "vertexai.*", "voyageai.*",