sference-cli 0.1.3__tar.gz → 0.1.5__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: sference-cli
3
- Version: 0.1.3
3
+ Version: 0.1.5
4
4
  Summary: sference command-line interface
5
5
  Project-URL: Homepage, https://sference.com
6
6
  Project-URL: Repository, https://github.com/s-ference/sference
@@ -21,7 +21,7 @@ Classifier: Programming Language :: Python :: 3.12
21
21
  Classifier: Programming Language :: Python :: 3.13
22
22
  Classifier: Topic :: Utilities
23
23
  Requires-Python: >=3.10
24
- Requires-Dist: sference-sdk>=0.1.3
24
+ Requires-Dist: sference-sdk>=0.1.5
25
25
  Requires-Dist: typer>=0.24.1
26
26
  Description-Content-Type: text/markdown
27
27
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "sference-cli"
3
- version = "0.1.3"
3
+ version = "0.1.5"
4
4
  description = "sference command-line interface"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
@@ -23,7 +23,7 @@ classifiers = [
23
23
  ]
24
24
  dependencies = [
25
25
  "typer>=0.24.1",
26
- "sference-sdk>=0.1.3",
26
+ "sference-sdk>=0.1.5",
27
27
  ]
28
28
 
29
29
  [project.urls]
@@ -32,11 +32,13 @@ batch_app = typer.Typer(help="Batch commands", invoke_without_command=True)
32
32
  stream_app = typer.Typer(help="Stream commands", invoke_without_command=True)
33
33
  responses_app = typer.Typer(help="Responses commands", invoke_without_command=True)
34
34
  models_app = typer.Typer(help="List models (GET /v1/models)", invoke_without_command=True)
35
+ embeddings_app = typer.Typer(help="Embeddings commands", invoke_without_command=True)
35
36
  app.add_typer(auth_app, name="auth")
36
37
  app.add_typer(batch_app, name="batch")
37
38
  app.add_typer(stream_app, name="stream")
38
39
  app.add_typer(responses_app, name="responses")
39
40
  app.add_typer(models_app, name="models")
41
+ app.add_typer(embeddings_app, name="embeddings")
40
42
  register_launch_commands(app)
41
43
 
42
44
  CREDENTIALS_PATH = Path.home() / ".sference" / "credentials.json"
@@ -148,7 +150,58 @@ def _print(value: object, as_json: bool) -> None:
148
150
 
149
151
  def _list_models(*, client: SferenceClient, as_json: bool) -> None:
150
152
  payload = _call_api(client.list_models)
151
- typer.echo(json.dumps(payload, indent=None if as_json else 2))
153
+ if as_json:
154
+ typer.echo(json.dumps(payload, indent=2, default=str))
155
+ return
156
+ _print_models_table(payload)
157
+
158
+
159
+ def _capability_flag(caps: object, key: str) -> str:
160
+ if not isinstance(caps, dict):
161
+ return "—"
162
+ entry = caps.get(key)
163
+ if isinstance(entry, dict) and "supported" in entry:
164
+ return "yes" if entry["supported"] else "no"
165
+ return "—"
166
+
167
+
168
+ def _print_models_table(payload: object) -> None:
169
+ if not isinstance(payload, dict):
170
+ typer.echo(str(payload))
171
+ return
172
+ rows = payload.get("data")
173
+ if not isinstance(rows, list):
174
+ typer.echo(json.dumps(payload, indent=2, default=str))
175
+ return
176
+ if not rows:
177
+ typer.echo("No models.")
178
+ return
179
+
180
+ w_id, w_name, w_ctx, w_vis, w_pdf, w_think, w_tools = 34, 18, 8, 6, 4, 8, 5
181
+ typer.echo(
182
+ f"{'id':<{w_id}} {'display_name':<{w_name}} {'context':>{w_ctx}} "
183
+ f"{'vision':>{w_vis}} {'pdf':>{w_pdf}} {'thinking':>{w_think}} {'tools':>{w_tools}}"
184
+ )
185
+ for row in rows:
186
+ if not isinstance(row, dict):
187
+ continue
188
+ model_id = str(row.get("id", ""))
189
+ if len(model_id) > w_id:
190
+ model_id = model_id[: w_id - 3] + "..."
191
+ display_name = str(row.get("display_name") or "")
192
+ if len(display_name) > w_name:
193
+ display_name = display_name[: w_name - 1] + "…"
194
+ ctx_raw = row.get("context_tokens")
195
+ context = str(ctx_raw) if isinstance(ctx_raw, int) else "—"
196
+ caps = row.get("capabilities")
197
+ vision = _capability_flag(caps, "image_input")
198
+ pdf = _capability_flag(caps, "pdf_input")
199
+ thinking = _capability_flag(caps, "thinking")
200
+ tools = _capability_flag(caps, "tools")
201
+ typer.echo(
202
+ f"{model_id:<{w_id}} {display_name:<{w_name}} {context:>{w_ctx}} "
203
+ f"{vision:>{w_vis}} {pdf:>{w_pdf}} {thinking:>{w_think}} {tools:>{w_tools}}"
204
+ )
152
205
 
153
206
 
154
207
  def _window_choice(value: str) -> str:
@@ -235,6 +288,34 @@ def models_list(
235
288
  _list_models(client=client, as_json=as_json)
236
289
 
237
290
 
291
+ @embeddings_app.command("create")
292
+ def embeddings_create(
293
+ model: str = typer.Option(..., "--model"),
294
+ input_text: list[str] = typer.Option(..., "--input", help="Text to embed (repeat for multiple strings)."),
295
+ encoding_format: str = typer.Option("float", "--encoding-format", help='"float" or "base64".'),
296
+ dimensions: int | None = typer.Option(None, "--dimensions"),
297
+ timeout: float = typer.Option(600.0, "--timeout", help="HTTP read timeout in seconds."),
298
+ base_url: str = typer.Option("https://api.sference.com"),
299
+ as_json: bool = typer.Option(False, "--json"),
300
+ ) -> None:
301
+ """Create embeddings (POST /v1/embeddings)."""
302
+ _ensure_api_credential()
303
+ if encoding_format not in ("float", "base64"):
304
+ typer.echo('encoding_format must be "float" or "base64".', err=True)
305
+ raise typer.Exit(code=1)
306
+ inp: str | list[str] = input_text[0] if len(input_text) == 1 else input_text
307
+ client = _client(base_url, timeout=timeout)
308
+ resp = _call_api(
309
+ lambda: client.create_embeddings(
310
+ model=model,
311
+ input=inp,
312
+ encoding_format=encoding_format, # type: ignore[arg-type]
313
+ dimensions=dimensions,
314
+ )
315
+ )
316
+ _print(resp.model_dump(), as_json or True)
317
+
318
+
238
319
  @auth_app.command("login")
239
320
  def auth_login(
240
321
  api_key: Optional[str] = typer.Option(
File without changes
File without changes
File without changes