soniox 2.3.2__tar.gz → 2.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. soniox-2.4.0/.claude/settings.local.json +15 -0
  2. soniox-2.4.0/.gitignore +15 -0
  3. {soniox-2.3.2 → soniox-2.4.0}/CHANGELOG.md +34 -9
  4. {soniox-2.3.2 → soniox-2.4.0}/PKG-INFO +28 -15
  5. {soniox-2.3.2 → soniox-2.4.0}/README.md +19 -12
  6. {soniox-2.3.2 → soniox-2.4.0}/docs/async_client.md +46 -0
  7. {soniox-2.3.2 → soniox-2.4.0}/docs/realtime_client.md +48 -22
  8. {soniox-2.3.2 → soniox-2.4.0}/docs/types.md +345 -10
  9. soniox-2.4.0/docs/utils.md +201 -0
  10. {soniox-2.3.2 → soniox-2.4.0}/examples/async_soniox_client/tts_realtime_multiplexed_example.py +1 -1
  11. {soniox-2.3.2 → soniox-2.4.0}/justfile +25 -0
  12. {soniox-2.3.2 → soniox-2.4.0}/pyproject.toml +51 -6
  13. {soniox-2.3.2 → soniox-2.4.0}/scripts/generate_docs.py +29 -6
  14. {soniox-2.3.2 → soniox-2.4.0}/src/soniox/api/__init__.py +8 -0
  15. soniox-2.4.0/src/soniox/api/async_concurrency_limits.py +30 -0
  16. {soniox-2.3.2 → soniox-2.4.0}/src/soniox/api/async_files.py +13 -0
  17. {soniox-2.3.2 → soniox-2.4.0}/src/soniox/api/async_stt.py +13 -0
  18. {soniox-2.3.2 → soniox-2.4.0}/src/soniox/api/async_tts.py +1 -2
  19. soniox-2.4.0/src/soniox/api/async_usage_logs.py +77 -0
  20. soniox-2.4.0/src/soniox/api/concurrency_limits.py +30 -0
  21. {soniox-2.3.2 → soniox-2.4.0}/src/soniox/api/files.py +13 -0
  22. {soniox-2.3.2 → soniox-2.4.0}/src/soniox/api/stt.py +13 -0
  23. {soniox-2.3.2 → soniox-2.4.0}/src/soniox/api/tts.py +1 -2
  24. soniox-2.4.0/src/soniox/api/usage_logs.py +76 -0
  25. {soniox-2.3.2 → soniox-2.4.0}/src/soniox/client.py +28 -0
  26. {soniox-2.3.2 → soniox-2.4.0}/src/soniox/errors.py +5 -2
  27. soniox-2.4.0/src/soniox/py.typed +0 -0
  28. {soniox-2.3.2 → soniox-2.4.0}/src/soniox/realtime/async_stt.py +23 -11
  29. {soniox-2.3.2 → soniox-2.4.0}/src/soniox/realtime/async_tts.py +5 -5
  30. {soniox-2.3.2 → soniox-2.4.0}/src/soniox/realtime/stt.py +23 -11
  31. {soniox-2.3.2 → soniox-2.4.0}/src/soniox/realtime/tts.py +5 -5
  32. {soniox-2.3.2 → soniox-2.4.0}/src/soniox/types/__init__.py +48 -0
  33. {soniox-2.3.2 → soniox-2.4.0}/src/soniox/types/api.py +237 -16
  34. {soniox-2.3.2 → soniox-2.4.0}/src/soniox/types/realtime.py +35 -7
  35. {soniox-2.3.2 → soniox-2.4.0}/src/soniox/utils.py +14 -5
  36. soniox-2.4.0/tests/__init__.py +0 -0
  37. soniox-2.4.0/tests/conftest.py +26 -0
  38. soniox-2.4.0/tests/data/openapi.json +1 -0
  39. soniox-2.4.0/tests/helpers.py +43 -0
  40. soniox-2.4.0/tests/realtime/__init__.py +0 -0
  41. soniox-2.4.0/tests/realtime/cases.py +84 -0
  42. soniox-2.4.0/tests/realtime/mock_ws.py +148 -0
  43. soniox-2.4.0/tests/realtime/test_async_tts_realtime.py +732 -0
  44. soniox-2.4.0/tests/realtime/test_chaos_realtime.py +157 -0
  45. soniox-2.4.0/tests/realtime/test_fuzz_realtime.py +98 -0
  46. soniox-2.4.0/tests/realtime/test_keepalive.py +118 -0
  47. soniox-2.4.0/tests/realtime/test_live_ws.py +267 -0
  48. soniox-2.4.0/tests/realtime/test_stt_realtime.py +433 -0
  49. soniox-2.4.0/tests/realtime/test_tts_realtime.py +688 -0
  50. soniox-2.4.0/tests/unit/__init__.py +0 -0
  51. soniox-2.4.0/tests/unit/_openapi.py +87 -0
  52. soniox-2.4.0/tests/unit/_sdk_bindings.py +215 -0
  53. soniox-2.4.0/tests/unit/test_api.py +250 -0
  54. soniox-2.4.0/tests/unit/test_async_client.py +231 -0
  55. soniox-2.4.0/tests/unit/test_async_stt_workflows.py +317 -0
  56. soniox-2.4.0/tests/unit/test_async_tts_workflows.py +111 -0
  57. soniox-2.4.0/tests/unit/test_client.py +196 -0
  58. soniox-2.4.0/tests/unit/test_concurrency_limits.py +58 -0
  59. soniox-2.4.0/tests/unit/test_coverage_gaps.py +174 -0
  60. soniox-2.4.0/tests/unit/test_schema_drift.py +94 -0
  61. soniox-2.4.0/tests/unit/test_stt_extras.py +151 -0
  62. soniox-2.4.0/tests/unit/test_stt_workflows.py +322 -0
  63. soniox-2.4.0/tests/unit/test_sync_async_parity.py +138 -0
  64. soniox-2.4.0/tests/unit/test_tts_workflows.py +115 -0
  65. soniox-2.4.0/tests/unit/test_usage_logs.py +166 -0
  66. soniox-2.4.0/tests/unit/test_utils.py +266 -0
  67. soniox-2.4.0/tests/unit/test_webhooks.py +139 -0
  68. {soniox-2.3.2 → soniox-2.4.0}/uv.lock +338 -5
  69. soniox-2.3.2/.gitignore +0 -3
  70. soniox-2.3.2/docs/soniox/__init__.md +0 -282
  71. soniox-2.3.2/docs/soniox/api/__init__.md +0 -1968
  72. soniox-2.3.2/docs/soniox/api/api__utils.md +0 -112
  73. soniox-2.3.2/docs/soniox/api/api_async_auth.md +0 -61
  74. soniox-2.3.2/docs/soniox/api/api_async_files.md +0 -239
  75. soniox-2.3.2/docs/soniox/api/api_async_models.md +0 -55
  76. soniox-2.3.2/docs/soniox/api/api_async_stt.md +0 -595
  77. soniox-2.3.2/docs/soniox/api/api_async_transcriptions.md +0 -546
  78. soniox-2.3.2/docs/soniox/api/api_async_webhooks.md +0 -10
  79. soniox-2.3.2/docs/soniox/api/api_auth.md +0 -61
  80. soniox-2.3.2/docs/soniox/api/api_files.md +0 -239
  81. soniox-2.3.2/docs/soniox/api/api_models.md +0 -55
  82. soniox-2.3.2/docs/soniox/api/api_stt.md +0 -595
  83. soniox-2.3.2/docs/soniox/api/api_transcriptions.md +0 -546
  84. soniox-2.3.2/docs/soniox/api/api_webhooks.md +0 -152
  85. soniox-2.3.2/docs/soniox/realtime/__init__.md +0 -1148
  86. soniox-2.3.2/docs/soniox/realtime/realtime__utils.md +0 -194
  87. soniox-2.3.2/docs/soniox/realtime/realtime_async_stt.md +0 -548
  88. soniox-2.3.2/docs/soniox/realtime/realtime_stt.md +0 -546
  89. soniox-2.3.2/docs/soniox/soniox_client.md +0 -346
  90. soniox-2.3.2/docs/soniox/soniox_errors.md +0 -204
  91. soniox-2.3.2/docs/soniox/soniox_utils.md +0 -195
  92. soniox-2.3.2/docs/soniox/types/__init__.md +0 -532
  93. soniox-2.3.2/docs/soniox/types/types_api.md +0 -400
  94. soniox-2.3.2/docs/soniox/types/types_common.md +0 -34
  95. soniox-2.3.2/docs/soniox/types/types_realtime.md +0 -112
  96. soniox-2.3.2/docs/soniox/types/types_webhooks.md +0 -30
  97. {soniox-2.3.2 → soniox-2.4.0}/LICENSE +0 -0
  98. {soniox-2.3.2 → soniox-2.4.0}/assets/coffee_shop.mp3 +0 -0
  99. {soniox-2.3.2 → soniox-2.4.0}/assets/coffee_shop.pcm_s16le +0 -0
  100. {soniox-2.3.2 → soniox-2.4.0}/assets/two_way_translation.mp3 +0 -0
  101. {soniox-2.3.2 → soniox-2.4.0}/assets/two_way_translation.pcm_s16le +0 -0
  102. {soniox-2.3.2 → soniox-2.4.0}/examples/async_soniox_client/api_example.py +0 -0
  103. {soniox-2.3.2 → soniox-2.4.0}/examples/async_soniox_client/realtime_example.py +0 -0
  104. {soniox-2.3.2 → soniox-2.4.0}/examples/async_soniox_client/tts_api_example.py +0 -0
  105. {soniox-2.3.2 → soniox-2.4.0}/examples/async_soniox_client/tts_realtime_example.py +0 -0
  106. {soniox-2.3.2 → soniox-2.4.0}/examples/soniox_client/api_example.py +0 -0
  107. {soniox-2.3.2 → soniox-2.4.0}/examples/soniox_client/realtime_example.py +0 -0
  108. {soniox-2.3.2 → soniox-2.4.0}/examples/soniox_client/tts_api_example.py +0 -0
  109. {soniox-2.3.2 → soniox-2.4.0}/examples/soniox_client/tts_realtime_example.py +0 -0
  110. {soniox-2.3.2 → soniox-2.4.0}/examples/soniox_client/tts_realtime_multiplexed_example.py +0 -0
  111. {soniox-2.3.2 → soniox-2.4.0}/src/soniox/__init__.py +0 -0
  112. {soniox-2.3.2 → soniox-2.4.0}/src/soniox/api/_utils.py +0 -0
  113. {soniox-2.3.2 → soniox-2.4.0}/src/soniox/api/async_auth.py +0 -0
  114. {soniox-2.3.2 → soniox-2.4.0}/src/soniox/api/async_models.py +0 -0
  115. {soniox-2.3.2 → soniox-2.4.0}/src/soniox/api/async_tts_models.py +0 -0
  116. {soniox-2.3.2 → soniox-2.4.0}/src/soniox/api/async_webhooks.py +0 -0
  117. {soniox-2.3.2 → soniox-2.4.0}/src/soniox/api/auth.py +0 -0
  118. {soniox-2.3.2 → soniox-2.4.0}/src/soniox/api/models.py +0 -0
  119. {soniox-2.3.2 → soniox-2.4.0}/src/soniox/api/tts_models.py +0 -0
  120. {soniox-2.3.2 → soniox-2.4.0}/src/soniox/api/webhooks.py +0 -0
  121. {soniox-2.3.2 → soniox-2.4.0}/src/soniox/realtime/__init__.py +0 -0
  122. {soniox-2.3.2 → soniox-2.4.0}/src/soniox/realtime/_constants.py +0 -0
  123. {soniox-2.3.2 → soniox-2.4.0}/src/soniox/realtime/_utils.py +0 -0
  124. {soniox-2.3.2 → soniox-2.4.0}/src/soniox/types/common.py +0 -0
  125. {soniox-2.3.2 → soniox-2.4.0}/src/soniox/types/webhooks.py +0 -0
@@ -0,0 +1,15 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(uv run *)",
5
+ "Bash(just test *)",
6
+ "Bash(/home/miha/workspace/soniox_python_sdk/.venv/bin/python *)",
7
+ "Bash(git apply *)",
8
+ "Bash(git add *)",
9
+ "Bash(sed -n '110,140p' tests/unit/test_client.py)",
10
+ "Bash(sed -n '85,120p' tests/unit/test_async_client.py)",
11
+ "Bash(/tmp/soniox-v240-test/.venv/bin/python -u test_schema_sync.py)",
12
+ "Bash(awk '/^class Transcription\\\\b/,/^class [A-Z]/' src/soniox/types/api.py)"
13
+ ]
14
+ }
15
+ }
@@ -0,0 +1,15 @@
1
+ dist
2
+ build
3
+ __pycache__
4
+ generated-docs
5
+
6
+ # Virtualenv
7
+ .venv
8
+
9
+ # Test / coverage artifacts
10
+ .coverage
11
+ .pytest_cache
12
+ htmlcov
13
+
14
+ # Local audio scratch
15
+ *.wav
@@ -21,12 +21,12 @@ The format is inspired by Keep a Changelog and this project follows Semantic Ver
21
21
 
22
22
  Use the following categories when adding entries:
23
23
 
24
- - **Added** new features or capabilities.
25
- - **Changed** updates to existing functionality.
26
- - **Deprecated** features that will be removed soon.
27
- - **Removed** features removed in this version.
28
- - **Fixed** bug fixes.
29
- - **Security** vulnerability fixes.
24
+ - **Added** - new features or capabilities.
25
+ - **Changed** - updates to existing functionality.
26
+ - **Deprecated** - features that will be removed soon.
27
+ - **Removed** - features removed in this version.
28
+ - **Fixed** - bug fixes.
29
+ - **Security** - vulnerability fixes.
30
30
 
31
31
  ---
32
32
 
@@ -53,9 +53,9 @@ This project follows Semantic Versioning:
53
53
 
54
54
  Examples:
55
55
 
56
- - `1.0.0` stable API
57
- - `1.1.0` new features added
58
- - `1.1.1` bug fixes only
56
+ - `1.0.0` - stable API
57
+ - `1.1.0` - new features added
58
+ - `1.1.1` - bug fixes only
59
59
 
60
60
  ---
61
61
 
@@ -77,6 +77,31 @@ Examples:
77
77
 
78
78
  ---
79
79
 
80
+ ## [2.4.0] - 13 may 2026
81
+
82
+ ### Added
83
+
84
+ - `client.files.count()` and `client.stt.count()` endpoints (and async variants) returning the total count of files and transcriptions.
85
+ - `client.usage_logs.list()` and `list_all()` (and async variants) for retrieving per-request usage logs over a time window.
86
+ - `client.concurrency_limits.get()` (and async variant) returning current and configured concurrency limits for realtime STT and TTS, scoped to project and organization.
87
+ - `TtsVoice.description` and `TtsVoice.gender` (`"male" | "female" | "neutral"`) fields, exposing richer voice metadata from the server. Enables programmatic voice filtering.
88
+ - `RealtimeSTTAudioFormat`, `RealtimeSTTHeaderFormat`, `RealtimeSTTRawFormat` literal types covering the 30 audio formats accepted by realtime STT.
89
+ - `py.typed` marker (PEP 561): downstream type-checkers now consume the SDK's inline type annotations.
90
+ - `StructuredContext.general` and `StructuredContext.translation_terms` now accept a plain dict in addition to the typed item lists.
91
+ - `finalize: bool = True` keyword-only parameter on realtime STT `pause()` (sync and async). When `False`, pause without emitting a finalize.
92
+ - `TtsModel.languages` field listing the languages supported by the model. Defaults to an empty list for backward compatibility with direct construction.
93
+ - `Language` type exported from `soniox.types` (previously only reachable via `soniox.types.api`).
94
+ - `ApiError.more_info` field - optional URL pointing to documentation for resolving an error.
95
+ - `Model.supports_max_endpoint_delay` flag indicating whether a model supports the `max_endpoint_delay_ms` option.
96
+ - Internal test suite (pytest + respx + polyfactory) covering REST, realtime websocket, schema drift, and sync/async parity. Not shipped to users; runnable via `just test`.
97
+
98
+ ### Changed
99
+
100
+ - `RealtimeSTTConfig.audio_format` is now typed as a Literal union instead of bare `str`. Passing an unrecognized value raises at validation time instead of failing on the wire.
101
+ - Raw realtime STT audio formats (`pcm_*`, `mulaw`, `alaw`) now require `sample_rate` and `num_channels` on `RealtimeSTTConfig`. Previously these were silently accepted client-side and rejected by the server.
102
+
103
+ ---
104
+
80
105
  ## [2.3.2] - 4 may 2026
81
106
 
82
107
  ### Added
@@ -1,8 +1,8 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: soniox
3
- Version: 2.3.2
3
+ Version: 2.4.0
4
4
  Summary: The official Python SDK for the Soniox API (STT, REST)
5
- Project-URL: Homepage, https://sonoix.com
5
+ Project-URL: Homepage, https://soniox.com
6
6
  Project-URL: Documentation, https://soniox.com/docs
7
7
  Project-URL: Repository, https://github.com/soniox/soniox-python
8
8
  Author-email: Soniox <support@soniox.com>
@@ -31,13 +31,20 @@ Requires-Dist: pydantic>2
31
31
  Requires-Dist: websockets>11.0
32
32
  Provides-Extra: dev
33
33
  Requires-Dist: griffe>=1.15.0; extra == 'dev'
34
- Requires-Dist: pyright>=1.1.0; extra == 'dev'
34
+ Requires-Dist: polyfactory>=2.15.0; extra == 'dev'
35
+ Requires-Dist: pyright>=1.1.409; extra == 'dev'
36
+ Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
37
+ Requires-Dist: pytest-cov>=5.0; extra == 'dev'
38
+ Requires-Dist: pytest-timeout>=2.3; extra == 'dev'
39
+ Requires-Dist: pytest>=8.0.0; extra == 'dev'
40
+ Requires-Dist: respx>=0.21.1; extra == 'dev'
35
41
  Requires-Dist: ruff>=0.0.0; extra == 'dev'
36
42
  Description-Content-Type: text/markdown
37
43
 
38
44
  # Soniox Python SDK
39
45
 
40
46
  The SDK exposes two clients: `SonioxClient` (sync) and `AsyncSonioxClient` (async). Each client supports:
47
+
41
48
  - STT over REST (`client.stt`) and realtime WebSocket (`client.realtime.stt`)
42
49
  - TTS over REST (`client.tts`) and realtime WebSocket (`client.realtime.tts`)
43
50
  - auth, file uploads, model listing, webhooks, and typed request/response models
@@ -53,20 +60,23 @@ export SONIOX_API_KEY=<your-key>
53
60
 
54
61
  Get your API key from the [Soniox Console](https://console.soniox.com) and inject it once per shell session. Both clients read `SONIOX_API_KEY` by default, but you can override it per-client if needed.
55
62
 
63
+ > **Avoid Python 3.13.6** - it has a regression in `ssl` that hangs realtime STT/TTS (CPython issue [#137583](https://github.com/python/cpython/issues/137583)). Use any other 3.10-3.13.x.
64
+
56
65
  ## Quick run (STT + TTS, REST + realtime)
57
66
 
58
- 1. **REST STT transcription**: copy this snippet or run [`examples/soniox_client/api_example.py`](https://github.com/soniox/soniox-python/blob/main/examples/soniox_client/api_example.py).
67
+ 1. **REST STT transcription**: transcribe a local file end-to-end in one call. Full example: [`examples/soniox_client/api_example.py`](https://github.com/soniox/soniox-python/blob/main/examples/soniox_client/api_example.py).
59
68
 
60
69
  ```python
61
70
  from soniox import SonioxClient
62
71
 
63
72
  client = SonioxClient()
64
- transcription = client.stt.transcribe(
65
- audio_url="https://soniox.com/media/examples/coffee_shop.mp3",
66
- client_reference_id="docs-quick-start",
73
+ transcript = client.stt.transcribe_and_wait_with_tokens(
74
+ file="path/to/audio.mp3", # local file
75
+ # audio_url="https://example.com/audio.mp3", # or remote URL
76
+ delete_after=True, # auto-cleanup file + transcription
67
77
  )
68
- client.stt.wait(transcription.id, timeout_sec=60)
69
- print(client.stt.get_transcript(transcription.id).text[:200])
78
+ print(transcript.text)
79
+ client.close()
70
80
  ```
71
81
 
72
82
  2. **REST TTS generation**: convert text to an audio file.
@@ -118,17 +128,19 @@ def realtime():
118
128
  non_final_tokens.clear()
119
129
 
120
130
  realtime()
131
+ client.close()
121
132
  ```
122
133
 
123
134
  See [`examples/soniox_client/realtime_example.py`](https://github.com/soniox/soniox-python/blob/main/examples/soniox_client/realtime_example.py) for the full flow.
124
135
 
125
- 4. **Realtime TTS streaming**: send text chunks and read generated audio chunks from the session.
136
+ 4. **Realtime TTS streaming**: send text chunks and write audio to a file as it arrives.
126
137
 
127
138
  ```python
128
139
  from uuid import uuid4
129
140
 
130
141
  from soniox import SonioxClient
131
142
  from soniox.types import RealtimeTTSConfig
143
+ from soniox.utils import output_file_for_audio_format
132
144
 
133
145
  client = SonioxClient()
134
146
  config = RealtimeTTSConfig(
@@ -139,17 +151,18 @@ config = RealtimeTTSConfig(
139
151
  audio_format="wav",
140
152
  )
141
153
 
142
- audio_chunks: list[bytes] = []
143
- with client.realtime.tts.connect(config=config) as session:
144
- session.keep_alive()
154
+ output_file = output_file_for_audio_format("wav", "tts_realtime_output")
155
+ bytes_written = 0
156
+ with client.realtime.tts.connect(config=config) as session, output_file.open("wb") as f:
145
157
  session.send_text_chunks(
146
158
  ["Hello from realtime TTS. ", "This is the final chunk."],
147
159
  text_end=True,
148
160
  )
149
161
  for chunk in session.receive_audio_chunks():
150
- audio_chunks.append(chunk)
162
+ f.write(chunk)
163
+ bytes_written += len(chunk)
151
164
 
152
- print(f"Collected {sum(len(c) for c in audio_chunks)} bytes of audio")
165
+ print(f"Wrote {bytes_written} bytes to {output_file.resolve()}")
153
166
  ```
154
167
 
155
168
  Run the full example at [`examples/soniox_client/tts_realtime_example.py`](https://github.com/soniox/soniox-python/blob/main/examples/soniox_client/tts_realtime_example.py) or async version at [`examples/async_soniox_client/tts_realtime_example.py`](https://github.com/soniox/soniox-python/blob/main/examples/async_soniox_client/tts_realtime_example.py).
@@ -1,6 +1,7 @@
1
1
  # Soniox Python SDK
2
2
 
3
3
  The SDK exposes two clients: `SonioxClient` (sync) and `AsyncSonioxClient` (async). Each client supports:
4
+
4
5
  - STT over REST (`client.stt`) and realtime WebSocket (`client.realtime.stt`)
5
6
  - TTS over REST (`client.tts`) and realtime WebSocket (`client.realtime.tts`)
6
7
  - auth, file uploads, model listing, webhooks, and typed request/response models
@@ -16,20 +17,23 @@ export SONIOX_API_KEY=<your-key>
16
17
 
17
18
  Get your API key from the [Soniox Console](https://console.soniox.com) and inject it once per shell session. Both clients read `SONIOX_API_KEY` by default, but you can override it per-client if needed.
18
19
 
20
+ > **Avoid Python 3.13.6** - it has a regression in `ssl` that hangs realtime STT/TTS (CPython issue [#137583](https://github.com/python/cpython/issues/137583)). Use any other 3.10-3.13.x.
21
+
19
22
  ## Quick run (STT + TTS, REST + realtime)
20
23
 
21
- 1. **REST STT transcription**: copy this snippet or run [`examples/soniox_client/api_example.py`](https://github.com/soniox/soniox-python/blob/main/examples/soniox_client/api_example.py).
24
+ 1. **REST STT transcription**: transcribe a local file end-to-end in one call. Full example: [`examples/soniox_client/api_example.py`](https://github.com/soniox/soniox-python/blob/main/examples/soniox_client/api_example.py).
22
25
 
23
26
  ```python
24
27
  from soniox import SonioxClient
25
28
 
26
29
  client = SonioxClient()
27
- transcription = client.stt.transcribe(
28
- audio_url="https://soniox.com/media/examples/coffee_shop.mp3",
29
- client_reference_id="docs-quick-start",
30
+ transcript = client.stt.transcribe_and_wait_with_tokens(
31
+ file="path/to/audio.mp3", # local file
32
+ # audio_url="https://example.com/audio.mp3", # or remote URL
33
+ delete_after=True, # auto-cleanup file + transcription
30
34
  )
31
- client.stt.wait(transcription.id, timeout_sec=60)
32
- print(client.stt.get_transcript(transcription.id).text[:200])
35
+ print(transcript.text)
36
+ client.close()
33
37
  ```
34
38
 
35
39
  2. **REST TTS generation**: convert text to an audio file.
@@ -81,17 +85,19 @@ def realtime():
81
85
  non_final_tokens.clear()
82
86
 
83
87
  realtime()
88
+ client.close()
84
89
  ```
85
90
 
86
91
  See [`examples/soniox_client/realtime_example.py`](https://github.com/soniox/soniox-python/blob/main/examples/soniox_client/realtime_example.py) for the full flow.
87
92
 
88
- 4. **Realtime TTS streaming**: send text chunks and read generated audio chunks from the session.
93
+ 4. **Realtime TTS streaming**: send text chunks and write audio to a file as it arrives.
89
94
 
90
95
  ```python
91
96
  from uuid import uuid4
92
97
 
93
98
  from soniox import SonioxClient
94
99
  from soniox.types import RealtimeTTSConfig
100
+ from soniox.utils import output_file_for_audio_format
95
101
 
96
102
  client = SonioxClient()
97
103
  config = RealtimeTTSConfig(
@@ -102,17 +108,18 @@ config = RealtimeTTSConfig(
102
108
  audio_format="wav",
103
109
  )
104
110
 
105
- audio_chunks: list[bytes] = []
106
- with client.realtime.tts.connect(config=config) as session:
107
- session.keep_alive()
111
+ output_file = output_file_for_audio_format("wav", "tts_realtime_output")
112
+ bytes_written = 0
113
+ with client.realtime.tts.connect(config=config) as session, output_file.open("wb") as f:
108
114
  session.send_text_chunks(
109
115
  ["Hello from realtime TTS. ", "This is the final chunk."],
110
116
  text_end=True,
111
117
  )
112
118
  for chunk in session.receive_audio_chunks():
113
- audio_chunks.append(chunk)
119
+ f.write(chunk)
120
+ bytes_written += len(chunk)
114
121
 
115
- print(f"Collected {sum(len(c) for c in audio_chunks)} bytes of audio")
122
+ print(f"Wrote {bytes_written} bytes to {output_file.resolve()}")
116
123
  ```
117
124
 
118
125
  Run the full example at [`examples/soniox_client/tts_realtime_example.py`](https://github.com/soniox/soniox-python/blob/main/examples/soniox_client/tts_realtime_example.py) or async version at [`examples/async_soniox_client/tts_realtime_example.py`](https://github.com/soniox/soniox-python/blob/main/examples/async_soniox_client/tts_realtime_example.py).
@@ -47,6 +47,8 @@ AsyncSonioxClient(api_key: str | None = None, api_base_url: str | None = None, w
47
47
  | `tts` | `AsyncTtsAPI` | Text-to-Speech API namespace |
48
48
  | `models` | `AsyncModelsAPI` | List of available Text-to-Speech models. |
49
49
  | `tts_models` | `AsyncTtsModelsAPI` | - |
50
+ | `usage_logs` | `AsyncUsageLogsAPI` | Per-request usage log entries ordered by end_time. |
51
+ | `concurrency_limits` | `AsyncConcurrencyLimitsAPI` | - |
50
52
  | `auth` | `AsyncAuthAPI` | Authentication API namespace. |
51
53
  | `webhooks` | `AsyncSonioxWebhooksAPI` | Webhook utilities API namespace. |
52
54
  | `realtime` | `AsyncRealtimeAPI` | Entrypoint for async realtime helpers on AsyncSonioxClient. |
@@ -143,6 +145,28 @@ Performs a GET request to ``/files`` with optional pagination.
143
145
 
144
146
  ***
145
147
 
148
+ <a id="asyncfilesapi-count"></a>
149
+
150
+ ### count()
151
+
152
+ ```python
153
+ count() -> GetFilesCountResponse
154
+ ```
155
+
156
+ Return a breakdown of uploaded file counts.
157
+
158
+ Performs a GET request to ``/files/count``.
159
+
160
+ **Returns**
161
+
162
+ `GetFilesCountResponse`
163
+
164
+ **Raises**
165
+
166
+ - `SonioxAPIError` When the API returns an error.
167
+
168
+ ***
169
+
146
170
  <a id="asyncfilesapi-list_all"></a>
147
171
 
148
172
  ### list_all()
@@ -390,6 +414,28 @@ Performs a GET request to ``/transcriptions`` with optional pagination.
390
414
 
391
415
  ***
392
416
 
417
+ <a id="asyncsttapi-count"></a>
418
+
419
+ ### count()
420
+
421
+ ```python
422
+ count() -> GetTranscriptionsCountResponse
423
+ ```
424
+
425
+ Return a breakdown of transcription counts.
426
+
427
+ Performs a GET request to ``/transcriptions/count``.
428
+
429
+ **Returns**
430
+
431
+ `GetTranscriptionsCountResponse`
432
+
433
+ **Raises**
434
+
435
+ - `SonioxAPIError` When the API returns an error.
436
+
437
+ ***
438
+
393
439
  <a id="asyncsttapi-list_all"></a>
394
440
 
395
441
  ### list_all()
@@ -184,10 +184,12 @@ is established when entering the context manager.
184
184
  close() -> None
185
185
  ```
186
186
 
187
- Gracefully close the realtime session.
187
+ Close the realtime session and release the WebSocket.
188
188
 
189
- Sends a final empty message to signal end-of-stream, then closes
190
- the WebSocket connection. Calling this method multiple times is safe.
189
+ Signals end-of-audio to the server and clears the underlying
190
+ connection. Subsequent calls are no-ops.
191
+
192
+ Called automatically when exiting the context manager.
191
193
 
192
194
  **Returns**
193
195
 
@@ -234,17 +236,18 @@ send_bytes(chunks: bytes | Iterator[bytes], *, finish: bool = True) -> None
234
236
 
235
237
  Send audio data to the realtime stream.
236
238
 
237
- This method accepts either a single bytes object or an iterator
238
- yielding audio chunks. When an iterator is provided, a FINISH
239
- control message is sent automatically after all chunks have
240
- been transmitted.
239
+ Accepts either a single bytes object or an iterator yielding byte
240
+ chunks (e.g. from `throttle_audio`). If `finish=True` (the default),
241
+ an end-of-audio signal is sent after the last chunk; pass
242
+ `finish=False` when you intend to send more audio later in the
243
+ same session.
241
244
 
242
245
  **Parameters**
243
246
 
244
247
  | Parameter | Type | Description |
245
248
  | ------ | ------ | ------ |
246
- | `chunks` | `bytes \| Iterator[bytes]` | Audio data as raw bytes or an iterator of byte chunks. |
247
- | `finish` | `bool` | Whether to send a finish signal after streaming completes. |
249
+ | `chunks` | `bytes \| Iterator[bytes]` | Raw bytes or an iterator of byte chunks. |
250
+ | `finish` | `bool` | If True (default), signal end-of-audio after the last chunk. |
248
251
 
249
252
  **Returns**
250
253
 
@@ -289,7 +292,11 @@ end-of-audio or requesting finalization.
289
292
  finish() -> None
290
293
  ```
291
294
 
292
- Signal that no more audio will be sent for this session.
295
+ Signal end-of-audio.
296
+
297
+ The server finalizes any pending tokens and closes the
298
+ connection. Continue iterating `receive_events()` to consume
299
+ the remaining tokens.
293
300
 
294
301
  **Returns**
295
302
 
@@ -441,7 +448,7 @@ Receive realtime events and dispatch them to a handler callback.
441
448
  ### pause()
442
449
 
443
450
  ```python
444
- pause() -> None
451
+ pause(*, finalize: bool = True) -> None
445
452
  ```
446
453
 
447
454
  Pause the session, suppressing outgoing audio and starting a
@@ -454,6 +461,12 @@ timing out the session.
454
461
 
455
462
  Calling `pause` on an already-paused session is a no-op.
456
463
 
464
+ **Parameters**
465
+
466
+ | Parameter | Type | Description |
467
+ | ------ | ------ | ------ |
468
+ | `finalize` | `bool` | If True (default), call `finalize()` before pausing. |
469
+
457
470
  **Returns**
458
471
 
459
472
  `None`
@@ -1246,10 +1259,12 @@ is established when entering the async context manager.
1246
1259
  close() -> None
1247
1260
  ```
1248
1261
 
1249
- Gracefully close the realtime session.
1262
+ Close the realtime session and release the WebSocket.
1250
1263
 
1251
- Sends a final empty message to signal end-of-stream, then closes
1252
- the WebSocket connection. Calling this method multiple times is safe.
1264
+ Signals end-of-audio to the server and clears the underlying
1265
+ connection. Subsequent calls are no-ops.
1266
+
1267
+ Called automatically when exiting the async context manager.
1253
1268
 
1254
1269
  **Returns**
1255
1270
 
@@ -1296,17 +1311,18 @@ send_bytes(chunks: bytes | AsyncIterator[bytes], *, finish: bool = True) -> None
1296
1311
 
1297
1312
  Send audio data to the realtime stream.
1298
1313
 
1299
- This method accepts either a single bytes object or an iterator
1300
- yielding audio chunks. When an iterator is provided, a
1301
- FINISH control message is sent automatically after all chunks
1302
- have been transmitted.
1314
+ Accepts either a single bytes object or an async iterator yielding
1315
+ byte chunks (e.g. from `throttle_audio_async`). If `finish=True`
1316
+ (the default), an end-of-audio signal is sent after the last chunk;
1317
+ pass `finish=False` when you intend to send more audio later in the
1318
+ same session.
1303
1319
 
1304
1320
  **Parameters**
1305
1321
 
1306
1322
  | Parameter | Type | Description |
1307
1323
  | ------ | ------ | ------ |
1308
- | `chunks` | `bytes \| AsyncIterator[bytes]` | Audio data as raw bytes or an iterator of byte chunks. |
1309
- | `finish` | `bool` | Whether to send a finish signal after streaming completes. |
1324
+ | `chunks` | `bytes \| AsyncIterator[bytes]` | Raw bytes or an async iterator of byte chunks. |
1325
+ | `finish` | `bool` | If True (default), signal end-of-audio after the last chunk. |
1310
1326
 
1311
1327
  **Returns**
1312
1328
 
@@ -1351,7 +1367,11 @@ end-of-audio or requesting finalization.
1351
1367
  finish() -> None
1352
1368
  ```
1353
1369
 
1354
- Signal that no more audio will be sent for this session.
1370
+ Signal end-of-audio.
1371
+
1372
+ The server finalizes any pending tokens and closes the
1373
+ connection. Continue iterating `receive_events()` to consume
1374
+ the remaining tokens.
1355
1375
 
1356
1376
  **Returns**
1357
1377
 
@@ -1503,7 +1523,7 @@ Receive realtime events and dispatch them to a handler callback.
1503
1523
  ### pause()
1504
1524
 
1505
1525
  ```python
1506
- pause() -> None
1526
+ pause(*, finalize: bool = True) -> None
1507
1527
  ```
1508
1528
 
1509
1529
  Pause the session, suppressing outgoing audio and starting a
@@ -1516,6 +1536,12 @@ timing out the session.
1516
1536
 
1517
1537
  Calling `pause` on an already-paused session is a no-op.
1518
1538
 
1539
+ **Parameters**
1540
+
1541
+ | Parameter | Type | Description |
1542
+ | ------ | ------ | ------ |
1543
+ | `finalize` | `bool` | If True (default), call `finalize()` before pausing. |
1544
+
1519
1545
  **Returns**
1520
1546
 
1521
1547
  `None`