# @decartai/sdk 中文文档

规范地址：https://npmcn.com/package/%40decartai/sdk/

版本：0\.2\.14
npm 元数据更新时间：2026-10-25T09:14:50.766Z
中文译文更新时间：2026-11-11T18:56:56.932Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40decartai/sdk
原文对照：https://npmcn.com/package/%40decartai/sdk/?lang=original
项目主页：https://github.com/decartai/sdk#readme
源码仓库：https://github.com/DecartAI/sdk

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：357 kB，79 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- 运行依赖：5 个
- 首次发布：2025-09-30T09:17:35.492Z
- 最新版本发布：2026-10-25T09:14:50.401Z
- 近 30 天下载量：225078（2026-10-12 至 2026-11-10，npm 官方下载统计）
- 已发布版本数：104（近 12 个月 95 个）

## 中文简介

Decart 的 Java 脚本 SDK

## 安装

```sh
npm install @decartai/sdk
```

也可以使用：`pnpm add @decartai/sdk`、`yarn add @decartai/sdk`、`bun add @decartai/sdk`

## README

# 解密SDK

一个JavaScript SDK,用于德卡特的模型.

## 安装

```bash
npm install @decartai/sdk
# or
pnpm add @decartai/sdk
# or
yarn add @decartai/sdk
```

## 文档

完整文件、指南和实例访问: **[https://docs.platform.decart.ai/sdks/javascript](https://docs.platform.decart.ai/sdks/javascript)**

## 快速启动

### 实时视频转换

实时连接在SDK中被LiveKit支持. 现有客户用途保持不变: 相机 `MediaStream`,选择一个实时模型,并处理已变换的远程流.

```typescript
import { createDecartClient, models } from "@decartai/sdk";

const model = models.realtime("lucy-restyle-2");

// Get user's camera stream
const stream = await navigator.mediaDevices.getUserMedia({
  audio: true,
  video: { 
        frameRate: model.fps,
        width: model.width,
        height: model.height,
  }
});

// Create a client
const client = createDecartClient({
  apiKey: "your-api-key-here"
});

// Connect and transform the video stream
const realtimeClient = await client.realtime.connect(stream, {
  model,
  onRemoteStream: (transformedStream) => {
    videoElement.srcObject = transformedStream;
  },
  initialState: {
    prompt: {
      text: "Anime",
      enhance: true
    }
  }
});

// Change the style on the fly
realtimeClient.setPrompt("Cyberpunk city");

// Disconnect when done
realtimeClient.disconnect();
```

#### 前相机镜像

预放输入流 :

```ts
const realtimeClient = await client.realtime.connect(stream, {
  model,
  mirror: "auto", // or true to always mirror
  // ...
});
```

选项 :

-   `false` (默认)——永远不要镜像.
-   `"auto"` 输入轨道报告时镜像 `facingMode: "user"` (移动前相机).
-   `true` ——总是镜像(例如桌面网络相机).

#### 远程音频

服务器的音频音轨是您发布的音频, 与已转换的视频同步播放 (模型增加了潜伏度,所以服务器会延迟您的音频以匹配). SDK只订阅它 当您的输入流带有音频音轨时; 远程流同时带有视频和音频 音轨,您应该播放远程音频 而不是您的本地麦克风 这样的声音和图片 保持同步。 只有视频输入流从不订阅,所以远程流没有音频音轨和 iOS不显示播放任何远程音频会触发的麦克风许可提示 .

#### 快取模式

快取模式( E)`speed: "fast"`) 以较高的计算级别为会议服务,以降低延迟度和较高的吞吐量;产出质量不变。 目前可供 `lucy-2.6`, (中文(简体) ), `lucy-2.5` 编号 : `lucy-latest` 财务报告和审定财务报表 `lucy-vton-3.6` 编号 : `lucy-vton-3.5` 编号 : `lucy-vton-latest`并按2x的标准实时费率计费。 其他模型忽略了选项. 关闭标准模式的默认值 .

```ts
const realtimeClient = await client.realtime.connect(stream, {
  model: models.realtime("lucy-2.5"),
  speed: "fast",
  // ...
});
```

提供快速模式的模型在定义中列出 `supportedSpeeds`数字 :

```ts
models.realtime("lucy-2.5").supportedSpeeds; // ["fast"]
models.realtime("lucy-2.1").supportedSpeeds; // undefined
```

通过 `speed` 对于一个没有容量的模型,通过客户端的日志记录一个警告,会话以标准速度运行.

#### 连接重试并拒绝会话

失败的连接会在前以指数回放(1 s- 10 s) 重拨最多5次 `connect()` 拒绝。 两次拒绝从未被重审,因为服务器会给出相同的答案: a 政策关闭(代码1008)和API 密钥的会话限制(接近 1013 “会话限制 已经到达。 会话限制拒绝 `connect()` 使用服务器信件的第一次尝试 (单位:千美元)`Concurrent session limit reached.`如果在届会确定后着陆,则届会结束 带有 `sessionEnded` 活动 `reason` 实值 `"session_limit"`。拒绝容量( 1013 “再次尝试” ) 后")是短暂的并仍在重复.

当服务器因能力不足拒绝拨号时,它也会发送 `error_type: "capacity"` (单位:千美元) `retry_after` 在几秒钟. `connect()` 然后等那么长(±20%焦急,至少1 s)和拨号 再说一次,只要 `capacityRetryBudgetMs` 允许(自第一次拨号起默认为60 000 ms),在 以服务器错误拒绝 . `retries: 0` 把这些再拨掉. `onCapacityWait` 报告 每个等待让应用程序显示:

```ts
const realtimeClient = await client.realtime.connect(stream, {
  model,
  capacityRetryBudgetMs: 30_000,
  onCapacityWait: ({ retryAfterMs }) => showStatus(`Server busy, retrying in ${Math.round(retryAfterMs / 1000)} s`),
  // ...
});
```

从会话队列中发出连接的应用程序应该关闭重试: 每一次重试都是一个 新的拨号,在排队等候的人之前需要一个空出的位置.

```ts
const realtimeClient = await client.realtime.connect(stream, {
  model,
  retries: 0, // dial once; on failure, rejoin your own queue
  // ...
});

realtimeClient.on("sessionEnded", ({ reason }) => {
  // "session_limit" | "policy_violation" | "moderation_violation" | "insufficient_credits" | ...
});
```

### 注意流线

连接的实时会话会暴露 SDK `subscribeToken` 一旦它到达一个 连接状态 。 和观众分享SDK的标志 `client.realtime.subscribe` 使用它从Decart请求只接收 LiveKit 证书,然后连接到 用于样式输出流的 LiveKit 房间。 不需要摄取相机 . 浏览器生成的流可以包括LiveKit帧元数据用于玻璃到玻璃 耐用,所以观众也需要浏览器运行时间,可以创建SDK的 fram-metadata 工作者; 不支持的运行时间在加入前拒绝这些符号 .

> **查看器必须是在这个 SDK 版本或更新.** 现在的浏览器发布器 默认发布帧时间, 这使得服务器附加一个数据包 拖车在房间里的每一个框架。 年长的观众 `@decartai/sdk` 忽略符号 `frame_timing` 在没有脱衣工的情况下加入 连接成功但解码为无, 因此视频元素保持黑色 没有产生错误。 本地观众完全无法脱去拖车 以 `UNSUPPORTED_PLATFORM_FEATURE`。在升级前升级观众 出版社.

**制作人** ——抓取当前会话中的符号:

```typescript
const realtimeClient = await client.realtime.connect(stream, {
  model,
  onRemoteStream: (transformedStream) => {
    videoElement.srcObject = transformedStream;
  },
});

realtimeClient.on("connectionChange", (state) => {
  if ((state === "connected" || state === "generating") && realtimeClient.subscribeToken) {
    const subscribeToken = realtimeClient.subscribeToken;
    // Pass `subscribeToken` to the viewer snippet below.
  }
});
```

**查看器** ——附送出品人相克之流:

```typescript
import { createDecartClient, type RealTimeSubscribeClient } from "@decartai/sdk";

const client = createDecartClient({ apiKey: "your-api-key-here" });

const subscriber: RealTimeSubscribeClient = await client.realtime.subscribe({
  token: subscribeToken,
  onRemoteStream: (stream) => {
    videoElement.srcObject = stream;
  },
});

subscriber.on("connectionChange", (state) => {
  console.log(`Viewer state: ${state}`);
});

// Disconnect when done
subscriber.disconnect();
```

**带有会话输入的查看器** - 也收到出版商寄来的东西(其相机和 麦克风),例如显示样式输出旁边的正本:

```typescript
const subscriber = await client.realtime.subscribe({
  token: subscribeToken,
  onRemoteStream: (stream) => {
    outputVideo.srcObject = stream;
  },
  onInputStream: (stream) => {
    inputVideo.srcObject = stream;
  },
  inputVideoQuality: "low", // "low" | "medium" | "high" (default)
});
```

无 `onInputStream` 输入永远不会被下载. `inputVideoQuality` 设置最高 要接收的输入视频的 simulcast 层; SFU 仍然在带宽需要时向下走.

### 连接质量

有两层:a **飞行前** 连接前检查,以及 **会期** 质量 在连接时发出信号。 两份关于共享 `"good" | "fair" | "poor" | "critical"` 比例- sDK报告,你决定怎么做(打开UI,警告用户等).

**飞行前(连接前).** 快速的,网络专用的可达性检查——它旋转起a 因此没有会话和费用:

```typescript
const { quality, metrics, reasons } = await client.realtime.checkConnectivity();
// metrics: { transport: "udp" | "relay" | "failed", rttMs }
if (quality === "critical") showFallbackUI(reasons);
```

**会期质量.** 在连接时, SDK 从 WebRTC 数据中得出一个平滑的判决 (纬度、数据包丢失、带宽室、帧率)并告诉你哪个维度是 瓶颈 :

```typescript
const realtimeClient = await client.realtime.connect(stream, {
  model,
  onRemoteStream: (s) => { videoElement.srcObject = s; },
  onConnectionQuality: ({ quality, limitingFactor, metrics }) => {
    // limitingFactor: "bandwidth" | "latency" | "loss" | "stall" | "cpu" | "none"
    // metrics: { rttMs, fps, packetLoss, upstreamJitterMs, availableUpstreamKbps, ... }
    console.log(quality, limitingFactor);
  },
});

// also available as an event and a getter:
realtimeClient.on("connectionQuality", (report) => { /* ... */ });
realtimeClient.getConnectionQuality(); // latest report, or null before the first sample
```

> `onConnectionQuality` 编辑 `connectionQuality` 事件为 **已卸载** 他们只重新开火 当判决时`quality`编号 :`limitingFactor`)变化,所以它们不是活的量子饲料. 对a 连续读取原始数字,更新每个数据勾选(~1/s),使用 `stats` 事件或 民意调查 `getConnectionQuality()?.metrics`数字 :
> 
> ```typescript
> realtimeClient.on("stats", (s) => updateLatencyHud(s.glassToGlass?.medianMs, s.video?.framesPerSecond));
> // or, on your own interval:
> setInterval(() => console.log(realtimeClient.getConnectionQuality()?.metrics.g2gMs), 1000);
> ```

**玻璃对玻璃后座.** 网络RTT在实时视频中隐藏主导成本——模式 推论——所以一个会话可以读出"好",而实际上可以感觉出拉吉. 在浏览器会话中, SDK 当需要的工人是 LiveKit 帧元数据时,自动附加一个捕获时间戳 可用; 服务器通过推论传播, SDK 匹配以输出播放. 这个表面 **启动** (单位:千美元)`ttffMs`和 **稳态** (单位:千美元)`g2gMs`延缓。 现在, 由玻璃对玻璃驱动,而不是RTT.

> 框架元数据目前在LiveKit中是实验性的,需要编码-转换支持. 它不会改变可见像素 . `g2gDropRatio` 遗 物 `null` 直到框架标识被传播 通过服务器管道和时间戳.

```typescript
const realtimeClient = await client.realtime.connect(stream, {
  model,
});

// g2g updates every stats tick — read it from the `stats` event (the
// `connectionQuality` verdict is debounced and would go stale between changes):
realtimeClient.on("stats", ({ glassToGlass }) => {
  console.log(glassToGlass?.ttffMs, glassToGlass?.medianMs);
});
```

对a _测量_ 连接前的判决(而不是只检查网络),使用 **深处 探测器**:它短暂地打开了一个真实的会话 合成源, 测量玻璃对玻璃,然后 撕下来。 这需要 `model` 并花费一个短的 GPU 会话 :

```typescript
const probe = await client.realtime.checkConnectivity({ deep: true, model });
console.log(probe.quality, probe.metrics.g2gMs, probe.metrics.ttffMs);
```

### Async 处理( API 队列)

对于视频生成任务,使用队列 API 提交任务和结果民意调查:

```typescript
import { createDecartClient, models } from "@decartai/sdk";

const client = createDecartClient({
  apiKey: "your-api-key-here"
});

// Submit and poll automatically
const result = await client.queue.submitAndPoll({
  model: models.video("lucy-latest"),
  prompt: "Make it look like a watercolor painting",
  data: videoFile,
  onStatusChange: (job) => {
    console.log(`Status: ${job.status}`);
  }
});

if (result.status === "completed") {
  videoElement.src = URL.createObjectURL(result.data);
} else {
  console.error("Job failed:", result.error);
}
```

或手动管理投票:

```typescript
// Submit the job
const job = await client.queue.submit({
  model: models.video("lucy-latest"),
  prompt: "Make it look like a watercolor painting",
  data: videoFile
});
console.log(`Job ID: ${job.job_id}`);

// Poll for status
const status = await client.queue.status(job.job_id);
console.log(`Status: ${status.status}`);

// Get result when completed
if (status.status === "completed") {
  const blob = await client.queue.result(job.job_id);
  videoElement.src = URL.createObjectURL(blob);
}
```

### 客户端

薄荷短寿命客户端在您的服务器上代号, 而不是传送您的 API 密钥 . 答复中还附有一份署名的JWT(`token`任何服务器或边缘运行时间 可以验证 **离线** 对平台的公开 JWKS —— 没有 API 键, 没有 往返至德甲 :

```ts
import { createDecartClient, verifyClientToken, decodeClientToken } from "@decartai/sdk";

const client = createDecartClient({ apiKey: process.env.DECART_API_KEY });
const { apiKey, token } = await client.tokens.create({ expiresIn: 300, metadata: { service_tier: 0 } });

// Verify offline (EdDSA signature, exp, iss, aud) and read the claims
const claims = await verifyClientToken(token); // or client.tokens.verify(token)
claims.serviceTier; // 0
claims.pool; // "free" for tier 0, otherwise "paid"
// also: userId, organizationId, apiKeyName, apiKeyId, allowedModels, allowedOrigins,
// expiresAt, realtimeConcurrentSessionLimit, zeroDataRetention, attribution, raw

// Read claims WITHOUT verifying — no network, no crypto. Untrusted: display/logging only.
const untrusted = decodeClientToken(token);
```

JWKS来自 `https://platform.decart.ai/api/auth/jwks` (平台) 没有主机 `baseUrl`)并被缓存; JWT 库被如此懒散地装入 永远不能核实,不要运送。 错误 : `TOKEN_INVALID`, (中文(简体) ), `TOKEN_EXPIRED`, (中文(简体) ), `TOKEN_VERIFY_ERROR` (JWKS无法到达). 选项 : `{ jwksUrl, issuer, audience, clockTolerance }`。这是离线检查,不是API电话。 它需要 WebCrypto: 打开 无此功能的运行时间( React Industrial) `verify` 拒绝方式 `UNSUPPORTED_PLATFORM_FEATURE`· ; `decodeClientToken` 到处工作.

#### 托肯寿命:连接前的薄荷

客户签名过期 **60秒钟** 默认的薄荷后( e)`expiresIn`, 1-3600 s) (中文(简体) ). 一个标志 在页面载荷或组件挂载上被铸造的,通常在用户授予相机时已死 访问并按下开始, 稍后与同一种符号的重接也会被拒绝 。 SDK读取 标志 `exp` 在每次实时拨号之前(连接、重试和重接)并拒绝一个 已过期 `TOKEN_EXPIRED` 而不是拨号: 没有打开套接字, 消息说如何 很久以前就过期了 几秒钟的时钟被容忍.

两种方法保持 标志新鲜:

-   早点把它薄荷 `connect()`之后 `getUserMedia` 和用户的点击和大小 `expiresIn` 连接窗口,例如. `client.tokens.create({ expiresIn: 300 })`。 。 。 .
-   过 `apiKeyProvider` 而不是(或同时) `apiKey`. SDK在每次连接之前都叫它 并用它得来的东西重新连接和拨号,每个拨号都携带一个铸造的印记:

```ts
const client = createDecartClient({
  apiKeyProvider: async () => {
    // Your server: `client.tokens.create(...)` with your permanent API key.
    const res = await fetch("/api/realtime-token", { method: "POST" });
    const { apiKey } = await res.json();
    return apiKey;
  },
});

const realtimeClient = await client.realtime.connect(stream, { model, onRemoteStream });
```

如果供应商拒绝 `connect()`, (中文(简体) ), `connect()` 以这个错误拒绝; 在 重新连接一个提供者的故障会像其它的拨号故障一样被重试.

供应商还提供服务 `process`, (中文(简体) ), `queue`, (中文(简体) ), `files` 财务报告和审定财务报表 `tokens`: SDK之前就叫它来着 每个 HTTP 请求, 包括每个 `submitAndPoll` 状态民调和结果下载,所以一个 客户端也为批量任务工作(代理模式从不为HTTP请求调用). SDK没有 缓存它返回的东西; 提供者可能会发出它早先铸造的标志, 而该标志仍然存在 足够的生命了。 API在请求体完全到达后检查了信使,所以使用了一个信使 上传必须超过上传:用薄荷薄荷 `expiresIn` 它覆盖了您最大的上传.

### 反应原生/博览会

实时反应原生需要 [LiveKit 的回放本地软件包](https://github.com/livekit/client-sdk-react-native) 和早点 `registerGlobals()` 电话 平面 `react-native-webrtc` 没有 已支持。 SDK进口和 `createDecartClient(...)` 用法不变.

```sh
npm install @decartai/sdk livekit-client@2.20.1 \
  @livekit/react-native@2.11.1 \
  @livekit/react-native-webrtc@144.1.1
```

从在路由器或应用程序之前运行的副作用模块调用 LiveKit 设置 切入点 :

```ts
// livekit-bootstrap.ts
import { registerGlobals } from "@livekit/react-native";

registerGlobals();
```

```ts
// index.ts
import "./livekit-bootstrap";
import "expo-router/entry"; // or import your root App component
```

随着全球注册,实时使用与网络上相同. 使用 模型的数值 FPS 当配置本地相机捕获,然后通过 `MediaStream` 给SDK:

```ts
import { createDecartClient, models, resolveFpsNumber } from "@decartai/sdk";
import { mediaDevices } from "@livekit/react-native-webrtc";

const client = createDecartClient({ apiKey: "your-api-key-here" });
const model = models.realtime("lucy-2.5");
const captureFps = resolveFpsNumber(model.fps);

const cameraStream = await mediaDevices.getUserMedia({
  audio: false,
  video: {
    facingMode: "user",
    frameRate: captureFps,
    width: model.width,
    height: model.height,
  },
});

const realtimeClient = await client.realtime.connect(cameraStream, {
  model,
  preferredVideoCodec: "vp8",
  onRemoteStream,
});
```

对于 Expo,请安装配置插件 :

```sh
npm install @livekit/react-native-expo-plugin@1.0.2 \
  @config-plugins/react-native-webrtc
```

把它们添加到 `app.json`数字 :

```json
{
  "expo": {
    "plugins": [
      "@livekit/react-native-expo-plugin",
      "@config-plugins/react-native-webrtc"
    ]
  }
}
```

运行 `npx expo prebuild` 重建本地应用程序。 LiveKit 不在博览会运行 开始 赤裸回放原生应用程序必须遵循LiveKit的原生设置指令.

发送 `mirror` 和深层连通性飞行前仅限浏览器且与失败 `UNSUPPORTED_PLATFORM_FEATURE` 在反应土著。 与您一起映射本地预览 改为本土视频取景.

## 发展

### 设置

```bash
pnpm install
```

### 发展指挥部

-   `pnpm build` - 建设项目
-   `pnpm dev:example` - 运行 Vite dev 服务器以获取实例
-   `pnpm test` - 运行单元测试
-   `pnpm test:e2e` - 运行端到端测试
-   `pnpm typecheck` - 使用类型脚本进行类型检查
-   `pnpm format` - 有Biome格式代码
-   `pnpm lint` - 与Biome的林特密码

### 出版

1.  **版本缓冲**运行 `pnpm release` 以折叠版本( 此使用) `bumpp` 以创建新版本标签)并推到 GitHub
2.  **自动出版**: GitHub 动作工作流程将:

-   构建工程
-   发布到 npm
-   创建带有更改日志的 GitHub 发布

软件包以 npm 的形式发布 `@decartai/sdk`。 。 。 .

## 许可证

麻省理工学院

## 常见问题

### @decartai/sdk 是什么？

Decart 的 Java 脚本 SDK

### 如何安装 @decartai/sdk？

在项目目录运行 npm install @decartai/sdk，或使用 pnpm add / yarn add / bun add。

### @decartai/sdk 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @decartai/sdk 支持 ESM 还是 CommonJS？

以 ES Module 形式发布，推荐使用 import 引入。在 CommonJS 项目中，Node\.js 20\.19\+ / 22\.12\+ 可以直接 require\(\) 不含顶层 await 的 ES Module，更早的版本需要改用动态 import\(\)。

### @decartai/sdk 可以商用吗？

@decartai/sdk 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @decartai/sdk 的下载量有多少？

根据 npm 官方下载统计，@decartai/sdk 在 2026/10/12 – 2026/11/10 这 30 天内被下载 225,078 次，日均约 7,503 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @decartai/sdk 还在维护吗？

最新版本 0\.2\.14 发布于 2026/10/25（17 天前）；至今共发布 104 个版本，其中过去 12 个月发布了 95 个；首次发布于 2025/09/30。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

