openai/openai-python

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v1.61.0

Branches

Tags

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

Clone

HTTPS

Download ZIP

README.md

811lines · modeblame

08b8179aDavid Schnurr2 years ago1# OpenAI Python API library
3c6d4cd6Greg Brockman5 years ago2
08b8179aDavid Schnurr2 years ago3[![PyPI version](https://img.shields.io/pypi/v/openai.svg)](https://pypi.org/project/openai/)
3c6d4cd6Greg Brockman5 years ago4
cb88c2f0stainless-app[bot]1 years ago5The OpenAI Python library provides convenient access to the OpenAI REST API from any Python 3.8+
08b8179aDavid Schnurr2 years ago6application. 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
2e8ea52bstainless-app[bot]1 years ago13The 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).
3c6d4cd6Greg Brockman5 years ago14
15## Installation
16
448ac7d0Stainless Bot2 years ago17> [!IMPORTANT]
db6cd764Stainless Bot2 years ago18> 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.
448ac7d0Stainless Bot2 years ago19
3c6d4cd6Greg Brockman5 years ago20```sh
1879c97aStainless Bot2 years ago21# install from PyPI
6d217096Robert Craigie2 years ago22pip install openai
3c6d4cd6Greg Brockman5 years ago23```
24
08b8179aDavid Schnurr2 years ago25## Usage
26
986f3128Stainless Bot2 years ago27The full API of this library can be found in [api.md](api.md).
376dd199Logan Kilpatrick2 years ago28
29```python
fb5ba01cStainless Bot2 years ago30import os
08b8179aDavid Schnurr2 years ago31from openai import OpenAI
32
33client = OpenAI(
6c6dfb19stainless-app[bot]1 years ago34api_key=os.environ.get("OPENAI_API_KEY"), # This is the default and can be omitted
08b8179aDavid Schnurr2 years ago35)
36
37chat_completion = client.chat.completions.create(
38messages=[
39{
40"role": "user",
41"content": "Say this is a test",
42}
43],
23444ed9Stainless Bot1 years ago44model="gpt-4o",
08b8179aDavid Schnurr2 years ago45)
376dd199Logan Kilpatrick2 years ago46```
47
08b8179aDavid Schnurr2 years ago48While 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.
3c6d4cd6Greg Brockman5 years ago52
192b8f2bDan Corin1 years ago53### Vision
54
55With a hosted image:
56
57```python
58response = client.chat.completions.create(
59model="gpt-4o-mini",
60messages=[
61{
62"role": "user",
63"content": [
64{"type": "text", "text": prompt},
65{
66"type": "image_url",
67"image_url": {"url": f"{img_url}"},
68},
69],
70}
71],
72)
73```
74
75With the image as a base64 encoded string:
76
77```python
78response = client.chat.completions.create(
79model="gpt-4o-mini",
80messages=[
81{
82"role": "user",
83"content": [
84{"type": "text", "text": prompt},
85{
86"type": "image_url",
87"image_url": {"url": f"data:{img_type};base64,{img_b64_str}"},
88},
89],
90}
91],
92)
93```
94
595f3b36Stainless Bot2 years ago95### Polling Helpers
96
5b20698dStainless Bot2 years ago97When interacting with the API some actions such as starting a Run and adding files to vector stores are asynchronous and take time to complete. The SDK includes
595f3b36Stainless Bot2 years ago98helper functions which will poll the status until it reaches a terminal state and then return the resulting object.
137f38baNino Risteski2 years ago99If an API method results in an action that could benefit from polling there will be a corresponding version of the
595f3b36Stainless Bot2 years ago100method ending in '\_and_poll'.
101
102For instance to create a Run and poll until it reaches a terminal state you can run:
103
104```python
105run = client.beta.threads.runs.create_and_poll(
106thread_id=thread.id,
107assistant_id=assistant.id,
108)
109```
110
111More information on the lifecycle of a Run can be found in the [Run Lifecycle Documentation](https://platform.openai.com/docs/assistants/how-it-works/run-lifecycle)
112
5b20698dStainless Bot2 years ago113### Bulk Upload Helpers
114
137f38baNino Risteski2 years ago115When creating and interacting with vector stores, you can use polling helpers to monitor the status of operations.
5b20698dStainless Bot2 years ago116For convenience, we also provide a bulk upload helper to allow you to simultaneously upload several files at once.
117
118```python
119sample_files = [Path("sample-paper.pdf"), ...]
120
121batch = await client.vector_stores.file_batches.upload_and_poll(
122store.id,
123files=sample_files,
124)
125```
126
5cfb125aStainless Bot2 years ago127### Streaming Helpers
128
137f38baNino Risteski2 years ago129The SDK also includes helpers to process streams and handle incoming events.
5cfb125aStainless Bot2 years ago130
131```python
595f3b36Stainless Bot2 years ago132with client.beta.threads.runs.stream(
5cfb125aStainless Bot2 years ago133thread_id=thread.id,
134assistant_id=assistant.id,
135instructions="Please address the user as Jane Doe. The user has a premium account.",
136) as stream:
137for event in stream:
138# Print the text from text delta events
139if event.type == "thread.message.delta" and event.data.delta.content:
140print(event.data.delta.content[0].text)
141```
142
143More information on streaming helpers can be found in the dedicated documentation: [helpers.md](helpers.md)
144
08b8179aDavid Schnurr2 years ago145## Async usage
3c6d4cd6Greg Brockman5 years ago146
08b8179aDavid Schnurr2 years ago147Simply import `AsyncOpenAI` instead of `OpenAI` and use `await` with each API call:
ede08829Jakub Roztocil3 years ago148
08b8179aDavid Schnurr2 years ago149```python
fb5ba01cStainless Bot2 years ago150import os
08b8179aDavid Schnurr2 years ago151import asyncio
152from openai import AsyncOpenAI
ede08829Jakub Roztocil3 years ago153
08b8179aDavid Schnurr2 years ago154client = AsyncOpenAI(
6c6dfb19stainless-app[bot]1 years ago155api_key=os.environ.get("OPENAI_API_KEY"), # This is the default and can be omitted
08b8179aDavid Schnurr2 years ago156)
ede08829Jakub Roztocil3 years ago157
158
08b8179aDavid Schnurr2 years ago159async def main() -> None:
160chat_completion = await client.chat.completions.create(
161messages=[
162{
163"role": "user",
164"content": "Say this is a test",
165}
166],
23444ed9Stainless Bot1 years ago167model="gpt-4o",
08b8179aDavid Schnurr2 years ago168)
ede08829Jakub Roztocil3 years ago169
170
08b8179aDavid Schnurr2 years ago171asyncio.run(main())
2b21516eAtty Eleti3 years ago172```
ede08829Jakub Roztocil3 years ago173
08b8179aDavid Schnurr2 years ago174Functionality between the synchronous and asynchronous clients is otherwise identical.
175
2b23eb53Stainless Bot2 years ago176## Streaming responses
08b8179aDavid Schnurr2 years ago177
178We provide support for streaming responses using Server Side Events (SSE).
d53d9efbRachel Lim5 years ago179
08b8179aDavid Schnurr2 years ago180```python
181from openai import OpenAI
182
183client = OpenAI()
d53d9efbRachel Lim5 years ago184
08b8179aDavid Schnurr2 years ago185stream = client.chat.completions.create(
23444ed9Stainless Bot1 years ago186messages=[
187{
188"role": "user",
189"content": "Say this is a test",
190}
191],
192model="gpt-4o",
08b8179aDavid Schnurr2 years ago193stream=True,
194)
54c7c512Stainless Bot2 years ago195for chunk in stream:
a3da0196Stainless Bot2 years ago196print(chunk.choices[0].delta.content or "", end="")
d53d9efbRachel Lim5 years ago197```
198
08b8179aDavid Schnurr2 years ago199The async client uses the exact same interface.
d53d9efbRachel Lim5 years ago200
201```python
db0aa22cAdel Basli1 years ago202import asyncio
08b8179aDavid Schnurr2 years ago203from openai import AsyncOpenAI
204
205client = AsyncOpenAI()
206
a3da0196Stainless Bot2 years ago207
dfe1c8daSahand Sojoodi2 years ago208async def main():
209stream = await client.chat.completions.create(
210model="gpt-4",
211messages=[{"role": "user", "content": "Say this is a test"}],
212stream=True,
213)
214async for chunk in stream:
a3da0196Stainless Bot2 years ago215print(chunk.choices[0].delta.content or "", end="")
216
dfe1c8daSahand Sojoodi2 years ago217
218asyncio.run(main())
53e5ba4bt-asutedjo4 years ago219```
2b21516eAtty Eleti3 years ago220
08b8179aDavid Schnurr2 years ago221## Module-level client
d53d9efbRachel Lim5 years ago222
08b8179aDavid Schnurr2 years ago223> [!IMPORTANT]
224> We highly recommend instantiating client instances instead of relying on the global client.
d53d9efbRachel Lim5 years ago225
08b8179aDavid Schnurr2 years ago226We also expose a global client instance that is accessible in a similar fashion to versions prior to v1.
6572ef4fZheNing Hu3 years ago227
08b8179aDavid Schnurr2 years ago228```py
229import openai
62b73b9bAtty Eleti3 years ago230
08b8179aDavid Schnurr2 years ago231# optional; defaults to `os.environ['OPENAI_API_KEY']`
232openai.api_key = '...'
233
234# all client options can be configured just like the `OpenAI` instantiation counterpart
235openai.base_url = "https://..."
236openai.default_headers = {"x-foo": "true"}
237
238completion = openai.chat.completions.create(
23444ed9Stainless Bot1 years ago239model="gpt-4o",
08b8179aDavid Schnurr2 years ago240messages=[
241{
242"role": "user",
243"content": "How do I output all files in a directory using Python?",
244},
245],
246)
62b73b9bAtty Eleti3 years ago247print(completion.choices[0].message.content)
248```
249
137f38baNino Risteski2 years ago250The API is the exact same as the standard client instance-based API.
376dd199Logan Kilpatrick2 years ago251
08b8179aDavid Schnurr2 years ago252This is intended to be used within REPLs or notebooks for faster iteration, **not** in application code.
2b21516eAtty Eleti3 years ago253
08b8179aDavid Schnurr2 years ago254We recommend that you always instantiate a client (e.g., with `client = OpenAI()`) in application code because:
2b21516eAtty Eleti3 years ago255
08b8179aDavid Schnurr2 years ago256- It can be difficult to reason about where client options are configured
257- It's not possible to change certain client options without potentially causing race conditions
258- It's harder to mock for testing purposes
259- It's not possible to control cleanup of network connections
260
488ec04bRobert Craigie1 years ago261## Realtime API beta
262
263The Realtime API enables you to build low-latency, multi-modal conversational experiences. It currently supports text and audio as both input and output, as well as [function calling](https://platform.openai.com/docs/guides/function-calling) through a WebSocket connection.
264
265Under the hood the SDK uses the [`websockets`](https://websockets.readthedocs.io/en/stable/) library to manage connections.
266
255677d7Robert Craigie1 years ago267The Realtime API works through a combination of client-sent events and server-sent events. Clients can send events to do things like update session configuration or send text and audio inputs. Server events confirm when audio responses have completed, or when a text response from the model has been received. A full event reference can be found [here](https://platform.openai.com/docs/api-reference/realtime-client-events) and a guide can be found [here](https://platform.openai.com/docs/guides/realtime).
488ec04bRobert Craigie1 years ago268
269Basic text based example:
270
271```py
272import asyncio
273from openai import AsyncOpenAI
274
275async def main():
276client = AsyncOpenAI()
277
fd763424Robert Craigie1 years ago278async with client.beta.realtime.connect(model="gpt-4o-realtime-preview") as connection:
488ec04bRobert Craigie1 years ago279await connection.session.update(session={'modalities': ['text']})
280
281await connection.conversation.item.create(
282item={
283"type": "message",
284"role": "user",
285"content": [{"type": "input_text", "text": "Say hello!"}],
286}
287)
288await connection.response.create()
289
290async for event in connection:
291if event.type == 'response.text.delta':
292print(event.delta, flush=True, end="")
293
294elif event.type == 'response.text.done':
295print()
296
297elif event.type == "response.done":
298break
299
300asyncio.run(main())
301```
302
6935dfdcRobert Craigie1 years ago303However the real magic of the Realtime API is handling audio inputs / outputs, see this example [TUI script](https://github.com/openai/openai-python/blob/main/examples/realtime/push_to_talk_app.py) for a fully fledged example.
488ec04bRobert Craigie1 years ago304
305### Realtime error handling
306
90e3d396Guspan Tanadi1 years ago307Whenever an error occurs, the Realtime API will send an [`error` event](https://platform.openai.com/docs/guides/realtime-model-capabilities#error-handling) and the connection will stay open and remain usable. This means you need to handle it yourself, as *no errors are raised directly* by the SDK when an `error` event comes in.
488ec04bRobert Craigie1 years ago308
309```py
310client = AsyncOpenAI()
311
fd763424Robert Craigie1 years ago312async with client.beta.realtime.connect(model="gpt-4o-realtime-preview") as connection:
488ec04bRobert Craigie1 years ago313...
314async for event in connection:
315if event.type == 'error':
316print(event.error.type)
317print(event.error.code)
318print(event.error.event_id)
319print(event.error.message)
320```
321
08b8179aDavid Schnurr2 years ago322## Using types
323
47656567Stainless Bot2 years ago324Nested request parameters are [TypedDicts](https://docs.python.org/3/library/typing.html#typing.TypedDict). Responses are [Pydantic models](https://docs.pydantic.dev) which also provide helper methods for things like:
f4b9655fStainless Bot2 years ago325
47656567Stainless Bot2 years ago326- Serializing back into JSON, `model.to_json()`
327- Converting to a dictionary, `model.to_dict()`
2b21516eAtty Eleti3 years ago328
08b8179aDavid Schnurr2 years ago329Typed 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`.
0e21703eTed Sanders4 years ago330
08b8179aDavid Schnurr2 years ago331## Pagination
0e21703eTed Sanders4 years ago332
08b8179aDavid Schnurr2 years ago333List methods in the OpenAI API are paginated.
334
335This library provides auto-paginating iterators with each list response, so you do not have to request successive pages manually:
0e21703eTed Sanders4 years ago336
337```python
ff5add01stainless-app[bot]1 years ago338from openai import OpenAI
0e21703eTed Sanders4 years ago339
08b8179aDavid Schnurr2 years ago340client = OpenAI()
0e21703eTed Sanders4 years ago341
08b8179aDavid Schnurr2 years ago342all_jobs = []
343# Automatically fetches more pages as needed.
344for job in client.fine_tuning.jobs.list(
345limit=20,
346):
347# Do something with job here
348all_jobs.append(job)
349print(all_jobs)
0e21703eTed Sanders4 years ago350```
351
08b8179aDavid Schnurr2 years ago352Or, asynchronously:
0e21703eTed Sanders4 years ago353
08b8179aDavid Schnurr2 years ago354```python
355import asyncio
ff5add01stainless-app[bot]1 years ago356from openai import AsyncOpenAI
0e21703eTed Sanders4 years ago357
08b8179aDavid Schnurr2 years ago358client = AsyncOpenAI()
0e21703eTed Sanders4 years ago359
360
08b8179aDavid Schnurr2 years ago361async def main() -> None:
362all_jobs = []
363# Iterate through items across all pages, issuing requests as needed.
364async for job in client.fine_tuning.jobs.list(
365limit=20,
366):
367all_jobs.append(job)
368print(all_jobs)
0e21703eTed Sanders4 years ago369
62b51ca0Boris Dayma4 years ago370
08b8179aDavid Schnurr2 years ago371asyncio.run(main())
372```
2942bf4bLogan Kilpatrick2 years ago373
08b8179aDavid Schnurr2 years ago374Alternatively, you can use the `.has_next_page()`, `.next_page_info()`, or `.get_next_page()` methods for more granular control working with pages:
2942bf4bLogan Kilpatrick2 years ago375
08b8179aDavid Schnurr2 years ago376```python
377first_page = await client.fine_tuning.jobs.list(
378limit=20,
379)
380if first_page.has_next_page():
381print(f"will fetch next page using these details: {first_page.next_page_info()}")
382next_page = await first_page.get_next_page()
383print(f"number of items we just fetched: {len(next_page.data)}")
384
385# Remove `await` for non-async usage.
62b51ca0Boris Dayma4 years ago386```
387
08b8179aDavid Schnurr2 years ago388Or just work directly with the returned data:
0e21703eTed Sanders4 years ago389
08b8179aDavid Schnurr2 years ago390```python
391first_page = await client.fine_tuning.jobs.list(
392limit=20,
393)
e389823bMorgan McGuire2 years ago394
08b8179aDavid Schnurr2 years ago395print(f"next page cursor: {first_page.after}") # => "next page cursor: ..."
396for job in first_page.data:
397print(job.id)
e389823bMorgan McGuire2 years ago398
08b8179aDavid Schnurr2 years ago399# Remove `await` for non-async usage.
400```
e389823bMorgan McGuire2 years ago401
08b8179aDavid Schnurr2 years ago402## Nested params
3c00e856hallacy3 years ago403
08b8179aDavid Schnurr2 years ago404Nested parameters are dictionaries, typed using `TypedDict`, for example:
3c00e856hallacy3 years ago405
406```python
08b8179aDavid Schnurr2 years ago407from openai import OpenAI
3c00e856hallacy3 years ago408
08b8179aDavid Schnurr2 years ago409client = OpenAI()
410
aa681899Stainless Bot2 years ago411completion = client.chat.completions.create(
412messages=[
413{
414"role": "user",
415"content": "Can you generate an example json object describing a fruit?",
416}
417],
23444ed9Stainless Bot1 years ago418model="gpt-4o",
aa681899Stainless Bot2 years ago419response_format={"type": "json_object"},
420)
08b8179aDavid Schnurr2 years ago421```
3c00e856hallacy3 years ago422
2b23eb53Stainless Bot2 years ago423## File uploads
dc33cb9dMichelle Pokrass3 years ago424
08b8179aDavid Schnurr2 years ago425Request 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)`.
dc33cb9dMichelle Pokrass3 years ago426
376dd199Logan Kilpatrick2 years ago427```python
08b8179aDavid Schnurr2 years ago428from pathlib import Path
429from openai import OpenAI
430
431client = OpenAI()
432
433client.files.create(
434file=Path("input.jsonl"),
435purpose="fine-tune",
436)
dc33cb9dMichelle Pokrass3 years ago437```
438
08b8179aDavid Schnurr2 years ago439The 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.
376dd199Logan Kilpatrick2 years ago440
08b8179aDavid Schnurr2 years ago441## Handling errors
376dd199Logan Kilpatrick2 years ago442
08b8179aDavid Schnurr2 years ago443When 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.
2b21516eAtty Eleti3 years ago444
08b8179aDavid Schnurr2 years ago445When the API returns a non-success status code (that is, 4xx or 5xx
446response), a subclass of `openai.APIStatusError` is raised, containing `status_code` and `response` properties.
62b73b9bAtty Eleti3 years ago447
08b8179aDavid Schnurr2 years ago448All errors inherit from `openai.APIError`.
449
450```python
451import openai
452from openai import OpenAI
453
454client = OpenAI()
455
456try:
8dab1421Stainless Bot2 years ago457client.fine_tuning.jobs.create(
23444ed9Stainless Bot1 years ago458model="gpt-4o",
8dab1421Stainless Bot2 years ago459training_file="file-abc123",
08b8179aDavid Schnurr2 years ago460)
461except openai.APIConnectionError as e:
462print("The server could not be reached")
463print(e.__cause__) # an underlying Exception, likely raised within httpx.
464except openai.RateLimitError as e:
465print("A 429 status code was received; we should back off a bit.")
466except openai.APIStatusError as e:
467print("Another non-200-range status code was received")
468print(e.status_code)
469print(e.response)
62b73b9bAtty Eleti3 years ago470```
471
fee9c81bstainless-app[bot]1 years ago472Error codes are as follows:
08b8179aDavid Schnurr2 years ago473
474| Status Code | Error Type |
475| ----------- | -------------------------- |
476| 400 | `BadRequestError` |
477| 401 | `AuthenticationError` |
478| 403 | `PermissionDeniedError` |
479| 404 | `NotFoundError` |
480| 422 | `UnprocessableEntityError` |
481| 429 | `RateLimitError` |
482| >=500 | `InternalServerError` |
483| N/A | `APIConnectionError` |
484
4b302346Robert Craigie1 years ago485## Request IDs
486
487> For more information on debugging requests, see [these docs](https://platform.openai.com/docs/api-reference/debugging-requests)
488
489All object responses in the SDK provide a `_request_id` property which is added from the `x-request-id` response header so that you can quickly log failing requests and report them back to OpenAI.
490
491```python
492completion = await client.chat.completions.create(
493messages=[{"role": "user", "content": "Say this is a test"}], model="gpt-4"
494)
495print(completion._request_id) # req_123
496```
497
498Note that unlike other properties that use an `_` prefix, the `_request_id` property
499*is* public. Unless documented otherwise, *all* other `_` prefix properties,
500methods and modules are *private*.
501
709926ffRobert Craigie1 years ago502> [!IMPORTANT]
503> If you need to access request IDs for failed requests you must catch the `APIStatusError` exception
504
505```python
506import openai
507
508try:
509completion = await client.chat.completions.create(
510messages=[{"role": "user", "content": "Say this is a test"}], model="gpt-4"
511)
512except openai.APIStatusError as exc:
513print(exc.request_id) # req_123
514raise exc
515```
516
4b302346Robert Craigie1 years ago517
08b8179aDavid Schnurr2 years ago518### Retries
376dd199Logan Kilpatrick2 years ago519
08b8179aDavid Schnurr2 years ago520Certain errors are automatically retried 2 times by default, with a short exponential backoff.
521Connection errors (for example, due to a network connectivity problem), 408 Request Timeout, 409 Conflict,
522429 Rate Limit, and >=500 Internal errors are all retried by default.
0abf6413Andrew Chen Wang3 years ago523
08b8179aDavid Schnurr2 years ago524You can use the `max_retries` option to configure or disable retry settings:
0abf6413Andrew Chen Wang3 years ago525
526```python
08b8179aDavid Schnurr2 years ago527from openai import OpenAI
528
529# Configure the default for all requests:
530client = OpenAI(
531# default is 2
532max_retries=0,
533)
534
535# Or, configure per-request:
536client.with_options(max_retries=5).chat.completions.create(
537messages=[
538{
539"role": "user",
23444ed9Stainless Bot1 years ago540"content": "How can I get the name of the current day in JavaScript?",
08b8179aDavid Schnurr2 years ago541}
542],
23444ed9Stainless Bot1 years ago543model="gpt-4o",
08b8179aDavid Schnurr2 years ago544)
0abf6413Andrew Chen Wang3 years ago545```
546
08b8179aDavid Schnurr2 years ago547### Timeouts
0abf6413Andrew Chen Wang3 years ago548
08b8179aDavid Schnurr2 years ago549By default requests time out after 10 minutes. You can configure this with a `timeout` option,
90e3d396Guspan Tanadi1 years ago550which accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/timeouts/#fine-tuning-the-configuration) object:
376dd199Logan Kilpatrick2 years ago551
08b8179aDavid Schnurr2 years ago552```python
553from openai import OpenAI
554
555# Configure the default for all requests:
556client = OpenAI(
1381f46eStainless Bot2 years ago557# 20 seconds (default is 10 minutes)
08b8179aDavid Schnurr2 years ago558timeout=20.0,
559)
560
561# More granular control:
562client = OpenAI(
563timeout=httpx.Timeout(60.0, read=5.0, write=10.0, connect=2.0),
564)
565
566# Override per-request:
2a678e30Stainless Bot2 years ago567client.with_options(timeout=5.0).chat.completions.create(
08b8179aDavid Schnurr2 years ago568messages=[
569{
570"role": "user",
571"content": "How can I list all files in a directory using Python?",
572}
573],
23444ed9Stainless Bot1 years ago574model="gpt-4o",
08b8179aDavid Schnurr2 years ago575)
0abf6413Andrew Chen Wang3 years ago576```
577
08b8179aDavid Schnurr2 years ago578On timeout, an `APITimeoutError` is thrown.
376dd199Logan Kilpatrick2 years ago579
08b8179aDavid Schnurr2 years ago580Note that requests that time out are [retried twice by default](#retries).
376dd199Logan Kilpatrick2 years ago581
08b8179aDavid Schnurr2 years ago582## Advanced
376dd199Logan Kilpatrick2 years ago583
08b8179aDavid Schnurr2 years ago584### Logging
376dd199Logan Kilpatrick2 years ago585
08b8179aDavid Schnurr2 years ago586We use the standard library [`logging`](https://docs.python.org/3/library/logging.html) module.
376dd199Logan Kilpatrick2 years ago587
f6199d60stainless-app[bot]1 years ago588You can enable logging by setting the environment variable `OPENAI_LOG` to `info`.
376dd199Logan Kilpatrick2 years ago589
08b8179aDavid Schnurr2 years ago590```shell
f6199d60stainless-app[bot]1 years ago591$ export OPENAI_LOG=info
376dd199Logan Kilpatrick2 years ago592```
593
f6199d60stainless-app[bot]1 years ago594Or to `debug` for more verbose logging.
595
08b8179aDavid Schnurr2 years ago596### How to tell whether `None` means `null` or missing
dc33cb9dMichelle Pokrass3 years ago597
08b8179aDavid Schnurr2 years ago598In 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`:
3c6d4cd6Greg Brockman5 years ago599
08b8179aDavid Schnurr2 years ago600```py
601if response.my_field is None:
602if 'my_field' not in response.model_fields_set:
603print('Got json like {}, without a "my_field" key present at all.')
604else:
605print('Got json like {"my_field": null}.')
606```
376dd199Logan Kilpatrick2 years ago607
08b8179aDavid Schnurr2 years ago608### Accessing raw response data (e.g. headers)
376dd199Logan Kilpatrick2 years ago609
86379b44Stainless Bot2 years ago610The "raw" Response object can be accessed by prefixing `.with_raw_response.` to any HTTP method call, e.g.,
08b8179aDavid Schnurr2 years ago611
612```py
613from openai import OpenAI
614
615client = OpenAI()
616response = client.chat.completions.with_raw_response.create(
617messages=[{
618"role": "user",
619"content": "Say this is a test",
620}],
23444ed9Stainless Bot1 years ago621model="gpt-4o",
08b8179aDavid Schnurr2 years ago622)
623print(response.headers.get('X-My-Header'))
624
625completion = response.parse() # get the object that `chat.completions.create()` would have returned
626print(completion)
376dd199Logan Kilpatrick2 years ago627```
628
16315f22stainless-app[bot]1 years ago629These methods return a [`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.
86379b44Stainless Bot2 years ago630
631For the sync client this will mostly be the same with the exception
632of `content` & `text` will be methods instead of properties. In the
633async client, all methods will be async.
634
635A migration script will be provided & the migration in general should
636be smooth.
637
638#### `.with_streaming_response`
639
640The above interface eagerly reads the full response body when you make the request, which may not always be what you want.
641
642To 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.
643
644As 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.
645
646```python
647with client.chat.completions.with_streaming_response.create(
648messages=[
649{
650"role": "user",
651"content": "Say this is a test",
652}
653],
23444ed9Stainless Bot1 years ago654model="gpt-4o",
86379b44Stainless Bot2 years ago655) as response:
656print(response.headers.get("X-My-Header"))
657
658for line in response.iter_lines():
659print(line)
660```
661
662The context manager is required so that the response will reliably be closed.
3c6d4cd6Greg Brockman5 years ago663
73869eeeStainless Bot2 years ago664### Making custom/undocumented requests
665
7931ebaaStainless Bot2 years ago666This library is typed for convenient access to the documented API.
73869eeeStainless Bot2 years ago667
668If you need to access undocumented endpoints, params, or response properties, the library can still be used.
669
670#### Undocumented endpoints
671
672To make requests to undocumented endpoints, you can make requests using `client.get`, `client.post`, and other
fee9c81bstainless-app[bot]1 years ago673http verbs. Options on the client will be respected (such as retries) when making this request.
73869eeeStainless Bot2 years ago674
675```py
676import httpx
677
678response = client.post(
679"/foo",
680cast_to=httpx.Response,
681body={"my_param": True},
682)
683
684print(response.headers.get("x-foo"))
685```
686
802819c8Stainless Bot2 years ago687#### Undocumented request params
73869eeeStainless Bot2 years ago688
689If you want to explicitly send an extra param, you can do so with the `extra_query`, `extra_body`, and `extra_headers` request
690options.
691
802819c8Stainless Bot2 years ago692#### Undocumented response properties
73869eeeStainless Bot2 years ago693
694To access undocumented response properties, you can access the extra fields like `response.unknown_prop`. You
695can also get all the extra fields on the Pydantic model as a dict with
696[`response.model_extra`](https://docs.pydantic.dev/latest/api/base_model/#pydantic.BaseModel.model_extra).
697
08b8179aDavid Schnurr2 years ago698### Configuring the HTTP client
376dd199Logan Kilpatrick2 years ago699
08b8179aDavid Schnurr2 years ago700You can directly override the [httpx client](https://www.python-httpx.org/api/#client) to customize it for your use case, including:
376dd199Logan Kilpatrick2 years ago701
6a1ab551stainless-app[bot]1 years ago702- Support for [proxies](https://www.python-httpx.org/advanced/proxies/)
703- Custom [transports](https://www.python-httpx.org/advanced/transports/)
d3254d12stainless-app[bot]2 years ago704- Additional [advanced](https://www.python-httpx.org/advanced/clients/) functionality
376dd199Logan Kilpatrick2 years ago705
706```python
6a1ab551stainless-app[bot]1 years ago707import httpx
347363edStainless Bot2 years ago708from openai import OpenAI, DefaultHttpxClient
08b8179aDavid Schnurr2 years ago709
710client = OpenAI(
0733934fStainless Bot2 years ago711# Or use the `OPENAI_BASE_URL` env var
38dd5348Adrian Cole1 years ago712base_url="http://my.test.server.example.com:8083/v1",
347363edStainless Bot2 years ago713http_client=DefaultHttpxClient(
6a1ab551stainless-app[bot]1 years ago714proxy="http://my.test.proxy.example.com",
08b8179aDavid Schnurr2 years ago715transport=httpx.HTTPTransport(local_address="0.0.0.0"),
716),
717)
718```
719
f8f01a61stainless-app[bot]1 years ago720You can also customize the client on a per-request basis by using `with_options()`:
721
722```python
723client.with_options(http_client=DefaultHttpxClient(...))
724```
725
08b8179aDavid Schnurr2 years ago726### Managing HTTP resources
727
728By 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.
729
588935e2stainless-app[bot]1 years ago730```py
731from openai import OpenAI
732
733with OpenAI() as client:
734# make requests here
735...
736
737# HTTP client is now closed
738```
739
08b8179aDavid Schnurr2 years ago740## Microsoft Azure OpenAI
741
6e7d8548Scott Addie2 years ago742To use this library with [Azure OpenAI](https://learn.microsoft.com/azure/ai-services/openai/overview), use the `AzureOpenAI`
08b8179aDavid Schnurr2 years ago743class instead of the `OpenAI` class.
744
745> [!IMPORTANT]
746> The Azure API shape differs from the core API shape which means that the static types for responses / params
747> won't always be correct.
376dd199Logan Kilpatrick2 years ago748
08b8179aDavid Schnurr2 years ago749```py
750from openai import AzureOpenAI
376dd199Logan Kilpatrick2 years ago751
08b8179aDavid Schnurr2 years ago752# gets the API Key from environment variable AZURE_OPENAI_API_KEY
753client = AzureOpenAI(
6e7d8548Scott Addie2 years ago754# https://learn.microsoft.com/azure/ai-services/openai/reference#rest-api-versioning
819ae68dJackYu2 years ago755api_version="2023-07-01-preview",
6e7d8548Scott Addie2 years ago756# https://learn.microsoft.com/azure/cognitive-services/openai/how-to/create-resource?pivots=web-portal#create-a-resource
08b8179aDavid Schnurr2 years ago757azure_endpoint="https://example-endpoint.openai.azure.com",
758)
759
760completion = client.chat.completions.create(
761model="deployment-name", # e.g. gpt-35-instant
762messages=[
763{
764"role": "user",
765"content": "How do I output all files in a directory using Python?",
766},
767],
768)
47656567Stainless Bot2 years ago769print(completion.to_json())
376dd199Logan Kilpatrick2 years ago770```
3c6d4cd6Greg Brockman5 years ago771
08b8179aDavid Schnurr2 years ago772In addition to the options provided in the base `OpenAI` client, the following options are provided:
773
7758c54bStainless Bot2 years ago774- `azure_endpoint` (or the `AZURE_OPENAI_ENDPOINT` environment variable)
08b8179aDavid Schnurr2 years ago775- `azure_deployment`
7758c54bStainless Bot2 years ago776- `api_version` (or the `OPENAI_API_VERSION` environment variable)
777- `azure_ad_token` (or the `AZURE_OPENAI_AD_TOKEN` environment variable)
08b8179aDavid Schnurr2 years ago778- `azure_ad_token_provider`
779
6e7d8548Scott Addie2 years ago780An example of using the client with Microsoft Entra ID (formerly known as Azure Active Directory) can be found [here](https://github.com/openai/openai-python/blob/main/examples/azure_ad.py).
08b8179aDavid Schnurr2 years ago781
782## Versioning
783
784This package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions:
785
7861. Changes that only affect static types, without breaking runtime behavior.
e502d301Josiah Altschuler1 years ago7872. 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.)_
08b8179aDavid Schnurr2 years ago7883. Changes that we do not expect to impact the vast majority of users in practice.
789
790We take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience.
791
792We are keen for your feedback; please open an [issue](https://www.github.com/openai/openai-python/issues) with questions, bugs, or suggestions.
793
fee10404stainless-app[bot]1 years ago794### Determining the installed version
795
796If you've upgraded to the latest version but aren't seeing any new features you were expecting then your python environment is likely still using an older version.
797
798You can determine the version that is being used at runtime with:
799
800```py
801import openai
802print(openai.__version__)
803```
804
08b8179aDavid Schnurr2 years ago805## Requirements
3c6d4cd6Greg Brockman5 years ago806
cb88c2f0stainless-app[bot]1 years ago807Python 3.8 or higher.
a3001d8dStainless Bot1 years ago808
809## Contributing
810
811See [the contributing documentation](./CONTRIBUTING.md).