openai/openai-python

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v1.86.0

Branches

Tags

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

Clone

HTTPS

Download ZIP

README.md

740lines · 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
2954945eRobert Craigie1 years ago13The REST API documentation can be found on [platform.openai.com](https://platform.openai.com/docs/api-reference). The full API of this library can be found in [api.md](api.md).
3c6d4cd6Greg Brockman5 years ago14
15## Installation
16
17```sh
1879c97aStainless Bot2 years ago18# install from PyPI
6d217096Robert Craigie2 years ago19pip install openai
3c6d4cd6Greg Brockman5 years ago20```
21
08b8179aDavid Schnurr2 years ago22## Usage
23
986f3128Stainless Bot2 years ago24The full API of this library can be found in [api.md](api.md).
376dd199Logan Kilpatrick2 years ago25
2954945eRobert Craigie1 years ago26The primary API for interacting with OpenAI models is the [Responses API](https://platform.openai.com/docs/api-reference/responses). You can generate text from the model with the code below.
27
376dd199Logan Kilpatrick2 years ago28```python
fb5ba01cStainless Bot2 years ago29import os
08b8179aDavid Schnurr2 years ago30from openai import OpenAI
31
32client = OpenAI(
2954945eRobert Craigie1 years ago33# This is the default and can be omitted
34api_key=os.environ.get("OPENAI_API_KEY"),
35)
36
37response = client.responses.create(
38model="gpt-4o",
39instructions="You are a coding assistant that talks like a pirate.",
40input="How do I check if a Python object is an instance of a class?",
08b8179aDavid Schnurr2 years ago41)
42
2954945eRobert Craigie1 years ago43print(response.output_text)
44```
45
46The previous standard (supported indefinitely) for generating text is the [Chat Completions API](https://platform.openai.com/docs/api-reference/chat). You can use that API to generate text from the model with the code below.
47
48```python
49from openai import OpenAI
50
51client = OpenAI()
52
53completion = client.chat.completions.create(
54model="gpt-4o",
08b8179aDavid Schnurr2 years ago55messages=[
2954945eRobert Craigie1 years ago56{"role": "developer", "content": "Talk like a pirate."},
08b8179aDavid Schnurr2 years ago57{
58"role": "user",
2954945eRobert Craigie1 years ago59"content": "How do I check if a Python object is an instance of a class?",
60},
08b8179aDavid Schnurr2 years ago61],
62)
2954945eRobert Craigie1 years ago63
64print(completion.choices[0].message.content)
376dd199Logan Kilpatrick2 years ago65```
66
08b8179aDavid Schnurr2 years ago67While you can provide an `api_key` keyword argument,
68we recommend using [python-dotenv](https://pypi.org/project/python-dotenv/)
69to add `OPENAI_API_KEY="My API Key"` to your `.env` file
2954945eRobert Craigie1 years ago70so that your API key is not stored in source control.
71[Get an API key here](https://platform.openai.com/settings/organization/api-keys).
3c6d4cd6Greg Brockman5 years ago72
192b8f2bDan Corin1 years ago73### Vision
74
2954945eRobert Craigie1 years ago75With an image URL:
192b8f2bDan Corin1 years ago76
77```python
2954945eRobert Craigie1 years ago78prompt = "What is in this image?"
79img_url = "https://upload.wikimedia.org/wikipedia/commons/thumb/d/d5/2023_06_08_Raccoon1.jpg/1599px-2023_06_08_Raccoon1.jpg"
80
81response = client.responses.create(
192b8f2bDan Corin1 years ago82model="gpt-4o-mini",
2954945eRobert Craigie1 years ago83input=[
192b8f2bDan Corin1 years ago84{
85"role": "user",
86"content": [
2954945eRobert Craigie1 years ago87{"type": "input_text", "text": prompt},
88{"type": "input_image", "image_url": f"{img_url}"},
192b8f2bDan Corin1 years ago89],
90}
91],
92)
93```
94
95With the image as a base64 encoded string:
96
97```python
2954945eRobert Craigie1 years ago98import base64
99from openai import OpenAI
100
101client = OpenAI()
102
103prompt = "What is in this image?"
104with open("path/to/image.png", "rb") as image_file:
105b64_image = base64.b64encode(image_file.read()).decode("utf-8")
106
107response = client.responses.create(
192b8f2bDan Corin1 years ago108model="gpt-4o-mini",
2954945eRobert Craigie1 years ago109input=[
192b8f2bDan Corin1 years ago110{
111"role": "user",
112"content": [
2954945eRobert Craigie1 years ago113{"type": "input_text", "text": prompt},
114{"type": "input_image", "image_url": f"data:image/png;base64,{b64_image}"},
192b8f2bDan Corin1 years ago115],
116}
117],
118)
119```
120
08b8179aDavid Schnurr2 years ago121## Async usage
3c6d4cd6Greg Brockman5 years ago122
08b8179aDavid Schnurr2 years ago123Simply import `AsyncOpenAI` instead of `OpenAI` and use `await` with each API call:
ede08829Jakub Roztocil3 years ago124
08b8179aDavid Schnurr2 years ago125```python
fb5ba01cStainless Bot2 years ago126import os
08b8179aDavid Schnurr2 years ago127import asyncio
128from openai import AsyncOpenAI
ede08829Jakub Roztocil3 years ago129
08b8179aDavid Schnurr2 years ago130client = AsyncOpenAI(
2954945eRobert Craigie1 years ago131# This is the default and can be omitted
132api_key=os.environ.get("OPENAI_API_KEY"),
08b8179aDavid Schnurr2 years ago133)
ede08829Jakub Roztocil3 years ago134
135
08b8179aDavid Schnurr2 years ago136async def main() -> None:
2954945eRobert Craigie1 years ago137response = await client.responses.create(
138model="gpt-4o", input="Explain disestablishmentarianism to a smart five year old."
08b8179aDavid Schnurr2 years ago139)
2954945eRobert Craigie1 years ago140print(response.output_text)
ede08829Jakub Roztocil3 years ago141
142
08b8179aDavid Schnurr2 years ago143asyncio.run(main())
2b21516eAtty Eleti3 years ago144```
ede08829Jakub Roztocil3 years ago145
08b8179aDavid Schnurr2 years ago146Functionality between the synchronous and asynchronous clients is otherwise identical.
147
2b23eb53Stainless Bot2 years ago148## Streaming responses
08b8179aDavid Schnurr2 years ago149
150We provide support for streaming responses using Server Side Events (SSE).
d53d9efbRachel Lim5 years ago151
08b8179aDavid Schnurr2 years ago152```python
153from openai import OpenAI
154
155client = OpenAI()
d53d9efbRachel Lim5 years ago156
2954945eRobert Craigie1 years ago157stream = client.responses.create(
23444ed9Stainless Bot1 years ago158model="gpt-4o",
2954945eRobert Craigie1 years ago159input="Write a one-sentence bedtime story about a unicorn.",
08b8179aDavid Schnurr2 years ago160stream=True,
161)
2954945eRobert Craigie1 years ago162
163for event in stream:
164print(event)
d53d9efbRachel Lim5 years ago165```
166
08b8179aDavid Schnurr2 years ago167The async client uses the exact same interface.
d53d9efbRachel Lim5 years ago168
169```python
db0aa22cAdel Basli1 years ago170import asyncio
08b8179aDavid Schnurr2 years ago171from openai import AsyncOpenAI
172
173client = AsyncOpenAI()
174
a3da0196Stainless Bot2 years ago175
dfe1c8daSahand Sojoodi2 years ago176async def main():
f588695fstainless-app[bot]1 years ago177stream = await client.responses.create(
2954945eRobert Craigie1 years ago178model="gpt-4o",
179input="Write a one-sentence bedtime story about a unicorn.",
dfe1c8daSahand Sojoodi2 years ago180stream=True,
181)
d53d9efbRachel Lim5 years ago182
f588695fstainless-app[bot]1 years ago183async for event in stream:
2954945eRobert Craigie1 years ago184print(event)
08b8179aDavid Schnurr2 years ago185
186
2954945eRobert Craigie1 years ago187asyncio.run(main())
62b73b9bAtty Eleti3 years ago188```
189
488ec04bRobert Craigie1 years ago190## Realtime API beta
191
192The 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.
193
194Under the hood the SDK uses the [`websockets`](https://websockets.readthedocs.io/en/stable/) library to manage connections.
195
255677d7Robert Craigie1 years ago196The 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 ago197
198Basic text based example:
199
200```py
201import asyncio
202from openai import AsyncOpenAI
203
204async def main():
205client = AsyncOpenAI()
206
fd763424Robert Craigie1 years ago207async with client.beta.realtime.connect(model="gpt-4o-realtime-preview") as connection:
488ec04bRobert Craigie1 years ago208await connection.session.update(session={'modalities': ['text']})
209
210await connection.conversation.item.create(
211item={
212"type": "message",
213"role": "user",
214"content": [{"type": "input_text", "text": "Say hello!"}],
215}
216)
217await connection.response.create()
218
219async for event in connection:
220if event.type == 'response.text.delta':
221print(event.delta, flush=True, end="")
222
223elif event.type == 'response.text.done':
224print()
225
226elif event.type == "response.done":
227break
228
229asyncio.run(main())
230```
231
6935dfdcRobert Craigie1 years ago232However 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 ago233
234### Realtime error handling
235
2954945eRobert Craigie1 years ago236Whenever 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 ago237
238```py
239client = AsyncOpenAI()
240
fd763424Robert Craigie1 years ago241async with client.beta.realtime.connect(model="gpt-4o-realtime-preview") as connection:
488ec04bRobert Craigie1 years ago242...
243async for event in connection:
244if event.type == 'error':
245print(event.error.type)
246print(event.error.code)
247print(event.error.event_id)
248print(event.error.message)
249```
250
08b8179aDavid Schnurr2 years ago251## Using types
252
47656567Stainless Bot2 years ago253Nested 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 ago254
47656567Stainless Bot2 years ago255- Serializing back into JSON, `model.to_json()`
256- Converting to a dictionary, `model.to_dict()`
2b21516eAtty Eleti3 years ago257
08b8179aDavid Schnurr2 years ago258Typed 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 ago259
08b8179aDavid Schnurr2 years ago260## Pagination
0e21703eTed Sanders4 years ago261
08b8179aDavid Schnurr2 years ago262List methods in the OpenAI API are paginated.
263
264This library provides auto-paginating iterators with each list response, so you do not have to request successive pages manually:
0e21703eTed Sanders4 years ago265
266```python
ff5add01stainless-app[bot]1 years ago267from openai import OpenAI
0e21703eTed Sanders4 years ago268
08b8179aDavid Schnurr2 years ago269client = OpenAI()
0e21703eTed Sanders4 years ago270
08b8179aDavid Schnurr2 years ago271all_jobs = []
272# Automatically fetches more pages as needed.
273for job in client.fine_tuning.jobs.list(
274limit=20,
275):
276# Do something with job here
277all_jobs.append(job)
278print(all_jobs)
0e21703eTed Sanders4 years ago279```
280
08b8179aDavid Schnurr2 years ago281Or, asynchronously:
0e21703eTed Sanders4 years ago282
08b8179aDavid Schnurr2 years ago283```python
284import asyncio
ff5add01stainless-app[bot]1 years ago285from openai import AsyncOpenAI
0e21703eTed Sanders4 years ago286
08b8179aDavid Schnurr2 years ago287client = AsyncOpenAI()
0e21703eTed Sanders4 years ago288
289
08b8179aDavid Schnurr2 years ago290async def main() -> None:
291all_jobs = []
292# Iterate through items across all pages, issuing requests as needed.
293async for job in client.fine_tuning.jobs.list(
294limit=20,
295):
296all_jobs.append(job)
297print(all_jobs)
0e21703eTed Sanders4 years ago298
62b51ca0Boris Dayma4 years ago299
08b8179aDavid Schnurr2 years ago300asyncio.run(main())
301```
2942bf4bLogan Kilpatrick2 years ago302
08b8179aDavid Schnurr2 years ago303Alternatively, 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 ago304
08b8179aDavid Schnurr2 years ago305```python
306first_page = await client.fine_tuning.jobs.list(
307limit=20,
308)
309if first_page.has_next_page():
310print(f"will fetch next page using these details: {first_page.next_page_info()}")
311next_page = await first_page.get_next_page()
312print(f"number of items we just fetched: {len(next_page.data)}")
313
314# Remove `await` for non-async usage.
62b51ca0Boris Dayma4 years ago315```
316
08b8179aDavid Schnurr2 years ago317Or just work directly with the returned data:
0e21703eTed Sanders4 years ago318
08b8179aDavid Schnurr2 years ago319```python
320first_page = await client.fine_tuning.jobs.list(
321limit=20,
322)
e389823bMorgan McGuire2 years ago323
08b8179aDavid Schnurr2 years ago324print(f"next page cursor: {first_page.after}") # => "next page cursor: ..."
325for job in first_page.data:
326print(job.id)
e389823bMorgan McGuire2 years ago327
08b8179aDavid Schnurr2 years ago328# Remove `await` for non-async usage.
329```
e389823bMorgan McGuire2 years ago330
08b8179aDavid Schnurr2 years ago331## Nested params
3c00e856hallacy3 years ago332
08b8179aDavid Schnurr2 years ago333Nested parameters are dictionaries, typed using `TypedDict`, for example:
3c00e856hallacy3 years ago334
335```python
08b8179aDavid Schnurr2 years ago336from openai import OpenAI
3c00e856hallacy3 years ago337
08b8179aDavid Schnurr2 years ago338client = OpenAI()
339
2954945eRobert Craigie1 years ago340response = client.chat.responses.create(
341input=[
aa681899Stainless Bot2 years ago342{
343"role": "user",
2954945eRobert Craigie1 years ago344"content": "How much ?",
aa681899Stainless Bot2 years ago345}
346],
23444ed9Stainless Bot1 years ago347model="gpt-4o",
aa681899Stainless Bot2 years ago348response_format={"type": "json_object"},
349)
08b8179aDavid Schnurr2 years ago350```
3c00e856hallacy3 years ago351
2b23eb53Stainless Bot2 years ago352## File uploads
dc33cb9dMichelle Pokrass3 years ago353
acf68ef3stainless-app[bot]1 years ago354Request parameters that correspond to file uploads can be passed as `bytes`, or a [`PathLike`](https://docs.python.org/3/library/os.html#os.PathLike) instance or a tuple of `(filename, contents, media type)`.
dc33cb9dMichelle Pokrass3 years ago355
376dd199Logan Kilpatrick2 years ago356```python
08b8179aDavid Schnurr2 years ago357from pathlib import Path
358from openai import OpenAI
359
360client = OpenAI()
361
362client.files.create(
363file=Path("input.jsonl"),
364purpose="fine-tune",
365)
dc33cb9dMichelle Pokrass3 years ago366```
367
08b8179aDavid Schnurr2 years ago368The 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 ago369
08b8179aDavid Schnurr2 years ago370## Handling errors
376dd199Logan Kilpatrick2 years ago371
08b8179aDavid Schnurr2 years ago372When 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 ago373
08b8179aDavid Schnurr2 years ago374When the API returns a non-success status code (that is, 4xx or 5xx
375response), a subclass of `openai.APIStatusError` is raised, containing `status_code` and `response` properties.
62b73b9bAtty Eleti3 years ago376
08b8179aDavid Schnurr2 years ago377All errors inherit from `openai.APIError`.
378
379```python
380import openai
381from openai import OpenAI
382
383client = OpenAI()
384
385try:
8dab1421Stainless Bot2 years ago386client.fine_tuning.jobs.create(
23444ed9Stainless Bot1 years ago387model="gpt-4o",
8dab1421Stainless Bot2 years ago388training_file="file-abc123",
08b8179aDavid Schnurr2 years ago389)
390except openai.APIConnectionError as e:
391print("The server could not be reached")
392print(e.__cause__) # an underlying Exception, likely raised within httpx.
393except openai.RateLimitError as e:
394print("A 429 status code was received; we should back off a bit.")
395except openai.APIStatusError as e:
396print("Another non-200-range status code was received")
397print(e.status_code)
398print(e.response)
62b73b9bAtty Eleti3 years ago399```
400
fee9c81bstainless-app[bot]1 years ago401Error codes are as follows:
08b8179aDavid Schnurr2 years ago402
403| Status Code | Error Type |
404| ----------- | -------------------------- |
405| 400 | `BadRequestError` |
406| 401 | `AuthenticationError` |
407| 403 | `PermissionDeniedError` |
408| 404 | `NotFoundError` |
409| 422 | `UnprocessableEntityError` |
410| 429 | `RateLimitError` |
411| >=500 | `InternalServerError` |
412| N/A | `APIConnectionError` |
413
4b302346Robert Craigie1 years ago414## Request IDs
415
416> For more information on debugging requests, see [these docs](https://platform.openai.com/docs/api-reference/debugging-requests)
417
418All 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.
419
420```python
2954945eRobert Craigie1 years ago421response = await client.responses.create(
422model="gpt-4o-mini",
423input="Say 'this is a test'.",
4b302346Robert Craigie1 years ago424)
2954945eRobert Craigie1 years ago425print(response._request_id) # req_123
4b302346Robert Craigie1 years ago426```
427
428Note that unlike other properties that use an `_` prefix, the `_request_id` property
2954945eRobert Craigie1 years ago429_is_ public. Unless documented otherwise, _all_ other `_` prefix properties,
430methods and modules are _private_.
4b302346Robert Craigie1 years ago431
709926ffRobert Craigie1 years ago432> [!IMPORTANT]
433> If you need to access request IDs for failed requests you must catch the `APIStatusError` exception
434
435```python
436import openai
437
438try:
439completion = await client.chat.completions.create(
440messages=[{"role": "user", "content": "Say this is a test"}], model="gpt-4"
441)
442except openai.APIStatusError as exc:
443print(exc.request_id) # req_123
444raise exc
445```
446
2954945eRobert Craigie1 years ago447## Retries
376dd199Logan Kilpatrick2 years ago448
08b8179aDavid Schnurr2 years ago449Certain errors are automatically retried 2 times by default, with a short exponential backoff.
450Connection errors (for example, due to a network connectivity problem), 408 Request Timeout, 409 Conflict,
451429 Rate Limit, and >=500 Internal errors are all retried by default.
0abf6413Andrew Chen Wang3 years ago452
08b8179aDavid Schnurr2 years ago453You can use the `max_retries` option to configure or disable retry settings:
0abf6413Andrew Chen Wang3 years ago454
455```python
08b8179aDavid Schnurr2 years ago456from openai import OpenAI
457
458# Configure the default for all requests:
459client = OpenAI(
460# default is 2
461max_retries=0,
462)
463
464# Or, configure per-request:
465client.with_options(max_retries=5).chat.completions.create(
466messages=[
467{
468"role": "user",
23444ed9Stainless Bot1 years ago469"content": "How can I get the name of the current day in JavaScript?",
08b8179aDavid Schnurr2 years ago470}
471],
23444ed9Stainless Bot1 years ago472model="gpt-4o",
08b8179aDavid Schnurr2 years ago473)
0abf6413Andrew Chen Wang3 years ago474```
475
2954945eRobert Craigie1 years ago476## Timeouts
0abf6413Andrew Chen Wang3 years ago477
08b8179aDavid Schnurr2 years ago478By default requests time out after 10 minutes. You can configure this with a `timeout` option,
90e3d396Guspan Tanadi1 years ago479which accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/timeouts/#fine-tuning-the-configuration) object:
376dd199Logan Kilpatrick2 years ago480
08b8179aDavid Schnurr2 years ago481```python
482from openai import OpenAI
483
484# Configure the default for all requests:
485client = OpenAI(
1381f46eStainless Bot2 years ago486# 20 seconds (default is 10 minutes)
08b8179aDavid Schnurr2 years ago487timeout=20.0,
488)
489
490# More granular control:
491client = OpenAI(
492timeout=httpx.Timeout(60.0, read=5.0, write=10.0, connect=2.0),
493)
494
495# Override per-request:
2a678e30Stainless Bot2 years ago496client.with_options(timeout=5.0).chat.completions.create(
08b8179aDavid Schnurr2 years ago497messages=[
498{
499"role": "user",
500"content": "How can I list all files in a directory using Python?",
501}
502],
23444ed9Stainless Bot1 years ago503model="gpt-4o",
08b8179aDavid Schnurr2 years ago504)
0abf6413Andrew Chen Wang3 years ago505```
506
08b8179aDavid Schnurr2 years ago507On timeout, an `APITimeoutError` is thrown.
376dd199Logan Kilpatrick2 years ago508
08b8179aDavid Schnurr2 years ago509Note that requests that time out are [retried twice by default](#retries).
376dd199Logan Kilpatrick2 years ago510
08b8179aDavid Schnurr2 years ago511## Advanced
376dd199Logan Kilpatrick2 years ago512
08b8179aDavid Schnurr2 years ago513### Logging
376dd199Logan Kilpatrick2 years ago514
08b8179aDavid Schnurr2 years ago515We use the standard library [`logging`](https://docs.python.org/3/library/logging.html) module.
376dd199Logan Kilpatrick2 years ago516
f6199d60stainless-app[bot]1 years ago517You can enable logging by setting the environment variable `OPENAI_LOG` to `info`.
376dd199Logan Kilpatrick2 years ago518
08b8179aDavid Schnurr2 years ago519```shell
f6199d60stainless-app[bot]1 years ago520$ export OPENAI_LOG=info
376dd199Logan Kilpatrick2 years ago521```
522
f6199d60stainless-app[bot]1 years ago523Or to `debug` for more verbose logging.
524
08b8179aDavid Schnurr2 years ago525### How to tell whether `None` means `null` or missing
dc33cb9dMichelle Pokrass3 years ago526
08b8179aDavid Schnurr2 years ago527In 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 ago528
08b8179aDavid Schnurr2 years ago529```py
530if response.my_field is None:
531if 'my_field' not in response.model_fields_set:
532print('Got json like {}, without a "my_field" key present at all.')
533else:
534print('Got json like {"my_field": null}.')
535```
376dd199Logan Kilpatrick2 years ago536
08b8179aDavid Schnurr2 years ago537### Accessing raw response data (e.g. headers)
376dd199Logan Kilpatrick2 years ago538
86379b44Stainless Bot2 years ago539The "raw" Response object can be accessed by prefixing `.with_raw_response.` to any HTTP method call, e.g.,
08b8179aDavid Schnurr2 years ago540
541```py
542from openai import OpenAI
543
544client = OpenAI()
545response = client.chat.completions.with_raw_response.create(
546messages=[{
547"role": "user",
548"content": "Say this is a test",
549}],
23444ed9Stainless Bot1 years ago550model="gpt-4o",
08b8179aDavid Schnurr2 years ago551)
552print(response.headers.get('X-My-Header'))
553
554completion = response.parse() # get the object that `chat.completions.create()` would have returned
555print(completion)
376dd199Logan Kilpatrick2 years ago556```
557
16315f22stainless-app[bot]1 years ago558These 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 ago559
560For the sync client this will mostly be the same with the exception
561of `content` & `text` will be methods instead of properties. In the
562async client, all methods will be async.
563
564A migration script will be provided & the migration in general should
565be smooth.
566
567#### `.with_streaming_response`
568
569The above interface eagerly reads the full response body when you make the request, which may not always be what you want.
570
571To 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.
572
573As 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.
574
575```python
576with client.chat.completions.with_streaming_response.create(
577messages=[
578{
579"role": "user",
580"content": "Say this is a test",
581}
582],
23444ed9Stainless Bot1 years ago583model="gpt-4o",
86379b44Stainless Bot2 years ago584) as response:
585print(response.headers.get("X-My-Header"))
586
587for line in response.iter_lines():
588print(line)
589```
590
591The context manager is required so that the response will reliably be closed.
3c6d4cd6Greg Brockman5 years ago592
73869eeeStainless Bot2 years ago593### Making custom/undocumented requests
594
7931ebaaStainless Bot2 years ago595This library is typed for convenient access to the documented API.
73869eeeStainless Bot2 years ago596
597If you need to access undocumented endpoints, params, or response properties, the library can still be used.
598
599#### Undocumented endpoints
600
601To make requests to undocumented endpoints, you can make requests using `client.get`, `client.post`, and other
fee9c81bstainless-app[bot]1 years ago602http verbs. Options on the client will be respected (such as retries) when making this request.
73869eeeStainless Bot2 years ago603
604```py
605import httpx
606
607response = client.post(
608"/foo",
609cast_to=httpx.Response,
610body={"my_param": True},
611)
612
613print(response.headers.get("x-foo"))
614```
615
802819c8Stainless Bot2 years ago616#### Undocumented request params
73869eeeStainless Bot2 years ago617
618If you want to explicitly send an extra param, you can do so with the `extra_query`, `extra_body`, and `extra_headers` request
619options.
620
802819c8Stainless Bot2 years ago621#### Undocumented response properties
73869eeeStainless Bot2 years ago622
623To access undocumented response properties, you can access the extra fields like `response.unknown_prop`. You
624can also get all the extra fields on the Pydantic model as a dict with
625[`response.model_extra`](https://docs.pydantic.dev/latest/api/base_model/#pydantic.BaseModel.model_extra).
626
08b8179aDavid Schnurr2 years ago627### Configuring the HTTP client
376dd199Logan Kilpatrick2 years ago628
08b8179aDavid Schnurr2 years ago629You can directly override the [httpx client](https://www.python-httpx.org/api/#client) to customize it for your use case, including:
376dd199Logan Kilpatrick2 years ago630
6a1ab551stainless-app[bot]1 years ago631- Support for [proxies](https://www.python-httpx.org/advanced/proxies/)
632- Custom [transports](https://www.python-httpx.org/advanced/transports/)
d3254d12stainless-app[bot]2 years ago633- Additional [advanced](https://www.python-httpx.org/advanced/clients/) functionality
376dd199Logan Kilpatrick2 years ago634
635```python
6a1ab551stainless-app[bot]1 years ago636import httpx
347363edStainless Bot2 years ago637from openai import OpenAI, DefaultHttpxClient
08b8179aDavid Schnurr2 years ago638
639client = OpenAI(
0733934fStainless Bot2 years ago640# Or use the `OPENAI_BASE_URL` env var
38dd5348Adrian Cole1 years ago641base_url="http://my.test.server.example.com:8083/v1",
347363edStainless Bot2 years ago642http_client=DefaultHttpxClient(
6a1ab551stainless-app[bot]1 years ago643proxy="http://my.test.proxy.example.com",
08b8179aDavid Schnurr2 years ago644transport=httpx.HTTPTransport(local_address="0.0.0.0"),
645),
646)
647```
648
f8f01a61stainless-app[bot]1 years ago649You can also customize the client on a per-request basis by using `with_options()`:
650
651```python
652client.with_options(http_client=DefaultHttpxClient(...))
653```
654
08b8179aDavid Schnurr2 years ago655### Managing HTTP resources
656
657By 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.
658
588935e2stainless-app[bot]1 years ago659```py
660from openai import OpenAI
661
662with OpenAI() as client:
663# make requests here
664...
665
666# HTTP client is now closed
667```
668
08b8179aDavid Schnurr2 years ago669## Microsoft Azure OpenAI
670
6e7d8548Scott Addie2 years ago671To use this library with [Azure OpenAI](https://learn.microsoft.com/azure/ai-services/openai/overview), use the `AzureOpenAI`
08b8179aDavid Schnurr2 years ago672class instead of the `OpenAI` class.
673
674> [!IMPORTANT]
675> The Azure API shape differs from the core API shape which means that the static types for responses / params
676> won't always be correct.
376dd199Logan Kilpatrick2 years ago677
08b8179aDavid Schnurr2 years ago678```py
679from openai import AzureOpenAI
376dd199Logan Kilpatrick2 years ago680
08b8179aDavid Schnurr2 years ago681# gets the API Key from environment variable AZURE_OPENAI_API_KEY
682client = AzureOpenAI(
6e7d8548Scott Addie2 years ago683# https://learn.microsoft.com/azure/ai-services/openai/reference#rest-api-versioning
819ae68dJackYu2 years ago684api_version="2023-07-01-preview",
6e7d8548Scott Addie2 years ago685# https://learn.microsoft.com/azure/cognitive-services/openai/how-to/create-resource?pivots=web-portal#create-a-resource
08b8179aDavid Schnurr2 years ago686azure_endpoint="https://example-endpoint.openai.azure.com",
687)
688
689completion = client.chat.completions.create(
690model="deployment-name", # e.g. gpt-35-instant
691messages=[
692{
693"role": "user",
694"content": "How do I output all files in a directory using Python?",
695},
696],
697)
47656567Stainless Bot2 years ago698print(completion.to_json())
376dd199Logan Kilpatrick2 years ago699```
3c6d4cd6Greg Brockman5 years ago700
08b8179aDavid Schnurr2 years ago701In addition to the options provided in the base `OpenAI` client, the following options are provided:
702
7758c54bStainless Bot2 years ago703- `azure_endpoint` (or the `AZURE_OPENAI_ENDPOINT` environment variable)
08b8179aDavid Schnurr2 years ago704- `azure_deployment`
7758c54bStainless Bot2 years ago705- `api_version` (or the `OPENAI_API_VERSION` environment variable)
706- `azure_ad_token` (or the `AZURE_OPENAI_AD_TOKEN` environment variable)
08b8179aDavid Schnurr2 years ago707- `azure_ad_token_provider`
708
6e7d8548Scott Addie2 years ago709An 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 ago710
711## Versioning
712
713This package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions:
714
7151. Changes that only affect static types, without breaking runtime behavior.
e502d301Josiah Altschuler1 years ago7162. 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 ago7173. Changes that we do not expect to impact the vast majority of users in practice.
718
719We take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience.
720
721We are keen for your feedback; please open an [issue](https://www.github.com/openai/openai-python/issues) with questions, bugs, or suggestions.
722
fee10404stainless-app[bot]1 years ago723### Determining the installed version
724
725If 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.
726
727You can determine the version that is being used at runtime with:
728
729```py
730import openai
731print(openai.__version__)
732```
733
08b8179aDavid Schnurr2 years ago734## Requirements
3c6d4cd6Greg Brockman5 years ago735
cb88c2f0stainless-app[bot]1 years ago736Python 3.8 or higher.
a3001d8dStainless Bot1 years ago737
738## Contributing
739
740See [the contributing documentation](./CONTRIBUTING.md).