Commit 2b264c39
Changed files (12)
openai/api_resources/abstract/api_resource.py
@@ -8,7 +8,8 @@ from openai.util import ApiType
class APIResource(OpenAIObject):
api_prefix = ""
- azure_api_prefix = 'openai/deployments'
+ azure_api_prefix = 'openai'
+ azure_deployments_prefix = 'deployments'
@classmethod
def retrieve(cls, id, api_key=None, request_id=None, **params):
@@ -46,20 +47,21 @@ class APIResource(OpenAIObject):
"id",
)
api_version = self.api_version or openai.api_version
+ extn = quote_plus(id)
if self.typed_api_type == ApiType.AZURE:
if not api_version:
raise error.InvalidRequestError("An API version is required for the Azure API type.")
+
if not operation:
- raise error.InvalidRequestError(
- "The request needs an operation (eg: 'search') for the Azure OpenAI API type."
- )
- extn = quote_plus(id)
- return "/%s/%s/%s?api-version=%s" % (self.azure_api_prefix, extn, operation, api_version)
+ base = self.class_url()
+ return "/%s%s/%s?api-version=%s" % (self.azure_api_prefix, base, extn, api_version)
+
+ return "/%s/%s/%s/%s?api-version=%s" % (
+ self.azure_api_prefix, self.azure_deployments_prefix, extn, operation, api_version)
elif self.typed_api_type == ApiType.OPEN_AI:
base = self.class_url()
- extn = quote_plus(id)
return "%s/%s" % (base, extn)
else:
@@ -75,6 +77,7 @@ class APIResource(OpenAIObject):
url_,
api_key=None,
api_base=None,
+ api_type=None,
request_id=None,
api_version=None,
organization=None,
@@ -85,6 +88,7 @@ class APIResource(OpenAIObject):
api_version=api_version,
organization=organization,
api_base=api_base,
+ api_type=api_type
)
response, _, api_key = requestor.request(
method_, url_, params, request_id=request_id
@@ -92,3 +96,10 @@ class APIResource(OpenAIObject):
return util.convert_to_openai_object(
response, api_key, api_version, organization
)
+
+ @classmethod
+ def _get_api_type_and_version(cls, api_type: str, api_version: str):
+ typed_api_type = ApiType.from_str(api_type) if api_type else ApiType.from_str(openai.api_type)
+ typed_api_version = api_version or openai.api_version
+ return (typed_api_type, typed_api_version)
+
openai/api_resources/abstract/createable_api_resource.py
@@ -1,5 +1,6 @@
-from openai import api_requestor, util
+from openai import api_requestor, util, error
from openai.api_resources.abstract.api_resource import APIResource
+from openai.util import ApiType
class CreateableAPIResource(APIResource):
@@ -10,6 +11,7 @@ class CreateableAPIResource(APIResource):
cls,
api_key=None,
api_base=None,
+ api_type=None,
request_id=None,
api_version=None,
organization=None,
@@ -18,10 +20,20 @@ class CreateableAPIResource(APIResource):
requestor = api_requestor.APIRequestor(
api_key,
api_base=api_base,
+ api_type=api_type,
api_version=api_version,
organization=organization,
)
- url = cls.class_url()
+ typed_api_type, api_version = cls._get_api_type_and_version(api_type, api_version)
+
+ if typed_api_type == ApiType.AZURE:
+ base = cls.class_url()
+ url = "/%s%s?api-version=%s" % (cls.azure_api_prefix, base, api_version)
+ elif typed_api_type == ApiType.OPEN_AI:
+ url = cls.class_url()
+ else:
+ raise error.InvalidAPIType('Unsupported API type %s' % api_type)
+
response, _, api_key = requestor.request(
"post", url, params, request_id=request_id
)
openai/api_resources/abstract/deletable_api_resource.py
@@ -1,12 +1,24 @@
from urllib.parse import quote_plus
+from openai import error
from openai.api_resources.abstract.api_resource import APIResource
-
+from openai.util import ApiType
class DeletableAPIResource(APIResource):
@classmethod
- def delete(cls, sid, **params):
+ def delete(cls, sid, api_type=None, api_version=None, **params):
if isinstance(cls, APIResource):
raise ValueError(".delete may only be called as a class method now.")
- url = "%s/%s" % (cls.class_url(), quote_plus(sid))
- return cls._static_request("delete", url, **params)
+
+ base = cls.class_url()
+ extn = quote_plus(sid)
+
+ typed_api_type, api_version = cls._get_api_type_and_version(api_type, api_version)
+ if typed_api_type == ApiType.AZURE:
+ url = "/%s%s/%s?api-version=%s" % (cls.azure_api_prefix, base, extn, api_version)
+ elif typed_api_type == ApiType.OPEN_AI:
+ url = "%s/%s" % (base, extn)
+ else:
+ raise error.InvalidAPIType('Unsupported API type %s' % api_type)
+
+ return cls._static_request("delete", url, api_type=api_type, api_version=api_version, **params)
openai/api_resources/abstract/engine_api_resource.py
@@ -15,7 +15,6 @@ MAX_TIMEOUT = 20
class EngineAPIResource(APIResource):
engine_required = True
plain_old_data = False
- azure_api_prefix = 'openai/deployments'
def __init__(self, engine: Optional[str] = None, **kwargs):
super().__init__(engine=engine, **kwargs)
@@ -25,8 +24,7 @@ class EngineAPIResource(APIResource):
# Namespaces are separated in object names with periods (.) and in URLs
# with forward slashes (/), so replace the former with the latter.
base = cls.OBJECT_NAME.replace(".", "/") # type: ignore
- typed_api_type = ApiType.from_str(api_type) if api_type else ApiType.from_str(openai.api_type)
- api_version = api_version or openai.api_version
+ typed_api_type, api_version = cls._get_api_type_and_version(api_type, api_version)
if typed_api_type == ApiType.AZURE:
if not api_version:
@@ -36,7 +34,8 @@ class EngineAPIResource(APIResource):
"You must provide the deployment name in the 'engine' parameter to access the Azure OpenAI service"
)
extn = quote_plus(engine)
- return "/%s/%s/%ss?api-version=%s" % (cls.azure_api_prefix, extn, base, api_version)
+ return "/%s/%s/%s/%ss?api-version=%s" % (
+ cls.azure_api_prefix, cls.azure_deployments_prefix, extn, base, api_version)
elif typed_api_type == ApiType.OPEN_AI:
if engine is None:
@@ -133,19 +132,20 @@ class EngineAPIResource(APIResource):
"id",
)
+ extn = quote_plus(id)
params_connector = '?'
+
if self.typed_api_type == ApiType.AZURE:
api_version = self.api_version or openai.api_version
if not api_version:
raise error.InvalidRequestError("An API version is required for the Azure API type.")
- extn = quote_plus(id)
base = self.OBJECT_NAME.replace(".", "/")
- url = "/%s/%s/%ss/%s?api-version=%s" % (self.azure_api_prefix, self.engine, base, extn, api_version)
+ url = "/%s/%s/%s/%ss/%s?api-version=%s" % (
+ self.azure_api_prefix, self.azure_deployments_prefix, self.engine, base, extn, api_version)
params_connector = '&'
elif self.typed_api_type == ApiType.OPEN_AI:
base = self.class_url(self.engine, self.api_type, self.api_version)
- extn = quote_plus(id)
url = "%s/%s" % (base, extn)
else:
openai/api_resources/abstract/listable_api_resource.py
@@ -1,5 +1,6 @@
-from openai import api_requestor, util
+from openai import api_requestor, util, error
from openai.api_resources.abstract.api_resource import APIResource
+from openai.util import ApiType
class ListableAPIResource(APIResource):
@@ -15,15 +16,27 @@ class ListableAPIResource(APIResource):
api_version=None,
organization=None,
api_base=None,
+ api_type=None,
**params,
):
requestor = api_requestor.APIRequestor(
api_key,
api_base=api_base or cls.api_base(),
api_version=api_version,
+ api_type=api_type,
organization=organization,
)
- url = cls.class_url()
+
+ typed_api_type, api_version = cls._get_api_type_and_version(api_type, api_version)
+
+ if typed_api_type == ApiType.AZURE:
+ base = cls.class_url()
+ url = "/%s%s?api-version=%s" % (cls.azure_api_prefix, base, api_version)
+ elif typed_api_type == ApiType.OPEN_AI:
+ url = cls.class_url()
+ else:
+ raise error.InvalidAPIType('Unsupported API type %s' % api_type)
+
response, _, api_key = requestor.request(
"get", url, params, request_id=request_id
)
openai/api_resources/file.py
@@ -3,8 +3,9 @@ import os
from typing import cast
import openai
-from openai import api_requestor, util
+from openai import api_requestor, util, error
from openai.api_resources.abstract import DeletableAPIResource, ListableAPIResource
+from openai.util import ApiType
class File(ListableAPIResource, DeletableAPIResource):
@@ -18,6 +19,7 @@ class File(ListableAPIResource, DeletableAPIResource):
model=None,
api_key=None,
api_base=None,
+ api_type=None,
api_version=None,
organization=None,
user_provided_filename=None,
@@ -27,19 +29,29 @@ class File(ListableAPIResource, DeletableAPIResource):
requestor = api_requestor.APIRequestor(
api_key,
api_base=api_base or openai.api_base,
+ api_type=api_type,
api_version=api_version,
organization=organization,
)
- url = cls.class_url()
+ typed_api_type, api_version = cls._get_api_type_and_version(api_type, api_version)
+
+ if typed_api_type == ApiType.AZURE:
+ base = cls.class_url()
+ url = "/%s%s?api-version=%s" % (cls.azure_api_prefix, base, api_version)
+ elif typed_api_type == ApiType.OPEN_AI:
+ url = cls.class_url()
+ else:
+ raise error.InvalidAPIType('Unsupported API type %s' % api_type)
+
# Set the filename on 'purpose' and 'model' to None so they are
# interpreted as form data.
files = [("purpose", (None, purpose))]
if model is not None:
files.append(("model", (None, model)))
if user_provided_filename is not None:
- files.append(("file", (user_provided_filename, file)))
+ files.append(("file", (user_provided_filename, file, 'application/octet-stream')))
else:
- files.append(("file", file))
+ files.append(("file", file, 'application/octet-stream'))
response, _, api_key = requestor.request("post", url, files=files)
return util.convert_to_openai_object(
response, api_key, api_version, organization
@@ -47,15 +59,31 @@ class File(ListableAPIResource, DeletableAPIResource):
@classmethod
def download(
- cls, id, api_key=None, api_base=None, api_version=None, organization=None
+ cls,
+ id,
+ api_key=None,
+ api_base=None,
+ api_type=None,
+ api_version=None,
+ organization=None
):
requestor = api_requestor.APIRequestor(
api_key,
api_base=api_base or openai.api_base,
+ api_type=api_type,
api_version=api_version,
organization=organization,
)
- url = f"{cls.class_url()}/{id}/content"
+ typed_api_type, api_version = cls._get_api_type_and_version(api_type, api_version)
+
+ if typed_api_type == ApiType.AZURE:
+ base = cls.class_url()
+ url = "/%s%s/%s/content?api-version=%s" % (cls.azure_api_prefix, base, id, api_version)
+ elif typed_api_type == ApiType.OPEN_AI:
+ url = f"{cls.class_url()}/{id}/content"
+ else:
+ raise error.InvalidAPIType('Unsupported API type %s' % api_type)
+
result = requestor.request_raw("get", url)
if not 200 <= result.status_code < 300:
raise requestor.handle_error_response(
@@ -75,6 +103,7 @@ class File(ListableAPIResource, DeletableAPIResource):
purpose,
api_key=None,
api_base=None,
+ api_type=None,
api_version=None,
organization=None,
):
@@ -82,6 +111,7 @@ class File(ListableAPIResource, DeletableAPIResource):
all_files = cls.list(
api_key=api_key,
api_base=api_base or openai.api_base,
+ api_type=api_type,
api_version=api_version,
organization=organization,
).get("data", [])
@@ -93,7 +123,9 @@ class File(ListableAPIResource, DeletableAPIResource):
file_basename = os.path.basename(f["filename"])
if file_basename != basename:
continue
- if f["bytes"] != bytes:
+ if "bytes" in f and f["bytes"] != bytes:
+ continue
+ if "size" in f and int(f["size"]) != bytes:
continue
matching_files.append(f)
return matching_files
openai/api_resources/fine_tune.py
@@ -1,23 +1,41 @@
from urllib.parse import quote_plus
-from openai import api_requestor, util
+from openai import api_requestor, util, error
from openai.api_resources.abstract import (
CreateableAPIResource,
ListableAPIResource,
nested_resource_class_methods,
)
+from openai.api_resources.abstract.deletable_api_resource import DeletableAPIResource
from openai.openai_response import OpenAIResponse
+from openai.util import ApiType
@nested_resource_class_methods("event", operations=["list"])
-class FineTune(ListableAPIResource, CreateableAPIResource):
+class FineTune(ListableAPIResource, CreateableAPIResource, DeletableAPIResource):
OBJECT_NAME = "fine-tune"
@classmethod
- def cancel(cls, id, api_key=None, request_id=None, **params):
+ def cancel(
+ cls,
+ id,
+ api_key=None,
+ api_type=None,
+ request_id=None,
+ api_version=None,
+ **params
+ ):
base = cls.class_url()
extn = quote_plus(id)
- url = "%s/%s/cancel" % (base, extn)
+
+ typed_api_type, api_version = cls._get_api_type_and_version(api_type, api_version)
+ if typed_api_type == ApiType.AZURE:
+ url = "/%s%s/%s/cancel?api-version=%s" % (cls.azure_api_prefix, base, extn, api_version)
+ elif typed_api_type == ApiType.OPEN_AI:
+ url = "%s/%s/cancel" % (base, extn)
+ else:
+ raise error.InvalidAPIType('Unsupported API type %s' % api_type)
+
instance = cls(id, api_key, **params)
return instance.request("post", url, request_id=request_id)
@@ -27,6 +45,7 @@ class FineTune(ListableAPIResource, CreateableAPIResource):
id,
api_key=None,
api_base=None,
+ api_type=None,
request_id=None,
api_version=None,
organization=None,
@@ -38,10 +57,20 @@ class FineTune(ListableAPIResource, CreateableAPIResource):
requestor = api_requestor.APIRequestor(
api_key,
api_base=api_base,
+ api_type=api_type,
api_version=api_version,
organization=organization,
)
- url = "%s/%s/events?stream=true" % (base, extn)
+
+ typed_api_type, api_version = cls._get_api_type_and_version(api_type, api_version)
+
+ if typed_api_type == ApiType.AZURE:
+ url = "/%s%s/%s/events?stream=true&api-version=%s" % (cls.azure_api_prefix, base, extn, api_version)
+ elif typed_api_type == ApiType.OPEN_AI:
+ url = "%s/%s/events?stream=true" % (base, extn)
+ else:
+ raise error.InvalidAPIType('Unsupported API type %s' % api_type)
+
response, _, api_key = requestor.request(
"get", url, params, stream=True, request_id=request_id
)
openai/api_requestor.py
@@ -111,7 +111,7 @@ class APIRequestor:
def handle_error_response(self, rbody, rcode, resp, rheaders, stream_error=False):
try:
- error_data = resp["error"]
+ error_data = resp["error"] if self.api_type == ApiType.OPEN_AI else resp
except (KeyError, TypeError):
raise error.APIError(
"Invalid response object from API: %r (HTTP response code "
@@ -322,6 +322,10 @@ class APIRequestor:
def _interpret_response_line(
self, rbody, rcode, rheaders, stream: bool
) -> OpenAIResponse:
+ # HTTP 204 response code does not have any content in the body.
+ if rcode == 204:
+ return OpenAIResponse(None, rheaders)
+
if rcode == 503:
raise error.ServiceUnavailableError(
"The server is overloaded or not ready yet.", rbody, rcode, headers=rheaders
openai/cli.py
@@ -320,7 +320,7 @@ class FineTune:
sys.stdout.write(
"Found potentially duplicated files with name '{name}', purpose 'fine-tune' and size {size} bytes\n".format(
name=os.path.basename(matching_files[0]["filename"]),
- size=matching_files[0]["bytes"],
+ size=matching_files[0]["bytes"] if "bytes" in matching_files[0] else matching_files[0]["size"],
)
)
sys.stdout.write("\n".join(file_ids))
openai/version.py
@@ -1,1 +1,1 @@
-VERSION = "0.15.0"
+VERSION = "0.16.0"
.gitignore
@@ -6,4 +6,5 @@ __pycache__
build
*.egg
.vscode/settings.json
-.ipynb_checkpoints
\ No newline at end of file
+.ipynb_checkpoints
+.vscode/launch.json
README.md
@@ -77,7 +77,7 @@ search = openai.Engine(id="deployment-namme").search(documents=["White House", "
print(search)
```
-Please note that for the moment, the Microsoft Azure endpoints can only be used for completion and search operations.
+Please note that for the moment, the Microsoft Azure endpoints can only be used for completion, search and fine-tuning operations.
### Command-line interface