Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
openai.py717 linesDownload Raw Back to embeddings
1from __future__ import annotations2 3import logging4import os5import warnings6from typing import (7    Any,8    Callable,9    Dict,10    List,11    Literal,12    Mapping,13    Optional,14    Sequence,15    Set,16    Tuple,17    Union,18    cast,19)20 21import numpy as np22from langchain_core._api.deprecation import deprecated23from langchain_core.embeddings import Embeddings24from langchain_core.utils import (25    get_from_dict_or_env,26    get_pydantic_field_names,27    pre_init,28)29from pydantic import BaseModel, ConfigDict, Field, model_validator30from tenacity import (31    AsyncRetrying,32    before_sleep_log,33    retry,34    retry_if_exception_type,35    stop_after_attempt,36    wait_exponential,37)38 39from langchain_community.utils.openai import is_openai_v140 41logger = logging.getLogger(__name__)42 43 44def _create_retry_decorator(embeddings: OpenAIEmbeddings) -> Callable[[Any], Any]:45    import openai46 47    # Wait 2^x * 1 second between each retry starting with48    # retry_min_seconds seconds, then up to retry_max_seconds seconds,49    # then retry_max_seconds seconds afterwards50    # retry_min_seconds and retry_max_seconds are optional arguments of51    # OpenAIEmbeddings52    return retry(53        reraise=True,54        stop=stop_after_attempt(embeddings.max_retries),55        wait=wait_exponential(56            multiplier=1,57            min=embeddings.retry_min_seconds,58            max=embeddings.retry_max_seconds,59        ),60        retry=(61            retry_if_exception_type(openai.error.Timeout)62            | retry_if_exception_type(openai.error.APIError)63            | retry_if_exception_type(openai.error.APIConnectionError)64            | retry_if_exception_type(openai.error.RateLimitError)65            | retry_if_exception_type(openai.error.ServiceUnavailableError)66        ),67        before_sleep=before_sleep_log(logger, logging.WARNING),68    )69 70 71def _async_retry_decorator(embeddings: OpenAIEmbeddings) -> Any:72    import openai73 74    # Wait 2^x * 1 second between each retry starting with75    # retry_min_seconds seconds, then up to retry_max_seconds seconds,76    # then retry_max_seconds seconds afterwards77    # retry_min_seconds and retry_max_seconds are optional arguments of78    # OpenAIEmbeddings79    async_retrying = AsyncRetrying(80        reraise=True,81        stop=stop_after_attempt(embeddings.max_retries),82        wait=wait_exponential(83            multiplier=1,84            min=embeddings.retry_min_seconds,85            max=embeddings.retry_max_seconds,86        ),87        retry=(88            retry_if_exception_type(openai.error.Timeout)89            | retry_if_exception_type(openai.error.APIError)90            | retry_if_exception_type(openai.error.APIConnectionError)91            | retry_if_exception_type(openai.error.RateLimitError)92            | retry_if_exception_type(openai.error.ServiceUnavailableError)93        ),94        before_sleep=before_sleep_log(logger, logging.WARNING),95    )96 97    def wrap(func: Callable) -> Callable:98        async def wrapped_f(*args: Any, **kwargs: Any) -> Callable:99            async for _ in async_retrying:100                return await func(*args, **kwargs)101            raise AssertionError("this is unreachable")102 103        return wrapped_f104 105    return wrap106 107 108# https://stackoverflow.com/questions/76469415/getting-embeddings-of-length-1-from-langchain-openaiembeddings109def _check_response(response: dict, skip_empty: bool = False) -> dict:110    if any(len(d["embedding"]) == 1 for d in response["data"]) and not skip_empty:111        import openai112 113        raise openai.error.APIError("OpenAI API returned an empty embedding")114    return response115 116 117def embed_with_retry(embeddings: OpenAIEmbeddings, **kwargs: Any) -> Any:118    """Use tenacity to retry the embedding call."""119    if is_openai_v1():120        return embeddings.client.create(**kwargs)121    retry_decorator = _create_retry_decorator(embeddings)122 123    @retry_decorator124    def _embed_with_retry(**kwargs: Any) -> Any:125        response = embeddings.client.create(**kwargs)126        return _check_response(response, skip_empty=embeddings.skip_empty)127 128    return _embed_with_retry(**kwargs)129 130 131async def async_embed_with_retry(embeddings: OpenAIEmbeddings, **kwargs: Any) -> Any:132    """Use tenacity to retry the embedding call."""133 134    if is_openai_v1():135        return await embeddings.async_client.create(**kwargs)136 137    @_async_retry_decorator(embeddings)138    async def _async_embed_with_retry(**kwargs: Any) -> Any:139        response = await embeddings.client.acreate(**kwargs)140        return _check_response(response, skip_empty=embeddings.skip_empty)141 142    return await _async_embed_with_retry(**kwargs)143 144 145@deprecated(146    since="0.0.9",147    removal="1.0",148    alternative_import="langchain_openai.OpenAIEmbeddings",149)150class OpenAIEmbeddings(BaseModel, Embeddings):151    """OpenAI embedding models.152 153    To use, you should have the ``openai`` python package installed, and the154    environment variable ``OPENAI_API_KEY`` set with your API key or pass it155    as a named parameter to the constructor.156 157    Example:158        .. code-block:: python159 160            from langchain_community.embeddings import OpenAIEmbeddings161            openai = OpenAIEmbeddings(openai_api_key="my-api-key")162 163    In order to use the library with Microsoft Azure endpoints, you need to set164    the OPENAI_API_TYPE, OPENAI_API_BASE, OPENAI_API_KEY and OPENAI_API_VERSION.165    The OPENAI_API_TYPE must be set to 'azure' and the others correspond to166    the properties of your endpoint.167    In addition, the deployment name must be passed as the model parameter.168 169    Example:170        .. code-block:: python171 172            import os173 174            os.environ["OPENAI_API_TYPE"] = "azure"175            os.environ["OPENAI_API_BASE"] = "https://<your-endpoint.openai.azure.com/"176            os.environ["OPENAI_API_KEY"] = "your AzureOpenAI key"177            os.environ["OPENAI_API_VERSION"] = "2023-05-15"178            os.environ["OPENAI_PROXY"] = "http://your-corporate-proxy:8080"179 180            from langchain_community.embeddings.openai import OpenAIEmbeddings181            embeddings = OpenAIEmbeddings(182                deployment="your-embeddings-deployment-name",183                model="your-embeddings-model-name",184                openai_api_base="https://your-endpoint.openai.azure.com/",185                openai_api_type="azure",186            )187            text = "This is a test query."188            query_result = embeddings.embed_query(text)189 190    """191 192    client: Any = Field(default=None, exclude=True)  #: :meta private:193    async_client: Any = Field(default=None, exclude=True)  #: :meta private:194    model: str = "text-embedding-ada-002"195    # to support Azure OpenAI Service custom deployment names196    deployment: Optional[str] = model197    # TODO: Move to AzureOpenAIEmbeddings.198    openai_api_version: Optional[str] = Field(default=None, alias="api_version")199    """Automatically inferred from env var `OPENAI_API_VERSION` if not provided."""200    # to support Azure OpenAI Service custom endpoints201    openai_api_base: Optional[str] = Field(default=None, alias="base_url")202    """Base URL path for API requests, leave blank if not using a proxy or service 203        emulator."""204    # to support Azure OpenAI Service custom endpoints205    openai_api_type: Optional[str] = None206    # to support explicit proxy for OpenAI207    openai_proxy: Optional[str] = None208    embedding_ctx_length: int = 8191209    """The maximum number of tokens to embed at once."""210    openai_api_key: Optional[str] = Field(default=None, alias="api_key")211    """Automatically inferred from env var `OPENAI_API_KEY` if not provided."""212    openai_organization: Optional[str] = Field(default=None, alias="organization")213    """Automatically inferred from env var `OPENAI_ORG_ID` if not provided."""214    allowed_special: Union[Literal["all"], Set[str]] = set()215    disallowed_special: Union[Literal["all"], Set[str], Sequence[str]] = "all"216    chunk_size: int = 1000217    """Maximum number of texts to embed in each batch"""218    max_retries: int = 2219    """Maximum number of retries to make when generating."""220    request_timeout: Optional[Union[float, Tuple[float, float], Any]] = Field(221        default=None, alias="timeout"222    )223    """Timeout for requests to OpenAI completion API. Can be float, httpx.Timeout or 224        None."""225    headers: Any = None226    tiktoken_enabled: bool = True227    """Set this to False for non-OpenAI implementations of the embeddings API, e.g.228    the `--extensions openai` extension for `text-generation-webui`"""229    tiktoken_model_name: Optional[str] = None230    """The model name to pass to tiktoken when using this class. 231    Tiktoken is used to count the number of tokens in documents to constrain 232    them to be under a certain limit. By default, when set to None, this will 233    be the same as the embedding model name. However, there are some cases 234    where you may want to use this Embedding class with a model name not 235    supported by tiktoken. This can include when using Azure embeddings or 236    when using one of the many model providers that expose an OpenAI-like 237    API but with different models. In those cases, in order to avoid erroring 238    when tiktoken is called, you can specify a model name to use here."""239    show_progress_bar: bool = False240    """Whether to show a progress bar when embedding."""241    model_kwargs: Dict[str, Any] = Field(default_factory=dict)242    """Holds any model parameters valid for `create` call not explicitly specified."""243    skip_empty: bool = False244    """Whether to skip empty strings when embedding or raise an error.245    Defaults to not skipping."""246    default_headers: Union[Mapping[str, str], None] = None247    default_query: Union[Mapping[str, object], None] = None248    # Configure a custom httpx client. See the249    # [httpx documentation](https://www.python-httpx.org/api/#client) for more details.250    retry_min_seconds: int = 4251    """Min number of seconds to wait between retries"""252    retry_max_seconds: int = 20253    """Max number of seconds to wait between retries"""254    http_client: Union[Any, None] = None255    """Optional httpx.Client."""256 257    model_config = ConfigDict(258        populate_by_name=True, extra="forbid", protected_namespaces=()259    )260 261    @model_validator(mode="before")262    @classmethod263    def build_extra(cls, values: Dict[str, Any]) -> Any:264        """Build extra kwargs from additional params that were passed in."""265        all_required_field_names = get_pydantic_field_names(cls)266        extra = values.get("model_kwargs", {})267        for field_name in list(values):268            if field_name in extra:269                raise ValueError(f"Found {field_name} supplied twice.")270            if field_name not in all_required_field_names:271                warnings.warn(272                    f"""WARNING! {field_name} is not default parameter.273                    {field_name} was transferred to model_kwargs.274                    Please confirm that {field_name} is what you intended."""275                )276                extra[field_name] = values.pop(field_name)277 278        invalid_model_kwargs = all_required_field_names.intersection(extra.keys())279        if invalid_model_kwargs:280            raise ValueError(281                f"Parameters {invalid_model_kwargs} should be specified explicitly. "282                f"Instead they were passed in as part of `model_kwargs` parameter."283            )284 285        values["model_kwargs"] = extra286        return values287 288    @pre_init289    def validate_environment(cls, values: Dict) -> Dict:290        """Validate that api key and python package exists in environment."""291        values["openai_api_key"] = get_from_dict_or_env(292            values, "openai_api_key", "OPENAI_API_KEY"293        )294        values["openai_api_base"] = values["openai_api_base"] or os.getenv(295            "OPENAI_API_BASE"296        )297        values["openai_api_type"] = get_from_dict_or_env(298            values,299            "openai_api_type",300            "OPENAI_API_TYPE",301            default="",302        )303        values["openai_proxy"] = get_from_dict_or_env(304            values,305            "openai_proxy",306            "OPENAI_PROXY",307            default="",308        )309        if values["openai_api_type"] in ("azure", "azure_ad", "azuread"):310            default_api_version = "2023-05-15"311            # Azure OpenAI embedding models allow a maximum of 2048312            # texts at a time in each batch313            # See: https://learn.microsoft.com/en-us/azure/ai-services/openai/reference#embeddings314            values["chunk_size"] = min(values["chunk_size"], 2048)315        else:316            default_api_version = ""317        values["openai_api_version"] = get_from_dict_or_env(318            values,319            "openai_api_version",320            "OPENAI_API_VERSION",321            default=default_api_version,322        )323        # Check OPENAI_ORGANIZATION for backwards compatibility.324        values["openai_organization"] = (325            values["openai_organization"]326            or os.getenv("OPENAI_ORG_ID")327            or os.getenv("OPENAI_ORGANIZATION")328        )329        try:330            import openai331        except ImportError:332            raise ImportError(333                "Could not import openai python package. "334                "Please install it with `pip install openai`."335            )336        else:337            if is_openai_v1():338                if values["openai_api_type"] in ("azure", "azure_ad", "azuread"):339                    warnings.warn(340                        "If you have openai>=1.0.0 installed and are using Azure, "341                        "please use the `AzureOpenAIEmbeddings` class."342                    )343                client_params = {344                    "api_key": values["openai_api_key"],345                    "organization": values["openai_organization"],346                    "base_url": values["openai_api_base"],347                    "timeout": values["request_timeout"],348                    "max_retries": values["max_retries"],349                    "default_headers": values["default_headers"],350                    "default_query": values["default_query"],351                    "http_client": values["http_client"],352                }353                if not values.get("client"):354                    values["client"] = openai.OpenAI(**client_params).embeddings355                if not values.get("async_client"):356                    values["async_client"] = openai.AsyncOpenAI(357                        **client_params358                    ).embeddings359            elif not values.get("client"):360                values["client"] = openai.Embedding361            else:362                pass363        return values364 365    @property366    def _invocation_params(self) -> Dict[str, Any]:367        if is_openai_v1():368            openai_args: Dict = {"model": self.model, **self.model_kwargs}369        else:370            openai_args = {371                "model": self.model,372                "request_timeout": self.request_timeout,373                "headers": self.headers,374                "api_key": self.openai_api_key,375                "organization": self.openai_organization,376                "api_base": self.openai_api_base,377                "api_type": self.openai_api_type,378                "api_version": self.openai_api_version,379                **self.model_kwargs,380            }381            if self.openai_api_type in ("azure", "azure_ad", "azuread"):382                openai_args["engine"] = self.deployment383            # TODO: Look into proxy with openai v1.384            if self.openai_proxy:385                try:386                    import openai387                except ImportError:388                    raise ImportError(389                        "Could not import openai python package. "390                        "Please install it with `pip install openai`."391                    )392 393                openai.proxy = {394                    "http": self.openai_proxy,395                    "https": self.openai_proxy,396                }397        return openai_args398 399    # please refer to400    # https://github.com/openai/openai-cookbook/blob/main/examples/Embedding_long_inputs.ipynb401    def _get_len_safe_embeddings(402        self, texts: List[str], *, engine: str, chunk_size: Optional[int] = None403    ) -> List[List[float]]:404        """405        Generate length-safe embeddings for a list of texts.406 407        This method handles tokenization and embedding generation, respecting the408        set embedding context length and chunk size. It supports both tiktoken409        and HuggingFace tokenizer based on the tiktoken_enabled flag.410 411        Args:412            texts (List[str]): A list of texts to embed.413            engine (str): The engine or model to use for embeddings.414            chunk_size (Optional[int]): The size of chunks for processing embeddings.415 416        Returns:417            List[List[float]]: A list of embeddings for each input text.418        """419 420        tokens = []421        indices = []422        model_name = self.tiktoken_model_name or self.model423        _chunk_size = chunk_size or self.chunk_size424 425        # If tiktoken flag set to False426        if not self.tiktoken_enabled:427            try:428                from transformers import AutoTokenizer429            except ImportError:430                raise ImportError(431                    "Could not import transformers python package. "432                    "This is needed in order to for OpenAIEmbeddings without "433                    "`tiktoken`. Please install it with `pip install transformers`. "434                )435 436            tokenizer = AutoTokenizer.from_pretrained(437                pretrained_model_name_or_path=model_name438            )439            for i, text in enumerate(texts):440                # Tokenize the text using HuggingFace transformers441                tokenized = tokenizer.encode(text, add_special_tokens=False)442 443                # Split tokens into chunks respecting the embedding_ctx_length444                for j in range(0, len(tokenized), self.embedding_ctx_length):445                    token_chunk = tokenized[j : j + self.embedding_ctx_length]446 447                    # Convert token IDs back to a string448                    chunk_text = tokenizer.decode(token_chunk)449                    tokens.append(chunk_text)450                    indices.append(i)451        else:452            try:453                import tiktoken454            except ImportError:455                raise ImportError(456                    "Could not import tiktoken python package. "457                    "This is needed in order to for OpenAIEmbeddings. "458                    "Please install it with `pip install tiktoken`."459                )460 461            try:462                encoding = tiktoken.encoding_for_model(model_name)463            except KeyError:464                logger.warning("Warning: model not found. Using cl100k_base encoding.")465                model = "cl100k_base"466                encoding = tiktoken.get_encoding(model)467            for i, text in enumerate(texts):468                if self.model.endswith("001"):469                    # See: https://github.com/openai/openai-python/470                    #      issues/418#issuecomment-1525939500471                    # replace newlines, which can negatively affect performance.472                    text = text.replace("\n", " ")473 474                token = encoding.encode(475                    text=text,476                    allowed_special=self.allowed_special,477                    disallowed_special=self.disallowed_special,478                )479 480                # Split tokens into chunks respecting the embedding_ctx_length481                for j in range(0, len(token), self.embedding_ctx_length):482                    tokens.append(token[j : j + self.embedding_ctx_length])483                    indices.append(i)484 485        if self.show_progress_bar:486            try:487                from tqdm.auto import tqdm488 489                _iter = tqdm(range(0, len(tokens), _chunk_size))490            except ImportError:491                _iter = range(0, len(tokens), _chunk_size)492        else:493            _iter = range(0, len(tokens), _chunk_size)494 495        batched_embeddings: List[List[float]] = []496        for i in _iter:497            response = embed_with_retry(498                self,499                input=tokens[i : i + _chunk_size],500                **self._invocation_params,501            )502            if not isinstance(response, dict):503                response = response.dict()504            batched_embeddings.extend(r["embedding"] for r in response["data"])505 506        results: List[List[List[float]]] = [[] for _ in range(len(texts))]507        num_tokens_in_batch: List[List[int]] = [[] for _ in range(len(texts))]508        for i in range(len(indices)):509            if self.skip_empty and len(batched_embeddings[i]) == 1:510                continue511            results[indices[i]].append(batched_embeddings[i])512            num_tokens_in_batch[indices[i]].append(len(tokens[i]))513 514        embeddings: List[List[float]] = [[] for _ in range(len(texts))]515        for i in range(len(texts)):516            _result = results[i]517            if len(_result) == 0:518                average_embedded = embed_with_retry(519                    self,520                    input="",521                    **self._invocation_params,522                )523                if not isinstance(average_embedded, dict):524                    average_embedded = average_embedded.dict()525                average = average_embedded["data"][0]["embedding"]526            else:527                average = np.average(_result, axis=0, weights=num_tokens_in_batch[i])528            embeddings[i] = (average / np.linalg.norm(average)).tolist()529 530        return embeddings531 532    # please refer to533    # https://github.com/openai/openai-cookbook/blob/main/examples/Embedding_long_inputs.ipynb534    async def _aget_len_safe_embeddings(535        self, texts: List[str], *, engine: str, chunk_size: Optional[int] = None536    ) -> List[List[float]]:537        """538        Asynchronously generate length-safe embeddings for a list of texts.539 540        This method handles tokenization and asynchronous embedding generation,541        respecting the set embedding context length and chunk size. It supports both542        `tiktoken` and HuggingFace `tokenizer` based on the tiktoken_enabled flag.543 544        Args:545            texts (List[str]): A list of texts to embed.546            engine (str): The engine or model to use for embeddings.547            chunk_size (Optional[int]): The size of chunks for processing embeddings.548 549        Returns:550            List[List[float]]: A list of embeddings for each input text.551        """552 553        tokens = []554        indices = []555        model_name = self.tiktoken_model_name or self.model556        _chunk_size = chunk_size or self.chunk_size557 558        # If tiktoken flag set to False559        if not self.tiktoken_enabled:560            try:561                from transformers import AutoTokenizer562            except ImportError:563                raise ImportError(564                    "Could not import transformers python package. "565                    "This is needed in order to for OpenAIEmbeddings without "566                    " `tiktoken`. Please install it with `pip install transformers`."567                )568 569            tokenizer = AutoTokenizer.from_pretrained(570                pretrained_model_name_or_path=model_name571            )572            for i, text in enumerate(texts):573                # Tokenize the text using HuggingFace transformers574                tokenized = tokenizer.encode(text, add_special_tokens=False)575 576                # Split tokens into chunks respecting the embedding_ctx_length577                for j in range(0, len(tokenized), self.embedding_ctx_length):578                    token_chunk = tokenized[j : j + self.embedding_ctx_length]579 580                    # Convert token IDs back to a string581                    chunk_text = tokenizer.decode(token_chunk)582                    tokens.append(chunk_text)583                    indices.append(i)584        else:585            try:586                import tiktoken587            except ImportError:588                raise ImportError(589                    "Could not import tiktoken python package. "590                    "This is needed in order to for OpenAIEmbeddings. "591                    "Please install it with `pip install tiktoken`."592                )593 594            try:595                encoding = tiktoken.encoding_for_model(model_name)596            except KeyError:597                logger.warning("Warning: model not found. Using cl100k_base encoding.")598                model = "cl100k_base"599                encoding = tiktoken.get_encoding(model)600            for i, text in enumerate(texts):601                if self.model.endswith("001"):602                    # See: https://github.com/openai/openai-python/603                    #      issues/418#issuecomment-1525939500604                    # replace newlines, which can negatively affect performance.605                    text = text.replace("\n", " ")606 607                token = encoding.encode(608                    text=text,609                    allowed_special=self.allowed_special,610                    disallowed_special=self.disallowed_special,611                )612 613                # Split tokens into chunks respecting the embedding_ctx_length614                for j in range(0, len(token), self.embedding_ctx_length):615                    tokens.append(token[j : j + self.embedding_ctx_length])616                    indices.append(i)617 618        batched_embeddings: List[List[float]] = []619        _chunk_size = chunk_size or self.chunk_size620        for i in range(0, len(tokens), _chunk_size):621            response = await async_embed_with_retry(622                self,623                input=tokens[i : i + _chunk_size],624                **self._invocation_params,625            )626 627            if not isinstance(response, dict):628                response = response.dict()629            batched_embeddings.extend(r["embedding"] for r in response["data"])630 631        results: List[List[List[float]]] = [[] for _ in range(len(texts))]632        num_tokens_in_batch: List[List[int]] = [[] for _ in range(len(texts))]633        for i in range(len(indices)):634            results[indices[i]].append(batched_embeddings[i])635            num_tokens_in_batch[indices[i]].append(len(tokens[i]))636 637        embeddings: List[List[float]] = [[] for _ in range(len(texts))]638        for i in range(len(texts)):639            _result = results[i]640            if len(_result) == 0:641                average_embedded = await async_embed_with_retry(642                    self,643                    input="",644                    **self._invocation_params,645                )646                if not isinstance(average_embedded, dict):647                    average_embedded = average_embedded.dict()648                average = average_embedded["data"][0]["embedding"]649            else:650                average = np.average(_result, axis=0, weights=num_tokens_in_batch[i])651            embeddings[i] = (average / np.linalg.norm(average)).tolist()652 653        return embeddings654 655    def embed_documents(656        self, texts: List[str], chunk_size: Optional[int] = 0657    ) -> List[List[float]]:658        """Call out to OpenAI's embedding endpoint for embedding search docs.659 660        Args:661            texts: The list of texts to embed.662            chunk_size: The chunk size of embeddings. If None, will use the chunk size663                specified by the class.664 665        Returns:666            List of embeddings, one for each text.667        """668        # NOTE: to keep things simple, we assume the list may contain texts longer669        #       than the maximum context and use length-safe embedding function.670        engine = cast(str, self.deployment)671        return self._get_len_safe_embeddings(672            texts, engine=engine, chunk_size=chunk_size673        )674 675    async def aembed_documents(676        self, texts: List[str], chunk_size: Optional[int] = 0677    ) -> List[List[float]]:678        """Call out to OpenAI's embedding endpoint async for embedding search docs.679 680        Args:681            texts: The list of texts to embed.682            chunk_size: The chunk size of embeddings. If None, will use the chunk size683                specified by the class.684 685        Returns:686            List of embeddings, one for each text.687        """688        # NOTE: to keep things simple, we assume the list may contain texts longer689        #       than the maximum context and use length-safe embedding function.690        engine = cast(str, self.deployment)691        return self._get_len_safe_embeddings(692            texts, engine=engine, chunk_size=chunk_size693        )694 695    def embed_query(self, text: str) -> List[float]:696        """Call out to OpenAI's embedding endpoint for embedding query text.697 698        Args:699            text: The text to embed.700 701        Returns:702            Embedding for the text.703        """704        return self.embed_documents([text])[0]705 706    async def aembed_query(self, text: str) -> List[float]:707        """Call out to OpenAI's embedding endpoint async for embedding query text.708 709        Args:710            text: The text to embed.711 712        Returns:713            Embedding for the text.714        """715        embeddings = await self.aembed_documents([text])716        return embeddings[0]717 
codekingpro/portable-devtools · Team Ai