Metadata-Version: 2.4
Name: wlt-platform
Version: 0.1.2
Summary: Official Python SDK for the WLT (White Label Token) Console API
Project-URL: Homepage, https://github.com/wlt/wlt-python
Project-URL: Documentation, https://docs.wlt.com/sdk/python
Project-URL: Repository, https://github.com/wlt/wlt-python
Author-email: WLT <sdk@wlt.com>
License-Expression: Apache-2.0
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Typing :: Typed
Requires-Python: >=3.8
Requires-Dist: click>=8.0
Requires-Dist: httpx>=0.25.0
Requires-Dist: pydantic>=2.0
Description-Content-Type: text/markdown

# WLT Python SDK

Official Python client library for the [WLT Console API](https://daily.sssxuntui.com).

- **Python**: 3.8+
- **Dependencies**: [httpx](https://www.python-httpx.org/) >= 0.25, [pydantic](https://docs.pydantic.dev/) v2

## Installation

```bash
pip install wlt-platform
```

## Quick Start

```python
from wlt import WltClient

# Initialize the client with your API Key (obtain from Console > Secret Management)
client = WltClient(api_key="sk-your-api-key")

# Authentication is automatic:
#   1. SDK calls loginByApiKey to exchange api_key for a Bearer token
#   2. Token is cached and sent with every request
#   3. On token expiry (code 3001), SDK refreshes automatically

# Example: list secrets
result = client.secrets.list()
print(result.data)

# Always close the client when done
client.close()
```

### Context Manager

```python
from wlt import WltClient

with WltClient(api_key="sk-your-api-key") as client:
    result = client.secrets.list()
    print(result.data)
# client is automatically closed
```

### Async Usage

```python
import asyncio
from wlt import AsyncWltClient

async def main():
    async with AsyncWltClient(api_key="sk-your-api-key") as client:
        result = await client.secrets.list()
        print(result.data)

asyncio.run(main())
```

> All synchronous examples below have identical async equivalents -- just use
> `AsyncWltClient` and `await` each method call.

## Configuration

```python
client = WltClient(
    api_key="sk-your-api-key",              # Required. Auto-exchanged for Bearer token
    timeout=30.0,                            # Request timeout in seconds (default: 30)
    max_retries=2,                           # Max retry attempts (default: 2)
)
```

---

## Base URL 配置

默认 Base URL：`https://daily.sssxuntui.com`，零配置即可使用。如需对接私有部署、staging、海外节点，可通过以下任一方式覆盖：

### 三种配置方式

1) **显式构造参数**（最高优先级）

```python
from wlt_platform import WltClient

client = WltClient(
    api_key="sk-your-api-key",
    base_url="https://your.host",
)
```

2) **环境变量**

```bash
export WLT_BASE_URL=https://your.host
```

3) **CLI 配置文件** `~/.wlt/config.json` 中的 `base_url` 字段（仅 Python / Node.js CLI 用户）

```bash
wlt config set base_url https://your.host
```

### 优先级

| 优先级 | 来源 |
|---|---|
| 1（最高）| 显式构造参数 / CLI `--base-url` flag |
| 2 | 环境变量 `WLT_BASE_URL` |
| 3 | `~/.wlt/config.json` 中的 `base_url` |
| 4（最低）| 默认值 `https://daily.sssxuntui.com` |

### 使用场景

- 私有化部署：指向客户自建网关
- Staging 测试：开发期切到测试环境
- 海外节点：按地域选择就近接入点

---

## Module Reference

| Module | Accessor | Description |
|--------|----------|-------------|
| **Auth** | `client.auth` | Tenant info |
| **Secret** | `client.secrets` | Secret CRUD, usage stats, model/provider queries |
| **ApiKey** | `client.api_keys` | BYOK API key CRUD, status, connectivity test, providers |
| **Usage** | `client.usage` | Serverless usage summary/list/charts/stats, call history, gateway providers |
| **UserInfo** | `client.user` | Current user info |
| **Billing** | `client.billing` | Monthly billing queries by GPU, AI service, or detail line items |
| **Payment** | `client.payment` | Recharge records, statistics, model usage billing |
| **Model Gallery** | `client.model_gallery` | Model page, detail, providers, prices |
| **Model Lab** | `client.model_lab` | Model list, stream inference, session, parameters, code samples |

---

## Auth

### `client.auth.tenant_info()`

Get the current user's tenant information.

#### Parameters

None.

#### Response

Returns `BaseResponse[PartnerResponse]`.

**PartnerResponse fields:**

| Field | Type | Description |
|-------|------|-------------|
| id | int | Tenant ID |
| gmtCreate | datetime | Creation time |
| gmtModified | datetime | Modification time |
| userId | int | Associated user ID |
| name | str | Tenant name |
| logo | str | Tenant logo URL |
| status | str | Tenant status |
| extend | Any | Extension info |
| url | str | Tenant URL |

```python
from wlt import WltClient

client = WltClient(api_key="sk-your-api-key")

tenant = client.auth.tenant_info()
if tenant.data:
    print(tenant.data.tenantName)
    print(tenant.data.tenantId)
else:
    print("User does not belong to a tenant")
```

---

## Secret

### `client.secrets.list()`

List secrets with pagination and optional filters.

#### Parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| page_num | int | No | 1 | Page number, starting from 1 |
| page_size | int | No | 10 | Items per page |
| status | int | No | None | Status filter: 1=active, 0=disabled |
| expired_before_utc | datetime | No | None | Expiry time upper bound (UTC), filter secrets expiring before this time |

#### Response

Returns `BaseResponse[SecretPageResultVO]`.

**SecretPageResultVO fields:**

| Field | Type | Description |
|-------|------|-------------|
| totalKeys | int | Total number of secrets |
| activeKeys | int | Number of active secrets |
| totalRequest | int | Total request count |
| avgQps | float | Average QPS |
| pageInfo | PageInfo[SecretVO] | Paginated secret data |

**PageInfo fields:**

| Field | Type | Description |
|-------|------|-------------|
| total | int | Total record count |
| totalPages | int | Total number of pages |
| currentPage | int | Current page number |
| pageSize | int | Items per page |
| list | list[SecretVO] | Data list |

**SecretVO fields:**

| Field | Type | Description |
|-------|------|-------------|
| id | int | Secret ID |
| name | str | Secret name |
| keyId | str | Key identifier |
| status | str | Status |
| createdAt | datetime | Creation time |
| lastUsed | datetime | Last used time |
| expiredFlag | bool | Whether expired |
| allowedModels | list[str] | Allowed model list |
| allowedProviders | list[str] | Allowed provider list |
| ipWhiteList | list[str] | IP whitelist |
| minuteTokensQuota | int | Per-minute token quota |
| annualTokensQuota | int | Annual token quota |
| description | str | Description |
| expiredAtUtc | datetime | Expiry time (UTC) |
| byokList | list[ApikeyVO] | Associated BYOK key list |
| defaultSecret | int | Whether default secret: 1=yes, 0=no |
| createUser | str | Creator |

```python
from wlt import WltClient

client = WltClient(api_key="sk-your-api-key")

# Basic listing
result = client.secrets.list()
print(f"Total secrets: {result.data.totalCount}")
for secret in result.data.pageInfo.list:
    print(secret.id, secret.name, secret.status)

# With filters
result = client.secrets.list(page_num=1, page_size=5, status=1)
```

### `client.secrets.detail()`

Get a single secret's details by ID.

#### Parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| id | int | Yes | -- | Secret ID |

#### Response

Returns `BaseResponse[SecretVO]`.

> SecretVO fields: see `client.secrets.list()` above.

```python
from wlt import WltClient

client = WltClient(api_key="sk-your-api-key")

detail = client.secrets.detail(id=123)
print(detail.data.name)
print(detail.data.allowedModels)
print(detail.data.allowedProviders)
```

### `client.secrets.create()`

Create a new secret. Returns the generated API key string.

#### Parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| name | str | No | None | Secret name |
| allowed_models | list[str] | No | None | List of allowed model names |
| allowed_providers | list[str] | No | None | List of allowed provider names |
| ip_white_list | list[str] | No | None | IP whitelist (CIDR notation) |
| minute_tokens_quota | int | No | None | Per-minute token quota |
| annual_tokens_quota | int | No | None | Annual token quota |
| expired_at_utc | datetime | No | None | Expiry time in UTC |
| byok_ids | list[int] | No | None | List of BYOK key IDs to associate |

#### Response

Returns `BaseResponse[str]`. The `data` field contains the generated API key string.

```python
from wlt import WltClient
from datetime import datetime, timezone, timedelta

client = WltClient(api_key="sk-your-api-key")

# Minimal creation
result = client.secrets.create(name="my-secret")
print(f"New API key: {result.data}")

# Full creation with all options
result = client.secrets.create(
    name="production-key",
    allowed_models=["qwen-turbo", "qwen-plus"],
    allowed_providers=["dashscope"],
    ip_white_list=["10.0.0.0/8"],
    minute_tokens_quota=100000,
    annual_tokens_quota=50000000,
    expired_at_utc=datetime(2027, 1, 1, tzinfo=timezone.utc),
    byok_ids=[1, 2],
)
print(f"New API key: {result.data}")
```

### `client.secrets.edit()`

Edit an existing secret.

#### Parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| id | int | Yes | -- | Secret ID |
| name | str | No | None | Updated name |
| allowed_models | list[str] | No | None | Updated allowed model list |
| allowed_providers | list[str] | No | None | Updated allowed provider list |
| ip_white_list | list[str] | No | None | Updated IP whitelist |
| minute_tokens_quota | int | No | None | Updated per-minute token quota |
| annual_tokens_quota | int | No | None | Updated annual token quota |
| expired_at_utc | datetime | No | None | Updated expiry time (UTC) |
| byok_ids | list[int] | No | None | Updated BYOK key IDs |

#### Response

Returns `BaseResponse[bool]`. `data=True` on success.

```python
from wlt import WltClient

client = WltClient(api_key="sk-your-api-key")

result = client.secrets.edit(
    id=123,
    name="updated-secret-name",
    allowed_models=["qwen-turbo", "qwen-max"],
    minute_tokens_quota=200000,
)
print(f"Success: {result.data}")  # True
```

### `client.secrets.action()`

Perform an action on a secret: `"ENABLE"`, `"DISABLE"`, or `"DELETE"`.

#### Parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| id | int | Yes | -- | Secret ID |
| status | str | Yes | -- | Action: `"ENABLE"`, `"DISABLE"`, or `"DELETE"` |

#### Response

Returns `BaseResponse[bool]`. `data=True` on success.

```python
from wlt import WltClient

client = WltClient(api_key="sk-your-api-key")

# Disable a secret
result = client.secrets.action(id=123, status="DISABLE")
print(f"Success: {result.data}")  # True

# Enable a secret
result = client.secrets.action(id=123, status="ENABLE")

# Delete a secret
result = client.secrets.action(id=123, status="DELETE")

# Convenience wrappers are also available:
client.secrets.enable(id=123)
client.secrets.disable(id=123)
client.secrets.delete(id=123)
```

### `client.secrets.get_usage_data()`

Get usage statistics for a specific secret.

#### Parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| id | int | Yes | -- | Secret ID |

#### Response

Returns `BaseResponse[SecretUsageDataVO]`.

**SecretUsageDataVO fields:**

| Field | Type | Description |
|-------|------|-------------|
| totalAPICalls | int | Total API call count |
| totalTokens | int | Total token consumption |
| promptTokens | int | Prompt token count |
| completionTokens | int | Completion token count |

```python
from wlt import WltClient

client = WltClient(api_key="sk-your-api-key")

usage = client.secrets.get_usage_data(id=123)
print(f"API calls: {usage.data.apiCalls}")
print(f"Total tokens: {usage.data.totalTokens}")
```

### `client.secrets.usage_by_model()`

Query secret usage breakdown by model with pagination.

#### Parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| secret_id | int | Yes | -- | Secret ID |
| start_time | datetime | No | None | Query start time |
| end_time | datetime | No | None | Query end time |
| page_num | int | No | 1 | Page number |
| page_size | int | No | 10 | Items per page |

#### Response

Returns `BaseResponse[PageInfo[SecretModelUsageVO]]`.

**SecretModelUsageVO fields:**

| Field | Type | Description |
|-------|------|-------------|
| model | str | Model name |
| requests | int | Request count |
| totalTokens | int | Total token consumption |
| promptTokens | int | Prompt token count |
| completionTokens | int | Completion token count |

```python
from wlt import WltClient
from datetime import datetime

client = WltClient(api_key="sk-your-api-key")

result = client.secrets.usage_by_model(
    secret_id=123,
    start_time=datetime(2026, 4, 1),
    end_time=datetime(2026, 4, 21),
    page_num=1,
    page_size=10,
)
for item in result.data.list:
    print(item.modelName, item.inputTokens, item.outputTokens)
```

### `client.secrets.model_list()`

Query available models for secret binding.

#### Parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| model_name | str | No | None | Model name (fuzzy search) |
| provider | str | No | None | Provider identifier |
| series_provider | str | No | None | Series provider identifier |
| model_type | str | No | None | Model type |
| view_all_flag | int | No | None | View all flag (1=view all) |
| page_size | int | No | None | Items per page |
| page_num | int | No | None | Page number |
| usage_type | str | No | None | Usage type: `"inference"` or `"train"` |
| training_method | str | No | None | Training method: `"sft"` or `"dpo"` |
| tags | list[str] | No | None | Tag filter list, e.g. `["New"]` |
| capability | str | No | None | Capability filter, e.g. `"text_to_text"` |
| model_type_list | list[str] | No | None | Model type list (multi-select) |
| origin_providers | list[str] | No | None | Origin provider list (multi-select) |
| inputs | list[str] | No | None | Input type list, e.g. `["text"]` |
| outputs | list[str] | No | None | Output type list, e.g. `["image"]` |

#### Response

Returns `BaseResponse[list[ModelInfoVO]]`.

**ModelInfoVO fields:**

| Field | Type | Description |
|-------|------|-------------|
| modelId | str | Model ID |
| modelName | str | Model name |
| modelImage | str | Model icon URL |
| isNew | int | Whether new model (1=yes) |
| provider | str | Provider identifier |
| providerName | str | Provider display name |
| originProvider | str | Origin provider identifier |
| seriesProvider | str | Series provider identifier |
| modelType | str | Model type |
| tags | list[str] | Tag list |
| modelSize | str | Model size |
| feature | str | Feature description |
| price | Decimal | Price |
| unit | str | Price unit |
| available | bool | Whether available |
| updated | datetime | Update time |
| deployPlatform | str | Deploy platform |
| regionId | str | Region ID |
| deployFrameworks | list[str] | Deploy framework list |
| labels | list[str] | Label list |
| capabilities | list[str] | Capability list (e.g. `text_to_text`) |
| inputs | list[str] | Input type set |
| outputs | list[str] | Output type set |
| priceExtend | PartnerApiPriceExtend | Extended price info |
| dataSource | str | Data source (`model_card` or `model_router`) |

```python
from wlt import WltClient

client = WltClient(api_key="sk-your-api-key")

# List all inference models
models = client.secrets.model_list(usage_type="inference")
for m in models.data:
    print(m.modelName, m.provider)

# Filter by provider
models = client.secrets.model_list(
    provider="dashscope",
    model_name="qwen",
    tags=["New"],
)
for m in models.data:
    print(m.modelName)
```

### `client.secrets.provider_list()`

Get the list of providers available for secrets.

#### Parameters

None.

#### Response

Returns `BaseResponse[list[ProviderVO]]`.

**ProviderVO fields:**

| Field | Type | Description |
|-------|------|-------------|
| id | str | Provider identifier |
| name | str | Provider display name |

```python
from wlt import WltClient

client = WltClient(api_key="sk-your-api-key")

providers = client.secrets.provider_list()
for p in providers.data:
    print(p.provider, p.providerName)
```

---

## ApiKey (BYOK)

### `client.api_keys.list()`

List API keys with pagination and optional filters.

#### Parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| page_num | int | No | 1 | Page number, starting from 1 |
| page_size | int | No | 10 | Items per page |
| provider | str | No | None | Filter by provider |
| timezone | str | No | None | Timezone for time field localization, e.g. `"Asia/Shanghai"` |

#### Response

Returns `BaseResponse[ApiKeyResultVO]`.

**ApiKeyResultVO fields:**

| Field | Type | Description |
|-------|------|-------------|
| totalApiCalls | int | Total API call count |
| activeKeys | int | Number of active keys |
| apiKeys | PageInfo[ApikeyVO] | Paginated API key data |

**ApikeyVO fields:**

| Field | Type | Description |
|-------|------|-------------|
| id | str | ApiKey ID |
| name | str | Key name |
| key | str | Key content (masked) |
| provider | str | Provider name |
| providerId | str | Provider ID |
| account | str | Account info |
| accountId | str | Account ID |
| projectID | str | Project ID |
| created | datetime | Creation time |
| lastUsedAt | datetime | Last used time |
| status | str | Status |
| accessKeyID | str | AccessKey ID (masked) |
| accessKeySecret | str | AccessKey Secret (masked) |
| resaleStatus | str | Resale status |

```python
from wlt import WltClient

client = WltClient(api_key="sk-your-api-key")

result = client.api_keys.list(page_num=1, page_size=10)
for key in result.data.pageInfo.list:
    print(key.id, key.keyName, key.provider, key.status)

# Filter by provider
result = client.api_keys.list(provider="dashscope")
```

### `client.api_keys.create()`

Create a new BYOK API key.

#### Parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| provider | str | Yes | -- | Provider name (must be a valid BYOK provider) |
| key_name | str | No | None | Key name |
| access_key_id | str | No | None | AccessKey ID |
| access_key_secret | str | No | None | AccessKey Secret |
| tpm_limit | str | No | None | TPM (tokens per minute) limit |
| token_limit | str | No | None | Total token limit |

#### Response

Returns `BaseResponse[ApikeyVO]`. The `data` field contains the newly created API key info.

> ApikeyVO fields: see `client.api_keys.list()` above.

```python
from wlt import WltClient

client = WltClient(api_key="sk-your-api-key")

new_key = client.api_keys.create(
    provider="dashscope",
    key_name="my-dashscope-key",
    access_key_id="LTAI5t...",
    access_key_secret="your-access-key-secret",
    tpm_limit="100000",
    token_limit="5000000",
)
print(f"Created key ID: {new_key.data.id}")
print(f"Key name: {new_key.data.keyName}")
```

### `client.api_keys.update()`

Update an existing API key.

#### Parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| path_id | str | Yes | -- | ApiKey ID (URL path parameter, for routing) |
| id | int | No | None | ApiKey database primary key (used for locating the record) |
| provider | str | No | None | Provider (must be a valid BYOK provider if provided) |
| key_name | str | No | None | Key name |
| aliyun_account_id | str | No | None | Aliyun account ID |
| status | int | No | None | Status |
| access_key_id | str | No | None | AccessKey ID |
| access_key_secret | str | No | None | AccessKey Secret |
| resale_status | str | No | None | Resale status |
| tpm_limit | str | No | None | TPM limit |
| token_limit | str | No | None | Total token limit |

#### Response

Returns `BaseResponse[bool]`. `data=True` on success.

```python
from wlt import WltClient

client = WltClient(api_key="sk-your-api-key")

result = client.api_keys.update(
    path_id="456",
    id=456,
    key_name="renamed-key",
    tpm_limit="200000",
)
print(f"Success: {result.data}")  # True
```

### `client.api_keys.delete()`

Delete an API key.

#### Parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| id | str | Yes | -- | ApiKey ID |

#### Response

Returns `BaseResponse[bool]`. `data=True` on success.

```python
from wlt import WltClient

client = WltClient(api_key="sk-your-api-key")

result = client.api_keys.delete(id="456")
print(f"Success: {result.data}")  # True
```

### `client.api_keys.change_status()`

Enable or disable an API key.

#### Parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| id | str | Yes | -- | ApiKey ID |
| status | int | Yes | -- | Target status: 1=enable, 0=disable |

#### Response

Returns `BaseResponse[bool]`. `data=True` on success.

```python
from wlt import WltClient

client = WltClient(api_key="sk-your-api-key")

# Disable a key (status: 0=disable, 1=enable)
result = client.api_keys.change_status(id="456", status=0)
print(f"Success: {result.data}")  # True

# Enable a key
result = client.api_keys.change_status(id="456", status=1)

# Convenience wrappers:
client.api_keys.enable(id="456")
client.api_keys.disable(id="456")
```

### `client.api_keys.test_connect()`

Test API key connectivity.

#### Parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| provider | str | No | None | Provider name |
| access_key_id | str | No | None | AccessKey ID |
| access_key_secret | str | No | None | AccessKey Secret |

#### Response

Returns `BaseResponse[bool]`. `data=True` if connection is successful.

```python
from wlt import WltClient

client = WltClient(api_key="sk-your-api-key")

result = client.api_keys.test_connect(
    provider="dashscope",
    access_key_id="LTAI5t...",
    access_key_secret="your-access-key-secret",
)
if result.data:
    print("Connection successful!")
else:
    print("Connection failed")
```

### `client.api_keys.get_by_providers_or_ids()`

Query API keys by providers or IDs.

#### Parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| secret_id | int | No | None | Secret ID (for context) |
| providers | list[str] | No | None | Provider list |
| ids | list[int] | No | None | ApiKey ID list |

#### Response

Returns `BaseResponse[list[ApikeyVO]]`.

> ApikeyVO fields: see `client.api_keys.list()` above.

```python
from wlt import WltClient

client = WltClient(api_key="sk-your-api-key")

# Query by providers
result = client.api_keys.get_by_providers_or_ids(
    providers=["dashscope", "openrouter"],
)
for key in result.data:
    print(key.id, key.keyName, key.provider)

# Query by IDs
result = client.api_keys.get_by_providers_or_ids(ids=[1, 2, 3])

# With secret context
result = client.api_keys.get_by_providers_or_ids(
    secret_id=123,
    providers=["dashscope"],
)
```

### `client.api_keys.provider_list()`

Get the list of providers available for API keys.

#### Parameters

None.

#### Response

Returns `BaseResponse[list[ProviderVO]]`.

**ProviderVO fields:**

| Field | Type | Description |
|-------|------|-------------|
| id | str | Provider identifier |
| name | str | Provider display name |

```python
from wlt import WltClient

client = WltClient(api_key="sk-your-api-key")

providers = client.api_keys.provider_list()
for p in providers.data:
    print(p.provider, p.providerName)
```

---

## Usage

### `client.usage.serverless_summary()`

Query serverless usage summary statistics.

#### Parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| start_time | datetime | No | None | Query start time |
| end_time | datetime | No | None | Query end time |
| page_num | int | No | 1 | Page number |
| page_size | int | No | 10 | Items per page |

#### Response

Returns `BaseResponse[ServerLessSummaryResult]`.

**ServerLessSummaryResult fields:**

| Field | Type | Description |
|-------|------|-------------|
| totalRequests | int | Total request count |
| requestTrend | str | Request trend (e.g. `"+12%"`) |
| totalTokens | int | Total token consumption |
| tokenTrend | str | Token trend |
| avgResponseTime | float | Average response time |
| avgResponseTrend | str | Average response time trend |
| totalUseModel | int | Total number of models used |
| totalUseModelTrend | str | Model usage trend |
| avgLatency | float | Average latency |
| avgLatencyTrend | str | Average latency trend |

```python
from wlt import WltClient
from datetime import datetime

client = WltClient(api_key="sk-your-api-key")

# Default: recent summary
summary = client.usage.serverless_summary()
print(summary.data)

# With time range
summary = client.usage.serverless_summary(
    start_time=datetime(2026, 4, 1),
    end_time=datetime(2026, 4, 21),
    page_num=1,
    page_size=10,
)
print(summary.data)
```

### `client.usage.serverless_usage()`

Query serverless usage list (legacy API).

#### Parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| start_time | datetime | No | None | Query start time |
| end_time | datetime | No | None | Query end time |
| page_num | int | No | 1 | Page number |
| page_size | int | No | 10 | Items per page |

#### Response

Returns `BaseResponse[PageInfo[ServerlessUsageInfo]]`.

**ServerlessUsageInfo fields:**

| Field | Type | Description |
|-------|------|-------------|
| modelName | str | Model name |
| requests | int | Request count |
| totalTokens | int | Total token consumption |
| promptTokens | int | Prompt token count |
| completionTokens | int | Completion token count |
| successRate | float | Success rate |
| avgLatency | float | Average latency |
| errorCount | int | Error count |
| throughput | float | Throughput (QPS) |
| provider | str | Provider name |
| apiKeyName | str | API Key name |

```python
from wlt import WltClient
from datetime import datetime

client = WltClient(api_key="sk-your-api-key")

result = client.usage.serverless_usage(
    start_time=datetime(2026, 4, 1),
    end_time=datetime(2026, 4, 21),
    page_num=1,
    page_size=10,
)
for item in result.data.list:
    print(item.modelName, item.totalTokens)
```

### `client.usage.serverless_list()`

Query serverless usage list with filters (new API).

#### Parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| start_time | datetime | Yes | -- | Query start time |
| end_time | datetime | Yes | -- | Query end time |
| page_num | int | No | 1 | Page number (>= 1) |
| page_size | int | No | 10 | Items per page (>= 1) |
| api_key | str | No | None | Filter by API Key |
| inputs | list[str] | No | None | Input type filter list |
| outputs | list[str] | No | None | Output type filter list |
| model_ids | list[str] | No | None | Model ID filter list |

#### Response

Returns `BaseResponse[PageInfo[ServerlessUsageRecord]]`.

**ServerlessUsageRecord fields:**

| Field | Type | Description |
|-------|------|-------------|
| modelName | str | Model name |
| apiKeyName | str | API Key name |
| requests | str | Request count |
| totalTokens | str | Total token consumption |
| avgLatency | str | Average latency |
| successRate | str | Success rate (%) |
| errorCount | str | Error count |
| totalFee | str | Total fee |
| throughput | str | Throughput (QPS) |
| usageStats | str | Usage statistics info |

```python
from wlt import WltClient
from datetime import datetime

client = WltClient(api_key="sk-your-api-key")

result = client.usage.serverless_list(
    start_time=datetime(2026, 4, 1),
    end_time=datetime(2026, 4, 21),
    page_num=1,
    page_size=20,
    model_ids=["qwen-turbo"],
)
for record in result.data.list:
    print(record.modelName, record.inputTokens, record.outputTokens)
```

### `client.usage.serverless_charts()`

Get serverless usage chart data (time-series trends).

#### Parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| start_time | datetime | Yes | -- | Query start time |
| end_time | datetime | Yes | -- | Query end time |
| page_num | int | No | 1 | Page number |
| page_size | int | No | 10 | Items per page |
| api_key | str | No | None | Filter by API Key |
| inputs | list[str] | No | None | Input type filter list |
| outputs | list[str] | No | None | Output type filter list |
| model_ids | list[str] | No | None | Model ID filter list |

#### Response

Returns `BaseResponse[ServerlessChartsResult]`.

**ServerlessChartsResult fields:**

| Field | Type | Description |
|-------|------|-------------|
| tokensTrend | list[TrendItem] | Token trend data points |
| requestsTrend | list[TrendItem] | Request trend data points |
| latencyTrend | list[TrendItem] | Latency trend data points |

**TrendItem fields:**

| Field | Type | Description |
|-------|------|-------------|
| dateLabel | str | Time label (e.g. date string) |
| value | Any | Corresponding value |

```python
from wlt import WltClient
from datetime import datetime

client = WltClient(api_key="sk-your-api-key")

charts = client.usage.serverless_charts(
    start_time=datetime(2026, 4, 1),
    end_time=datetime(2026, 4, 21),
)
print(charts.data)
```

### `client.usage.serverless_stats()`

Get serverless usage aggregated statistics.

#### Parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| start_time | datetime | Yes | -- | Query start time |
| end_time | datetime | Yes | -- | Query end time |
| page_num | int | No | 1 | Page number |
| page_size | int | No | 10 | Items per page |
| api_key | str | No | None | Filter by API Key |
| inputs | list[str] | No | None | Input type filter list |
| outputs | list[str] | No | None | Output type filter list |
| model_ids | list[str] | No | None | Model ID filter list |

#### Response

Returns `BaseResponse[ServerlessStatsResult]`.

**ServerlessStatsResult fields:**

| Field | Type | Description |
|-------|------|-------------|
| totalRequests | int | Total request count |
| requestTrend | str | Request trend |
| totalTokens | int | Total token consumption |
| tokenTrend | str | Token trend |
| totalUseModel | int | Total number of models used |
| totalUseModelTrend | str | Model usage trend |
| avgLatency | str | Average latency |
| avgLatencyTrend | str | Average latency trend |

```python
from wlt import WltClient
from datetime import datetime

client = WltClient(api_key="sk-your-api-key")

stats = client.usage.serverless_stats(
    start_time=datetime(2026, 4, 1),
    end_time=datetime(2026, 4, 21),
    model_ids=["qwen-turbo", "qwen-plus"],
)
print(stats.data)
```

### `client.usage.history()`

Query API call history with multi-dimension filters.

#### Parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| provider | str | No | None | Provider filter |
| feature | str | No | None | Feature module filter |
| request_type | str | No | None | Request type filter |
| start_time | datetime | No | None | Query start time |
| end_time | datetime | No | None | Query end time |
| keyword | str | No | None | Keyword search |
| page_num | int | No | None | Page number |
| page_size | int | No | None | Items per page |
| model_ids | list[str] | No | None | Model ID filter list |
| inputs | list[str] | No | None | Input type filter list |
| outputs | list[str] | No | None | Output type filter list |

#### Response

Returns `BaseResponse[PageInfo[HistoryRecord]]`.

**HistoryRecord fields:**

| Field | Type | Description |
|-------|------|-------------|
| requestId | str | Request ID |
| modelNameVersion | str | Model name and version |
| statusCode | int | HTTP status code |
| latency | float | Gateway latency (ms) |
| totalTokens | int | Total token count |
| timestamp | datetime | Request time |
| requestType | str | Request type |
| modelTechnology | str | Model technology |
| promptTokens | int | Input token count |
| completionTokens | int | Output token count |
| providerTtft | float | TTFT (time to first token, ms) |
| providerLatency | float | Provider latency (ms) |
| providerResponseType | str | Response type |
| apiKeyName | str | API Key name |
| gatewayRequestBodySize | int | Request body size (bytes) |
| errorMsg | str | Error message |

```python
from wlt import WltClient
from datetime import datetime

client = WltClient(api_key="sk-your-api-key")

result = client.usage.history(
    start_time=datetime(2026, 4, 1),
    end_time=datetime(2026, 4, 21),
    provider="dashscope",
    page_num=1,
    page_size=20,
)
for record in result.data.list:
    print(record.modelId, record.requestType, record.createdAt)

# Search by keyword
result = client.usage.history(keyword="qwen", page_num=1, page_size=10)
```

### `client.usage.gateway_providers()`

Get gateway provider list for usage filtering.

#### Parameters

None.

#### Response

Returns `BaseResponse[list[ProviderVO]]`.

**ProviderVO fields:**

| Field | Type | Description |
|-------|------|-------------|
| id | str | Provider identifier |
| name | str | Provider display name |

```python
from wlt import WltClient

client = WltClient(api_key="sk-your-api-key")

providers = client.usage.gateway_providers()
for p in providers.data:
    print(p.provider, p.providerName)
```

---

## UserInfo

### `client.user.get_info()`

Get the current logged-in user's information.

#### Parameters

None.

#### Response

Returns `BaseResponse[LoginUser]`.

**LoginUser fields:**

| Field | Type | Description |
|-------|------|-------------|
| userId | int | User ID |
| aliyunPk | str | Aliyun PK info |
| parentPk | str | Parent account PK info |
| accountStructure | int | Account type: 1=Partner, 2=Customer main account, 3=SubUser, 4=TokenLogin |
| cmUserId | str | CM user ID |
| tenantCode | str | Tenant code |
| userName | str | Username |
| bucId | int | BUC ID |
| bid | str | BID |
| needAuth | bool | Whether SLR authorization is needed |
| parentUserId | int | Parent account database ID |
| securityToken | str | Security token |
| accessKeyId | str | AccessKey ID |
| timezone | str | Timezone info |
| region | str | Region info |
| userPermission | UserPermissionResponse | User permission info |
| userType | str | User type (e.g. `PartnerUser` / `PartnerUserSub`) |
| partnerId | int | Tenant ID |
| partnerName | str | Tenant name |
| partnerLogoUrl | str | Tenant logo URL |
| sourceExternalTicket | str | SSO external ticket |
| thirdChannel | str | Third-party channel source |

```python
from wlt import WltClient

client = WltClient(api_key="sk-your-api-key")

user = client.user.get_info()
print(f"User ID: {user.data.userId}")
print(f"Username: {user.data.userName}")
print(f"Email: {user.data.email}")
```

---

## Billing

### `client.billing.query_all_amount()`

Query total billing amount for a given billing cycle.

#### Parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| billing_cycle | str | Yes | -- | Billing cycle, format `"YYYY-MM"` (e.g. `"2026-04"`) |

#### Response

Returns `BaseResponse[UserBillingMonthResponse]`.

**UserBillingMonthResponse fields:**

| Field | Type | Description |
|-------|------|-------------|
| afterDiscountAmountSum | Decimal | Amount after discount |
| deductedByCouponsSum | Decimal | Coupon deduction amount |
| pretaxGrossAmountSum | Decimal | Original amount (list price) |
| pretaxAmountSum | Decimal | Payable amount |
| currency | str | Currency code (e.g. `"USD"`) |

```python
from wlt import WltClient

client = WltClient(api_key="sk-your-api-key")

bill = client.billing.query_all_amount(billing_cycle="2026-04")
print(f"Total amount: {bill.data.pretaxAmountSum}")
print(f"Currency: {bill.data.currency}")
```

### `client.billing.query_bill_by_gpu()`

Query billing details by GPU spec with pagination.

#### Parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| billing_cycle | str | Yes | -- | Billing cycle, format `"YYYY-MM"` |
| page_size | int | Yes | -- | Items per page |
| page_num | int | Yes | -- | Page number, starting from 1 |

#### Response

Returns `BaseResponse[PageInfo[UserBillingGpuServiceResponse]]`.

**UserBillingGpuServiceResponse fields:**

| Field | Type | Description |
|-------|------|-------------|
| afterDiscountAmountSum | Decimal | Amount after discount |
| deductedByCouponsSum | Decimal | Coupon deduction amount |
| pretaxGrossAmountSum | Decimal | Original amount |
| pretaxAmountSum | Decimal | Payable amount |
| listPrice | Decimal | List price (unit price) |
| currency | str | Currency code |
| gpuSpec | str | GPU spec (e.g. `"A100-80G"`) |
| servicePeriodUnit | str | Service period unit (e.g. `"Hour"`) |
| servicePeriodSum | str | Total service period |
| modelResource | str | Model resource identifier |

```python
from wlt import WltClient

client = WltClient(api_key="sk-your-api-key")

result = client.billing.query_bill_by_gpu(
    billing_cycle="2026-04",
    page_size=10,
    page_num=1,
)
for item in result.data.list:
    print(f"GPU: {item.gpuSpec}, Amount: {item.pretaxAmountSum}")
```

### `client.billing.query_bill_by_service()`

Query billing details by AI service with pagination.

#### Parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| billing_cycle | str | Yes | -- | Billing cycle, format `"YYYY-MM"` |
| page_size | int | Yes | -- | Items per page |
| page_num | int | Yes | -- | Page number, starting from 1 |

#### Response

Returns `BaseResponse[PageInfo[UserBillingAiServiceResponse]]`.

**UserBillingAiServiceResponse fields:**

| Field | Type | Description |
|-------|------|-------------|
| afterDiscountAmountSum | Decimal | Amount after discount |
| deductedByCouponsSum | Decimal | Coupon deduction amount |
| pretaxGrossAmountSum | Decimal | Original amount |
| pretaxAmountSum | Decimal | Payable amount |
| currency | str | Currency code |
| gpuSpec | str | GPU spec |
| modelResource | str | Model resource identifier |
| servicePeriodUnit | str | Service period unit |
| servicePeriodSum | str | Total service period |
| bizType | str | Business type (e.g. `"Deploy"`, `"Finetune"`) |

```python
from wlt import WltClient

client = WltClient(api_key="sk-your-api-key")

result = client.billing.query_bill_by_service(
    billing_cycle="2026-04",
    page_size=10,
    page_num=1,
)
for item in result.data.list:
    print(f"Service: {item.serviceName}, Amount: {item.pretaxAmountSum}")
```

### `client.billing.query_bill_list()`

Query billing detail list with pagination.

#### Parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| billing_cycle | str | Yes | -- | Billing cycle, format `"YYYY-MM"` |
| page_size | int | Yes | -- | Items per page |
| page_num | int | Yes | -- | Page number, starting from 1 |

#### Response

Returns `BaseResponse[PageInfo[UserBillingResponse]]`.

**UserBillingResponse fields:**

| Field | Type | Description |
|-------|------|-------------|
| afterDiscountAmount | Decimal | Amount after discount |
| deductedByCoupons | Decimal | Coupon deduction amount |
| pretaxGrossAmount | Decimal | Original amount |
| pretaxAmount | Decimal | Payable amount |
| instanceID | str | Instance ID |
| currency | str | Currency code |
| productCode | str | Product code |
| region | str | Region |
| gpuSpec | str | GPU spec |
| modelResource | str | Model resource identifier |
| servicePeriodUnit | str | Service period unit |
| servicePeriod | str | Service period |
| bizType | str | Business type (e.g. `"Deploy"`, `"Finetune"`) |

```python
from wlt import WltClient

client = WltClient(api_key="sk-your-api-key")

result = client.billing.query_bill_list(
    billing_cycle="2026-04",
    page_size=20,
    page_num=1,
)
print(f"Total records: {result.data.total}")
for item in result.data.list:
    print(item)
```

---

## Payment

### `client.payment.records()`

Query recharge records with pagination.

#### Parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| page_num | int | No | 1 | Page number, starting from 1 |
| page_size | int | No | 10 | Items per page (max 1000) |
| status_list | list[str] | No | None | Status filter: `"0"`=processing, `"1"`=success, `"2"`=failed, `"3"`=closed |
| start_time | datetime | No | None | Query start time |
| end_time | datetime | No | None | Query end time |
| transaction_type | str | No | None | Transaction type: `"Recharge"` or `"Refund"` |

#### Response

Returns `BaseResponse[PageResponse]` where the `list` field contains `RechargeTransactionResponse` items.

**PageResponse fields (Payment-specific pagination):**

| Field | Type | Description |
|-------|------|-------------|
| pageNum | int | Current page number |
| pageSize | int | Items per page |
| total | int | Total record count |
| pages | int | Total number of pages |
| hasNext | bool | Whether there is a next page |
| hasPrevious | bool | Whether there is a previous page |
| list | list | Data list |

**RechargeTransactionResponse fields:**

| Field | Type | Description |
|-------|------|-------------|
| id | int | Record primary key ID |
| createdAtUtc | str | Creation time (UTC) |
| updatedAtUtc | str | Update time (UTC) |
| userId | int | User ID |
| payChannel | str | Payment channel (e.g. `"Stripe"`) |
| payType | str | Payment type (`APP` / `WEB`) |
| transactionType | str | Transaction type (`Recharge` / `Refund`) |
| status | str | Status: 0=processing, 1=success, 2=failed, 3=closed |
| callbackAtUtc | str | Callback time (UTC) |
| transactionNo | str | Platform transaction number |
| externalNo | str | External transaction number (Stripe ID) |
| amount | str | Transaction amount |
| refundAmount | str | Refunded amount |
| currency | str | Currency (ISO 4217) |
| refundStatus | str | Refund status: 0=none, 1=partial, 2=full |
| originalTransactionNo | str | Original transaction number (for refund records) |
| extend | str | Extension field (JSON) |

```python
from wlt import WltClient
from datetime import datetime

client = WltClient(api_key="sk-your-api-key")

# List successful recharge records
result = client.payment.records(
    page_num=1,
    page_size=10,
    status_list=["1"],  # 0=processing, 1=success, 2=failed, 3=closed
)
print(f"Total: {result.data.total}")
for record in result.data.list:
    print(record.transactionNo, record.amount, record.status)

# With time range and transaction type
result = client.payment.records(
    start_time=datetime(2026, 4, 1),
    end_time=datetime(2026, 4, 21),
    transaction_type="Recharge",
)
```

### `client.payment.statistics()`

Query recharge statistics summary.

#### Parameters

None.

#### Response

Returns `BaseResponse[RechargeStatisticsResponse]`.

**RechargeStatisticsResponse fields:**

| Field | Type | Description |
|-------|------|-------------|
| totalRechargedAmount | str | Total recharged amount |
| totalUsedRechargedAmount | str | Total used recharged amount |
| totalBalanceRechargedAmount | str | Unused recharge balance |
| totalRefundAmount | str | Total refund amount |
| totalFreeAmount | str | Free quota amount |
| currency | str | Currency code |

```python
from wlt import WltClient

client = WltClient(api_key="sk-your-api-key")

stats = client.payment.statistics()
print(f"Total recharged: {stats.data.totalRechargedAmount}")
```

### `client.payment.list()`

Query recharge transaction list (non-paginated).

#### Parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| status_list | list[str] | No | None | Status filter: `"0"`=processing, `"1"`=success, `"2"`=failed, `"3"`=closed |
| start_time | datetime | No | None | Query start time |
| end_time | datetime | No | None | Query end time |
| transaction_type | str | No | None | Transaction type: `"Recharge"` or `"Refund"` |

#### Response

Returns `BaseResponse[list[RechargeTransactionResponse]]`.

> RechargeTransactionResponse fields: see `client.payment.records()` above.

```python
from wlt import WltClient

client = WltClient(api_key="sk-your-api-key")

records = client.payment.list(transaction_type="Recharge")
for record in records.data:
    print(record.transactionNo, record.amount)

# With filters
records = client.payment.list(
    status_list=["1"],
    transaction_type="Refund",
)
```

### `client.payment.get_record()`

Get a single recharge record by transaction number.

#### Parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| transaction_no | str | Yes | -- | Platform transaction number |

#### Response

Returns `BaseResponse[RechargeTransactionResponse]`.

> RechargeTransactionResponse fields: see `client.payment.records()` above.

```python
from wlt import WltClient

client = WltClient(api_key="sk-your-api-key")

record = client.payment.get_record(transaction_no="TXN20260421001")
print(f"Amount: {record.data.amount}")
print(f"Status: {record.data.status}")
print(f"Created: {record.data.createdAt}")
```

### `client.payment.billing_list()`

Query model usage billing list with pagination.

#### Parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| page_num | int | No | 1 | Page number, starting from 1 |
| page_size | int | No | 10 | Items per page (max 1000) |
| start_time | str | No | None | Start time, format `"yyyy-MM-dd HH:mm:ss"` |
| end_time | str | No | None | End time, format `"yyyy-MM-dd HH:mm:ss"` |
| model_id | str | No | None | Model ID for exact filtering |

#### Response

Returns `BaseResponse[PageInfo[LmModelUsageBillingResponse]]`.

**LmModelUsageBillingResponse fields:**

| Field | Type | Description |
|-------|------|-------------|
| id | int | Record primary key ID |
| createdAtUtc | str | Record creation time (UTC) |
| userId | int | User ID |
| username | str | Username |
| modelName | str | Model name |
| modelType | str | Model type |
| feeType | str | Fee type (e.g. `"input tokens"` / `"output tokens"`) |
| unitPrice | str | Unit price (per 1K tokens) |
| currency | str | Currency (ISO 4217) |
| usedAmout | str | Usage amount (token count). Note: field name matches backend spelling |
| amount | str | Billed amount |
| billingTimeStart | str | Billing start time |
| billingTimeEnd | str | Billing end time |
| extend | str | Extension field (JSON) |
| inputs | set[str] | Input type list |
| outputs | set[str] | Output type list |

```python
from wlt import WltClient

client = WltClient(api_key="sk-your-api-key")

result = client.payment.billing_list(
    page_num=1,
    page_size=10,
    start_time="2026-04-01 00:00:00",
    end_time="2026-04-21 23:59:59",
)
print(f"Total: {result.data.total}")
for item in result.data.list:
    print(item.modelId, item.totalAmount)

# Filter by model
result = client.payment.billing_list(
    start_time="2026-04-01 00:00:00",
    end_time="2026-04-21 23:59:59",
    model_id="qwen-turbo",
)
```

### `client.payment.billing_query_all_amount()`

Query model usage billing total amount.

#### Parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| start_time | str | No | None | Start time, format `"yyyy-MM-dd HH:mm:ss"` |
| end_time | str | No | None | End time, format `"yyyy-MM-dd HH:mm:ss"` |
| model_id | str | No | None | Model ID for exact filtering |

#### Response

Returns `BaseResponse[ModelUsageBillingAmountResponse]`.

**ModelUsageBillingAmountResponse fields:**

| Field | Type | Description |
|-------|------|-------------|
| totalBillingAmount | str | Total billing amount |
| currency | str | Currency code |

```python
from wlt import WltClient

client = WltClient(api_key="sk-your-api-key")

total = client.payment.billing_query_all_amount(
    start_time="2026-04-01 00:00:00",
    end_time="2026-04-21 23:59:59",
)
print(f"Total billing amount: {total.data.totalAmount}")

# Filter by specific model
total = client.payment.billing_query_all_amount(
    start_time="2026-04-01 00:00:00",
    end_time="2026-04-21 23:59:59",
    model_id="qwen-turbo",
)
```

---

## Model Gallery

### `client.model_gallery.page()`

Query model list with pagination.

#### Parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| page_num | int | No | 1 | Page number, starting from 1 |
| page_size | int | No | 10 | Items per page |
| model_name | str | No | None | Model name (fuzzy search) |
| provider | str | No | None | Provider identifier |
| series_provider | str | No | None | Series provider identifier |
| model_type | str | No | None | Model type |
| view_all_flag | int | No | None | View all flag (1=view all) |
| usage_type | str | No | None | Usage type: `"inference"` or `"train"` |
| training_method | str | No | None | Training method: `"sft"` or `"dpo"` |
| tags | list[str] | No | None | Tag filter list |
| capability | str | No | None | Capability filter, e.g. `"text_to_text"` |
| model_type_list | list[str] | No | None | Model type list (multi-select) |
| origin_providers | list[str] | No | None | Origin provider list (multi-select) |
| inputs | list[str] | No | None | Input type list, e.g. `["text"]` |
| outputs | list[str] | No | None | Output type list, e.g. `["image"]` |

#### Response

Returns `BaseResponse[PageInfo[ModelInfoVO]]`.

> ModelInfoVO fields: see `client.secrets.model_list()` above.

```python
from wlt import WltClient

client = WltClient(api_key="sk-your-api-key")

# Browse all models
result = client.model_gallery.page(page_num=1, page_size=10)
print(f"Total models: {result.data.total}")
for model in result.data.list:
    print(model.modelName, model.provider)

# Filter by criteria
result = client.model_gallery.page(
    usage_type="inference",
    provider="dashscope",
    tags=["New"],
    inputs=["text"],
    outputs=["text"],
)
```

### `client.model_gallery.detail()`

Get model detail by model ID.

#### Parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| model_id | str | Yes | -- | Model ID |

#### Response

Returns `BaseResponse[ModelDetailVO]`.

**ModelDetailVO fields:**

| Field | Type | Description |
|-------|------|-------------|
| modelImage | str | Model icon URL |
| modelName | str | Model name |
| modelType | str | Model type |
| modelTag | str | Model tag |
| modelSeries | str | Model series |
| price | str | Price |
| newFlag | bool | Whether new model |
| updatedAt | datetime | Update time |
| createdOn | datetime | Creation time |
| provider | str | Provider identifier |
| originProvider | str | Origin provider identifier |
| status | str | Status |
| huggingFaceLink | str | HuggingFace model page link |
| modelSize | str | Model size |
| parameters | str | Parameter count |
| contextLength | int | Context length (token count) |
| language | str | Supported languages |
| supportedFunctionality | str | Supported functionality |
| introduction | str | Model introduction |
| features | str | Feature description |
| deployments | str | Deployment info |
| rawJson | str | Raw JSON data |

```python
from wlt import WltClient

client = WltClient(api_key="sk-your-api-key")

detail = client.model_gallery.detail(model_id="Qwen2.5-72B-Instruct")
print(f"Context length: {detail.data.contextLength}")
print(f"Model type: {detail.data.modelType}")
```

### `client.model_gallery.provider_list()`

Get the list of model providers.

#### Parameters

None.

#### Response

Returns `BaseResponse[list[ProviderVO]]`.

**ProviderVO fields:**

| Field | Type | Description |
|-------|------|-------------|
| id | str | Provider identifier |
| name | str | Provider display name |

```python
from wlt import WltClient

client = WltClient(api_key="sk-your-api-key")

providers = client.model_gallery.provider_list()
for p in providers.data:
    print(p.provider, p.providerName)
```

### `client.model_gallery.get_price()`

Get model API price for the current tenant.

#### Parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| model_name | str | Yes | -- | Model name |

#### Response

Returns `BaseResponse[PartnerApiPriceResponse]`.

**PartnerApiPriceResponse fields:**

| Field | Type | Description |
|-------|------|-------------|
| id | int | Record ID |
| partnerId | int | Tenant ID |
| modelName | str | Model name |
| modelType | str | Model type |
| type | str | Resale type (model / BYOK) |
| originProvider | str | Origin provider |
| seriesProvider | str | Series provider |
| capabilities | str | Model capabilities |
| inputs | set[str] | Input type set |
| outputs | set[str] | Output type set |
| priceExtend | PartnerApiPriceExtendDetail | Price details |
| gmtCreate | datetime | Creation time |
| gmtModified | datetime | Modification time |

**PartnerApiPriceExtendDetail fields:**

| Field | Type | Description |
|-------|------|-------------|
| llmInput | str | LLM input price (per 1K tokens) |
| llmOutput | str | LLM output price (per 1K tokens) |
| vlmInput | str | VLM input price (per 1K tokens) |
| vlmOutput | str | VLM output price (per 1K tokens) |
| image | str | Image generation price |
| imageEa | str | Image unit price |
| imageStep | str | Image step price |
| video | str | Video generation price |
| audio | str | Audio price |
| tieredPricing | list[TieredPricing] | Tiered pricing list |
| videoPricing | list[VideoPricing] | Video pricing list |
| imagePricing | list[ImagePricing] | Image pricing list |

```python
from wlt import WltClient

client = WltClient(api_key="sk-your-api-key")

price = client.model_gallery.get_price(model_name="Qwen2.5-72B-Instruct")
print(f"Input price: {price.data.inputPrice}")
print(f"Output price: {price.data.outputPrice}")
```

---

## Model Lab

### `client.model_lab.list()`

Get model list for the Model Lab.

#### Parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| model_name | str | No | None | Model name (fuzzy search) |
| provider | str | No | None | Provider identifier |
| series_provider | str | No | None | Series provider identifier |
| model_type | str | No | None | Model type |
| view_all_flag | int | No | None | View all flag (1=view all) |
| page_size | int | No | None | Items per page. **Required by backend** (code=1000 if missing). Recommended default: 20 |
| page_num | int | No | None | Page number. **Required by backend** (code=1000 if missing). Recommended default: 1 |
| usage_type | str | No | None | Usage type: `"inference"` or `"train"` |
| training_method | str | No | None | Training method: `"sft"` or `"dpo"` |
| tags | list[str] | No | None | Tag filter list |
| capability | str | No | None | Capability filter, e.g. `"text_to_text"` |
| model_type_list | list[str] | No | None | Model type list (multi-select) |
| origin_providers | list[str] | No | None | Origin provider list (multi-select) |
| inputs | list[str] | No | None | Input type list, e.g. `["text"]` |
| outputs | list[str] | No | None | Output type list (max 1 item), e.g. `["image"]` |

#### Response

Returns `BaseResponse[list[ModelInfoVO]]`.

> ModelInfoVO fields: see `client.secrets.model_list()` above.

```python
from wlt import WltClient

client = WltClient(api_key="sk-your-api-key")

# List inference models
models = client.model_lab.list(usage_type="inference")
for m in models.data:
    print(m.modelName, m.provider)

# Filter by provider and capability
models = client.model_lab.list(
    provider="dashscope",
    capability="text_to_text",
    inputs=["text"],
    outputs=["text"],
)
```

### `client.model_lab.create_session()`

Create a new chat session for multi-turn conversations.

#### Parameters

None.

#### Response

Returns `BaseResponse[str]`. The `data` field contains a UUID string (session ID).

```python
from wlt import WltClient

client = WltClient(api_key="sk-your-api-key")

session = client.model_lab.create_session()
session_id = session.data  # UUID string
print(f"Session ID: {session_id}")
```

### `client.model_lab.stream()`

Call model stream inference (SSE). Yields each SSE data chunk as a raw JSON string.

#### Parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| provider | str | Yes | -- | Provider identifier |
| model_name | str | Yes | -- | Model name |
| user_prompt | str | Yes (unless retry) | None | User prompt text |
| session_id | str | No | None | Session ID (for multi-turn conversations, use UUID) |
| task_id | str | No | None | Task ID (for retry, references the failed task) |
| task_type | str | No | `"TEXT"` | Task type |
| is_retry | bool | No | False | Whether this is a retry request (requires task_id) |
| options | OptionsDTO | No | None | Model parameter configuration (see below) |

**OptionsDTO fields:**

| Field | Type | Required | Default | Description |
|-------|------|----------|---------|-------------|
| temperature | float | No | None | Temperature, controls output randomness |
| maxToken | int | No | None | Maximum generated token count |
| topP | float | No | None | Top P sampling parameter |
| topK | int | No | None | Top K sampling parameter |
| presencePenalty | float | No | None | Presence penalty |
| frequencyPenalty | float | No | None | Frequency penalty |
| stopSequences | str | No | None | Stop sequences |
| systemPrompt | str | No | None | System prompt |
| enableThinking | bool | No | False | Enable deep thinking |
| enableProgress | bool | No | True | Enable progress push |
| timeoutSeconds | int | No | 300 | Task timeout (seconds) |
| enableCache | bool | No | False | Enable result caching |
| enableDocumentInlining | bool | No | None | Enable document inlining |
| budgetTokens | int | No | None | Budget token count |

#### Response

Returns a generator yielding SSE data chunks as raw JSON strings. Each chunk follows the OpenAI-compatible streaming format. The stream ends with a `[DONE]` sentinel.

```python
import json
from wlt import WltClient
from wlt.models.model_lab import OptionsDTO

client = WltClient(api_key="sk-your-api-key")

# Create a session for multi-turn conversation
session = client.model_lab.create_session()

# Stream inference
for chunk in client.model_lab.stream(
    provider="dashscope",
    model_name="Qwen2.5-72B-Instruct",
    user_prompt="Explain quantum computing in one paragraph.",
    session_id=session.data,
    options=OptionsDTO(
        temperature=0.7,
        maxToken=2048,
        topP=0.9,
        systemPrompt="You are a helpful assistant.",
    ),
):
    data = json.loads(chunk)
    # Each chunk contains delta content, finish_reason, usage, etc.
    if "content" in data:
        print(data["content"], end="", flush=True)

print()  # newline after streaming completes
```

### `client.model_lab.get_parameters()`

Get model parameter configuration.

#### Parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| model_id | str | Yes | -- | Model ID |
| provider | str | Yes | -- | Provider identifier |

#### Response

Returns `BaseResponse[dict]`. The `data` field is a dictionary where keys are parameter names and values are configuration objects with `min`, `max`, and `default` fields.

```python
from wlt import WltClient

client = WltClient(api_key="sk-your-api-key")

params = client.model_lab.get_parameters(
    model_id="Qwen2.5-72B-Instruct",
    provider="dashscope",
)
print(params.data)
# e.g. {"temperature": {"min": 0, "max": 2, "default": 0.7}, ...}
```

### `client.model_lab.code_samples()`

Get model code samples in multiple languages.

#### Parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| model_id | str | Yes | -- | Model ID |
| provider | str | Yes | -- | Provider identifier |
| languages | list[str] | No | None | Language list: `"CURL"`, `"PYTHON"`, `"JAVASCRIPT"`, `"GO"`, `"JAVA"`. If not provided, returns all |
| request_schema | Any | No | None | Custom request parameter JSON Schema |
| model_type | str | No | None | Model type (`IMAGE` / `VIDEO` etc.), recommended when request_schema is provided |

#### Response

Returns `BaseResponse[ModelCodeSampleResponse]`.

**ModelCodeSampleResponse fields:**

| Field | Type | Description |
|-------|------|-------------|
| samples | dict[str, str] | Code samples map. Key = language code, value = sample code string |

```python
from wlt import WltClient

client = WltClient(api_key="sk-your-api-key")

samples = client.model_lab.code_samples(
    model_id="Qwen2.5-72B-Instruct",
    provider="dashscope",
    languages=["CURL", "PYTHON", "JAVASCRIPT", "GO", "JAVA"],
)
# Print the Python sample
if samples.data and samples.data.samples:
    print(samples.data.samples.get("PYTHON"))
```

---

## Error Handling

All API methods can raise typed exceptions. The SDK auto-refreshes tokens on expiry,
so `AuthenticationError` is only raised if the refresh also fails.

```python
from wlt import WltClient
from wlt._exceptions import (
    AuthenticationError,
    PermissionError,
    NotFoundError,
    ValidationError,
    RateLimitError,
    InternalError,
    APIError,
    ConnectionError,
    TimeoutError,
)

client = WltClient(api_key="sk-your-api-key")

try:
    result = client.secrets.list()
except AuthenticationError as e:
    # code 2000/2002: API Key invalid; code 3001: token expired (auto-refresh failed)
    print(f"Auth failed (code={e.code}): {e.message}")
except PermissionError as e:
    print(f"Permission denied (code={e.code}): {e.message}")
except NotFoundError as e:
    print(f"Not found (code={e.code}): {e.message}")
except ValidationError as e:
    print(f"Invalid params (code={e.code}): {e.message}")
except RateLimitError as e:
    print(f"Rate limited (code={e.code}): {e.message}")
except InternalError as e:
    print(f"Server error (code={e.code}): {e.message}")
except APIError as e:
    # Catch-all for any other business error code
    print(f"API error (code={e.code}): {e.message}")
except ConnectionError as e:
    print(f"Network error: {e.message}")
except TimeoutError as e:
    print(f"Request timeout: {e.message}")
```

### Error Code Reference

| Code | Exception | Description |
|------|-----------|-------------|
| 200 | _(success)_ | OK |
| 1000 | `InternalError` | Server internal error |
| 1001 | `ValidationError` | Invalid request parameters |
| 1002 | `NotFoundError` | Resource not found |
| 2000 | `AuthenticationError` | Login failure |
| 2002 | `AuthenticationError` | Authentication error |
| 2007 | `PermissionError` | Permission denied |
| 3001 | `AuthenticationError` | Token expired / invalid |
| 3002 | `RateLimitError` | Rate limit exceeded |

---

## Provider Values

Valid provider values for Secret `allowedProviders` and ApiKey operations:

- `dashscope`
- `dashscope-intl`
- `dashscope-us`
- `openrouter`
- `zenlayer`

Use `client.secrets.provider_list()`, `client.api_keys.provider_list()`, or
`client.model_gallery.provider_list()` to retrieve the latest available providers dynamically.

---

## Available Services Summary (45 Methods)

| Service | Field | Methods |
|---------|-------|---------|
| Auth | `client.auth` | `tenant_info` |
| Secrets | `client.secrets` | `list`, `detail`, `create`, `edit`, `action`, `get_usage_data`, `usage_by_model`, `model_list`, `provider_list` |
| ApiKeys | `client.api_keys` | `list`, `create`, `update`, `delete`, `change_status`, `test_connect`, `get_by_providers_or_ids`, `provider_list` |
| Usage | `client.usage` | `serverless_summary`, `serverless_usage`, `serverless_list`, `serverless_charts`, `serverless_stats`, `history`, `gateway_providers` |
| Users | `client.users` | `get_info` |
| Billing | `client.billing` | `query_all_amount`, `query_bill_by_gpu`, `query_bill_by_service`, `query_bill_list` |
| Payment | `client.payment` | `records`, `statistics`, `list`, `get_record`, `billing_list`, `billing_query_all_amount` |
| ModelGallery | `client.model_gallery` | `page`, `detail`, `provider_list`, `get_price` |
| ModelLab | `client.model_lab` | `list`, `create_session`, `stream`, `get_parameters`, `code_samples` |

## License

Apache-2.0
