deepctl-core 0.2.13__tar.gz → 0.2.16__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_core-0.2.13 → deepctl_core-0.2.16}/PKG-INFO +3 -3
- {deepctl_core-0.2.13 → deepctl_core-0.2.16}/README.md +1 -1
- {deepctl_core-0.2.13 → deepctl_core-0.2.16}/pyproject.toml +2 -2
- {deepctl_core-0.2.13 → deepctl_core-0.2.16}/src/deepctl_core/__init__.py +3 -0
- {deepctl_core-0.2.13 → deepctl_core-0.2.16}/src/deepctl_core/auth.py +8 -1
- {deepctl_core-0.2.13 → deepctl_core-0.2.16}/src/deepctl_core/base_command.py +57 -6
- {deepctl_core-0.2.13 → deepctl_core-0.2.16}/src/deepctl_core/client.py +71 -3
- {deepctl_core-0.2.13 → deepctl_core-0.2.16}/src/deepctl_core/output.py +16 -0
- {deepctl_core-0.2.13 → deepctl_core-0.2.16}/src/deepctl_core/skill_generator.py +59 -21
- {deepctl_core-0.2.13 → deepctl_core-0.2.16}/src/deepctl_core.egg-info/PKG-INFO +3 -3
- {deepctl_core-0.2.13 → deepctl_core-0.2.16}/src/deepctl_core.egg-info/requires.txt +1 -1
- {deepctl_core-0.2.13 → deepctl_core-0.2.16}/setup.cfg +0 -0
- {deepctl_core-0.2.13 → deepctl_core-0.2.16}/src/deepctl_core/base_group_command.py +0 -0
- {deepctl_core-0.2.13 → deepctl_core-0.2.16}/src/deepctl_core/config.py +0 -0
- {deepctl_core-0.2.13 → deepctl_core-0.2.16}/src/deepctl_core/models.py +0 -0
- {deepctl_core-0.2.13 → deepctl_core-0.2.16}/src/deepctl_core/plugin_env.py +0 -0
- {deepctl_core-0.2.13 → deepctl_core-0.2.16}/src/deepctl_core/plugin_manager.py +0 -0
- {deepctl_core-0.2.13 → deepctl_core-0.2.16}/src/deepctl_core/py.typed +0 -0
- {deepctl_core-0.2.13 → deepctl_core-0.2.16}/src/deepctl_core/timing.py +0 -0
- {deepctl_core-0.2.13 → deepctl_core-0.2.16}/src/deepctl_core.egg-info/SOURCES.txt +0 -0
- {deepctl_core-0.2.13 → deepctl_core-0.2.16}/src/deepctl_core.egg-info/dependency_links.txt +0 -0
- {deepctl_core-0.2.13 → deepctl_core-0.2.16}/src/deepctl_core.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: deepctl-core
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.16
|
|
4
4
|
Summary: Core components for deepctl
|
|
5
5
|
Author-email: Deepgram <devrel@deepgram.com>
|
|
6
6
|
Maintainer-email: Deepgram <devrel@deepgram.com>
|
|
@@ -16,7 +16,7 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
|
16
16
|
Requires-Python: >=3.10
|
|
17
17
|
Description-Content-Type: text/markdown
|
|
18
18
|
Requires-Dist: click>=8.0.0
|
|
19
|
-
Requires-Dist: deepgram-sdk
|
|
19
|
+
Requires-Dist: deepgram-sdk<8,>=7.7.0
|
|
20
20
|
Requires-Dist: pydantic>=2.0.0
|
|
21
21
|
Requires-Dist: rich>=13.0.0
|
|
22
22
|
Requires-Dist: httpx>=0.24.0
|
|
@@ -63,7 +63,7 @@ pipx run deepctl --help
|
|
|
63
63
|
## Dependencies
|
|
64
64
|
|
|
65
65
|
- `click>=8.0.0`
|
|
66
|
-
- `deepgram-sdk>=
|
|
66
|
+
- `deepgram-sdk>=7.7.0,<8`
|
|
67
67
|
- `pydantic>=2.0.0`
|
|
68
68
|
- `rich>=13.0.0`
|
|
69
69
|
- `httpx>=0.24.0`
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "deepctl-core"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.16" # x-release-please-version
|
|
8
8
|
description = "Core components for deepctl"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
@@ -23,7 +23,7 @@ keywords = ["deepgram", "core", "auth", "config", "client"]
|
|
|
23
23
|
requires-python = ">=3.10"
|
|
24
24
|
dependencies = [
|
|
25
25
|
"click>=8.0.0",
|
|
26
|
-
"deepgram-sdk>=
|
|
26
|
+
"deepgram-sdk>=7.7.0,<8",
|
|
27
27
|
"pydantic>=2.0.0",
|
|
28
28
|
"rich>=13.0.0",
|
|
29
29
|
"httpx>=0.24.0",
|
|
@@ -16,6 +16,7 @@ from .output import (
|
|
|
16
16
|
OutputFormatter,
|
|
17
17
|
get_console,
|
|
18
18
|
get_output_format,
|
|
19
|
+
get_status_console,
|
|
19
20
|
is_agentic,
|
|
20
21
|
print_error,
|
|
21
22
|
print_info,
|
|
@@ -50,6 +51,8 @@ __all__ = [
|
|
|
50
51
|
"TimingContext",
|
|
51
52
|
"enable_timing",
|
|
52
53
|
"get_console",
|
|
54
|
+
"get_output_format",
|
|
55
|
+
"get_status_console",
|
|
53
56
|
"get_timing_summary",
|
|
54
57
|
"is_agentic",
|
|
55
58
|
"is_timing_enabled",
|
|
@@ -12,6 +12,7 @@ from pydantic import BaseModel
|
|
|
12
12
|
from rich.console import Console
|
|
13
13
|
from rich.progress import Progress, SpinnerColumn, TextColumn
|
|
14
14
|
|
|
15
|
+
from .client import _split_base_url
|
|
15
16
|
from .config import Config
|
|
16
17
|
from .models import ProfileInfo, ProfilesResult
|
|
17
18
|
|
|
@@ -273,8 +274,14 @@ class AuthManager:
|
|
|
273
274
|
"Content-Type": "application/json",
|
|
274
275
|
}
|
|
275
276
|
|
|
277
|
+
# Verify against the configured base URL (not hardcoded prod), so a
|
|
278
|
+
# custom base (e.g. staging) validates its own keys correctly.
|
|
279
|
+
# Preserve the input scheme so a plaintext endpoint isn't forced
|
|
280
|
+
# onto TLS.
|
|
281
|
+
base = self.config.get_profile().base_url or "https://api.deepgram.com"
|
|
282
|
+
rest_scheme, _, host = _split_base_url(base)
|
|
276
283
|
response = self.client.get(
|
|
277
|
-
"
|
|
284
|
+
f"{rest_scheme}://{host}/v1/projects",
|
|
278
285
|
headers=headers,
|
|
279
286
|
)
|
|
280
287
|
|
|
@@ -29,6 +29,19 @@ class BaseCommand(ABC):
|
|
|
29
29
|
requires_project: bool = False
|
|
30
30
|
ci_friendly: bool = True
|
|
31
31
|
|
|
32
|
+
# Result status -> process exit code, per the contract published in
|
|
33
|
+
# llms-full.txt: 0 = success, 1 = error, 2 = user interrupt. A command that
|
|
34
|
+
# reports failure must not exit 0 -- scripts and CI branch on the exit code,
|
|
35
|
+
# not on the "status" field inside the payload. "cancelled" is 2 rather than
|
|
36
|
+
# the shell's 130 to match that contract and main.py's own KeyboardInterrupt
|
|
37
|
+
# handler; `dg mcp` in particular returns cancelled straight out of its
|
|
38
|
+
# KeyboardInterrupt path. Any status not listed here exits 0
|
|
39
|
+
# (success, succeeded, info, dry_run, warning).
|
|
40
|
+
EXIT_CODES: ClassVar[dict[str, int]] = {
|
|
41
|
+
"error": 1,
|
|
42
|
+
"cancelled": 2,
|
|
43
|
+
}
|
|
44
|
+
|
|
32
45
|
# Agent-oriented metadata
|
|
33
46
|
examples: ClassVar[list[str]] = []
|
|
34
47
|
agent_help: str = ""
|
|
@@ -56,7 +69,10 @@ class BaseCommand(ABC):
|
|
|
56
69
|
config = Config()
|
|
57
70
|
|
|
58
71
|
# Extract explicit credentials from kwargs if provided
|
|
59
|
-
|
|
72
|
+
# (or from the global --api-key option stored on ctx.obj)
|
|
73
|
+
explicit_api_key = kwargs.get("api_key") or (
|
|
74
|
+
ctx.obj.get("api_key") if ctx.obj else None
|
|
75
|
+
)
|
|
60
76
|
explicit_project_id = kwargs.get("project_id")
|
|
61
77
|
|
|
62
78
|
# Create auth manager with explicit credentials
|
|
@@ -144,6 +160,23 @@ class BaseCommand(ABC):
|
|
|
144
160
|
stderr_console.print_exception()
|
|
145
161
|
raise click.ClickException(str(e))
|
|
146
162
|
|
|
163
|
+
# Payload is already on stdout; now make the exit code agree with it.
|
|
164
|
+
exit_code = self.exit_code_for(result)
|
|
165
|
+
if exit_code:
|
|
166
|
+
raise SystemExit(exit_code)
|
|
167
|
+
|
|
168
|
+
def exit_code_for(self, result: Any) -> int:
|
|
169
|
+
"""Map a command result to a process exit code.
|
|
170
|
+
|
|
171
|
+
Args:
|
|
172
|
+
result: Command result (may be None)
|
|
173
|
+
|
|
174
|
+
Returns:
|
|
175
|
+
Exit code for this result's status; 0 when it reported no failure
|
|
176
|
+
"""
|
|
177
|
+
status = str(getattr(result, "status", "") or "")
|
|
178
|
+
return self.EXIT_CODES.get(status, 0)
|
|
179
|
+
|
|
147
180
|
def is_guided(self, ctx: click.Context) -> bool:
|
|
148
181
|
"""True only when the user invoked this command with no input at all.
|
|
149
182
|
|
|
@@ -282,9 +315,25 @@ class BaseCommand(ABC):
|
|
|
282
315
|
elif output_format == "csv":
|
|
283
316
|
self._output_csv(result)
|
|
284
317
|
else:
|
|
285
|
-
|
|
318
|
+
# Diagnostics belong on stderr even here, or the complaint about
|
|
319
|
+
# the format corrupts the payload we fall back to.
|
|
320
|
+
stderr_console.print(
|
|
321
|
+
f"[red]Unknown output format:[/red] {output_format}"
|
|
322
|
+
)
|
|
286
323
|
self._output_json(result)
|
|
287
324
|
|
|
325
|
+
def _write_payload(self, text: str) -> None:
|
|
326
|
+
"""Write already-serialised machine-readable text to stdout verbatim.
|
|
327
|
+
|
|
328
|
+
Rich's default print would treat square brackets as style markup and
|
|
329
|
+
silently delete them, so a key comment of "[ci] runner" would lose the
|
|
330
|
+
"[ci]". It would also hard-wrap at the console width, injecting newlines
|
|
331
|
+
into the middle of a value. Both corrupt the payload, so markup,
|
|
332
|
+
highlighting and wrapping are all off. Routed through `console` rather
|
|
333
|
+
than `sys.stdout` so `--quiet` still suppresses output.
|
|
334
|
+
"""
|
|
335
|
+
console.print(text, markup=False, highlight=False, soft_wrap=True)
|
|
336
|
+
|
|
288
337
|
def _output_json(self, result: Any) -> None:
|
|
289
338
|
"""Output result as JSON."""
|
|
290
339
|
import json
|
|
@@ -307,9 +356,11 @@ class BaseCommand(ABC):
|
|
|
307
356
|
import yaml
|
|
308
357
|
|
|
309
358
|
if isinstance(result, dict | list):
|
|
310
|
-
|
|
359
|
+
self._write_payload(yaml.dump(result, default_flow_style=False))
|
|
311
360
|
else:
|
|
312
|
-
|
|
361
|
+
self._write_payload(
|
|
362
|
+
yaml.dump({"result": str(result)}, default_flow_style=False)
|
|
363
|
+
)
|
|
313
364
|
|
|
314
365
|
def _output_table(self, result: Any) -> None:
|
|
315
366
|
"""Output result as table."""
|
|
@@ -356,7 +407,7 @@ class BaseCommand(ABC):
|
|
|
356
407
|
dict_writer = csv.DictWriter(output, fieldnames=result[0].keys())
|
|
357
408
|
dict_writer.writeheader()
|
|
358
409
|
dict_writer.writerows(result)
|
|
359
|
-
|
|
410
|
+
self._write_payload(output.getvalue())
|
|
360
411
|
|
|
361
412
|
elif isinstance(result, dict):
|
|
362
413
|
# Dictionary
|
|
@@ -365,7 +416,7 @@ class BaseCommand(ABC):
|
|
|
365
416
|
writer.writerow(["Key", "Value"])
|
|
366
417
|
for key, value in result.items():
|
|
367
418
|
writer.writerow([key, value])
|
|
368
|
-
|
|
419
|
+
self._write_payload(output.getvalue())
|
|
369
420
|
|
|
370
421
|
else:
|
|
371
422
|
# Fallback to JSON
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import re
|
|
5
6
|
from pathlib import Path
|
|
6
7
|
from typing import TYPE_CHECKING, Any, cast
|
|
7
8
|
|
|
@@ -20,6 +21,22 @@ if TYPE_CHECKING:
|
|
|
20
21
|
console = Console()
|
|
21
22
|
|
|
22
23
|
|
|
24
|
+
def _split_base_url(base_url: str) -> tuple[str, str, str]:
|
|
25
|
+
"""Split a base URL into (rest_scheme, ws_scheme, host).
|
|
26
|
+
|
|
27
|
+
Preserves the transport implied by the input scheme so a plaintext
|
|
28
|
+
endpoint is not forced onto TLS: an ``http://`` base maps to ``http`` for
|
|
29
|
+
REST and ``ws`` for WebSocket; anything else (including a bare host) maps
|
|
30
|
+
to ``https``/``wss``. The host is returned without scheme or trailing slash.
|
|
31
|
+
"""
|
|
32
|
+
match = re.match(r"^([a-z]+)://", base_url)
|
|
33
|
+
scheme = match.group(1) if match else "https"
|
|
34
|
+
host = re.sub(r"^[a-z]+://", "", base_url).rstrip("/")
|
|
35
|
+
if scheme in ("http", "ws"):
|
|
36
|
+
return "http", "ws", host
|
|
37
|
+
return "https", "wss", host
|
|
38
|
+
|
|
39
|
+
|
|
23
40
|
class DeepgramClient:
|
|
24
41
|
"""Wrapper around Deepgram SDK with authentication integration."""
|
|
25
42
|
|
|
@@ -64,10 +81,18 @@ class DeepgramClient:
|
|
|
64
81
|
current_profile.base_url
|
|
65
82
|
and current_profile.base_url != "https://api.deepgram.com"
|
|
66
83
|
):
|
|
84
|
+
# Derive both the REST and WebSocket endpoints from the
|
|
85
|
+
# configured base URL, so a custom base works for batch REST
|
|
86
|
+
# *and* streaming. Preserve the transport implied by the input
|
|
87
|
+
# scheme (http→ws, https→wss) so a plaintext local/staging
|
|
88
|
+
# endpoint isn't forced onto TLS. agent_rest is required by the
|
|
89
|
+
# SDK environment.
|
|
90
|
+
rest_scheme, ws_scheme, host = _split_base_url(current_profile.base_url)
|
|
67
91
|
kwargs["environment"] = DeepgramClientEnvironment(
|
|
68
|
-
base=
|
|
69
|
-
production=
|
|
70
|
-
agent=
|
|
92
|
+
base=f"{rest_scheme}://{host}",
|
|
93
|
+
production=f"{ws_scheme}://{host}",
|
|
94
|
+
agent=f"{ws_scheme}://{host}",
|
|
95
|
+
agent_rest=f"{rest_scheme}://{host}",
|
|
71
96
|
)
|
|
72
97
|
|
|
73
98
|
client = DGClient(**kwargs)
|
|
@@ -158,6 +183,49 @@ class DeepgramClient:
|
|
|
158
183
|
except Exception as e:
|
|
159
184
|
raise ApiError(body=f"Text-to-speech failed: {e}")
|
|
160
185
|
|
|
186
|
+
def speak_text_stream(
|
|
187
|
+
self,
|
|
188
|
+
text: str,
|
|
189
|
+
model: str,
|
|
190
|
+
encoding: str | None = None,
|
|
191
|
+
sample_rate: float | None = None,
|
|
192
|
+
speed: float | None = None,
|
|
193
|
+
expressivity: int | None = None,
|
|
194
|
+
) -> Iterator[bytes]:
|
|
195
|
+
"""Stream TTS audio over the Flux v2 WebSocket (speak.v2.connect).
|
|
196
|
+
|
|
197
|
+
Yields raw audio chunks as they arrive. The streaming transport emits
|
|
198
|
+
raw (non-containerized) audio, so only linear16/mulaw/alaw encodings
|
|
199
|
+
apply and sample_rate is sent as the string the streaming API expects.
|
|
200
|
+
|
|
201
|
+
``speed`` (0.85-1.15) and beta ``expressivity`` (-2..2, default 0) are
|
|
202
|
+
Flux connect query parameters; they are only sent when set.
|
|
203
|
+
"""
|
|
204
|
+
from deepgram.speak.v2.types.speak_v2speak import SpeakV2Speak
|
|
205
|
+
|
|
206
|
+
connect_kwargs: dict[str, Any] = {"model": model}
|
|
207
|
+
if encoding:
|
|
208
|
+
connect_kwargs["encoding"] = encoding
|
|
209
|
+
if sample_rate:
|
|
210
|
+
connect_kwargs["sample_rate"] = str(int(sample_rate))
|
|
211
|
+
if speed is not None:
|
|
212
|
+
connect_kwargs["speed"] = speed
|
|
213
|
+
if expressivity is not None:
|
|
214
|
+
connect_kwargs["expressivity"] = expressivity
|
|
215
|
+
|
|
216
|
+
try:
|
|
217
|
+
with self.client.speak.v2.connect(**connect_kwargs) as conn:
|
|
218
|
+
conn.send_speak(SpeakV2Speak(type="Speak", text=text))
|
|
219
|
+
conn.send_flush()
|
|
220
|
+
conn.send_close()
|
|
221
|
+
for message in conn:
|
|
222
|
+
# Audio arrives as raw bytes; control messages are parsed
|
|
223
|
+
# objects, which we skip here.
|
|
224
|
+
if isinstance(message, bytes):
|
|
225
|
+
yield message
|
|
226
|
+
except Exception as e:
|
|
227
|
+
raise ApiError(body=f"Text-to-speech streaming failed: {e}")
|
|
228
|
+
|
|
161
229
|
# ── Text Intelligence (Read) ───────────────────────────────────
|
|
162
230
|
|
|
163
231
|
def analyze_text(
|
|
@@ -505,3 +505,19 @@ def get_console() -> Console:
|
|
|
505
505
|
Console instance
|
|
506
506
|
"""
|
|
507
507
|
return console
|
|
508
|
+
|
|
509
|
+
|
|
510
|
+
def get_status_console() -> Console:
|
|
511
|
+
"""Get the console for status/progress chrome.
|
|
512
|
+
|
|
513
|
+
Always writes to stderr, so anything printed through it can never corrupt
|
|
514
|
+
the machine-readable payload a command writes to stdout. Commands should
|
|
515
|
+
use this rather than declaring their own ``Console(stderr=True)`` — a
|
|
516
|
+
per-command console silently misses the agentic no-color settings, and a
|
|
517
|
+
command that reaches for a bare ``Console()`` reintroduces the stdout
|
|
518
|
+
pollution this exists to prevent.
|
|
519
|
+
|
|
520
|
+
Returns:
|
|
521
|
+
Console instance writing to stderr
|
|
522
|
+
"""
|
|
523
|
+
return stderr_console
|
|
@@ -417,7 +417,8 @@ def render_developer_guide(
|
|
|
417
417
|
lines.append("## Text-to-Speech (TTS)")
|
|
418
418
|
lines.append("")
|
|
419
419
|
lines.append(
|
|
420
|
-
"Generate natural-sounding speech from text using Deepgram's Aura
|
|
420
|
+
"Generate natural-sounding speech from text using Deepgram's Aura and "
|
|
421
|
+
"Flux voices."
|
|
421
422
|
)
|
|
422
423
|
lines.append("")
|
|
423
424
|
lines.append("### Models")
|
|
@@ -426,47 +427,84 @@ def render_developer_guide(
|
|
|
426
427
|
"- **Aura-2** — Latest generation. High quality, low latency, many voices."
|
|
427
428
|
)
|
|
428
429
|
lines.append("- **Aura** — Previous generation. Solid quality and performance.")
|
|
430
|
+
lines.append(
|
|
431
|
+
"- **Flux** — Conversational TTS on the Speak v2 WebSocket API "
|
|
432
|
+
"(streaming, turn-based). Voices like `flux-alexis-en`."
|
|
433
|
+
)
|
|
429
434
|
lines.append("")
|
|
430
435
|
lines.append("### Popular Voices")
|
|
431
436
|
lines.append("")
|
|
432
|
-
lines.append("
|
|
437
|
+
lines.append("Aura voices follow `aura-2-{name}-en`. Examples:")
|
|
433
438
|
lines.append("- `aura-2-andromeda-en`, `aura-2-arcas-en`, `aura-2-atlas-en`")
|
|
434
439
|
lines.append("- `aura-2-luna-en`, `aura-2-stella-en`, `aura-2-helios-en`")
|
|
435
440
|
lines.append("")
|
|
441
|
+
lines.append(
|
|
442
|
+
"Flux (Speak v2) voices follow `flux-{name}-en` (English at launch), "
|
|
443
|
+
"e.g. `flux-alexis-en`."
|
|
444
|
+
)
|
|
445
|
+
lines.append("")
|
|
436
446
|
lines.append("Full voice list: <https://developers.deepgram.com/docs/tts-models>")
|
|
437
447
|
lines.append("")
|
|
438
|
-
lines.append("### TTS
|
|
448
|
+
lines.append("### Aura TTS — Speak v1, batch REST (Python)")
|
|
439
449
|
lines.append("")
|
|
440
450
|
lines.append("```python")
|
|
441
|
-
lines.append("from deepgram import DeepgramClient
|
|
451
|
+
lines.append("from deepgram import DeepgramClient")
|
|
442
452
|
lines.append("")
|
|
443
|
-
lines.append('
|
|
453
|
+
lines.append('client = DeepgramClient(api_key="DEEPGRAM_API_KEY")')
|
|
444
454
|
lines.append("")
|
|
445
|
-
lines.append("
|
|
446
|
-
lines.append('
|
|
455
|
+
lines.append("audio = client.speak.v1.audio.generate(")
|
|
456
|
+
lines.append(' text="Hello from Deepgram!",')
|
|
457
|
+
lines.append(' model="aura-2-andromeda-en",')
|
|
458
|
+
lines.append(' encoding="mp3",')
|
|
447
459
|
lines.append(")")
|
|
460
|
+
lines.append('with open("output.mp3", "wb") as f:')
|
|
461
|
+
lines.append(" for chunk in audio:")
|
|
462
|
+
lines.append(" f.write(chunk)")
|
|
463
|
+
lines.append("```")
|
|
448
464
|
lines.append("")
|
|
449
|
-
lines.append(
|
|
450
|
-
lines.append(
|
|
451
|
-
lines.append(
|
|
452
|
-
|
|
453
|
-
|
|
465
|
+
lines.append("### Flux TTS — Speak v2, WebSocket streaming (Python)")
|
|
466
|
+
lines.append("")
|
|
467
|
+
lines.append(
|
|
468
|
+
"`expressivity` is beta and defaults to `0` (nominal delivery) when omitted."
|
|
469
|
+
)
|
|
470
|
+
lines.append("")
|
|
471
|
+
lines.append("```python")
|
|
472
|
+
lines.append("from deepgram import DeepgramClient")
|
|
473
|
+
lines.append("from deepgram.speak.v2.types.speak_v2speak import SpeakV2Speak")
|
|
474
|
+
lines.append("")
|
|
475
|
+
lines.append('client = DeepgramClient(api_key="DEEPGRAM_API_KEY")')
|
|
476
|
+
lines.append("")
|
|
477
|
+
lines.append("with client.speak.v2.connect(")
|
|
478
|
+
lines.append(' model="flux-alexis-en",')
|
|
479
|
+
lines.append(' encoding="linear16",')
|
|
480
|
+
lines.append(' sample_rate="24000",')
|
|
481
|
+
lines.append(" speed=1.0, # 0.85–1.15 in 0.05 steps (optional)")
|
|
482
|
+
lines.append(" expressivity=0, # beta; -2..2, default 0 = nominal (optional)")
|
|
483
|
+
lines.append(") as conn:")
|
|
484
|
+
lines.append(
|
|
485
|
+
' conn.send_speak(SpeakV2Speak(type="Speak", text="Hello from Flux!"))'
|
|
486
|
+
)
|
|
487
|
+
lines.append(" conn.send_flush()")
|
|
488
|
+
lines.append(" conn.send_close()")
|
|
489
|
+
lines.append(' with open("output.raw", "wb") as f:')
|
|
490
|
+
lines.append(" for message in conn:")
|
|
491
|
+
lines.append(" if isinstance(message, bytes):")
|
|
492
|
+
lines.append(" f.write(message) # raw linear16 PCM, 24kHz mono")
|
|
454
493
|
lines.append("```")
|
|
455
494
|
lines.append("")
|
|
456
|
-
lines.append("### TTS
|
|
495
|
+
lines.append("### Aura TTS — Speak v1 (JavaScript)")
|
|
457
496
|
lines.append("")
|
|
458
497
|
lines.append("```javascript")
|
|
459
498
|
lines.append('import { createClient } from "@deepgram/sdk";')
|
|
460
499
|
lines.append("")
|
|
461
|
-
lines.append('const
|
|
462
|
-
lines.append("")
|
|
463
|
-
lines.append("const response = await dg.speak.request(")
|
|
464
|
-
lines.append(' { text: "Hello from Deepgram!" },')
|
|
465
|
-
lines.append(' { model: "aura-2-andromeda-en" }')
|
|
466
|
-
lines.append(");")
|
|
500
|
+
lines.append('const client = createClient("DEEPGRAM_API_KEY");')
|
|
467
501
|
lines.append("")
|
|
468
|
-
lines.append("const
|
|
469
|
-
lines.append("
|
|
502
|
+
lines.append("const response = await client.speak.v1.audio.generate({")
|
|
503
|
+
lines.append(' text: "Hello from Deepgram!",')
|
|
504
|
+
lines.append(' model: "aura-2-andromeda-en",')
|
|
505
|
+
lines.append("});")
|
|
506
|
+
lines.append("const buffer = await response.arrayBuffer();")
|
|
507
|
+
lines.append("// Write buffer to a file or audio output")
|
|
470
508
|
lines.append("```")
|
|
471
509
|
lines.append("")
|
|
472
510
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: deepctl-core
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.16
|
|
4
4
|
Summary: Core components for deepctl
|
|
5
5
|
Author-email: Deepgram <devrel@deepgram.com>
|
|
6
6
|
Maintainer-email: Deepgram <devrel@deepgram.com>
|
|
@@ -16,7 +16,7 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
|
16
16
|
Requires-Python: >=3.10
|
|
17
17
|
Description-Content-Type: text/markdown
|
|
18
18
|
Requires-Dist: click>=8.0.0
|
|
19
|
-
Requires-Dist: deepgram-sdk
|
|
19
|
+
Requires-Dist: deepgram-sdk<8,>=7.7.0
|
|
20
20
|
Requires-Dist: pydantic>=2.0.0
|
|
21
21
|
Requires-Dist: rich>=13.0.0
|
|
22
22
|
Requires-Dist: httpx>=0.24.0
|
|
@@ -63,7 +63,7 @@ pipx run deepctl --help
|
|
|
63
63
|
## Dependencies
|
|
64
64
|
|
|
65
65
|
- `click>=8.0.0`
|
|
66
|
-
- `deepgram-sdk>=
|
|
66
|
+
- `deepgram-sdk>=7.7.0,<8`
|
|
67
67
|
- `pydantic>=2.0.0`
|
|
68
68
|
- `rich>=13.0.0`
|
|
69
69
|
- `httpx>=0.24.0`
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|