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.
- {sference_cli-0.1.3 → sference_cli-0.1.5}/PKG-INFO +2 -2
- {sference_cli-0.1.3 → sference_cli-0.1.5}/pyproject.toml +2 -2
- {sference_cli-0.1.3 → sference_cli-0.1.5}/sference_cli/main.py +82 -1
- {sference_cli-0.1.3 → sference_cli-0.1.5}/.gitignore +0 -0
- {sference_cli-0.1.3 → sference_cli-0.1.5}/LICENSE +0 -0
- {sference_cli-0.1.3 → sference_cli-0.1.5}/README.md +0 -0
- {sference_cli-0.1.3 → sference_cli-0.1.5}/sference_cli/__init__.py +0 -0
- {sference_cli-0.1.3 → sference_cli-0.1.5}/sference_cli/launch.py +0 -0
- {sference_cli-0.1.3 → sference_cli-0.1.5}/sference_cli/stream_cache.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sference-cli
|
|
3
|
-
Version: 0.1.
|
|
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.
|
|
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
|
+
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.
|
|
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
|
-
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|