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 · 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
08b8179aDavid Schnurr2 years ago5The 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
986f3128Stainless Bot2 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
6d217096Robert Craigie2 years ago21pip install openai
3c6d4cd6Greg Brockman5 years ago22```
23
08b8179aDavid Schnurr2 years ago24## Usage
25
986f3128Stainless Bot2 years ago26The full API of this library can be found in [api.md](api.md).
376dd199Logan Kilpatrick2 years ago27
28```python
fb5ba01cStainless Bot2 years ago29import os
08b8179aDavid Schnurr2 years ago30from openai import OpenAI
31
32client = OpenAI(
fb5ba01cStainless Bot2 years ago33# This is the default and can be omitted
34api_key=os.environ.get("OPENAI_API_KEY"),
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],
44model="gpt-3.5-turbo",
45)
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
08b8179aDavid Schnurr2 years ago53## Async usage
3c6d4cd6Greg Brockman5 years ago54
08b8179aDavid Schnurr2 years ago55Simply import `AsyncOpenAI` instead of `OpenAI` and use `await` with each API call:
ede08829Jakub Roztocil3 years ago56
08b8179aDavid Schnurr2 years ago57```python
fb5ba01cStainless Bot2 years ago58import os
08b8179aDavid Schnurr2 years ago59import asyncio
60from openai import AsyncOpenAI
ede08829Jakub Roztocil3 years ago61
08b8179aDavid Schnurr2 years ago62client = AsyncOpenAI(
fb5ba01cStainless Bot2 years ago63# This is the default and can be omitted
64api_key=os.environ.get("OPENAI_API_KEY"),
08b8179aDavid Schnurr2 years ago65)
ede08829Jakub Roztocil3 years ago66
67
08b8179aDavid Schnurr2 years ago68async def main() -> None:
69chat_completion = await client.chat.completions.create(
70messages=[
71{
72"role": "user",
73"content": "Say this is a test",
74}
75],
76model="gpt-3.5-turbo",
77)
ede08829Jakub Roztocil3 years ago78
79
08b8179aDavid Schnurr2 years ago80asyncio.run(main())
2b21516eAtty Eleti3 years ago81```
ede08829Jakub Roztocil3 years ago82
08b8179aDavid Schnurr2 years ago83Functionality 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).
d53d9efbRachel Lim5 years ago88
08b8179aDavid Schnurr2 years ago89```python
90from openai import OpenAI
91
92client = OpenAI()
d53d9efbRachel Lim5 years ago93
08b8179aDavid Schnurr2 years ago94stream = client.chat.completions.create(
95model="gpt-4",
96messages=[{"role": "user", "content": "Say this is a test"}],
97stream=True,
98)
54c7c512Stainless Bot2 years ago99for chunk in stream:
a3da0196Stainless Bot2 years ago100print(chunk.choices[0].delta.content or "", end="")
d53d9efbRachel Lim5 years ago101```
102
08b8179aDavid Schnurr2 years ago103The async client uses the exact same interface.
d53d9efbRachel Lim5 years ago104
105```python
08b8179aDavid Schnurr2 years ago106from openai import AsyncOpenAI
107
108client = AsyncOpenAI()
109
a3da0196Stainless Bot2 years ago110
dfe1c8daSahand Sojoodi2 years ago111async def main():
112stream = await client.chat.completions.create(
113model="gpt-4",
114messages=[{"role": "user", "content": "Say this is a test"}],
115stream=True,
116)
117async for chunk in stream:
a3da0196Stainless Bot2 years ago118print(chunk.choices[0].delta.content or "", end="")
119
dfe1c8daSahand Sojoodi2 years ago120
121asyncio.run(main())
53e5ba4bt-asutedjo4 years ago122```
2b21516eAtty Eleti3 years ago123
08b8179aDavid Schnurr2 years ago124## Module-level client
d53d9efbRachel Lim5 years ago125
08b8179aDavid Schnurr2 years ago126> [!IMPORTANT]
127> We highly recommend instantiating client instances instead of relying on the global client.
d53d9efbRachel Lim5 years ago128
08b8179aDavid Schnurr2 years ago129We also expose a global client instance that is accessible in a similar fashion to versions prior to v1.
6572ef4fZheNing Hu3 years ago130
08b8179aDavid Schnurr2 years ago131```py
132import openai
62b73b9bAtty Eleti3 years ago133
08b8179aDavid Schnurr2 years ago134# 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(
142model="gpt-4",
143messages=[
144{
145"role": "user",
146"content": "How do I output all files in a directory using Python?",
147},
148],
149)
62b73b9bAtty Eleti3 years ago150print(completion.choices[0].message.content)
151```
152
08b8179aDavid Schnurr2 years ago153The API is the exact same as the standard client instance based API.
376dd199Logan Kilpatrick2 years ago154
08b8179aDavid Schnurr2 years ago155This is intended to be used within REPLs or notebooks for faster iteration, **not** in application code.
2b21516eAtty Eleti3 years ago156
08b8179aDavid Schnurr2 years ago157We recommend that you always instantiate a client (e.g., with `client = OpenAI()`) in application code because:
2b21516eAtty Eleti3 years ago158
08b8179aDavid Schnurr2 years ago159- 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
f4b9655fStainless Bot2 years ago166Nested 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)`
2b21516eAtty Eleti3 years ago170
08b8179aDavid Schnurr2 years ago171Typed 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 ago172
08b8179aDavid Schnurr2 years ago173## Pagination
0e21703eTed Sanders4 years ago174
08b8179aDavid Schnurr2 years ago175List 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:
0e21703eTed Sanders4 years ago178
179```python
08b8179aDavid Schnurr2 years ago180import openai
0e21703eTed Sanders4 years ago181
08b8179aDavid Schnurr2 years ago182client = OpenAI()
0e21703eTed Sanders4 years ago183
08b8179aDavid Schnurr2 years ago184all_jobs = []
185# Automatically fetches more pages as needed.
186for job in client.fine_tuning.jobs.list(
187limit=20,
188):
189# Do something with job here
190all_jobs.append(job)
191print(all_jobs)
0e21703eTed Sanders4 years ago192```
193
08b8179aDavid Schnurr2 years ago194Or, asynchronously:
0e21703eTed Sanders4 years ago195
08b8179aDavid Schnurr2 years ago196```python
197import asyncio
198import openai
0e21703eTed Sanders4 years ago199
08b8179aDavid Schnurr2 years ago200client = AsyncOpenAI()
0e21703eTed Sanders4 years ago201
202
08b8179aDavid Schnurr2 years ago203async def main() -> None:
204all_jobs = []
205# Iterate through items across all pages, issuing requests as needed.
206async for job in client.fine_tuning.jobs.list(
207limit=20,
208):
209all_jobs.append(job)
210print(all_jobs)
0e21703eTed Sanders4 years ago211
62b51ca0Boris Dayma4 years ago212
08b8179aDavid Schnurr2 years ago213asyncio.run(main())
214```
2942bf4bLogan Kilpatrick2 years ago215
08b8179aDavid Schnurr2 years ago216Alternatively, 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 ago217
08b8179aDavid Schnurr2 years ago218```python
219first_page = await client.fine_tuning.jobs.list(
220limit=20,
221)
222if first_page.has_next_page():
223print(f"will fetch next page using these details: {first_page.next_page_info()}")
224next_page = await first_page.get_next_page()
225print(f"number of items we just fetched: {len(next_page.data)}")
226
227# Remove `await` for non-async usage.
62b51ca0Boris Dayma4 years ago228```
229
08b8179aDavid Schnurr2 years ago230Or just work directly with the returned data:
0e21703eTed Sanders4 years ago231
08b8179aDavid Schnurr2 years ago232```python
233first_page = await client.fine_tuning.jobs.list(
234limit=20,
235)
e389823bMorgan McGuire2 years ago236
08b8179aDavid Schnurr2 years ago237print(f"next page cursor: {first_page.after}") # => "next page cursor: ..."
238for job in first_page.data:
239print(job.id)
e389823bMorgan McGuire2 years ago240
08b8179aDavid Schnurr2 years ago241# Remove `await` for non-async usage.
242```
e389823bMorgan McGuire2 years ago243
08b8179aDavid Schnurr2 years ago244## Nested params
3c00e856hallacy3 years ago245
08b8179aDavid Schnurr2 years ago246Nested parameters are dictionaries, typed using `TypedDict`, for example:
3c00e856hallacy3 years ago247
248```python
08b8179aDavid Schnurr2 years ago249from openai import OpenAI
3c00e856hallacy3 years ago250
08b8179aDavid Schnurr2 years ago251client = OpenAI()
252
aa681899Stainless Bot2 years ago253completion = client.chat.completions.create(
254messages=[
255{
256"role": "user",
257"content": "Can you generate an example json object describing a fruit?",
258}
259],
9c8789c2Stainless Bot2 years ago260model="gpt-3.5-turbo-1106",
aa681899Stainless Bot2 years ago261response_format={"type": "json_object"},
262)
08b8179aDavid Schnurr2 years ago263```
3c00e856hallacy3 years ago264
08b8179aDavid Schnurr2 years ago265## File Uploads
dc33cb9dMichelle Pokrass3 years ago266
08b8179aDavid Schnurr2 years ago267Request 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 ago268
376dd199Logan Kilpatrick2 years ago269```python
08b8179aDavid Schnurr2 years ago270from pathlib import Path
271from openai import OpenAI
272
273client = OpenAI()
274
275client.files.create(
276file=Path("input.jsonl"),
277purpose="fine-tune",
278)
dc33cb9dMichelle Pokrass3 years ago279```
280
08b8179aDavid Schnurr2 years ago281The 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 ago282
08b8179aDavid Schnurr2 years ago283## Handling errors
376dd199Logan Kilpatrick2 years ago284
08b8179aDavid Schnurr2 years ago285When 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 ago286
08b8179aDavid Schnurr2 years ago287When 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.
62b73b9bAtty Eleti3 years ago289
08b8179aDavid Schnurr2 years ago290All errors inherit from `openai.APIError`.
291
292```python
293import openai
294from openai import OpenAI
295
296client = OpenAI()
297
298try:
8dab1421Stainless Bot2 years ago299client.fine_tuning.jobs.create(
300model="gpt-3.5-turbo",
301training_file="file-abc123",
08b8179aDavid Schnurr2 years ago302)
303except openai.APIConnectionError as e:
304print("The server could not be reached")
305print(e.__cause__) # an underlying Exception, likely raised within httpx.
306except openai.RateLimitError as e:
307print("A 429 status code was received; we should back off a bit.")
308except openai.APIStatusError as e:
309print("Another non-200-range status code was received")
310print(e.status_code)
311print(e.response)
62b73b9bAtty Eleti3 years ago312```
313
08b8179aDavid Schnurr2 years ago314Error 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
376dd199Logan Kilpatrick2 years ago328
08b8179aDavid Schnurr2 years ago329Certain 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.
0abf6413Andrew Chen Wang3 years ago332
08b8179aDavid Schnurr2 years ago333You can use the `max_retries` option to configure or disable retry settings:
0abf6413Andrew Chen Wang3 years ago334
335```python
08b8179aDavid Schnurr2 years ago336from openai import OpenAI
337
338# Configure the default for all requests:
339client = OpenAI(
340# default is 2
341max_retries=0,
342)
343
344# Or, configure per-request:
345client.with_options(max_retries=5).chat.completions.create(
346messages=[
347{
348"role": "user",
349"content": "How can I get the name of the current day in Node.js?",
350}
351],
352model="gpt-3.5-turbo",
353)
0abf6413Andrew Chen Wang3 years ago354```
355
08b8179aDavid Schnurr2 years ago356### Timeouts
0abf6413Andrew Chen Wang3 years ago357
08b8179aDavid Schnurr2 years ago358By 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:
376dd199Logan Kilpatrick2 years ago360
08b8179aDavid Schnurr2 years ago361```python
362from openai import OpenAI
363
364# Configure the default for all requests:
365client = OpenAI(
1381f46eStainless Bot2 years ago366# 20 seconds (default is 10 minutes)
08b8179aDavid Schnurr2 years ago367timeout=20.0,
368)
369
370# More granular control:
371client = OpenAI(
372timeout=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(
377messages=[
378{
379"role": "user",
380"content": "How can I list all files in a directory using Python?",
381}
382],
383model="gpt-3.5-turbo",
384)
0abf6413Andrew Chen Wang3 years ago385```
386
08b8179aDavid Schnurr2 years ago387On timeout, an `APITimeoutError` is thrown.
376dd199Logan Kilpatrick2 years ago388
08b8179aDavid Schnurr2 years ago389Note that requests that time out are [retried twice by default](#retries).
376dd199Logan Kilpatrick2 years ago390
08b8179aDavid Schnurr2 years ago391## Advanced
376dd199Logan Kilpatrick2 years ago392
08b8179aDavid Schnurr2 years ago393### Logging
376dd199Logan Kilpatrick2 years ago394
08b8179aDavid Schnurr2 years ago395We use the standard library [`logging`](https://docs.python.org/3/library/logging.html) module.
376dd199Logan Kilpatrick2 years ago396
08b8179aDavid Schnurr2 years ago397You can enable logging by setting the environment variable `OPENAI_LOG` to `debug`.
376dd199Logan Kilpatrick2 years ago398
08b8179aDavid Schnurr2 years ago399```shell
400$ export OPENAI_LOG=debug
376dd199Logan Kilpatrick2 years ago401```
402
08b8179aDavid Schnurr2 years ago403### How to tell whether `None` means `null` or missing
dc33cb9dMichelle Pokrass3 years ago404
08b8179aDavid Schnurr2 years ago405In 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 ago406
08b8179aDavid Schnurr2 years ago407```py
408if response.my_field is None:
409if 'my_field' not in response.model_fields_set:
410print('Got json like {}, without a "my_field" key present at all.')
411else:
412print('Got json like {"my_field": null}.')
413```
376dd199Logan Kilpatrick2 years ago414
08b8179aDavid Schnurr2 years ago415### Accessing raw response data (e.g. headers)
376dd199Logan Kilpatrick2 years ago416
86379b44Stainless Bot2 years ago417The "raw" Response object can be accessed by prefixing `.with_raw_response.` to any HTTP method call, e.g.,
08b8179aDavid Schnurr2 years ago418
419```py
420from openai import OpenAI
421
422client = OpenAI()
423response = client.chat.completions.with_raw_response.create(
424messages=[{
425"role": "user",
426"content": "Say this is a test",
427}],
428model="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)
376dd199Logan Kilpatrick2 years ago434```
435
86379b44Stainless Bot2 years ago436These 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(
455messages=[
456{
457"role": "user",
458"content": "Say this is a test",
459}
460],
461model="gpt-3.5-turbo",
462) as response:
463print(response.headers.get("X-My-Header"))
464
465for line in response.iter_lines():
466print(line)
467```
468
469The context manager is required so that the response will reliably be closed.
3c6d4cd6Greg Brockman5 years ago470
08b8179aDavid Schnurr2 years ago471### Configuring the HTTP client
376dd199Logan Kilpatrick2 years ago472
08b8179aDavid Schnurr2 years ago473You can directly override the [httpx client](https://www.python-httpx.org/api/#client) to customize it for your use case, including:
376dd199Logan Kilpatrick2 years ago474
08b8179aDavid Schnurr2 years ago475- Support for proxies
476- Custom transports
477- Additional [advanced](https://www.python-httpx.org/advanced/#client-instances) functionality
376dd199Logan Kilpatrick2 years ago478
479```python
08b8179aDavid Schnurr2 years ago480import httpx
481from openai import OpenAI
482
483client = OpenAI(
0733934fStainless Bot2 years ago484# Or use the `OPENAI_BASE_URL` env var
08b8179aDavid Schnurr2 years ago485base_url="http://my.test.server.example.com:8083",
486http_client=httpx.Client(
487proxies="http://my.test.proxy.example.com",
488transport=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.
376dd199Logan Kilpatrick2 years ago505
08b8179aDavid Schnurr2 years ago506```py
507from openai import AzureOpenAI
376dd199Logan Kilpatrick2 years ago508
08b8179aDavid Schnurr2 years ago509# 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
819ae68dJackYu2 years ago512api_version="2023-07-01-preview",
08b8179aDavid Schnurr2 years ago513# https://learn.microsoft.com/en-us/azure/cognitive-services/openai/how-to/create-resource?pivots=web-portal#create-a-resource
514azure_endpoint="https://example-endpoint.openai.azure.com",
515)
516
517completion = client.chat.completions.create(
518model="deployment-name", # e.g. gpt-35-instant
519messages=[
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))
376dd199Logan Kilpatrick2 years ago527```
3c6d4cd6Greg Brockman5 years ago528
08b8179aDavid Schnurr2 years ago529In addition to the options provided in the base `OpenAI` client, the following options are provided:
530
7758c54bStainless Bot2 years ago531- `azure_endpoint` (or the `AZURE_OPENAI_ENDPOINT` environment variable)
08b8179aDavid Schnurr2 years ago532- `azure_deployment`
7758c54bStainless Bot2 years ago533- `api_version` (or the `OPENAI_API_VERSION` environment variable)
534- `azure_ad_token` (or the `AZURE_OPENAI_AD_TOKEN` environment variable)
08b8179aDavid Schnurr2 years ago535- `azure_ad_token_provider`
536
812839cbMikyo King2 years ago537An 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).
08b8179aDavid Schnurr2 years ago538
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
3c6d4cd6Greg Brockman5 years ago552
08b8179aDavid Schnurr2 years ago553Python 3.7 or higher.