Metadata-Version: 2.4
Name: seacloudai-sdk
Version: 0.1.3
Summary: Python SDK for SeaCloud AI generation APIs.
Project-URL: Homepage, https://github.com/SeaCloudAI/seacloud-sdk#readme
Project-URL: Repository, https://github.com/SeaCloudAI/seacloud-sdk
Project-URL: Issues, https://github.com/SeaCloudAI/seacloud-sdk/issues
Author: SeaCloudAI
License-Expression: MIT
Keywords: ai,generation,python,sdk,seacloud
Requires-Python: >=3.10
Requires-Dist: httpx<1,>=0.27
Requires-Dist: typing-extensions>=4.6
Provides-Extra: dev
Requires-Dist: build>=1.2; extra == 'dev'
Requires-Dist: mypy>=1.10; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest>=8.2; extra == 'dev'
Requires-Dist: ruff>=0.5; extra == 'dev'
Requires-Dist: twine>=5; extra == 'dev'
Description-Content-Type: text/markdown

# seacloudai-sdk

English | [简体中文](README.zh-CN.md)

Python SDK for SeaCloud AI generation APIs.

SeaCloud SDK is a multimodal task execution SDK designed for agents and developers. With one SeaCloud API key, it provides LLM chat through `chat.send` and image, video, audio, 3D, and other queue generation through `run` / `run_sync`; supports model search, contract queries, task execution, and result tracking; and helps discover and manage professional skills for creative workflows through SkillHub.

Chinese operation manual: [`docs/SDK_OPERATION_MANUAL.zh-CN.md`](docs/SDK_OPERATION_MANUAL.zh-CN.md).

If you are new to Python, start with [`docs/PYTHON_LEARNING_NOTES.zh-CN.md`](docs/PYTHON_LEARNING_NOTES.zh-CN.md). It explains the Python syntax and code flow used in this project file by file.

## Install

```bash
pip install seacloudai-sdk
```

For local development in this repository:

```bash
python -m venv .venv
.venv/bin/python -m pip install -e '.[dev]'
```

## Server-Side Usage

Use this SDK from trusted server-side Python code. Do not put the API key in browser code. For browser apps, call your own backend route and let that route use `seacloudai-sdk`.

```python
import os
from seacloud_sdk import SeaCloud, getSeaCloudDocs, isSeaCloudError

docs = getSeaCloudDocs()
print(docs["quickStart"]["content"])

client = SeaCloud(api_key=os.environ["SEACLOUD_API_KEY"])

try:
    result = await client.run_sync("gpt_image_2", {
        "prompt": "Generate cute cats programming",
        "n": 1,
        "size": "1024x1024",
        "output_format": "png",
        "quality": "auto",
        "moderation": "auto",
    })
    print(result.get("output", {}).get("urls"))
except Exception as error:
    if isSeaCloudError(error):
        print(error.type, str(error), error.hint)
```

## Overview

`seacloudai-sdk` is a pure code SDK. It exposes typed Python methods, returns data objects, and never reads `apiKey` from environment variables by itself. Callers must pass `api_key` or the compatible `apiKey` parameter explicitly.

## Service Endpoints and Environment Overrides

The SDK ships with production service endpoints, so application code can create a client with only an explicit `api_key`. Runtime service endpoints are generated from `.env.prod` into `src/seacloud_sdk/core/default_base_urls.py`; API keys are never read from env by the SDK.

Maintainers who need local-only endpoints can create an ignored `.env.local` file with the same keys and run:

```bash
python scripts/generate_base_urls.py .env.local
```

`.env.local` is intentionally not tracked and must not be pushed.

## Quick Start

```python
from seacloud_sdk import SeaCloud, getSeaCloudDocs

docs = getSeaCloudDocs()
print([method["name"] for method in docs["methods"]])

client = SeaCloud(api_key="sk-...", timeout=600_000)

text = await client.chat.send("gpt-5.5", [
    {"role": "user", "content": "Hello"},
])

task = await client.run("gpt_image_2", {
    "prompt": "Generate cute cats programming",
    "n": 1,
    "size": "1024x1024",
    "output_format": "png",
    "quality": "auto",
    "moderation": "auto",
})

print(task["id"], task.get("statusUrl"), task.get("responseUrl"))

result = await client.run_sync("gpt_image_2", {
    "prompt": "Generate cute cats programming",
    "n": 1,
    "size": "1024x1024",
    "output_format": "png",
    "quality": "auto",
    "moderation": "auto",
})

print(result.get("output", {}).get("urls", [None])[0])
```

## API Overview

| Module | Method | Purpose |
| --- | --- | --- |
| Docs | `getSeaCloudDocs()` | Read the offline SDK operation manual and agent / skill usage guide |
| Client | `SeaCloud(options)` / `SeaCloud(api_key=...)` | Create a client with an explicit `apiKey` |
| Chat | `client.chat.send(model, messages, options)` | Send a text chat request |
| Generation | `client.run(model_id, params, options)` | Create a contract-aware queue task and return a task handle immediately |
| Generation | `client.run_sync(model_id, params, options)` | Create a contract-aware queue task and wait for the final response |
| Models | `client.models.list(options)` | List available models |
| Models | `client.models.get_spec(model_id)` | Read the model contract used for generation planning |
| Tasks | `client.tasks.get(task_id, {"endpoint": model_id})` | Read queue task status |
| Tasks | `client.tasks.get_response(task_id, {"responseUrl": url})` | Read the final queue task response |
| Skills | `client.skills.find(query, options)` | Search SkillHub skills |
| Skills | `client.skills.list(options)` | List SkillHub skills |
| Version | `client.version()` | Read the SDK version |

## Client Options

```python
client = SeaCloud(
    api_key="sk-...",
    timeout=600_000,
    fetch=my_async_fetch,
)
```

`api_key` is required and has no default value. The SDK also accepts `apiKey` as an equivalent parameter for compatibility with camelCase call conventions. `timeout` can be set at the client level or overridden for a single method call. `fetch` is optional and is useful for proxies, tests, or special runtimes.

## Offline Docs

`getSeaCloudDocs()` does not initialize a client, does not require `apiKey`, and does not make network requests. It is suitable for agents, LLM tool calls, and test pages that need to inspect public SDK usage.

```python
docs = getSeaCloudDocs()
zh_docs = getSeaCloudDocs({"locale": "zh-CN"})

print(docs["operationManual"]["content"])
print(docs["agentSkillUsage"]["content"])
print([method["name"] for method in docs["methods"]])
```

## Generation Parameters

Generation methods use fixed syntax:

```python
client.run(model_id, params, options)
client.run_sync(model_id, params, options)
client.runSync(model_id, params, options)  # compatibility alias
```

- `model_id` is the first positional argument. By default, the SDK reads the model contract, resolves the queue submit endpoint, and falls back to `/model/v1/queue/{model_id}` when the contract is unavailable in auto mode.
- `params` is the second positional argument and must be a dict. The SDK sends Python dicts as queue JSON; string flag syntax is not accepted.
- `options["timeout"]` overrides the timeout for this request or synchronous wait.
- `options["dryRun"]` or the `dry_run=True` keyword plans and previews the request without submitting a task, polling, or reading the final response.
- `options["contract"]` is optional and defaults to `"auto"`. `"auto"` tries to read the contract and can fall back to raw queue passthrough. `"strict"` requires the contract to be readable and plannable. `"off"` explicitly disables contract reads and submits `params` as raw queue JSON.
- There is no `onProgress`. The current backend lifecycle APIs do not provide trustworthy progress, so the SDK does not invent progress events.

By default, `run` and `run_sync` read the model contract to resolve protocol, body mode, queue submit endpoint, and contract headers. If `input_schema.required` is a non-empty array, the SDK only checks that those top-level required fields are present before submitting. It does not validate types, formats, ranges, defaults, or mutual-exclusion rules; those model-specific rules are handled by the API. If the contract cannot be read in `"auto"` mode, the SDK falls back to raw JSON submission at `/model/v1/queue/{model_id}`. The SDK accepts Python dict objects, does not accept shell-style parameter strings, and does not auto-upload local files.

Contract-aware generation flow:

| Step | SDK behavior |
| --- | --- |
| 1 | `client.models.get_spec(model_id)`, `client.run()`, and `client.run_sync()` read `GET https://sea-cloud-admin-web.real-cloud.seaart.ai/api/v1/skill/model-contracts/{modelId}` when contract mode is enabled. |
| 2 | If `input_schema.required` is non-empty, the SDK only checks that those top-level required fields are present; otherwise it does not block. |
| 3 | For `protocol=queue` and `body_mode=raw_json`, the SDK resolves `spec.endpoints.submit.path` against the queue base URL and submits the caller-provided JSON body. |
| 4 | `client.run_sync()` polls `statusUrl` and reads `responseUrl`; `client.run()` returns the task handle for manual `tasks.get()` / `tasks.get_response()`. |

```mermaid
flowchart TD
  User["User calls run/run_sync"] --> ValidateInput["Validate model_id and params dict"]
  ValidateInput --> ContractMode{"Use contract mode?"}
  ContractMode -- default auto/strict --> ReadContract["Read model contract"]
  ContractMode -- off --> PlanRaw["Use raw queue request"]
  ReadContract --> PlanContract["Plan protocol, bodyMode, queue endpoint, headers"]
  ReadContract -- auto unavailable --> PlanRaw
  PlanRaw --> DryRun{"dryRun / dry_run?"}
  PlanContract --> DryRun
  DryRun -- yes --> Preview["Return planned request preview"]
  DryRun -- no --> Submit["POST queue submit request"]
  Submit --> Task["Return task handle"]
  Task --> Sync{"run_sync?"}
  Sync -- no --> Done["Caller polls manually with tasks.get/get_response"]
  Sync -- yes --> Poll["Poll statusUrl"]
  Poll --> Response["GET responseUrl"]
  Response --> Result["Return normalized RunSyncResult"]
```

## run: Create an Async Task

`run` reads the model contract in default contract mode, then submits the planned queue request:

```text
POST https://cloud.seaart.ai/model/v1/queue/{modelId}
```

```python
task = await client.run("gpt_image_2", {
    "prompt": "Generate cute cats programming",
    "n": 1,
    "size": "1024x1024",
    "output_format": "png",
    "quality": "auto",
    "moderation": "auto",
})
```

Task handle:

```python
{
    "id": "mmsu_...",
    "status": "queued",
    "model": "gpt_image_2",
    "statusUrl": "...",
    "responseUrl": "...",
    "cancelUrl": "...",
    "queuePosition": 0,
}
```

Async mode does not return `output`, because the final generation result does not exist when the task is created.

## run_sync: Wait for Final Result

`run_sync` creates a task, polls `statusUrl`, requests `responseUrl` after completion, and wraps the real response in a stable structure.

```python
result = await client.run_sync("gpt_image_2", {
    "prompt": "Generate cute cats programming",
    "n": 1,
    "size": "1024x1024",
    "output_format": "png",
    "quality": "auto",
    "moderation": "auto",
})
```

Return shape:

```python
{
    "id": "mmsu_...",
    "status": "completed",
    "model": "gpt_image_2",
    "output": {
        "urls": ["https://..."],
        "raw": {"request_id": "mmsu_..."},
    },
}
```

Mapping rules:

- `id`: prefers `request_id`, then `id`, then the task creation ID.
- `status`: success states normalize to `completed`; failed states normalize to `failed`.
- `output.urls`: recursively extracts all `url` fields from the real response.
- `output.raw`: keeps the real response so model-specific fields are not lost.
- `error`: maps task failures from the real response. Failed results do not invent `output`.

## dry_run

```python
preview = await client.run("gpt_image_2", {
    "prompt": "a cinematic photo of a cat astronaut",
    "n": 1,
}, {"dryRun": True})

preview = await client.run("gpt_image_2", {"prompt": "cat"}, dry_run=True)
```

`dry_run` returns `modelId`, `protocol`, `bodyMode`, endpoint, method, redacted headers, the planned request body, and `validation`, but it does not submit a generation task. With contract mode on, it may read the model contract and only checks `input_schema.required` top-level fields locally.

## Manual Task Lookup After run

```python
status = await client.tasks.get(task["id"], {
    "endpoint": "gpt_image_2",
    "statusUrl": task.get("statusUrl"),
})

result = await client.tasks.get_response(task["id"], {
    "endpoint": "gpt_image_2",
    "responseUrl": status.get("responseUrl") or task.get("responseUrl"),
})
```

`get_response` returns the same structure as `run_sync`: successful results include `output.urls` and `output.raw`; failed results include `error` and do not invent `output`.

## Service Endpoints

| Capability | Endpoint |
| --- | --- |
| Chat | `POST https://cloud.seaart.ai/llm/chat/completions` |
| Model list | `GET https://sea-cloud-admin-web.real-cloud.seaart.ai/api/v1/skill/models` |
| Queue submit | `POST https://cloud.seaart.ai/model/v1/queue/{modelId}` |
| Queue status | `GET https://cloud.seaart.ai/model/v1/queue/{modelId}/requests/{request_id}/status` |
| Queue response | `GET https://cloud.seaart.ai/model/v1/queue/{modelId}/requests/{request_id}/response` |
| Model contract | `GET https://sea-cloud-admin-web.real-cloud.seaart.ai/api/v1/skill/model-contracts/{modelId}` |
| SkillHub search | `GET https://skill-hub.vtrix.ai/api/v1/search` |
| SkillHub list | `GET https://skill-hub.vtrix.ai/api/v1/skills` |

## Naming Compatibility

Python code should prefer snake_case: `run_sync`, `models.get_spec`, `tasks.get_response`, `api_key`, and `dry_run`. The SDK also keeps camelCase compatibility aliases: `runSync`, `models.getSpec`, `tasks.getResponse`, `apiKey`, and `dryRun`. Returned data uses the public protocol's camelCase fields, such as `statusUrl`, `responseUrl`, `queuePosition`, `pageSize`, and `totalPages`.

## Development

```bash
.venv/bin/python -m pip install -e '.[dev]'
.venv/bin/python -m pytest
.venv/bin/ruff check .
.venv/bin/mypy src
```

## Architecture

```text
src/seacloud_sdk/
  client.py              SeaCloud facade and resource assembly
  __init__.py            Public exports
  core/                  Runtime config, HTTP client, errors, version
  domain/                Model aliases, response mapping, task result normalization
  resources/             One aggregate resource class per SDK capability
  types/                 Public typed contracts grouped by capability
  utils/                 Small shared objects and URL helpers
skills/                  Project-local agent skills for SDK usage
```
