deepctl 0.2.25__tar.gz → 0.3.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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: deepctl
3
- Version: 0.2.25
3
+ Version: 0.3.0
4
4
  Summary: Official Deepgram CLI for speech recognition and audio intelligence
5
5
  Author-email: Deepgram <devrel@deepgram.com>
6
6
  Maintainer-email: Deepgram <devrel@deepgram.com>
@@ -26,13 +26,13 @@ Requires-Python: >=3.10
26
26
  Description-Content-Type: text/markdown
27
27
  License-File: LICENSE
28
28
  Requires-Dist: click>=8.0.0
29
- Requires-Dist: deepgram-sdk>=6.0.0rc2
30
- Requires-Dist: deepctl-core>=0.1.10
31
- Requires-Dist: deepctl-cmd-login>=0.1.10
32
- Requires-Dist: deepctl-cmd-projects>=0.1.10
29
+ Requires-Dist: deepgram-sdk<8,>=7.7.0
30
+ Requires-Dist: deepctl-core>=0.2.16
31
+ Requires-Dist: deepctl-cmd-login>=0.1.17
32
+ Requires-Dist: deepctl-cmd-projects>=0.2.0
33
33
  Requires-Dist: deepctl-cmd-transcribe>=0.1.10
34
- Requires-Dist: deepctl-cmd-usage>=0.1.10
35
- Requires-Dist: deepctl-cmd-mcp>=0.1.10
34
+ Requires-Dist: deepctl-cmd-usage>=0.2.0
35
+ Requires-Dist: deepctl-cmd-mcp>=0.1.15
36
36
  Requires-Dist: deepctl-cmd-api>=0.0.1
37
37
  Requires-Dist: deepctl-cmd-debug>=0.1.10
38
38
  Requires-Dist: deepctl-cmd-debug-browser>=0.1.10
@@ -41,21 +41,21 @@ Requires-Dist: deepctl-cmd-debug-audio>=0.1.10
41
41
  Requires-Dist: deepctl-cmd-debug-probe>=0.0.1
42
42
  Requires-Dist: deepctl-cmd-debug-toolkit>=0.0.1
43
43
  Requires-Dist: deepctl-cmd-ffprobe>=0.0.1
44
- Requires-Dist: deepctl-cmd-update>=0.1.10
44
+ Requires-Dist: deepctl-cmd-update>=0.2.6
45
45
  Requires-Dist: deepctl-cmd-plugin>=0.1.10
46
- Requires-Dist: deepctl-cmd-skills>=0.0.1
46
+ Requires-Dist: deepctl-cmd-skills>=0.0.7
47
47
  Requires-Dist: deepctl-cmd-init>=0.0.1
48
- Requires-Dist: deepctl-cmd-models>=0.0.1
49
- Requires-Dist: deepctl-cmd-speak>=0.0.1
50
- Requires-Dist: deepctl-cmd-keys>=0.0.1
51
- Requires-Dist: deepctl-cmd-read>=0.0.1
52
- Requires-Dist: deepctl-cmd-listen>=0.0.1
53
- Requires-Dist: deepctl-cmd-requests>=0.0.1
54
- Requires-Dist: deepctl-cmd-billing>=0.0.1
55
- Requires-Dist: deepctl-cmd-members>=0.0.1
48
+ Requires-Dist: deepctl-cmd-models>=0.1.0
49
+ Requires-Dist: deepctl-cmd-speak>=0.0.4
50
+ Requires-Dist: deepctl-cmd-keys>=0.1.0
51
+ Requires-Dist: deepctl-cmd-read>=0.1.0
52
+ Requires-Dist: deepctl-cmd-listen>=0.0.14
53
+ Requires-Dist: deepctl-cmd-requests>=0.1.0
54
+ Requires-Dist: deepctl-cmd-billing>=0.1.0
55
+ Requires-Dist: deepctl-cmd-members>=0.1.0
56
56
  Requires-Dist: deepctl-cmd-completion>=0.0.1
57
57
  Requires-Dist: deepctl-shared-utils>=0.1.10
58
- Requires-Dist: deepctl-telemetry>=0.0.1
58
+ Requires-Dist: deepctl-telemetry>=0.0.6
59
59
  Requires-Dist: pydantic>=2.0.0
60
60
  Requires-Dist: rich>=13.0.0
61
61
  Requires-Dist: httpx>=0.24.0
@@ -70,13 +70,14 @@ Requires-Dist: pytest>=7.0.0; extra == "dev"
70
70
  Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
71
71
  Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
72
72
  Requires-Dist: pytest-mock>=3.10.0; extra == "dev"
73
+ Requires-Dist: pytest-timeout<3,>=2.3.1; extra == "dev"
73
74
  Requires-Dist: responses>=0.23.0; extra == "dev"
74
75
  Requires-Dist: ruff>=0.8.0; extra == "dev"
75
76
  Requires-Dist: mypy>=1.0.0; extra == "dev"
76
77
  Requires-Dist: types-PyYAML>=6.0.0; extra == "dev"
77
78
  Requires-Dist: types-requests>=2.31.0; extra == "dev"
78
79
  Requires-Dist: pre-commit>=3.0.0; extra == "dev"
79
- Requires-Dist: twine>=4.0.0; extra == "dev"
80
+ Requires-Dist: twine>=7.0.0; extra == "dev"
80
81
  Requires-Dist: build>=0.10.0; extra == "dev"
81
82
  Dynamic: license-file
82
83
 
@@ -157,8 +158,8 @@ dg login
157
158
  # Transcribe an audio file
158
159
  dg listen recording.wav
159
160
 
160
- # Text-to-speech
161
- dg speak "Hello from Deepgram" -o hello.mp3
161
+ # Text-to-speech (Flux TTS by default)
162
+ dg speak "Hello from Deepgram" -o hello.wav
162
163
 
163
164
  # Live microphone transcription
164
165
  dg listen --mic
@@ -183,6 +184,10 @@ dg -o json listen standup.mp3 \
183
184
  # Live microphone with interim (partial) results
184
185
  dg listen --mic --model nova-3 --interim
185
186
 
187
+ # Redact sensitive numbers and spell numbers as digits (files or live)
188
+ # Flux STT (v2) accepts --redact numbers|aggressive_numbers; v1 also pci, ssn, …
189
+ dg listen call.wav --redact numbers --numerals
190
+
186
191
  # Raw audio stream from ffmpeg
187
192
  ffmpeg -i video.mp4 -f s16le -ar 16000 -ac 1 - \
188
193
  | dg listen --encoding linear16
@@ -214,8 +219,9 @@ dg read earnings.txt --sentiment --summarize --topics
214
219
  ### Text-to-speech
215
220
 
216
221
  ```bash
217
- # Stream directly to a player
218
- dg speak "Hello from Deepgram" | ffplay -nodisp -autoexit -
222
+ # Stream directly to a player (Flux TTS streams a WAV; -loglevel error hides
223
+ # ffmpeg's cosmetic end-of-stream notice)
224
+ dg speak "Hello from Deepgram" | ffplay -loglevel error -nodisp -autoexit -
219
225
  ```
220
226
 
221
227
  ### Account & project management
@@ -255,11 +261,30 @@ cat audio.raw | dg listen --encoding linear16 --sample-rate 16000
255
261
 
256
262
  Convert text to natural speech. Supports file output and piping.
257
263
 
264
+ By default `dg speak` uses Flux TTS (`flux-alexis-en`) — the Speak v2 WebSocket
265
+ API, which streams and emits raw audio; its `linear16` output is wrapped in a WAV
266
+ container so it is directly playable. Pass an `aura-*` model to use the Speak v1
267
+ batch REST API instead, which supports containerized formats like MP3.
268
+
258
269
  ```bash
259
- dg speak "Welcome to Deepgram" -o welcome.mp3
270
+ # Flux TTS (v2, WebSocket streaming) — the default
271
+ dg speak "Hello from Flux" -o hello.wav
272
+ # Piped audio is a streaming WAV; -loglevel error hides ffmpeg's cosmetic
273
+ # end-of-stream notice (the audio is complete).
274
+ dg speak "Hello from Flux" | ffplay -loglevel error -nodisp -autoexit -
275
+
276
+ # Flux TTS streaming controls (flux-* only): --speed 0.85–1.15 (0.05 steps).
277
+ # --expressivity -2..2 is beta; its default 0 is nominal delivery.
278
+ dg speak "A little slower" --speed 0.9 --expressivity 1 -o slow.wav
279
+
280
+ # Aura (v1, batch REST) — opt in with -m aura-*; needed for MP3 output
281
+ dg speak "Welcome to Deepgram" -o welcome.mp3 -m aura-2-asteria-en
260
282
  dg speak --file script.txt -o output.mp3 -m aura-2-luna-en
261
- echo "Hello" | dg speak -o greeting.mp3
262
- dg speak "Stream me" | ffplay -nodisp - # pipe to audio player
283
+ echo "Hello" | dg speak -o greeting.mp3 -m aura-2-asteria-en
284
+
285
+ # Aura-2 also has Spanish voices (e.g. aura-2-selena-es); run `dg models`
286
+ # for the full, current list.
287
+ dg speak "Hola, bienvenido a Deepgram" -o hola.mp3 -m aura-2-selena-es
263
288
  ```
264
289
 
265
290
  ### Text Intelligence
@@ -363,7 +388,7 @@ export DEEPGRAM_PROJECT_ID="your-project-id"
363
388
 
364
389
  # Non-interactive usage
365
390
  dg listen recording.wav
366
- dg speak "Deploy complete" -o notification.mp3
391
+ dg speak "Deploy complete" -o notification.mp3 -m aura-2-asteria-en
367
392
  dg keys --create --comment "ci-key" --scopes member
368
393
  dg keys --delete KEY_ID --yes
369
394
  dg read --file report.txt --summarize
@@ -75,8 +75,8 @@ dg login
75
75
  # Transcribe an audio file
76
76
  dg listen recording.wav
77
77
 
78
- # Text-to-speech
79
- dg speak "Hello from Deepgram" -o hello.mp3
78
+ # Text-to-speech (Flux TTS by default)
79
+ dg speak "Hello from Deepgram" -o hello.wav
80
80
 
81
81
  # Live microphone transcription
82
82
  dg listen --mic
@@ -101,6 +101,10 @@ dg -o json listen standup.mp3 \
101
101
  # Live microphone with interim (partial) results
102
102
  dg listen --mic --model nova-3 --interim
103
103
 
104
+ # Redact sensitive numbers and spell numbers as digits (files or live)
105
+ # Flux STT (v2) accepts --redact numbers|aggressive_numbers; v1 also pci, ssn, …
106
+ dg listen call.wav --redact numbers --numerals
107
+
104
108
  # Raw audio stream from ffmpeg
105
109
  ffmpeg -i video.mp4 -f s16le -ar 16000 -ac 1 - \
106
110
  | dg listen --encoding linear16
@@ -132,8 +136,9 @@ dg read earnings.txt --sentiment --summarize --topics
132
136
  ### Text-to-speech
133
137
 
134
138
  ```bash
135
- # Stream directly to a player
136
- dg speak "Hello from Deepgram" | ffplay -nodisp -autoexit -
139
+ # Stream directly to a player (Flux TTS streams a WAV; -loglevel error hides
140
+ # ffmpeg's cosmetic end-of-stream notice)
141
+ dg speak "Hello from Deepgram" | ffplay -loglevel error -nodisp -autoexit -
137
142
  ```
138
143
 
139
144
  ### Account & project management
@@ -173,11 +178,30 @@ cat audio.raw | dg listen --encoding linear16 --sample-rate 16000
173
178
 
174
179
  Convert text to natural speech. Supports file output and piping.
175
180
 
181
+ By default `dg speak` uses Flux TTS (`flux-alexis-en`) — the Speak v2 WebSocket
182
+ API, which streams and emits raw audio; its `linear16` output is wrapped in a WAV
183
+ container so it is directly playable. Pass an `aura-*` model to use the Speak v1
184
+ batch REST API instead, which supports containerized formats like MP3.
185
+
176
186
  ```bash
177
- dg speak "Welcome to Deepgram" -o welcome.mp3
187
+ # Flux TTS (v2, WebSocket streaming) — the default
188
+ dg speak "Hello from Flux" -o hello.wav
189
+ # Piped audio is a streaming WAV; -loglevel error hides ffmpeg's cosmetic
190
+ # end-of-stream notice (the audio is complete).
191
+ dg speak "Hello from Flux" | ffplay -loglevel error -nodisp -autoexit -
192
+
193
+ # Flux TTS streaming controls (flux-* only): --speed 0.85–1.15 (0.05 steps).
194
+ # --expressivity -2..2 is beta; its default 0 is nominal delivery.
195
+ dg speak "A little slower" --speed 0.9 --expressivity 1 -o slow.wav
196
+
197
+ # Aura (v1, batch REST) — opt in with -m aura-*; needed for MP3 output
198
+ dg speak "Welcome to Deepgram" -o welcome.mp3 -m aura-2-asteria-en
178
199
  dg speak --file script.txt -o output.mp3 -m aura-2-luna-en
179
- echo "Hello" | dg speak -o greeting.mp3
180
- dg speak "Stream me" | ffplay -nodisp - # pipe to audio player
200
+ echo "Hello" | dg speak -o greeting.mp3 -m aura-2-asteria-en
201
+
202
+ # Aura-2 also has Spanish voices (e.g. aura-2-selena-es); run `dg models`
203
+ # for the full, current list.
204
+ dg speak "Hola, bienvenido a Deepgram" -o hola.mp3 -m aura-2-selena-es
181
205
  ```
182
206
 
183
207
  ### Text Intelligence
@@ -281,7 +305,7 @@ export DEEPGRAM_PROJECT_ID="your-project-id"
281
305
 
282
306
  # Non-interactive usage
283
307
  dg listen recording.wav
284
- dg speak "Deploy complete" -o notification.mp3
308
+ dg speak "Deploy complete" -o notification.mp3 -m aura-2-asteria-en
285
309
  dg keys --create --comment "ci-key" --scopes member
286
310
  dg keys --delete KEY_ID --yes
287
311
  dg read --file report.txt --summarize
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "deepctl"
7
- version = "0.2.25" # x-release-please-version
7
+ version = "0.3.0" # x-release-please-version
8
8
  description = "Official Deepgram CLI for speech recognition and audio intelligence"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -34,13 +34,13 @@ keywords = [
34
34
  requires-python = ">=3.10"
35
35
  dependencies = [
36
36
  "click>=8.0.0",
37
- "deepgram-sdk>=6.0.0rc2",
38
- "deepctl-core>=0.1.10",
39
- "deepctl-cmd-login>=0.1.10",
40
- "deepctl-cmd-projects>=0.1.10",
37
+ "deepgram-sdk>=7.7.0,<8",
38
+ "deepctl-core>=0.2.16",
39
+ "deepctl-cmd-login>=0.1.17",
40
+ "deepctl-cmd-projects>=0.2.0",
41
41
  "deepctl-cmd-transcribe>=0.1.10",
42
- "deepctl-cmd-usage>=0.1.10",
43
- "deepctl-cmd-mcp>=0.1.10",
42
+ "deepctl-cmd-usage>=0.2.0",
43
+ "deepctl-cmd-mcp>=0.1.15",
44
44
  "deepctl-cmd-api>=0.0.1",
45
45
  "deepctl-cmd-debug>=0.1.10",
46
46
  "deepctl-cmd-debug-browser>=0.1.10",
@@ -49,21 +49,21 @@ dependencies = [
49
49
  "deepctl-cmd-debug-probe>=0.0.1",
50
50
  "deepctl-cmd-debug-toolkit>=0.0.1",
51
51
  "deepctl-cmd-ffprobe>=0.0.1",
52
- "deepctl-cmd-update>=0.1.10",
52
+ "deepctl-cmd-update>=0.2.6",
53
53
  "deepctl-cmd-plugin>=0.1.10",
54
- "deepctl-cmd-skills>=0.0.1",
54
+ "deepctl-cmd-skills>=0.0.7",
55
55
  "deepctl-cmd-init>=0.0.1",
56
- "deepctl-cmd-models>=0.0.1",
57
- "deepctl-cmd-speak>=0.0.1",
58
- "deepctl-cmd-keys>=0.0.1",
59
- "deepctl-cmd-read>=0.0.1",
60
- "deepctl-cmd-listen>=0.0.1",
61
- "deepctl-cmd-requests>=0.0.1",
62
- "deepctl-cmd-billing>=0.0.1",
63
- "deepctl-cmd-members>=0.0.1",
56
+ "deepctl-cmd-models>=0.1.0",
57
+ "deepctl-cmd-speak>=0.0.4",
58
+ "deepctl-cmd-keys>=0.1.0",
59
+ "deepctl-cmd-read>=0.1.0",
60
+ "deepctl-cmd-listen>=0.0.14",
61
+ "deepctl-cmd-requests>=0.1.0",
62
+ "deepctl-cmd-billing>=0.1.0",
63
+ "deepctl-cmd-members>=0.1.0",
64
64
  "deepctl-cmd-completion>=0.0.1",
65
65
  "deepctl-shared-utils>=0.1.10",
66
- "deepctl-telemetry>=0.0.1",
66
+ "deepctl-telemetry>=0.0.6",
67
67
  "pydantic>=2.0.0",
68
68
  "rich>=13.0.0",
69
69
  "httpx>=0.24.0",
@@ -82,6 +82,7 @@ dev = [
82
82
  "pytest-asyncio>=0.21.0",
83
83
  "pytest-cov>=4.0.0",
84
84
  "pytest-mock>=3.10.0",
85
+ "pytest-timeout>=2.3.1,<3",
85
86
  "responses>=0.23.0",
86
87
  # Code Quality
87
88
  "ruff>=0.8.0",
@@ -92,7 +93,9 @@ dev = [
92
93
  # Development Tools
93
94
  "pre-commit>=3.0.0",
94
95
  # Publishing
95
- "twine>=4.0.0",
96
+ # twine <7 rejects Metadata-Version 2.5 (emitted by hatchling), which
97
+ # silently broke the 0.2.27 publish. Keep local verify == what publishes.
98
+ "twine>=7.0.0",
96
99
  "build>=0.10.0",
97
100
  ]
98
101
 
@@ -144,6 +147,11 @@ module = [
144
147
  # Optional microphone dependencies (sounddevice, numpy) and the MCP SDK
145
148
  # (deepgram_mcp) ship without type stubs.
146
149
  ignore_missing_imports = true
150
+ # numpy>=2.2 ships PEP 695 `type` aliases in its stubs, which mypy rejects
151
+ # under python_version = "3.10" (aborting before our code is checked). Skip
152
+ # analyzing these third-party stubs entirely; usages fall back to Any.
153
+ follow_imports = "skip"
154
+ follow_imports_for_stubs = true
147
155
 
148
156
  [tool.pytest.ini_options]
149
157
  testpaths = ["tests", "packages/*/tests"]
@@ -227,6 +235,7 @@ testing = [
227
235
  "pytest-asyncio>=0.21.0",
228
236
  "pytest-cov>=4.0.0",
229
237
  "pytest-mock>=3.10.0",
238
+ "pytest-timeout>=2.3.1,<3",
230
239
  "responses>=0.23.0",
231
240
  "deepctl-plugin-example",
232
241
  ]
@@ -241,7 +250,9 @@ dev = [
241
250
  # Development Tools
242
251
  "pre-commit>=3.0.0",
243
252
  # Publishing
244
- "twine>=4.0.0",
253
+ # twine <7 rejects Metadata-Version 2.5 (emitted by hatchling), which
254
+ # silently broke the 0.2.27 publish. Keep local verify == what publishes.
255
+ "twine>=7.0.0",
245
256
  "build>=0.10.0",
246
257
  ]
247
258
 
@@ -1,7 +1,7 @@
1
1
  """deepctl - Official command-line interface for Deepgram's speech
2
2
  recognition API."""
3
3
 
4
- __version__ = "0.2.25" # x-release-please-version
4
+ __version__ = "0.3.0" # x-release-please-version
5
5
  __author__ = "Deepgram"
6
6
  __email__ = "devrel@deepgram.com"
7
7
  __license__ = "MIT"
@@ -3,6 +3,7 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import importlib.metadata
6
+ import os
6
7
  import sys
7
8
  from contextlib import contextmanager
8
9
  from typing import TYPE_CHECKING
@@ -18,12 +19,18 @@ from deepctl_core import (
18
19
  print_timing_summary,
19
20
  setup_output,
20
21
  )
21
- from rich.console import Console
22
+ from deepctl_core.output import stderr_console
22
23
  from rich.traceback import install
23
24
 
24
25
  # Install rich traceback for better error messages
25
26
  install(show_locals=True)
26
- console = Console()
27
+
28
+ # Diagnostics go to stderr so stdout carries only the requested payload -- a
29
+ # crash or usage error must not corrupt `dg -o json ...` for a script piping
30
+ # stdout into jq. Same console the command layer uses via print_error(), so
31
+ # root-level and command-level diagnostics format identically (including the
32
+ # no-color handling for agentic/CI callers).
33
+ console = stderr_console
27
34
 
28
35
 
29
36
  def _record_install_method_cb(
@@ -130,6 +137,21 @@ def preprocess_hyphenated_commands(args: list[str]) -> list[str]:
130
137
  "-p",
131
138
  help="Configuration profile to use",
132
139
  )
140
+ @click.option(
141
+ "--base-url",
142
+ help=(
143
+ "Override the API base URL (e.g. https://api.staging.deepgram.com). "
144
+ "REST and WebSocket endpoints are derived from this host. "
145
+ "Also settable via the DEEPGRAM_BASE_URL environment variable."
146
+ ),
147
+ )
148
+ @click.option(
149
+ "--api-key",
150
+ help=(
151
+ "Deepgram API key to use, overriding login/profile/env credentials. "
152
+ "Intended for testing and CI."
153
+ ),
154
+ )
133
155
  @click.option(
134
156
  "--output",
135
157
  "-o",
@@ -179,6 +201,8 @@ def cli(
179
201
  ctx: click.Context,
180
202
  config: str | None,
181
203
  profile: str | None,
204
+ base_url: str | None,
205
+ api_key: str | None,
182
206
  output: str | None,
183
207
  quiet: bool,
184
208
  verbose: bool,
@@ -206,9 +230,16 @@ def cli(
206
230
  enable_timing()
207
231
 
208
232
  with TimingContext("cli_initialization"):
233
+ # A --base-url flag overrides the configured/env base URL (flag wins).
234
+ # Config reads DEEPGRAM_BASE_URL at init, so set it before constructing.
235
+ if base_url:
236
+ os.environ["DEEPGRAM_BASE_URL"] = base_url
237
+
209
238
  # Initialize configuration
210
239
  ctx.ensure_object(dict)
211
240
  ctx.obj["config"] = Config(config_path=config, profile=profile)
241
+ # Global --api-key passthrough (highest-precedence explicit credential).
242
+ ctx.obj["api_key"] = api_key
212
243
  ctx.obj["timing"] = timing or timing_detailed
213
244
  ctx.obj["timing_detailed"] = timing_detailed
214
245
 
@@ -256,6 +287,20 @@ def _telemetry_transaction() -> Iterator[None]:
256
287
  yield
257
288
 
258
289
 
290
+ def _safe_console_print(message: str) -> None:
291
+ """Print a diagnostic to stderr, tolerating a closed/broken stream.
292
+
293
+ When `dg` runs as an MCP server, the host can close stdio before the
294
+ process finishes. A write to the closed stream raises ``BrokenPipeError``
295
+ (or rich's ``ValueError: I/O operation on closed file``); there is nowhere
296
+ left to report the message, so swallow it rather than crash on exit.
297
+ """
298
+ try:
299
+ console.print(message)
300
+ except (BrokenPipeError, OSError, ValueError):
301
+ pass
302
+
303
+
259
304
  def main() -> None:
260
305
  """Main entry point for the CLI."""
261
306
  try:
@@ -322,12 +367,18 @@ def main() -> None:
322
367
  # Preprocess arguments to handle hyphenated commands
323
368
  processed_args = preprocess_hyphenated_commands(args)
324
369
 
370
+ exit_code = 0
325
371
  with TimingContext("cli_execution"), _telemetry_transaction():
326
372
  try:
327
373
  cli(args=processed_args, standalone_mode=False)
328
- except SystemExit:
329
- # Click calls sys.exit() even in non-standalone mode
330
- pass
374
+ except SystemExit as exc:
375
+ # Click calls sys.exit() even in non-standalone mode, so we
376
+ # cannot let this propagate — the notifications and timing
377
+ # summary below still need to run. But swallowing the code
378
+ # outright made every failure exit 0, which is what broke
379
+ # `if dg -o json keys; then ...` in scripts and CI. Carry it
380
+ # and re-raise at the end instead.
381
+ exit_code = exc.code if isinstance(exc.code, int) else 0
331
382
 
332
383
  # Print update notifications if available (before timing summary)
333
384
  if print_pending_notification is not None:
@@ -341,12 +392,18 @@ def main() -> None:
341
392
  if timing_requested:
342
393
  print_timing_summary(detailed_timing)
343
394
 
344
- except KeyboardInterrupt:
345
- console.print("\n[yellow]Operation cancelled by user[/yellow]")
395
+ if exit_code:
396
+ sys.exit(exit_code)
397
+
398
+ except (KeyboardInterrupt, click.exceptions.Abort):
399
+ # Click wraps a Ctrl-C/Ctrl-D raised inside cli() in Abort when
400
+ # standalone_mode=False, so a mid-command interrupt arrives here as
401
+ # Abort, not KeyboardInterrupt. Both are user cancellation: exit 2.
402
+ _safe_console_print("\n[yellow]Operation cancelled by user[/yellow]")
346
403
  sys.exit(2)
347
404
  except Exception as e:
348
- console.print(f"[red]Error: {e}[/red]")
349
- sys.exit(2)
405
+ _safe_console_print(f"[red]Error: {e}[/red]")
406
+ sys.exit(1) # 1 = error; 2 is reserved for user interrupt
350
407
 
351
408
 
352
409
  if __name__ == "__main__":
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: deepctl
3
- Version: 0.2.25
3
+ Version: 0.3.0
4
4
  Summary: Official Deepgram CLI for speech recognition and audio intelligence
5
5
  Author-email: Deepgram <devrel@deepgram.com>
6
6
  Maintainer-email: Deepgram <devrel@deepgram.com>
@@ -26,13 +26,13 @@ Requires-Python: >=3.10
26
26
  Description-Content-Type: text/markdown
27
27
  License-File: LICENSE
28
28
  Requires-Dist: click>=8.0.0
29
- Requires-Dist: deepgram-sdk>=6.0.0rc2
30
- Requires-Dist: deepctl-core>=0.1.10
31
- Requires-Dist: deepctl-cmd-login>=0.1.10
32
- Requires-Dist: deepctl-cmd-projects>=0.1.10
29
+ Requires-Dist: deepgram-sdk<8,>=7.7.0
30
+ Requires-Dist: deepctl-core>=0.2.16
31
+ Requires-Dist: deepctl-cmd-login>=0.1.17
32
+ Requires-Dist: deepctl-cmd-projects>=0.2.0
33
33
  Requires-Dist: deepctl-cmd-transcribe>=0.1.10
34
- Requires-Dist: deepctl-cmd-usage>=0.1.10
35
- Requires-Dist: deepctl-cmd-mcp>=0.1.10
34
+ Requires-Dist: deepctl-cmd-usage>=0.2.0
35
+ Requires-Dist: deepctl-cmd-mcp>=0.1.15
36
36
  Requires-Dist: deepctl-cmd-api>=0.0.1
37
37
  Requires-Dist: deepctl-cmd-debug>=0.1.10
38
38
  Requires-Dist: deepctl-cmd-debug-browser>=0.1.10
@@ -41,21 +41,21 @@ Requires-Dist: deepctl-cmd-debug-audio>=0.1.10
41
41
  Requires-Dist: deepctl-cmd-debug-probe>=0.0.1
42
42
  Requires-Dist: deepctl-cmd-debug-toolkit>=0.0.1
43
43
  Requires-Dist: deepctl-cmd-ffprobe>=0.0.1
44
- Requires-Dist: deepctl-cmd-update>=0.1.10
44
+ Requires-Dist: deepctl-cmd-update>=0.2.6
45
45
  Requires-Dist: deepctl-cmd-plugin>=0.1.10
46
- Requires-Dist: deepctl-cmd-skills>=0.0.1
46
+ Requires-Dist: deepctl-cmd-skills>=0.0.7
47
47
  Requires-Dist: deepctl-cmd-init>=0.0.1
48
- Requires-Dist: deepctl-cmd-models>=0.0.1
49
- Requires-Dist: deepctl-cmd-speak>=0.0.1
50
- Requires-Dist: deepctl-cmd-keys>=0.0.1
51
- Requires-Dist: deepctl-cmd-read>=0.0.1
52
- Requires-Dist: deepctl-cmd-listen>=0.0.1
53
- Requires-Dist: deepctl-cmd-requests>=0.0.1
54
- Requires-Dist: deepctl-cmd-billing>=0.0.1
55
- Requires-Dist: deepctl-cmd-members>=0.0.1
48
+ Requires-Dist: deepctl-cmd-models>=0.1.0
49
+ Requires-Dist: deepctl-cmd-speak>=0.0.4
50
+ Requires-Dist: deepctl-cmd-keys>=0.1.0
51
+ Requires-Dist: deepctl-cmd-read>=0.1.0
52
+ Requires-Dist: deepctl-cmd-listen>=0.0.14
53
+ Requires-Dist: deepctl-cmd-requests>=0.1.0
54
+ Requires-Dist: deepctl-cmd-billing>=0.1.0
55
+ Requires-Dist: deepctl-cmd-members>=0.1.0
56
56
  Requires-Dist: deepctl-cmd-completion>=0.0.1
57
57
  Requires-Dist: deepctl-shared-utils>=0.1.10
58
- Requires-Dist: deepctl-telemetry>=0.0.1
58
+ Requires-Dist: deepctl-telemetry>=0.0.6
59
59
  Requires-Dist: pydantic>=2.0.0
60
60
  Requires-Dist: rich>=13.0.0
61
61
  Requires-Dist: httpx>=0.24.0
@@ -70,13 +70,14 @@ Requires-Dist: pytest>=7.0.0; extra == "dev"
70
70
  Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
71
71
  Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
72
72
  Requires-Dist: pytest-mock>=3.10.0; extra == "dev"
73
+ Requires-Dist: pytest-timeout<3,>=2.3.1; extra == "dev"
73
74
  Requires-Dist: responses>=0.23.0; extra == "dev"
74
75
  Requires-Dist: ruff>=0.8.0; extra == "dev"
75
76
  Requires-Dist: mypy>=1.0.0; extra == "dev"
76
77
  Requires-Dist: types-PyYAML>=6.0.0; extra == "dev"
77
78
  Requires-Dist: types-requests>=2.31.0; extra == "dev"
78
79
  Requires-Dist: pre-commit>=3.0.0; extra == "dev"
79
- Requires-Dist: twine>=4.0.0; extra == "dev"
80
+ Requires-Dist: twine>=7.0.0; extra == "dev"
80
81
  Requires-Dist: build>=0.10.0; extra == "dev"
81
82
  Dynamic: license-file
82
83
 
@@ -157,8 +158,8 @@ dg login
157
158
  # Transcribe an audio file
158
159
  dg listen recording.wav
159
160
 
160
- # Text-to-speech
161
- dg speak "Hello from Deepgram" -o hello.mp3
161
+ # Text-to-speech (Flux TTS by default)
162
+ dg speak "Hello from Deepgram" -o hello.wav
162
163
 
163
164
  # Live microphone transcription
164
165
  dg listen --mic
@@ -183,6 +184,10 @@ dg -o json listen standup.mp3 \
183
184
  # Live microphone with interim (partial) results
184
185
  dg listen --mic --model nova-3 --interim
185
186
 
187
+ # Redact sensitive numbers and spell numbers as digits (files or live)
188
+ # Flux STT (v2) accepts --redact numbers|aggressive_numbers; v1 also pci, ssn, …
189
+ dg listen call.wav --redact numbers --numerals
190
+
186
191
  # Raw audio stream from ffmpeg
187
192
  ffmpeg -i video.mp4 -f s16le -ar 16000 -ac 1 - \
188
193
  | dg listen --encoding linear16
@@ -214,8 +219,9 @@ dg read earnings.txt --sentiment --summarize --topics
214
219
  ### Text-to-speech
215
220
 
216
221
  ```bash
217
- # Stream directly to a player
218
- dg speak "Hello from Deepgram" | ffplay -nodisp -autoexit -
222
+ # Stream directly to a player (Flux TTS streams a WAV; -loglevel error hides
223
+ # ffmpeg's cosmetic end-of-stream notice)
224
+ dg speak "Hello from Deepgram" | ffplay -loglevel error -nodisp -autoexit -
219
225
  ```
220
226
 
221
227
  ### Account & project management
@@ -255,11 +261,30 @@ cat audio.raw | dg listen --encoding linear16 --sample-rate 16000
255
261
 
256
262
  Convert text to natural speech. Supports file output and piping.
257
263
 
264
+ By default `dg speak` uses Flux TTS (`flux-alexis-en`) — the Speak v2 WebSocket
265
+ API, which streams and emits raw audio; its `linear16` output is wrapped in a WAV
266
+ container so it is directly playable. Pass an `aura-*` model to use the Speak v1
267
+ batch REST API instead, which supports containerized formats like MP3.
268
+
258
269
  ```bash
259
- dg speak "Welcome to Deepgram" -o welcome.mp3
270
+ # Flux TTS (v2, WebSocket streaming) — the default
271
+ dg speak "Hello from Flux" -o hello.wav
272
+ # Piped audio is a streaming WAV; -loglevel error hides ffmpeg's cosmetic
273
+ # end-of-stream notice (the audio is complete).
274
+ dg speak "Hello from Flux" | ffplay -loglevel error -nodisp -autoexit -
275
+
276
+ # Flux TTS streaming controls (flux-* only): --speed 0.85–1.15 (0.05 steps).
277
+ # --expressivity -2..2 is beta; its default 0 is nominal delivery.
278
+ dg speak "A little slower" --speed 0.9 --expressivity 1 -o slow.wav
279
+
280
+ # Aura (v1, batch REST) — opt in with -m aura-*; needed for MP3 output
281
+ dg speak "Welcome to Deepgram" -o welcome.mp3 -m aura-2-asteria-en
260
282
  dg speak --file script.txt -o output.mp3 -m aura-2-luna-en
261
- echo "Hello" | dg speak -o greeting.mp3
262
- dg speak "Stream me" | ffplay -nodisp - # pipe to audio player
283
+ echo "Hello" | dg speak -o greeting.mp3 -m aura-2-asteria-en
284
+
285
+ # Aura-2 also has Spanish voices (e.g. aura-2-selena-es); run `dg models`
286
+ # for the full, current list.
287
+ dg speak "Hola, bienvenido a Deepgram" -o hola.mp3 -m aura-2-selena-es
263
288
  ```
264
289
 
265
290
  ### Text Intelligence
@@ -363,7 +388,7 @@ export DEEPGRAM_PROJECT_ID="your-project-id"
363
388
 
364
389
  # Non-interactive usage
365
390
  dg listen recording.wav
366
- dg speak "Deploy complete" -o notification.mp3
391
+ dg speak "Deploy complete" -o notification.mp3 -m aura-2-asteria-en
367
392
  dg keys --create --comment "ci-key" --scopes member
368
393
  dg keys --delete KEY_ID --yes
369
394
  dg read --file report.txt --summarize
@@ -1,11 +1,11 @@
1
1
  click>=8.0.0
2
- deepgram-sdk>=6.0.0rc2
3
- deepctl-core>=0.1.10
4
- deepctl-cmd-login>=0.1.10
5
- deepctl-cmd-projects>=0.1.10
2
+ deepgram-sdk<8,>=7.7.0
3
+ deepctl-core>=0.2.16
4
+ deepctl-cmd-login>=0.1.17
5
+ deepctl-cmd-projects>=0.2.0
6
6
  deepctl-cmd-transcribe>=0.1.10
7
- deepctl-cmd-usage>=0.1.10
8
- deepctl-cmd-mcp>=0.1.10
7
+ deepctl-cmd-usage>=0.2.0
8
+ deepctl-cmd-mcp>=0.1.15
9
9
  deepctl-cmd-api>=0.0.1
10
10
  deepctl-cmd-debug>=0.1.10
11
11
  deepctl-cmd-debug-browser>=0.1.10
@@ -14,21 +14,21 @@ deepctl-cmd-debug-audio>=0.1.10
14
14
  deepctl-cmd-debug-probe>=0.0.1
15
15
  deepctl-cmd-debug-toolkit>=0.0.1
16
16
  deepctl-cmd-ffprobe>=0.0.1
17
- deepctl-cmd-update>=0.1.10
17
+ deepctl-cmd-update>=0.2.6
18
18
  deepctl-cmd-plugin>=0.1.10
19
- deepctl-cmd-skills>=0.0.1
19
+ deepctl-cmd-skills>=0.0.7
20
20
  deepctl-cmd-init>=0.0.1
21
- deepctl-cmd-models>=0.0.1
22
- deepctl-cmd-speak>=0.0.1
23
- deepctl-cmd-keys>=0.0.1
24
- deepctl-cmd-read>=0.0.1
25
- deepctl-cmd-listen>=0.0.1
26
- deepctl-cmd-requests>=0.0.1
27
- deepctl-cmd-billing>=0.0.1
28
- deepctl-cmd-members>=0.0.1
21
+ deepctl-cmd-models>=0.1.0
22
+ deepctl-cmd-speak>=0.0.4
23
+ deepctl-cmd-keys>=0.1.0
24
+ deepctl-cmd-read>=0.1.0
25
+ deepctl-cmd-listen>=0.0.14
26
+ deepctl-cmd-requests>=0.1.0
27
+ deepctl-cmd-billing>=0.1.0
28
+ deepctl-cmd-members>=0.1.0
29
29
  deepctl-cmd-completion>=0.0.1
30
30
  deepctl-shared-utils>=0.1.10
31
- deepctl-telemetry>=0.0.1
31
+ deepctl-telemetry>=0.0.6
32
32
  pydantic>=2.0.0
33
33
  rich>=13.0.0
34
34
  httpx>=0.24.0
@@ -44,11 +44,12 @@ pytest>=7.0.0
44
44
  pytest-asyncio>=0.21.0
45
45
  pytest-cov>=4.0.0
46
46
  pytest-mock>=3.10.0
47
+ pytest-timeout<3,>=2.3.1
47
48
  responses>=0.23.0
48
49
  ruff>=0.8.0
49
50
  mypy>=1.0.0
50
51
  types-PyYAML>=6.0.0
51
52
  types-requests>=2.31.0
52
53
  pre-commit>=3.0.0
53
- twine>=4.0.0
54
+ twine>=7.0.0
54
55
  build>=0.10.0
File without changes
File without changes