Skip to content

Commit

Permalink
fix(client): add support for streaming binary responses (#866)
Browse files Browse the repository at this point in the history
  • Loading branch information
stainless-bot committed Nov 23, 2023
1 parent 9f828cb commit b2b4239
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 9 deletions.
5 changes: 4 additions & 1 deletion examples/audio.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@
def main() -> None:
# Create text-to-speech audio file
response = openai.audio.speech.create(
model="tts-1", voice="alloy", input="the quick brown fox jumped over the lazy dogs"
model="tts-1",
voice="alloy",
input="the quick brown fox jumped over the lazy dogs",
stream=True,
)

response.stream_to_file(speech_file_path)
Expand Down
8 changes: 6 additions & 2 deletions src/openai/_base_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -863,7 +863,7 @@ def _request(
self._prepare_request(request)

try:
response = self._client.send(request, auth=self.custom_auth, stream=stream)
response = self._client.send(request, auth=self.custom_auth, stream=stream or options.stream or False)
log.debug(
'HTTP Request: %s %s "%i %s"', request.method, request.url, response.status_code, response.reason_phrase
)
Expand Down Expand Up @@ -1304,7 +1304,7 @@ async def _request(
await self._prepare_request(request)

try:
response = await self._client.send(request, auth=self.custom_auth, stream=stream)
response = await self._client.send(request, auth=self.custom_auth, stream=stream or options.stream or False)
log.debug(
'HTTP Request: %s %s "%i %s"', request.method, request.url, response.status_code, response.reason_phrase
)
Expand Down Expand Up @@ -1541,6 +1541,7 @@ def make_request_options(
idempotency_key: str | None = None,
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
post_parser: PostParser | NotGiven = NOT_GIVEN,
stream: bool | None = None,
) -> RequestOptions:
"""Create a dict of type RequestOptions without keys of NotGiven values."""
options: RequestOptions = {}
Expand All @@ -1562,6 +1563,9 @@ def make_request_options(
if idempotency_key is not None:
options["idempotency_key"] = idempotency_key

if stream is not None:
options["stream"] = stream

if is_given(post_parser):
# internal
options["post_parser"] = post_parser # type: ignore
Expand Down
2 changes: 2 additions & 0 deletions src/openai/_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,7 @@ class FinalRequestOptionsInput(TypedDict, total=False):
params: Query
headers: Headers
max_retries: int
stream: bool | None
timeout: float | Timeout | None
files: HttpxRequestFiles | None
idempotency_key: str
Expand All @@ -420,6 +421,7 @@ class FinalRequestOptions(pydantic.BaseModel):
timeout: Union[float, Timeout, None, NotGiven] = NotGiven()
files: Union[HttpxRequestFiles, None] = None
idempotency_key: Union[str, None] = None
stream: Union[bool, None] = None
post_parser: Union[Callable[[Any], Any], NotGiven] = NotGiven()

# It should be noted that we cannot use `json` here as that would override
Expand Down
23 changes: 21 additions & 2 deletions src/openai/_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,16 @@ def stream_to_file(
chunk_size: int | None = None,
) -> None:
"""
Stream the output to the given file.
Stream the output to the given file. NOTE, requires passing `stream=True`
to the request for expected behavior, e.g.,
response = openai.audio.speech.create(
model="tts-1",
voice="alloy",
input="the quick brown fox jumped over the lazy dogs",
stream=True,
)
response.stream_to_file(speech_file_path)
"""
pass

Expand Down Expand Up @@ -185,7 +194,16 @@ async def astream_to_file(
chunk_size: int | None = None,
) -> None:
"""
Stream the output to the given file.
Stream the output to the given file. NOTE, requires passing `stream=True`
to the request for expected behavior, e.g.,
response = await openai.audio.speech.create(
model="tts-1",
voice="alloy",
input="the quick brown fox jumped over the lazy dogs",
stream=True,
)
response.stream_to_file(speech_file_path)
"""
pass

Expand Down Expand Up @@ -257,6 +275,7 @@ async def aclose(self) -> None:
class RequestOptions(TypedDict, total=False):
headers: Headers
max_retries: int
stream: bool
timeout: float | Timeout | None
params: Query
extra_json: AnyMapping
Expand Down
20 changes: 18 additions & 2 deletions src/openai/resources/audio/speech.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ def create(
extra_query: Query | None = None,
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
stream: bool | None = None,
) -> HttpxBinaryResponseContent:
"""
Generates audio from the input text.
Expand All @@ -67,6 +68,9 @@ def create(
extra_body: Add additional JSON properties to the request
timeout: Override the client-level default timeout for this request, in seconds
stream: Whether or not the response content should be streamed (i.e. not read to
completion immediately), default False
"""
return self._post(
"/audio/speech",
Expand All @@ -81,7 +85,11 @@ def create(
speech_create_params.SpeechCreateParams,
),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
extra_headers=extra_headers,
extra_query=extra_query,
extra_body=extra_body,
timeout=timeout,
stream=stream,
),
cast_to=HttpxBinaryResponseContent,
)
Expand All @@ -108,6 +116,7 @@ async def create(
extra_query: Query | None = None,
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
stream: bool | None = None,
) -> HttpxBinaryResponseContent:
"""
Generates audio from the input text.
Expand All @@ -134,6 +143,9 @@ async def create(
extra_body: Add additional JSON properties to the request
timeout: Override the client-level default timeout for this request, in seconds
stream: Whether or not the response content should be streamed (i.e. not read to
completion immediately), default False
"""
return await self._post(
"/audio/speech",
Expand All @@ -148,7 +160,11 @@ async def create(
speech_create_params.SpeechCreateParams,
),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
extra_headers=extra_headers,
extra_query=extra_query,
extra_body=extra_body,
timeout=timeout,
stream=stream,
),
cast_to=HttpxBinaryResponseContent,
)
Expand Down
20 changes: 18 additions & 2 deletions src/openai/resources/files.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ def content(
extra_query: Query | None = None,
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
stream: bool | None = None,
) -> HttpxBinaryResponseContent:
"""
Returns the contents of the specified file.
Expand All @@ -224,11 +225,18 @@ def content(
extra_body: Add additional JSON properties to the request
timeout: Override the client-level default timeout for this request, in seconds
stream: Whether or not the response content should be streamed (i.e. not read to
completion immediately), default False
"""
return self._get(
f"/files/{file_id}/content",
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
extra_headers=extra_headers,
extra_query=extra_query,
extra_body=extra_body,
timeout=timeout,
stream=stream,
),
cast_to=HttpxBinaryResponseContent,
)
Expand Down Expand Up @@ -475,6 +483,7 @@ async def content(
extra_query: Query | None = None,
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
stream: bool | None = None,
) -> HttpxBinaryResponseContent:
"""
Returns the contents of the specified file.
Expand All @@ -487,11 +496,18 @@ async def content(
extra_body: Add additional JSON properties to the request
timeout: Override the client-level default timeout for this request, in seconds
stream: Whether or not the response content should be streamed (i.e. not read to
completion immediately), default False
"""
return await self._get(
f"/files/{file_id}/content",
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
extra_headers=extra_headers,
extra_query=extra_query,
extra_body=extra_body,
timeout=timeout,
stream=stream,
),
cast_to=HttpxBinaryResponseContent,
)
Expand Down

0 comments on commit b2b4239

Please sign in to comment.