---
title: JavaScript 示例
description: 使用原生 fetch 建立、輪詢並下載影片任務。
icon: file-json
---

以下示例適用於 Node.js 18 及更高版本，使用原生 `fetch` 完成完整非同步任務流程。

## 環境變數

```bash
export BLACKPIG_API_KEY="sk-your-api-key"
```

## 完整示例

```javascript
import { createWriteStream } from 'node:fs';
import { Readable } from 'node:stream';
import { pipeline } from 'node:stream/promises';

const baseURL = 'https://api.heizhu.lol';
const apiKey = process.env.BLACKPIG_API_KEY;

if (!apiKey) {
  throw new Error('BLACKPIG_API_KEY is required');
}

async function request(path, options = {}) {
  const response = await fetch(`${baseURL}${path}`, {
    ...options,
    headers: {
      Authorization: `Bearer ${apiKey}`,
      ...options.headers,
    },
  });

  if (!response.ok) {
    throw new Error(`HTTP ${response.status}: ${await response.text()}`);
  }

  return response;
}

async function createVideo() {
  const response = await request('/v1/videos', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      model: 'L-stable-seedance-2-0-933-720p',
      prompt: '电影感近景，人物在雨夜街道缓慢回头，镜头平稳推进',
      duration: 1,
      video_duration: 15,
      aspect_ratio: '9:16',
      resolution: '720p',
      image_urls: ['https://example.com/reference.jpg'],
    }),
  });

  return response.json();
}

async function waitForVideo(taskId) {
  while (true) {
    const response = await request(`/v1/videos/${taskId}`);
    const task = await response.json();

    console.log(`${task.status} ${task.progress}%`);

    if (task.status === 'completed') return task;
    if (task.status === 'failed') {
      throw new Error(task.error?.message || 'Video generation failed');
    }

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

async function downloadVideo(taskId, outputPath) {
  const response = await request(`/v1/videos/${taskId}/content`);
  await pipeline(Readable.fromWeb(response.body), createWriteStream(outputPath));
}

const task = await createVideo();
console.log(`Created: ${task.id}`);

await waitForVideo(task.id);
await downloadVideo(task.id, 'result.mp4');
console.log('Saved: result.mp4');
```

## 生產環境建議

- 為建立和查詢請求分別設定超時。
- 將任務 ID 儲存到資料庫，不依賴單個程序持續執行。
- 使用任務佇列或定時任務執行輪詢。
- 對 `429`、`502` 和 `503` 使用有限指數退避。
- 下載結果時使用流，不要把大檔案完整載入記憶體。

