# SDK 연동

Tripo 공식 SDK를 사용하여 text-to-model 작업을 제출하고, 완료될 때까지 기다리고, 최종 상태를 확인한 다음 생성된 모델을 다운로드합니다. 아래 설치 소스는 이 페이지를 검증할 때 사용한 버전으로 고정되어 있습니다.

## 지원 SDK

| 언어 | API | 고정 버전 | 설치 소스 |
| --- | --- | --- | --- |
| JavaScript / TypeScript | V3 | [`e351348`](https://github.com/VAST-AI-Research/tripo-js-sdk/tree/e35134801b339caac0b84f36fe02d08e73e217b2) | 공식 Git 커밋 |
| Python | V2 + limited V3 | [`v0.4.2`](https://github.com/VAST-AI-Research/tripo-python-sdk/tree/v0.4.2) | PyPI `tripo3d==0.4.2` |
| Go | V3 | [`2c8c8d4`](https://github.com/VAST-AI-Research/tripo-go-sdk/tree/2c8c8d4e6a9e1fc9e49699fc055140eca689ee79) | Go pseudo-version `v0.0.0-20260713072120-2c8c8d4e6a9e` |
| Rust | V3 | [`f992f6a`](https://github.com/VAST-AI-Research/tripo-rust-sdk/tree/f992f6a7cf7a28c10781f9fa28e4630c7802291c) | Cargo Git 종속성 |
| Java | V3 | [`7b6a68d`](https://github.com/VAST-AI-Research/tripo-java-sdk/tree/7b6a68d855e01a0b098775b1ee14ce7f3c8ac7d9) | 소스 빌드; 로컬 Maven `0.1.0-SNAPSHOT` |

## 1. API 키 및 리전 구성

[Tripo 콘솔](https://platform.tripo3d.ai/)에서 키를 생성하고 서버 측 프로세스에만 제공하세요. API 키를 브라우저 코드에 넣거나 소스 제어에 커밋하지 마세요.

```bash
export TRIPO_API_KEY="tsk_..."
```

JavaScript, Go 및 Rust는 전 세계에서 `https://openapi.tripo3d.ai/v3`, 중국에서 `https://openapi.tripo3d.com/v3`를 사용합니다. Java는 `TripoRegion.GLOBAL` 또는 `TripoRegion.CN`을 선택합니다. SDK는 해당 `.ai` 또는 `.com` 오리진에서 시작하여 `/v3`를 추가합니다. Python 0.4.2의 기본 V2 클라이언트는 전 세계에서 `https://api.tripo3d.ai/v2/openapi`, 중국에서 `https://api.tripo3d.com/v2/openapi`를 사용하며, 제한된 V3 분할 흐름은 해당 `https://openapi.tripo3d.ai` 또는 `.com` 오리진도 사용합니다.

## 2. SDK 설치

각 SDK를 고정된 프로덕션 소스에서 설치합니다.

### JavaScript

```bash
npm install github:VAST-AI-Research/tripo-js-sdk#e35134801b339caac0b84f36fe02d08e73e217b2
```

### Python

```bash
python -m pip install tripo3d==0.4.2
```

### Go

```bash
go get github.com/VAST-AI-Research/tripo-go-sdk@v0.0.0-20260713072120-2c8c8d4e6a9e
```

### Rust

```toml
[dependencies]
tripo3d-sdk = { git = "https://github.com/VAST-AI-Research/tripo-rust-sdk.git", rev = "f992f6a7cf7a28c10781f9fa28e4630c7802291c" }
tokio = { version = "1", features = ["full"] }
anyhow = "1"
```

### Java

```bash
git clone https://github.com/VAST-AI-Research/tripo-java-sdk.git
cd tripo-java-sdk
git checkout 7b6a68d855e01a0b098775b1ee14ce7f3c8ac7d9
./mvnw install
```

Java 빌드는 로컬 Maven 저장소에 `ai.tripo3d:tripo-sdk:0.1.0-SNAPSHOT`을 설치합니다. 소스 빌드가 완료되면 애플리케이션에 이 좌표를 추가하세요.

## 3. 제출, 대기 및 다운로드

각 서버 측 예제는 `TRIPO_API_KEY`를 읽고, text-to-model 작업을 제출하고, 최종 결과를 기다리고, 성공 여부를 확인한 다음 기본 모델을 즉시 저장합니다. 생성된 모델 URL은 임시 URL입니다.

### JavaScript

```javascript
import { writeFile } from 'node:fs/promises';
import { TripoClient, ModelVersion, TaskStatus } from 'tripo3d-sdk-js';

const apiKey = process.env.TRIPO_API_KEY;
if (!apiKey) throw new Error('TRIPO_API_KEY is required');

const client = new TripoClient({
  apiKey,
  baseUrl: 'https://openapi.tripo3d.ai/v3',
});

const taskId = await client.textToModel({
  prompt: 'a cute red panda holding bamboo',
  model: ModelVersion.H3_1,
  texture: true,
  pbr: true,
  texture_quality: 'detailed',
});

const task = await client.waitForTask(taskId, {
  pollingIntervalMs: 2000,
  onProgress: (value) => console.log(`${value.status} — ${value.progress ?? 0}%`),
});

if (task.status !== TaskStatus.SUCCESS) {
  throw new Error(`Task did not succeed: ${task.status}`);
}

const modelUrl = task.output.model_url ?? task.output.model;
if (!modelUrl) throw new Error('Task returned no model URL');

const response = await fetch(modelUrl);
if (!response.ok) throw new Error(`Download failed: HTTP ${response.status}`);

await writeFile(`tripo-${taskId}.glb`, Buffer.from(await response.arrayBuffer()));
```

### Python

```python
import asyncio
import os
import shutil
from urllib.request import urlopen

from tripo3d import TripoClient
from tripo3d.models import TaskStatus


def download_file(url, path):
    with urlopen(url) as response, open(path, "wb") as output:
        shutil.copyfileobj(response, output)


async def main():
    api_key = os.environ["TRIPO_API_KEY"]
    os.makedirs("./output", exist_ok=True)

    async with TripoClient(api_key=api_key) as client:
        task_id = await client.text_to_model(
            prompt="a cute red panda holding bamboo",
            model_version="v2.5-20250123",
        )
        task = await client.wait_for_task(task_id, verbose=True)

        if task.status != TaskStatus.SUCCESS:
            raise RuntimeError(f"Task did not succeed: {task.status}")

        model_url = task.output.model
        if not model_url:
            raise RuntimeError("Task returned no model URL")

        output_path = "./output/model.glb"
        await asyncio.to_thread(download_file, model_url, output_path)
        print(f"Downloaded model: {output_path}")


asyncio.run(main())
```

### Go

```go
package main

import (
	"context"
	"fmt"
	"log"
	"os"
	"time"

	tripo3d "github.com/VAST-AI-Research/tripo-go-sdk"
)

func main() {
	apiKey := os.Getenv("TRIPO_API_KEY")
	if apiKey == "" {
		log.Fatal("TRIPO_API_KEY is required")
	}

	client, err := tripo3d.NewClient(tripo3d.ClientOptions{
		APIKey:  apiKey,
		BaseURL: "https://openapi.tripo3d.ai/v3",
	})
	if err != nil {
		log.Fatal(err)
	}

	ctx := context.Background()
	taskID, err := client.TextToModel(ctx, tripo3d.TextToModelParams{
		Prompt:         "a cute red panda holding bamboo",
		Model:          tripo3d.String(tripo3d.ModelVersionH31),
		Texture:        tripo3d.Bool(true),
		PBR:            tripo3d.Bool(true),
		TextureQuality: tripo3d.String("detailed"),
	})
	if err != nil {
		log.Fatal(err)
	}

	task, err := client.WaitForTask(ctx, taskID, tripo3d.WaitOptions{
		PollInterval: 2 * time.Second,
	})
	if err != nil {
		log.Fatal(err)
	}
	if task.Status != tripo3d.TaskStatusSuccess {
		log.Fatalf("Task did not succeed: %s", task.Status)
	}

	downloaded, err := client.DownloadModel(ctx, task)
	if err != nil {
		log.Fatal(err)
	}
	if downloaded == nil {
		log.Fatal("Task returned no model URL")
	}

	filename := fmt.Sprintf("tripo-%s.glb", taskID)
	if err := os.WriteFile(filename, downloaded.Data, 0o644); err != nil {
		log.Fatal(err)
	}
}
```

### Rust

```rust
use tokio::fs;
use tripo3d_sdk::{
    constants::model_version,
    params::TextToModelParams,
    ClientOptions,
    TaskStatus,
    TripoClient,
    WaitOptions,
};

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let api_key = std::env::var("TRIPO_API_KEY")?;
    let client = TripoClient::new(ClientOptions {
        api_key: Some(api_key),
        base_url: Some("https://openapi.tripo3d.ai/v3".into()),
        ..Default::default()
    })?;

    let task_id = client
        .text_to_model(TextToModelParams {
            prompt: "a cute red panda holding bamboo".into(),
            model: Some(model_version::H3_1.to_string()),
            texture: Some(true),
            pbr: Some(true),
            texture_quality: Some("detailed".into()),
            ..Default::default()
        })
        .await?;

    let task = client
        .wait_for_task(&task_id, WaitOptions::default())
        .await?;
    if task.status != TaskStatus::Success {
        anyhow::bail!("Task did not succeed: {}", task.status);
    }

    let downloaded = client
        .download_model(&task)
        .await?
        .ok_or_else(|| anyhow::anyhow!("Task returned no model URL"))?;

    fs::write(format!("tripo-{task_id}.glb"), downloaded.data).await?;
    Ok(())
}
```

### Java

```java
import ai.tripo3d.sdk.api.TripoClient;
import ai.tripo3d.sdk.api.TripoClientConfig;
import ai.tripo3d.sdk.api.TripoRegion;
import ai.tripo3d.sdk.model.request.TaskRequestPayload;
import ai.tripo3d.sdk.model.response.TaskDetail;

import java.io.InputStream;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.Map;

public final class TripoQuickStart {
    public static void main(String[] args) throws Exception {
        String apiKey = System.getenv("TRIPO_API_KEY");
        if (apiKey == null || apiKey.trim().isEmpty()) {
            throw new IllegalStateException("TRIPO_API_KEY is required");
        }

        try (TripoClient client = TripoClient.create(
                TripoClientConfig.builder(apiKey)
                        .region(TripoRegion.GLOBAL)
                        .build())) {
            TaskDetail created = client.textToModel(TaskRequestPayload.builder()
                    .prompt("a wooden chair")
                    .model("v3.1-20260211")
                    .build());

            TaskDetail done = client.pollUntilTerminal(created.taskId());
            if (!"success".equalsIgnoreCase(done.status())) {
                throw new IllegalStateException(
                        "Task failed: status=" + done.status()
                                + ", message=" + done.errorMsg());
            }

            Map<String, Object> output = done.output();
            Object modelUrl = output == null ? null : output.get("model_url");
            if (!(modelUrl instanceof String)) {
                throw new IllegalStateException(
                        "Task output does not contain model_url");
            }

            try (InputStream input =
                         new URL((String) modelUrl).openStream()) {
                Files.copy(
                        input,
                        Paths.get("model.glb"),
                        StandardCopyOption.REPLACE_EXISTING);
            }
        }
    }
}
```

JavaScript, Python 및 Java는 서명된 모델 URL에 네이티브 HTTP 클라이언트를 사용하며 `Authorization` 헤더를 첨부하지 않습니다. Go 및 Rust SDK 다운로드 메서드도 API 키 없이 서명된 URL을 가져옵니다.

## 4. V3 라우트 지원

이 매트릭스는 위 고정 버전에서 5개 SDK 구현의 합집합입니다. 체크 표시는 공개 SDK 흐름이 최종 V3 HTTP 라우트에 직접 또는 내부 단계를 통해 도달한다는 뜻이며, 사용되지 않는 라우트 상수는 계산하지 않습니다.

| HTTP 라우트 | 용도 | JavaScript | Python | Go | Rust | Java |
| --- | --- | :---: | :---: | :---: | :---: | :---: |
| `POST /v3/generation/text-to-model` | 텍스트에서 모델 생성 | ✓ | — | ✓ | ✓ | ✓ |
| `POST /v3/generation/image-to-model` | 이미지 한 장에서 모델 생성 | ✓ | — | ✓ | ✓ | ✓ |
| `POST /v3/generation/multiview-to-model` | 여러 시점에서 모델 생성 | ✓ | — | ✓ | ✓ | ✓ |
| `POST /v3/generation/text-to-image` | 텍스트에서 이미지 생성 | ✓ | — | ✓ | ✓ | — |
| `POST /v3/generation/image-to-image` | 이미지 변환 | ✓ | — | ✓ | ✓ | — |
| `POST /v3/generation/image-to-multiview` | 멀티뷰 이미지 생성 | ✓ | — | ✓ | ✓ | ✓ |
| `POST /v3/generation/edit-multiview` | 멀티뷰 출력 편집 | ✓ | — | ✓ | ✓ | — |
| `POST /v3/generation/image-to-splat` | Gaussian splat 생성 | — | — | — | — | ✓ |
| `POST /v3/models/refine` | 초안 모델 개선 | — | — | — | — | ✓ |
| `POST /v3/models/texture` | 텍스처 적용 또는 재생성 | ✓ | — | ✓ | ✓ | ✓ |
| `POST /v3/models/stylize` | 모델 스타일화 | — | — | — | — | ✓ |
| `POST /v3/models/convert` | 모델 형식 변환 | ✓ | — | ✓ | ✓ | ✓ |
| `POST /v3/models/import` | 외부 모델 가져오기 | — | — | — | — | ✓ |
| `POST /v3/mesh/segment` | 메시 분할 | ✓ | ✓ | ✓ | ✓ | ✓ |
| `POST /v3/mesh/complete` | 메시 완성 또는 복구 | ✓ | — | ✓ | ✓ | ✓ |
| `POST /v3/mesh/decimate` | 면 수 감소 | ✓ | — | ✓ | ✓ | ✓ |
| `POST /v3/animations/rig-check` | 모델 리깅 가능 여부 확인 | ✓ | — | ✓ | ✓ | ✓ |
| `POST /v3/animations/rig` | 스켈레톤 연결 | ✓ | — | ✓ | ✓ | ✓ |
| `POST /v3/animations/retarget` | 사전 설정 애니메이션 적용 | ✓ | — | ✓ | ✓ | ✓ |
| `GET /v3/tasks/{task_id}` | 작업 하나 가져오기 | ✓ | ✓ | ✓ | ✓ | ✓ |
| `POST /v3/tasks/list` | 여러 작업 가져오기 | ✓ | — | ✓ | ✓ | ✓ |
| `POST /v3/files` | 파일 업로드 | ✓ | ✓ | ✓ | ✓ | ✓ |
| `POST /v3/files/presign` | 사전 서명 업로드 생성 | — | — | — | — | ✓ |
| `GET /v3/account/balance` | 계정 잔액 가져오기 | ✓ | — | ✓ | ✓ | ✓ |
| `GET /v3/account/usage` | 사용량 기록 가져오기 | — | — | — | — | ✓ |

이 고정 버전에서는 Java만 image-to-splat, refine, stylize, import, presign 및 usage를 제공합니다. Java는 text-to-image, image-to-image 또는 edit-multiview를 제공하지 않습니다. `/v3/files/upload-credentials` 내부 설명자에는 대응하는 서비스나 공개 클라이언트 메서드가 없으므로 지원 대상으로 계산하지 않습니다.

Python은 여전히 주로 V2 SDK입니다. `mesh_segmentation(..., model_version="v2.0-20260430")` 분기에서는 추가로 `POST /v3/mesh/segment`, `GET /v3/tasks/{task_id}`, 로컬 `ref_image` 업로드가 필요한 경우 `POST /v3/files`를 사용합니다.

### Python V2 라우트 지원

Python 0.4.2는 5개의 최종 V2 HTTP 라우트를 제공합니다. `POST /v2/openapi/task`는 생성, 모델 처리, 메시 및 애니메이션 작업 메서드가 공유하며 text-to-model에만 국한되지 않습니다.

| HTTP 라우트 | 용도 |
| --- | --- |
| `POST /v2/openapi/task` | 지원되는 모든 V2 작업 제출 |
| `GET /v2/openapi/task/{task_id}` | 작업 상태 및 출력 조회 |
| `GET /v2/openapi/user/balance` | 계정 잔액 조회 |
| `POST /v2/openapi/upload/sts/token` | `boto3`를 사용할 수 있을 때 STS 업로드 자격 증명 조회 |
| `POST /v2/openapi/upload` | SDK의 레거시 multipart 대체 경로로 파일 업로드 |

Java 및 기타 V3 SDK는 각 공식 V3 매개변수 모델을 통해 모델 선택을 전송합니다. Java 전송 필드 이름은 `model`입니다.

## 5. 문제 해결

- **키 누락:** 서버 프로세스에 `TRIPO_API_KEY`를 설정하세요. [인증](./authentication)을 참조하세요.
- **잘못된 리전:** 사용 중인 SDK 및 API 버전에 맞는 전 세계 또는 중국 엔드포인트를 선택하세요.
- **작업 실패 또는 시간 초과:** `task_id`를 보관하고 최종 상태를 확인한 다음 [작업 수명 주기](./task-lifecycle)와 [오류 처리](./error-handling)를 참조하세요.
- **모델 URL 만료:** SDK에서 지원하는 경우 작업을 다시 조회한 다음 모델을 즉시 다운로드하세요. 임시 서명 URL을 영구 자산으로 저장하지 마세요.

## 공식 저장소

- [JavaScript SDK](https://github.com/VAST-AI-Research/tripo-js-sdk)
- [Python SDK](https://github.com/VAST-AI-Research/tripo-python-sdk)
- [Go SDK](https://github.com/VAST-AI-Research/tripo-go-sdk)
- [Rust SDK](https://github.com/VAST-AI-Research/tripo-rust-sdk)
- [Java SDK](https://github.com/VAST-AI-Research/tripo-java-sdk)
