diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index d087636a64..9c28de3543 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -61,14 +61,18 @@ jobs:
run: rye build
- name: Get GitHub OIDC Token
- if: github.repository == 'stainless-sdks/openai-python'
+ if: |-
+ github.repository == 'stainless-sdks/openai-python' &&
+ !startsWith(github.ref, 'refs/heads/stl/')
id: github-oidc
uses: actions/github-script@v8
with:
script: core.setOutput('github_token', await core.getIDToken());
- name: Upload tarball
- if: github.repository == 'stainless-sdks/openai-python'
+ if: |-
+ github.repository == 'stainless-sdks/openai-python' &&
+ !startsWith(github.ref, 'refs/heads/stl/')
env:
URL: https://pkg.stainless.com/s
AUTH: ${{ steps.github-oidc.outputs.github_token }}
diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index 1441304df6..fa4d75253f 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "2.26.0"
+ ".": "2.28.0"
}
\ No newline at end of file
diff --git a/.stats.yml b/.stats.yml
index bd550123f1..3e6307edaf 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
-configured_endpoints: 148
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-9c802d45a9bf2a896b5fd22ac22bba185e8a145bd40ed242df9bb87a05e954eb.yml
-openapi_spec_hash: 97984ed69285e660b7d5c810c69ed449
-config_hash: 8240b8a7a7fc145a45b93bda435612d6
+configured_endpoints: 152
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-cb3e4451108eed58d59cff25bf77ec0dc960ec9c6f3dba68f90e7a9847c09d21.yml
+openapi_spec_hash: dec6d9be64a5ba8f474a1f2a7a4fafef
+config_hash: e922f01e25accd07d8fd3641c37fbd62
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c8508a0b1d..dfc7ddca89 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,37 @@
# Changelog
+## 2.28.0 (2026-03-13)
+
+Full Changelog: [v2.27.0...v2.28.0](https://github.com/openai/openai-python/compare/v2.27.0...v2.28.0)
+
+### Features
+
+* **api:** custom voices ([50dc060](https://github.com/openai/openai-python/commit/50dc060b55767615419219ef567d31210517e613))
+
+## 2.27.0 (2026-03-13)
+
+Full Changelog: [v2.26.0...v2.27.0](https://github.com/openai/openai-python/compare/v2.26.0...v2.27.0)
+
+### Features
+
+* **api:** api update ([60ab24a](https://github.com/openai/openai-python/commit/60ab24ae722a7fa280eb4b2273da4ded1f930231))
+* **api:** manual updates ([b244b09](https://github.com/openai/openai-python/commit/b244b0946045aaa0dbfa8c0ce5164b64e1156834))
+* **api:** manual updates ([d806635](https://github.com/openai/openai-python/commit/d806635081a736cc81344bf1e62b57956a88d093))
+* **api:** sora api improvements: character api, video extensions/edits, higher resolution exports. ([58b70d3](https://github.com/openai/openai-python/commit/58b70d304a4b2cf70eae4db4b448d439fc8b8ba3))
+
+
+### Bug Fixes
+
+* **api:** repair merged videos resource ([742d8ee](https://github.com/openai/openai-python/commit/742d8ee1f969ee1bbb39ba9d799dcd5c480d8ddb))
+
+
+### Chores
+
+* **internal:** codegen related update ([4e6498e](https://github.com/openai/openai-python/commit/4e6498e2d222dd35d76bb397ba976ff53c852e12))
+* **internal:** codegen related update ([93af129](https://github.com/openai/openai-python/commit/93af129e8919de6d3aee19329c8bdef0532bd20a))
+* match http protocol with ws protocol instead of wss ([026f9de](https://github.com/openai/openai-python/commit/026f9de35d2aa74f35c91261eb5ea43d4ab1b8ba))
+* use proper capitalization for WebSockets ([a2f9b07](https://github.com/openai/openai-python/commit/a2f9b0722597627e8d01aa05c27a52015072726b))
+
## 2.26.0 (2026-03-05)
Full Changelog: [v2.25.0...v2.26.0](https://github.com/openai/openai-python/compare/v2.25.0...v2.26.0)
diff --git a/api.md b/api.md
index a7981f7185..852df5bb8a 100644
--- a/api.md
+++ b/api.md
@@ -859,12 +859,15 @@ Types:
```python
from openai.types import (
+ ImageInputReferenceParam,
Video,
VideoCreateError,
VideoModel,
VideoSeconds,
VideoSize,
VideoDeleteResponse,
+ VideoCreateCharacterResponse,
+ VideoGetCharacterResponse,
)
```
@@ -874,7 +877,11 @@ Methods:
- client.videos.retrieve(video_id) -> Video
- client.videos.list(\*\*params) -> SyncConversationCursorPage[Video]
- client.videos.delete(video_id) -> VideoDeleteResponse
+- client.videos.create_character(\*\*params) -> VideoCreateCharacterResponse
- client.videos.download_content(video_id, \*\*params) -> HttpxBinaryResponseContent
+- client.videos.edit(\*\*params) -> Video
+- client.videos.extend(\*\*params) -> Video
+- client.videos.get_character(character_id) -> VideoGetCharacterResponse
- client.videos.remix(video_id, \*\*params) -> Video
- client.videos.create_and_poll(\*args) -> Video
-
+- client.videos.poll(\*args) -> Video
diff --git a/pyproject.toml b/pyproject.toml
index 41738c8c5e..ea82be70c4 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "openai"
-version = "2.26.0"
+version = "2.28.0"
description = "The official Python library for the openai API"
dynamic = ["readme"]
license = "Apache-2.0"
diff --git a/src/openai/_compat.py b/src/openai/_compat.py
index 020ffeb2ca..50027c62dc 100644
--- a/src/openai/_compat.py
+++ b/src/openai/_compat.py
@@ -149,7 +149,7 @@ def model_dump(
exclude_defaults=exclude_defaults,
# warnings are not supported in Pydantic v1
warnings=True if PYDANTIC_V1 else warnings,
- by_alias=by_alias,
+ by_alias=by_alias if by_alias is not None else True,
)
return cast(
"dict[str, Any]",
diff --git a/src/openai/_version.py b/src/openai/_version.py
index 2feccec170..45ae8eb37a 100644
--- a/src/openai/_version.py
+++ b/src/openai/_version.py
@@ -1,4 +1,4 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
__title__ = "openai"
-__version__ = "2.26.0" # x-release-please-version
+__version__ = "2.28.0" # x-release-please-version
diff --git a/src/openai/resources/audio/speech.py b/src/openai/resources/audio/speech.py
index f937321baa..80dbb44077 100644
--- a/src/openai/resources/audio/speech.py
+++ b/src/openai/resources/audio/speech.py
@@ -52,9 +52,7 @@ def create(
*,
input: str,
model: Union[str, SpeechModel],
- voice: Union[
- str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"]
- ],
+ voice: speech_create_params.Voice,
instructions: str | Omit = omit,
response_format: Literal["mp3", "opus", "aac", "flac", "wav", "pcm"] | Omit = omit,
speed: float | Omit = omit,
@@ -80,8 +78,9 @@ def create(
voice: The voice to use when generating the audio. Supported built-in voices are
`alloy`, `ash`, `ballad`, `coral`, `echo`, `fable`, `onyx`, `nova`, `sage`,
- `shimmer`, `verse`, `marin`, and `cedar`. Previews of the voices are available
- in the
+ `shimmer`, `verse`, `marin`, and `cedar`. You may also provide a custom voice
+ object with an `id`, for example `{ "id": "voice_1234" }`. Previews of the
+ voices are available in the
[Text to speech guide](https://platform.openai.com/docs/guides/text-to-speech#voice-options).
instructions: Control the voice of your generated audio with additional instructions. Does not
@@ -153,9 +152,7 @@ async def create(
*,
input: str,
model: Union[str, SpeechModel],
- voice: Union[
- str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"]
- ],
+ voice: speech_create_params.Voice,
instructions: str | Omit = omit,
response_format: Literal["mp3", "opus", "aac", "flac", "wav", "pcm"] | Omit = omit,
speed: float | Omit = omit,
@@ -181,8 +178,9 @@ async def create(
voice: The voice to use when generating the audio. Supported built-in voices are
`alloy`, `ash`, `ballad`, `coral`, `echo`, `fable`, `onyx`, `nova`, `sage`,
- `shimmer`, `verse`, `marin`, and `cedar`. Previews of the voices are available
- in the
+ `shimmer`, `verse`, `marin`, and `cedar`. You may also provide a custom voice
+ object with an `id`, for example `{ "id": "voice_1234" }`. Previews of the
+ voices are available in the
[Text to speech guide](https://platform.openai.com/docs/guides/text-to-speech#voice-options).
instructions: Control the voice of your generated audio with additional instructions. Does not
diff --git a/src/openai/resources/realtime/realtime.py b/src/openai/resources/realtime/realtime.py
index 44f14cd3aa..73a87fc2e7 100644
--- a/src/openai/resources/realtime/realtime.py
+++ b/src/openai/resources/realtime/realtime.py
@@ -41,7 +41,7 @@
AsyncClientSecretsWithStreamingResponse,
)
from ...types.realtime import session_update_event_param
-from ...types.websocket_connection_options import WebsocketConnectionOptions
+from ...types.websocket_connection_options import WebSocketConnectionOptions
from ...types.realtime.realtime_client_event import RealtimeClientEvent
from ...types.realtime.realtime_server_event import RealtimeServerEvent
from ...types.realtime.conversation_item_param import ConversationItemParam
@@ -49,8 +49,8 @@
from ...types.realtime.realtime_response_create_params_param import RealtimeResponseCreateParamsParam
if TYPE_CHECKING:
- from websockets.sync.client import ClientConnection as WebsocketConnection
- from websockets.asyncio.client import ClientConnection as AsyncWebsocketConnection
+ from websockets.sync.client import ClientConnection as WebSocketConnection
+ from websockets.asyncio.client import ClientConnection as AsyncWebSocketConnection
from ..._client import OpenAI, AsyncOpenAI
@@ -96,7 +96,7 @@ def connect(
model: str | Omit = omit,
extra_query: Query = {},
extra_headers: Headers = {},
- websocket_connection_options: WebsocketConnectionOptions = {},
+ websocket_connection_options: WebSocketConnectionOptions = {},
) -> RealtimeConnectionManager:
"""
The 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.
@@ -156,7 +156,7 @@ def connect(
model: str | Omit = omit,
extra_query: Query = {},
extra_headers: Headers = {},
- websocket_connection_options: WebsocketConnectionOptions = {},
+ websocket_connection_options: WebSocketConnectionOptions = {},
) -> AsyncRealtimeConnectionManager:
"""
The 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.
@@ -240,9 +240,9 @@ class AsyncRealtimeConnection:
conversation: AsyncRealtimeConversationResource
output_audio_buffer: AsyncRealtimeOutputAudioBufferResource
- _connection: AsyncWebsocketConnection
+ _connection: AsyncWebSocketConnection
- def __init__(self, connection: AsyncWebsocketConnection) -> None:
+ def __init__(self, connection: AsyncWebSocketConnection) -> None:
self._connection = connection
self.session = AsyncRealtimeSessionResource(self)
@@ -281,7 +281,7 @@ async def recv_bytes(self) -> bytes:
then you can call `.parse_event(data)`.
"""
message = await self._connection.recv(decode=False)
- log.debug(f"Received websocket message: %s", message)
+ log.debug(f"Received WebSocket message: %s", message)
return message
async def send(self, event: RealtimeClientEvent | RealtimeClientEventParam) -> None:
@@ -334,7 +334,7 @@ def __init__(
model: str | Omit = omit,
extra_query: Query,
extra_headers: Headers,
- websocket_connection_options: WebsocketConnectionOptions,
+ websocket_connection_options: WebSocketConnectionOptions,
) -> None:
self.__client = client
self.__call_id = call_id
@@ -408,7 +408,9 @@ def _prepare_url(self) -> httpx.URL:
if self.__client.websocket_base_url is not None:
base_url = httpx.URL(self.__client.websocket_base_url)
else:
- base_url = self.__client._base_url.copy_with(scheme="wss")
+ scheme = self.__client._base_url.scheme
+ ws_scheme = "ws" if scheme == "http" else "wss"
+ base_url = self.__client._base_url.copy_with(scheme=ws_scheme)
merge_raw_path = base_url.raw_path.rstrip(b"/") + b"/realtime"
return base_url.copy_with(raw_path=merge_raw_path)
@@ -429,9 +431,9 @@ class RealtimeConnection:
conversation: RealtimeConversationResource
output_audio_buffer: RealtimeOutputAudioBufferResource
- _connection: WebsocketConnection
+ _connection: WebSocketConnection
- def __init__(self, connection: WebsocketConnection) -> None:
+ def __init__(self, connection: WebSocketConnection) -> None:
self._connection = connection
self.session = RealtimeSessionResource(self)
@@ -470,7 +472,7 @@ def recv_bytes(self) -> bytes:
then you can call `.parse_event(data)`.
"""
message = self._connection.recv(decode=False)
- log.debug(f"Received websocket message: %s", message)
+ log.debug(f"Received WebSocket message: %s", message)
return message
def send(self, event: RealtimeClientEvent | RealtimeClientEventParam) -> None:
@@ -523,7 +525,7 @@ def __init__(
model: str | Omit = omit,
extra_query: Query,
extra_headers: Headers,
- websocket_connection_options: WebsocketConnectionOptions,
+ websocket_connection_options: WebSocketConnectionOptions,
) -> None:
self.__client = client
self.__call_id = call_id
@@ -597,7 +599,9 @@ def _prepare_url(self) -> httpx.URL:
if self.__client.websocket_base_url is not None:
base_url = httpx.URL(self.__client.websocket_base_url)
else:
- base_url = self.__client._base_url.copy_with(scheme="wss")
+ scheme = self.__client._base_url.scheme
+ ws_scheme = "ws" if scheme == "http" else "wss"
+ base_url = self.__client._base_url.copy_with(scheme=ws_scheme)
merge_raw_path = base_url.raw_path.rstrip(b"/") + b"/realtime"
return base_url.copy_with(raw_path=merge_raw_path)
diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py
index 5d34909fd1..12f1e1aea1 100644
--- a/src/openai/resources/responses/responses.py
+++ b/src/openai/resources/responses/responses.py
@@ -58,7 +58,7 @@
from ...types.responses.parsed_response import ParsedResponse
from ...lib.streaming.responses._responses import ResponseStreamManager, AsyncResponseStreamManager
from ...types.responses.compacted_response import CompactedResponse
-from ...types.websocket_connection_options import WebsocketConnectionOptions
+from ...types.websocket_connection_options import WebSocketConnectionOptions
from ...types.responses.response_includable import ResponseIncludable
from ...types.shared_params.responses_model import ResponsesModel
from ...types.responses.response_input_param import ResponseInputParam
@@ -71,8 +71,8 @@
from ...types.responses.responses_client_event_param import ResponsesClientEventParam
if TYPE_CHECKING:
- from websockets.sync.client import ClientConnection as WebsocketConnection
- from websockets.asyncio.client import ClientConnection as AsyncWebsocketConnection
+ from websockets.sync.client import ClientConnection as WebSocketConnection
+ from websockets.asyncio.client import ClientConnection as AsyncWebSocketConnection
from ..._client import OpenAI, AsyncOpenAI
@@ -1730,7 +1730,7 @@ def connect(
self,
extra_query: Query = {},
extra_headers: Headers = {},
- websocket_connection_options: WebsocketConnectionOptions = {},
+ websocket_connection_options: WebSocketConnectionOptions = {},
) -> ResponsesConnectionManager:
"""Connect to a persistent Responses API WebSocket.
@@ -3397,7 +3397,7 @@ def connect(
self,
extra_query: Query = {},
extra_headers: Headers = {},
- websocket_connection_options: WebsocketConnectionOptions = {},
+ websocket_connection_options: WebSocketConnectionOptions = {},
) -> AsyncResponsesConnectionManager:
"""Connect to a persistent Responses API WebSocket.
@@ -3576,9 +3576,9 @@ class AsyncResponsesConnection:
response: AsyncResponsesResponseResource
- _connection: AsyncWebsocketConnection
+ _connection: AsyncWebSocketConnection
- def __init__(self, connection: AsyncWebsocketConnection) -> None:
+ def __init__(self, connection: AsyncWebSocketConnection) -> None:
self._connection = connection
self.response = AsyncResponsesResponseResource(self)
@@ -3613,7 +3613,7 @@ async def recv_bytes(self) -> bytes:
then you can call `.parse_event(data)`.
"""
message = await self._connection.recv(decode=False)
- log.debug(f"Received websocket message: %s", message)
+ log.debug(f"Received WebSocket message: %s", message)
return message
async def send(self, event: ResponsesClientEvent | ResponsesClientEventParam) -> None:
@@ -3665,7 +3665,7 @@ def __init__(
client: AsyncOpenAI,
extra_query: Query,
extra_headers: Headers,
- websocket_connection_options: WebsocketConnectionOptions,
+ websocket_connection_options: WebSocketConnectionOptions,
) -> None:
self.__client = client
self.__connection: AsyncResponsesConnection | None = None
@@ -3723,7 +3723,9 @@ def _prepare_url(self) -> httpx.URL:
if self.__client.websocket_base_url is not None:
base_url = httpx.URL(self.__client.websocket_base_url)
else:
- base_url = self.__client._base_url.copy_with(scheme="wss")
+ scheme = self.__client._base_url.scheme
+ ws_scheme = "ws" if scheme == "http" else "wss"
+ base_url = self.__client._base_url.copy_with(scheme=ws_scheme)
merge_raw_path = base_url.raw_path.rstrip(b"/") + b"/responses"
return base_url.copy_with(raw_path=merge_raw_path)
@@ -3740,9 +3742,9 @@ class ResponsesConnection:
response: ResponsesResponseResource
- _connection: WebsocketConnection
+ _connection: WebSocketConnection
- def __init__(self, connection: WebsocketConnection) -> None:
+ def __init__(self, connection: WebSocketConnection) -> None:
self._connection = connection
self.response = ResponsesResponseResource(self)
@@ -3777,7 +3779,7 @@ def recv_bytes(self) -> bytes:
then you can call `.parse_event(data)`.
"""
message = self._connection.recv(decode=False)
- log.debug(f"Received websocket message: %s", message)
+ log.debug(f"Received WebSocket message: %s", message)
return message
def send(self, event: ResponsesClientEvent | ResponsesClientEventParam) -> None:
@@ -3829,7 +3831,7 @@ def __init__(
client: OpenAI,
extra_query: Query,
extra_headers: Headers,
- websocket_connection_options: WebsocketConnectionOptions,
+ websocket_connection_options: WebSocketConnectionOptions,
) -> None:
self.__client = client
self.__connection: ResponsesConnection | None = None
@@ -3887,7 +3889,9 @@ def _prepare_url(self) -> httpx.URL:
if self.__client.websocket_base_url is not None:
base_url = httpx.URL(self.__client.websocket_base_url)
else:
- base_url = self.__client._base_url.copy_with(scheme="wss")
+ scheme = self.__client._base_url.scheme
+ ws_scheme = "ws" if scheme == "http" else "wss"
+ base_url = self.__client._base_url.copy_with(scheme=ws_scheme)
merge_raw_path = base_url.raw_path.rstrip(b"/") + b"/responses"
return base_url.copy_with(raw_path=merge_raw_path)
diff --git a/src/openai/resources/videos.py b/src/openai/resources/videos.py
index 51df6da4d3..f387f55824 100644
--- a/src/openai/resources/videos.py
+++ b/src/openai/resources/videos.py
@@ -11,9 +11,12 @@
from ..types import (
VideoSize,
VideoSeconds,
+ video_edit_params,
video_list_params,
video_remix_params,
video_create_params,
+ video_extend_params,
+ video_create_character_params,
video_download_content_params,
)
from .._types import Body, Omit, Query, Headers, NotGiven, FileTypes, omit, not_given
@@ -36,6 +39,8 @@
from ..types.video_seconds import VideoSeconds
from ..types.video_model_param import VideoModelParam
from ..types.video_delete_response import VideoDeleteResponse
+from ..types.video_get_character_response import VideoGetCharacterResponse
+from ..types.video_create_character_response import VideoCreateCharacterResponse
__all__ = ["Videos", "AsyncVideos"]
@@ -64,7 +69,7 @@ def create(
self,
*,
prompt: str,
- input_reference: FileTypes | Omit = omit,
+ input_reference: video_create_params.InputReference | Omit = omit,
model: VideoModelParam | Omit = omit,
seconds: VideoSeconds | Omit = omit,
size: VideoSize | Omit = omit,
@@ -81,7 +86,7 @@ def create(
Args:
prompt: Text prompt that describes the video to generate.
- input_reference: Optional multipart reference asset that guides generation.
+ input_reference: Optional reference asset upload or reference object that guides generation.
model: The video generation model to use (allowed values: sora-2, sora-2-pro). Defaults
to `sora-2`.
@@ -109,11 +114,10 @@ def create(
}
)
files = extract_files(cast(Mapping[str, object], body), paths=[["input_reference"]])
- if files:
- # It should be noted that the actual Content-Type header that will be
- # sent to the server will contain a `boundary` parameter, e.g.
- # multipart/form-data; boundary=---abc--
- extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})}
+ # It should be noted that the actual Content-Type header that will be
+ # sent to the server will contain a `boundary` parameter, e.g.
+ # multipart/form-data; boundary=---abc--
+ extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})}
return self._post(
"/videos",
body=maybe_transform(body, video_create_params.VideoCreateParams),
@@ -128,7 +132,7 @@ def create_and_poll(
self,
*,
prompt: str,
- input_reference: FileTypes | Omit = omit,
+ input_reference: video_create_params.InputReference | Omit = omit,
model: VideoModelParam | Omit = omit,
seconds: VideoSeconds | Omit = omit,
size: VideoSize | Omit = omit,
@@ -315,6 +319,55 @@ def delete(
cast_to=VideoDeleteResponse,
)
+ def create_character(
+ self,
+ *,
+ name: str,
+ video: FileTypes,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> VideoCreateCharacterResponse:
+ """
+ Create a character from an uploaded video.
+
+ Args:
+ name: Display name for this API character.
+
+ video: Video file used to create a character.
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ body = deepcopy_minimal(
+ {
+ "name": name,
+ "video": video,
+ }
+ )
+ files = extract_files(cast(Mapping[str, object], body), paths=[["video"]])
+ # It should be noted that the actual Content-Type header that will be
+ # sent to the server will contain a `boundary` parameter, e.g.
+ # multipart/form-data; boundary=---abc--
+ extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})}
+ return self._post(
+ "/videos/characters",
+ body=maybe_transform(body, video_create_character_params.VideoCreateCharacterParams),
+ files=files,
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=VideoCreateCharacterResponse,
+ )
+
def download_content(
self,
video_id: str,
@@ -358,6 +411,143 @@ def download_content(
cast_to=_legacy_response.HttpxBinaryResponseContent,
)
+ def edit(
+ self,
+ *,
+ prompt: str,
+ video: video_edit_params.Video,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> Video:
+ """
+ Create a new video generation job by editing a source video or existing
+ generated video.
+
+ Args:
+ prompt: Text prompt that describes how to edit the source video.
+
+ video: Reference to the completed video to edit.
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ body = deepcopy_minimal(
+ {
+ "prompt": prompt,
+ "video": video,
+ }
+ )
+ files = extract_files(cast(Mapping[str, object], body), paths=[["video"]])
+ # It should be noted that the actual Content-Type header that will be
+ # sent to the server will contain a `boundary` parameter, e.g.
+ # multipart/form-data; boundary=---abc--
+ extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})}
+ return self._post(
+ "/videos/edits",
+ body=maybe_transform(body, video_edit_params.VideoEditParams),
+ files=files,
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=Video,
+ )
+
+ def extend(
+ self,
+ *,
+ prompt: str,
+ seconds: VideoSeconds,
+ video: video_extend_params.Video,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> Video:
+ """
+ Create an extension of a completed video.
+
+ Args:
+ prompt: Updated text prompt that directs the extension generation.
+
+ seconds: Length of the newly generated extension segment in seconds (allowed values: 4,
+ 8, 12, 16, 20).
+
+ video: Reference to the completed video to extend.
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ body = deepcopy_minimal(
+ {
+ "prompt": prompt,
+ "seconds": seconds,
+ "video": video,
+ }
+ )
+ files = extract_files(cast(Mapping[str, object], body), paths=[["video"]])
+ # It should be noted that the actual Content-Type header that will be
+ # sent to the server will contain a `boundary` parameter, e.g.
+ # multipart/form-data; boundary=---abc--
+ extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})}
+ return self._post(
+ "/videos/extensions",
+ body=maybe_transform(body, video_extend_params.VideoExtendParams),
+ files=files,
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=Video,
+ )
+
+ def get_character(
+ self,
+ character_id: str,
+ *,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> VideoGetCharacterResponse:
+ """
+ Fetch a character.
+
+ Args:
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ if not character_id:
+ raise ValueError(f"Expected a non-empty value for `character_id` but received {character_id!r}")
+ return self._get(
+ f"/videos/characters/{character_id}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=VideoGetCharacterResponse,
+ )
+
def remix(
self,
video_id: str,
@@ -420,7 +610,7 @@ async def create(
self,
*,
prompt: str,
- input_reference: FileTypes | Omit = omit,
+ input_reference: video_create_params.InputReference | Omit = omit,
model: VideoModelParam | Omit = omit,
seconds: VideoSeconds | Omit = omit,
size: VideoSize | Omit = omit,
@@ -437,7 +627,7 @@ async def create(
Args:
prompt: Text prompt that describes the video to generate.
- input_reference: Optional multipart reference asset that guides generation.
+ input_reference: Optional reference asset upload or reference object that guides generation.
model: The video generation model to use (allowed values: sora-2, sora-2-pro). Defaults
to `sora-2`.
@@ -465,11 +655,10 @@ async def create(
}
)
files = extract_files(cast(Mapping[str, object], body), paths=[["input_reference"]])
- if files:
- # It should be noted that the actual Content-Type header that will be
- # sent to the server will contain a `boundary` parameter, e.g.
- # multipart/form-data; boundary=---abc--
- extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})}
+ # It should be noted that the actual Content-Type header that will be
+ # sent to the server will contain a `boundary` parameter, e.g.
+ # multipart/form-data; boundary=---abc--
+ extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})}
return await self._post(
"/videos",
body=await async_maybe_transform(body, video_create_params.VideoCreateParams),
@@ -484,7 +673,7 @@ async def create_and_poll(
self,
*,
prompt: str,
- input_reference: FileTypes | Omit = omit,
+ input_reference: video_create_params.InputReference | Omit = omit,
model: VideoModelParam | Omit = omit,
seconds: VideoSeconds | Omit = omit,
size: VideoSize | Omit = omit,
@@ -671,6 +860,55 @@ async def delete(
cast_to=VideoDeleteResponse,
)
+ async def create_character(
+ self,
+ *,
+ name: str,
+ video: FileTypes,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> VideoCreateCharacterResponse:
+ """
+ Create a character from an uploaded video.
+
+ Args:
+ name: Display name for this API character.
+
+ video: Video file used to create a character.
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ body = deepcopy_minimal(
+ {
+ "name": name,
+ "video": video,
+ }
+ )
+ files = extract_files(cast(Mapping[str, object], body), paths=[["video"]])
+ # It should be noted that the actual Content-Type header that will be
+ # sent to the server will contain a `boundary` parameter, e.g.
+ # multipart/form-data; boundary=---abc--
+ extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})}
+ return await self._post(
+ "/videos/characters",
+ body=await async_maybe_transform(body, video_create_character_params.VideoCreateCharacterParams),
+ files=files,
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=VideoCreateCharacterResponse,
+ )
+
async def download_content(
self,
video_id: str,
@@ -716,6 +954,143 @@ async def download_content(
cast_to=_legacy_response.HttpxBinaryResponseContent,
)
+ async def edit(
+ self,
+ *,
+ prompt: str,
+ video: video_edit_params.Video,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> Video:
+ """
+ Create a new video generation job by editing a source video or existing
+ generated video.
+
+ Args:
+ prompt: Text prompt that describes how to edit the source video.
+
+ video: Reference to the completed video to edit.
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ body = deepcopy_minimal(
+ {
+ "prompt": prompt,
+ "video": video,
+ }
+ )
+ files = extract_files(cast(Mapping[str, object], body), paths=[["video"]])
+ # It should be noted that the actual Content-Type header that will be
+ # sent to the server will contain a `boundary` parameter, e.g.
+ # multipart/form-data; boundary=---abc--
+ extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})}
+ return await self._post(
+ "/videos/edits",
+ body=await async_maybe_transform(body, video_edit_params.VideoEditParams),
+ files=files,
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=Video,
+ )
+
+ async def extend(
+ self,
+ *,
+ prompt: str,
+ seconds: VideoSeconds,
+ video: video_extend_params.Video,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> Video:
+ """
+ Create an extension of a completed video.
+
+ Args:
+ prompt: Updated text prompt that directs the extension generation.
+
+ seconds: Length of the newly generated extension segment in seconds (allowed values: 4,
+ 8, 12, 16, 20).
+
+ video: Reference to the completed video to extend.
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ body = deepcopy_minimal(
+ {
+ "prompt": prompt,
+ "seconds": seconds,
+ "video": video,
+ }
+ )
+ files = extract_files(cast(Mapping[str, object], body), paths=[["video"]])
+ # It should be noted that the actual Content-Type header that will be
+ # sent to the server will contain a `boundary` parameter, e.g.
+ # multipart/form-data; boundary=---abc--
+ extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})}
+ return await self._post(
+ "/videos/extensions",
+ body=await async_maybe_transform(body, video_extend_params.VideoExtendParams),
+ files=files,
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=Video,
+ )
+
+ async def get_character(
+ self,
+ character_id: str,
+ *,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> VideoGetCharacterResponse:
+ """
+ Fetch a character.
+
+ Args:
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ if not character_id:
+ raise ValueError(f"Expected a non-empty value for `character_id` but received {character_id!r}")
+ return await self._get(
+ f"/videos/characters/{character_id}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=VideoGetCharacterResponse,
+ )
+
async def remix(
self,
video_id: str,
@@ -770,9 +1145,21 @@ def __init__(self, videos: Videos) -> None:
self.delete = _legacy_response.to_raw_response_wrapper(
videos.delete,
)
+ self.create_character = _legacy_response.to_raw_response_wrapper(
+ videos.create_character,
+ )
self.download_content = _legacy_response.to_raw_response_wrapper(
videos.download_content,
)
+ self.edit = _legacy_response.to_raw_response_wrapper(
+ videos.edit,
+ )
+ self.extend = _legacy_response.to_raw_response_wrapper(
+ videos.extend,
+ )
+ self.get_character = _legacy_response.to_raw_response_wrapper(
+ videos.get_character,
+ )
self.remix = _legacy_response.to_raw_response_wrapper(
videos.remix,
)
@@ -794,9 +1181,21 @@ def __init__(self, videos: AsyncVideos) -> None:
self.delete = _legacy_response.async_to_raw_response_wrapper(
videos.delete,
)
+ self.create_character = _legacy_response.async_to_raw_response_wrapper(
+ videos.create_character,
+ )
self.download_content = _legacy_response.async_to_raw_response_wrapper(
videos.download_content,
)
+ self.edit = _legacy_response.async_to_raw_response_wrapper(
+ videos.edit,
+ )
+ self.extend = _legacy_response.async_to_raw_response_wrapper(
+ videos.extend,
+ )
+ self.get_character = _legacy_response.async_to_raw_response_wrapper(
+ videos.get_character,
+ )
self.remix = _legacy_response.async_to_raw_response_wrapper(
videos.remix,
)
@@ -818,10 +1217,22 @@ def __init__(self, videos: Videos) -> None:
self.delete = to_streamed_response_wrapper(
videos.delete,
)
+ self.create_character = to_streamed_response_wrapper(
+ videos.create_character,
+ )
self.download_content = to_custom_streamed_response_wrapper(
videos.download_content,
StreamedBinaryAPIResponse,
)
+ self.edit = to_streamed_response_wrapper(
+ videos.edit,
+ )
+ self.extend = to_streamed_response_wrapper(
+ videos.extend,
+ )
+ self.get_character = to_streamed_response_wrapper(
+ videos.get_character,
+ )
self.remix = to_streamed_response_wrapper(
videos.remix,
)
@@ -843,10 +1254,22 @@ def __init__(self, videos: AsyncVideos) -> None:
self.delete = async_to_streamed_response_wrapper(
videos.delete,
)
+ self.create_character = async_to_streamed_response_wrapper(
+ videos.create_character,
+ )
self.download_content = async_to_custom_streamed_response_wrapper(
videos.download_content,
AsyncStreamedBinaryAPIResponse,
)
+ self.edit = async_to_streamed_response_wrapper(
+ videos.edit,
+ )
+ self.extend = async_to_streamed_response_wrapper(
+ videos.extend,
+ )
+ self.get_character = async_to_streamed_response_wrapper(
+ videos.get_character,
+ )
self.remix = async_to_streamed_response_wrapper(
videos.remix,
)
diff --git a/src/openai/types/__init__.py b/src/openai/types/__init__.py
index 9190bc146c..d8dbea71ad 100644
--- a/src/openai/types/__init__.py
+++ b/src/openai/types/__init__.py
@@ -56,6 +56,7 @@
from .completion_choice import CompletionChoice as CompletionChoice
from .image_edit_params import ImageEditParams as ImageEditParams
from .skill_list_params import SkillListParams as SkillListParams
+from .video_edit_params import VideoEditParams as VideoEditParams
from .video_list_params import VideoListParams as VideoListParams
from .video_model_param import VideoModelParam as VideoModelParam
from .eval_create_params import EvalCreateParams as EvalCreateParams
@@ -68,6 +69,7 @@
from .skill_create_params import SkillCreateParams as SkillCreateParams
from .skill_update_params import SkillUpdateParams as SkillUpdateParams
from .video_create_params import VideoCreateParams as VideoCreateParams
+from .video_extend_params import VideoExtendParams as VideoExtendParams
from .batch_request_counts import BatchRequestCounts as BatchRequestCounts
from .eval_create_response import EvalCreateResponse as EvalCreateResponse
from .eval_delete_response import EvalDeleteResponse as EvalDeleteResponse
@@ -98,16 +100,23 @@
from .vector_store_search_params import VectorStoreSearchParams as VectorStoreSearchParams
from .vector_store_update_params import VectorStoreUpdateParams as VectorStoreUpdateParams
from .container_retrieve_response import ContainerRetrieveResponse as ContainerRetrieveResponse
+from .image_input_reference_param import ImageInputReferenceParam as ImageInputReferenceParam
from .moderation_text_input_param import ModerationTextInputParam as ModerationTextInputParam
from .file_chunking_strategy_param import FileChunkingStrategyParam as FileChunkingStrategyParam
from .vector_store_search_response import VectorStoreSearchResponse as VectorStoreSearchResponse
-from .websocket_connection_options import WebsocketConnectionOptions as WebsocketConnectionOptions
+from .video_get_character_response import VideoGetCharacterResponse as VideoGetCharacterResponse
+from .websocket_connection_options import (
+ WebSocketConnectionOptions as WebSocketConnectionOptions,
+ WebsocketConnectionOptions as WebsocketConnectionOptions,
+)
from .image_create_variation_params import ImageCreateVariationParams as ImageCreateVariationParams
from .image_gen_partial_image_event import ImageGenPartialImageEvent as ImageGenPartialImageEvent
from .static_file_chunking_strategy import StaticFileChunkingStrategy as StaticFileChunkingStrategy
+from .video_create_character_params import VideoCreateCharacterParams as VideoCreateCharacterParams
from .video_download_content_params import VideoDownloadContentParams as VideoDownloadContentParams
from .eval_custom_data_source_config import EvalCustomDataSourceConfig as EvalCustomDataSourceConfig
from .image_edit_partial_image_event import ImageEditPartialImageEvent as ImageEditPartialImageEvent
+from .video_create_character_response import VideoCreateCharacterResponse as VideoCreateCharacterResponse
from .moderation_image_url_input_param import ModerationImageURLInputParam as ModerationImageURLInputParam
from .auto_file_chunking_strategy_param import AutoFileChunkingStrategyParam as AutoFileChunkingStrategyParam
from .moderation_multi_modal_input_param import ModerationMultiModalInputParam as ModerationMultiModalInputParam
diff --git a/src/openai/types/audio/speech_create_params.py b/src/openai/types/audio/speech_create_params.py
index 417df5b218..1c0472ea85 100644
--- a/src/openai/types/audio/speech_create_params.py
+++ b/src/openai/types/audio/speech_create_params.py
@@ -3,11 +3,11 @@
from __future__ import annotations
from typing import Union
-from typing_extensions import Literal, Required, TypedDict
+from typing_extensions import Literal, Required, TypeAlias, TypedDict
from .speech_model import SpeechModel
-__all__ = ["SpeechCreateParams"]
+__all__ = ["SpeechCreateParams", "Voice", "VoiceID"]
class SpeechCreateParams(TypedDict, total=False):
@@ -20,14 +20,13 @@ class SpeechCreateParams(TypedDict, total=False):
`tts-1`, `tts-1-hd`, `gpt-4o-mini-tts`, or `gpt-4o-mini-tts-2025-12-15`.
"""
- voice: Required[
- Union[str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"]]
- ]
+ voice: Required[Voice]
"""The voice to use when generating the audio.
Supported built-in voices are `alloy`, `ash`, `ballad`, `coral`, `echo`,
- `fable`, `onyx`, `nova`, `sage`, `shimmer`, `verse`, `marin`, and `cedar`.
- Previews of the voices are available in the
+ `fable`, `onyx`, `nova`, `sage`, `shimmer`, `verse`, `marin`, and `cedar`. You
+ may also provide a custom voice object with an `id`, for example
+ `{ "id": "voice_1234" }`. Previews of the voices are available in the
[Text to speech guide](https://platform.openai.com/docs/guides/text-to-speech#voice-options).
"""
@@ -55,3 +54,15 @@ class SpeechCreateParams(TypedDict, total=False):
Supported formats are `sse` and `audio`. `sse` is not supported for `tts-1` or
`tts-1-hd`.
"""
+
+
+class VoiceID(TypedDict, total=False):
+ """Custom voice reference."""
+
+ id: Required[str]
+ """The custom voice ID, e.g. `voice_1234`."""
+
+
+Voice: TypeAlias = Union[
+ str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"], VoiceID
+]
diff --git a/src/openai/types/chat/chat_completion_audio_param.py b/src/openai/types/chat/chat_completion_audio_param.py
index 1a73bb0c7e..fe64ba49aa 100644
--- a/src/openai/types/chat/chat_completion_audio_param.py
+++ b/src/openai/types/chat/chat_completion_audio_param.py
@@ -3,9 +3,21 @@
from __future__ import annotations
from typing import Union
-from typing_extensions import Literal, Required, TypedDict
+from typing_extensions import Literal, Required, TypeAlias, TypedDict
-__all__ = ["ChatCompletionAudioParam"]
+__all__ = ["ChatCompletionAudioParam", "Voice", "VoiceID"]
+
+
+class VoiceID(TypedDict, total=False):
+ """Custom voice reference."""
+
+ id: Required[str]
+ """The custom voice ID, e.g. `voice_1234`."""
+
+
+Voice: TypeAlias = Union[
+ str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"], VoiceID
+]
class ChatCompletionAudioParam(TypedDict, total=False):
@@ -21,11 +33,11 @@ class ChatCompletionAudioParam(TypedDict, total=False):
Must be one of `wav`, `mp3`, `flac`, `opus`, or `pcm16`.
"""
- voice: Required[
- Union[str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"]]
- ]
+ voice: Required[Voice]
"""The voice the model uses to respond.
Supported built-in voices are `alloy`, `ash`, `ballad`, `coral`, `echo`,
- `fable`, `nova`, `onyx`, `sage`, `shimmer`, `marin`, and `cedar`.
+ `fable`, `nova`, `onyx`, `sage`, `shimmer`, `marin`, and `cedar`. You may also
+ provide a custom voice object with an `id`, for example
+ `{ "id": "voice_1234" }`.
"""
diff --git a/src/openai/types/image_input_reference_param.py b/src/openai/types/image_input_reference_param.py
new file mode 100644
index 0000000000..1065632910
--- /dev/null
+++ b/src/openai/types/image_input_reference_param.py
@@ -0,0 +1,14 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import TypedDict
+
+__all__ = ["ImageInputReferenceParam"]
+
+
+class ImageInputReferenceParam(TypedDict, total=False):
+ file_id: str
+
+ image_url: str
+ """A fully qualified URL or base64-encoded data URL."""
diff --git a/src/openai/types/realtime/realtime_audio_config_output.py b/src/openai/types/realtime/realtime_audio_config_output.py
index 2922405f63..143cef67a5 100644
--- a/src/openai/types/realtime/realtime_audio_config_output.py
+++ b/src/openai/types/realtime/realtime_audio_config_output.py
@@ -1,12 +1,24 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import Union, Optional
-from typing_extensions import Literal
+from typing_extensions import Literal, TypeAlias
from ..._models import BaseModel
from .realtime_audio_formats import RealtimeAudioFormats
-__all__ = ["RealtimeAudioConfigOutput"]
+__all__ = ["RealtimeAudioConfigOutput", "Voice", "VoiceID"]
+
+
+class VoiceID(BaseModel):
+ """Custom voice reference."""
+
+ id: str
+ """The custom voice ID, e.g. `voice_1234`."""
+
+
+Voice: TypeAlias = Union[
+ str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"], VoiceID
+]
class RealtimeAudioConfigOutput(BaseModel):
@@ -24,13 +36,12 @@ class RealtimeAudioConfigOutput(BaseModel):
generated, it's also possible to prompt the model to speak faster or slower.
"""
- voice: Union[
- str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"], None
- ] = None
+ voice: Optional[Voice] = None
"""The voice the model uses to respond.
Supported built-in voices are `alloy`, `ash`, `ballad`, `coral`, `echo`, `sage`,
- `shimmer`, `verse`, `marin`, and `cedar`. Voice cannot be changed during the
- session once the model has responded with audio at least once. We recommend
- `marin` and `cedar` for best quality.
+ `shimmer`, `verse`, `marin`, and `cedar`. You may also provide a custom voice
+ object with an `id`, for example `{ "id": "voice_1234" }`. Voice cannot be
+ changed during the session once the model has responded with audio at least
+ once. We recommend `marin` and `cedar` for best quality.
"""
diff --git a/src/openai/types/realtime/realtime_audio_config_output_param.py b/src/openai/types/realtime/realtime_audio_config_output_param.py
index d04fd3a303..5d920f69a6 100644
--- a/src/openai/types/realtime/realtime_audio_config_output_param.py
+++ b/src/openai/types/realtime/realtime_audio_config_output_param.py
@@ -3,11 +3,23 @@
from __future__ import annotations
from typing import Union
-from typing_extensions import Literal, TypedDict
+from typing_extensions import Literal, Required, TypeAlias, TypedDict
from .realtime_audio_formats_param import RealtimeAudioFormatsParam
-__all__ = ["RealtimeAudioConfigOutputParam"]
+__all__ = ["RealtimeAudioConfigOutputParam", "Voice", "VoiceID"]
+
+
+class VoiceID(TypedDict, total=False):
+ """Custom voice reference."""
+
+ id: Required[str]
+ """The custom voice ID, e.g. `voice_1234`."""
+
+
+Voice: TypeAlias = Union[
+ str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"], VoiceID
+]
class RealtimeAudioConfigOutputParam(TypedDict, total=False):
@@ -25,11 +37,12 @@ class RealtimeAudioConfigOutputParam(TypedDict, total=False):
generated, it's also possible to prompt the model to speak faster or slower.
"""
- voice: Union[str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"]]
+ voice: Voice
"""The voice the model uses to respond.
Supported built-in voices are `alloy`, `ash`, `ballad`, `coral`, `echo`, `sage`,
- `shimmer`, `verse`, `marin`, and `cedar`. Voice cannot be changed during the
- session once the model has responded with audio at least once. We recommend
- `marin` and `cedar` for best quality.
+ `shimmer`, `verse`, `marin`, and `cedar`. You may also provide a custom voice
+ object with an `id`, for example `{ "id": "voice_1234" }`. Voice cannot be
+ changed during the session once the model has responded with audio at least
+ once. We recommend `marin` and `cedar` for best quality.
"""
diff --git a/src/openai/types/realtime/realtime_response_create_audio_output.py b/src/openai/types/realtime/realtime_response_create_audio_output.py
index db02511ab1..7848357236 100644
--- a/src/openai/types/realtime/realtime_response_create_audio_output.py
+++ b/src/openai/types/realtime/realtime_response_create_audio_output.py
@@ -1,26 +1,38 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import Union, Optional
-from typing_extensions import Literal
+from typing_extensions import Literal, TypeAlias
from ..._models import BaseModel
from .realtime_audio_formats import RealtimeAudioFormats
-__all__ = ["RealtimeResponseCreateAudioOutput", "Output"]
+__all__ = ["RealtimeResponseCreateAudioOutput", "Output", "OutputVoice", "OutputVoiceID"]
+
+
+class OutputVoiceID(BaseModel):
+ """Custom voice reference."""
+
+ id: str
+ """The custom voice ID, e.g. `voice_1234`."""
+
+
+OutputVoice: TypeAlias = Union[
+ str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"], OutputVoiceID
+]
class Output(BaseModel):
format: Optional[RealtimeAudioFormats] = None
"""The format of the output audio."""
- voice: Union[
- str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"], None
- ] = None
+ voice: Optional[OutputVoice] = None
"""The voice the model uses to respond.
Supported built-in voices are `alloy`, `ash`, `ballad`, `coral`, `echo`, `sage`,
- `shimmer`, `verse`, `marin`, and `cedar`. Voice cannot be changed during the
- session once the model has responded with audio at least once.
+ `shimmer`, `verse`, `marin`, and `cedar`. You may also provide a custom voice
+ object with an `id`, for example `{ "id": "voice_1234" }`. Voice cannot be
+ changed during the session once the model has responded with audio at least
+ once. We recommend `marin` and `cedar` for best quality.
"""
diff --git a/src/openai/types/realtime/realtime_response_create_audio_output_param.py b/src/openai/types/realtime/realtime_response_create_audio_output_param.py
index 22787ad106..bb930f5488 100644
--- a/src/openai/types/realtime/realtime_response_create_audio_output_param.py
+++ b/src/openai/types/realtime/realtime_response_create_audio_output_param.py
@@ -3,23 +3,37 @@
from __future__ import annotations
from typing import Union
-from typing_extensions import Literal, TypedDict
+from typing_extensions import Literal, Required, TypeAlias, TypedDict
from .realtime_audio_formats_param import RealtimeAudioFormatsParam
-__all__ = ["RealtimeResponseCreateAudioOutputParam", "Output"]
+__all__ = ["RealtimeResponseCreateAudioOutputParam", "Output", "OutputVoice", "OutputVoiceID"]
+
+
+class OutputVoiceID(TypedDict, total=False):
+ """Custom voice reference."""
+
+ id: Required[str]
+ """The custom voice ID, e.g. `voice_1234`."""
+
+
+OutputVoice: TypeAlias = Union[
+ str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"], OutputVoiceID
+]
class Output(TypedDict, total=False):
format: RealtimeAudioFormatsParam
"""The format of the output audio."""
- voice: Union[str, Literal["alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse", "marin", "cedar"]]
+ voice: OutputVoice
"""The voice the model uses to respond.
Supported built-in voices are `alloy`, `ash`, `ballad`, `coral`, `echo`, `sage`,
- `shimmer`, `verse`, `marin`, and `cedar`. Voice cannot be changed during the
- session once the model has responded with audio at least once.
+ `shimmer`, `verse`, `marin`, and `cedar`. You may also provide a custom voice
+ object with an `id`, for example `{ "id": "voice_1234" }`. Voice cannot be
+ changed during the session once the model has responded with audio at least
+ once. We recommend `marin` and `cedar` for best quality.
"""
diff --git a/src/openai/types/responses/response_input_file.py b/src/openai/types/responses/response_input_file.py
index 97cc176f35..3e5fb70c5f 100644
--- a/src/openai/types/responses/response_input_file.py
+++ b/src/openai/types/responses/response_input_file.py
@@ -14,12 +14,6 @@ class ResponseInputFile(BaseModel):
type: Literal["input_file"]
"""The type of the input item. Always `input_file`."""
- detail: Optional[Literal["low", "high"]] = None
- """The detail level of the file to be sent to the model.
-
- One of `high` or `low`. Defaults to `high`.
- """
-
file_data: Optional[str] = None
"""The content of the file to be sent to the model."""
diff --git a/src/openai/types/responses/response_input_file_content.py b/src/openai/types/responses/response_input_file_content.py
index 7b1c76bff7..f0dfef55d0 100644
--- a/src/openai/types/responses/response_input_file_content.py
+++ b/src/openai/types/responses/response_input_file_content.py
@@ -14,12 +14,6 @@ class ResponseInputFileContent(BaseModel):
type: Literal["input_file"]
"""The type of the input item. Always `input_file`."""
- detail: Optional[Literal["high", "low"]] = None
- """The detail level of the file to be sent to the model.
-
- One of `high` or `low`. Defaults to `high`.
- """
-
file_data: Optional[str] = None
"""The base64-encoded data of the file to be sent to the model."""
diff --git a/src/openai/types/responses/response_input_file_content_param.py b/src/openai/types/responses/response_input_file_content_param.py
index 73e8acd27b..376f6c7a45 100644
--- a/src/openai/types/responses/response_input_file_content_param.py
+++ b/src/openai/types/responses/response_input_file_content_param.py
@@ -14,12 +14,6 @@ class ResponseInputFileContentParam(TypedDict, total=False):
type: Required[Literal["input_file"]]
"""The type of the input item. Always `input_file`."""
- detail: Literal["high", "low"]
- """The detail level of the file to be sent to the model.
-
- One of `high` or `low`. Defaults to `high`.
- """
-
file_data: Optional[str]
"""The base64-encoded data of the file to be sent to the model."""
diff --git a/src/openai/types/responses/response_input_file_param.py b/src/openai/types/responses/response_input_file_param.py
index 25eec2fe01..8b5da20245 100644
--- a/src/openai/types/responses/response_input_file_param.py
+++ b/src/openai/types/responses/response_input_file_param.py
@@ -14,12 +14,6 @@ class ResponseInputFileParam(TypedDict, total=False):
type: Required[Literal["input_file"]]
"""The type of the input item. Always `input_file`."""
- detail: Literal["low", "high"]
- """The detail level of the file to be sent to the model.
-
- One of `high` or `low`. Defaults to `high`.
- """
-
file_data: str
"""The content of the file to be sent to the model."""
diff --git a/src/openai/types/video_create_character_params.py b/src/openai/types/video_create_character_params.py
new file mode 100644
index 0000000000..ef671e598f
--- /dev/null
+++ b/src/openai/types/video_create_character_params.py
@@ -0,0 +1,17 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Required, TypedDict
+
+from .._types import FileTypes
+
+__all__ = ["VideoCreateCharacterParams"]
+
+
+class VideoCreateCharacterParams(TypedDict, total=False):
+ name: Required[str]
+ """Display name for this API character."""
+
+ video: Required[FileTypes]
+ """Video file used to create a character."""
diff --git a/src/openai/types/video_create_character_response.py b/src/openai/types/video_create_character_response.py
new file mode 100644
index 0000000000..e3a65a0200
--- /dev/null
+++ b/src/openai/types/video_create_character_response.py
@@ -0,0 +1,18 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Optional
+
+from .._models import BaseModel
+
+__all__ = ["VideoCreateCharacterResponse"]
+
+
+class VideoCreateCharacterResponse(BaseModel):
+ id: Optional[str] = None
+ """Identifier for the character creation cameo."""
+
+ created_at: int
+ """Unix timestamp (in seconds) when the character was created."""
+
+ name: Optional[str] = None
+ """Display name for the character."""
diff --git a/src/openai/types/video_create_params.py b/src/openai/types/video_create_params.py
index 282b1db429..641ac7db45 100644
--- a/src/openai/types/video_create_params.py
+++ b/src/openai/types/video_create_params.py
@@ -2,22 +2,24 @@
from __future__ import annotations
-from typing_extensions import Required, TypedDict
+from typing import Union
+from typing_extensions import Required, TypeAlias, TypedDict
from .._types import FileTypes
from .video_size import VideoSize
from .video_seconds import VideoSeconds
from .video_model_param import VideoModelParam
+from .image_input_reference_param import ImageInputReferenceParam
-__all__ = ["VideoCreateParams"]
+__all__ = ["VideoCreateParams", "InputReference"]
class VideoCreateParams(TypedDict, total=False):
prompt: Required[str]
"""Text prompt that describes the video to generate."""
- input_reference: FileTypes
- """Optional multipart reference asset that guides generation."""
+ input_reference: InputReference
+ """Optional reference asset upload or reference object that guides generation."""
model: VideoModelParam
"""The video generation model to use (allowed values: sora-2, sora-2-pro).
@@ -33,3 +35,6 @@ class VideoCreateParams(TypedDict, total=False):
Output resolution formatted as width x height (allowed values: 720x1280,
1280x720, 1024x1792, 1792x1024). Defaults to 720x1280.
"""
+
+
+InputReference: TypeAlias = Union[FileTypes, ImageInputReferenceParam]
diff --git a/src/openai/types/video_edit_params.py b/src/openai/types/video_edit_params.py
new file mode 100644
index 0000000000..8d3b15fc6f
--- /dev/null
+++ b/src/openai/types/video_edit_params.py
@@ -0,0 +1,28 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Union
+from typing_extensions import Required, TypeAlias, TypedDict
+
+from .._types import FileTypes
+
+__all__ = ["VideoEditParams", "Video", "VideoVideoReferenceInputParam"]
+
+
+class VideoEditParams(TypedDict, total=False):
+ prompt: Required[str]
+ """Text prompt that describes how to edit the source video."""
+
+ video: Required[Video]
+ """Reference to the completed video to edit."""
+
+
+class VideoVideoReferenceInputParam(TypedDict, total=False):
+ """Reference to the completed video."""
+
+ id: Required[str]
+ """The identifier of the completed video."""
+
+
+Video: TypeAlias = Union[FileTypes, VideoVideoReferenceInputParam]
diff --git a/src/openai/types/video_extend_params.py b/src/openai/types/video_extend_params.py
new file mode 100644
index 0000000000..65be4b5270
--- /dev/null
+++ b/src/openai/types/video_extend_params.py
@@ -0,0 +1,35 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Union
+from typing_extensions import Required, TypeAlias, TypedDict
+
+from .._types import FileTypes
+from .video_seconds import VideoSeconds
+
+__all__ = ["VideoExtendParams", "Video", "VideoVideoReferenceInputParam"]
+
+
+class VideoExtendParams(TypedDict, total=False):
+ prompt: Required[str]
+ """Updated text prompt that directs the extension generation."""
+
+ seconds: Required[VideoSeconds]
+ """
+ Length of the newly generated extension segment in seconds (allowed values: 4,
+ 8, 12, 16, 20).
+ """
+
+ video: Required[Video]
+ """Reference to the completed video to extend."""
+
+
+class VideoVideoReferenceInputParam(TypedDict, total=False):
+ """Reference to the completed video."""
+
+ id: Required[str]
+ """The identifier of the completed video."""
+
+
+Video: TypeAlias = Union[FileTypes, VideoVideoReferenceInputParam]
diff --git a/src/openai/types/video_get_character_response.py b/src/openai/types/video_get_character_response.py
new file mode 100644
index 0000000000..df6202ed03
--- /dev/null
+++ b/src/openai/types/video_get_character_response.py
@@ -0,0 +1,18 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Optional
+
+from .._models import BaseModel
+
+__all__ = ["VideoGetCharacterResponse"]
+
+
+class VideoGetCharacterResponse(BaseModel):
+ id: Optional[str] = None
+ """Identifier for the character creation cameo."""
+
+ created_at: int
+ """Unix timestamp (in seconds) when the character was created."""
+
+ name: Optional[str] = None
+ """Display name for the character."""
diff --git a/src/openai/types/websocket_connection_options.py b/src/openai/types/websocket_connection_options.py
index 40fd24ab03..519e434124 100644
--- a/src/openai/types/websocket_connection_options.py
+++ b/src/openai/types/websocket_connection_options.py
@@ -3,15 +3,17 @@
from __future__ import annotations
from typing import TYPE_CHECKING
-from typing_extensions import Sequence, TypedDict
+from typing_extensions import Sequence, TypeAlias, TypedDict
+
+__all__ = ["WebSocketConnectionOptions", "WebsocketConnectionOptions"]
if TYPE_CHECKING:
from websockets import Subprotocol
from websockets.extensions import ClientExtensionFactory
-class WebsocketConnectionOptions(TypedDict, total=False):
- """Websocket connection options copied from `websockets`.
+class WebSocketConnectionOptions(TypedDict, total=False):
+ """WebSocket connection options copied from `websockets`.
For example: https://websockets.readthedocs.io/en/stable/reference/asyncio/client.html#websockets.asyncio.client.connect
"""
@@ -34,3 +36,7 @@ class WebsocketConnectionOptions(TypedDict, total=False):
write_limit: int | tuple[int, int | None]
"""High-water mark of write buffer in bytes. It is passed to set_write_buffer_limits(). It defaults to 32 KiB. You may pass a (high, low) tuple to set the high-water and low-water marks."""
+
+
+# Backward compatibility for pre-rename imports.
+WebsocketConnectionOptions: TypeAlias = WebSocketConnectionOptions
diff --git a/tests/api_resources/audio/test_speech.py b/tests/api_resources/audio/test_speech.py
index 2c77f38949..a42c77126d 100644
--- a/tests/api_resources/audio/test_speech.py
+++ b/tests/api_resources/audio/test_speech.py
@@ -28,7 +28,7 @@ def test_method_create(self, client: OpenAI, respx_mock: MockRouter) -> None:
speech = client.audio.speech.create(
input="string",
model="string",
- voice="ash",
+ voice="string",
)
assert isinstance(speech, _legacy_response.HttpxBinaryResponseContent)
assert speech.json() == {"foo": "bar"}
@@ -40,7 +40,7 @@ def test_method_create_with_all_params(self, client: OpenAI, respx_mock: MockRou
speech = client.audio.speech.create(
input="string",
model="string",
- voice="ash",
+ voice="string",
instructions="instructions",
response_format="mp3",
speed=0.25,
@@ -57,7 +57,7 @@ def test_raw_response_create(self, client: OpenAI, respx_mock: MockRouter) -> No
response = client.audio.speech.with_raw_response.create(
input="string",
model="string",
- voice="ash",
+ voice="string",
)
assert response.is_closed is True
@@ -72,7 +72,7 @@ def test_streaming_response_create(self, client: OpenAI, respx_mock: MockRouter)
with client.audio.speech.with_streaming_response.create(
input="string",
model="string",
- voice="ash",
+ voice="string",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -95,7 +95,7 @@ async def test_method_create(self, async_client: AsyncOpenAI, respx_mock: MockRo
speech = await async_client.audio.speech.create(
input="string",
model="string",
- voice="ash",
+ voice="string",
)
assert isinstance(speech, _legacy_response.HttpxBinaryResponseContent)
assert speech.json() == {"foo": "bar"}
@@ -107,7 +107,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI, re
speech = await async_client.audio.speech.create(
input="string",
model="string",
- voice="ash",
+ voice="string",
instructions="instructions",
response_format="mp3",
speed=0.25,
@@ -124,7 +124,7 @@ async def test_raw_response_create(self, async_client: AsyncOpenAI, respx_mock:
response = await async_client.audio.speech.with_raw_response.create(
input="string",
model="string",
- voice="ash",
+ voice="string",
)
assert response.is_closed is True
@@ -139,7 +139,7 @@ async def test_streaming_response_create(self, async_client: AsyncOpenAI, respx_
async with async_client.audio.speech.with_streaming_response.create(
input="string",
model="string",
- voice="ash",
+ voice="string",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
diff --git a/tests/api_resources/audio/test_transcriptions.py b/tests/api_resources/audio/test_transcriptions.py
index b5eaa4be1f..b4525937b4 100644
--- a/tests/api_resources/audio/test_transcriptions.py
+++ b/tests/api_resources/audio/test_transcriptions.py
@@ -20,7 +20,7 @@ class TestTranscriptions:
@parametrize
def test_method_create_overload_1(self, client: OpenAI) -> None:
transcription = client.audio.transcriptions.create(
- file=b"raw file contents",
+ file=b"Example data",
model="gpt-4o-transcribe",
)
assert_matches_type(TranscriptionCreateResponse, transcription, path=["response"])
@@ -28,7 +28,7 @@ def test_method_create_overload_1(self, client: OpenAI) -> None:
@parametrize
def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None:
transcription = client.audio.transcriptions.create(
- file=b"raw file contents",
+ file=b"Example data",
model="gpt-4o-transcribe",
chunking_strategy="auto",
include=["logprobs"],
@@ -46,7 +46,7 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None:
@parametrize
def test_raw_response_create_overload_1(self, client: OpenAI) -> None:
response = client.audio.transcriptions.with_raw_response.create(
- file=b"raw file contents",
+ file=b"Example data",
model="gpt-4o-transcribe",
)
@@ -58,7 +58,7 @@ def test_raw_response_create_overload_1(self, client: OpenAI) -> None:
@parametrize
def test_streaming_response_create_overload_1(self, client: OpenAI) -> None:
with client.audio.transcriptions.with_streaming_response.create(
- file=b"raw file contents",
+ file=b"Example data",
model="gpt-4o-transcribe",
) as response:
assert not response.is_closed
@@ -72,7 +72,7 @@ def test_streaming_response_create_overload_1(self, client: OpenAI) -> None:
@parametrize
def test_method_create_overload_2(self, client: OpenAI) -> None:
transcription_stream = client.audio.transcriptions.create(
- file=b"raw file contents",
+ file=b"Example data",
model="gpt-4o-transcribe",
stream=True,
)
@@ -81,7 +81,7 @@ def test_method_create_overload_2(self, client: OpenAI) -> None:
@parametrize
def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None:
transcription_stream = client.audio.transcriptions.create(
- file=b"raw file contents",
+ file=b"Example data",
model="gpt-4o-transcribe",
stream=True,
chunking_strategy="auto",
@@ -99,7 +99,7 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None:
@parametrize
def test_raw_response_create_overload_2(self, client: OpenAI) -> None:
response = client.audio.transcriptions.with_raw_response.create(
- file=b"raw file contents",
+ file=b"Example data",
model="gpt-4o-transcribe",
stream=True,
)
@@ -111,7 +111,7 @@ def test_raw_response_create_overload_2(self, client: OpenAI) -> None:
@parametrize
def test_streaming_response_create_overload_2(self, client: OpenAI) -> None:
with client.audio.transcriptions.with_streaming_response.create(
- file=b"raw file contents",
+ file=b"Example data",
model="gpt-4o-transcribe",
stream=True,
) as response:
@@ -132,7 +132,7 @@ class TestAsyncTranscriptions:
@parametrize
async def test_method_create_overload_1(self, async_client: AsyncOpenAI) -> None:
transcription = await async_client.audio.transcriptions.create(
- file=b"raw file contents",
+ file=b"Example data",
model="gpt-4o-transcribe",
)
assert_matches_type(TranscriptionCreateResponse, transcription, path=["response"])
@@ -140,7 +140,7 @@ async def test_method_create_overload_1(self, async_client: AsyncOpenAI) -> None
@parametrize
async def test_method_create_with_all_params_overload_1(self, async_client: AsyncOpenAI) -> None:
transcription = await async_client.audio.transcriptions.create(
- file=b"raw file contents",
+ file=b"Example data",
model="gpt-4o-transcribe",
chunking_strategy="auto",
include=["logprobs"],
@@ -158,7 +158,7 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn
@parametrize
async def test_raw_response_create_overload_1(self, async_client: AsyncOpenAI) -> None:
response = await async_client.audio.transcriptions.with_raw_response.create(
- file=b"raw file contents",
+ file=b"Example data",
model="gpt-4o-transcribe",
)
@@ -170,7 +170,7 @@ async def test_raw_response_create_overload_1(self, async_client: AsyncOpenAI) -
@parametrize
async def test_streaming_response_create_overload_1(self, async_client: AsyncOpenAI) -> None:
async with async_client.audio.transcriptions.with_streaming_response.create(
- file=b"raw file contents",
+ file=b"Example data",
model="gpt-4o-transcribe",
) as response:
assert not response.is_closed
@@ -184,7 +184,7 @@ async def test_streaming_response_create_overload_1(self, async_client: AsyncOpe
@parametrize
async def test_method_create_overload_2(self, async_client: AsyncOpenAI) -> None:
transcription_stream = await async_client.audio.transcriptions.create(
- file=b"raw file contents",
+ file=b"Example data",
model="gpt-4o-transcribe",
stream=True,
)
@@ -193,7 +193,7 @@ async def test_method_create_overload_2(self, async_client: AsyncOpenAI) -> None
@parametrize
async def test_method_create_with_all_params_overload_2(self, async_client: AsyncOpenAI) -> None:
transcription_stream = await async_client.audio.transcriptions.create(
- file=b"raw file contents",
+ file=b"Example data",
model="gpt-4o-transcribe",
stream=True,
chunking_strategy="auto",
@@ -211,7 +211,7 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn
@parametrize
async def test_raw_response_create_overload_2(self, async_client: AsyncOpenAI) -> None:
response = await async_client.audio.transcriptions.with_raw_response.create(
- file=b"raw file contents",
+ file=b"Example data",
model="gpt-4o-transcribe",
stream=True,
)
@@ -223,7 +223,7 @@ async def test_raw_response_create_overload_2(self, async_client: AsyncOpenAI) -
@parametrize
async def test_streaming_response_create_overload_2(self, async_client: AsyncOpenAI) -> None:
async with async_client.audio.transcriptions.with_streaming_response.create(
- file=b"raw file contents",
+ file=b"Example data",
model="gpt-4o-transcribe",
stream=True,
) as response:
diff --git a/tests/api_resources/audio/test_translations.py b/tests/api_resources/audio/test_translations.py
index ead69e9369..d6848d1278 100644
--- a/tests/api_resources/audio/test_translations.py
+++ b/tests/api_resources/audio/test_translations.py
@@ -20,7 +20,7 @@ class TestTranslations:
@parametrize
def test_method_create(self, client: OpenAI) -> None:
translation = client.audio.translations.create(
- file=b"raw file contents",
+ file=b"Example data",
model="whisper-1",
)
assert_matches_type(TranslationCreateResponse, translation, path=["response"])
@@ -28,7 +28,7 @@ def test_method_create(self, client: OpenAI) -> None:
@parametrize
def test_method_create_with_all_params(self, client: OpenAI) -> None:
translation = client.audio.translations.create(
- file=b"raw file contents",
+ file=b"Example data",
model="whisper-1",
prompt="prompt",
response_format="json",
@@ -39,7 +39,7 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None:
@parametrize
def test_raw_response_create(self, client: OpenAI) -> None:
response = client.audio.translations.with_raw_response.create(
- file=b"raw file contents",
+ file=b"Example data",
model="whisper-1",
)
@@ -51,7 +51,7 @@ def test_raw_response_create(self, client: OpenAI) -> None:
@parametrize
def test_streaming_response_create(self, client: OpenAI) -> None:
with client.audio.translations.with_streaming_response.create(
- file=b"raw file contents",
+ file=b"Example data",
model="whisper-1",
) as response:
assert not response.is_closed
@@ -71,7 +71,7 @@ class TestAsyncTranslations:
@parametrize
async def test_method_create(self, async_client: AsyncOpenAI) -> None:
translation = await async_client.audio.translations.create(
- file=b"raw file contents",
+ file=b"Example data",
model="whisper-1",
)
assert_matches_type(TranslationCreateResponse, translation, path=["response"])
@@ -79,7 +79,7 @@ async def test_method_create(self, async_client: AsyncOpenAI) -> None:
@parametrize
async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None:
translation = await async_client.audio.translations.create(
- file=b"raw file contents",
+ file=b"Example data",
model="whisper-1",
prompt="prompt",
response_format="json",
@@ -90,7 +90,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) ->
@parametrize
async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None:
response = await async_client.audio.translations.with_raw_response.create(
- file=b"raw file contents",
+ file=b"Example data",
model="whisper-1",
)
@@ -102,7 +102,7 @@ async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None:
@parametrize
async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> None:
async with async_client.audio.translations.with_streaming_response.create(
- file=b"raw file contents",
+ file=b"Example data",
model="whisper-1",
) as response:
assert not response.is_closed
diff --git a/tests/api_resources/chat/test_completions.py b/tests/api_resources/chat/test_completions.py
index 995b752e11..c55c132697 100644
--- a/tests/api_resources/chat/test_completions.py
+++ b/tests/api_resources/chat/test_completions.py
@@ -48,7 +48,7 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None:
model="gpt-5.4",
audio={
"format": "wav",
- "voice": "ash",
+ "voice": "string",
},
frequency_penalty=-2,
function_call="none",
@@ -182,7 +182,7 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None:
stream=True,
audio={
"format": "wav",
- "voice": "ash",
+ "voice": "string",
},
frequency_penalty=-2,
function_call="none",
@@ -491,7 +491,7 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn
model="gpt-5.4",
audio={
"format": "wav",
- "voice": "ash",
+ "voice": "string",
},
frequency_penalty=-2,
function_call="none",
@@ -625,7 +625,7 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn
stream=True,
audio={
"format": "wav",
- "voice": "ash",
+ "voice": "string",
},
frequency_penalty=-2,
function_call="none",
diff --git a/tests/api_resources/containers/test_files.py b/tests/api_resources/containers/test_files.py
index f9d82d005c..9d47785894 100644
--- a/tests/api_resources/containers/test_files.py
+++ b/tests/api_resources/containers/test_files.py
@@ -33,7 +33,7 @@ def test_method_create(self, client: OpenAI) -> None:
def test_method_create_with_all_params(self, client: OpenAI) -> None:
file = client.containers.files.create(
container_id="container_id",
- file=b"raw file contents",
+ file=b"Example data",
file_id="file_id",
)
assert_matches_type(FileCreateResponse, file, path=["response"])
@@ -230,7 +230,7 @@ async def test_method_create(self, async_client: AsyncOpenAI) -> None:
async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None:
file = await async_client.containers.files.create(
container_id="container_id",
- file=b"raw file contents",
+ file=b"Example data",
file_id="file_id",
)
assert_matches_type(FileCreateResponse, file, path=["response"])
diff --git a/tests/api_resources/realtime/test_calls.py b/tests/api_resources/realtime/test_calls.py
index 9bb6ef3faf..9e2810841d 100644
--- a/tests/api_resources/realtime/test_calls.py
+++ b/tests/api_resources/realtime/test_calls.py
@@ -67,7 +67,7 @@ def test_method_create_with_all_params(self, client: OpenAI, respx_mock: MockRou
"type": "audio/pcm",
},
"speed": 0.25,
- "voice": "ash",
+ "voice": "string",
},
},
"include": ["item.input_audio_transcription.logprobs"],
@@ -166,7 +166,7 @@ def test_method_accept_with_all_params(self, client: OpenAI) -> None:
"type": "audio/pcm",
},
"speed": 0.25,
- "voice": "ash",
+ "voice": "string",
},
},
include=["item.input_audio_transcription.logprobs"],
@@ -405,7 +405,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI, re
"type": "audio/pcm",
},
"speed": 0.25,
- "voice": "ash",
+ "voice": "string",
},
},
"include": ["item.input_audio_transcription.logprobs"],
@@ -504,7 +504,7 @@ async def test_method_accept_with_all_params(self, async_client: AsyncOpenAI) ->
"type": "audio/pcm",
},
"speed": 0.25,
- "voice": "ash",
+ "voice": "string",
},
},
include=["item.input_audio_transcription.logprobs"],
diff --git a/tests/api_resources/realtime/test_client_secrets.py b/tests/api_resources/realtime/test_client_secrets.py
index 17762771ac..bfa0deac55 100644
--- a/tests/api_resources/realtime/test_client_secrets.py
+++ b/tests/api_resources/realtime/test_client_secrets.py
@@ -59,7 +59,7 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None:
"type": "audio/pcm",
},
"speed": 0.25,
- "voice": "ash",
+ "voice": "string",
},
},
"include": ["item.input_audio_transcription.logprobs"],
@@ -155,7 +155,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) ->
"type": "audio/pcm",
},
"speed": 0.25,
- "voice": "ash",
+ "voice": "string",
},
},
"include": ["item.input_audio_transcription.logprobs"],
diff --git a/tests/api_resources/skills/test_versions.py b/tests/api_resources/skills/test_versions.py
index 5f4dcbf51d..40c807354a 100644
--- a/tests/api_resources/skills/test_versions.py
+++ b/tests/api_resources/skills/test_versions.py
@@ -30,7 +30,7 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None:
version = client.skills.versions.create(
skill_id="skill_123",
default=True,
- files=[b"raw file contents"],
+ files=[b"Example data"],
)
assert_matches_type(SkillVersion, version, path=["response"])
@@ -227,7 +227,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) ->
version = await async_client.skills.versions.create(
skill_id="skill_123",
default=True,
- files=[b"raw file contents"],
+ files=[b"Example data"],
)
assert_matches_type(SkillVersion, version, path=["response"])
diff --git a/tests/api_resources/test_files.py b/tests/api_resources/test_files.py
index 67c809f155..940ac97022 100644
--- a/tests/api_resources/test_files.py
+++ b/tests/api_resources/test_files.py
@@ -26,7 +26,7 @@ class TestFiles:
@parametrize
def test_method_create(self, client: OpenAI) -> None:
file = client.files.create(
- file=b"raw file contents",
+ file=b"Example data",
purpose="assistants",
)
assert_matches_type(FileObject, file, path=["response"])
@@ -34,7 +34,7 @@ def test_method_create(self, client: OpenAI) -> None:
@parametrize
def test_method_create_with_all_params(self, client: OpenAI) -> None:
file = client.files.create(
- file=b"raw file contents",
+ file=b"Example data",
purpose="assistants",
expires_after={
"anchor": "created_at",
@@ -46,7 +46,7 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None:
@parametrize
def test_raw_response_create(self, client: OpenAI) -> None:
response = client.files.with_raw_response.create(
- file=b"raw file contents",
+ file=b"Example data",
purpose="assistants",
)
@@ -58,7 +58,7 @@ def test_raw_response_create(self, client: OpenAI) -> None:
@parametrize
def test_streaming_response_create(self, client: OpenAI) -> None:
with client.files.with_streaming_response.create(
- file=b"raw file contents",
+ file=b"Example data",
purpose="assistants",
) as response:
assert not response.is_closed
@@ -279,7 +279,7 @@ class TestAsyncFiles:
@parametrize
async def test_method_create(self, async_client: AsyncOpenAI) -> None:
file = await async_client.files.create(
- file=b"raw file contents",
+ file=b"Example data",
purpose="assistants",
)
assert_matches_type(FileObject, file, path=["response"])
@@ -287,7 +287,7 @@ async def test_method_create(self, async_client: AsyncOpenAI) -> None:
@parametrize
async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None:
file = await async_client.files.create(
- file=b"raw file contents",
+ file=b"Example data",
purpose="assistants",
expires_after={
"anchor": "created_at",
@@ -299,7 +299,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) ->
@parametrize
async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None:
response = await async_client.files.with_raw_response.create(
- file=b"raw file contents",
+ file=b"Example data",
purpose="assistants",
)
@@ -311,7 +311,7 @@ async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None:
@parametrize
async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> None:
async with async_client.files.with_streaming_response.create(
- file=b"raw file contents",
+ file=b"Example data",
purpose="assistants",
) as response:
assert not response.is_closed
diff --git a/tests/api_resources/test_images.py b/tests/api_resources/test_images.py
index 99fe77d8e0..9862b79c65 100644
--- a/tests/api_resources/test_images.py
+++ b/tests/api_resources/test_images.py
@@ -20,14 +20,14 @@ class TestImages:
@parametrize
def test_method_create_variation(self, client: OpenAI) -> None:
image = client.images.create_variation(
- image=b"raw file contents",
+ image=b"Example data",
)
assert_matches_type(ImagesResponse, image, path=["response"])
@parametrize
def test_method_create_variation_with_all_params(self, client: OpenAI) -> None:
image = client.images.create_variation(
- image=b"raw file contents",
+ image=b"Example data",
model="string",
n=1,
response_format="url",
@@ -39,7 +39,7 @@ def test_method_create_variation_with_all_params(self, client: OpenAI) -> None:
@parametrize
def test_raw_response_create_variation(self, client: OpenAI) -> None:
response = client.images.with_raw_response.create_variation(
- image=b"raw file contents",
+ image=b"Example data",
)
assert response.is_closed is True
@@ -50,7 +50,7 @@ def test_raw_response_create_variation(self, client: OpenAI) -> None:
@parametrize
def test_streaming_response_create_variation(self, client: OpenAI) -> None:
with client.images.with_streaming_response.create_variation(
- image=b"raw file contents",
+ image=b"Example data",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -63,7 +63,7 @@ def test_streaming_response_create_variation(self, client: OpenAI) -> None:
@parametrize
def test_method_edit_overload_1(self, client: OpenAI) -> None:
image = client.images.edit(
- image=b"raw file contents",
+ image=b"Example data",
prompt="A cute baby sea otter wearing a beret",
)
assert_matches_type(ImagesResponse, image, path=["response"])
@@ -71,11 +71,11 @@ def test_method_edit_overload_1(self, client: OpenAI) -> None:
@parametrize
def test_method_edit_with_all_params_overload_1(self, client: OpenAI) -> None:
image = client.images.edit(
- image=b"raw file contents",
+ image=b"Example data",
prompt="A cute baby sea otter wearing a beret",
background="transparent",
input_fidelity="high",
- mask=b"raw file contents",
+ mask=b"Example data",
model="string",
n=1,
output_compression=100,
@@ -92,7 +92,7 @@ def test_method_edit_with_all_params_overload_1(self, client: OpenAI) -> None:
@parametrize
def test_raw_response_edit_overload_1(self, client: OpenAI) -> None:
response = client.images.with_raw_response.edit(
- image=b"raw file contents",
+ image=b"Example data",
prompt="A cute baby sea otter wearing a beret",
)
@@ -104,7 +104,7 @@ def test_raw_response_edit_overload_1(self, client: OpenAI) -> None:
@parametrize
def test_streaming_response_edit_overload_1(self, client: OpenAI) -> None:
with client.images.with_streaming_response.edit(
- image=b"raw file contents",
+ image=b"Example data",
prompt="A cute baby sea otter wearing a beret",
) as response:
assert not response.is_closed
@@ -118,7 +118,7 @@ def test_streaming_response_edit_overload_1(self, client: OpenAI) -> None:
@parametrize
def test_method_edit_overload_2(self, client: OpenAI) -> None:
image_stream = client.images.edit(
- image=b"raw file contents",
+ image=b"Example data",
prompt="A cute baby sea otter wearing a beret",
stream=True,
)
@@ -127,12 +127,12 @@ def test_method_edit_overload_2(self, client: OpenAI) -> None:
@parametrize
def test_method_edit_with_all_params_overload_2(self, client: OpenAI) -> None:
image_stream = client.images.edit(
- image=b"raw file contents",
+ image=b"Example data",
prompt="A cute baby sea otter wearing a beret",
stream=True,
background="transparent",
input_fidelity="high",
- mask=b"raw file contents",
+ mask=b"Example data",
model="string",
n=1,
output_compression=100,
@@ -148,7 +148,7 @@ def test_method_edit_with_all_params_overload_2(self, client: OpenAI) -> None:
@parametrize
def test_raw_response_edit_overload_2(self, client: OpenAI) -> None:
response = client.images.with_raw_response.edit(
- image=b"raw file contents",
+ image=b"Example data",
prompt="A cute baby sea otter wearing a beret",
stream=True,
)
@@ -160,7 +160,7 @@ def test_raw_response_edit_overload_2(self, client: OpenAI) -> None:
@parametrize
def test_streaming_response_edit_overload_2(self, client: OpenAI) -> None:
with client.images.with_streaming_response.edit(
- image=b"raw file contents",
+ image=b"Example data",
prompt="A cute baby sea otter wearing a beret",
stream=True,
) as response:
@@ -285,14 +285,14 @@ class TestAsyncImages:
@parametrize
async def test_method_create_variation(self, async_client: AsyncOpenAI) -> None:
image = await async_client.images.create_variation(
- image=b"raw file contents",
+ image=b"Example data",
)
assert_matches_type(ImagesResponse, image, path=["response"])
@parametrize
async def test_method_create_variation_with_all_params(self, async_client: AsyncOpenAI) -> None:
image = await async_client.images.create_variation(
- image=b"raw file contents",
+ image=b"Example data",
model="string",
n=1,
response_format="url",
@@ -304,7 +304,7 @@ async def test_method_create_variation_with_all_params(self, async_client: Async
@parametrize
async def test_raw_response_create_variation(self, async_client: AsyncOpenAI) -> None:
response = await async_client.images.with_raw_response.create_variation(
- image=b"raw file contents",
+ image=b"Example data",
)
assert response.is_closed is True
@@ -315,7 +315,7 @@ async def test_raw_response_create_variation(self, async_client: AsyncOpenAI) ->
@parametrize
async def test_streaming_response_create_variation(self, async_client: AsyncOpenAI) -> None:
async with async_client.images.with_streaming_response.create_variation(
- image=b"raw file contents",
+ image=b"Example data",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -328,7 +328,7 @@ async def test_streaming_response_create_variation(self, async_client: AsyncOpen
@parametrize
async def test_method_edit_overload_1(self, async_client: AsyncOpenAI) -> None:
image = await async_client.images.edit(
- image=b"raw file contents",
+ image=b"Example data",
prompt="A cute baby sea otter wearing a beret",
)
assert_matches_type(ImagesResponse, image, path=["response"])
@@ -336,11 +336,11 @@ async def test_method_edit_overload_1(self, async_client: AsyncOpenAI) -> None:
@parametrize
async def test_method_edit_with_all_params_overload_1(self, async_client: AsyncOpenAI) -> None:
image = await async_client.images.edit(
- image=b"raw file contents",
+ image=b"Example data",
prompt="A cute baby sea otter wearing a beret",
background="transparent",
input_fidelity="high",
- mask=b"raw file contents",
+ mask=b"Example data",
model="string",
n=1,
output_compression=100,
@@ -357,7 +357,7 @@ async def test_method_edit_with_all_params_overload_1(self, async_client: AsyncO
@parametrize
async def test_raw_response_edit_overload_1(self, async_client: AsyncOpenAI) -> None:
response = await async_client.images.with_raw_response.edit(
- image=b"raw file contents",
+ image=b"Example data",
prompt="A cute baby sea otter wearing a beret",
)
@@ -369,7 +369,7 @@ async def test_raw_response_edit_overload_1(self, async_client: AsyncOpenAI) ->
@parametrize
async def test_streaming_response_edit_overload_1(self, async_client: AsyncOpenAI) -> None:
async with async_client.images.with_streaming_response.edit(
- image=b"raw file contents",
+ image=b"Example data",
prompt="A cute baby sea otter wearing a beret",
) as response:
assert not response.is_closed
@@ -383,7 +383,7 @@ async def test_streaming_response_edit_overload_1(self, async_client: AsyncOpenA
@parametrize
async def test_method_edit_overload_2(self, async_client: AsyncOpenAI) -> None:
image_stream = await async_client.images.edit(
- image=b"raw file contents",
+ image=b"Example data",
prompt="A cute baby sea otter wearing a beret",
stream=True,
)
@@ -392,12 +392,12 @@ async def test_method_edit_overload_2(self, async_client: AsyncOpenAI) -> None:
@parametrize
async def test_method_edit_with_all_params_overload_2(self, async_client: AsyncOpenAI) -> None:
image_stream = await async_client.images.edit(
- image=b"raw file contents",
+ image=b"Example data",
prompt="A cute baby sea otter wearing a beret",
stream=True,
background="transparent",
input_fidelity="high",
- mask=b"raw file contents",
+ mask=b"Example data",
model="string",
n=1,
output_compression=100,
@@ -413,7 +413,7 @@ async def test_method_edit_with_all_params_overload_2(self, async_client: AsyncO
@parametrize
async def test_raw_response_edit_overload_2(self, async_client: AsyncOpenAI) -> None:
response = await async_client.images.with_raw_response.edit(
- image=b"raw file contents",
+ image=b"Example data",
prompt="A cute baby sea otter wearing a beret",
stream=True,
)
@@ -425,7 +425,7 @@ async def test_raw_response_edit_overload_2(self, async_client: AsyncOpenAI) ->
@parametrize
async def test_streaming_response_edit_overload_2(self, async_client: AsyncOpenAI) -> None:
async with async_client.images.with_streaming_response.edit(
- image=b"raw file contents",
+ image=b"Example data",
prompt="A cute baby sea otter wearing a beret",
stream=True,
) as response:
diff --git a/tests/api_resources/test_skills.py b/tests/api_resources/test_skills.py
index fb4cea92ce..6708fb3cbf 100644
--- a/tests/api_resources/test_skills.py
+++ b/tests/api_resources/test_skills.py
@@ -26,7 +26,7 @@ def test_method_create(self, client: OpenAI) -> None:
@parametrize
def test_method_create_with_all_params(self, client: OpenAI) -> None:
skill = client.skills.create(
- files=[b"raw file contents"],
+ files=[b"Example data"],
)
assert_matches_type(Skill, skill, path=["response"])
@@ -216,7 +216,7 @@ async def test_method_create(self, async_client: AsyncOpenAI) -> None:
@parametrize
async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None:
skill = await async_client.skills.create(
- files=[b"raw file contents"],
+ files=[b"Example data"],
)
assert_matches_type(Skill, skill, path=["response"])
diff --git a/tests/api_resources/test_videos.py b/tests/api_resources/test_videos.py
index b785e03ca5..73acf6d05d 100644
--- a/tests/api_resources/test_videos.py
+++ b/tests/api_resources/test_videos.py
@@ -15,6 +15,8 @@
from openai.types import (
Video,
VideoDeleteResponse,
+ VideoGetCharacterResponse,
+ VideoCreateCharacterResponse,
)
from openai._utils import assert_signatures_in_sync
from openai.pagination import SyncConversationCursorPage, AsyncConversationCursorPage
@@ -38,7 +40,7 @@ def test_method_create(self, client: OpenAI) -> None:
def test_method_create_with_all_params(self, client: OpenAI) -> None:
video = client.videos.create(
prompt="x",
- input_reference=b"raw file contents",
+ input_reference=b"Example data",
model="string",
seconds="4",
size="720x1280",
@@ -179,6 +181,40 @@ def test_path_params_delete(self, client: OpenAI) -> None:
"",
)
+ @parametrize
+ def test_method_create_character(self, client: OpenAI) -> None:
+ video = client.videos.create_character(
+ name="x",
+ video=b"Example data",
+ )
+ assert_matches_type(VideoCreateCharacterResponse, video, path=["response"])
+
+ @parametrize
+ def test_raw_response_create_character(self, client: OpenAI) -> None:
+ response = client.videos.with_raw_response.create_character(
+ name="x",
+ video=b"Example data",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ video = response.parse()
+ assert_matches_type(VideoCreateCharacterResponse, video, path=["response"])
+
+ @parametrize
+ def test_streaming_response_create_character(self, client: OpenAI) -> None:
+ with client.videos.with_streaming_response.create_character(
+ name="x",
+ video=b"Example data",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ video = response.parse()
+ assert_matches_type(VideoCreateCharacterResponse, video, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
@parametrize
@pytest.mark.respx(base_url=base_url)
def test_method_download_content(self, client: OpenAI, respx_mock: MockRouter) -> None:
@@ -237,6 +273,115 @@ def test_path_params_download_content(self, client: OpenAI) -> None:
video_id="",
)
+ @parametrize
+ def test_method_edit(self, client: OpenAI) -> None:
+ video = client.videos.edit(
+ prompt="x",
+ video=b"Example data",
+ )
+ assert_matches_type(Video, video, path=["response"])
+
+ @parametrize
+ def test_raw_response_edit(self, client: OpenAI) -> None:
+ response = client.videos.with_raw_response.edit(
+ prompt="x",
+ video=b"Example data",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ video = response.parse()
+ assert_matches_type(Video, video, path=["response"])
+
+ @parametrize
+ def test_streaming_response_edit(self, client: OpenAI) -> None:
+ with client.videos.with_streaming_response.edit(
+ prompt="x",
+ video=b"Example data",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ video = response.parse()
+ assert_matches_type(Video, video, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_method_extend(self, client: OpenAI) -> None:
+ video = client.videos.extend(
+ prompt="x",
+ seconds="4",
+ video=b"Example data",
+ )
+ assert_matches_type(Video, video, path=["response"])
+
+ @parametrize
+ def test_raw_response_extend(self, client: OpenAI) -> None:
+ response = client.videos.with_raw_response.extend(
+ prompt="x",
+ seconds="4",
+ video=b"Example data",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ video = response.parse()
+ assert_matches_type(Video, video, path=["response"])
+
+ @parametrize
+ def test_streaming_response_extend(self, client: OpenAI) -> None:
+ with client.videos.with_streaming_response.extend(
+ prompt="x",
+ seconds="4",
+ video=b"Example data",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ video = response.parse()
+ assert_matches_type(Video, video, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_method_get_character(self, client: OpenAI) -> None:
+ video = client.videos.get_character(
+ "char_123",
+ )
+ assert_matches_type(VideoGetCharacterResponse, video, path=["response"])
+
+ @parametrize
+ def test_raw_response_get_character(self, client: OpenAI) -> None:
+ response = client.videos.with_raw_response.get_character(
+ "char_123",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ video = response.parse()
+ assert_matches_type(VideoGetCharacterResponse, video, path=["response"])
+
+ @parametrize
+ def test_streaming_response_get_character(self, client: OpenAI) -> None:
+ with client.videos.with_streaming_response.get_character(
+ "char_123",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ video = response.parse()
+ assert_matches_type(VideoGetCharacterResponse, video, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_get_character(self, client: OpenAI) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `character_id` but received ''"):
+ client.videos.with_raw_response.get_character(
+ "",
+ )
+
@parametrize
def test_method_remix(self, client: OpenAI) -> None:
video = client.videos.remix(
@@ -296,7 +441,7 @@ async def test_method_create(self, async_client: AsyncOpenAI) -> None:
async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None:
video = await async_client.videos.create(
prompt="x",
- input_reference=b"raw file contents",
+ input_reference=b"Example data",
model="string",
seconds="4",
size="720x1280",
@@ -437,6 +582,40 @@ async def test_path_params_delete(self, async_client: AsyncOpenAI) -> None:
"",
)
+ @parametrize
+ async def test_method_create_character(self, async_client: AsyncOpenAI) -> None:
+ video = await async_client.videos.create_character(
+ name="x",
+ video=b"Example data",
+ )
+ assert_matches_type(VideoCreateCharacterResponse, video, path=["response"])
+
+ @parametrize
+ async def test_raw_response_create_character(self, async_client: AsyncOpenAI) -> None:
+ response = await async_client.videos.with_raw_response.create_character(
+ name="x",
+ video=b"Example data",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ video = response.parse()
+ assert_matches_type(VideoCreateCharacterResponse, video, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_create_character(self, async_client: AsyncOpenAI) -> None:
+ async with async_client.videos.with_streaming_response.create_character(
+ name="x",
+ video=b"Example data",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ video = await response.parse()
+ assert_matches_type(VideoCreateCharacterResponse, video, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
@parametrize
@pytest.mark.respx(base_url=base_url)
async def test_method_download_content(self, async_client: AsyncOpenAI, respx_mock: MockRouter) -> None:
@@ -497,6 +676,115 @@ async def test_path_params_download_content(self, async_client: AsyncOpenAI) ->
video_id="",
)
+ @parametrize
+ async def test_method_edit(self, async_client: AsyncOpenAI) -> None:
+ video = await async_client.videos.edit(
+ prompt="x",
+ video=b"Example data",
+ )
+ assert_matches_type(Video, video, path=["response"])
+
+ @parametrize
+ async def test_raw_response_edit(self, async_client: AsyncOpenAI) -> None:
+ response = await async_client.videos.with_raw_response.edit(
+ prompt="x",
+ video=b"Example data",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ video = response.parse()
+ assert_matches_type(Video, video, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_edit(self, async_client: AsyncOpenAI) -> None:
+ async with async_client.videos.with_streaming_response.edit(
+ prompt="x",
+ video=b"Example data",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ video = await response.parse()
+ assert_matches_type(Video, video, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_method_extend(self, async_client: AsyncOpenAI) -> None:
+ video = await async_client.videos.extend(
+ prompt="x",
+ seconds="4",
+ video=b"Example data",
+ )
+ assert_matches_type(Video, video, path=["response"])
+
+ @parametrize
+ async def test_raw_response_extend(self, async_client: AsyncOpenAI) -> None:
+ response = await async_client.videos.with_raw_response.extend(
+ prompt="x",
+ seconds="4",
+ video=b"Example data",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ video = response.parse()
+ assert_matches_type(Video, video, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_extend(self, async_client: AsyncOpenAI) -> None:
+ async with async_client.videos.with_streaming_response.extend(
+ prompt="x",
+ seconds="4",
+ video=b"Example data",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ video = await response.parse()
+ assert_matches_type(Video, video, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_method_get_character(self, async_client: AsyncOpenAI) -> None:
+ video = await async_client.videos.get_character(
+ "char_123",
+ )
+ assert_matches_type(VideoGetCharacterResponse, video, path=["response"])
+
+ @parametrize
+ async def test_raw_response_get_character(self, async_client: AsyncOpenAI) -> None:
+ response = await async_client.videos.with_raw_response.get_character(
+ "char_123",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ video = response.parse()
+ assert_matches_type(VideoGetCharacterResponse, video, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_get_character(self, async_client: AsyncOpenAI) -> None:
+ async with async_client.videos.with_streaming_response.get_character(
+ "char_123",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ video = await response.parse()
+ assert_matches_type(VideoGetCharacterResponse, video, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_get_character(self, async_client: AsyncOpenAI) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `character_id` but received ''"):
+ await async_client.videos.with_raw_response.get_character(
+ "",
+ )
+
@parametrize
async def test_method_remix(self, async_client: AsyncOpenAI) -> None:
video = await async_client.videos.remix(
diff --git a/tests/api_resources/uploads/test_parts.py b/tests/api_resources/uploads/test_parts.py
index 191d3a1b04..b5956d263b 100644
--- a/tests/api_resources/uploads/test_parts.py
+++ b/tests/api_resources/uploads/test_parts.py
@@ -21,7 +21,7 @@ class TestParts:
def test_method_create(self, client: OpenAI) -> None:
part = client.uploads.parts.create(
upload_id="upload_abc123",
- data=b"raw file contents",
+ data=b"Example data",
)
assert_matches_type(UploadPart, part, path=["response"])
@@ -29,7 +29,7 @@ def test_method_create(self, client: OpenAI) -> None:
def test_raw_response_create(self, client: OpenAI) -> None:
response = client.uploads.parts.with_raw_response.create(
upload_id="upload_abc123",
- data=b"raw file contents",
+ data=b"Example data",
)
assert response.is_closed is True
@@ -41,7 +41,7 @@ def test_raw_response_create(self, client: OpenAI) -> None:
def test_streaming_response_create(self, client: OpenAI) -> None:
with client.uploads.parts.with_streaming_response.create(
upload_id="upload_abc123",
- data=b"raw file contents",
+ data=b"Example data",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -56,7 +56,7 @@ def test_path_params_create(self, client: OpenAI) -> None:
with pytest.raises(ValueError, match=r"Expected a non-empty value for `upload_id` but received ''"):
client.uploads.parts.with_raw_response.create(
upload_id="",
- data=b"raw file contents",
+ data=b"Example data",
)
@@ -69,7 +69,7 @@ class TestAsyncParts:
async def test_method_create(self, async_client: AsyncOpenAI) -> None:
part = await async_client.uploads.parts.create(
upload_id="upload_abc123",
- data=b"raw file contents",
+ data=b"Example data",
)
assert_matches_type(UploadPart, part, path=["response"])
@@ -77,7 +77,7 @@ async def test_method_create(self, async_client: AsyncOpenAI) -> None:
async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None:
response = await async_client.uploads.parts.with_raw_response.create(
upload_id="upload_abc123",
- data=b"raw file contents",
+ data=b"Example data",
)
assert response.is_closed is True
@@ -89,7 +89,7 @@ async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None:
async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> None:
async with async_client.uploads.parts.with_streaming_response.create(
upload_id="upload_abc123",
- data=b"raw file contents",
+ data=b"Example data",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -104,5 +104,5 @@ async def test_path_params_create(self, async_client: AsyncOpenAI) -> None:
with pytest.raises(ValueError, match=r"Expected a non-empty value for `upload_id` but received ''"):
await async_client.uploads.parts.with_raw_response.create(
upload_id="",
- data=b"raw file contents",
+ data=b"Example data",
)
diff --git a/tests/test_websocket_connection_options.py b/tests/test_websocket_connection_options.py
new file mode 100644
index 0000000000..122ee10078
--- /dev/null
+++ b/tests/test_websocket_connection_options.py
@@ -0,0 +1,20 @@
+from openai import types
+from openai.types import websocket_connection_options
+
+
+def test_submodule_alias_is_preserved() -> None:
+ assert (
+ websocket_connection_options.WebsocketConnectionOptions
+ is websocket_connection_options.WebSocketConnectionOptions
+ )
+
+
+def test_public_types_alias_is_preserved() -> None:
+ assert types.WebsocketConnectionOptions is types.WebSocketConnectionOptions
+
+
+def test_beta_realtime_import_still_works_with_old_alias() -> None:
+ from openai.resources.beta.realtime.realtime import Realtime, AsyncRealtime
+
+ assert Realtime.__name__ == "Realtime"
+ assert AsyncRealtime.__name__ == "AsyncRealtime"