Metadata-Version: 2.4
Name: simplismart-sdk
Version: 0.1.3
Summary: Python SDK for Simplismart API - Deploy models, manage deployments, and query usage analytics
Author-email: Simplismart <developers@simplismart.ai>
Project-URL: Homepage, https://simplismart.ai
Project-URL: Source, https://docs.simplismart.ai/sdk/python
Keywords: simplismart,sdk,api,deployments,models
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: License :: Other/Proprietary License
Classifier: Operating System :: OS Independent
Requires-Python: >=3.9
Description-Content-Type: text/markdown
Requires-Dist: requests>=2.31
Requires-Dist: pydantic<3,>=2.0

# Simplismart Python SDK

[![PyPI version](https://img.shields.io/pypi/v/simplismart-sdk.svg)](https://pypi.org/project/simplismart-sdk/)
[![Python 3.9+](https://img.shields.io/badge/python-3.9+-blue.svg)](https://www.python.org/downloads/)

Official Python SDK and CLI for the [Simplismart](https://simplismart.ai) MLOps platform. Deploy and manage AI/ML models and containers with an idiomatic Python client and a full-featured CLI.

## Features

- **Model repos** - List, create (Bring Your Own Container), create private compile jobs, get, profile lookup, delete
- **Deployments** - Create private or BYOC deployments; list, update, start, stop, scale, delete; health checks and autoscaling
- **Secrets** - Create and manage registry credentials (e.g. Docker Hub) for secure image pulls
- **Usage analytics** - Query cost and usage data per plan type, with optional filtering by deployment / training job / model repo
- **CLI** - Same capabilities from the terminal with `simplismart` for scripts and CI/CD

## Requirements

- **Python 3.9+**
- A Simplismart **Playground token** (PG token) and **organization ID**

## Installation

```bash
pip install simplismart-sdk
```

## Authentication

```bash
export SIMPLISMART_PG_TOKEN="<YOUR_PG_TOKEN>"
export ORG_ID="<YOUR_ORG_UUID>"

# Optional
export SIMPLISMART_BASE_URL="https://api.app.simplismart.ai"
export SIMPLISMART_TIMEOUT="300"
```

### Configuration Reference

| Variable | Required | Default | Description |
|---|---|---|---|
| `SIMPLISMART_PG_TOKEN` | Yes* | - | Playground API token |
| `ORG_ID` | Recommended | - | Organization UUID used in create/list examples |
| `SIMPLISMART_BASE_URL` | No | `https://api.app.simplismart.ai` | API base URL |
| `SIMPLISMART_TIMEOUT` | No | `300` | Optional request timeout in seconds |
| `SIMPLISMART_TRACE_ID` | No | (none) | Default trace ID value; if unset, SDK auto-generates one per request |

\* Required unless passed in constructor (`Simplismart(pg_token=...)`).

## Quick Start (Python)

```python
from simplismart import ModelRepoListParams, Simplismart

client = Simplismart()  # uses SIMPLISMART_PG_TOKEN from environment

repos = client.list_model_repos(
    ModelRepoListParams(
        org_id="<YOUR_ORG_UUID>",
        offset=0,
        count=5,
    )
)

print(repos)
```

### Explicit Client Constructor

Use explicit parameters instead of environment variables when needed.
Trace IDs are set per request. If you don't pass `trace_id`, the SDK auto-generates one.

```python
from simplismart import Simplismart

client = Simplismart(
    pg_token="<YOUR_PG_TOKEN>",
    base_url="https://api.app.simplismart.ai",  # optional
    timeout=300,                                  # optional
)
```

### Tracing (Trace ID)

Every request sends an `X-Trace-Id` header.

- Python: pass `trace_id=...` on the SDK method call.
- CLI: pass `--trace-id ...` once per CLI invocation.
- Optional: set `SIMPLISMART_TRACE_ID` to define a default trace ID when you don't pass `trace_id`.
- If omitted, the SDK generates a new trace ID per request.

```python
repo = client.get_model_repo(model_id="<MODEL_REPO_ID>", trace_id="my-correlation-id")
print(repo)
```

```bash
simplismart --trace-id my-correlation-id model-repos get --model-id "<MODEL_REPO_ID>"
```

## Model Repositories

### List and Get

#### CLI

```bash
# List
simplismart model-repos list --org-id "$ORG_ID" --offset 0 --count 5

# Print only model repo IDs
simplismart model-repos list --org-id "$ORG_ID" | jq -r '.results[].uuid'
# Note: `jq` is optional. If you don't have it installed, remove the pipe and inspect the JSON output.

# Get one model repo
simplismart model-repos get --model-id "<MODEL_REPO_ID>"

# Model profiles
simplismart model-repos profiles --type hf --path "meta-llama/Llama-3.2-1B-Instruct"
# Optional: pass a secret if the source requires it
simplismart model-repos profiles --type hf --path "meta-llama/Llama-3.2-1B-Instruct" --secret-id "<SECRET_ID>"
```

#### Python

```python
from simplismart import ModelRepoListParams, Simplismart

client = Simplismart()

data = client.list_model_repos(ModelRepoListParams(org_id="<YOUR_ORG_UUID>", count=5))
print(data)

one = client.get_model_repo(model_id="<MODEL_REPO_ID>")
print(one)
```

### Create Container (Bring Your Own Container)

Use this flow when you already have an image in a supported registry.

#### CLI

```bash
simplismart model-repos create-container \
  --name "byom-1" \
  --org-id "$ORG_ID" \
  --source-type "docker_hub" \
  --source-secret "<SECRET_ID>" \
  --registry-path "my-org/my-image" \
  --docker-tag "latest" \
  --runtime-gpus 0
```

#### Python

```python
from simplismart import ModelRepoCreate, Simplismart

client = Simplismart()

resp = client.create_model_repo(
    ModelRepoCreate(
        name="byom-1",
        org_id="<YOUR_ORG_UUID>",
        source_type="docker_hub",
        source_secret="<SECRET_ID>",
        registry_path="my-org/my-image",
        docker_tag="latest",
        runtime_gpus=0,
    )
)

print(resp)
```

### Create Private Compile Model Repo

Use this flow when Simplismart should compile/optimize and package the model.

Notes:
- This method always sends `use_simplismart_infrastructure=true`.
- `org` is optional in payload for compile flow because backend can infer it from PG token.
- You should pass full JSON for `model_config`, `optimisation_config`, and `pipeline_config`.

#### CLI

```bash
simplismart model-repos create-private-compile \
  --name "llama-model" \
  --description "llama-model - A model deployed using Simplismart" \
  --avatar-url "https://ui-avatars.com/api/?background=f3f3f3&color=000000&name=llama-model" \
  --source-type "huggingface" \
  --source-url "meta-llama/Llama-3.2-1B-Instruct" \
  --model-class "LlamaForCausalLM" \
  --accelerator-type "nvidia-h100" \
  --accelerator-count 0 \
  --cloud-account "<CLOUD_ACCOUNT_UUID>" \
  --model-config '{"architectures":["LlamaForCausalLM"],"model_type":"llama","hidden_size":2048}' \
  --optimisation-config '{"model_type":"llm","quantization":"float16","tensor_parallel_size":2}' \
  --pipeline-config '{"type":"llm","mode":"chat","extra_params":{}}'
```

You can also pass JSON via files using the `@path.json` form:

```bash
simplismart model-repos create-private-compile \
  --name "llama-model" \
  --avatar-url "https://ui-avatars.com/api/?background=f3f3f3&color=000000&name=llama-model" \
  --source-type "huggingface" \
  --source-url "meta-llama/Llama-3.2-1B-Instruct" \
  --model-class "LlamaForCausalLM" \
  --accelerator-type "nvidia-h100" \
  --cloud-account "<CLOUD_ACCOUNT_UUID>" \
  --model-config @model_config.json \
  --optimisation-config @optimisation_config.json \
  --pipeline-config @pipeline_config.json
```

#### Python

```python
from simplismart import (
    ModelRepoCompileAvatar,
    ModelRepoCompileCreate,
    Simplismart,
)

client = Simplismart()

resp = client.create_model_repo_private_compile(
    ModelRepoCompileCreate(
        name="llama-model",
        description="llama-model - A model deployed using Simplismart",
        avatar=ModelRepoCompileAvatar(
            image_url="https://ui-avatars.com/api/?background=f3f3f3&color=000000&name=llama-model"
        ),
        source_type="huggingface",
        source_url="meta-llama/Llama-3.2-1B-Instruct",
        model_class="LlamaForCausalLM",
        accelerator_type="nvidia-h100",
        accelerator_count=0,
        cloud_account="<CLOUD_ACCOUNT_UUID>",
        model_config_data={
            "architectures": ["LlamaForCausalLM"],
            "model_type": "llama",
            "hidden_size": 2048,
        },
        optimisation_config={
            "model_type": "llm",
            "quantization": "float16",
            "tensor_parallel_size": 2,
        },
        pipeline_config={
            "type": "llm",
            "mode": "chat",
            "extra_params": {},
        },
    )
)

print(resp)
```

### Delete

```bash
simplismart model-repos delete --model-id "<MODEL_REPO_ID>"
```

## Deployments

### Create Private Deployment

#### CLI

```bash
simplismart deployments create-private --model-repo <MODEL_REPO_ID> --org "$ORG_ID" \
  --gpu-id nvidia-h100 --name my-deploy --min-pod-replicas 1 --max-pod-replicas 2 \
  --autoscale-config '{"targets":[{"metric":"gpu","target":80}]}'

# Update (payload from file)
simplismart deployments update --deployment-id <DEPLOYMENT_ID> --payload @edit-payload.json
```

#### Python

```python
from simplismart import DeploymentCreate, Simplismart

client = Simplismart()

resp = client.create_private_deployment(
    DeploymentCreate(
        model_repo="<MODEL_REPO_ID>",
        org="<YOUR_ORG_UUID>",
        gpu_id="nvidia-h100",
        name="my-deployment",
        min_pod_replicas=1,
        max_pod_replicas=2,
        autoscale_config={"targets": [{"metric": "gpu", "target": 80}]},
    )
)

print(resp)
```

### Common Deployment Commands

```bash
simplismart deployments list --offset 0 --count 20
simplismart deployments get --deployment-id "<DEPLOYMENT_ID>"
simplismart deployments stop --deployment-id "<DEPLOYMENT_ID>"
simplismart deployments start --deployment-id "<DEPLOYMENT_ID>"
simplismart deployments scale --deployment-id "<DEPLOYMENT_ID>" --min-replicas 1 --max-replicas 3
simplismart deployments delete --deployment-id "<DEPLOYMENT_ID>"
```

## Secrets

### Create, List, Get

#### CLI

```bash
simplismart secrets create \
  --org-id "$ORG_ID" \
  --name "dockerhub-secret" \
  --secret-type "docker_hub" \
  --data '{"username":"my-user","token":"my-token"}'

simplismart secrets list --org-id "$ORG_ID"
simplismart secrets get --secret-id "<SECRET_ID>"

# Secret config schema from PG token context
simplismart secrets config
```

#### Python

```python
from simplismart import SecretCreate, Simplismart

client = Simplismart()

resp = client.create_secret(
    SecretCreate(
        org="<YOUR_ORG_UUID>",
        name="dockerhub-secret",
        secret_type="docker_hub",
        data={"username": "my-user", "token": "my-token"},
    )
)

print(resp)
```

## Usage Analytics

Query cost and usage data for the org behind your PG token. Supports six plan types and optional filtering by deployment, training job, or model repo.

### Fetch usage stats

#### CLI

```bash
simplismart usage stats \
  --plan-type private \
  --start-time 2025-02-04T00:00:00+00:00 \
  --end-time   2025-05-05T00:00:00+00:00 \
  --window-size DAY

# Multiple deployments by slug — pass a comma-separated list
simplismart usage stats \
  --plan-type private \
  --start-time 2025-02-04T00:00:00+00:00 \
  --end-time   2025-05-05T00:00:00+00:00 \
  --window-size DAY \
  --deployment-slug my-deploy,another-deploy,yet-another

# Multiple deployments by id (plan-type ∈ private/byoc/reserved)
simplismart usage stats \
  --plan-type private \
  --start-time 2025-02-04T00:00:00+00:00 \
  --end-time   2025-05-05T00:00:00+00:00 \
  --window-size DAY \
  --deployment-id 54360212-2263-44c6-afaf-133354485487,9a8b6c54-7f3e-41a9-9b22-5e7e0bce9f12

# Combine deployment ids and slugs in one call — results are the union
simplismart usage stats \
  --plan-type private \
  --start-time 2025-02-04T00:00:00+00:00 \
  --end-time   2025-05-05T00:00:00+00:00 \
  --window-size DAY \
  --deployment-id   54360212-2263-44c6-afaf-133354485487,9a8b6c54-7f3e-41a9-9b22-5e7e0bce9f12 \
  --deployment-slug my-deploy,another-deploy

# Shared plan filters by model name only (no ids/slugs).
# Shared usage events expose only the model name (e.g. "DeepSeek-R1"),
# not a per-org deployment id, so use --model-name.
simplismart usage stats \
  --plan-type shared \
  --start-time 2025-02-04T00:00:00+00:00 \
  --end-time   2025-05-05T00:00:00+00:00 \
  --window-size DAY \
  --model-name DeepSeek-R1,Llama-3

# Training jobs by name (plan-type=training only)
simplismart usage stats \
  --plan-type training \
  --start-time 2025-02-04T00:00:00+00:00 \
  --end-time   2025-05-05T00:00:00+00:00 \
  --window-size DAY \
  --training-job-name finetune-llama-3,finetune-mistral-7b

# Combine training-job ids and names in one call — results are the union
simplismart usage stats \
  --plan-type training \
  --start-time 2025-02-04T00:00:00+00:00 \
  --end-time   2025-05-05T00:00:00+00:00 \
  --window-size DAY \
  --training-job-id   a1f2c3d4-5678-90ab-cdef-1234567890ab \
  --training-job-name finetune-llama-3,finetune-mistral-7b

# Compiled model repos by id (plan-type=compilation only)
simplismart usage stats \
  --plan-type compilation \
  --start-time 2025-02-04T00:00:00+00:00 \
  --end-time   2025-05-05T00:00:00+00:00 \
  --window-size DAY \
  --model-repo-id 54360212-2263-44c6-afaf-133354485487,9a8b6c54-7f3e-41a9-9b22-5e7e0bce9f12

# Combine model-repo ids and names in one call — results are the union
simplismart usage stats \
  --plan-type compilation \
  --start-time 2025-02-04T00:00:00+00:00 \
  --end-time   2025-05-05T00:00:00+00:00 \
  --window-size DAY \
  --model-repo-id   54360212-2263-44c6-afaf-133354485487 \
  --model-repo-name llama-3-8b-int4,mistral-7b-int8
```

**How filters work:**

- Each filter flag takes a single value or a **comma-separated list** (`a,b,c`). All values must be passed in one invocation.
- Passing the same flag twice (e.g. `--deployment-slug a --deployment-slug b`) is **rejected** with a CLI error — use `--deployment-slug a,b` instead.
- Pick whichever flag fits — id or slug/name. A single flag with N values is the typical case.
- Multiple values combine with **OR (union)**. A record is included if it matches *any* of the supplied values.
- Filters only ever match records visible to your org for the given `plan_type`. Unknown values return a `400` listing exactly which entries didn't resolve.

**Including deleted resources:**

Use `--include-all-statuses` to include deleted resources in your results. By default, deleted items are excluded.

| Plan type | Default (without flag) | With `--include-all-statuses` |
|---|---|---|
| `private` / `byoc` / `reserved` | Active deployments only | All deployments (including deleted) |
| `shared` | Active deployments only | All deployments (including deleted) |
| `compilation` | Successful model repos only | All model repos (including deleted) |
| `training` | Not supported (always rejected) | Not supported (always rejected) |

**Important:** When filtering by specific names or IDs, you must add `--include-all-statuses` if you want to see deleted items. Otherwise, deleted resources won't be found and you'll get a "not found" error.

```bash
# Private plan, including deleted deployments
simplismart usage stats \
  --plan-type private \
  --start-time 2025-02-04T00:00:00+00:00 \
  --end-time   2025-05-05T00:00:00+00:00 \
  --window-size DAY \
  --all-statuses

# Shared plan + specific model (including deleted)
simplismart usage stats \
  --plan-type shared \
  --start-time 2025-02-04T00:00:00+00:00 \
  --end-time   2025-05-05T00:00:00+00:00 \
  --window-size DAY \
  --model-name DeepSeek-R1 \
  --all-statuses

# Multiple deployments by ID
simplismart usage stats \
  --plan-type private \
  --start-time 2025-02-04T00:00:00+00:00 \
  --end-time   2025-05-05T00:00:00+00:00 \
  --window-size DAY \
  --deployment-id uuid1,uuid2,uuid3

# Training plan (doesn't support --all-statuses)
simplismart usage stats \
  --plan-type training \
  --start-time 2025-02-04T00:00:00+00:00 \
  --end-time   2025-05-05T00:00:00+00:00 \
  --window-size DAY
```

```python
# SDK Examples
from simplismart import Simplismart, UsageStatsParams

client = Simplismart()

# Basic usage - private plan
data = client.get_usage_stats(
    UsageStatsParams(
        plan_type="private",
        start_time="2025-02-04T00:00:00+00:00",
        end_time="2025-05-05T00:00:00+00:00",
        window_size="DAY",
    )
)

# Include deleted resources
data = client.get_usage_stats(
    UsageStatsParams(
        plan_type="private",
        start_time="2025-02-04T00:00:00+00:00",
        end_time="2025-05-05T00:00:00+00:00",
        window_size="DAY",
        include_all_statuses=True,
    )
)

# Filter by specific deployments
data = client.get_usage_stats(
    UsageStatsParams(
        plan_type="private",
        start_time="2025-02-04T00:00:00+00:00",
        end_time="2025-05-05T00:00:00+00:00",
        window_size="DAY",
        deployment_ids=["uuid1", "uuid2"],
    )
)

# Training plan (include_all_statuses not supported)
try:
    data = client.get_usage_stats(
        UsageStatsParams(
            plan_type="training",
            start_time="2025-02-04T00:00:00+00:00",
            end_time="2025-05-05T00:00:00+00:00",
            window_size="DAY",
            include_all_statuses=True,  # This will raise ValidationError
        )
    )
except ValueError as e:
    print(f"Error: {e}")
```

#### Python

```python
from simplismart import Simplismart, UsageStatsParams

client = Simplismart()

resp = client.get_usage_stats(
    UsageStatsParams(
        plan_type="private",
        start_time="2025-02-04T00:00:00+00:00",
        end_time="2025-05-05T00:00:00+00:00",
        window_size="DAY",
        deployment_slugs=["my-deploy", "another-deploy"],
    )
)

# Combine ids and slugs — results are the union
resp = client.get_usage_stats(
    UsageStatsParams(
        plan_type="private",
        start_time="2025-02-04T00:00:00+00:00",
        end_time="2025-05-05T00:00:00+00:00",
        window_size="DAY",
        deployment_ids=["54360212-2263-44c6-afaf-133354485487"],
        deployment_slugs=["my-deploy", "another-deploy"],
    )
)

# Training jobs — combine ids and names
resp = client.get_usage_stats(
    UsageStatsParams(
        plan_type="training",
        start_time="2025-02-04T00:00:00+00:00",
        end_time="2025-05-05T00:00:00+00:00",
        window_size="DAY",
        training_job_ids=["a1f2c3d4-5678-90ab-cdef-1234567890ab"],
        training_job_names=["finetune-llama-3"],
    )
)

# Compilation — combine model-repo ids and names
resp = client.get_usage_stats(
    UsageStatsParams(
        plan_type="compilation",
        start_time="2025-02-04T00:00:00+00:00",
        end_time="2025-05-05T00:00:00+00:00",
        window_size="DAY",
        model_repo_ids=["54360212-2263-44c6-afaf-133354485487"],
        model_repo_names=["llama-3-8b-int4"],
    )
)

# Shared — filter by model name only (plan-type=shared)
resp = client.get_usage_stats(
    UsageStatsParams(
        plan_type="shared",
        start_time="2025-02-04T00:00:00+00:00",
        end_time="2025-05-05T00:00:00+00:00",
        window_size="DAY",
        model_names=["DeepSeek-R1", "Llama-3"],
    )
)

print(resp["total_cost"])
for item in resp["items"]:
    print(item["source"], item["total_cost"])
```

`UsageStatsParams` validates filter scope before the request is sent — e.g. passing `training_job_ids` with `plan_type="private"` raises `ValidationError`. Filter values are auto-trimmed and de-duplicated.

## CLI Reference

### Global Options

| Option | Description |
|---|---|
| `--pg-token` | Override `SIMPLISMART_PG_TOKEN` |
| `--base-url` | Override `SIMPLISMART_BASE_URL` |
| `--timeout` | Optional request timeout in seconds |
| `--trace-id` | Optional trace/correlation ID (auto-generated if omitted) |

### Command Groups

| Group | Purpose |
|---|---|
| `model-repos` | List/get/create/delete model repositories |
| `deployments` | Create/update/list/manage deployments |
| `secrets` | Create/list/get secrets and list secret config schemas |
| `usage` | Fetch usage analytics; supports per-deployment / training-job / model-repo filters |

Use:

```bash
simplismart <group> --help
simplismart <group> <command> --help
```

## Python API Reference

| Area | Methods |
|---|---|
| Model repos | `list_model_repos`, `get_model_repo`, `create_model_repo`, `create_model_repo_private_compile`, `get_model_repo_profiles`, `delete_model_repo` |
| Deployments | `create_private_deployment`, `create_deployment` (alias), `list_deployments`, `list_model_deployments`, `create_byoc_deployment`, `get_model_deployment`, `get_deployment` (alias), `update_deployment`, `stop_deployment`, `start_deployment`, `restart_deployment`, `fetch_deployment_health`, `update_deployment_autoscaling`, `delete_deployment`, `delete_model_deployment` (alias) |
| Secrets | `create_secret`, `list_secrets`, `get_secret`, `list_secret_configs` |
| Usage | `get_usage_stats` |

Exported request models:
- `ModelRepoListParams`
- `ModelRepoCreate`
- `ModelRepoCompileCreate`
- `ModelRepoCompileAvatar`
- `ModelRepoProfilesRequest`
- `DeploymentCreate`
- `SecretCreate`
- `UsageStatsParams`

## Error Handling

The SDK raises `SimplismartError` for non-2xx responses.

```python
from simplismart import Simplismart, SimplismartError

client = Simplismart()

try:
    client.get_model_repo("<MODEL_REPO_ID>")
except SimplismartError as exc:
    print(exc.message)
    print(exc.status_code)
    print(exc.payload)
```

CLI errors are printed as JSON.

## Security Notes

- Do not hardcode tokens or cloud credentials in source code.
- Use environment variables or a secret manager in CI/CD.
- Rotate credentials immediately if exposed.

## Troubleshooting

- **Missing or invalid token:** Ensure `SIMPLISMART_PG_TOKEN` is set (or pass `pg_token` to `Simplismart(...)`). Get your Playground token from the Simplismart dashboard.
- **Wrong base URL:** Use `https://api.app.simplismart.ai` (no trailing slash) unless you have a custom endpoint.
- **4xx/5xx errors:** Check `SimplismartError.status_code` and `SimplismartError.payload` for details; refer to the API docs for required fields.

## License

Proprietary. See your Simplismart agreement for terms.
