Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 54 additions & 54 deletions api-reference/sdk/python/core.mdx
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
<a id="fishaudio.core.omit"></a>

# fishaudio.core.omit

OMIT sentinel for distinguishing None from not-provided parameters.

Comment on lines +1 to +6

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Add required frontmatter to both API-reference pages.

Both pages begin with generated anchors. Neither page declares the required YAML title and description.

  • api-reference/sdk/python/core.mdx#L1-L6: Add frontmatter before <a id="fishaudio.core.omit"></a>.
  • api-reference/sdk/python/utils.mdx#L1-L5: Add frontmatter before <a id="fishaudio.utils.stream"></a>.

As per coding guidelines, do not skip frontmatter on any MDX file. Include a clear title and description in the YAML frontmatter.

📍 Affects 2 files
  • api-reference/sdk/python/core.mdx#L1-L6 (this comment)
  • api-reference/sdk/python/utils.mdx#L1-L5
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@api-reference/sdk/python/core.mdx` around lines 1 - 6, Add YAML frontmatter
with clear title and description before the generated anchor in
api-reference/sdk/python/core.mdx (lines 1-6) and
api-reference/sdk/python/utils.mdx (lines 1-5). Ensure both MDX pages retain
their existing anchors and comply with the required frontmatter convention.

Source: Coding guidelines

<a id="fishaudio.core.client_wrapper"></a>

# fishaudio.core.client\_wrapper
Expand All @@ -14,7 +20,7 @@

Base wrapper with shared logic for sync/async clients.

<a id="fishaudio.core.client_wrapper.BaseClientWrapper.get_headers"></a>

Check warning on line 23 in api-reference/sdk/python/core.mdx

View check run for this annotation

Mintlify / Mintlify Validation (hanabiaiinc) - vale-spellcheck

api-reference/sdk/python/core.mdx#L23

Did you really mean 'get_headers'?

#### get\_headers

Expand Down Expand Up @@ -172,7 +178,7 @@
- `additional_headers` - Additional headers to include in the request
- `additional_query_params` - Additional query parameters to include

<a id="fishaudio.core.request_options.RequestOptions.get_timeout"></a>

Check warning on line 181 in api-reference/sdk/python/core.mdx

View check run for this annotation

Mintlify / Mintlify Validation (hanabiaiinc) - vale-spellcheck

api-reference/sdk/python/core.mdx#L181

Did you really mean 'get_timeout'?

#### get\_timeout

Expand All @@ -182,6 +188,54 @@

Convert timeout to httpx.Timeout if set.

<a id="fishaudio.core.websocket_options"></a>

# fishaudio.core.websocket\_options

WebSocket-level options for WebSocket connections.

<a id="fishaudio.core.websocket_options.WebSocketOptions"></a>

## WebSocketOptions Objects

```python
class WebSocketOptions()
```

Options for configuring WebSocket connections.

These options are passed directly to httpx_ws's connect_ws/aconnect_ws functions.

Check warning on line 207 in api-reference/sdk/python/core.mdx

View check run for this annotation

Mintlify / Mintlify Validation (hanabiaiinc) - vale-spellcheck

api-reference/sdk/python/core.mdx#L207

Did you really mean 'httpx_ws's'?
For complete documentation, see https://frankie567.github.io/httpx-ws/reference/httpx_ws/

**Attributes**:

- `keepalive_ping_timeout_seconds` - Maximum delay the client will wait for an answer
to its Ping event. If the delay is exceeded, WebSocketNetworkError will be
raised and the connection closed. Default: 20 seconds.
- `keepalive_ping_interval_seconds` - Interval at which the client will automatically
send a Ping event to keep the connection alive. Set to None to disable this
mechanism. Default: 20 seconds.
- `max_message_size_bytes` - Message size in bytes to receive from the server.
- `Default` - 65536 bytes (64 KiB).
- `queue_size` - Size of the queue where received messages will be held until they
Comment on lines +218 to +220

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Keep the default value under max_message_size_bytes.

Line 219 is rendered as a separate attribute named Default. Move the value into the max_message_size_bytes description.

Proposed fix
-- `max_message_size_bytes` - Message size in bytes to receive from the server.
-- `Default` - 65536 bytes (64 KiB).
+- `max_message_size_bytes` - Message size in bytes to receive from the server.
+  Default: 65536 bytes (64 KiB).
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- `max_message_size_bytes` - Message size in bytes to receive from the server.
- `Default` - 65536 bytes (64 KiB).
- `queue_size` - Size of the queue where received messages will be held until they
- `max_message_size_bytes` - Message size in bytes to receive from the server.
Default: 65536 bytes (64 KiB).
- `queue_size` - Size of the queue where received messages will be held until they
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@api-reference/sdk/python/core.mdx` around lines 218 - 220, Update the
max_message_size_bytes documentation entry so “Default: 65536 bytes (64 KiB)”
remains part of its description rather than appearing as a separate attribute;
keep the queue_size entry unchanged.

are consumed. If the queue is full, the client will stop receiving messages
from the server until the queue has room available. Default: 512.


**Notes**:

Parameter descriptions adapted from httpx_ws documentation.

Check warning on line 227 in api-reference/sdk/python/core.mdx

View check run for this annotation

Mintlify / Mintlify Validation (hanabiaiinc) - vale-spellcheck

api-reference/sdk/python/core.mdx#L227

Did you really mean 'httpx_ws'?

<a id="fishaudio.core.websocket_options.WebSocketOptions.to_httpx_ws_kwargs"></a>

Check warning on line 229 in api-reference/sdk/python/core.mdx

View check run for this annotation

Mintlify / Mintlify Validation (hanabiaiinc) - vale-spellcheck

api-reference/sdk/python/core.mdx#L229

Did you really mean 'to_httpx_ws_kwargs'?

#### to\_httpx\_ws\_kwargs

```python
def to_httpx_ws_kwargs() -> dict[str, Any]
```

Convert to kwargs dict for httpx_ws aconnect_ws/connect_ws.

Check warning on line 237 in api-reference/sdk/python/core.mdx

View check run for this annotation

Mintlify / Mintlify Validation (hanabiaiinc) - vale-spellcheck

api-reference/sdk/python/core.mdx#L237

Did you really mean 'kwargs'?

Check warning on line 237 in api-reference/sdk/python/core.mdx

View check run for this annotation

Mintlify / Mintlify Validation (hanabiaiinc) - vale-spellcheck

api-reference/sdk/python/core.mdx#L237

Did you really mean 'httpx_ws'?

<a id="fishaudio.core.iterators"></a>

# fishaudio.core.iterators
Expand Down Expand Up @@ -221,7 +275,7 @@
#### \_\_init\_\_

```python
def __init__(iterator: Iterator[bytes])

Check warning on line 278 in api-reference/sdk/python/core.mdx

View check run for this annotation

Mintlify / Mintlify Validation (hanabiaiinc) - vale-spellcheck

api-reference/sdk/python/core.mdx#L278

Did you really mean '__init__'?
```

Initialize the audio iterator wrapper.
Expand All @@ -235,7 +289,7 @@
#### \_\_iter\_\_

```python
def __iter__() -> Iterator[bytes]

Check warning on line 292 in api-reference/sdk/python/core.mdx

View check run for this annotation

Mintlify / Mintlify Validation (hanabiaiinc) - vale-spellcheck

api-reference/sdk/python/core.mdx#L292

Did you really mean '__iter__'?
```

Allow direct iteration over audio chunks.
Expand Down Expand Up @@ -300,7 +354,7 @@
#### \_\_init\_\_

```python
def __init__(async_iterator: AsyncIterator[bytes])

Check warning on line 357 in api-reference/sdk/python/core.mdx

View check run for this annotation

Mintlify / Mintlify Validation (hanabiaiinc) - vale-spellcheck

api-reference/sdk/python/core.mdx#L357

Did you really mean '__init__'?
```

Initialize the async audio iterator wrapper.
Expand All @@ -314,7 +368,7 @@
#### \_\_aiter\_\_

```python
def __aiter__() -> AsyncIterator[bytes]

Check warning on line 371 in api-reference/sdk/python/core.mdx

View check run for this annotation

Mintlify / Mintlify Validation (hanabiaiinc) - vale-spellcheck

api-reference/sdk/python/core.mdx#L371

Did you really mean '__aiter__'?
```

Allow direct async iteration over audio chunks.
Expand Down Expand Up @@ -346,57 +400,3 @@
f.write(audio)
```

<a id="fishaudio.core.websocket_options"></a>

# fishaudio.core.websocket\_options

WebSocket-level options for WebSocket connections.

<a id="fishaudio.core.websocket_options.WebSocketOptions"></a>

## WebSocketOptions Objects

```python
class WebSocketOptions()
```

Options for configuring WebSocket connections.

These options are passed directly to httpx_ws's connect_ws/aconnect_ws functions.
For complete documentation, see https://frankie567.github.io/httpx-ws/reference/httpx_ws/

**Attributes**:

- `keepalive_ping_timeout_seconds` - Maximum delay the client will wait for an answer
to its Ping event. If the delay is exceeded, WebSocketNetworkError will be
raised and the connection closed. Default: 20 seconds.
- `keepalive_ping_interval_seconds` - Interval at which the client will automatically
send a Ping event to keep the connection alive. Set to None to disable this
mechanism. Default: 20 seconds.
- `max_message_size_bytes` - Message size in bytes to receive from the server.
- `Default` - 65536 bytes (64 KiB).
- `queue_size` - Size of the queue where received messages will be held until they
are consumed. If the queue is full, the client will stop receiving messages
from the server until the queue has room available. Default: 512.


**Notes**:

Parameter descriptions adapted from httpx_ws documentation.

<a id="fishaudio.core.websocket_options.WebSocketOptions.to_httpx_ws_kwargs"></a>

#### to\_httpx\_ws\_kwargs

```python
def to_httpx_ws_kwargs() -> dict[str, Any]
```

Convert to kwargs dict for httpx_ws aconnect_ws/connect_ws.

<a id="fishaudio.core.omit"></a>

# fishaudio.core.omit

OMIT sentinel for distinguishing None from not-provided parameters.

47 changes: 22 additions & 25 deletions api-reference/sdk/python/overview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
[![PyPI version](https://img.shields.io/pypi/v/fish-audio-sdk.svg)](https://badge.fury.io/py/fish-audio-sdk)
[![Python Version](https://img.shields.io/badge/python-3.9+-blue)](https://pypi.org/project/fish-audio-sdk/)
[![PyPI - Downloads](https://img.shields.io/pypi/dm/fish-audio-sdk)](https://pypi.org/project/fish-audio-sdk/)
[![codecov](https://img.shields.io/codecov/c/github/fishaudio/fish-audio-python)](https://codecov.io/gh/fishaudio/fish-audio-python)

Check warning on line 14 in api-reference/sdk/python/overview.mdx

View check run for this annotation

Mintlify / Mintlify Validation (hanabiaiinc) - vale-spellcheck

api-reference/sdk/python/overview.mdx#L14

Did you really mean 'codecov'?
[![License](https://img.shields.io/github/license/fishaudio/fish-audio-python)](https://github.com/fishaudio/fish-audio-python/blob/main/LICENSE)

The official Python library for the Fish Audio API
Expand Down Expand Up @@ -91,13 +91,23 @@

### Text-to-Speech

**Selecting a model:**

```python
# Recommended for production
production_audio = client.tts.convert(
text="Production speech",
model="s2.1-pro",
)
```

**With custom voice:**

```python
# Use a specific voice by ID
audio = client.tts.convert(
text="Custom voice",
reference_id="9a9cf47702da476aa4629e2506d4a857"
reference_id="802e3bc2b27e49c2995d23ef70e6ac89"
)
```

Expand Down Expand Up @@ -138,7 +148,7 @@
audio = client.tts.stream(text="Hello!").collect()
```

[Learn more](https://docs.fish.audio/features/text-to-speech)
[Learn more](https://docs.fish.audio/developer-guide/sdk-guide/python/text-to-speech)

### Speech-to-Text

Expand All @@ -154,7 +164,7 @@
print(f"[{segment.start:.2f}s - {segment.end:.2f}s] {segment.text}")
```

[Learn more](https://docs.fish.audio/features/speech-to-text)
[Learn more](https://docs.fish.audio/developer-guide/sdk-guide/python/speech-to-text)

### Real-time Streaming

Expand All @@ -175,26 +185,16 @@
**Asynchronous:**

```python
import asyncio
from fishaudio import AsyncFishAudio

async def text_chunks():
yield "Hello, "
yield "this is "
yield "streaming!"

async def main():
async with AsyncFishAudio() as client:
# stream_websocket is an async generator — iterate it, don't await the call
audio_stream = client.tts.stream_websocket(text_chunks(), latency="balanced")
with open("out.mp3", "wb") as f:
async for chunk in audio_stream:
f.write(chunk)

asyncio.run(main())
audio_stream = await client.tts.stream_websocket(text_chunks(), latency="balanced")
play(audio_stream)
```

[Learn more](https://docs.fish.audio/features/realtime-streaming)
[Learn more](https://docs.fish.audio/developer-guide/sdk-guide/python/websocket)
Comment on lines 188 to +197

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== locate files =="
git ls-files | rg '(^|/)api-reference/sdk/python/(overview|resources)\.mdx$|(^|/)src/|^packages/|pyproject\.toml|README' || true

echo
echo "== overview snippet =="
sed -n '170,210p' api-reference/sdk/python/overview.mdx

echo
echo "== resources around method docs =="
sed -n '540,590p' api-reference/sdk/python/resources.mdx

echo
echo "== search stream_websocket occurrences =="
rg -n "stream_websocket|AsyncTTSClient|tts\.stream_websocket|for .* stream_websocket|await .* stream_websocket" api-reference/sdk/python . --glob '!**/.git/**' | head -200

Repository: fishaudio/docs

Length of output: 12956


🌐 Web query:

Fish.audio SDK Python AsyncTTSClient stream_websocket example async for await documentation

💡 Result:

To perform real-time, token-by-token text-to-speech streaming with the Fish.audio Python SDK using AsyncTTSClient (accessed via AsyncFishAudio), you should use the stream_websocket method [1][2]. The stream_websocket method is an asynchronous generator [1][3]. You do not await the call itself; instead, you iterate over it using an async for loop [1][2]. This allows you to process or play back each audio chunk as soon as it is received from the server [1][4]. Example usage: import asyncio from fishaudio import AsyncFishAudio async def text_chunks: # This async generator yields text tokens as they become available yield "Hello, " yield "this is " yield "streaming via WebSocket!" async def main: async with AsyncFishAudio as client: # stream_websocket is an async generator — iterate it, don't await the call audio_stream = client.tts.stream_websocket( text_chunks, reference_id="YOUR_VOICE_ID", latency="balanced") async for chunk in audio_stream: # Handle the incoming audio chunk (e.g., write to file or stream to audio device) print(f"Received {len(chunk)} bytes of audio") # with open("out.mp3", "ab") as f: # f.write(chunk) asyncio.run(main) Key implementation details: 1. Input Generator: You must provide an iterable (or async iterable) that yields text tokens [1][4]. 2. Streaming Iteration: Use async for chunk in client.tts.stream_websocket(...) to consume the audio chunks [4][2]. 3. Lifecycle: The SDK handles the underlying WebSocket lifecycle (frames, connection, etc.) automatically [1][4]. 4. Async Clients: Ensure you are using AsyncFishAudio for asynchronous operations, as FishAudio is for synchronous usage [1][5]. For further details, refer to the official Fish Audio documentation on WebSocket streaming [1] and the SDK cookbook [4].

Citations:


🌐 Web query:

site:docs.fish.audio/developer-guide/sdk-guide/python/websocket "async for chunk" "stream_websocket"

💡 Result:

The async for loop is the standard pattern in Python for consuming asynchronous streams, such as those provided by WebSocket clients [1]. When working with WebSocket APIs that support streaming (like text-to-speech or real-time data feeds), the client typically provides an asynchronous generator that yields chunks as they arrive over the network [1]. To use this pattern, you define an asynchronous loop that iterates over the response stream. This allows your application to process or forward each chunk immediately without waiting for the entire stream to complete [1]. Example Implementation: The following example demonstrates how to consume a stream from an asynchronous WebSocket client [1]: async def main: client = AsyncFishAudio # Define an async generator to provide input tokens/data async def data_source: async for item in your_async_source: yield item # Use async for to iterate over the WebSocket stream as chunks arrive async for chunk in client.tts.stream_websocket(data_source): # Process each chunk as it arrives process(chunk) asyncio.run(main) Key implementation details: - Async Generator: The method (e.g., stream_websocket) is designed as an asynchronous generator [1]. - Non-blocking: By using async for, your program remains responsive, allowing other tasks to run while waiting for new chunks to arrive from the WebSocket connection [1]. - Protocol Handling: While high-level SDKs often handle framing (such as MessagePack or JSON) automatically, direct WebSocket implementations require manual management of message framing and connection state if not using a library-provided method [1].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== websocket docs =="
for f in api-reference/sdk/python/overview.mdx developer-guide/sdk-guide/python/websocket.mdx; do
  if [ -f "$f" ]; then
    echo "-- $f --"
    sed -n '1,240p' "$f"
  fi
done

echo
echo "== realtime streaming docs sync/async snippets =="
sed -n '180,210p' features/realtime-streaming.mdx || true
sed -n '50,75p' developer-guide/best-practices/real-time-streaming.mdx || true
sed -n '135,155p' developer-guide/best-practices/real-time-streaming.mdx || true

Repository: fishaudio/docs

Length of output: 8648


Use async iteration for stream_websocket in the async example.

features/realtime-streaming.mdx states that async clients expose the same streaming methods and explicitly shows async for chunk in client.tts.stream_websocket(...). resources.mdx also documents the same method as an async iterator, so api-reference/sdk/python/overview.mdx should not await client.tts.stream_websocket(...) before play(audio_stream); align it with the async async for pattern shown elsewhere.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@api-reference/sdk/python/overview.mdx` around lines 188 - 197, Update the
async example around text_chunks to consume client.tts.stream_websocket(...)
with async iteration instead of awaiting it before play(audio_stream). Align the
example with the documented async iterator pattern and preserve the existing
streaming behavior.


### Voice Cloning

Expand Down Expand Up @@ -232,7 +232,7 @@
)
```

[Learn more](https://docs.fish.audio/features/voice-cloning)
[Learn more](https://docs.fish.audio/developer-guide/sdk-guide/python/voice-cloning)

## Resource Clients

Expand All @@ -249,9 +249,8 @@
from fishaudio.exceptions import (
AuthenticationError,
RateLimitError,
NotFoundError,
APIError,
FishAudioError,
ValidationError,
FishAudioError
)

try:
Expand All @@ -260,12 +259,10 @@
print("Invalid API key")
except RateLimitError:
print("Rate limit exceeded")
except NotFoundError:
print("Voice model not found")
except APIError as e:
print(f"API error {e.status}: {e.message}") # any other HTTP error, including 422 validation
except ValidationError as e:
print(f"Invalid request: {e}")
except FishAudioError as e:
print(f"SDK error: {e}")
print(f"API error: {e}")
```

## Resources
Expand Down
Loading
Loading