# 任务生命周期

Tripo API 的生成类接口均采用异步任务模式。提交请求后返回 `task_id`，通过轮询查询任务状态和结果。

## 状态机

```
queued → running → success
                 → failed
                 → cancelled
```

## 状态说明

| 状态 | 说明 | progress |
| :-: | :-: | :-: |
| `queued` | 任务已创建，排队等待处理 | 0 |
| `running` | 任务正在处理中 | 0–100 |
| `success` | 任务完成，`output` 字段可用 | 100 |
| `failed` | 任务失败，通常是服务端问题，请联系支持 | — |
| `banned` | 输入内容违反内容政策 | — |
| `expired` | 任务已过期，输出文件不再可用 | — |
| `cancelled` | 任务已被取消 | — |

## 任务流程

```
1. 创建任务 (POST /v3/generation/*)
   ↓
2. 返回 task_id
   ↓
3. 轮询状态 (GET /v3/tasks/{task_id})
   ↓
4a. status=success → 获取 output 中的下载链接
4b. status=failed  → 检查错误信息，联系支持
4c. status=banned  → 修改输入内容后重新提交
```

## 积分冻结模型

Tripo 采用「冻结-扣除」的积分模型，确保用户不会为失败的任务付费：

| 阶段 | 积分变化 | 说明 |
| :-: | :-: | :-: |
| 创建任务 | 冻结对应积分 | 从可用余额中预扣，进入冻结状态 |
| 任务成功 | 冻结积分转为已消耗 | 正式扣除 |
| 任务失败 | 冻结积分退回 | 退还到可用余额 |
| 任务取消 | 冻结积分退回 | 退还到可用余额 |

查询当前余额和冻结积分：

```bash
curl -X GET https://openapi.tripo3d.ai/v3/account/balance \
  -H "Authorization: Bearer {api_key}"
```

```json
{
  "code": 0,
  "data": {
    "balance": 10000,
    "frozen": 200
  }
}
```

## 轮询建议

- **轮询间隔**：每 1–2 秒查询一次
- **使用 `progress` 字段展示进度**：值为 0–100 的整数
- **设置超时**：建议设置最大轮询时间（如 5 分钟），超时后提示用户稍后查看
- **批量任务使用 `POST /v3/tasks/list`**：减少请求次数

### Python 轮询示例

```python
import time
import requests

def wait_for_task(task_id, api_key, interval=2, timeout=300):
    url = f"https://openapi.tripo3d.ai/v3/tasks/{task_id}"
    headers = {"Authorization": f"Bearer {api_key}"}
    start = time.time()

    while time.time() - start < timeout:
        response = requests.get(url, headers=headers)
        task = response.json()["data"]
        status = task["status"]
        progress = task.get("progress", 0)

        print(f"[{task_id}] {status} ({progress}%)")

        if status == "success":
            return task["output"]
        if status in ("failed", "cancelled", "banned"):
            raise Exception(f"任务终止: {status}")

        time.sleep(interval)

    raise TimeoutError(f"任务 {task_id} 超时")
```

### JavaScript 轮询示例

```javascript
async function waitForTask(taskId, apiKey, interval = 2000, timeout = 300000) {
  const url = `https://openapi.tripo3d.ai/v3/tasks/${taskId}`;
  const headers = { "Authorization": `Bearer ${apiKey}` };
  const start = Date.now();

  while (Date.now() - start < timeout) {
    const response = await fetch(url, { headers });
    const { data: task } = await response.json();
    const { status, progress = 0 } = task;

    console.log(`[${taskId}] ${status} (${progress}%)`);

    if (status === "success") return task.output;
    if (["failed", "cancelled", "banned"].includes(status)) {
      throw new Error(`任务终止: ${status}`);
    }

    await new Promise(resolve => setTimeout(resolve, interval));
  }

  throw new Error(`任务 ${taskId} 超时`);
}
```
