From b8669b249e6775c280b94b9c547935ac848902b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ja=C3=A9GeR?= <91129126+J4e6eR@users.noreply.github.com> Date: Thu, 7 Sep 2023 03:25:48 +0530 Subject: [PATCH] Added Hugging face inference api (#10280) Embed documents without locally downloading the HF model --------- Co-authored-by: Bagatur --- .../text_embedding/huggingfacehub.ipynb | 109 +++++++++++++++--- .../langchain/embeddings/__init__.py | 2 + .../langchain/embeddings/huggingface.py | 72 +++++++++++- 3 files changed, 169 insertions(+), 14 deletions(-) diff --git a/docs/extras/integrations/text_embedding/huggingfacehub.ipynb b/docs/extras/integrations/text_embedding/huggingfacehub.ipynb index a86df86d74..cb897f8693 100644 --- a/docs/extras/integrations/text_embedding/huggingfacehub.ipynb +++ b/docs/extras/integrations/text_embedding/huggingfacehub.ipynb @@ -5,13 +5,23 @@ "id": "ed47bb62", "metadata": {}, "source": [ - "# Hugging Face Hub\n", + "# Hugging Face\n", "Let's load the Hugging Face Embedding class." ] }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, + "id": "16b20335-da1d-46ba-aa23-fbf3e2c6fe60", + "metadata": {}, + "outputs": [], + "source": [ + "!pip install langchain sentence_transformers" + ] + }, + { + "cell_type": "code", + "execution_count": 2, "id": "861521a9", "metadata": {}, "outputs": [], @@ -21,7 +31,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 3, "id": "ff9be586", "metadata": {}, "outputs": [], @@ -31,7 +41,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 3, "id": "d0a98ae9", "metadata": {}, "outputs": [], @@ -41,7 +51,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 5, "id": "5d6c682b", "metadata": {}, "outputs": [], @@ -51,7 +61,28 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 6, + "id": "b57b8ce9-ef7d-4e63-979e-aa8763d1f9a8", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[-0.04895168915390968, -0.03986193612217903, -0.021562768146395683]" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "query_result[:3]" + ] + }, + { + "cell_type": "code", + "execution_count": 7, "id": "bb5e74c0", "metadata": {}, "outputs": [], @@ -60,19 +91,71 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "aaad49f8", + "cell_type": "markdown", + "id": "92019ef1-5d30-4985-b4e6-c0d98bdfe265", "metadata": {}, - "outputs": [], - "source": [] + "source": [ + "## Hugging Face Inference API\n", + "We can also access embedding models via the Hugging Face Inference API, which does not require us to install ``sentence_transformers`` and download models locally." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "66f5c6ba-1446-43e1-b012-800d17cef300", + "metadata": {}, + "outputs": [ + { + "name": "stdin", + "output_type": "stream", + "text": [ + "Enter your HF Inference API Key:\n", + "\n", + " ········\n" + ] + } + ], + "source": [ + "import getpass\n", + "\n", + "inference_api_key = getpass.getpass(\"Enter your HF Inference API Key:\\n\\n\")" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "d0623c1f-cd82-4862-9bce-3655cb9b66ac", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[-0.038338541984558105, 0.1234646737575531, -0.028642963618040085]" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from langchain.embeddings import HuggingFaceInferenceAPIEmbeddings\n", + "\n", + "embeddings = HuggingFaceInferenceAPIEmbeddings(\n", + " api_key=inference_api_key,\n", + " model_name=\"sentence-transformers/all-MiniLM-l6-v2\"\n", + ")\n", + "\n", + "query_result = embeddings.embed_query(text)\n", + "query_result[:3]" + ] } ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "poetry-venv", "language": "python", - "name": "python3" + "name": "poetry-venv" }, "language_info": { "codemirror_mode": { diff --git a/libs/langchain/langchain/embeddings/__init__.py b/libs/langchain/langchain/embeddings/__init__.py index 87cb5e90d5..e8aa683a9a 100644 --- a/libs/langchain/langchain/embeddings/__init__.py +++ b/libs/langchain/langchain/embeddings/__init__.py @@ -35,6 +35,7 @@ from langchain.embeddings.gpt4all import GPT4AllEmbeddings from langchain.embeddings.huggingface import ( HuggingFaceBgeEmbeddings, HuggingFaceEmbeddings, + HuggingFaceInferenceAPIEmbeddings, HuggingFaceInstructEmbeddings, ) from langchain.embeddings.huggingface_hub import HuggingFaceHubEmbeddings @@ -69,6 +70,7 @@ __all__ = [ "CohereEmbeddings", "ElasticsearchEmbeddings", "HuggingFaceEmbeddings", + "HuggingFaceInferenceAPIEmbeddings", "JinaEmbeddings", "LlamaCppEmbeddings", "HuggingFaceHubEmbeddings", diff --git a/libs/langchain/langchain/embeddings/huggingface.py b/libs/langchain/langchain/embeddings/huggingface.py index 52afabd79b..a91d643793 100644 --- a/libs/langchain/langchain/embeddings/huggingface.py +++ b/libs/langchain/langchain/embeddings/huggingface.py @@ -1,5 +1,7 @@ from typing import Any, Dict, List, Optional +import requests + from langchain.embeddings.base import Embeddings from langchain.pydantic_v1 import BaseModel, Extra, Field @@ -58,7 +60,7 @@ class HuggingFaceEmbeddings(BaseModel, Embeddings): except ImportError as exc: raise ImportError( "Could not import sentence_transformers python package. " - "Please install it with `pip install sentence_transformers`." + "Please install it with `pip install sentence-transformers`." ) from exc self.client = sentence_transformers.SentenceTransformer( @@ -266,3 +268,71 @@ class HuggingFaceBgeEmbeddings(BaseModel, Embeddings): self.query_instruction + text, **self.encode_kwargs ) return embedding.tolist() + + +class HuggingFaceInferenceAPIEmbeddings(BaseModel, Embeddings): + """Embed texts using the HuggingFace API. + + Requires a HuggingFace Inference API key and a model name. + """ + + api_key: str + """Your API key for the HuggingFace Inference API.""" + model_name: str = "sentence-transformers/all-MiniLM-L6-v2" + """The name of the model to use for text embeddings.""" + + @property + def _api_url(self) -> str: + return ( + "https://api-inference.huggingface.co" + "/pipeline" + "/feature-extraction" + f"/{self.model_name}" + ) + + @property + def _headers(self) -> dict: + return {"Authorization": f"Bearer {self.api_key}"} + + def embed_documents(self, texts: List[str]) -> List[List[float]]: + """Get the embeddings for a list of texts. + + Args: + texts (Documents): A list of texts to get embeddings for. + + Returns: + Embedded texts as List[List[float]], where each inner List[float] + corresponds to a single input text. + + Example: + .. code-block:: python + + from langchain.embeddings import HuggingFaceInferenceAPIEmbeddings + + hf_embeddings = HuggingFaceInferenceAPIEmbeddings( + api_key="your_api_key", + model_name="sentence-transformers/all-MiniLM-l6-v2" + ) + texts = ["Hello, world!", "How are you?"] + hf_embeddings.embed_documents(texts) + """ + response = requests.post( + self._api_url, + headers=self._headers, + json={ + "inputs": texts, + "options": {"wait_for_model": True, "use_cache": True}, + }, + ) + return response.json() + + def embed_query(self, text: str) -> List[float]: + """Compute query embeddings using a HuggingFace transformer model. + + Args: + text: The text to embed. + + Returns: + Embeddings for the text. + """ + return self.embed_documents([text])[0]