EdenAI LLM update. Add models name option (#8963)

This PR follows the **Eden AI (LLM + embeddings) integration**. #8633 

We added an optional parameter to choose different AI models for
providers (like 'text-bison' for provider 'google', 'text-davinci-003'
for provider 'openai', etc.).

Usage:

```python
llm = EdenAI(
    feature="text",
    provider="google",
    params={
        "model": "text-bison",  # new
        "temperature": 0.2,
        "max_tokens": 250,
    },
)

```

You can also change the provider + model after initialization
```python
llm = EdenAI(
    feature="text",
    provider="google",
    params={
        "temperature": 0.2,
        "max_tokens": 250,
    },
)

prompt = """
hi 
"""

llm(prompt, providers='openai', model='text-davinci-003')  # change provider & model
```

The jupyter notebook as been updated with an example well.


Ping: @hwchase17, @baskaryan

---------

Co-authored-by: RedhaWassim <rwasssim@gmail.com>
Co-authored-by: sam <melaine.samy@gmail.com>
pull/10198/head
KyrianC 1 year ago committed by GitHub
parent b5a74fb973
commit 491089754d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -11,7 +11,7 @@
"cell_type": "markdown", "cell_type": "markdown",
"metadata": {}, "metadata": {},
"source": [ "source": [
"Eden AI is an AI consulting company that was founded to use its resources to empower people and create impactful products that use AI to improve the quality of life for individuals, businesses and societies at large." "Eden AI is revolutionizing the AI landscape by uniting the best AI providers, empowering users to unlock limitless possibilities and tap into the true potential of artificial intelligence. With an all-in-one comprehensive and hassle-free platform, it allows users to deploy AI features to production lightning fast, enabling effortless access to the full breadth of AI capabilities via a single API. (website: https://edenai.co/)"
] ]
}, },
{ {
@ -56,7 +56,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 3, "execution_count": 1,
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
@ -65,11 +65,11 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 14, "execution_count": 2,
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
"llm = EdenAI(edenai_api_key=\"...\",provider=\"openai\", params={\"temperature\" : 0.2,\"max_tokens\" : 250})" "llm = EdenAI(edenai_api_key=\"...\",provider=\"openai\", temperature=0.2, max_tokens=250)"
] ]
}, },
{ {
@ -85,7 +85,7 @@
"source": [ "source": [
"The EdenAI API brings together various providers, each offering multiple models.\n", "The EdenAI API brings together various providers, each offering multiple models.\n",
"\n", "\n",
"To access a specific model, you can simply use the \"settings\" when calling.\n", "To access a specific model, you can simply add 'model' during instantiation.\n",
"\n", "\n",
"For instance, let's explore the models provided by OpenAI, such as GPT3.5 " "For instance, let's explore the models provided by OpenAI, such as GPT3.5 "
] ]
@ -99,30 +99,30 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 11, "execution_count": 3,
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"\" No, a dog cannot drive a car.\\n\\nReasoning: \\n\\n1. A dog does not have the physical capability to operate a car. \\n2. A dog does not have the cognitive ability to understand the rules of the road and the mechanics of driving. \\n3. A dog does not have a driver's license, which is a legal requirement to operate a motor vehicle. \\n\\nTherefore, a dog cannot drive a car.\"" "\" No, a dog cannot drive a car.\\n\\nReasoning: \\n1. Driving a car requires a driver's license, which is only issued to humans. \\n2. Dogs do not have the physical capability to operate a car, as they do not have hands to steer or feet to operate the pedals. \\n3. Dogs also do not have the mental capacity to understand the rules of the road and operate a car safely. \\n4. Therefore, a dog cannot drive a car.\""
] ]
}, },
"execution_count": 11, "execution_count": 3,
"metadata": {}, "metadata": {},
"output_type": "execute_result" "output_type": "execute_result"
} }
], ],
"source": [ "source": [
"from langchain import PromptTemplate, LLMChain\n", "from langchain import PromptTemplate, LLMChain\n",
"llm=EdenAI(feature=\"text\",provider=\"openai\", params={\"temperature\" : 0.2,\"max_tokens\" : 250})\n", "llm=EdenAI(feature=\"text\",provider=\"openai\",model=\"text-davinci-003\",temperature=0.2, max_tokens=250)\n",
"\n", "\n",
"prompt = \"\"\"\n", "prompt = \"\"\"\n",
"User: Answer the following yes/no question by reasoning step by step. Can a dog drive a car?\n", "User: Answer the following yes/no question by reasoning step by step. Can a dog drive a car?\n",
"Assistant:\n", "Assistant:\n",
"\"\"\"\n", "\"\"\"\n",
"\n", "\n",
"llm(prompt,settings={'openai' : 'text-davinci-003'})" "llm(prompt)"
] ]
}, },
{ {
@ -165,9 +165,7 @@
"text2image = EdenAI(\n", "text2image = EdenAI(\n",
" feature=\"image\" ,\n", " feature=\"image\" ,\n",
" provider= \"openai\",\n", " provider= \"openai\",\n",
" params={\n", " resolution=\"512x512\"\n",
" \"resolution\" : \"512x512\"\n",
" }\n",
")" ")"
] ]
}, },
@ -222,7 +220,7 @@
"\n", "\n",
"llm = EdenAI(\n", "llm = EdenAI(\n",
" callbacks=[StreamingStdOutCallbackHandler()],\n", " callbacks=[StreamingStdOutCallbackHandler()],\n",
" feature=\"text\",provider=\"openai\", params={\"temperature\" : 0.2,\"max_tokens\" : 250}\n", " feature=\"text\",provider=\"openai\", temperature=0.2,max_tokens=250\n",
")\n", ")\n",
"prompt = \"\"\"\n", "prompt = \"\"\"\n",
"User: Answer the following yes/no question by reasoning step by step. Can a dog drive a car?\n", "User: Answer the following yes/no question by reasoning step by step. Can a dog drive a car?\n",
@ -256,10 +254,10 @@
"outputs": [], "outputs": [],
"source": [ "source": [
"llm = EdenAI(\n", "llm = EdenAI(\n",
"feature=\"text\" ,provider=\"openai\" , params={\"temperature\" : 0.2,\"max_tokens\" : 250}\n", "feature=\"text\", provider=\"openai\", temperature=0.2, max_tokens=250\n",
")\n", ")\n",
"text2image = EdenAI(\n", "text2image = EdenAI(\n",
"feature=\"image\" ,provider=\"openai\", params={\"resolution\" : \"512x512\"}\n", "feature=\"image\", provider=\"openai\", resolution=\"512x512\"\n",
")" ")"
] ]
}, },
@ -314,13 +312,7 @@
"text": [ "text": [
"\n", "\n",
"\n", "\n",
"\u001b[1m> Entering new SimpleSequentialChain chain...\u001b[0m\n" "\u001b[1m> Entering new SimpleSequentialChain chain...\u001b[0m\n",
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[36;1m\u001b[1;3m\n", "\u001b[36;1m\u001b[1;3m\n",
"\n", "\n",
"Headwear Haven\u001b[0m\n", "Headwear Haven\u001b[0m\n",
@ -352,7 +344,7 @@
], ],
"metadata": { "metadata": {
"kernelspec": { "kernelspec": {
"display_name": "Python 3", "display_name": "Python 3 (ipykernel)",
"language": "python", "language": "python",
"name": "python3" "name": "python3"
}, },
@ -366,9 +358,8 @@
"name": "python", "name": "python",
"nbconvert_exporter": "python", "nbconvert_exporter": "python",
"pygments_lexer": "ipython3", "pygments_lexer": "ipython3",
"version": "3.10.11" "version": "3.10.12"
}, }
"orig_nbformat": 4
}, },
"nbformat": 4, "nbformat": 4,
"nbformat_minor": 2 "nbformat_minor": 2

@ -11,7 +11,7 @@
"cell_type": "markdown", "cell_type": "markdown",
"metadata": {}, "metadata": {},
"source": [ "source": [
"Eden AI is an AI consulting company that was founded to use its resources to empower people and create impactful products that use AI to improve the quality of life for individuals, businesses and societies at large." "Eden AI is revolutionizing the AI landscape by uniting the best AI providers, empowering users to unlock limitless possibilities and tap into the true potential of artificial intelligence. With an all-in-one comprehensive and hassle-free platform, it allows users to deploy AI features to production lightning fast, enabling effortless access to the full breadth of AI capabilities via a single API. (website: https://edenai.co/)"
] ]
}, },
{ {

@ -1,4 +1,4 @@
from typing import Dict, List, Optional from typing import Any, Dict, List, Optional
from langchain.embeddings.base import Embeddings from langchain.embeddings.base import Embeddings
from langchain.pydantic_v1 import BaseModel, Extra, Field, root_validator from langchain.pydantic_v1 import BaseModel, Extra, Field, root_validator
@ -14,9 +14,15 @@ class EdenAiEmbeddings(BaseModel, Embeddings):
edenai_api_key: Optional[str] = Field(None, description="EdenAI API Token") edenai_api_key: Optional[str] = Field(None, description="EdenAI API Token")
provider: Optional[str] = "openai" provider: str = "openai"
"""embedding provider to use (eg: openai,google etc.)""" """embedding provider to use (eg: openai,google etc.)"""
model: Optional[str] = None
"""
model name for above provider (eg: 'text-davinci-003' for openai)
available models are shown on https://docs.edenai.co/ under 'available providers'
"""
class Config: class Config:
"""Configuration for this pydantic object.""" """Configuration for this pydantic object."""
@ -30,6 +36,12 @@ class EdenAiEmbeddings(BaseModel, Embeddings):
) )
return values return values
@staticmethod
def get_user_agent() -> str:
from langchain import __version__
return f"langchain/{__version__}"
def _generate_embeddings(self, texts: List[str]) -> List[List[float]]: def _generate_embeddings(self, texts: List[str]) -> List[List[float]]:
"""Compute embeddings using EdenAi api.""" """Compute embeddings using EdenAi api."""
url = "https://api.edenai.run/v2/text/embeddings" url = "https://api.edenai.run/v2/text/embeddings"
@ -38,9 +50,14 @@ class EdenAiEmbeddings(BaseModel, Embeddings):
"accept": "application/json", "accept": "application/json",
"content-type": "application/json", "content-type": "application/json",
"authorization": f"Bearer {self.edenai_api_key}", "authorization": f"Bearer {self.edenai_api_key}",
"User-Agent": self.get_user_agent(),
} }
payload = {"texts": texts, "providers": self.provider} payload: Dict[str, Any] = {"texts": texts, "providers": self.provider}
if self.model is not None:
payload["settings"] = {self.provider: self.model}
request = Requests(headers=headers) request = Requests(headers=headers)
response = request.post(url=url, data=payload) response = request.post(url=url, data=payload)
if response.status_code >= 500: if response.status_code >= 500:
@ -55,6 +72,11 @@ class EdenAiEmbeddings(BaseModel, Embeddings):
temp = response.json() temp = response.json()
provider_response = temp[self.provider]
if provider_response.get("status") == "fail":
err_msg = provider_response.get("error", {}).get("message")
raise Exception(err_msg)
embeddings = [] embeddings = []
for embed_item in temp[self.provider]["items"]: for embed_item in temp[self.provider]["items"]:
embedding = embed_item["embedding"] embedding = embed_item["embedding"]

@ -41,13 +41,24 @@ class EdenAI(LLM):
"""Subfeature of above feature, use generation by default""" """Subfeature of above feature, use generation by default"""
provider: str provider: str
"""Geneerative provider to use (eg: openai,stabilityai,cohere,google etc.)""" """Generative provider to use (eg: openai,stabilityai,cohere,google etc.)"""
params: Dict[str, Any] model: Optional[str] = None
""" """
Parameters to pass to above subfeature (excluding 'providers' & 'text') model name for above provider (eg: 'text-davinci-003' for openai)
ref text: https://docs.edenai.co/reference/text_generation_create available models are shown on https://docs.edenai.co/ under 'available providers'
ref image: https://docs.edenai.co/reference/text_generation_create """
# Optional parameters to add depending of chosen feature
# see api reference for more infos
temperature: Optional[float] = Field(default=None, ge=0, le=1) # for text
max_tokens: Optional[int] = Field(default=None, ge=0) # for text
resolution: Optional[Literal["256x256", "512x512", "1024x1024"]] = None # for image
params: Dict[str, Any] = Field(default_factory=dict)
"""
DEPRECATED: use temperature, max_tokens, resolution directly
optional parameters to pass to api
""" """
model_kwargs: Dict[str, Any] = Field(default_factory=dict) model_kwargs: Dict[str, Any] = Field(default_factory=dict)
@ -98,6 +109,12 @@ class EdenAI(LLM):
else: else:
return output[self.provider]["items"][0]["image"] return output[self.provider]["items"][0]["image"]
@staticmethod
def get_user_agent() -> str:
from langchain import __version__
return f"langchain/{__version__}"
def _call( def _call(
self, self,
prompt: str, prompt: str,
@ -112,7 +129,6 @@ class EdenAI(LLM):
Returns: Returns:
json formatted str response. json formatted str response.
""" """
stops = None stops = None
if self.stop_sequences is not None and stop is not None: if self.stop_sequences is not None and stop is not None:
@ -125,16 +141,28 @@ class EdenAI(LLM):
stops = stop stops = stop
url = f"{self.base_url}/{self.feature}/{self.subfeature}" url = f"{self.base_url}/{self.feature}/{self.subfeature}"
headers = {"Authorization": f"Bearer {self.edenai_api_key}"} headers = {
payload = { "Authorization": f"Bearer {self.edenai_api_key}",
**self.params, "User-Agent": self.get_user_agent(),
}
payload: Dict[str, Any] = {
"providers": self.provider, "providers": self.provider,
"num_images": 1, # always limit to 1 (ignored for text)
"text": prompt, "text": prompt,
"max_tokens": self.max_tokens,
"temperature": self.temperature,
"resolution": self.resolution,
**self.params,
**kwargs, **kwargs,
"num_images": 1, # always limit to 1 (ignored for text)
} }
request = Requests(headers=headers)
# filter None values to not pass them to the http payload
payload = {k: v for k, v in payload.items() if v is not None}
if self.model is not None:
payload["settings"] = {self.provider: self.model}
request = Requests(headers=headers)
response = request.post(url=url, data=payload) response = request.post(url=url, data=payload)
if response.status_code >= 500: if response.status_code >= 500:
@ -147,7 +175,13 @@ class EdenAI(LLM):
f"{response.status_code}: {response.text}" f"{response.status_code}: {response.text}"
) )
output = self._format_output(response.json()) data = response.json()
provider_response = data[self.provider]
if provider_response.get("status") == "fail":
err_msg = provider_response.get("error", {}).get("message")
raise Exception(err_msg)
output = self._format_output(data)
if stops is not None: if stops is not None:
output = enforce_stop_tokens(output, stops) output = enforce_stop_tokens(output, stops)
@ -182,19 +216,29 @@ class EdenAI(LLM):
else: else:
stops = stop stops = stop
print("Running the acall")
url = f"{self.base_url}/{self.feature}/{self.subfeature}" url = f"{self.base_url}/{self.feature}/{self.subfeature}"
headers = {"Authorization": f"Bearer {self.edenai_api_key}"} headers = {
payload = { "Authorization": f"Bearer {self.edenai_api_key}",
**self.params, "User-Agent": self.get_user_agent(),
}
payload: Dict[str, Any] = {
"providers": self.provider, "providers": self.provider,
"num_images": 1, # always limit to 1 (ignored for text)
"text": prompt, "text": prompt,
"max_tokens": self.max_tokens,
"temperature": self.temperature,
"resolution": self.resolution,
**self.params,
**kwargs, **kwargs,
"num_images": 1, # always limit to 1 (ignored for text)
} }
# filter `None` values to not pass them to the http payload as null
payload = {k: v for k, v in payload.items() if v is not None}
if self.model is not None:
payload["settings"] = {self.provider: self.model}
async with ClientSession() as session: async with ClientSession() as session:
print("Requesting")
async with session.post(url, json=payload, headers=headers) as response: async with session.post(url, json=payload, headers=headers) as response:
if response.status >= 500: if response.status >= 500:
raise Exception(f"EdenAI Server: Error {response.status}") raise Exception(f"EdenAI Server: Error {response.status}")
@ -209,6 +253,10 @@ class EdenAI(LLM):
) )
response_json = await response.json() response_json = await response.json()
provider_response = response_json[self.provider]
if provider_response.get("status") == "fail":
err_msg = provider_response.get("error", {}).get("message")
raise Exception(err_msg)
output = self._format_output(response_json) output = self._format_output(response_json)
if stops is not None: if stops is not None:

@ -13,7 +13,7 @@ from langchain.llms import EdenAI
def test_edenai_call() -> None: def test_edenai_call() -> None:
"""Test simple call to edenai.""" """Test simple call to edenai."""
llm = EdenAI(provider="openai", params={"temperature": 0.2, "max_tokens": 250}) llm = EdenAI(provider="openai", temperature=0.2, max_tokens=250)
output = llm("Say foo:") output = llm("Say foo:")
assert llm._llm_type == "edenai" assert llm._llm_type == "edenai"
@ -24,9 +24,23 @@ def test_edenai_call() -> None:
async def test_edenai_acall() -> None: async def test_edenai_acall() -> None:
"""Test simple call to edenai.""" """Test simple call to edenai."""
llm = EdenAI(provider="openai", params={"temperature": 0.2, "max_tokens": 250}) llm = EdenAI(provider="openai", temperature=0.2, max_tokens=250)
output = await llm.agenerate(["Say foo:"]) output = await llm.agenerate(["Say foo:"])
assert llm._llm_type == "edenai" assert llm._llm_type == "edenai"
assert llm.feature == "text" assert llm.feature == "text"
assert llm.subfeature == "generation" assert llm.subfeature == "generation"
assert isinstance(output, str) assert isinstance(output, str)
def test_edenai_call_with_old_params() -> None:
"""
Test simple call to edenai with using `params`
to pass optional parameters to api
"""
llm = EdenAI(provider="openai", params={"temperature": 0.2, "max_tokens": 250})
output = llm("Say foo:")
assert llm._llm_type == "edenai"
assert llm.feature == "text"
assert llm.subfeature == "generation"
assert isinstance(output, str)

Loading…
Cancel
Save