openai/openai-python

Public

mirrored from https://github.com/openai/openai-pythonAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v1.13.0

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

README.md

553lines · modecode

1# OpenAI Python API library
2
3[![PyPI version](https://img.shields.io/pypi/v/openai.svg)](https://pypi.org/project/openai/)
4
5The OpenAI Python library provides convenient access to the OpenAI REST API from any Python 3.7+
6application. The library includes type definitions for all request params and response fields,
7and offers both synchronous and asynchronous clients powered by [httpx](https://github.com/encode/httpx).
8
9It is generated from our [OpenAPI specification](https://github.com/openai/openai-openapi) with [Stainless](https://stainlessapi.com/).
10
11## Documentation
12
13The REST API documentation can be found [on platform.openai.com](https://platform.openai.com/docs). The full API of this library can be found in [api.md](api.md).
14
15## Installation
16
17> [!IMPORTANT]
18> The SDK was rewritten in v1, which was released November 6th 2023. See the [v1 migration guide](https://github.com/openai/openai-python/discussions/742), which includes scripts to automatically update your code.
19
20```sh
21pip install openai
22```
23
24## Usage
25
26The full API of this library can be found in [api.md](api.md).
27
28```python
29import os
30from openai import OpenAI
31
32client = OpenAI(
33 # This is the default and can be omitted
34 api_key=os.environ.get("OPENAI_API_KEY"),
35)
36
37chat_completion = client.chat.completions.create(
38 messages=[
39 {
40 "role": "user",
41 "content": "Say this is a test",
42 }
43 ],
44 model="gpt-3.5-turbo",
45)
46```
47
48While you can provide an `api_key` keyword argument,
49we recommend using [python-dotenv](https://pypi.org/project/python-dotenv/)
50to add `OPENAI_API_KEY="My API Key"` to your `.env` file
51so that your API Key is not stored in source control.
52
53## Async usage
54
55Simply import `AsyncOpenAI` instead of `OpenAI` and use `await` with each API call:
56
57```python
58import os
59import asyncio
60from openai import AsyncOpenAI
61
62client = AsyncOpenAI(
63 # This is the default and can be omitted
64 api_key=os.environ.get("OPENAI_API_KEY"),
65)
66
67
68async def main() -> None:
69 chat_completion = await client.chat.completions.create(
70 messages=[
71 {
72 "role": "user",
73 "content": "Say this is a test",
74 }
75 ],
76 model="gpt-3.5-turbo",
77 )
78
79
80asyncio.run(main())
81```
82
83Functionality between the synchronous and asynchronous clients is otherwise identical.
84
85## Streaming Responses
86
87We provide support for streaming responses using Server Side Events (SSE).
88
89```python
90from openai import OpenAI
91
92client = OpenAI()
93
94stream = client.chat.completions.create(
95 model="gpt-4",
96 messages=[{"role": "user", "content": "Say this is a test"}],
97 stream=True,
98)
99for chunk in stream:
100 print(chunk.choices[0].delta.content or "", end="")
101```
102
103The async client uses the exact same interface.
104
105```python
106from openai import AsyncOpenAI
107
108client = AsyncOpenAI()
109
110
111async def main():
112 stream = await client.chat.completions.create(
113 model="gpt-4",
114 messages=[{"role": "user", "content": "Say this is a test"}],
115 stream=True,
116 )
117 async for chunk in stream:
118 print(chunk.choices[0].delta.content or "", end="")
119
120
121asyncio.run(main())
122```
123
124## Module-level client
125
126> [!IMPORTANT]
127> We highly recommend instantiating client instances instead of relying on the global client.
128
129We also expose a global client instance that is accessible in a similar fashion to versions prior to v1.
130
131```py
132import openai
133
134# optional; defaults to `os.environ['OPENAI_API_KEY']`
135openai.api_key = '...'
136
137# all client options can be configured just like the `OpenAI` instantiation counterpart
138openai.base_url = "https://..."
139openai.default_headers = {"x-foo": "true"}
140
141completion = openai.chat.completions.create(
142 model="gpt-4",
143 messages=[
144 {
145 "role": "user",
146 "content": "How do I output all files in a directory using Python?",
147 },
148 ],
149)
150print(completion.choices[0].message.content)
151```
152
153The API is the exact same as the standard client instance based API.
154
155This is intended to be used within REPLs or notebooks for faster iteration, **not** in application code.
156
157We recommend that you always instantiate a client (e.g., with `client = OpenAI()`) in application code because:
158
159- It can be difficult to reason about where client options are configured
160- It's not possible to change certain client options without potentially causing race conditions
161- It's harder to mock for testing purposes
162- It's not possible to control cleanup of network connections
163
164## Using types
165
166Nested request parameters are [TypedDicts](https://docs.python.org/3/library/typing.html#typing.TypedDict). Responses are [Pydantic models](https://docs.pydantic.dev), which provide helper methods for things like:
167
168- Serializing back into JSON, `model.model_dump_json(indent=2, exclude_unset=True)`
169- Converting to a dictionary, `model.model_dump(exclude_unset=True)`
170
171Typed requests and responses provide autocomplete and documentation within your editor. If you would like to see type errors in VS Code to help catch bugs earlier, set `python.analysis.typeCheckingMode` to `basic`.
172
173## Pagination
174
175List methods in the OpenAI API are paginated.
176
177This library provides auto-paginating iterators with each list response, so you do not have to request successive pages manually:
178
179```python
180import openai
181
182client = OpenAI()
183
184all_jobs = []
185# Automatically fetches more pages as needed.
186for job in client.fine_tuning.jobs.list(
187 limit=20,
188):
189 # Do something with job here
190 all_jobs.append(job)
191print(all_jobs)
192```
193
194Or, asynchronously:
195
196```python
197import asyncio
198import openai
199
200client = AsyncOpenAI()
201
202
203async def main() -> None:
204 all_jobs = []
205 # Iterate through items across all pages, issuing requests as needed.
206 async for job in client.fine_tuning.jobs.list(
207 limit=20,
208 ):
209 all_jobs.append(job)
210 print(all_jobs)
211
212
213asyncio.run(main())
214```
215
216Alternatively, you can use the `.has_next_page()`, `.next_page_info()`, or `.get_next_page()` methods for more granular control working with pages:
217
218```python
219first_page = await client.fine_tuning.jobs.list(
220 limit=20,
221)
222if first_page.has_next_page():
223 print(f"will fetch next page using these details: {first_page.next_page_info()}")
224 next_page = await first_page.get_next_page()
225 print(f"number of items we just fetched: {len(next_page.data)}")
226
227# Remove `await` for non-async usage.
228```
229
230Or just work directly with the returned data:
231
232```python
233first_page = await client.fine_tuning.jobs.list(
234 limit=20,
235)
236
237print(f"next page cursor: {first_page.after}") # => "next page cursor: ..."
238for job in first_page.data:
239 print(job.id)
240
241# Remove `await` for non-async usage.
242```
243
244## Nested params
245
246Nested parameters are dictionaries, typed using `TypedDict`, for example:
247
248```python
249from openai import OpenAI
250
251client = OpenAI()
252
253completion = client.chat.completions.create(
254 messages=[
255 {
256 "role": "user",
257 "content": "Can you generate an example json object describing a fruit?",
258 }
259 ],
260 model="gpt-3.5-turbo-1106",
261 response_format={"type": "json_object"},
262)
263```
264
265## File Uploads
266
267Request parameters that correspond to file uploads can be passed as `bytes`, a [`PathLike`](https://docs.python.org/3/library/os.html#os.PathLike) instance or a tuple of `(filename, contents, media type)`.
268
269```python
270from pathlib import Path
271from openai import OpenAI
272
273client = OpenAI()
274
275client.files.create(
276 file=Path("input.jsonl"),
277 purpose="fine-tune",
278)
279```
280
281The async client uses the exact same interface. If you pass a [`PathLike`](https://docs.python.org/3/library/os.html#os.PathLike) instance, the file contents will be read asynchronously automatically.
282
283## Handling errors
284
285When the library is unable to connect to the API (for example, due to network connection problems or a timeout), a subclass of `openai.APIConnectionError` is raised.
286
287When the API returns a non-success status code (that is, 4xx or 5xx
288response), a subclass of `openai.APIStatusError` is raised, containing `status_code` and `response` properties.
289
290All errors inherit from `openai.APIError`.
291
292```python
293import openai
294from openai import OpenAI
295
296client = OpenAI()
297
298try:
299 client.fine_tuning.jobs.create(
300 model="gpt-3.5-turbo",
301 training_file="file-abc123",
302 )
303except openai.APIConnectionError as e:
304 print("The server could not be reached")
305 print(e.__cause__) # an underlying Exception, likely raised within httpx.
306except openai.RateLimitError as e:
307 print("A 429 status code was received; we should back off a bit.")
308except openai.APIStatusError as e:
309 print("Another non-200-range status code was received")
310 print(e.status_code)
311 print(e.response)
312```
313
314Error codes are as followed:
315
316| Status Code | Error Type |
317| ----------- | -------------------------- |
318| 400 | `BadRequestError` |
319| 401 | `AuthenticationError` |
320| 403 | `PermissionDeniedError` |
321| 404 | `NotFoundError` |
322| 422 | `UnprocessableEntityError` |
323| 429 | `RateLimitError` |
324| >=500 | `InternalServerError` |
325| N/A | `APIConnectionError` |
326
327### Retries
328
329Certain errors are automatically retried 2 times by default, with a short exponential backoff.
330Connection errors (for example, due to a network connectivity problem), 408 Request Timeout, 409 Conflict,
331429 Rate Limit, and >=500 Internal errors are all retried by default.
332
333You can use the `max_retries` option to configure or disable retry settings:
334
335```python
336from openai import OpenAI
337
338# Configure the default for all requests:
339client = OpenAI(
340 # default is 2
341 max_retries=0,
342)
343
344# Or, configure per-request:
345client.with_options(max_retries=5).chat.completions.create(
346 messages=[
347 {
348 "role": "user",
349 "content": "How can I get the name of the current day in Node.js?",
350 }
351 ],
352 model="gpt-3.5-turbo",
353)
354```
355
356### Timeouts
357
358By default requests time out after 10 minutes. You can configure this with a `timeout` option,
359which accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/#fine-tuning-the-configuration) object:
360
361```python
362from openai import OpenAI
363
364# Configure the default for all requests:
365client = OpenAI(
366 # 20 seconds (default is 10 minutes)
367 timeout=20.0,
368)
369
370# More granular control:
371client = OpenAI(
372 timeout=httpx.Timeout(60.0, read=5.0, write=10.0, connect=2.0),
373)
374
375# Override per-request:
376client.with_options(timeout=5 * 1000).chat.completions.create(
377 messages=[
378 {
379 "role": "user",
380 "content": "How can I list all files in a directory using Python?",
381 }
382 ],
383 model="gpt-3.5-turbo",
384)
385```
386
387On timeout, an `APITimeoutError` is thrown.
388
389Note that requests that time out are [retried twice by default](#retries).
390
391## Advanced
392
393### Logging
394
395We use the standard library [`logging`](https://docs.python.org/3/library/logging.html) module.
396
397You can enable logging by setting the environment variable `OPENAI_LOG` to `debug`.
398
399```shell
400$ export OPENAI_LOG=debug
401```
402
403### How to tell whether `None` means `null` or missing
404
405In an API response, a field may be explicitly `null`, or missing entirely; in either case, its value is `None` in this library. You can differentiate the two cases with `.model_fields_set`:
406
407```py
408if response.my_field is None:
409 if 'my_field' not in response.model_fields_set:
410 print('Got json like {}, without a "my_field" key present at all.')
411 else:
412 print('Got json like {"my_field": null}.')
413```
414
415### Accessing raw response data (e.g. headers)
416
417The "raw" Response object can be accessed by prefixing `.with_raw_response.` to any HTTP method call, e.g.,
418
419```py
420from openai import OpenAI
421
422client = OpenAI()
423response = client.chat.completions.with_raw_response.create(
424 messages=[{
425 "role": "user",
426 "content": "Say this is a test",
427 }],
428 model="gpt-3.5-turbo",
429)
430print(response.headers.get('X-My-Header'))
431
432completion = response.parse() # get the object that `chat.completions.create()` would have returned
433print(completion)
434```
435
436These methods return an [`LegacyAPIResponse`](https://github.com/openai/openai-python/tree/main/src/openai/_legacy_response.py) object. This is a legacy class as we're changing it slightly in the next major version.
437
438For the sync client this will mostly be the same with the exception
439of `content` & `text` will be methods instead of properties. In the
440async client, all methods will be async.
441
442A migration script will be provided & the migration in general should
443be smooth.
444
445#### `.with_streaming_response`
446
447The above interface eagerly reads the full response body when you make the request, which may not always be what you want.
448
449To stream the response body, use `.with_streaming_response` instead, which requires a context manager and only reads the response body once you call `.read()`, `.text()`, `.json()`, `.iter_bytes()`, `.iter_text()`, `.iter_lines()` or `.parse()`. In the async client, these are async methods.
450
451As such, `.with_streaming_response` methods return a different [`APIResponse`](https://github.com/openai/openai-python/tree/main/src/openai/_response.py) object, and the async client returns an [`AsyncAPIResponse`](https://github.com/openai/openai-python/tree/main/src/openai/_response.py) object.
452
453```python
454with client.chat.completions.with_streaming_response.create(
455 messages=[
456 {
457 "role": "user",
458 "content": "Say this is a test",
459 }
460 ],
461 model="gpt-3.5-turbo",
462) as response:
463 print(response.headers.get("X-My-Header"))
464
465 for line in response.iter_lines():
466 print(line)
467```
468
469The context manager is required so that the response will reliably be closed.
470
471### Configuring the HTTP client
472
473You can directly override the [httpx client](https://www.python-httpx.org/api/#client) to customize it for your use case, including:
474
475- Support for proxies
476- Custom transports
477- Additional [advanced](https://www.python-httpx.org/advanced/#client-instances) functionality
478
479```python
480import httpx
481from openai import OpenAI
482
483client = OpenAI(
484 # Or use the `OPENAI_BASE_URL` env var
485 base_url="http://my.test.server.example.com:8083",
486 http_client=httpx.Client(
487 proxies="http://my.test.proxy.example.com",
488 transport=httpx.HTTPTransport(local_address="0.0.0.0"),
489 ),
490)
491```
492
493### Managing HTTP resources
494
495By default the library closes underlying HTTP connections whenever the client is [garbage collected](https://docs.python.org/3/reference/datamodel.html#object.__del__). You can manually close the client using the `.close()` method if desired, or with a context manager that closes when exiting.
496
497## Microsoft Azure OpenAI
498
499To use this library with [Azure OpenAI](https://learn.microsoft.com/en-us/azure/ai-services/openai/overview), use the `AzureOpenAI`
500class instead of the `OpenAI` class.
501
502> [!IMPORTANT]
503> The Azure API shape differs from the core API shape which means that the static types for responses / params
504> won't always be correct.
505
506```py
507from openai import AzureOpenAI
508
509# gets the API Key from environment variable AZURE_OPENAI_API_KEY
510client = AzureOpenAI(
511 # https://learn.microsoft.com/en-us/azure/ai-services/openai/reference#rest-api-versioning
512 api_version="2023-07-01-preview",
513 # https://learn.microsoft.com/en-us/azure/cognitive-services/openai/how-to/create-resource?pivots=web-portal#create-a-resource
514 azure_endpoint="https://example-endpoint.openai.azure.com",
515)
516
517completion = client.chat.completions.create(
518 model="deployment-name", # e.g. gpt-35-instant
519 messages=[
520 {
521 "role": "user",
522 "content": "How do I output all files in a directory using Python?",
523 },
524 ],
525)
526print(completion.model_dump_json(indent=2))
527```
528
529In addition to the options provided in the base `OpenAI` client, the following options are provided:
530
531- `azure_endpoint` (or the `AZURE_OPENAI_ENDPOINT` environment variable)
532- `azure_deployment`
533- `api_version` (or the `OPENAI_API_VERSION` environment variable)
534- `azure_ad_token` (or the `AZURE_OPENAI_AD_TOKEN` environment variable)
535- `azure_ad_token_provider`
536
537An example of using the client with Azure Active Directory can be found [here](https://github.com/openai/openai-python/blob/main/examples/azure_ad.py).
538
539## Versioning
540
541This package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions:
542
5431. Changes that only affect static types, without breaking runtime behavior.
5442. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals)_.
5453. Changes that we do not expect to impact the vast majority of users in practice.
546
547We take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience.
548
549We are keen for your feedback; please open an [issue](https://www.github.com/openai/openai-python/issues) with questions, bugs, or suggestions.
550
551## Requirements
552
553Python 3.7 or higher.
554