-
-
Notifications
You must be signed in to change notification settings - Fork 129
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #43 from farizrahman4u/feature/azure_openai
OpenAI Azure API support
- Loading branch information
Showing
15 changed files
with
250 additions
and
54 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import numpy as np | ||
import openai | ||
from loopgpt.embeddings.openai_ import OpenAIEmbeddingProvider | ||
from typing import Optional | ||
|
||
from loopgpt.utils.openai_key import get_openai_key | ||
|
||
|
||
class AzureOpenAIEmbeddingProvider(OpenAIEmbeddingProvider): | ||
"""Creates an Azure OpenAI embedding provider from a deployment ID. Can be created only when ``openai.api_type`` is set to ``azure``. | ||
:param deployment_id: The deployment ID of the embedding provider. | ||
:type deployment_id: str | ||
:param api_key: The API key to use for the embedding provider. | ||
If not specified, it will be found from ``openai.api_key`` or ``.env`` file or the ``OPENAI_API_KEY`` environment variable. | ||
:type api_key: str, optional | ||
.. note:: | ||
See :class:`AzureOpenAIModel <loopgpt.models.azure_openai.AzureOpenAIModel>` also. | ||
""" | ||
|
||
def __init__(self, deployment_id: str, api_key: Optional[str] = None): | ||
# sanity check | ||
assert ( | ||
openai.api_type == "azure" | ||
), "AzureOpenAIModel can only be used with Azure API" | ||
|
||
self.deployment_id = deployment_id | ||
self.api_key = api_key | ||
|
||
def get(self, text: str): | ||
api_key = get_openai_key(self.api_key) | ||
return np.array( | ||
openai.Embedding.create( | ||
input=[text], engine=self.deployment_id, api_key=api_key | ||
)["data"][0]["embedding"], | ||
dtype=np.float32, | ||
) | ||
|
||
def config(self): | ||
cfg = {"deployment_id": self.deployment_id, "api_key": self.api_key} | ||
return cfg | ||
|
||
@classmethod | ||
def from_config(cls, config): | ||
return cls(config["deployment_id"], config["api_key"]) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,29 +1,31 @@ | ||
from typing import Optional | ||
from loopgpt.embeddings.provider import BaseEmbeddingProvider | ||
from loopgpt.utils.openai_key import get_openai_key | ||
import numpy as np | ||
import openai | ||
|
||
|
||
class OpenAIEmbeddingProvider(BaseEmbeddingProvider): | ||
def __init__(self, model: str = "text-embedding-ada-002"): | ||
super(OpenAIEmbeddingProvider, self).__init__() | ||
def __init__( | ||
self, model: str = "text-embedding-ada-002", api_key: Optional[str] = None | ||
): | ||
self.model = model | ||
self.api_key = api_key | ||
|
||
def get(self, text: str): | ||
import openai | ||
|
||
api_key = get_openai_key(self.api_key) | ||
return np.array( | ||
openai.Embedding.create(input=[text], model="text-embedding-ada-002")[ | ||
"data" | ||
][0]["embedding"], | ||
openai.Embedding.create( | ||
input=[text], model="text-embedding-ada-002", api_key=api_key | ||
)["data"][0]["embedding"], | ||
dtype=np.float32, | ||
) | ||
|
||
def config(self): | ||
cfg = super().config() | ||
cfg.update({"model": self.model}) | ||
cfg.update({"model": self.model, "api_key": self.api_key}) | ||
return cfg | ||
|
||
@classmethod | ||
def from_config(cls, config): | ||
obj = cls() | ||
obj.model = config["model"] | ||
return obj | ||
return cls(config["model"], config.get("api_key")) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
from typing import List, Dict, Optional | ||
from loopgpt.models.openai_ import OpenAIModel | ||
from loopgpt.utils.openai_key import get_openai_key | ||
from loopgpt.logger import logger | ||
from time import time | ||
|
||
from openai.error import RateLimitError | ||
import requests | ||
import openai | ||
|
||
|
||
def get_deployment_details(endpoint, deployment_id, api_version, api_key): | ||
api_key = get_openai_key(api_key) | ||
response = requests.get( | ||
f"{endpoint}/openai/deployments/{deployment_id}?api-version={api_version}", | ||
headers={"api-key": api_key}, | ||
) | ||
return response.json() | ||
|
||
|
||
def get_deployment_model(endpoint, deployment_id, api_version, api_key): | ||
details = get_deployment_details(endpoint, deployment_id, api_version, api_key) | ||
model = details["model"] | ||
|
||
return { | ||
"gpt-35-turbo": "gpt-3.5-turbo", | ||
"gpt-4": "gpt-4", | ||
"gpt-4-32k": "gpt-4-32k", | ||
}[model] | ||
|
||
|
||
class AzureOpenAIModel(OpenAIModel): | ||
"""Creates an Azure OpenAI model from a deployment ID. Can be created only when ``openai.api_type`` is set to ``azure``. | ||
:param deployment_id: The deployment ID of the model. | ||
:type deployment_id: str | ||
:param api_key: The API key to use for the model. | ||
If not specified, it will be found from ``openai.api_key`` or ``.env`` file or the ``OPENAI_API_KEY`` environment variable. | ||
:type api_key: str, optional | ||
:raises AssertionError: If ``openai.api_type`` is not set to ``azure``. | ||
.. note:: | ||
You will also need an embedding provider deployed (e.g., text-embedding-ada-002) for creating an agent. | ||
Example: | ||
.. code-block:: python | ||
import os | ||
import openai | ||
import loopgpt | ||
from loopgpt.models import AzureOpenAIModel | ||
from loopgpt.embeddings import AzureOpenAIEmbeddingProvider | ||
openai.api_type = "azure" | ||
openai.api_base = "https://<your deployment>.openai.azure.com/" | ||
openai.api_version = "2023-03-15-preview" | ||
openai.api_key = os.getenv("OPENAI_API_KEY") | ||
model = AzureOpenAIModel("my-gpt4-deployment") | ||
embedding_provider = AzureOpenAIEmbeddingProvider("my-embeddings-deployment") | ||
agent = loopgpt.Agent(model=model, embedding_provider=embedding_provider) | ||
agent.chat("Hello, how are you?") | ||
""" | ||
|
||
def __init__(self, deployment_id: str, api_key: Optional[str] = None): | ||
# sanity check | ||
assert ( | ||
openai.api_type == "azure" | ||
), "AzureOpenAIModel can only be used with Azure API" | ||
|
||
self.deployment_id = deployment_id | ||
self.api_key = api_key | ||
self.endpoint = openai.api_base | ||
self.api_version = openai.api_version | ||
self.model = get_deployment_model( | ||
self.endpoint, self.deployment_id, self.api_version, self.api_key | ||
) | ||
|
||
def chat( | ||
self, | ||
messages: List[Dict[str, str]], | ||
max_tokens: Optional[int] = None, | ||
temperature: float = 0.8, | ||
) -> str: | ||
api_key = get_openai_key(self.api_key) | ||
num_retries = 3 | ||
for _ in range(num_retries): | ||
try: | ||
resp = openai.ChatCompletion.create( | ||
engine=self.deployment_id, | ||
messages=messages, | ||
api_key=api_key, | ||
max_tokens=max_tokens, | ||
temperature=temperature, | ||
)["choices"][0]["message"]["content"] | ||
return resp | ||
|
||
except RateLimitError: | ||
logger.warn("Rate limit exceeded. Retrying after 20 seconds.") | ||
time.sleep(20) | ||
continue | ||
|
||
def config(self): | ||
cfg = super().config() | ||
cfg.update( | ||
{ | ||
"deployment_id": self.deployment_id, | ||
} | ||
) | ||
return cfg | ||
|
||
@classmethod | ||
def from_config(cls, config): | ||
return cls(config["deployment_id"], config.get("api_key")) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.