Boadiwaa commited on
Commit
a459c98
1 Parent(s): e4d36a8

Upload 77 files

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. openai/__init__.py +73 -0
  2. openai/__pycache__/__init__.cpython-39.pyc +0 -0
  3. openai/__pycache__/_openai_scripts.cpython-39.pyc +0 -0
  4. openai/__pycache__/api_requestor.cpython-39.pyc +0 -0
  5. openai/__pycache__/cli.cpython-39.pyc +0 -0
  6. openai/__pycache__/embeddings_utils.cpython-39.pyc +0 -0
  7. openai/__pycache__/error.cpython-39.pyc +0 -0
  8. openai/__pycache__/object_classes.cpython-39.pyc +0 -0
  9. openai/__pycache__/openai_object.cpython-39.pyc +0 -0
  10. openai/__pycache__/openai_response.cpython-39.pyc +0 -0
  11. openai/__pycache__/upload_progress.cpython-39.pyc +0 -0
  12. openai/__pycache__/util.cpython-39.pyc +0 -0
  13. openai/__pycache__/validators.cpython-39.pyc +0 -0
  14. openai/__pycache__/version.cpython-39.pyc +0 -0
  15. openai/__pycache__/wandb_logger.cpython-39.pyc +0 -0
  16. openai/_openai_scripts.py +74 -0
  17. openai/api_requestor.py +365 -0
  18. openai/api_resources/__init__.py +13 -0
  19. openai/api_resources/__pycache__/__init__.cpython-39.pyc +0 -0
  20. openai/api_resources/__pycache__/answer.cpython-39.pyc +0 -0
  21. openai/api_resources/__pycache__/classification.cpython-39.pyc +0 -0
  22. openai/api_resources/__pycache__/completion.cpython-39.pyc +0 -0
  23. openai/api_resources/__pycache__/customer.cpython-39.pyc +0 -0
  24. openai/api_resources/__pycache__/deployment.cpython-39.pyc +0 -0
  25. openai/api_resources/__pycache__/edit.cpython-39.pyc +0 -0
  26. openai/api_resources/__pycache__/embedding.cpython-39.pyc +0 -0
  27. openai/api_resources/__pycache__/engine.cpython-39.pyc +0 -0
  28. openai/api_resources/__pycache__/error_object.cpython-39.pyc +0 -0
  29. openai/api_resources/__pycache__/file.cpython-39.pyc +0 -0
  30. openai/api_resources/__pycache__/fine_tune.cpython-39.pyc +0 -0
  31. openai/api_resources/__pycache__/model.cpython-39.pyc +0 -0
  32. openai/api_resources/__pycache__/search.cpython-39.pyc +0 -0
  33. openai/api_resources/abstract/__init__.py +10 -0
  34. openai/api_resources/abstract/__pycache__/__init__.cpython-39.pyc +0 -0
  35. openai/api_resources/abstract/__pycache__/api_resource.cpython-39.pyc +0 -0
  36. openai/api_resources/abstract/__pycache__/createable_api_resource.cpython-39.pyc +0 -0
  37. openai/api_resources/abstract/__pycache__/deletable_api_resource.cpython-39.pyc +0 -0
  38. openai/api_resources/abstract/__pycache__/engine_api_resource.cpython-39.pyc +0 -0
  39. openai/api_resources/abstract/__pycache__/listable_api_resource.cpython-39.pyc +0 -0
  40. openai/api_resources/abstract/__pycache__/nested_resource_class_methods.cpython-39.pyc +0 -0
  41. openai/api_resources/abstract/__pycache__/updateable_api_resource.cpython-39.pyc +0 -0
  42. openai/api_resources/abstract/api_resource.py +117 -0
  43. openai/api_resources/abstract/createable_api_resource.py +47 -0
  44. openai/api_resources/abstract/deletable_api_resource.py +24 -0
  45. openai/api_resources/abstract/engine_api_resource.py +192 -0
  46. openai/api_resources/abstract/listable_api_resource.py +47 -0
  47. openai/api_resources/abstract/nested_resource_class_methods.py +102 -0
  48. openai/api_resources/abstract/updateable_api_resource.py +10 -0
  49. openai/api_resources/answer.py +12 -0
  50. openai/api_resources/classification.py +12 -0
openai/__init__.py ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # OpenAI Python bindings.
2
+ #
3
+ # Originally forked from the MIT-licensed Stripe Python bindings.
4
+
5
+ import os
6
+ from typing import Optional
7
+
8
+ from openai.api_resources import (
9
+ Answer,
10
+ Classification,
11
+ Completion,
12
+ Customer,
13
+ Edit,
14
+ Deployment,
15
+ Embedding,
16
+ Engine,
17
+ ErrorObject,
18
+ File,
19
+ FineTune,
20
+ Model,
21
+ Search,
22
+ )
23
+ from openai.error import APIError, InvalidRequestError, OpenAIError
24
+
25
+ api_key = os.environ.get("OPENAI_API_KEY")
26
+ # Path of a file with an API key, whose contents can change. Supercedes
27
+ # `api_key` if set. The main use case is volume-mounted Kubernetes secrets,
28
+ # which are updated automatically.
29
+ api_key_path: Optional[str] = os.environ.get("OPENAI_API_KEY_PATH")
30
+
31
+ organization = os.environ.get("OPENAI_ORGANIZATION")
32
+ api_base = os.environ.get("OPENAI_API_BASE", "https://api.openai.com/v1")
33
+ api_type = os.environ.get("OPENAI_API_TYPE", "open_ai")
34
+ api_version = "2021-11-01-preview" if api_type == "azure" else None
35
+ verify_ssl_certs = True # No effect. Certificates are always verified.
36
+ proxy = None
37
+ app_info = None
38
+ enable_telemetry = False # Ignored; the telemetry feature was removed.
39
+ ca_bundle_path = None # No longer used, feature was removed
40
+ debug = False
41
+ log = None # Set to either 'debug' or 'info', controls console logging
42
+
43
+ __all__ = [
44
+ "APIError",
45
+ "Answer",
46
+ "Classification",
47
+ "Completion",
48
+ "Customer",
49
+ "Edit",
50
+ "Deployment",
51
+ "Embedding",
52
+ "Engine",
53
+ "ErrorObject",
54
+ "File",
55
+ "FineTune",
56
+ "InvalidRequestError",
57
+ "Model",
58
+ "OpenAIError",
59
+ "Search",
60
+ "api_base",
61
+ "api_key",
62
+ "api_type",
63
+ "api_key_path",
64
+ "api_version",
65
+ "app_info",
66
+ "ca_bundle_path",
67
+ "debug",
68
+ "enable_elemetry",
69
+ "log",
70
+ "organization",
71
+ "proxy",
72
+ "verify_ssl_certs",
73
+ ]
openai/__pycache__/__init__.cpython-39.pyc ADDED
Binary file (1.3 kB). View file
 
openai/__pycache__/_openai_scripts.cpython-39.pyc ADDED
Binary file (2.06 kB). View file
 
openai/__pycache__/api_requestor.cpython-39.pyc ADDED
Binary file (9.27 kB). View file
 
openai/__pycache__/cli.cpython-39.pyc ADDED
Binary file (26.4 kB). View file
 
openai/__pycache__/embeddings_utils.cpython-39.pyc ADDED
Binary file (7.83 kB). View file
 
openai/__pycache__/error.cpython-39.pyc ADDED
Binary file (4.7 kB). View file
 
openai/__pycache__/object_classes.cpython-39.pyc ADDED
Binary file (484 Bytes). View file
 
openai/__pycache__/openai_object.cpython-39.pyc ADDED
Binary file (6.94 kB). View file
 
openai/__pycache__/openai_response.cpython-39.pyc ADDED
Binary file (1.18 kB). View file
 
openai/__pycache__/upload_progress.cpython-39.pyc ADDED
Binary file (2.05 kB). View file
 
openai/__pycache__/util.cpython-39.pyc ADDED
Binary file (5.35 kB). View file
 
openai/__pycache__/validators.cpython-39.pyc ADDED
Binary file (28.7 kB). View file
 
openai/__pycache__/version.cpython-39.pyc ADDED
Binary file (210 Bytes). View file
 
openai/__pycache__/wandb_logger.cpython-39.pyc ADDED
Binary file (7.27 kB). View file
 
openai/_openai_scripts.py ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python
2
+ import argparse
3
+ import logging
4
+ import sys
5
+
6
+ import openai
7
+ from openai.cli import api_register, display_error, tools_register, wandb_register
8
+
9
+ logger = logging.getLogger()
10
+ formatter = logging.Formatter("[%(asctime)s] %(message)s")
11
+ handler = logging.StreamHandler(sys.stderr)
12
+ handler.setFormatter(formatter)
13
+ logger.addHandler(handler)
14
+
15
+
16
+ def main():
17
+ parser = argparse.ArgumentParser(description=None)
18
+ parser.add_argument(
19
+ "-v",
20
+ "--verbose",
21
+ action="count",
22
+ dest="verbosity",
23
+ default=0,
24
+ help="Set verbosity.",
25
+ )
26
+ parser.add_argument("-b", "--api-base", help="What API base url to use.")
27
+ parser.add_argument("-k", "--api-key", help="What API key to use.")
28
+ parser.add_argument(
29
+ "-o",
30
+ "--organization",
31
+ help="Which organization to run as (will use your default organization if not specified)",
32
+ )
33
+
34
+ def help(args):
35
+ parser.print_help()
36
+
37
+ parser.set_defaults(func=help)
38
+
39
+ subparsers = parser.add_subparsers()
40
+ sub_api = subparsers.add_parser("api", help="Direct API calls")
41
+ sub_tools = subparsers.add_parser("tools", help="Client side tools for convenience")
42
+ sub_wandb = subparsers.add_parser("wandb", help="Logging with Weights & Biases")
43
+
44
+ api_register(sub_api)
45
+ tools_register(sub_tools)
46
+ wandb_register(sub_wandb)
47
+
48
+ args = parser.parse_args()
49
+ if args.verbosity == 1:
50
+ logger.setLevel(logging.INFO)
51
+ elif args.verbosity >= 2:
52
+ logger.setLevel(logging.DEBUG)
53
+
54
+ openai.debug = True
55
+ if args.api_key is not None:
56
+ openai.api_key = args.api_key
57
+ if args.api_base is not None:
58
+ openai.api_base = args.api_base
59
+ if args.organization is not None:
60
+ openai.organization = args.organization
61
+
62
+ try:
63
+ args.func(args)
64
+ except openai.error.OpenAIError as e:
65
+ display_error(e)
66
+ return 1
67
+ except KeyboardInterrupt:
68
+ sys.stderr.write("\n")
69
+ return 1
70
+ return 0
71
+
72
+
73
+ if __name__ == "__main__":
74
+ sys.exit(main())
openai/api_requestor.py ADDED
@@ -0,0 +1,365 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import platform
3
+ import threading
4
+ import warnings
5
+ from email import header
6
+ from json import JSONDecodeError
7
+ from typing import Dict, Iterator, Optional, Tuple, Union
8
+ from urllib.parse import urlencode, urlsplit, urlunsplit
9
+
10
+ import requests
11
+
12
+ import openai
13
+ from openai import error, util, version
14
+ from openai.openai_response import OpenAIResponse
15
+ from openai.util import ApiType
16
+
17
+ TIMEOUT_SECS = 600
18
+ MAX_CONNECTION_RETRIES = 2
19
+
20
+ # Has one attribute per thread, 'session'.
21
+ _thread_context = threading.local()
22
+
23
+
24
+ def _build_api_url(url, query):
25
+ scheme, netloc, path, base_query, fragment = urlsplit(url)
26
+
27
+ if base_query:
28
+ query = "%s&%s" % (base_query, query)
29
+
30
+ return urlunsplit((scheme, netloc, path, query, fragment))
31
+
32
+
33
+ def _requests_proxies_arg(proxy) -> Optional[Dict[str, str]]:
34
+ """Returns a value suitable for the 'proxies' argument to 'requests.request."""
35
+ if proxy is None:
36
+ return None
37
+ elif isinstance(proxy, str):
38
+ return {"http": proxy, "https": proxy}
39
+ elif isinstance(proxy, dict):
40
+ return proxy.copy()
41
+ else:
42
+ raise ValueError(
43
+ "'openai.proxy' must be specified as either a string URL or a dict with string URL under the https and/or http keys."
44
+ )
45
+
46
+
47
+ def _make_session() -> requests.Session:
48
+ if not openai.verify_ssl_certs:
49
+ warnings.warn("verify_ssl_certs is ignored; openai always verifies.")
50
+ s = requests.Session()
51
+ proxies = _requests_proxies_arg(openai.proxy)
52
+ if proxies:
53
+ s.proxies = proxies
54
+ s.mount(
55
+ "https://",
56
+ requests.adapters.HTTPAdapter(max_retries=MAX_CONNECTION_RETRIES),
57
+ )
58
+ return s
59
+
60
+
61
+ def parse_stream(rbody):
62
+ for line in rbody:
63
+ if line:
64
+ if line == b"data: [DONE]":
65
+ # return here will cause GeneratorExit exception in urllib3
66
+ # and it will close http connection with TCP Reset
67
+ continue
68
+ if hasattr(line, "decode"):
69
+ line = line.decode("utf-8")
70
+ if line.startswith("data: "):
71
+ line = line[len("data: ") :]
72
+ yield line
73
+
74
+
75
+ class APIRequestor:
76
+ def __init__(
77
+ self,
78
+ key=None,
79
+ api_base=None,
80
+ api_type=None,
81
+ api_version=None,
82
+ organization=None,
83
+ ):
84
+ self.api_base = api_base or openai.api_base
85
+ self.api_key = key or util.default_api_key()
86
+ self.api_type = (
87
+ ApiType.from_str(api_type)
88
+ if api_type
89
+ else ApiType.from_str(openai.api_type)
90
+ )
91
+ self.api_version = api_version or openai.api_version
92
+ self.organization = organization or openai.organization
93
+
94
+ @classmethod
95
+ def format_app_info(cls, info):
96
+ str = info["name"]
97
+ if info["version"]:
98
+ str += "/%s" % (info["version"],)
99
+ if info["url"]:
100
+ str += " (%s)" % (info["url"],)
101
+ return str
102
+
103
+ def request(
104
+ self,
105
+ method,
106
+ url,
107
+ params=None,
108
+ headers=None,
109
+ files=None,
110
+ stream=False,
111
+ request_id: Optional[str] = None,
112
+ ) -> Tuple[Union[OpenAIResponse, Iterator[OpenAIResponse]], bool, str]:
113
+ result = self.request_raw(
114
+ method.lower(),
115
+ url,
116
+ params=params,
117
+ supplied_headers=headers,
118
+ files=files,
119
+ stream=stream,
120
+ request_id=request_id,
121
+ )
122
+ resp, got_stream = self._interpret_response(result, stream)
123
+ return resp, got_stream, self.api_key
124
+
125
+ def handle_error_response(self, rbody, rcode, resp, rheaders, stream_error=False):
126
+ try:
127
+ error_data = resp["error"]
128
+ except (KeyError, TypeError):
129
+ raise error.APIError(
130
+ "Invalid response object from API: %r (HTTP response code "
131
+ "was %d)" % (rbody, rcode),
132
+ rbody,
133
+ rcode,
134
+ resp,
135
+ )
136
+
137
+ if "internal_message" in error_data:
138
+ error_data["message"] += "\n\n" + error_data["internal_message"]
139
+
140
+ util.log_info(
141
+ "OpenAI API error received",
142
+ error_code=error_data.get("code"),
143
+ error_type=error_data.get("type"),
144
+ error_message=error_data.get("message"),
145
+ error_param=error_data.get("param"),
146
+ stream_error=stream_error,
147
+ )
148
+
149
+ # Rate limits were previously coded as 400's with code 'rate_limit'
150
+ if rcode == 429:
151
+ return error.RateLimitError(
152
+ error_data.get("message"), rbody, rcode, resp, rheaders
153
+ )
154
+ elif rcode in [400, 404, 415]:
155
+ return error.InvalidRequestError(
156
+ error_data.get("message"),
157
+ error_data.get("param"),
158
+ error_data.get("code"),
159
+ rbody,
160
+ rcode,
161
+ resp,
162
+ rheaders,
163
+ )
164
+ elif rcode == 401:
165
+ return error.AuthenticationError(
166
+ error_data.get("message"), rbody, rcode, resp, rheaders
167
+ )
168
+ elif rcode == 403:
169
+ return error.PermissionError(
170
+ error_data.get("message"), rbody, rcode, resp, rheaders
171
+ )
172
+ elif rcode == 409:
173
+ return error.TryAgain(
174
+ error_data.get("message"), rbody, rcode, resp, rheaders
175
+ )
176
+ elif stream_error:
177
+ # TODO: we will soon attach status codes to stream errors
178
+ parts = [error_data.get("message"), "(Error occurred while streaming.)"]
179
+ message = " ".join([p for p in parts if p is not None])
180
+ return error.APIError(message, rbody, rcode, resp, rheaders)
181
+ else:
182
+ return error.APIError(
183
+ error_data.get("message"), rbody, rcode, resp, rheaders
184
+ )
185
+
186
+ def request_headers(
187
+ self, method: str, extra, request_id: Optional[str]
188
+ ) -> Dict[str, str]:
189
+ user_agent = "OpenAI/v1 PythonBindings/%s" % (version.VERSION,)
190
+ if openai.app_info:
191
+ user_agent += " " + self.format_app_info(openai.app_info)
192
+
193
+ uname_without_node = " ".join(
194
+ v for k, v in platform.uname()._asdict().items() if k != "node"
195
+ )
196
+ ua = {
197
+ "bindings_version": version.VERSION,
198
+ "httplib": "requests",
199
+ "lang": "python",
200
+ "lang_version": platform.python_version(),
201
+ "platform": platform.platform(),
202
+ "publisher": "openai",
203
+ "uname": uname_without_node,
204
+ }
205
+ if openai.app_info:
206
+ ua["application"] = openai.app_info
207
+
208
+ headers = {
209
+ "X-OpenAI-Client-User-Agent": json.dumps(ua),
210
+ "User-Agent": user_agent,
211
+ }
212
+
213
+ headers.update(util.api_key_to_header(self.api_type, self.api_key))
214
+
215
+ if self.organization:
216
+ headers["OpenAI-Organization"] = self.organization
217
+
218
+ if self.api_version is not None and self.api_type == ApiType.OPEN_AI:
219
+ headers["OpenAI-Version"] = self.api_version
220
+ if request_id is not None:
221
+ headers["X-Request-Id"] = request_id
222
+ if openai.debug:
223
+ headers["OpenAI-Debug"] = "true"
224
+ headers.update(extra)
225
+
226
+ return headers
227
+
228
+ def _validate_headers(
229
+ self, supplied_headers: Optional[Dict[str, str]]
230
+ ) -> Dict[str, str]:
231
+ headers: Dict[str, str] = {}
232
+ if supplied_headers is None:
233
+ return headers
234
+
235
+ if not isinstance(supplied_headers, dict):
236
+ raise TypeError("Headers must be a dictionary")
237
+
238
+ for k, v in supplied_headers.items():
239
+ if not isinstance(k, str):
240
+ raise TypeError("Header keys must be strings")
241
+ if not isinstance(v, str):
242
+ raise TypeError("Header values must be strings")
243
+ headers[k] = v
244
+
245
+ # NOTE: It is possible to do more validation of the headers, but a request could always
246
+ # be made to the API manually with invalid headers, so we need to handle them server side.
247
+
248
+ return headers
249
+
250
+ def request_raw(
251
+ self,
252
+ method,
253
+ url,
254
+ *,
255
+ params=None,
256
+ supplied_headers: Dict[str, str] = None,
257
+ files=None,
258
+ stream: bool = False,
259
+ request_id: Optional[str] = None,
260
+ ) -> requests.Response:
261
+ abs_url = "%s%s" % (self.api_base, url)
262
+ headers = self._validate_headers(supplied_headers)
263
+
264
+ data = None
265
+ if method == "get" or method == "delete":
266
+ if params:
267
+ encoded_params = urlencode(
268
+ [(k, v) for k, v in params.items() if v is not None]
269
+ )
270
+ abs_url = _build_api_url(abs_url, encoded_params)
271
+ elif method in {"post", "put"}:
272
+ if params and files:
273
+ raise ValueError("At most one of params and files may be specified.")
274
+ if params:
275
+ data = json.dumps(params).encode()
276
+ headers["Content-Type"] = "application/json"
277
+ else:
278
+ raise error.APIConnectionError(
279
+ "Unrecognized HTTP method %r. This may indicate a bug in the "
280
+ "OpenAI bindings. Please contact support@openai.com for "
281
+ "assistance." % (method,)
282
+ )
283
+
284
+ headers = self.request_headers(method, headers, request_id)
285
+
286
+ util.log_info("Request to OpenAI API", method=method, path=abs_url)
287
+ util.log_debug("Post details", data=data, api_version=self.api_version)
288
+
289
+ if not hasattr(_thread_context, "session"):
290
+ _thread_context.session = _make_session()
291
+ try:
292
+ result = _thread_context.session.request(
293
+ method,
294
+ abs_url,
295
+ headers=headers,
296
+ data=data,
297
+ files=files,
298
+ stream=stream,
299
+ timeout=TIMEOUT_SECS,
300
+ )
301
+ except requests.exceptions.RequestException as e:
302
+ raise error.APIConnectionError("Error communicating with OpenAI") from e
303
+ util.log_info(
304
+ "OpenAI API response",
305
+ path=abs_url,
306
+ response_code=result.status_code,
307
+ processing_ms=result.headers.get("OpenAI-Processing-Ms"),
308
+ )
309
+ # Don't read the whole stream for debug logging unless necessary.
310
+ if openai.log == "debug":
311
+ util.log_debug(
312
+ "API response body", body=result.content, headers=result.headers
313
+ )
314
+ return result
315
+
316
+ def _interpret_response(
317
+ self, result: requests.Response, stream: bool
318
+ ) -> Tuple[Union[OpenAIResponse, Iterator[OpenAIResponse]], bool]:
319
+ """Returns the response(s) and a bool indicating whether it is a stream."""
320
+ if stream and "text/event-stream" in result.headers.get("Content-Type", ""):
321
+ return (
322
+ self._interpret_response_line(
323
+ line, result.status_code, result.headers, stream=True
324
+ )
325
+ for line in parse_stream(result.iter_lines())
326
+ ), True
327
+ else:
328
+ return (
329
+ self._interpret_response_line(
330
+ result.content, result.status_code, result.headers, stream=False
331
+ ),
332
+ False,
333
+ )
334
+
335
+ def _interpret_response_line(
336
+ self, rbody, rcode, rheaders, stream: bool
337
+ ) -> OpenAIResponse:
338
+ # HTTP 204 response code does not have any content in the body.
339
+ if rcode == 204:
340
+ return OpenAIResponse(None, rheaders)
341
+
342
+ if rcode == 503:
343
+ raise error.ServiceUnavailableError(
344
+ "The server is overloaded or not ready yet.",
345
+ rbody,
346
+ rcode,
347
+ headers=rheaders,
348
+ )
349
+ try:
350
+ if hasattr(rbody, "decode"):
351
+ rbody = rbody.decode("utf-8")
352
+ data = json.loads(rbody)
353
+ except (JSONDecodeError, UnicodeDecodeError):
354
+ raise error.APIError(
355
+ f"HTTP code {rcode} from API ({rbody})", rbody, rcode, headers=rheaders
356
+ )
357
+ resp = OpenAIResponse(data, rheaders)
358
+ # In the future, we might add a "status" parameter to errors
359
+ # to better handle the "error while streaming" case.
360
+ stream_error = stream and "error" in resp.data
361
+ if stream_error or not 200 <= rcode < 300:
362
+ raise self.handle_error_response(
363
+ rbody, rcode, resp.data, rheaders, stream_error=stream_error
364
+ )
365
+ return resp
openai/api_resources/__init__.py ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from openai.api_resources.answer import Answer # noqa: F401
2
+ from openai.api_resources.classification import Classification # noqa: F401
3
+ from openai.api_resources.completion import Completion # noqa: F401
4
+ from openai.api_resources.customer import Customer # noqa: F401
5
+ from openai.api_resources.edit import Edit # noqa: F401
6
+ from openai.api_resources.deployment import Deployment # noqa: F401
7
+ from openai.api_resources.embedding import Embedding # noqa: F401
8
+ from openai.api_resources.engine import Engine # noqa: F401
9
+ from openai.api_resources.error_object import ErrorObject # noqa: F401
10
+ from openai.api_resources.file import File # noqa: F401
11
+ from openai.api_resources.fine_tune import FineTune # noqa: F401
12
+ from openai.api_resources.model import Model # noqa: F401
13
+ from openai.api_resources.search import Search # noqa: F401
openai/api_resources/__pycache__/__init__.cpython-39.pyc ADDED
Binary file (1.01 kB). View file
 
openai/api_resources/__pycache__/answer.cpython-39.pyc ADDED
Binary file (736 Bytes). View file
 
openai/api_resources/__pycache__/classification.cpython-39.pyc ADDED
Binary file (776 Bytes). View file
 
openai/api_resources/__pycache__/completion.cpython-39.pyc ADDED
Binary file (1.52 kB). View file
 
openai/api_resources/__pycache__/customer.cpython-39.pyc ADDED
Binary file (795 Bytes). View file
 
openai/api_resources/__pycache__/deployment.cpython-39.pyc ADDED
Binary file (2.26 kB). View file
 
openai/api_resources/__pycache__/edit.cpython-39.pyc ADDED
Binary file (1.28 kB). View file
 
openai/api_resources/__pycache__/embedding.cpython-39.pyc ADDED
Binary file (1.82 kB). View file
 
openai/api_resources/__pycache__/engine.cpython-39.pyc ADDED
Binary file (1.69 kB). View file
 
openai/api_resources/__pycache__/error_object.cpython-39.pyc ADDED
Binary file (856 Bytes). View file
 
openai/api_resources/__pycache__/file.cpython-39.pyc ADDED
Binary file (2.98 kB). View file
 
openai/api_resources/__pycache__/fine_tune.cpython-39.pyc ADDED
Binary file (2.39 kB). View file
 
openai/api_resources/__pycache__/model.cpython-39.pyc ADDED
Binary file (513 Bytes). View file
 
openai/api_resources/__pycache__/search.cpython-39.pyc ADDED
Binary file (1.38 kB). View file
 
openai/api_resources/abstract/__init__.py ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ # flake8: noqa
2
+
3
+ from openai.api_resources.abstract.api_resource import APIResource
4
+ from openai.api_resources.abstract.createable_api_resource import CreateableAPIResource
5
+ from openai.api_resources.abstract.deletable_api_resource import DeletableAPIResource
6
+ from openai.api_resources.abstract.listable_api_resource import ListableAPIResource
7
+ from openai.api_resources.abstract.nested_resource_class_methods import (
8
+ nested_resource_class_methods,
9
+ )
10
+ from openai.api_resources.abstract.updateable_api_resource import UpdateableAPIResource
openai/api_resources/abstract/__pycache__/__init__.cpython-39.pyc ADDED
Binary file (797 Bytes). View file
 
openai/api_resources/abstract/__pycache__/api_resource.cpython-39.pyc ADDED
Binary file (3.04 kB). View file
 
openai/api_resources/abstract/__pycache__/createable_api_resource.cpython-39.pyc ADDED
Binary file (1.36 kB). View file
 
openai/api_resources/abstract/__pycache__/deletable_api_resource.cpython-39.pyc ADDED
Binary file (1.25 kB). View file
 
openai/api_resources/abstract/__pycache__/engine_api_resource.cpython-39.pyc ADDED
Binary file (4.25 kB). View file
 
openai/api_resources/abstract/__pycache__/listable_api_resource.cpython-39.pyc ADDED
Binary file (1.54 kB). View file
 
openai/api_resources/abstract/__pycache__/nested_resource_class_methods.cpython-39.pyc ADDED
Binary file (3.37 kB). View file
 
openai/api_resources/abstract/__pycache__/updateable_api_resource.cpython-39.pyc ADDED
Binary file (770 Bytes). View file
 
openai/api_resources/abstract/api_resource.py ADDED
@@ -0,0 +1,117 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from urllib.parse import quote_plus
2
+
3
+ import openai
4
+ from openai import api_requestor, error, util
5
+ from openai.openai_object import OpenAIObject
6
+ from openai.util import ApiType
7
+
8
+
9
+ class APIResource(OpenAIObject):
10
+ api_prefix = ""
11
+ azure_api_prefix = "openai"
12
+ azure_deployments_prefix = "deployments"
13
+
14
+ @classmethod
15
+ def retrieve(cls, id, api_key=None, request_id=None, **params):
16
+ instance = cls(id, api_key, **params)
17
+ instance.refresh(request_id=request_id)
18
+ return instance
19
+
20
+ def refresh(self, request_id=None):
21
+ self.refresh_from(
22
+ self.request("get", self.instance_url(), request_id=request_id)
23
+ )
24
+ return self
25
+
26
+ @classmethod
27
+ def class_url(cls):
28
+ if cls == APIResource:
29
+ raise NotImplementedError(
30
+ "APIResource is an abstract class. You should perform actions on its subclasses."
31
+ )
32
+ # Namespaces are separated in object names with periods (.) and in URLs
33
+ # with forward slashes (/), so replace the former with the latter.
34
+ base = cls.OBJECT_NAME.replace(".", "/") # type: ignore
35
+ if cls.api_prefix:
36
+ return "/%s/%s" % (cls.api_prefix, base)
37
+ return "/%s" % (base)
38
+
39
+ def instance_url(self, operation=None):
40
+ id = self.get("id")
41
+
42
+ if not isinstance(id, str):
43
+ raise error.InvalidRequestError(
44
+ "Could not determine which URL to request: %s instance "
45
+ "has invalid ID: %r, %s. ID should be of type `str` (or"
46
+ " `unicode`)" % (type(self).__name__, id, type(id)),
47
+ "id",
48
+ )
49
+ api_version = self.api_version or openai.api_version
50
+ extn = quote_plus(id)
51
+
52
+ if self.typed_api_type == ApiType.AZURE:
53
+ if not api_version:
54
+ raise error.InvalidRequestError(
55
+ "An API version is required for the Azure API type."
56
+ )
57
+
58
+ if not operation:
59
+ base = self.class_url()
60
+ return "/%s%s/%s?api-version=%s" % (
61
+ self.azure_api_prefix,
62
+ base,
63
+ extn,
64
+ api_version
65
+ )
66
+
67
+ return "/%s/%s/%s/%s?api-version=%s" % (
68
+ self.azure_api_prefix,
69
+ self.azure_deployments_prefix,
70
+ extn,
71
+ operation,
72
+ api_version
73
+ )
74
+
75
+
76
+ elif self.typed_api_type == ApiType.OPEN_AI:
77
+ base = self.class_url()
78
+ return "%s/%s" % (base, extn)
79
+
80
+ else:
81
+ raise error.InvalidAPIType("Unsupported API type %s" % self.api_type)
82
+
83
+ # The `method_` and `url_` arguments are suffixed with an underscore to
84
+ # avoid conflicting with actual request parameters in `params`.
85
+ @classmethod
86
+ def _static_request(
87
+ cls,
88
+ method_,
89
+ url_,
90
+ api_key=None,
91
+ api_base=None,
92
+ api_type=None,
93
+ request_id=None,
94
+ api_version=None,
95
+ organization=None,
96
+ **params,
97
+ ):
98
+ requestor = api_requestor.APIRequestor(
99
+ api_key,
100
+ api_version=api_version,
101
+ organization=organization,
102
+ api_base=api_base,
103
+ api_type=api_type
104
+ )
105
+ response, _, api_key = requestor.request(
106
+ method_, url_, params, request_id=request_id
107
+ )
108
+ return util.convert_to_openai_object(
109
+ response, api_key, api_version, organization
110
+ )
111
+
112
+ @classmethod
113
+ def _get_api_type_and_version(cls, api_type: str, api_version: str):
114
+ typed_api_type = ApiType.from_str(api_type) if api_type else ApiType.from_str(openai.api_type)
115
+ typed_api_version = api_version or openai.api_version
116
+ return (typed_api_type, typed_api_version)
117
+
openai/api_resources/abstract/createable_api_resource.py ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from openai import api_requestor, util, error
2
+ from openai.api_resources.abstract.api_resource import APIResource
3
+ from openai.util import ApiType
4
+
5
+
6
+ class CreateableAPIResource(APIResource):
7
+ plain_old_data = False
8
+
9
+ @classmethod
10
+ def create(
11
+ cls,
12
+ api_key=None,
13
+ api_base=None,
14
+ api_type=None,
15
+ request_id=None,
16
+ api_version=None,
17
+ organization=None,
18
+ **params,
19
+ ):
20
+ requestor = api_requestor.APIRequestor(
21
+ api_key,
22
+ api_base=api_base,
23
+ api_type=api_type,
24
+ api_version=api_version,
25
+ organization=organization,
26
+ )
27
+ typed_api_type, api_version = cls._get_api_type_and_version(api_type, api_version)
28
+
29
+ if typed_api_type == ApiType.AZURE:
30
+ base = cls.class_url()
31
+ url = "/%s%s?api-version=%s" % (cls.azure_api_prefix, base, api_version)
32
+ elif typed_api_type == ApiType.OPEN_AI:
33
+ url = cls.class_url()
34
+ else:
35
+ raise error.InvalidAPIType('Unsupported API type %s' % api_type)
36
+
37
+ response, _, api_key = requestor.request(
38
+ "post", url, params, request_id=request_id
39
+ )
40
+
41
+ return util.convert_to_openai_object(
42
+ response,
43
+ api_key,
44
+ api_version,
45
+ organization,
46
+ plain_old_data=cls.plain_old_data,
47
+ )
openai/api_resources/abstract/deletable_api_resource.py ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from urllib.parse import quote_plus
2
+
3
+ from openai import error
4
+ from openai.api_resources.abstract.api_resource import APIResource
5
+ from openai.util import ApiType
6
+
7
+ class DeletableAPIResource(APIResource):
8
+ @classmethod
9
+ def delete(cls, sid, api_type=None, api_version=None, **params):
10
+ if isinstance(cls, APIResource):
11
+ raise ValueError(".delete may only be called as a class method now.")
12
+
13
+ base = cls.class_url()
14
+ extn = quote_plus(sid)
15
+
16
+ typed_api_type, api_version = cls._get_api_type_and_version(api_type, api_version)
17
+ if typed_api_type == ApiType.AZURE:
18
+ url = "/%s%s/%s?api-version=%s" % (cls.azure_api_prefix, base, extn, api_version)
19
+ elif typed_api_type == ApiType.OPEN_AI:
20
+ url = "%s/%s" % (base, extn)
21
+ else:
22
+ raise error.InvalidAPIType('Unsupported API type %s' % api_type)
23
+
24
+ return cls._static_request("delete", url, api_type=api_type, api_version=api_version, **params)
openai/api_resources/abstract/engine_api_resource.py ADDED
@@ -0,0 +1,192 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import time
2
+ from pydoc import apropos
3
+ from typing import Optional
4
+ from urllib.parse import quote_plus
5
+
6
+ import openai
7
+ from openai import api_requestor, error, util
8
+ from openai.api_resources.abstract.api_resource import APIResource
9
+ from openai.openai_response import OpenAIResponse
10
+ from openai.util import ApiType
11
+
12
+ MAX_TIMEOUT = 20
13
+
14
+
15
+ class EngineAPIResource(APIResource):
16
+ engine_required = True
17
+ plain_old_data = False
18
+
19
+ def __init__(self, engine: Optional[str] = None, **kwargs):
20
+ super().__init__(engine=engine, **kwargs)
21
+
22
+ @classmethod
23
+ def class_url(
24
+ cls,
25
+ engine: Optional[str] = None,
26
+ api_type: Optional[str] = None,
27
+ api_version: Optional[str] = None,
28
+ ):
29
+ # Namespaces are separated in object names with periods (.) and in URLs
30
+ # with forward slashes (/), so replace the former with the latter.
31
+ base = cls.OBJECT_NAME.replace(".", "/") # type: ignore
32
+ typed_api_type, api_version = cls._get_api_type_and_version(api_type, api_version)
33
+
34
+ if typed_api_type == ApiType.AZURE:
35
+ if not api_version:
36
+ raise error.InvalidRequestError(
37
+ "An API version is required for the Azure API type."
38
+ )
39
+ if engine is None:
40
+ raise error.InvalidRequestError(
41
+ "You must provide the deployment name in the 'engine' parameter to access the Azure OpenAI service"
42
+ )
43
+ extn = quote_plus(engine)
44
+ return "/%s/%s/%s/%s?api-version=%s" % (
45
+ cls.azure_api_prefix,
46
+ cls.azure_deployments_prefix,
47
+ extn,
48
+ base,
49
+ api_version
50
+ )
51
+
52
+ elif typed_api_type == ApiType.OPEN_AI:
53
+ if engine is None:
54
+ return "/%s" % (base)
55
+
56
+ extn = quote_plus(engine)
57
+ return "/engines/%s/%s" % (extn, base)
58
+
59
+ else:
60
+ raise error.InvalidAPIType("Unsupported API type %s" % api_type)
61
+
62
+ @classmethod
63
+ def create(
64
+ cls,
65
+ api_key=None,
66
+ api_base=None,
67
+ api_type=None,
68
+ request_id=None,
69
+ api_version=None,
70
+ organization=None,
71
+ **params,
72
+ ):
73
+ engine = params.pop("engine", None)
74
+ timeout = params.pop("timeout", None)
75
+ stream = params.get("stream", False)
76
+ headers = params.pop("headers", None)
77
+ if engine is None and cls.engine_required:
78
+ raise error.InvalidRequestError(
79
+ "Must provide an 'engine' parameter to create a %s" % cls, "engine"
80
+ )
81
+
82
+ if timeout is None:
83
+ # No special timeout handling
84
+ pass
85
+ elif timeout > 0:
86
+ # API only supports timeouts up to MAX_TIMEOUT
87
+ params["timeout"] = min(timeout, MAX_TIMEOUT)
88
+ timeout = (timeout - params["timeout"]) or None
89
+ elif timeout == 0:
90
+ params["timeout"] = MAX_TIMEOUT
91
+
92
+ requestor = api_requestor.APIRequestor(
93
+ api_key,
94
+ api_base=api_base,
95
+ api_type=api_type,
96
+ api_version=api_version,
97
+ organization=organization,
98
+ )
99
+ url = cls.class_url(engine, api_type, api_version)
100
+ response, _, api_key = requestor.request(
101
+ "post",
102
+ url,
103
+ params=params,
104
+ headers=headers,
105
+ stream=stream,
106
+ request_id=request_id,
107
+ )
108
+
109
+ if stream:
110
+ assert not isinstance(response, OpenAIResponse) # must be an iterator
111
+ return (
112
+ util.convert_to_openai_object(
113
+ line,
114
+ api_key,
115
+ api_version,
116
+ organization,
117
+ engine=engine,
118
+ plain_old_data=cls.plain_old_data,
119
+ )
120
+ for line in response
121
+ )
122
+ else:
123
+ obj = util.convert_to_openai_object(
124
+ response,
125
+ api_key,
126
+ api_version,
127
+ organization,
128
+ engine=engine,
129
+ plain_old_data=cls.plain_old_data,
130
+ )
131
+
132
+ if timeout is not None:
133
+ obj.wait(timeout=timeout or None)
134
+
135
+ return obj
136
+
137
+ def instance_url(self):
138
+ id = self.get("id")
139
+
140
+ if not isinstance(id, str):
141
+ raise error.InvalidRequestError(
142
+ f"Could not determine which URL to request: {type(self).__name__} instance has invalid ID: {id}, {type(id)}. ID should be of type str.",
143
+ "id",
144
+ )
145
+
146
+ extn = quote_plus(id)
147
+ params_connector = '?'
148
+
149
+ if self.typed_api_type == ApiType.AZURE:
150
+ api_version = self.api_version or openai.api_version
151
+ if not api_version:
152
+ raise error.InvalidRequestError(
153
+ "An API version is required for the Azure API type."
154
+ )
155
+ base = self.OBJECT_NAME.replace(".", "/")
156
+ url = "/%s/%s/%s/%s/%s?api-version=%s" % (
157
+ self.azure_api_prefix,
158
+ self.azure_deployments_prefix,
159
+ self.engine,
160
+ base,
161
+ extn,
162
+ api_version
163
+ )
164
+ params_connector = '&'
165
+
166
+
167
+ elif self.typed_api_type == ApiType.OPEN_AI:
168
+ base = self.class_url(self.engine, self.api_type, self.api_version)
169
+ url = "%s/%s" % (base, extn)
170
+
171
+ else:
172
+ raise error.InvalidAPIType("Unsupported API type %s" % self.api_type)
173
+
174
+ timeout = self.get("timeout")
175
+ if timeout is not None:
176
+ timeout = quote_plus(str(timeout))
177
+ url += params_connector + "timeout={}".format(timeout)
178
+ return url
179
+
180
+ def wait(self, timeout=None):
181
+ start = time.time()
182
+ while self.status != "complete":
183
+ self.timeout = (
184
+ min(timeout + start - time.time(), MAX_TIMEOUT)
185
+ if timeout is not None
186
+ else MAX_TIMEOUT
187
+ )
188
+ if self.timeout < 0:
189
+ del self.timeout
190
+ break
191
+ self.refresh()
192
+ return self
openai/api_resources/abstract/listable_api_resource.py ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from openai import api_requestor, util, error
2
+ from openai.api_resources.abstract.api_resource import APIResource
3
+ from openai.util import ApiType
4
+
5
+
6
+ class ListableAPIResource(APIResource):
7
+ @classmethod
8
+ def auto_paging_iter(cls, *args, **params):
9
+ return cls.list(*args, **params).auto_paging_iter()
10
+
11
+ @classmethod
12
+ def list(
13
+ cls,
14
+ api_key=None,
15
+ request_id=None,
16
+ api_version=None,
17
+ organization=None,
18
+ api_base=None,
19
+ api_type=None,
20
+ **params,
21
+ ):
22
+ requestor = api_requestor.APIRequestor(
23
+ api_key,
24
+ api_base=api_base or cls.api_base(),
25
+ api_version=api_version,
26
+ api_type=api_type,
27
+ organization=organization,
28
+ )
29
+
30
+ typed_api_type, api_version = cls._get_api_type_and_version(api_type, api_version)
31
+
32
+ if typed_api_type == ApiType.AZURE:
33
+ base = cls.class_url()
34
+ url = "/%s%s?api-version=%s" % (cls.azure_api_prefix, base, api_version)
35
+ elif typed_api_type == ApiType.OPEN_AI:
36
+ url = cls.class_url()
37
+ else:
38
+ raise error.InvalidAPIType('Unsupported API type %s' % api_type)
39
+
40
+ response, _, api_key = requestor.request(
41
+ "get", url, params, request_id=request_id
42
+ )
43
+ openai_object = util.convert_to_openai_object(
44
+ response, api_key, api_version, organization
45
+ )
46
+ openai_object._retrieve_params = params
47
+ return openai_object
openai/api_resources/abstract/nested_resource_class_methods.py ADDED
@@ -0,0 +1,102 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from urllib.parse import quote_plus
2
+
3
+ from openai import api_requestor, util
4
+
5
+
6
+ def nested_resource_class_methods(
7
+ resource, path=None, operations=None, resource_plural=None
8
+ ):
9
+ if resource_plural is None:
10
+ resource_plural = "%ss" % resource
11
+ if path is None:
12
+ path = resource_plural
13
+ if operations is None:
14
+ raise ValueError("operations list required")
15
+
16
+ def wrapper(cls):
17
+ def nested_resource_url(cls, id, nested_id=None):
18
+ url = "%s/%s/%s" % (cls.class_url(), quote_plus(id), quote_plus(path))
19
+ if nested_id is not None:
20
+ url += "/%s" % quote_plus(nested_id)
21
+ return url
22
+
23
+ resource_url_method = "%ss_url" % resource
24
+ setattr(cls, resource_url_method, classmethod(nested_resource_url))
25
+
26
+ def nested_resource_request(
27
+ cls,
28
+ method,
29
+ url,
30
+ api_key=None,
31
+ request_id=None,
32
+ api_version=None,
33
+ organization=None,
34
+ **params,
35
+ ):
36
+ requestor = api_requestor.APIRequestor(
37
+ api_key, api_version=api_version, organization=organization
38
+ )
39
+ response, _, api_key = requestor.request(
40
+ method, url, params, request_id=request_id
41
+ )
42
+ return util.convert_to_openai_object(
43
+ response, api_key, api_version, organization
44
+ )
45
+
46
+ resource_request_method = "%ss_request" % resource
47
+ setattr(cls, resource_request_method, classmethod(nested_resource_request))
48
+
49
+ for operation in operations:
50
+ if operation == "create":
51
+
52
+ def create_nested_resource(cls, id, **params):
53
+ url = getattr(cls, resource_url_method)(id)
54
+ return getattr(cls, resource_request_method)("post", url, **params)
55
+
56
+ create_method = "create_%s" % resource
57
+ setattr(cls, create_method, classmethod(create_nested_resource))
58
+
59
+ elif operation == "retrieve":
60
+
61
+ def retrieve_nested_resource(cls, id, nested_id, **params):
62
+ url = getattr(cls, resource_url_method)(id, nested_id)
63
+ return getattr(cls, resource_request_method)("get", url, **params)
64
+
65
+ retrieve_method = "retrieve_%s" % resource
66
+ setattr(cls, retrieve_method, classmethod(retrieve_nested_resource))
67
+
68
+ elif operation == "update":
69
+
70
+ def modify_nested_resource(cls, id, nested_id, **params):
71
+ url = getattr(cls, resource_url_method)(id, nested_id)
72
+ return getattr(cls, resource_request_method)("post", url, **params)
73
+
74
+ modify_method = "modify_%s" % resource
75
+ setattr(cls, modify_method, classmethod(modify_nested_resource))
76
+
77
+ elif operation == "delete":
78
+
79
+ def delete_nested_resource(cls, id, nested_id, **params):
80
+ url = getattr(cls, resource_url_method)(id, nested_id)
81
+ return getattr(cls, resource_request_method)(
82
+ "delete", url, **params
83
+ )
84
+
85
+ delete_method = "delete_%s" % resource
86
+ setattr(cls, delete_method, classmethod(delete_nested_resource))
87
+
88
+ elif operation == "list":
89
+
90
+ def list_nested_resources(cls, id, **params):
91
+ url = getattr(cls, resource_url_method)(id)
92
+ return getattr(cls, resource_request_method)("get", url, **params)
93
+
94
+ list_method = "list_%s" % resource_plural
95
+ setattr(cls, list_method, classmethod(list_nested_resources))
96
+
97
+ else:
98
+ raise ValueError("Unknown operation: %s" % operation)
99
+
100
+ return cls
101
+
102
+ return wrapper
openai/api_resources/abstract/updateable_api_resource.py ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ from urllib.parse import quote_plus
2
+
3
+ from openai.api_resources.abstract.api_resource import APIResource
4
+
5
+
6
+ class UpdateableAPIResource(APIResource):
7
+ @classmethod
8
+ def modify(cls, sid, **params):
9
+ url = "%s/%s" % (cls.class_url(), quote_plus(sid))
10
+ return cls._static_request("post", url, **params)
openai/api_resources/answer.py ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from openai.openai_object import OpenAIObject
2
+
3
+
4
+ class Answer(OpenAIObject):
5
+ @classmethod
6
+ def get_url(self):
7
+ return "/answers"
8
+
9
+ @classmethod
10
+ def create(cls, **params):
11
+ instance = cls()
12
+ return instance.request("post", cls.get_url(), params)
openai/api_resources/classification.py ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from openai.openai_object import OpenAIObject
2
+
3
+
4
+ class Classification(OpenAIObject):
5
+ @classmethod
6
+ def get_url(self):
7
+ return "/classifications"
8
+
9
+ @classmethod
10
+ def create(cls, **params):
11
+ instance = cls()
12
+ return instance.request("post", cls.get_url(), params)