Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added OCI Model Deployment Endpoint Embedding #29213

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
{
"cells": [
{
"cell_type": "raw",
"metadata": {
"vscode": {
"languageId": "raw"
}
},
"source": [
"---\n",
"keywords: [OCIModelDeploymentEndpointEmbeddings]\n",
"---"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# OCI Data Science Model Deployment Endpoint\n",
"\n",
"## Overview\n",
"\n",
"[OCI Data Science](https://docs.oracle.com/en-us/iaas/data-science/using/home.htm) is a fully managed and serverless platform for data science teams to build, train, and manage machine learning models in the Oracle Cloud Infrastructure.\n",
"\n",
"This notebooks goes over how to use an embedding model hosted on a [OCI Data Science Model Deployment](https://docs.oracle.com/en-us/iaas/data-science/using/model-dep-about.htm).\n",
"\n",
"To authenticate, [oracle-ads](https://accelerated-data-science.readthedocs.io/en/latest/user_guide/cli/authentication.html) has been used to automatically load credentials for invoking endpoint."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Instantiation\n",
"We will need to install the `oracle-ads` sdk"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"!pip3 install -U oracle-ads"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Prerequisite\n",
"\n",
"### Deploy model\n",
"Check [Oracle GitHub samples repository](https://github.com/oracle-samples/oci-data-science-ai-samples/tree/main/model-deployment/containers/llama2) on how to deploy your embedding model on OCI Data Science Model deployment.\n",
"\n",
"### Policies\n",
"Make sure to have the required [policies](https://docs.oracle.com/en-us/iaas/data-science/using/model-dep-policies-auth.htm#model_dep_policies_auth__predict-endpoint) to access the OCI Data Science Model Deployment endpoint.\n",
"\n",
"## Setup\n",
"After having deployed model, you have to set up **`endpoint`**: The model HTTP endpoint from the deployed model, e.g. `\"https://modeldeployment.us-ashburn-1.oci.customer-oci.com/<MD_OCID>/predict\"` of the `OCIModelDeploymentEndpointEmbeddings` call."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Authentication\n",
"\n",
"You can set authentication through either ads or environment variables. When you are working in OCI Data Science Notebook Session, you can leverage resource principal to access other OCI resources. Check out [here](https://accelerated-data-science.readthedocs.io/en/latest/user_guide/cli/authentication.html) to see more options. "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import ads\n",
"\n",
"# Set authentication through ads\n",
"# Use resource principal are operating within a\n",
"# OCI service that has resource principal based\n",
"# authentication configured\n",
"ads.set_auth(\"resource_principal\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Direct Usage"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from langchain_community.embeddings import OCIModelDeploymentEndpointEmbeddings\n",
"\n",
"# Create an instance of OCI Model Deployment Endpoint\n",
"# Replace the endpoint uri with your own\n",
"embeddings = OCIModelDeploymentEndpointEmbeddings(\n",
" endpoint=\"https://modeldeployment.us-ashburn-1.oci.customer-oci.com/<MD_OCID>/predict\",\n",
")\n",
"\n",
"query = \"Hello World!\"\n",
"embeddings.embed_query(query)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"documents = [\"This is a sample document\", \"and here is another one\"]\n",
"embeddings.embed_documents(documents)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## API Reference\n",
"\n",
"For detailed documentation on `OCIModelDeploymentEndpointEmbeddings` features and configuration options, please refer to the [API reference](https://python.langchain.com/api_reference/community/embeddings/langchain_community.embeddings.oci_data_science_model_deployment_endpoint.OCIModelDeploymentEndpointEmbeddings.html)."
]
}
],
"metadata": {
"kernelspec": {
"display_name": "oci_langchain",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.9"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
5 changes: 5 additions & 0 deletions libs/community/langchain_community/embeddings/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,238 +15,241 @@
from typing import TYPE_CHECKING, Any

if TYPE_CHECKING:
from langchain_community.embeddings.aleph_alpha import (
AlephAlphaAsymmetricSemanticEmbedding,
AlephAlphaSymmetricSemanticEmbedding,
)
from langchain_community.embeddings.anyscale import (
AnyscaleEmbeddings,
)
from langchain_community.embeddings.ascend import (
AscendEmbeddings,
)
from langchain_community.embeddings.awa import (
AwaEmbeddings,
)
from langchain_community.embeddings.azure_openai import (
AzureOpenAIEmbeddings,
)
from langchain_community.embeddings.baichuan import (
BaichuanTextEmbeddings,
)
from langchain_community.embeddings.baidu_qianfan_endpoint import (
QianfanEmbeddingsEndpoint,
)
from langchain_community.embeddings.bedrock import (
BedrockEmbeddings,
)
from langchain_community.embeddings.bookend import (
BookendEmbeddings,
)
from langchain_community.embeddings.clarifai import (
ClarifaiEmbeddings,
)
from langchain_community.embeddings.clova import (
ClovaEmbeddings,
)
from langchain_community.embeddings.cohere import (
CohereEmbeddings,
)
from langchain_community.embeddings.dashscope import (
DashScopeEmbeddings,
)
from langchain_community.embeddings.databricks import (
DatabricksEmbeddings,
)
from langchain_community.embeddings.deepinfra import (
DeepInfraEmbeddings,
)
from langchain_community.embeddings.edenai import (
EdenAiEmbeddings,
)
from langchain_community.embeddings.elasticsearch import (
ElasticsearchEmbeddings,
)
from langchain_community.embeddings.embaas import (
EmbaasEmbeddings,
)
from langchain_community.embeddings.ernie import (
ErnieEmbeddings,
)
from langchain_community.embeddings.fake import (
DeterministicFakeEmbedding,
FakeEmbeddings,
)
from langchain_community.embeddings.fastembed import (
FastEmbedEmbeddings,
)
from langchain_community.embeddings.gigachat import (
GigaChatEmbeddings,
)
from langchain_community.embeddings.google_palm import (
GooglePalmEmbeddings,
)
from langchain_community.embeddings.gpt4all import (
GPT4AllEmbeddings,
)
from langchain_community.embeddings.gradient_ai import (
GradientEmbeddings,
)
from langchain_community.embeddings.huggingface import (
HuggingFaceBgeEmbeddings,
HuggingFaceEmbeddings,
HuggingFaceInferenceAPIEmbeddings,
HuggingFaceInstructEmbeddings,
)
from langchain_community.embeddings.huggingface_hub import (
HuggingFaceHubEmbeddings,
)
from langchain_community.embeddings.hunyuan import (
HunyuanEmbeddings,
)
from langchain_community.embeddings.infinity import (
InfinityEmbeddings,
)
from langchain_community.embeddings.infinity_local import (
InfinityEmbeddingsLocal,
)
from langchain_community.embeddings.ipex_llm import IpexLLMBgeEmbeddings
from langchain_community.embeddings.itrex import (
QuantizedBgeEmbeddings,
)
from langchain_community.embeddings.javelin_ai_gateway import (
JavelinAIGatewayEmbeddings,
)
from langchain_community.embeddings.jina import (
JinaEmbeddings,
)
from langchain_community.embeddings.johnsnowlabs import (
JohnSnowLabsEmbeddings,
)
from langchain_community.embeddings.laser import (
LaserEmbeddings,
)
from langchain_community.embeddings.llamacpp import (
LlamaCppEmbeddings,
)
from langchain_community.embeddings.llamafile import (
LlamafileEmbeddings,
)
from langchain_community.embeddings.llm_rails import (
LLMRailsEmbeddings,
)
from langchain_community.embeddings.localai import (
LocalAIEmbeddings,
)
from langchain_community.embeddings.minimax import (
MiniMaxEmbeddings,
)
from langchain_community.embeddings.mlflow import (
MlflowCohereEmbeddings,
MlflowEmbeddings,
)
from langchain_community.embeddings.mlflow_gateway import (
MlflowAIGatewayEmbeddings,
)
from langchain_community.embeddings.model2vec import (
Model2vecEmbeddings,
)
from langchain_community.embeddings.modelscope_hub import (
ModelScopeEmbeddings,
)
from langchain_community.embeddings.mosaicml import (
MosaicMLInstructorEmbeddings,
)
from langchain_community.embeddings.naver import (
ClovaXEmbeddings,
)
from langchain_community.embeddings.nemo import (
NeMoEmbeddings,
)
from langchain_community.embeddings.nlpcloud import (
NLPCloudEmbeddings,
)
from langchain_community.embeddings.oci_data_science_model_deployment_endpoint import ( # noqa: E501
OCIModelDeploymentEndpointEmbeddings,
)
from langchain_community.embeddings.oci_generative_ai import (
OCIGenAIEmbeddings,
)
from langchain_community.embeddings.octoai_embeddings import (
OctoAIEmbeddings,
)
from langchain_community.embeddings.ollama import (
OllamaEmbeddings,
)
from langchain_community.embeddings.openai import (
OpenAIEmbeddings,
)
from langchain_community.embeddings.openvino import (
OpenVINOBgeEmbeddings,
OpenVINOEmbeddings,
)
from langchain_community.embeddings.optimum_intel import (
QuantizedBiEncoderEmbeddings,
)
from langchain_community.embeddings.oracleai import (
OracleEmbeddings,
)
from langchain_community.embeddings.ovhcloud import (
OVHCloudEmbeddings,
)
from langchain_community.embeddings.premai import (
PremAIEmbeddings,
)
from langchain_community.embeddings.sagemaker_endpoint import (
SagemakerEndpointEmbeddings,
)
from langchain_community.embeddings.sambanova import (
SambaStudioEmbeddings,
)
from langchain_community.embeddings.self_hosted import (
SelfHostedEmbeddings,
)
from langchain_community.embeddings.self_hosted_hugging_face import (
SelfHostedHuggingFaceEmbeddings,
SelfHostedHuggingFaceInstructEmbeddings,
)
from langchain_community.embeddings.sentence_transformer import (
SentenceTransformerEmbeddings,
)
from langchain_community.embeddings.solar import (
SolarEmbeddings,
)
from langchain_community.embeddings.spacy_embeddings import (
SpacyEmbeddings,
)
from langchain_community.embeddings.sparkllm import (
SparkLLMTextEmbeddings,
)
from langchain_community.embeddings.tensorflow_hub import (
TensorflowHubEmbeddings,
)
from langchain_community.embeddings.textembed import (
TextEmbedEmbeddings,
)
from langchain_community.embeddings.titan_takeoff import (
TitanTakeoffEmbed,
)
from langchain_community.embeddings.vertexai import (
VertexAIEmbeddings,
)
from langchain_community.embeddings.volcengine import (
VolcanoEmbeddings,
)
from langchain_community.embeddings.voyageai import (
VoyageEmbeddings,
)
from langchain_community.embeddings.xinference import (
XinferenceEmbeddings,
)
from langchain_community.embeddings.yandex import (
YandexGPTEmbeddings,
)
from langchain_community.embeddings.zhipuai import (
ZhipuAIEmbeddings,
)

Check failure on line 252 in libs/community/langchain_community/embeddings/__init__.py

View workflow job for this annotation

GitHub Actions / cd libs/community / make lint #3.13

Ruff (I001)

langchain_community/embeddings/__init__.py:18:1: I001 Import block is un-sorted or un-formatted

Check failure on line 252 in libs/community/langchain_community/embeddings/__init__.py

View workflow job for this annotation

GitHub Actions / cd libs/community / make lint #3.9

Ruff (I001)

langchain_community/embeddings/__init__.py:18:1: I001 Import block is un-sorted or un-formatted
__all__ = [
"AlephAlphaAsymmetricSemanticEmbedding",
"AlephAlphaSymmetricSemanticEmbedding",
Expand Down Expand Up @@ -300,6 +303,7 @@
"MosaicMLInstructorEmbeddings",
"NLPCloudEmbeddings",
"NeMoEmbeddings",
"OCIModelDeploymentEndpointEmbeddings",
"OCIGenAIEmbeddings",
"OctoAIEmbeddings",
"OllamaEmbeddings",
Expand Down Expand Up @@ -385,6 +389,7 @@
"MosaicMLInstructorEmbeddings": "langchain_community.embeddings.mosaicml",
"NLPCloudEmbeddings": "langchain_community.embeddings.nlpcloud",
"NeMoEmbeddings": "langchain_community.embeddings.nemo",
"OCIModelDeploymentEndpointEmbeddings": "langchain_community.embeddings.oci_data_science_model_deployment_endpoint", # noqa: E501
"OCIGenAIEmbeddings": "langchain_community.embeddings.oci_generative_ai",
"OctoAIEmbeddings": "langchain_community.embeddings.octoai_embeddings",
"OllamaEmbeddings": "langchain_community.embeddings.ollama",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
from langchain_core.embeddings import Embeddings
from langchain_core.language_models.llms import create_base_retry_decorator
from langchain_core.utils import get_from_dict_or_env
from pydantic import BaseModel, Field, model_validator
import requests
from typing import Any, Callable, Dict, List, Mapping, Optional


DEFAULT_HEADER = {

Check failure on line 9 in libs/community/langchain_community/embeddings/oci_data_science_model_deployment_endpoint.py

View workflow job for this annotation

GitHub Actions / cd libs/community / make lint #3.13

Ruff (I001)

langchain_community/embeddings/oci_data_science_model_deployment_endpoint.py:1:1: I001 Import block is un-sorted or un-formatted

Check failure on line 9 in libs/community/langchain_community/embeddings/oci_data_science_model_deployment_endpoint.py

View workflow job for this annotation

GitHub Actions / cd libs/community / make lint #3.9

Ruff (I001)

langchain_community/embeddings/oci_data_science_model_deployment_endpoint.py:1:1: I001 Import block is un-sorted or un-formatted
"Content-Type": "application/json",
}


class TokenExpiredError(Exception):
pass


def _create_retry_decorator(llm) -> Callable[[Any], Any]:
"""Creates a retry decorator."""
errors = [requests.exceptions.ConnectTimeout, TokenExpiredError]
decorator = create_base_retry_decorator(
error_types=errors, max_retries=llm.max_retries
)
return decorator


class OCIModelDeploymentEndpointEmbeddings(BaseModel, Embeddings):
"""Embedding model deployed on OCI Data Science Model Deployment.

Example:

.. code-block:: python

from langchain_community.embeddings import OCIModelDeploymentEndpointEmbeddings

embeddings = OCIModelDeploymentEndpointEmbeddings(
endpoint="https://modeldeployment.us-ashburn-1.oci.customer-oci.com/<md_ocid>/predict",
)
""" # noqa: E501

auth: dict = Field(default_factory=dict, exclude=True)
"""ADS auth dictionary for OCI authentication:
https://accelerated-data-science.readthedocs.io/en/latest/user_guide/cli/authentication.html.
This can be generated by calling `ads.common.auth.api_keys()`
or `ads.common.auth.resource_principal()`. If this is not
provided then the `ads.common.default_signer()` will be used."""

endpoint: str = ""
"""The uri of the endpoint from the deployed Model Deployment model."""

model_kwargs: Optional[Dict] = None
"""Keyword arguments to pass to the model."""

endpoint_kwargs: Optional[Dict] = None
"""Optional attributes (except for headers) passed to the request.post
function.
"""

max_retries: int = 1
"""The maximum number of retries to make when generating."""

@model_validator(mode="before")
def validate_environment( # pylint: disable=no-self-argument
cls, values: Dict
) -> Dict:
"""Validate that python package exists in environment."""
try:
import ads

except ImportError as ex:
raise ImportError(
"Could not import ads python package. "
"Please install it with `pip install oracle_ads`."
) from ex
if not values.get("auth", None):
values["auth"] = ads.common.auth.default_signer()
values["endpoint"] = get_from_dict_or_env(
values,
"endpoint",
"OCI_LLM_ENDPOINT",
)
return values

@property
def _identifying_params(self) -> Mapping[str, Any]:
"""Get the identifying parameters."""
_model_kwargs = self.model_kwargs or {}
return {
**{"endpoint": self.endpoint},
**{"model_kwargs": _model_kwargs},
}

def _embed_with_retry(self, **kwargs) -> Any:
"""Use tenacity to retry the call."""
retry_decorator = _create_retry_decorator(self)

@retry_decorator
def _completion_with_retry(**kwargs: Any) -> Any:
try:
response = requests.post(self.endpoint, **kwargs)
response.raise_for_status()
return response
except requests.exceptions.HTTPError as http_err:
if response.status_code == 401 and self._refresh_signer():
raise TokenExpiredError() from http_err
else:
raise ValueError(
f"Server error: {str(http_err)}. Message: {response.text}"
) from http_err
except Exception as e:
raise ValueError(f"Error occurs by inference endpoint: {str(e)}") from e

return _completion_with_retry(**kwargs)

def _embedding(self, texts: List[str]) -> List[List[float]]:
"""Call out to OCI Data Science Model Deployment Endpoint.

Args:
texts: A list of texts to embed.

Returns:
A list of list of floats representing the embeddings, or None if an
error occurs.
"""
_model_kwargs = self.model_kwargs or {}
body = self._construct_request_body(texts, _model_kwargs)
request_kwargs = self._construct_request_kwargs(body)
response = self._embed_with_retry(**request_kwargs)
return self._proceses_response(response)

def _construct_request_kwargs(self, body: Any) -> dict:
"""Constructs the request kwargs as a dictionary."""
from ads.model.common.utils import _is_json_serializable

_endpoint_kwargs = self.endpoint_kwargs or {}
headers = _endpoint_kwargs.pop("headers", DEFAULT_HEADER)
return (
dict(
headers=headers,
json=body,
auth=self.auth.get("signer"),
**_endpoint_kwargs,
)
if _is_json_serializable(body)
else dict(
headers=headers,
data=body,
auth=self.auth.get("signer"),
**_endpoint_kwargs,
)
)

def _construct_request_body(self, texts: List[str], params: dict) -> Any:
"""Constructs the request body."""
return {"input": texts}

def _proceses_response(self, response: requests.Response) -> List[List[float]]:
"""Extracts results from requests.Response."""
try:
res_json = response.json()
embeddings = res_json["data"][0]["embedding"]
except Exception as e:
raise ValueError(
f"Error raised by inference API: {e}.\nResponse: {response.text}"
)
return embeddings

def embed_documents(
self,
texts: List[str],
chunk_size: Optional[int] = None,
) -> List[List[float]]:
"""Compute doc embeddings using OCI Data Science Model Deployment Endpoint.

Args:
texts: The list of texts to embed.
chunk_size: The chunk size defines how many input texts will
be grouped together as request. If None, will use the
chunk size specified by the class.

Returns:
List of embeddings, one for each text.
"""
results = []
_chunk_size = (
len(texts) if (not chunk_size or chunk_size > len(texts)) else chunk_size
)
for i in range(0, len(texts), _chunk_size):
response = self._embedding(texts[i : i + _chunk_size])
results.extend(response)
return results

def embed_query(self, text: str) -> List[float]:
"""Compute query embeddings using OCI Data Science Model Deployment Endpoint.

Args:
text: The text to embed.

Returns:
Embeddings for the text.
"""
return self._embedding([text])[0]
1 change: 1 addition & 0 deletions libs/community/tests/unit_tests/embeddings/test_imports.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
"VoyageEmbeddings",
"BookendEmbeddings",
"VolcanoEmbeddings",
"OCIModelDeploymentEndpointEmbeddings",
"OCIGenAIEmbeddings",
"QuantizedBiEncoderEmbeddings",
"NeMoEmbeddings",
Expand Down
Loading
Loading