deepctl-cmd-speak 0.0.3__tar.gz → 0.0.4__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.
- {deepctl_cmd_speak-0.0.3 → deepctl_cmd_speak-0.0.4}/PKG-INFO +2 -2
- {deepctl_cmd_speak-0.0.3 → deepctl_cmd_speak-0.0.4}/pyproject.toml +2 -2
- {deepctl_cmd_speak-0.0.3 → deepctl_cmd_speak-0.0.4}/src/deepctl_cmd_speak/command.py +91 -23
- {deepctl_cmd_speak-0.0.3 → deepctl_cmd_speak-0.0.4}/src/deepctl_cmd_speak.egg-info/PKG-INFO +2 -2
- {deepctl_cmd_speak-0.0.3 → deepctl_cmd_speak-0.0.4}/src/deepctl_cmd_speak.egg-info/requires.txt +1 -1
- {deepctl_cmd_speak-0.0.3 → deepctl_cmd_speak-0.0.4}/README.md +0 -0
- {deepctl_cmd_speak-0.0.3 → deepctl_cmd_speak-0.0.4}/setup.cfg +0 -0
- {deepctl_cmd_speak-0.0.3 → deepctl_cmd_speak-0.0.4}/src/deepctl_cmd_speak/__init__.py +0 -0
- {deepctl_cmd_speak-0.0.3 → deepctl_cmd_speak-0.0.4}/src/deepctl_cmd_speak/models.py +0 -0
- {deepctl_cmd_speak-0.0.3 → deepctl_cmd_speak-0.0.4}/src/deepctl_cmd_speak.egg-info/SOURCES.txt +0 -0
- {deepctl_cmd_speak-0.0.3 → deepctl_cmd_speak-0.0.4}/src/deepctl_cmd_speak.egg-info/dependency_links.txt +0 -0
- {deepctl_cmd_speak-0.0.3 → deepctl_cmd_speak-0.0.4}/src/deepctl_cmd_speak.egg-info/entry_points.txt +0 -0
- {deepctl_cmd_speak-0.0.3 → deepctl_cmd_speak-0.0.4}/src/deepctl_cmd_speak.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: deepctl-cmd-speak
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.4
|
|
4
4
|
Summary: Speak (text-to-speech) command for deepctl
|
|
5
5
|
Author-email: Deepgram <devrel@deepgram.com>
|
|
6
6
|
Maintainer-email: Deepgram <devrel@deepgram.com>
|
|
@@ -14,7 +14,7 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
14
14
|
Classifier: Programming Language :: Python :: 3.12
|
|
15
15
|
Requires-Python: >=3.10
|
|
16
16
|
Description-Content-Type: text/markdown
|
|
17
|
-
Requires-Dist: deepctl-core>=0.
|
|
17
|
+
Requires-Dist: deepctl-core>=0.2.15
|
|
18
18
|
Requires-Dist: click>=8.0.0
|
|
19
19
|
Requires-Dist: rich>=13.0.0
|
|
20
20
|
Requires-Dist: pydantic>=2.0.0
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "deepctl-cmd-speak"
|
|
7
|
-
version = "0.0.
|
|
7
|
+
version = "0.0.4" # x-release-please-version
|
|
8
8
|
description = "Speak (text-to-speech) command for deepctl"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
@@ -21,7 +21,7 @@ classifiers = [
|
|
|
21
21
|
keywords = ["deepgram", "cli", "tts", "text-to-speech", "speak"]
|
|
22
22
|
requires-python = ">=3.10"
|
|
23
23
|
dependencies = [
|
|
24
|
-
"deepctl-core>=0.
|
|
24
|
+
"deepctl-core>=0.2.15",
|
|
25
25
|
"click>=8.0.0",
|
|
26
26
|
"rich>=13.0.0",
|
|
27
27
|
"pydantic>=2.0.0",
|
|
@@ -27,6 +27,13 @@ if TYPE_CHECKING:
|
|
|
27
27
|
|
|
28
28
|
console = Console(stderr=True)
|
|
29
29
|
|
|
30
|
+
# Flux (Speak v2) streaming controls, per the /v2/speak API. `speed` is a
|
|
31
|
+
# 0.05-increment multiplier and `expressivity` is a small integer range; both
|
|
32
|
+
# are validated up front so we fail with a clear message instead of surfacing
|
|
33
|
+
# a raw SPEED_OUT_OF_RANGE / server error mid-stream.
|
|
34
|
+
_FLUX_SPEEDS = (0.85, 0.90, 0.95, 1.00, 1.05, 1.10, 1.15)
|
|
35
|
+
_FLUX_EXPRESSIVITY = (-2, -1, 0, 1, 2)
|
|
36
|
+
|
|
30
37
|
|
|
31
38
|
def _fmt_bytes(n: int) -> str:
|
|
32
39
|
"""Human-readable byte count for progress display."""
|
|
@@ -162,26 +169,38 @@ class SpeakCommand(BaseCommand):
|
|
|
162
169
|
ci_friendly = True
|
|
163
170
|
|
|
164
171
|
examples = [
|
|
172
|
+
# Flux TTS is the default (flux-alexis-en) — WebSocket streaming,
|
|
173
|
+
# raw audio wrapped in WAV. Piped audio is a streaming WAV (unknown
|
|
174
|
+
# length up front), so pass `-loglevel error` to silence ffmpeg's
|
|
175
|
+
# cosmetic end-of-stream notice.
|
|
165
176
|
'dg speak "Hello world"',
|
|
166
|
-
'dg speak "Hello world" -o hello.
|
|
167
|
-
"dg speak --file message.txt -o output.
|
|
168
|
-
'
|
|
169
|
-
|
|
177
|
+
'dg speak "Hello world" -o hello.wav',
|
|
178
|
+
"dg speak --file message.txt -o output.wav",
|
|
179
|
+
'dg speak "Hello" | ffplay -loglevel error -nodisp -autoexit -',
|
|
180
|
+
# Flux TTS streaming controls: --speed (0.85-1.15) and beta
|
|
181
|
+
# --expressivity (-2..2, default 0).
|
|
182
|
+
'dg speak "A little slower, please" --speed 0.9 -o slow.wav',
|
|
183
|
+
'dg speak "So exciting!" --expressivity 2 -o lively.wav # beta; default: 0',
|
|
184
|
+
# Aura (Speak v1, batch REST) — opt in with -m aura-*; needed for
|
|
185
|
+
# containerized formats like mp3.
|
|
186
|
+
'dg speak "Hello" -m aura-2-asteria-en -o hello.mp3',
|
|
170
187
|
'dg speak "Hello" -m aura-2-luna-en -o hello.wav --encoding linear16 --container wav',
|
|
171
|
-
|
|
172
|
-
#
|
|
173
|
-
|
|
174
|
-
'dg speak "Hello from Flux" -m flux-alexis-en -o hello.wav',
|
|
175
|
-
'dg speak "Hello from Flux" -m flux-alexis-en | ffplay -loglevel error -nodisp -autoexit -',
|
|
188
|
+
'echo "Hello" | dg speak -o hello.mp3 -m aura-2-asteria-en',
|
|
189
|
+
# Aura-2 Spanish voice (run `dg models` for the full list).
|
|
190
|
+
'dg speak "Hola, mundo" -m aura-2-selena-es -o hola.mp3',
|
|
176
191
|
]
|
|
177
192
|
agent_help = (
|
|
178
193
|
"Convert text to speech using Deepgram's TTS API. "
|
|
179
194
|
"Text can be provided as an argument, from a file, or piped via stdin. "
|
|
180
195
|
"Audio is written to a file (--output) or stdout for piping. "
|
|
181
|
-
"
|
|
182
|
-
"
|
|
183
|
-
"
|
|
184
|
-
"
|
|
196
|
+
"By default (flux-* models, e.g. flux-alexis-en) uses Flux TTS / Speak "
|
|
197
|
+
"v2, streaming over WebSocket and emitting raw audio; linear16 output is "
|
|
198
|
+
"wrapped in a WAV container so it is directly playable. Pass an aura-* "
|
|
199
|
+
"model to use Speak v1 (batch REST), which supports containerized "
|
|
200
|
+
"formats like mp3. Supports model selection and audio format options. "
|
|
201
|
+
"Flux TTS models also accept --speed (0.85–1.15) and beta "
|
|
202
|
+
"--expressivity (-2..2; default 0 = nominal) streaming controls; these "
|
|
203
|
+
"are rejected for other models."
|
|
185
204
|
)
|
|
186
205
|
|
|
187
206
|
def get_arguments(self) -> list[dict[str, Any]]:
|
|
@@ -201,13 +220,13 @@ class SpeakCommand(BaseCommand):
|
|
|
201
220
|
{
|
|
202
221
|
"names": ["--model", "-m"],
|
|
203
222
|
"help": (
|
|
204
|
-
"TTS model.
|
|
205
|
-
"
|
|
206
|
-
"
|
|
223
|
+
"TTS model. flux-* = Flux TTS / Speak v2 (WebSocket "
|
|
224
|
+
"streaming; default flux-alexis-en); aura-* = Speak v1 "
|
|
225
|
+
"(REST batch, e.g. aura-2-asteria-en)."
|
|
207
226
|
),
|
|
208
227
|
"type": str,
|
|
209
228
|
"is_option": True,
|
|
210
|
-
"default": "
|
|
229
|
+
"default": "flux-alexis-en",
|
|
211
230
|
},
|
|
212
231
|
{
|
|
213
232
|
"names": ["--encoding"],
|
|
@@ -234,6 +253,25 @@ class SpeakCommand(BaseCommand):
|
|
|
234
253
|
"type": float,
|
|
235
254
|
"is_option": True,
|
|
236
255
|
},
|
|
256
|
+
{
|
|
257
|
+
"names": ["--speed"],
|
|
258
|
+
"help": (
|
|
259
|
+
"Flux TTS (v2) only. Speech-rate multiplier: 0.85, 0.90, 0.95, "
|
|
260
|
+
"1.00, 1.05, 1.10, or 1.15 (1.00 = nominal)."
|
|
261
|
+
),
|
|
262
|
+
"type": float,
|
|
263
|
+
"is_option": True,
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
"names": ["--expressivity"],
|
|
267
|
+
"help": (
|
|
268
|
+
"Flux TTS (v2) only, beta. Expressive range: -2, -1, 0, 1, "
|
|
269
|
+
"or 2 (default 0 = nominal; negative flatter, positive more "
|
|
270
|
+
"animated). Fixed for the connection."
|
|
271
|
+
),
|
|
272
|
+
"type": int,
|
|
273
|
+
"is_option": True,
|
|
274
|
+
},
|
|
237
275
|
{
|
|
238
276
|
"names": ["--file", "-f"],
|
|
239
277
|
"help": "Read text from file",
|
|
@@ -251,10 +289,12 @@ class SpeakCommand(BaseCommand):
|
|
|
251
289
|
) -> BaseResult | None:
|
|
252
290
|
text = kwargs.get("text")
|
|
253
291
|
output_path = kwargs.get("output")
|
|
254
|
-
model = kwargs.get("model") or "
|
|
292
|
+
model = kwargs.get("model") or "flux-alexis-en"
|
|
255
293
|
encoding = kwargs.get("encoding")
|
|
256
294
|
container = kwargs.get("container")
|
|
257
295
|
sample_rate = kwargs.get("sample_rate")
|
|
296
|
+
speed = kwargs.get("speed")
|
|
297
|
+
expressivity = kwargs.get("expressivity")
|
|
258
298
|
file_path = kwargs.get("file")
|
|
259
299
|
|
|
260
300
|
# Resolve text input: arg > --file > stdin
|
|
@@ -282,8 +322,29 @@ class SpeakCommand(BaseCommand):
|
|
|
282
322
|
message="No output specified. Use -o/--output to save to file, or pipe stdout.",
|
|
283
323
|
)
|
|
284
324
|
|
|
285
|
-
#
|
|
286
|
-
|
|
325
|
+
# Only the documented flux-* namespace uses speak.v2. Aura and unknown
|
|
326
|
+
# model names pass through to the REST API so the service can resolve them.
|
|
327
|
+
is_flux = model.lower().startswith("flux-")
|
|
328
|
+
|
|
329
|
+
# speed / expressivity are Flux (Speak v2) connect controls; reject them
|
|
330
|
+
# for other models rather than silently dropping them. Raise (not return)
|
|
331
|
+
# so the failure exits non-zero in every output mode.
|
|
332
|
+
if not is_flux and (speed is not None or expressivity is not None):
|
|
333
|
+
raise click.ClickException(
|
|
334
|
+
"--speed and --expressivity are only supported for Flux TTS "
|
|
335
|
+
"(Speak v2) models (flux-*). They are not available for "
|
|
336
|
+
f"Speak v1 model '{model}'."
|
|
337
|
+
)
|
|
338
|
+
if speed is not None and speed not in _FLUX_SPEEDS:
|
|
339
|
+
allowed = ", ".join(f"{s:.2f}" for s in _FLUX_SPEEDS)
|
|
340
|
+
raise click.ClickException(
|
|
341
|
+
f"--speed must be one of: {allowed} (got {speed})."
|
|
342
|
+
)
|
|
343
|
+
if expressivity is not None and expressivity not in _FLUX_EXPRESSIVITY:
|
|
344
|
+
allowed = ", ".join(str(e) for e in _FLUX_EXPRESSIVITY)
|
|
345
|
+
raise click.ClickException(
|
|
346
|
+
f"--expressivity must be one of: {allowed} (got {expressivity})."
|
|
347
|
+
)
|
|
287
348
|
|
|
288
349
|
if is_flux:
|
|
289
350
|
# WebSocket streaming path. Streaming output is raw audio, so
|
|
@@ -310,6 +371,8 @@ class SpeakCommand(BaseCommand):
|
|
|
310
371
|
model=model,
|
|
311
372
|
encoding=eff_encoding,
|
|
312
373
|
sample_rate=eff_sample_rate,
|
|
374
|
+
speed=speed,
|
|
375
|
+
expressivity=expressivity,
|
|
313
376
|
)
|
|
314
377
|
)
|
|
315
378
|
|
|
@@ -392,7 +455,7 @@ class SpeakCommand(BaseCommand):
|
|
|
392
455
|
# to the stderr console.
|
|
393
456
|
return None
|
|
394
457
|
|
|
395
|
-
# REST path (
|
|
458
|
+
# REST path (Speak v1, including Aura and unknown-model pass-through).
|
|
396
459
|
try:
|
|
397
460
|
console.print(f"[blue]Generating speech with {model}...[/blue]")
|
|
398
461
|
|
|
@@ -440,6 +503,11 @@ class SpeakCommand(BaseCommand):
|
|
|
440
503
|
# summary above went to the stderr console.
|
|
441
504
|
return None
|
|
442
505
|
|
|
506
|
+
except click.ClickException:
|
|
507
|
+
raise
|
|
443
508
|
except Exception as e:
|
|
444
|
-
|
|
445
|
-
|
|
509
|
+
# Raise (not return an error result) so the failure exits non-zero
|
|
510
|
+
# in every output mode — a returned BaseResult is only printed and
|
|
511
|
+
# still exits 0. Reachable now that unknown models (e.g. a bare
|
|
512
|
+
# "flux" typo) route here instead of the raising v2 path.
|
|
513
|
+
raise click.ClickException(f"Error generating speech: {e}")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: deepctl-cmd-speak
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.4
|
|
4
4
|
Summary: Speak (text-to-speech) command for deepctl
|
|
5
5
|
Author-email: Deepgram <devrel@deepgram.com>
|
|
6
6
|
Maintainer-email: Deepgram <devrel@deepgram.com>
|
|
@@ -14,7 +14,7 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
14
14
|
Classifier: Programming Language :: Python :: 3.12
|
|
15
15
|
Requires-Python: >=3.10
|
|
16
16
|
Description-Content-Type: text/markdown
|
|
17
|
-
Requires-Dist: deepctl-core>=0.
|
|
17
|
+
Requires-Dist: deepctl-core>=0.2.15
|
|
18
18
|
Requires-Dist: click>=8.0.0
|
|
19
19
|
Requires-Dist: rich>=13.0.0
|
|
20
20
|
Requires-Dist: pydantic>=2.0.0
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{deepctl_cmd_speak-0.0.3 → deepctl_cmd_speak-0.0.4}/src/deepctl_cmd_speak.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{deepctl_cmd_speak-0.0.3 → deepctl_cmd_speak-0.0.4}/src/deepctl_cmd_speak.egg-info/entry_points.txt
RENAMED
|
File without changes
|
{deepctl_cmd_speak-0.0.3 → deepctl_cmd_speak-0.0.4}/src/deepctl_cmd_speak.egg-info/top_level.txt
RENAMED
|
File without changes
|