deepctl-cmd-models 0.0.2__tar.gz → 0.1.1__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-cmd-models
3
- Version: 0.0.2
3
+ Version: 0.1.1
4
4
  Summary: Models 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.1.10
17
+ Requires-Dist: deepctl-core>=0.2.16
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-models"
7
- version = "0.0.2" # x-release-please-version
7
+ version = "0.1.1" # x-release-please-version
8
8
  description = "Models command for deepctl"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -21,7 +21,7 @@ classifiers = [
21
21
  keywords = ["deepgram", "cli", "models"]
22
22
  requires-python = ">=3.10"
23
23
  dependencies = [
24
- "deepctl-core>=0.1.10",
24
+ "deepctl-core>=0.2.16",
25
25
  "click>=8.0.0",
26
26
  "rich>=13.0.0",
27
27
  "pydantic>=2.0.0",
@@ -0,0 +1,216 @@
1
+ """Models command for deepctl."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+ from deepctl_core import (
8
+ AuthManager,
9
+ BaseCommand,
10
+ BaseResult,
11
+ Config,
12
+ DeepgramClient,
13
+ get_output_format,
14
+ get_status_console,
15
+ )
16
+ from rich.console import Console
17
+ from rich.table import Table
18
+
19
+ from .models import ModelInfo, ModelsResult
20
+
21
+ console = Console()
22
+ # Status/progress chrome must never touch stdout, or it corrupts JSON/CSV
23
+ # output that callers pipe into jq and friends.
24
+ status_console = get_status_console()
25
+
26
+ # Models the API still lists but which are legacy. The catalog flags them so
27
+ # that nobody — human or coding agent — treats them as a current model family
28
+ # or composes new model names from them. (Paying accounts have requested the
29
+ # nonexistent "nova-3-conversational", a natural composition of "nova-3" and
30
+ # the legacy name below.)
31
+ DEPRECATED_MODELS: dict[str, str] = {
32
+ "conversationalai": (
33
+ "Legacy model. For conversational audio use 'nova-3'. There is no "
34
+ "model named 'nova-3-conversational'."
35
+ ),
36
+ "2-conversationalai": (
37
+ "Legacy model. For conversational audio use 'nova-3'. There is no "
38
+ "model named 'nova-3-conversational'."
39
+ ),
40
+ }
41
+
42
+
43
+ def _build_model_info(m: dict[str, Any], model_type: str) -> ModelInfo:
44
+ """Map one API model entry onto ModelInfo.
45
+
46
+ The Deepgram Python SDK's generated response classes rename the API's
47
+ ``uuid`` field to ``uuid_`` (to avoid shadowing), so ``model_dump()``
48
+ emits ``uuid_`` — both spellings are read here. The API also reports
49
+ ``languages`` as a list; the older singular ``language`` key is kept as
50
+ a fallback for compatibility.
51
+ """
52
+ model_id = m.get("uuid_") or m.get("uuid") or m.get("model_id") or ""
53
+
54
+ raw_languages = m.get("languages") or []
55
+ if not isinstance(raw_languages, list):
56
+ raw_languages = [raw_languages]
57
+ languages = [str(lang) for lang in raw_languages]
58
+ primary_language = str(m.get("language") or (languages[0] if languages else ""))
59
+
60
+ name = str(m.get("name") or "")
61
+ deprecation_note = DEPRECATED_MODELS.get(name.lower(), "")
62
+
63
+ return ModelInfo(
64
+ model_id=str(model_id),
65
+ name=name,
66
+ canonical_name=str(m.get("canonical_name") or ""),
67
+ architecture=str(m.get("architecture") or ""),
68
+ version=str(m.get("version") or ""),
69
+ language=primary_language,
70
+ languages=languages,
71
+ model_type=model_type,
72
+ deprecated=bool(deprecation_note),
73
+ deprecation_note=deprecation_note,
74
+ )
75
+
76
+
77
+ def _format_languages(languages: list[str], limit: int = 4) -> str:
78
+ """Join a language list for table display, truncating long lists."""
79
+ if len(languages) <= limit:
80
+ return ", ".join(languages)
81
+ return ", ".join(languages[:limit]) + f" +{len(languages) - limit}"
82
+
83
+
84
+ class ModelsCommand(BaseCommand):
85
+ """Command for listing available Deepgram models."""
86
+
87
+ name = "models"
88
+ help = "List available Deepgram models"
89
+ short_help = "List models"
90
+
91
+ requires_auth = True
92
+ requires_project = False
93
+ ci_friendly = True
94
+
95
+ examples = [
96
+ "dg models",
97
+ "dg models --type stt",
98
+ "dg models --type tts",
99
+ "dg models --include-outdated",
100
+ ]
101
+ agent_help = (
102
+ "List available Deepgram speech-to-text and text-to-speech models. "
103
+ "Filter by type (stt/tts) and optionally include outdated versions. "
104
+ "Use the canonical_name field as the `model` request parameter. "
105
+ "Entries flagged deprecated are legacy: do not use them or derive "
106
+ "new model names from them. Requires authentication."
107
+ )
108
+
109
+ def get_arguments(self) -> list[dict[str, Any]]:
110
+ return [
111
+ {
112
+ "names": ["--type", "-t"],
113
+ "help": "Filter by model type (stt, tts)",
114
+ "type": str,
115
+ "is_option": True,
116
+ },
117
+ {
118
+ "names": ["--include-outdated"],
119
+ "help": "Include outdated model versions",
120
+ "is_flag": True,
121
+ "is_option": True,
122
+ },
123
+ ]
124
+
125
+ def handle(
126
+ self,
127
+ config: Config,
128
+ auth_manager: AuthManager,
129
+ client: DeepgramClient,
130
+ **kwargs: Any,
131
+ ) -> BaseResult:
132
+ model_type = kwargs.get("type")
133
+ include_outdated = kwargs.get("include_outdated", False)
134
+
135
+ try:
136
+ result = client.list_models(include_outdated=include_outdated)
137
+
138
+ # `or []` also covers an explicit null in the response body.
139
+ stt_models = result.get("stt") or []
140
+ tts_models = result.get("tts") or []
141
+
142
+ all_models: list[ModelInfo] = []
143
+
144
+ if model_type != "tts":
145
+ for m in stt_models:
146
+ all_models.append(_build_model_info(m, "stt"))
147
+ if not stt_models:
148
+ status_console.print(
149
+ "[yellow]Warning: the API returned zero speech-to-text "
150
+ "models. Deepgram publishes speech-to-text models "
151
+ "(Nova-3, Flux), so an empty list usually means an API "
152
+ "or account problem, not an empty catalog.[/yellow]"
153
+ )
154
+
155
+ if model_type != "stt":
156
+ for m in tts_models:
157
+ all_models.append(_build_model_info(m, "tts"))
158
+ if not tts_models:
159
+ status_console.print(
160
+ "[yellow]Warning: the API returned zero text-to-speech "
161
+ "models. Deepgram publishes text-to-speech models "
162
+ "(Aura-2), so an empty list usually means an API or "
163
+ "account problem, not an empty catalog.[/yellow]"
164
+ )
165
+
166
+ if not all_models:
167
+ status_console.print("[yellow]No models found[/yellow]")
168
+ return ModelsResult(status="info", message="No models found")
169
+
170
+ # Render the human table only in default mode. For json/yaml/csv
171
+ # the framework serialises the returned result to stdout, so
172
+ # printing the table here would corrupt that output for piping.
173
+ if get_output_format() == "default":
174
+ table = Table(
175
+ title="Deepgram Models", show_header=True, header_style="bold blue"
176
+ )
177
+ table.add_column("Name", style="green")
178
+ table.add_column("Canonical name", style="green")
179
+ table.add_column("Architecture")
180
+ table.add_column("Type", style="cyan")
181
+ table.add_column("Languages")
182
+ table.add_column("Version")
183
+ table.add_column("ID", style="dim")
184
+
185
+ for m in all_models:
186
+ display_name = m.name
187
+ if m.deprecated:
188
+ display_name = f"{m.name} [yellow](deprecated)[/yellow]"
189
+ table.add_row(
190
+ display_name,
191
+ m.canonical_name,
192
+ m.architecture,
193
+ m.model_type.upper(),
194
+ _format_languages(m.languages),
195
+ m.version,
196
+ m.model_id,
197
+ )
198
+
199
+ console.print(table)
200
+ console.print(f"\n[dim]{len(all_models)} model(s) found[/dim]")
201
+
202
+ deprecated_notes = {
203
+ m.name: m.deprecation_note for m in all_models if m.deprecated
204
+ }
205
+ for name, note in sorted(deprecated_notes.items()):
206
+ console.print(f"[yellow]Deprecated:[/yellow] {name} — {note}")
207
+
208
+ return ModelsResult(
209
+ status="success",
210
+ models=all_models,
211
+ count=len(all_models),
212
+ )
213
+
214
+ except Exception as e:
215
+ status_console.print(f"[red]Error listing models:[/red] {e}")
216
+ return BaseResult(status="error", message=str(e))
@@ -9,9 +9,14 @@ from pydantic import BaseModel, Field
9
9
  class ModelInfo(BaseModel):
10
10
  model_id: str = ""
11
11
  name: str = ""
12
+ canonical_name: str = "" # the value to pass as the `model` parameter
13
+ architecture: str = ""
12
14
  version: str = ""
13
- language: str = ""
15
+ language: str = "" # primary language (first entry of `languages`)
16
+ languages: list[str] = Field(default_factory=list)
14
17
  model_type: str = "" # "stt" or "tts"
18
+ deprecated: bool = False
19
+ deprecation_note: str = ""
15
20
 
16
21
 
17
22
  class ModelsResult(BaseResult):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: deepctl-cmd-models
3
- Version: 0.0.2
3
+ Version: 0.1.1
4
4
  Summary: Models 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.1.10
17
+ Requires-Dist: deepctl-core>=0.2.16
18
18
  Requires-Dist: click>=8.0.0
19
19
  Requires-Dist: rich>=13.0.0
20
20
  Requires-Dist: pydantic>=2.0.0
@@ -1,4 +1,4 @@
1
- deepctl-core>=0.1.10
1
+ deepctl-core>=0.2.16
2
2
  click>=8.0.0
3
3
  rich>=13.0.0
4
4
  pydantic>=2.0.0
@@ -1,133 +0,0 @@
1
- """Models command for deepctl."""
2
-
3
- from __future__ import annotations
4
-
5
- from typing import Any
6
-
7
- from deepctl_core import (
8
- AuthManager,
9
- BaseCommand,
10
- BaseResult,
11
- Config,
12
- DeepgramClient,
13
- )
14
- from rich.console import Console
15
- from rich.table import Table
16
-
17
- from .models import ModelInfo, ModelsResult
18
-
19
- console = Console()
20
-
21
-
22
- class ModelsCommand(BaseCommand):
23
- """Command for listing available Deepgram models."""
24
-
25
- name = "models"
26
- help = "List available Deepgram models"
27
- short_help = "List models"
28
-
29
- requires_auth = True
30
- requires_project = False
31
- ci_friendly = True
32
-
33
- examples = [
34
- "dg models",
35
- "dg models --type stt",
36
- "dg models --type tts",
37
- "dg models --include-outdated",
38
- ]
39
- agent_help = (
40
- "List available Deepgram speech-to-text and text-to-speech models. "
41
- "Filter by type (stt/tts) and optionally include outdated versions. "
42
- "Requires authentication."
43
- )
44
-
45
- def get_arguments(self) -> list[dict[str, Any]]:
46
- return [
47
- {
48
- "names": ["--type", "-t"],
49
- "help": "Filter by model type (stt, tts)",
50
- "type": str,
51
- "is_option": True,
52
- },
53
- {
54
- "names": ["--include-outdated"],
55
- "help": "Include outdated model versions",
56
- "is_flag": True,
57
- "is_option": True,
58
- },
59
- ]
60
-
61
- def handle(
62
- self,
63
- config: Config,
64
- auth_manager: AuthManager,
65
- client: DeepgramClient,
66
- **kwargs: Any,
67
- ) -> BaseResult:
68
- model_type = kwargs.get("type")
69
- include_outdated = kwargs.get("include_outdated", False)
70
-
71
- try:
72
- result = client.list_models(include_outdated=include_outdated)
73
-
74
- stt_models = result.get("stt", [])
75
- tts_models = result.get("tts", [])
76
-
77
- all_models: list[ModelInfo] = []
78
-
79
- if model_type != "tts":
80
- for m in stt_models:
81
- all_models.append(
82
- ModelInfo(
83
- model_id=m.get("uuid", m.get("model_id", "")),
84
- name=m.get("name", ""),
85
- version=m.get("version", ""),
86
- language=m.get("language", ""),
87
- model_type="stt",
88
- )
89
- )
90
-
91
- if model_type != "stt":
92
- for m in tts_models:
93
- all_models.append(
94
- ModelInfo(
95
- model_id=m.get("uuid", m.get("model_id", "")),
96
- name=m.get("name", ""),
97
- version=m.get("version", ""),
98
- language=m.get("language", ""),
99
- model_type="tts",
100
- )
101
- )
102
-
103
- if not all_models:
104
- console.print("[yellow]No models found[/yellow]")
105
- return ModelsResult(status="info", message="No models found")
106
-
107
- # Display as table
108
- table = Table(
109
- title="Deepgram Models", show_header=True, header_style="bold blue"
110
- )
111
- table.add_column("Name", style="green")
112
- table.add_column("Type", style="cyan")
113
- table.add_column("Language")
114
- table.add_column("Version")
115
- table.add_column("ID", style="dim")
116
-
117
- for m in all_models:
118
- table.add_row(
119
- m.name, m.model_type.upper(), m.language, m.version, m.model_id
120
- )
121
-
122
- console.print(table)
123
- console.print(f"\n[dim]{len(all_models)} model(s) found[/dim]")
124
-
125
- return ModelsResult(
126
- status="success",
127
- models=all_models,
128
- count=len(all_models),
129
- )
130
-
131
- except Exception as e:
132
- console.print(f"[red]Error listing models:[/red] {e}")
133
- return BaseResult(status="error", message=str(e))