Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
timescalevector.py884 linesDownload Raw Back to vectorstores
1"""VectorStore wrapper around a Postgres-TimescaleVector database."""2 3from __future__ import annotations4 5import enum6import logging7import uuid8from datetime import timedelta9from typing import (10    TYPE_CHECKING,11    Any,12    Callable,13    Dict,14    Iterable,15    List,16    Optional,17    Tuple,18    Type,19    Union,20)21 22from langchain_core.documents import Document23from langchain_core.embeddings import Embeddings24from langchain_core.utils import get_from_dict_or_env25from langchain_core.vectorstores import VectorStore26 27from langchain_community.vectorstores.utils import DistanceStrategy28 29if TYPE_CHECKING:30    from timescale_vector import Predicates31 32 33DEFAULT_DISTANCE_STRATEGY = DistanceStrategy.COSINE34 35ADA_TOKEN_COUNT = 153636 37_LANGCHAIN_DEFAULT_COLLECTION_NAME = "langchain_store"38 39 40class TimescaleVector(VectorStore):41    """Timescale Postgres vector store42 43    To use, you should have the ``timescale_vector`` python package installed.44 45    Args:46        service_url: Service url on timescale cloud.47        embedding: Any embedding function implementing48            `langchain.embeddings.base.Embeddings` interface.49        collection_name: The name of the collection to use. (default: langchain_store)50            This will become the table name used for the collection.51        distance_strategy: The distance strategy to use. (default: COSINE)52        pre_delete_collection: If True, will delete the collection if it exists.53            (default: False). Useful for testing.54 55    Example:56        .. code-block:: python57 58            from langchain_community.vectorstores import TimescaleVector59            from langchain_community.embeddings.openai import OpenAIEmbeddings60 61            SERVICE_URL = "postgres://tsdbadmin:<password>@<id>.tsdb.cloud.timescale.com:<port>/tsdb?sslmode=require"62            COLLECTION_NAME = "state_of_the_union_test"63            embeddings = OpenAIEmbeddings()64            vectorestore = TimescaleVector.from_documents(65                embedding=embeddings,66                documents=docs,67                collection_name=COLLECTION_NAME,68                service_url=SERVICE_URL,69            )70    """71 72    def __init__(73        self,74        service_url: str,75        embedding: Embeddings,76        collection_name: str = _LANGCHAIN_DEFAULT_COLLECTION_NAME,77        num_dimensions: int = ADA_TOKEN_COUNT,78        distance_strategy: DistanceStrategy = DEFAULT_DISTANCE_STRATEGY,79        pre_delete_collection: bool = False,80        logger: Optional[logging.Logger] = None,81        relevance_score_fn: Optional[Callable[[float], float]] = None,82        time_partition_interval: Optional[timedelta] = None,83        **kwargs: Any,84    ) -> None:85        try:86            from timescale_vector import client87        except ImportError:88            raise ImportError(89                "Could not import timescale_vector python package. "90                "Please install it with `pip install timescale-vector`."91            )92 93        self.service_url = service_url94        self.embedding = embedding95        self.collection_name = collection_name96        self.num_dimensions = num_dimensions97        self._distance_strategy = distance_strategy98        self.pre_delete_collection = pre_delete_collection99        self.logger = logger or logging.getLogger(__name__)100        self.override_relevance_score_fn = relevance_score_fn101        self._time_partition_interval = time_partition_interval102        self.sync_client = client.Sync(103            self.service_url,104            self.collection_name,105            self.num_dimensions,106            self._distance_strategy.value.lower(),107            time_partition_interval=self._time_partition_interval,108            **kwargs,109        )110        self.async_client = client.Async(111            self.service_url,112            self.collection_name,113            self.num_dimensions,114            self._distance_strategy.value.lower(),115            time_partition_interval=self._time_partition_interval,116            **kwargs,117        )118        self.__post_init__()119 120    def __post_init__(121        self,122    ) -> None:123        """124        Initialize the store.125        """126        self.sync_client.create_tables()127        if self.pre_delete_collection:128            self.sync_client.delete_all()129 130    @property131    def embeddings(self) -> Embeddings:132        return self.embedding133 134    def drop_tables(self) -> None:135        self.sync_client.drop_table()136 137    @classmethod138    def __from(139        cls,140        texts: List[str],141        embeddings: List[List[float]],142        embedding: Embeddings,143        metadatas: Optional[List[dict]] = None,144        ids: Optional[List[str]] = None,145        collection_name: str = _LANGCHAIN_DEFAULT_COLLECTION_NAME,146        distance_strategy: DistanceStrategy = DEFAULT_DISTANCE_STRATEGY,147        service_url: Optional[str] = None,148        pre_delete_collection: bool = False,149        **kwargs: Any,150    ) -> TimescaleVector:151        num_dimensions = len(embeddings[0])152 153        if ids is None:154            ids = [str(uuid.uuid4()) for _ in texts]155 156        if not metadatas:157            metadatas = [{} for _ in texts]158 159        if service_url is None:160            service_url = cls.get_service_url(kwargs)161 162        store = cls(163            service_url=service_url,164            num_dimensions=num_dimensions,165            collection_name=collection_name,166            embedding=embedding,167            distance_strategy=distance_strategy,168            pre_delete_collection=pre_delete_collection,169            **kwargs,170        )171 172        store.add_embeddings(173            texts=texts, embeddings=embeddings, metadatas=metadatas, ids=ids, **kwargs174        )175 176        return store177 178    @classmethod179    async def __afrom(180        cls,181        texts: List[str],182        embeddings: List[List[float]],183        embedding: Embeddings,184        metadatas: Optional[List[dict]] = None,185        ids: Optional[List[str]] = None,186        collection_name: str = _LANGCHAIN_DEFAULT_COLLECTION_NAME,187        distance_strategy: DistanceStrategy = DEFAULT_DISTANCE_STRATEGY,188        service_url: Optional[str] = None,189        pre_delete_collection: bool = False,190        **kwargs: Any,191    ) -> TimescaleVector:192        num_dimensions = len(embeddings[0])193 194        if ids is None:195            ids = [str(uuid.uuid4()) for _ in texts]196 197        if not metadatas:198            metadatas = [{} for _ in texts]199 200        if service_url is None:201            service_url = cls.get_service_url(kwargs)202 203        store = cls(204            service_url=service_url,205            num_dimensions=num_dimensions,206            collection_name=collection_name,207            embedding=embedding,208            distance_strategy=distance_strategy,209            pre_delete_collection=pre_delete_collection,210            **kwargs,211        )212 213        await store.aadd_embeddings(214            texts=texts, embeddings=embeddings, metadatas=metadatas, ids=ids, **kwargs215        )216 217        return store218 219    def add_embeddings(220        self,221        texts: Iterable[str],222        embeddings: List[List[float]],223        metadatas: Optional[List[dict]] = None,224        ids: Optional[List[str]] = None,225        **kwargs: Any,226    ) -> List[str]:227        """Add embeddings to the vectorstore.228 229        Args:230            texts: Iterable of strings to add to the vectorstore.231            embeddings: List of list of embedding vectors.232            metadatas: List of metadatas associated with the texts.233            kwargs: vectorstore specific parameters234        """235        if ids is None:236            ids = [str(uuid.uuid4()) for _ in texts]237 238        if not metadatas:239            metadatas = [{} for _ in texts]240 241        records = list(zip(ids, metadatas, texts, embeddings))242        self.sync_client.upsert(records)243 244        return ids245 246    async def aadd_embeddings(247        self,248        texts: Iterable[str],249        embeddings: List[List[float]],250        metadatas: Optional[List[dict]] = None,251        ids: Optional[List[str]] = None,252        **kwargs: Any,253    ) -> List[str]:254        """Add embeddings to the vectorstore.255 256        Args:257            texts: Iterable of strings to add to the vectorstore.258            embeddings: List of list of embedding vectors.259            metadatas: List of metadatas associated with the texts.260            kwargs: vectorstore specific parameters261        """262        if ids is None:263            ids = [str(uuid.uuid4()) for _ in texts]264 265        if not metadatas:266            metadatas = [{} for _ in texts]267 268        records = list(zip(ids, metadatas, texts, embeddings))269        await self.async_client.upsert(records)270 271        return ids272 273    def add_texts(274        self,275        texts: Iterable[str],276        metadatas: Optional[List[dict]] = None,277        ids: Optional[List[str]] = None,278        **kwargs: Any,279    ) -> List[str]:280        """Run more texts through the embeddings and add to the vectorstore.281 282        Args:283            texts: Iterable of strings to add to the vectorstore.284            metadatas: Optional list of metadatas associated with the texts.285            kwargs: vectorstore specific parameters286 287        Returns:288            List of ids from adding the texts into the vectorstore.289        """290        embeddings = self.embedding.embed_documents(list(texts))291        return self.add_embeddings(292            texts=texts, embeddings=embeddings, metadatas=metadatas, ids=ids, **kwargs293        )294 295    async def aadd_texts(296        self,297        texts: Iterable[str],298        metadatas: Optional[List[dict]] = None,299        ids: Optional[List[str]] = None,300        **kwargs: Any,301    ) -> List[str]:302        """Run more texts through the embeddings and add to the vectorstore.303 304        Args:305            texts: Iterable of strings to add to the vectorstore.306            metadatas: Optional list of metadatas associated with the texts.307            kwargs: vectorstore specific parameters308 309        Returns:310            List of ids from adding the texts into the vectorstore.311        """312        embeddings = self.embedding.embed_documents(list(texts))313        return await self.aadd_embeddings(314            texts=texts, embeddings=embeddings, metadatas=metadatas, ids=ids, **kwargs315        )316 317    def _embed_query(self, query: str) -> Optional[List[float]]:318        # an empty query should not be embedded319        if query is None or query == "" or query.isspace():320            return None321        else:322            return self.embedding.embed_query(query)323 324    def similarity_search(325        self,326        query: str,327        k: int = 4,328        filter: Optional[Union[dict, list]] = None,329        predicates: Optional[Predicates] = None,330        **kwargs: Any,331    ) -> List[Document]:332        """Run similarity search with TimescaleVector with distance.333 334        Args:335            query (str): Query text to search for.336            k (int): Number of results to return. Defaults to 4.337            filter (Optional[Dict[str, str]]): Filter by metadata. Defaults to None.338 339        Returns:340            List of Documents most similar to the query.341        """342        embedding = self._embed_query(query)343        return self.similarity_search_by_vector(344            embedding=embedding,345            k=k,346            filter=filter,347            predicates=predicates,348            **kwargs,349        )350 351    async def asimilarity_search(352        self,353        query: str,354        k: int = 4,355        filter: Optional[Union[dict, list]] = None,356        predicates: Optional[Predicates] = None,357        **kwargs: Any,358    ) -> List[Document]:359        """Run similarity search with TimescaleVector with distance.360 361        Args:362            query (str): Query text to search for.363            k (int): Number of results to return. Defaults to 4.364            filter (Optional[Dict[str, str]]): Filter by metadata. Defaults to None.365 366        Returns:367            List of Documents most similar to the query.368        """369        embedding = self._embed_query(query)370        return await self.asimilarity_search_by_vector(371            embedding=embedding,372            k=k,373            filter=filter,374            predicates=predicates,375            **kwargs,376        )377 378    def similarity_search_with_score(379        self,380        query: str,381        k: int = 4,382        filter: Optional[Union[dict, list]] = None,383        predicates: Optional[Predicates] = None,384        **kwargs: Any,385    ) -> List[Tuple[Document, float]]:386        """Return docs most similar to query.387 388        Args:389            query: Text to look up documents similar to.390            k: Number of Documents to return. Defaults to 4.391            filter (Optional[Dict[str, str]]): Filter by metadata. Defaults to None.392 393        Returns:394            List of Documents most similar to the query and score for each395        """396        embedding = self._embed_query(query)397        docs = self.similarity_search_with_score_by_vector(398            embedding=embedding,399            k=k,400            filter=filter,401            predicates=predicates,402            **kwargs,403        )404        return docs405 406    async def asimilarity_search_with_score(407        self,408        query: str,409        k: int = 4,410        filter: Optional[Union[dict, list]] = None,411        predicates: Optional[Predicates] = None,412        **kwargs: Any,413    ) -> List[Tuple[Document, float]]:414        """Return docs most similar to query.415 416        Args:417            query: Text to look up documents similar to.418            k: Number of Documents to return. Defaults to 4.419            filter (Optional[Dict[str, str]]): Filter by metadata. Defaults to None.420 421        Returns:422            List of Documents most similar to the query and score for each423        """424 425        embedding = self._embed_query(query)426        return await self.asimilarity_search_with_score_by_vector(427            embedding=embedding,428            k=k,429            filter=filter,430            predicates=predicates,431            **kwargs,432        )433 434    def date_to_range_filter(self, **kwargs: Any) -> Any:435        constructor_args = {436            key: kwargs[key]437            for key in [438                "start_date",439                "end_date",440                "time_delta",441                "start_inclusive",442                "end_inclusive",443            ]444            if key in kwargs445        }446        if not constructor_args or len(constructor_args) == 0:447            return None448 449        try:450            from timescale_vector import client451        except ImportError:452            raise ImportError(453                "Could not import timescale_vector python package. "454                "Please install it with `pip install timescale-vector`."455            )456        return client.UUIDTimeRange(**constructor_args)457 458    def similarity_search_with_score_by_vector(459        self,460        embedding: Optional[List[float]],461        k: int = 4,462        filter: Optional[Union[dict, list]] = None,463        predicates: Optional[Predicates] = None,464        **kwargs: Any,465    ) -> List[Tuple[Document, float]]:466        try:467            from timescale_vector import client468        except ImportError:469            raise ImportError(470                "Could not import timescale_vector python package. "471                "Please install it with `pip install timescale-vector`."472            )473 474        results = self.sync_client.search(475            embedding,476            limit=k,477            filter=filter,478            predicates=predicates,479            uuid_time_filter=self.date_to_range_filter(**kwargs),480        )481 482        docs = [483            (484                Document(485                    page_content=result[client.SEARCH_RESULT_CONTENTS_IDX],486                    metadata=result[client.SEARCH_RESULT_METADATA_IDX],487                ),488                result[client.SEARCH_RESULT_DISTANCE_IDX],489            )490            for result in results491        ]492        return docs493 494    async def asimilarity_search_with_score_by_vector(495        self,496        embedding: Optional[List[float]],497        k: int = 4,498        filter: Optional[Union[dict, list]] = None,499        predicates: Optional[Predicates] = None,500        **kwargs: Any,501    ) -> List[Tuple[Document, float]]:502        try:503            from timescale_vector import client504        except ImportError:505            raise ImportError(506                "Could not import timescale_vector python package. "507                "Please install it with `pip install timescale-vector`."508            )509 510        results = await self.async_client.search(511            embedding,512            limit=k,513            filter=filter,514            predicates=predicates,515            uuid_time_filter=self.date_to_range_filter(**kwargs),516        )517 518        docs = [519            (520                Document(521                    page_content=result[client.SEARCH_RESULT_CONTENTS_IDX],522                    metadata=result[client.SEARCH_RESULT_METADATA_IDX],523                ),524                result[client.SEARCH_RESULT_DISTANCE_IDX],525            )526            for result in results527        ]528        return docs529 530    def similarity_search_by_vector(531        self,532        embedding: Optional[List[float]],533        k: int = 4,534        filter: Optional[Union[dict, list]] = None,535        predicates: Optional[Predicates] = None,536        **kwargs: Any,537    ) -> List[Document]:538        """Return docs most similar to embedding vector.539 540        Args:541            embedding: Embedding to look up documents similar to.542            k: Number of Documents to return. Defaults to 4.543            filter (Optional[Dict[str, str]]): Filter by metadata. Defaults to None.544 545        Returns:546            List of Documents most similar to the query vector.547        """548        docs_and_scores = self.similarity_search_with_score_by_vector(549            embedding=embedding, k=k, filter=filter, predicates=predicates, **kwargs550        )551        return [doc for doc, _ in docs_and_scores]552 553    async def asimilarity_search_by_vector(554        self,555        embedding: Optional[List[float]],556        k: int = 4,557        filter: Optional[Union[dict, list]] = None,558        predicates: Optional[Predicates] = None,559        **kwargs: Any,560    ) -> List[Document]:561        """Return docs most similar to embedding vector.562 563        Args:564            embedding: Embedding to look up documents similar to.565            k: Number of Documents to return. Defaults to 4.566            filter (Optional[Dict[str, str]]): Filter by metadata. Defaults to None.567 568        Returns:569            List of Documents most similar to the query vector.570        """571        docs_and_scores = await self.asimilarity_search_with_score_by_vector(572            embedding=embedding, k=k, filter=filter, predicates=predicates, **kwargs573        )574        return [doc for doc, _ in docs_and_scores]575 576    @classmethod577    def from_texts(578        cls: Type[TimescaleVector],579        texts: List[str],580        embedding: Embeddings,581        metadatas: Optional[List[dict]] = None,582        collection_name: str = _LANGCHAIN_DEFAULT_COLLECTION_NAME,583        distance_strategy: DistanceStrategy = DEFAULT_DISTANCE_STRATEGY,584        ids: Optional[List[str]] = None,585        pre_delete_collection: bool = False,586        **kwargs: Any,587    ) -> TimescaleVector:588        """589        Return VectorStore initialized from texts and embeddings.590        Postgres connection string is required591        "Either pass it as a parameter592        or set the TIMESCALE_SERVICE_URL environment variable.593        """594        embeddings = embedding.embed_documents(list(texts))595 596        return cls.__from(597            texts,598            embeddings,599            embedding,600            metadatas=metadatas,601            ids=ids,602            collection_name=collection_name,603            distance_strategy=distance_strategy,604            pre_delete_collection=pre_delete_collection,605            **kwargs,606        )607 608    @classmethod609    async def afrom_texts(610        cls: Type[TimescaleVector],611        texts: List[str],612        embedding: Embeddings,613        metadatas: Optional[List[dict]] = None,614        collection_name: str = _LANGCHAIN_DEFAULT_COLLECTION_NAME,615        distance_strategy: DistanceStrategy = DEFAULT_DISTANCE_STRATEGY,616        ids: Optional[List[str]] = None,617        pre_delete_collection: bool = False,618        **kwargs: Any,619    ) -> TimescaleVector:620        """621        Return VectorStore initialized from texts and embeddings.622        Postgres connection string is required623        "Either pass it as a parameter624        or set the TIMESCALE_SERVICE_URL environment variable.625        """626        embeddings = embedding.embed_documents(list(texts))627 628        return await cls.__afrom(629            texts,630            embeddings,631            embedding,632            metadatas=metadatas,633            ids=ids,634            collection_name=collection_name,635            distance_strategy=distance_strategy,636            pre_delete_collection=pre_delete_collection,637            **kwargs,638        )639 640    @classmethod641    def from_embeddings(642        cls,643        text_embeddings: List[Tuple[str, List[float]]],644        embedding: Embeddings,645        metadatas: Optional[List[dict]] = None,646        collection_name: str = _LANGCHAIN_DEFAULT_COLLECTION_NAME,647        distance_strategy: DistanceStrategy = DEFAULT_DISTANCE_STRATEGY,648        ids: Optional[List[str]] = None,649        pre_delete_collection: bool = False,650        **kwargs: Any,651    ) -> TimescaleVector:652        """Construct TimescaleVector wrapper from raw documents and pre-653        generated embeddings.654 655        Return VectorStore initialized from documents and embeddings.656        Postgres connection string is required657        "Either pass it as a parameter658        or set the TIMESCALE_SERVICE_URL environment variable.659 660        Example:661            .. code-block:: python662 663                from langchain_community.vectorstores import TimescaleVector664                from langchain_community.embeddings import OpenAIEmbeddings665                embeddings = OpenAIEmbeddings()666                text_embeddings = embeddings.embed_documents(texts)667                text_embedding_pairs = list(zip(texts, text_embeddings))668                tvs = TimescaleVector.from_embeddings(text_embedding_pairs, embeddings)669        """670        texts = [t[0] for t in text_embeddings]671        embeddings = [t[1] for t in text_embeddings]672 673        return cls.__from(674            texts,675            embeddings,676            embedding,677            metadatas=metadatas,678            ids=ids,679            collection_name=collection_name,680            distance_strategy=distance_strategy,681            pre_delete_collection=pre_delete_collection,682            **kwargs,683        )684 685    @classmethod686    async def afrom_embeddings(687        cls,688        text_embeddings: List[Tuple[str, List[float]]],689        embedding: Embeddings,690        metadatas: Optional[List[dict]] = None,691        collection_name: str = _LANGCHAIN_DEFAULT_COLLECTION_NAME,692        distance_strategy: DistanceStrategy = DEFAULT_DISTANCE_STRATEGY,693        ids: Optional[List[str]] = None,694        pre_delete_collection: bool = False,695        **kwargs: Any,696    ) -> TimescaleVector:697        """Construct TimescaleVector wrapper from raw documents and pre-698        generated embeddings.699 700        Return VectorStore initialized from documents and embeddings.701        Postgres connection string is required702        "Either pass it as a parameter703        or set the TIMESCALE_SERVICE_URL environment variable.704 705        Example:706            .. code-block:: python707 708                from langchain_community.vectorstores import TimescaleVector709                from langchain_community.embeddings import OpenAIEmbeddings710                embeddings = OpenAIEmbeddings()711                text_embeddings = embeddings.embed_documents(texts)712                text_embedding_pairs = list(zip(texts, text_embeddings))713                tvs = TimescaleVector.from_embeddings(text_embedding_pairs, embeddings)714        """715        texts = [t[0] for t in text_embeddings]716        embeddings = [t[1] for t in text_embeddings]717 718        return await cls.__afrom(719            texts,720            embeddings,721            embedding,722            metadatas=metadatas,723            ids=ids,724            collection_name=collection_name,725            distance_strategy=distance_strategy,726            pre_delete_collection=pre_delete_collection,727            **kwargs,728        )729 730    @classmethod731    def from_existing_index(732        cls: Type[TimescaleVector],733        embedding: Embeddings,734        collection_name: str = _LANGCHAIN_DEFAULT_COLLECTION_NAME,735        distance_strategy: DistanceStrategy = DEFAULT_DISTANCE_STRATEGY,736        pre_delete_collection: bool = False,737        **kwargs: Any,738    ) -> TimescaleVector:739        """740        Get instance of an existing TimescaleVector store.This method will741        return the instance of the store without inserting any new742        embeddings743        """744 745        service_url = cls.get_service_url(kwargs)746 747        store = cls(748            service_url=service_url,749            collection_name=collection_name,750            embedding=embedding,751            distance_strategy=distance_strategy,752            pre_delete_collection=pre_delete_collection,753        )754 755        return store756 757    @classmethod758    def get_service_url(cls, kwargs: Dict[str, Any]) -> str:759        service_url: str = get_from_dict_or_env(760            data=kwargs,761            key="service_url",762            env_key="TIMESCALE_SERVICE_URL",763        )764 765        if not service_url:766            raise ValueError(767                "Postgres connection string is required"768                "Either pass it as a parameter"769                "or set the TIMESCALE_SERVICE_URL environment variable."770            )771 772        return service_url773 774    @classmethod775    def service_url_from_db_params(776        cls,777        host: str,778        port: int,779        database: str,780        user: str,781        password: str,782    ) -> str:783        """Return connection string from database parameters."""784        return f"postgresql://{user}:{password}@{host}:{port}/{database}"785 786    def _select_relevance_score_fn(self) -> Callable[[float], float]:787        """788        The 'correct' relevance function789        may differ depending on a few things, including:790        - the distance / similarity metric used by the VectorStore791        - the scale of your embeddings (OpenAI's are unit normed. Many others are not!)792        - embedding dimensionality793        - etc.794        """795        if self.override_relevance_score_fn is not None:796            return self.override_relevance_score_fn797 798        # Default strategy is to rely on distance strategy provided799        # in vectorstore constructor800        if self._distance_strategy == DistanceStrategy.COSINE:801            return self._cosine_relevance_score_fn802        elif self._distance_strategy == DistanceStrategy.EUCLIDEAN_DISTANCE:803            return self._euclidean_relevance_score_fn804        elif self._distance_strategy == DistanceStrategy.MAX_INNER_PRODUCT:805            return self._max_inner_product_relevance_score_fn806        else:807            raise ValueError(808                "No supported normalization function"809                f" for distance_strategy of {self._distance_strategy}."810                "Consider providing relevance_score_fn to TimescaleVector constructor."811            )812 813    def delete(self, ids: Optional[List[str]] = None, **kwargs: Any) -> Optional[bool]:814        """Delete by vector ID or other criteria.815 816        Args:817            ids: List of ids to delete.818            **kwargs: Other keyword arguments that subclasses might use.819 820        Returns:821            Optional[bool]: True if deletion is successful,822            False otherwise, None if not implemented.823        """824        if ids is None:825            raise ValueError("No ids provided to delete.")826 827        self.sync_client.delete_by_ids(ids)828        return True829 830    # todo should this be part of delete|()?831    def delete_by_metadata(832        self, filter: Union[Dict[str, str], List[Dict[str, str]]], **kwargs: Any833    ) -> Optional[bool]:834        """Delete by vector ID or other criteria.835 836        Args:837            ids: List of ids to delete.838            **kwargs: Other keyword arguments that subclasses might use.839 840        Returns:841            Optional[bool]: True if deletion is successful,842            False otherwise, None if not implemented.843        """844 845        self.sync_client.delete_by_metadata(filter)846        return True847 848    class IndexType(str, enum.Enum):849        """Enumerator for the supported Index types"""850 851        TIMESCALE_VECTOR = "tsv"852        PGVECTOR_IVFFLAT = "ivfflat"853        PGVECTOR_HNSW = "hnsw"854 855    DEFAULT_INDEX_TYPE = IndexType.TIMESCALE_VECTOR856 857    def create_index(858        self, index_type: Union[IndexType, str] = DEFAULT_INDEX_TYPE, **kwargs: Any859    ) -> None:860        try:861            from timescale_vector import client862        except ImportError:863            raise ImportError(864                "Could not import timescale_vector python package. "865                "Please install it with `pip install timescale-vector`."866            )867 868        index_type = (869            index_type.value if isinstance(index_type, self.IndexType) else index_type870        )871        if index_type == self.IndexType.PGVECTOR_IVFFLAT.value:872            self.sync_client.create_embedding_index(client.IvfflatIndex(**kwargs))873 874        if index_type == self.IndexType.PGVECTOR_HNSW.value:875            self.sync_client.create_embedding_index(client.HNSWIndex(**kwargs))876 877        if index_type == self.IndexType.TIMESCALE_VECTOR.value:878            self.sync_client.create_embedding_index(879                client.TimescaleVectorIndex(**kwargs)880            )881 882    def drop_index(self) -> None:883        self.sync_client.drop_embedding_index()884 
codekingpro/portable-devtools · Team Ai