python/index.md +0 −958 deleted
File Deleted View Diff
1# OpenAI Python API library
2
3<!-- prettier-ignore -->
4[)](https://pypi.org/project/openai/)
5
6The OpenAI Python library provides convenient access to the OpenAI REST API from any Python 3.9+
7application. The library includes type definitions for all request params and response fields,
8and offers both synchronous and asynchronous clients powered by [httpx](https://github.com/encode/httpx).
9
10It is generated from our [OpenAPI specification](https://github.com/openai/openai-openapi) with [Stainless](https://stainlessapi.com/).
11
12## Documentation
13
14The 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).
15
16## Installation
17
18```sh
19# install from PyPI
20pip install openai
21```
22
23## Usage
24
25The full API of this library can be found in [api.md](api.md).
26
27The 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.
28
29```python
30import os
31from openai import OpenAI
32
33client = OpenAI(
34 # This is the default and can be omitted
35 api_key=os.environ.get("OPENAI_API_KEY"),
36)
37
38response = client.responses.create(
39 model="gpt-5.2",
40 instructions="You are a coding assistant that talks like a pirate.",
41 input="How do I check if a Python object is an instance of a class?",
42)
43
44print(response.output_text)
45```
46
47The 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.
48
49```python
50from openai import OpenAI
51
52client = OpenAI()
53
54completion = client.chat.completions.create(
55 model="gpt-5.2",
56 messages=[
57 {"role": "developer", "content": "Talk like a pirate."},
58 {
59 "role": "user",
60 "content": "How do I check if a Python object is an instance of a class?",
61 },
62 ],
63)
64
65print(completion.choices[0].message.content)
66```
67
68While you can provide an `api_key` keyword argument,
69we recommend using [python-dotenv](https://pypi.org/project/python-dotenv/)
70to add `OPENAI_API_KEY="My API Key"` to your `.env` file
71so that your API key is not stored in source control.
72[Get an API key here](https://platform.openai.com/settings/organization/api-keys).
73
74### Workload Identity Authentication
75
76For secure, automated environments like cloud-managed Kubernetes, Azure, and Google Cloud Platform, you can use workload identity authentication with short-lived tokens from cloud identity providers instead of long-lived API keys.
77
78#### Kubernetes (service account tokens)
79
80```python
81from openai import OpenAI
82from openai.auth import k8s_service_account_token_provider
83
84client = OpenAI(
85 workload_identity={
86 "identity_provider_id": "idp-123",
87 "service_account_id": "sa-456",
88 "provider": k8s_service_account_token_provider(
89 "/var/run/secrets/kubernetes.io/serviceaccount/token"
90 ),
91 },
92)
93
94response = client.chat.completions.create(
95 model="gpt-4",
96 messages=[{"role": "user", "content": "Hello!"}],
97)
98```
99
100#### Azure (managed identity)
101
102```python
103from openai import OpenAI
104from openai.auth import azure_managed_identity_token_provider
105
106client = OpenAI(
107 workload_identity={
108 "identity_provider_id": "idp-123",
109 "service_account_id": "sa-456",
110 "provider": azure_managed_identity_token_provider(
111 resource="https://management.azure.com/",
112 ),
113 },
114)
115```
116
117#### Google Cloud Platform (compute engine metadata)
118
119```python
120from openai import OpenAI
121from openai.auth import gcp_id_token_provider
122
123client = OpenAI(
124 workload_identity={
125 "identity_provider_id": "idp-123",
126 "service_account_id": "sa-456",
127 "provider": gcp_id_token_provider(audience="https://api.openai.com/v1"),
128 },
129)
130```
131
132#### Custom subject token provider
133
134```python
135from openai import OpenAI
136
137
138def get_custom_token() -> str:
139 return "your-jwt-token"
140
141
142client = OpenAI(
143 workload_identity={
144 "identity_provider_id": "idp-123",
145 "service_account_id": "sa-456",
146 "provider": {
147 "token_type": "jwt",
148 "get_token": get_custom_token,
149 },
150 }
151)
152```
153
154You can also customize the token refresh buffer (default is 1200 seconds (20 minutes) before expiration):
155
156```python
157from openai import OpenAI
158from openai.auth import k8s_service_account_token_provider
159
160client = OpenAI(
161 workload_identity={
162 "identity_provider_id": "idp-123",
163 "service_account_id": "sa-456",
164 "provider": k8s_service_account_token_provider("/var/token"),
165 "refresh_buffer_seconds": 120.0,
166 }
167)
168```
169
170### Vision
171
172With an image URL:
173
174```python
175prompt = "What is in this image?"
176img_url = "https://upload.wikimedia.org/wikipedia/commons/thumb/d/d5/2023_06_08_Raccoon1.jpg/1599px-2023_06_08_Raccoon1.jpg"
177
178response = client.responses.create(
179 model="gpt-5.2",
180 input=[
181 {
182 "role": "user",
183 "content": [
184 {"type": "input_text", "text": prompt},
185 {"type": "input_image", "image_url": f"{img_url}"},
186 ],
187 }
188 ],
189)
190```
191
192With the image as a base64 encoded string:
193
194```python
195import base64
196from openai import OpenAI
197
198client = OpenAI()
199
200prompt = "What is in this image?"
201with open("path/to/image.png", "rb") as image_file:
202 b64_image = base64.b64encode(image_file.read()).decode("utf-8")
203
204response = client.responses.create(
205 model="gpt-5.2",
206 input=[
207 {
208 "role": "user",
209 "content": [
210 {"type": "input_text", "text": prompt},
211 {"type": "input_image", "image_url": f"data:image/png;base64,{b64_image}"},
212 ],
213 }
214 ],
215)
216```
217
218## Async usage
219
220Simply import `AsyncOpenAI` instead of `OpenAI` and use `await` with each API call:
221
222```python
223import os
224import asyncio
225from openai import AsyncOpenAI
226
227client = AsyncOpenAI(
228 # This is the default and can be omitted
229 api_key=os.environ.get("OPENAI_API_KEY"),
230)
231
232
233async def main() -> None:
234 response = await client.responses.create(
235 model="gpt-5.2", input="Explain disestablishmentarianism to a smart five year old."
236 )
237 print(response.output_text)
238
239
240asyncio.run(main())
241```
242
243Functionality between the synchronous and asynchronous clients is otherwise identical.
244
245### With aiohttp
246
247By default, the async client uses `httpx` for HTTP requests. However, for improved concurrency performance you may also use `aiohttp` as the HTTP backend.
248
249You can enable this by installing `aiohttp`:
250
251```sh
252# install from PyPI
253pip install openai[aiohttp]
254```
255
256Then you can enable it by instantiating the client with `http_client=DefaultAioHttpClient()`:
257
258```python
259import os
260import asyncio
261from openai import DefaultAioHttpClient
262from openai import AsyncOpenAI
263
264
265async def main() -> None:
266 async with AsyncOpenAI(
267 api_key=os.environ.get("OPENAI_API_KEY"), # This is the default and can be omitted
268 http_client=DefaultAioHttpClient(),
269 ) as client:
270 chat_completion = await client.chat.completions.create(
271 messages=[
272 {
273 "role": "user",
274 "content": "Say this is a test",
275 }
276 ],
277 model="gpt-5.2",
278 )
279
280
281asyncio.run(main())
282```
283
284## Streaming responses
285
286We provide support for streaming responses using Server Side Events (SSE).
287
288```python
289from openai import OpenAI
290
291client = OpenAI()
292
293stream = client.responses.create(
294 model="gpt-5.2",
295 input="Write a one-sentence bedtime story about a unicorn.",
296 stream=True,
297)
298
299for event in stream:
300 print(event)
301```
302
303The async client uses the exact same interface.
304
305```python
306import asyncio
307from openai import AsyncOpenAI
308
309client = AsyncOpenAI()
310
311
312async def main():
313 stream = await client.responses.create(
314 model="gpt-5.2",
315 input="Write a one-sentence bedtime story about a unicorn.",
316 stream=True,
317 )
318
319 async for event in stream:
320 print(event)
321
322
323asyncio.run(main())
324```
325
326## Realtime API
327
328The 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.
329
330Under the hood the SDK uses the [`websockets`](https://websockets.readthedocs.io/en/stable/) library to manage connections.
331
332The 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).
333
334Basic text based example:
335
336```py
337import asyncio
338from openai import AsyncOpenAI
339
340async def main():
341 client = AsyncOpenAI()
342
343 async with client.realtime.connect(model="gpt-realtime") as connection:
344 await connection.session.update(
345 session={"type": "realtime", "output_modalities": ["text"]}
346 )
347
348 await connection.conversation.item.create(
349 item={
350 "type": "message",
351 "role": "user",
352 "content": [{"type": "input_text", "text": "Say hello!"}],
353 }
354 )
355 await connection.response.create()
356
357 async for event in connection:
358 if event.type == "response.output_text.delta":
359 print(event.delta, flush=True, end="")
360
361 elif event.type == "response.output_text.done":
362 print()
363
364 elif event.type == "response.done":
365 break
366
367asyncio.run(main())
368```
369
370However 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.
371
372### Realtime error handling
373
374Whenever 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.
375
376```py
377client = AsyncOpenAI()
378
379async with client.realtime.connect(model="gpt-realtime") as connection:
380 ...
381 async for event in connection:
382 if event.type == 'error':
383 print(event.error.type)
384 print(event.error.code)
385 print(event.error.event_id)
386 print(event.error.message)
387```
388
389## Using types
390
391Nested 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:
392
393- Serializing back into JSON, `model.to_json()`
394- Converting to a dictionary, `model.to_dict()`
395
396Typed 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`.
397
398## Pagination
399
400List methods in the OpenAI API are paginated.
401
402This library provides auto-paginating iterators with each list response, so you do not have to request successive pages manually:
403
404```python
405from openai import OpenAI
406
407client = OpenAI()
408
409all_jobs = []
410# Automatically fetches more pages as needed.
411for job in client.fine_tuning.jobs.list(
412 limit=20,
413):
414 # Do something with job here
415 all_jobs.append(job)
416print(all_jobs)
417```
418
419Or, asynchronously:
420
421```python
422import asyncio
423from openai import AsyncOpenAI
424
425client = AsyncOpenAI()
426
427
428async def main() -> None:
429 all_jobs = []
430 # Iterate through items across all pages, issuing requests as needed.
431 async for job in client.fine_tuning.jobs.list(
432 limit=20,
433 ):
434 all_jobs.append(job)
435 print(all_jobs)
436
437
438asyncio.run(main())
439```
440
441Alternatively, you can use the `.has_next_page()`, `.next_page_info()`, or `.get_next_page()` methods for more granular control working with pages:
442
443```python
444first_page = await client.fine_tuning.jobs.list(
445 limit=20,
446)
447if first_page.has_next_page():
448 print(f"will fetch next page using these details: {first_page.next_page_info()}")
449 next_page = await first_page.get_next_page()
450 print(f"number of items we just fetched: {len(next_page.data)}")
451
452# Remove `await` for non-async usage.
453```
454
455Or just work directly with the returned data:
456
457```python
458first_page = await client.fine_tuning.jobs.list(
459 limit=20,
460)
461
462print(f"next page cursor: {first_page.after}") # => "next page cursor: ..."
463for job in first_page.data:
464 print(job.id)
465
466# Remove `await` for non-async usage.
467```
468
469## Nested params
470
471Nested parameters are dictionaries, typed using `TypedDict`, for example:
472
473```python
474from openai import OpenAI
475
476client = OpenAI()
477
478response = client.chat.responses.create(
479 input=[
480 {
481 "role": "user",
482 "content": "How much ?",
483 }
484 ],
485 model="gpt-5.2",
486 response_format={"type": "json_object"},
487)
488```
489
490## File uploads
491
492Request 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)`.
493
494```python
495from pathlib import Path
496from openai import OpenAI
497
498client = OpenAI()
499
500client.files.create(
501 file=Path("input.jsonl"),
502 purpose="fine-tune",
503)
504```
505
506The 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.
507
508## Webhook Verification
509
510Verifying webhook signatures is _optional but encouraged_.
511
512For more information about webhooks, see [the API docs](https://platform.openai.com/docs/guides/webhooks).
513
514### Parsing webhook payloads
515
516For most use cases, you will likely want to verify the webhook and parse the payload at the same time. To achieve this, we provide the method `client.webhooks.unwrap()`, which parses a webhook request and verifies that it was sent by OpenAI. This method will raise an error if the signature is invalid.
517
518Note that the `body` parameter must be the raw JSON string sent from the server (do not parse it first). The `.unwrap()` method will parse this JSON for you into an event object after verifying the webhook was sent from OpenAI.
519
520```python
521from openai import OpenAI
522from flask import Flask, request
523
524app = Flask(__name__)
525client = OpenAI() # OPENAI_WEBHOOK_SECRET environment variable is used by default
526
527
528@app.route("/webhook", methods=["POST"])
529def webhook():
530 request_body = request.get_data(as_text=True)
531
532 try:
533 event = client.webhooks.unwrap(request_body, request.headers)
534
535 if event.type == "response.completed":
536 print("Response completed:", event.data)
537 elif event.type == "response.failed":
538 print("Response failed:", event.data)
539 else:
540 print("Unhandled event type:", event.type)
541
542 return "ok"
543 except Exception as e:
544 print("Invalid signature:", e)
545 return "Invalid signature", 400
546
547
548if __name__ == "__main__":
549 app.run(port=8000)
550```
551
552### Verifying webhook payloads directly
553
554In some cases, you may want to verify the webhook separately from parsing the payload. If you prefer to handle these steps separately, we provide the method `client.webhooks.verify_signature()` to _only verify_ the signature of a webhook request. Like `.unwrap()`, this method will raise an error if the signature is invalid.
555
556Note that the `body` parameter must be the raw JSON string sent from the server (do not parse it first). You will then need to parse the body after verifying the signature.
557
558```python
559import json
560from openai import OpenAI
561from flask import Flask, request
562
563app = Flask(__name__)
564client = OpenAI() # OPENAI_WEBHOOK_SECRET environment variable is used by default
565
566
567@app.route("/webhook", methods=["POST"])
568def webhook():
569 request_body = request.get_data(as_text=True)
570
571 try:
572 client.webhooks.verify_signature(request_body, request.headers)
573
574 # Parse the body after verification
575 event = json.loads(request_body)
576 print("Verified event:", event)
577
578 return "ok"
579 except Exception as e:
580 print("Invalid signature:", e)
581 return "Invalid signature", 400
582
583
584if __name__ == "__main__":
585 app.run(port=8000)
586```
587
588## Handling errors
589
590When 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.
591
592When the API returns a non-success status code (that is, 4xx or 5xx
593response), a subclass of `openai.APIStatusError` is raised, containing `status_code` and `response` properties.
594
595All errors inherit from `openai.APIError`.
596
597```python
598import openai
599from openai import OpenAI
600
601client = OpenAI()
602
603try:
604 client.fine_tuning.jobs.create(
605 model="gpt-4o",
606 training_file="file-abc123",
607 )
608except openai.APIConnectionError as e:
609 print("The server could not be reached")
610 print(e.__cause__) # an underlying Exception, likely raised within httpx.
611except openai.RateLimitError as e:
612 print("A 429 status code was received; we should back off a bit.")
613except openai.APIStatusError as e:
614 print("Another non-200-range status code was received")
615 print(e.status_code)
616 print(e.response)
617```
618
619Error codes are as follows:
620
621| Status Code | Error Type |
622| ----------- | -------------------------- |
623| 400 | `BadRequestError` |
624| 401 | `AuthenticationError` |
625| 403 | `PermissionDeniedError` |
626| 404 | `NotFoundError` |
627| 422 | `UnprocessableEntityError` |
628| 429 | `RateLimitError` |
629| >=500 | `InternalServerError` |
630| N/A | `APIConnectionError` |
631
632## Request IDs
633
634> For more information on debugging requests, see [these docs](https://platform.openai.com/docs/api-reference/debugging-requests)
635
636All 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.
637
638```python
639response = await client.responses.create(
640 model="gpt-5.2",
641 input="Say 'this is a test'.",
642)
643print(response._request_id) # req_123
644```
645
646Note that unlike other properties that use an `_` prefix, the `_request_id` property
647_is_ public. Unless documented otherwise, _all_ other `_` prefix properties,
648methods and modules are _private_.
649
650> [!IMPORTANT]
651> If you need to access request IDs for failed requests you must catch the `APIStatusError` exception
652
653```python
654import openai
655
656try:
657 completion = await client.chat.completions.create(
658 messages=[{"role": "user", "content": "Say this is a test"}], model="gpt-5.2"
659 )
660except openai.APIStatusError as exc:
661 print(exc.request_id) # req_123
662 raise exc
663```
664
665## Retries
666
667Certain errors are automatically retried 2 times by default, with a short exponential backoff.
668Connection errors (for example, due to a network connectivity problem), 408 Request Timeout, 409 Conflict,
669429 Rate Limit, and >=500 Internal errors are all retried by default.
670
671You can use the `max_retries` option to configure or disable retry settings:
672
673```python
674from openai import OpenAI
675
676# Configure the default for all requests:
677client = OpenAI(
678 # default is 2
679 max_retries=0,
680)
681
682# Or, configure per-request:
683client.with_options(max_retries=5).chat.completions.create(
684 messages=[
685 {
686 "role": "user",
687 "content": "How can I get the name of the current day in JavaScript?",
688 }
689 ],
690 model="gpt-5.2",
691)
692```
693
694## Timeouts
695
696By default requests time out after 10 minutes. You can configure this with a `timeout` option,
697which accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/timeouts/#fine-tuning-the-configuration) object:
698
699```python
700from openai import OpenAI
701
702# Configure the default for all requests:
703client = OpenAI(
704 # 20 seconds (default is 10 minutes)
705 timeout=20.0,
706)
707
708# More granular control:
709client = OpenAI(
710 timeout=httpx.Timeout(60.0, read=5.0, write=10.0, connect=2.0),
711)
712
713# Override per-request:
714client.with_options(timeout=5.0).chat.completions.create(
715 messages=[
716 {
717 "role": "user",
718 "content": "How can I list all files in a directory using Python?",
719 }
720 ],
721 model="gpt-5.2",
722)
723```
724
725On timeout, an `APITimeoutError` is thrown.
726
727Note that requests that time out are [retried twice by default](#retries).
728
729## Advanced
730
731### Logging
732
733We use the standard library [`logging`](https://docs.python.org/3/library/logging.html) module.
734
735You can enable logging by setting the environment variable `OPENAI_LOG` to `info`.
736
737```shell
738$ export OPENAI_LOG=info
739```
740
741Or to `debug` for more verbose logging.
742
743### How to tell whether `None` means `null` or missing
744
745In 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`:
746
747```py
748if response.my_field is None:
749 if 'my_field' not in response.model_fields_set:
750 print('Got json like {}, without a "my_field" key present at all.')
751 else:
752 print('Got json like {"my_field": null}.')
753```
754
755### Accessing raw response data (e.g. headers)
756
757The "raw" Response object can be accessed by prefixing `.with_raw_response.` to any HTTP method call, e.g.,
758
759```py
760from openai import OpenAI
761
762client = OpenAI()
763response = client.chat.completions.with_raw_response.create(
764 messages=[{
765 "role": "user",
766 "content": "Say this is a test",
767 }],
768 model="gpt-5.2",
769)
770print(response.headers.get('X-My-Header'))
771
772completion = response.parse() # get the object that `chat.completions.create()` would have returned
773print(completion)
774```
775
776These 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.
777
778For the sync client this will mostly be the same with the exception
779of `content` & `text` will be methods instead of properties. In the
780async client, all methods will be async.
781
782A migration script will be provided & the migration in general should
783be smooth.
784
785#### `.with_streaming_response`
786
787The above interface eagerly reads the full response body when you make the request, which may not always be what you want.
788
789To 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.
790
791As 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.
792
793```python
794with client.chat.completions.with_streaming_response.create(
795 messages=[
796 {
797 "role": "user",
798 "content": "Say this is a test",
799 }
800 ],
801 model="gpt-5.2",
802) as response:
803 print(response.headers.get("X-My-Header"))
804
805 for line in response.iter_lines():
806 print(line)
807```
808
809The context manager is required so that the response will reliably be closed.
810
811### Making custom/undocumented requests
812
813This library is typed for convenient access to the documented API.
814
815If you need to access undocumented endpoints, params, or response properties, the library can still be used.
816
817#### Undocumented endpoints
818
819To make requests to undocumented endpoints, you can make requests using `client.get`, `client.post`, and other
820http verbs. Options on the client will be respected (such as retries) when making this request.
821
822```py
823import httpx
824
825response = client.post(
826 "/foo",
827 cast_to=httpx.Response,
828 body={"my_param": True},
829)
830
831print(response.headers.get("x-foo"))
832```
833
834#### Undocumented request params
835
836If you want to explicitly send an extra param, you can do so with the `extra_query`, `extra_body`, and `extra_headers` request
837options.
838
839#### Undocumented response properties
840
841To access undocumented response properties, you can access the extra fields like `response.unknown_prop`. You
842can also get all the extra fields on the Pydantic model as a dict with
843[`response.model_extra`](https://docs.pydantic.dev/latest/api/base_model/#pydantic.BaseModel.model_extra).
844
845### Configuring the HTTP client
846
847You can directly override the [httpx client](https://www.python-httpx.org/api/#client) to customize it for your use case, including:
848
849- Support for [proxies](https://www.python-httpx.org/advanced/proxies/)
850- Custom [transports](https://www.python-httpx.org/advanced/transports/)
851- Additional [advanced](https://www.python-httpx.org/advanced/clients/) functionality
852
853```python
854import httpx
855from openai import OpenAI, DefaultHttpxClient
856
857client = OpenAI(
858 # Or use the `OPENAI_BASE_URL` env var
859 base_url="http://my.test.server.example.com:8083/v1",
860 http_client=DefaultHttpxClient(
861 proxy="http://my.test.proxy.example.com",
862 transport=httpx.HTTPTransport(local_address="0.0.0.0"),
863 ),
864)
865```
866
867You can also customize the client on a per-request basis by using `with_options()`:
868
869```python
870client.with_options(http_client=DefaultHttpxClient(...))
871```
872
873### Managing HTTP resources
874
875By 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.
876
877```py
878from openai import OpenAI
879
880with OpenAI() as client:
881 # make requests here
882 ...
883
884# HTTP client is now closed
885```
886
887## Microsoft Azure OpenAI
888
889To use this library with [Azure OpenAI](https://learn.microsoft.com/azure/ai-services/openai/overview), use the `AzureOpenAI`
890class instead of the `OpenAI` class.
891
892> [!IMPORTANT]
893> The Azure API shape differs from the core API shape which means that the static types for responses / params
894> won't always be correct.
895
896```py
897from openai import AzureOpenAI
898
899# gets the API Key from environment variable AZURE_OPENAI_API_KEY
900client = AzureOpenAI(
901 # https://learn.microsoft.com/azure/ai-services/openai/reference#rest-api-versioning
902 api_version="2023-07-01-preview",
903 # https://learn.microsoft.com/azure/cognitive-services/openai/how-to/create-resource?pivots=web-portal#create-a-resource
904 azure_endpoint="https://example-endpoint.openai.azure.com",
905)
906
907completion = client.chat.completions.create(
908 model="deployment-name", # e.g. gpt-35-instant
909 messages=[
910 {
911 "role": "user",
912 "content": "How do I output all files in a directory using Python?",
913 },
914 ],
915)
916print(completion.to_json())
917```
918
919In addition to the options provided in the base `OpenAI` client, the following options are provided:
920
921- `azure_endpoint` (or the `AZURE_OPENAI_ENDPOINT` environment variable)
922- `azure_deployment`
923- `api_version` (or the `OPENAI_API_VERSION` environment variable)
924- `azure_ad_token` (or the `AZURE_OPENAI_AD_TOKEN` environment variable)
925- `azure_ad_token_provider`
926
927An 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).
928
929## Versioning
930
931This package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions:
932
9331. Changes that only affect static types, without breaking runtime behavior.
9342. 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.)_
9353. Changes that we do not expect to impact the vast majority of users in practice.
936
937We take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience.
938
939We are keen for your feedback; please open an [issue](https://www.github.com/openai/openai-python/issues) with questions, bugs, or suggestions.
940
941### Determining the installed version
942
943If 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.
944
945You can determine the version that is being used at runtime with:
946
947```py
948import openai
949print(openai.__version__)
950```
951
952## Requirements
953
954Python 3.9 or higher.
955
956## Contributing
957
958See [the contributing documentation](./CONTRIBUTING.md).