npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

router-brain-sdk

v1.0.1

Published

Router Brain SDK

Readme

@router-brain/sdk

Router Brain 的官方 Node.js SDK。通过统一入口调用 LLM 网关(OpenAI 兼容接口)、Anthropic 接口、图片生成接口和视频生成接口。


目录


安装

pnpm add @router-brain/sdk

SDK 已声明 openai@anthropic-ai/sdk 为运行时依赖。


快速开始

import { RouterBrain } from '@router-brain/sdk';

const rb = new RouterBrain('sk-your-api-key-here');

// === OpenAI Chat ===
const chat = await rb.openai().chat.completions.create({
  model: 'gpt-4o',
  messages: [{ role: 'user', content: '你好,讲个笑话' }],
});
console.log(chat.choices[0].message.content);

// === Anthropic Messages ===
const msg = await rb.anthropic().messages.create({
  model: 'claude-sonnet-4-20250514',
  max_tokens: 1024,
  messages: [{ role: 'user', content: '写一首关于春天的诗' }],
});
console.log(msg.content[0].text);

// === 图片生成 ===
const result = await rb.image({
  model: 'dall-e-3',
  prompt: '一只可爱的橘猫在阳光下打盹',
  size: '1024x1024',
}).json();
console.log(result.data[0].url);

// === 视频生成 ===
const video = await rb.video({
  model: 'wan2.1-t2v-turbo',
  prompt: '夜晚城市街道的电影感推进镜头',
  resolution: '720p',
}).task();
console.log(video.data[0]?.url);

// === 模型列表 ===
const models = await rb.models('text', { q: 'gpt-4o' });
console.log(models.data[0].pricing.prompt);

// === 文档重排 ===
const ranked = await rb.rerank({
  model: 'rerank-model',
  query: 'RAG 检索',
  documents: ['doc1', 'doc2'],
});
console.log(ranked.results[0].relevance_score);

配置

1. 通过 API Key 字符串初始化

const rb = new RouterBrain('sk-your-api-key');

网关地址默认为 https://51kik.com

2. 通过配置对象初始化

const rb = new RouterBrain({
  apiKey: 'sk-your-api-key',
});

3. 自定义网关地址

自建部署或私有化环境时传入 baseUrl

const rb = new RouterBrain({
  apiKey: 'sk-your-api-key',
  baseUrl: 'https://gateway.your-company.com',  // 你的网关地址
});

baseUrl 只需传入根域名或根地址,SDK 会自动拼接路径前缀(如 /v1/anthropic/v1/image/v1/generations)。


OpenAI 接口

通过 rb.openai() 获取 OpenAI SDK 实例(openai npm 包),所有请求自动路由到 {baseUrl}/v1

Chat Completions

const rb = new RouterBrain('sk-xxx');

// 基本对话
const res = await rb.openai().chat.completions.create({
  model: 'gpt-4o',
  messages: [
    { role: 'system', content: '你是一个助手' },
    { role: 'user', content: '南京今天天气怎么样?' },
  ],
});
console.log(res.choices[0].message.content);

// 流式对话
const stream = await rb.openai().chat.completions.create({
  model: 'gpt-4o',
  messages: [{ role: 'user', content: '讲个故事' }],
  stream: true,
});
for await (const chunk of stream) {
  process.stdout.write(chunk.choices[0]?.delta?.content || '');
}

// 带函数调用
const res2 = await rb.openai().chat.completions.create({
  model: 'gpt-4o',
  messages: [{ role: 'user', content: '北京的天气如何?' }],
  tools: [{
    type: 'function',
    function: {
      name: 'get_weather',
      parameters: {
        type: 'object',
        properties: {
          city: { type: 'string' },
        },
      },
    },
  }],
});

Embeddings

const res = await rb.openai().embeddings.create({
  model: 'text-embedding-3-small',
  input: '需要向量化的文本',
});
console.log(res.data[0].embedding); // number[]

Responses API

const res = await rb.openai().responses.create({
  model: 'gpt-4o',
  input: '写一首关于秋天的诗',
});
console.log(res.output_text);

rb.openai() 返回的是完整的 OpenAI SDK 实例,所有 OpenAI 官方支持的方法(chat.completionsembeddingsresponsesimagesmodels 等)都可用。

暂未实现的接口

以下 OpenAI 标准接口网关已注册路由但尚未实现,调用会返回 501 错误:

| 接口 | 状态 | |------|------| | POST /v1/audio/speech | ❌ 暂不支持 TTS | | POST /v1/files / GET /v1/files | ❌ 暂不支持文件管理 |

try {
  await rb.openai().audio.speech.create({ ... });
} catch (err) {
  if (err instanceof OpenAI.APIError && err.status === 501) {
    console.log('TTS 功能尚未上线');
  }
}

Anthropic 接口

通过 rb.anthropic() 获取 Anthropic SDK 实例(@anthropic-ai/sdk),所有请求自动路由到 {baseUrl}/anthropic/v1

Messages

const rb = new RouterBrain('sk-xxx');

// 基本消息
const res = await rb.anthropic().messages.create({
  model: 'claude-sonnet-4-20250514',
  max_tokens: 1024,
  messages: [
    { role: 'user', content: '用中文解释量子计算的基本原理' },
  ],
});
console.log(res.content[0].text);

// 流式响应
const stream = rb.anthropic().messages.stream({
  model: 'claude-sonnet-4-20250514',
  max_tokens: 1024,
  messages: [{ role: 'user', content: '讲一个长篇科幻故事' }],
}).on('text', (text) => {
  process.stdout.write(text);
});

await stream.finalMessage();

// 带 system prompt
const res2 = await rb.anthropic().messages.create({
  model: 'claude-sonnet-4-20250514',
  max_tokens: 1024,
  system: '你是一位资深 Python 工程师,只输出代码。',
  messages: [
    { role: 'user', content: '写一个快速排序的实现' },
  ],
});

rb.anthropic() 返回的是完整的 Anthropic SDK 实例,所有 Anthropic 官方支持的方法(messagesstream 等)都可用。


Models 接口

RouterBrain 提供统一的模型目录方法,第一个参数用于区分目录类型。当前支持 textimagevideo

接口速览

| SDK 方法 | 服务端接口 | 说明 | |----------|------------|------| | rb.models('text', params) | GET /v1/models | 文本模型目录,OpenRouter 兼容格式 | | rb.models('image', params) | GET /image/v1/models | 图片模型目录,包含驱动、计费方式和对客价格 | | rb.models('video', params) | GET /video/v1/models | 视频模型目录,包含驱动、计费方式和对客价格 | | rb.endpoints('text', code) | GET /v1/models/:code/endpoints | 文本模型可用上游 endpoint | | rb.endpoints('image', code) | GET /image/v1/models/:code/endpoints | 图片模型可用上游 endpoint | | rb.endpoints('video', code) | GET /video/v1/models/:code/endpoints | 视频模型可用上游 endpoint | | rb.providers('text') | GET /v1/providers | 文本模型供应商聚合 | | rb.providers('image', params) | GET /image/v1/providers | 图片生成驱动聚合 | | rb.providers('video', params) | GET /video/v1/providers | 视频生成驱动聚合 |

搜索模型列表

通过 rb.models(type, params) 查询可用模型。type='text' 请求 GET {baseUrl}/v1/models,响应格式与 OpenRouter /api/v1/models 兼容;type='image' 请求 GET {baseUrl}/image/v1/modelstype='video' 请求 GET {baseUrl}/video/v1/models

// 列出全部文本模型
const all = await rb.models('text');
console.log(all.data.length, 'models available');

// 搜索文本模型
const models = await rb.models('text', { q: 'gpt-4' });
for (const m of models.data) {
  console.log(m.id, m.pricing.prompt, '/', m.pricing.completion);
}

// 按供应商过滤文本模型
const openaiModels = await rb.models('text', { provider: 'openai' });

// 按标签过滤 + 分页 + 排序
const result = await rb.models('text', {
  tags: ['vision'],
  limit: 5,
  sort: 'newest',
});
console.log(result.has_more ? '还有更多' : '最后一页');

// 搜索图片模型
const imageModels = await rb.models('image', {
  q: 'seedream',
  billingMethods: ['images'],
  limit: 10,
});
console.log(imageModels.data[0].drives[0].name);

// 搜索视频模型
const videoModels = await rb.models('video', {
  q: 'wan',
  billingMethods: ['duration'],
  limit: 10,
});
console.log(videoModels.data[0].pricing[0]);

TextModelsQueryParams 参数说明:

| 参数 | 类型 | 说明 | |------|------|------| | q | string | 按 code/name/description 模糊搜索 | | provider | string | 按公开供应商 code 过滤 | | tags | string[] | 标签过滤(如 ['vision', 'fast']) | | inputModalities | string[] | 输入模态过滤 | | outputModalities | string[] | 输出模态过滤 | | supportedParameters | string[] | 支持的参数过滤 | | limit | number | 分页条数(1-100) | | offset | number | 跳过条数 | | sort | 'newest' \| 'name' \| 'code' | 排序方式 |

ImageModelsQueryParams 参数说明:

| 参数 | 类型 | 说明 | |------|------|------| | q | string | 按 model code/description/drive 模糊搜索 | | drive | string \| string[] | 按图片驱动过滤 | | billingMethods | ('images' \| 'tokens')[] | 按计费方式过滤 | | limit | number | 分页条数(1-100) | | offset | number | 跳过条数 | | sort | 'newest' \| 'drive' \| 'code' | 排序方式 |

VideoModelsQueryParams 参数说明:

| 参数 | 类型 | 说明 | |------|------|------| | q | string | 按 model code/description/drive 模糊搜索 | | drive | string \| string[] | 按视频驱动过滤 | | billingMethods | ('duration' \| 'tokens' \| 'modality_tokens')[] | 按计费方式过滤 | | limit | number | 分页条数(1-100) | | offset | number | 跳过条数 | | sort | 'newest' \| 'drive' \| 'code' | 排序方式 |

查看模型 Endpoint 详情

通过 rb.endpoints(type, code) 获取单个模型的上游路由信息。type='text' 请求 GET {baseUrl}/v1/models/:code/endpointstype='image' 请求 GET {baseUrl}/image/v1/models/:code/endpointstype='video' 请求 GET {baseUrl}/video/v1/models/:code/endpoints

const detail = await rb.endpoints('text', 'gpt-4o');

console.log(detail.name);                    // 模型名称
console.log(detail.pricing.prompt);          // 提示词单价
console.log(detail.tags);                    // 标签列表

// 各上游端点的实时状态
for (const ep of detail.endpoints) {
  console.log(ep.provider_name);              // 供应商名称
  console.log(ep.latency_30m);                // 近30分钟平均延迟(ms)
  console.log(ep.uptime_5m);                  // 近5分钟可用率
  console.log(ep.supports_implicit_caching);  // 是否支持缓存
}

const imageDetail = await rb.endpoints('image', 'doubao-seedream-4-0-250828');
for (const ep of imageDetail.endpoints) {
  console.log(ep.drive_name, ep.billing_method, ep.pricing);
}

const videoDetail = await rb.endpoints('video', 'wan2.1-t2v-turbo');
for (const ep of videoDetail.endpoints) {
  console.log(ep.drive_name, ep.billing_method, ep.pricing);
}

TextModelEndpointsResponse 结构:

interface TextModelEndpointsResponse {
  id: string;
  name: string;
  created: number;
  description: string;
  architecture: { modality: string; input_modalities: string[]; output_modalities: string[] };
  endpoints: TextModelEndpointItem[];   // 各上游路由详情
  pricing: { prompt: string; completion: string; ... };  // 定价
  discount: number;
  fiat_currency?: string;
  context_length: number | null;
  tags: string[];
}

ImageModelEndpointsResponse 结构:

interface ImageModelEndpointsResponse {
  id: string;
  canonical_slug: string;
  name: string;
  description: string;
  created: number;
  billing_methods: Array<'images' | 'tokens'>;
  drives: Array<{ id: string; name: string }>;
  fiat_currency: string;
  available_routes: number;
  endpoints: ImageModelEndpointItem[];
}

VideoModelEndpointsResponse 结构:

interface VideoModelEndpointsResponse {
  id: string;
  canonical_slug: string;
  name: string;
  description: string;
  created: number;
  billing_methods: Array<'duration' | 'tokens' | 'modality_tokens'>;
  drives: Array<{ id: string; name: string }>;
  fiat_currency: string;
  available_routes: number;
  endpoints: VideoModelEndpointItem[];
}

查看供应商/驱动目录

通过 rb.providers(type, params) 获取公开供应商或驱动目录。

const textProviders = await rb.providers('text');
for (const provider of textProviders.data) {
  console.log(provider.id, provider.protocol, provider.model_count);
}

const imageProviders = await rb.providers('image', { includeEmpty: true });
for (const drive of imageProviders.data) {
  console.log(drive.id, drive.name, drive.billing_method, drive.provider_count);
}

const videoProviders = await rb.providers('video', { includeEmpty: true });
for (const drive of videoProviders.data) {
  console.log(drive.id, drive.name, drive.billing_method, drive.provider_count);
}

Providers 响应结构:

interface TextProvidersResponse {
  data: Array<{
    id: string;
    name: string;
    protocol: string;
    model_count: number;
    endpoint_count: number;
    links: { models: string };
  }>;
}

interface ImageProvidersResponse {
  data: Array<{
    id: string;
    name: string;
    billing_method: 'images' | 'tokens';
    model_count: number;
    provider_count: number;
    links: { models: string };
  }>;
}

interface VideoProvidersResponse {
  data: Array<{
    id: string;
    name: string;
    billing_method: 'duration' | 'tokens' | 'modality_tokens';
    model_count: number;
    provider_count: number;
    links: { models: string };
  }>;
}

Rerank 接口

通过 rb.rerank() 对文档列表按与查询文本的相关性进行重排(Cohere V2 标准协议)。请求路由到 {baseUrl}/v1/rerank

Rerank 基本用法

import { RouterBrain } from '@router-brain/sdk';

const rb = new RouterBrain('sk-your-api-key');

const result = await rb.rerank({
  model: 'rerank-model-name',
  query: '量子计算的应用场景',
  documents: [
    '量子计算在密码学领域有重要应用,可以破解现有加密体系',
    '经典计算机使用二进制位(0或1)进行计算',
    '量子比特利用叠加态可以同时表示0和1',
    'Shor算法可以在量子计算机上高效分解大整数',
  ],
  top_n: 2,  // 只返回最相关的 2 条
});

console.log('文档排序结果:');
for (const item of result.results) {
  console.log(`  #${item.index}  分数: ${item.relevance_score}`);
}

// 带原始文档内容回传
const result2 = await rb.rerank({
  model: 'rerank-model-name',
  query: 'RAG 检索增强生成',
  documents: docs,
  return_documents: true,  // 结果中携带原文档内容
});
for (const item of result2.results) {
  console.log(`[${item.relevance_score}] ${item.document}`);
}

RerankCreateParams 参数说明

| 参数 | 类型 | 必需 | 说明 | |------|------|------|------| | model | string | ✅ | 重排模型标识 | | query | string | ✅ | 查询文本 | | documents | (string \| { text: string })[] | ✅ | 待重排的文档列表 | | top_n | number \| null | ❌ | 返回前 N 条结果,默认全部返回 | | return_documents | boolean | ❌ | 是否在结果中回传原文档 | | max_tokens_per_doc | number \| null | ❌ | 每篇文档最大 token 数,默认 4096 | | instructions | string | ❌ | 重排指引说明(部分上游驱动支持) |

RerankResponse 响应结构

interface RerankResponse {
  id: string;                          // 请求 ID
  results: RerankResultItem[];         // 按相关性降序排列的结果
  meta: {
    api_version: { version: string };
    billed_units?: { search_units: number };     // 计费单元
    usage?: {
      total_tokens?: number;
      prompt_tokens?: number;
      completion_tokens?: number;
    };
  };
}

interface RerankResultItem {
  index: number;                       // 原始 documents 数组中的下标
  relevance_score: number;             // 相关性分数(0 ~ 1)
  document?: { text: string } | string; // 原文档内容(return_documents=true 时)
}

错误处理

try {
  const result = await rb.rerank({ ... });
} catch (err) {
  console.error('Rerank failed:', (err as Error).message);
}

非 2xx 时自动抛出,错误消息来自上游返回的 error.message


图片生成接口

通过 rb.image() 调用网关的图片生成能力,返回 ImageResponse 包装器。请求路由到 {baseUrl}/image/v1/generations

非流式生成

// 获取 URL 格式
const result = await rb.image({
  model: 'dall-e-3',
  prompt: '一只橘猫在樱花树下睡觉,夕阳,温暖色调',
  size: '1024x1024',
}).json();

console.log(result.created);       // 时间戳
console.log(result.data[0].url);   // 图片 URL
console.log(result.usage?.images); // 生成图片张数

// 获取 Base64 格式
const result2 = await rb.image({
  model: 'dall-e-3',
  prompt: '山水画,水墨风格',
  size: '1792x1024',
  response_format: 'b64_json',   // 返回 base64 编码
}).json();

console.log(result2.data[0].b64_json); // base64 字符串

流式生成(SSE)

流式场景下,按 SSE 事件逐行读取原始字节流:

const stream = await rb.image({
  model: 'stabilityai/stable-diffusion-3',
  prompt: '赛博朋克城市夜景',
  stream: true,
}).stream();

for await (const chunk of stream!) {
  // chunk 是 Uint8Array,需要按 SSE 协议解析
  const text = new TextDecoder().decode(chunk);
  console.log(text);
}

SSE 事件类型:

| 事件 | 说明 | |------|------| | success | 单张图片生成成功,携带图片 URL 或 b64_json | | error | 单张图片生成失败,携带错误信息 | | complete | 全部图片生成完毕,携带最终用量 |

异步任务轮询

部分图片模型将生成任务提交为后台异步处理,响应中携带 task_id。可通过 .task() 方法自动轮询直到任务完成或失败:

const result = await rb.image({
  model: 'stabilityai/stable-diffusion-3',
  prompt: '星空下的独角兽',
}).task({
  pollInterval: 2000,  // 轮询间隔,默认 2000ms
});

// 结果类型为 ImageTaskResponseJson
console.log(result.task_status);    // 'success'
console.log(result.data[0].url);    // 生成的图片 URL
console.log(result.usage.images);   // 用量

若需取消轮询,可传入 AbortSignal

const controller = new AbortController();

setTimeout(() => controller.abort(), 30000); // 30 秒超时自动取消

try {
  const result = await rb.image({
    model: 'stabilityai/stable-diffusion-3',
    prompt: '...',
  }).task({ signal: controller.signal });
} catch (err) {
  console.error('Task aborted or failed:', (err as Error).message);
}

.task() 内部通过 GET /image/v1/tasks/:task_id 轮询,直到 task_status 变为 'success''failed'

ImageResponse 方法说明

| 方法 | 返回类型 | 说明 | |------|---------|------| | json() | Promise<ImageResponseJson> | 解析为非流式 JSON 响应。非 2xx 时自动抛错 | | stream() | Promise<ReadableStream<Uint8Array> \| null> | 获取流式响应的原始字节流。适用于 stream: true 场景 | | task(opts?) | Promise<ImageTaskResponseJson> | 轮询异步任务直到完成。要求响应中包含 task_id,否则抛错 | | httpStatus() | Promise<number> | HTTP 状态码 |

ImageAdapterProps 参数说明

interface ImageAdapterProps {
  model: string;                    // 模型名,如 'dall-e-3'、'stabilityai/stable-diffusion-3'
  prompt: string;                   // 正向提示词
  image?: ImageAdapterImage | ImageAdapterImage[];  // 参考图片(驱动支持时可用)
  size?: string;                    // 尺寸:'1024x1024' | '1792x1024' | 等
  stream?: boolean;                 // 是否启用 SSE 流式响应
  response_format?: 'url' | 'b64_json'; // 输出格式,默认 'url'
  upstream_options?: Record<string, any>; // 透传给上游驱动的额外参数
  headers?: Record<string, string | string[]>;  // 自定义 HTTP 请求头
}

ImageAdapterImage:

type ImageAdapterImage = string | {
  file_id: string;          // 文件 ID(需先上传)
  image_url?: string;       // 或直接传图片 URL
};

图片尺寸参考:

| 模型 | 支持尺寸 | |------|---------| | dall-e-3 | 1024x10241792x10241024x1792 | | dall-e-2 | 1024x1024512x512256x256 | | stabilityai/stable-diffusion-系列 | 通常支持多种正方形和宽屏尺寸 |

具体支持的尺寸取决于网关上游配置的驱动,请以实际响应为准。

ImageResponseJson 响应结构

interface ImageResponseJson {
  created: number;                  // Unix 时间戳(秒)
  data: ImageData[];                // 图片数组,每张图片包含 url 或 b64_json
  usage?: ImageResponseUsage;       // 用量信息(部分驱动提供)
  task_id?: string;                 // 异步任务 ID(部分模型返回,此时任务尚未完成)
  task_status?: 'pending' | 'running' | 'success' | 'failed';  // 异步任务状态
}

interface ImageData {
  url?: string;                     // 图片下载 URL
  b64_json?: string;                // Base64 编码的图片数据
}

interface ImageResponseUsage {
  images?: number;                  // 生成图片数量
  total_tokens?: number;            // 总 token 数
  input_tokens?: {
    image_tokens?: number;
    text_tokens?: number;
  };
  output_tokens?: {
    image_tokens?: number;
    text_tokens?: number;
  };
  cached_tokens?: {
    image_tokens?: number;
    text_tokens?: number;
  };
}

// 异步任务轮询响应
interface ImageTaskResponseJson {
  completed: number;                // 任务完成时间戳
  created: number;                  // 请求创建时间戳
  task_id: string;                  // 任务唯一标识
  task_status: 'pending' | 'running' | 'success' | 'failed';  // 当前状态
  data: { url: string }[];          // 生成的图片数组(success 时有值)
  usage: ImageResponseUsage;        // 用量信息
  error?: string;                   // 错误信息(failed 时有值)
  model: string;                    // 使用的模型
  updated: number;                  // 最后更新时间戳
}

视频生成接口

通过 rb.video() 调用网关的视频生成能力,返回 VideoResponse 包装器。请求路由到 {baseUrl}/video/v1/generations,任务查询由 .task() 内部通过 GET /video/v1/tasks/:task_id 完成。

视频生成全部为异步任务模式。创建任务后必须轮询获取结果,SDK 的 .task() 方法已封装自动轮询。

提交任务

const created = await rb.video({
  model: 'wan2.1-t2v-turbo',
  prompt: '一只机器人在火星基地巡检',
  resolution: '720p',
  ratio: '16:9',
}).json();

console.log(created.task_id); // 本地任务 ID

自动轮询任务

const result = await rb.video({
  model: 'wan2.1-t2v-turbo',
  prompt: '夜晚城市街道的电影感推进镜头,霓虹灯,雨后反光',
  resolution: '720p',
  ratio: '16:9',
}).task({
  pollInterval: 3000,  // 轮询间隔,默认 2000ms
});

console.log(result.task_status);    // 'success'
console.log(result.data[0]?.url);   // 生成的视频 URL

若需取消本地轮询,可传入 AbortSignal

const controller = new AbortController();
setTimeout(() => controller.abort(), 120000);

try {
  const result = await rb.video({
    model: 'wan2.1-t2v-turbo',
    prompt: '...',
  }).task({ signal: controller.signal });
} catch (err) {
  console.error('Task aborted or failed:', (err as Error).message);
}

取消只停止 SDK 轮询,不会取消已提交到上游的视频任务。

多模态输入

rb.video() 支持文本、图片、视频和音频输入。字符串会作为 URL 处理;对象使用 VideoURL 结构,可指定媒体角色。

// 图生视频
const imageResult = await rb.video({
  model: 'kling-v2-1-turbo',
  prompt: '让图片中的人物转头微笑',
  image: 'https://example.com/portrait.jpg',
  resolution: '720p',
}).task();

// 多参考图
const multiImageResult = await rb.video({
  model: 'doubao-seedance-1-0-pro-250528',
  prompt: '基于两张参考图生成平滑转场',
  image: [
    'https://example.com/frame1.jpg',
    'https://example.com/frame2.jpg',
  ],
  resolution: '720p',
}).task();

// 视频输入,Seedance 的 modality_tokens 计费会根据是否传入 video 切换价格
const videoResult = await rb.video({
  model: 'doubao-seedance-1-0-pro-250528',
  prompt: '基于参考视频生成续集',
  video: { type: 'reference_video', url: 'https://example.com/clip.mp4' },
  resolution: '720p',
}).task();

// 音频参考
const audioResult = await rb.video({
  model: 'doubao-seedance-1-0-pro-250528',
  prompt: '根据参考音频生成带节奏感的短视频',
  audio: { type: 'reference_audio', url: 'https://example.com/bgm.mp3' },
  resolution: '720p',
}).task();

VideoResponse 方法说明

| 方法 | 返回类型 | 说明 | |------|---------|------| | json() | Promise<VideoResponseJson> | 解析创建任务响应,包含 task_id。非 2xx 时自动抛错 | | task(opts?) | Promise<VideoTaskResponseJson> | 轮询视频任务直到成功、失败或取消。内部先调 json() 获取 task_id,再轮询 | | httpStatus() | Promise<number> | HTTP 状态码 |

VideoAdapterProps 参数说明

interface VideoAdapterProps<T extends Record<string, any> = Record<string, any>> {
  model: string;                    // 视频模型代码,如 'wan2.1-t2v-turbo'、'kling-v2-1-turbo'
  prompt: string;                   // 正向提示词
  image?: string | string[] | VideoURL | VideoURL[]; // 参考图片
  video?: string | string[] | VideoURL | VideoURL[]; // 参考视频
  audio?: string | string[] | VideoURL | VideoURL[]; // 参考音频
  ratio?: string;                   // 画幅比例,如 '16:9'、'9:16'、'1:1'
  resolution?: string;              // 分辨率,如 '480p'、'720p'、'1080p'
  upstream_options?: T;             // 透传给上游驱动的额外参数
  headers?: Record<string, string | string[]>; // 自定义 HTTP 请求头
}

interface VideoURL {
  type: string;                     // 媒体类型或角色,由驱动解释
  url: string;                      // 媒体 URL
}

字段说明:

| 字段 | 说明 | |------|------| | model | 模型代码,必须在视频模型目录中存在并有可用路由 | | prompt | 文本提示词 | | image | 参考图片。字符串默认为图片 URL;数组会逐项展开 | | video | 参考视频。字符串默认为视频 URL;数组会逐项展开 | | audio | 参考音频。字符串默认为音频 URL;数组会逐项展开 | | ratio | 输出画幅比例,如 16:99:161:1 | | resolution | 输出分辨率,如 480p720p1080p4k | | upstream_options | 厂商私有参数,按驱动透传 | | headers | 自定义请求头,会透传到上游创建任务请求 |

驱动参数说明

当前视频驱动:

| 驱动 | 计费方式 | 说明 | |------|----------|------| | seedance | modality_tokens | 火山 Seedance,多模态输入,按分辨率和是否包含输入视频选择输出 token 单价 | | bailian | duration | 阿里云百炼,按输出视频秒数计费,分辨率用于选档 |

Seedance

Seedance 会把统一入参转换为上游 content 数组:

| SDK 字段 | Seedance 上游字段 | |----------|-------------------| | prompt | { type: 'text', text: prompt } | | image: string | { type: 'image_url', image_url: { url }, role: 'reference_image' } | | image: VideoURL | { type: 'image_url', image_url: { url }, role: image.type } | | video: string | { type: 'video_url', video_url: { url }, role: 'reference_video' } | | video: VideoURL | { type: 'video_url', video_url: { url }, role: video.type } | | audio: string | { type: 'audio_url', audio_url: { url }, role: 'reference_audio' } | | audio: VideoURL | { type: 'audio_url', audio_url: { url }, role: audio.type } |

Seedance 支持的 upstream_options

type SeedanceOptions = {
  callback_url?: string;
  return_last_frame?: boolean;
  service_tier?: 'default' | 'flex';
  execution_expires_after?: number;
  generate_audio?: boolean;
  draft?: boolean;
  tools?: Array<{ type: string }>;
  safety_identifier?: string;
  priority?: number;
  duration?: number;
  frames?: number;
  seed?: number;
  camera_fixed?: boolean;
  watermark?: boolean;
};

调用示例:

const result = await rb.video({
  model: 'doubao-seedance-1-0-pro-250528',
  prompt: '根据参考视频生成续集,保持人物和场景一致',
  video: { type: 'reference_video', url: 'https://example.com/reference.mp4' },
  resolution: '720p',
  ratio: '16:9',
  upstream_options: {
    duration: 5,
    watermark: false,
    service_tier: 'default',
    seed: 42,
  },
}).task();

百炼

百炼会把统一入参转换为上游 input.media 数组:

| SDK 字段 | 百炼上游字段 | |----------|--------------| | prompt | input.prompt | | image: string | { type: 'reference_image', url } | | image: VideoURL | 原样放入 input.media | | video: string | { type: 'video', url } | | video: VideoURL | 原样放入 input.media | | audio: string | { type: 'audio', url } | | audio: VideoURL | 原样放入 input.media | | resolution | parameters.resolution | | ratio | parameters.ratio |

百炼支持的 upstream_options

type BailianOptions = {
  duration?: number;
  watermark?: boolean;
  seed?: number;
  audio_setting?: string;
};

调用示例:

const result = await rb.video({
  model: 'kling-v2-1-turbo',
  prompt: '让图片中的人物转头微笑,镜头轻微推进',
  image: 'https://example.com/source.jpg',
  resolution: '720p',
  upstream_options: {
    duration: 5,
    watermark: false,
    seed: 123,
  },
}).task();

视频响应结构

VideoResponseJson

interface VideoResponseJson {
  task_id: string;                  // 本地任务唯一标识
}

VideoTaskResponseJson

interface VideoTaskResponseJson {
  task_id: string;                  // 任务唯一标识
  task_status: 'pending' | 'running' | 'success' | 'failed' | 'cancelled';  // 当前状态
  model: string;                    // 使用的模型
  created: number | null;           // 任务创建时间戳(毫秒)
  updated: number | null;           // 最后更新时间戳(毫秒)
  completed: number | null;         // 任务完成时间戳(毫秒)
  data: VideoTaskData[];            // 生成的视频数组(success 时有值)
  error: VideoTaskError | null;     // 错误信息(failed / cancelled 时有值)
}

interface VideoTaskData {
  url?: string;                     // 视频下载 URL
  [key: string]: unknown;           // 驱动扩展字段
}

interface VideoTaskError {
  code: string;                     // 错误码
  message: string;                  // 错误描述
}

任务状态说明:

| 状态 | 说明 | |------|------| | pending | 任务已创建,尚未开始处理 | | running | 任务正在上游处理中 | | success | 任务完成,data[0].url 有值 | | failed | 任务失败,error 有值 | | cancelled | 任务被取消,error 有值 |

视频模型定价

通过 rb.models('video')rb.endpoints('video', code) 可以拿到视频模型的计费方式和分辨率分档价格。

const models = await rb.models('video', {
  q: 'seedance',
  billingMethods: ['modality_tokens'],
});

for (const item of models.data) {
  console.log(item.id, item.billing_methods, item.pricing);
}

const detail = await rb.endpoints('video', 'doubao-seedance-1-0-pro-250528');
for (const endpoint of detail.endpoints) {
  console.log(endpoint.drive_id, endpoint.billing_method, endpoint.pricing);
}

定价类型:

type VideoBillingMethod = 'duration' | 'tokens' | 'modality_tokens';

interface VideoDurationPrice {
  unit: 'credits/second';
  tiers: Array<{
    max_resolution_inclusive: number | null;
    duration: string;
    duration_fiat: string;
  }>;
}

interface VideoTokenPrice {
  unit: 'credits/token';
  tiers: Array<{
    max_resolution_inclusive: number | null;
    input: string;
    input_fiat: string;
    output: string;
    output_fiat: string;
    cached: string;
    cached_fiat: string;
  }>;
}

interface VideoModalityTokenPrice {
  unit: 'credits/token';
  tiers: Array<{
    max_resolution_inclusive: number | null;
    output: string;                    // 输入不含 video 时的输出 token 单价
    output_fiat: string;
    input_video_output: string;        // 输入包含 video 时的输出 token 单价
    input_video_output_fiat: string;
  }>;
}

modality_tokens 的价格按分辨率分档,并在每个分辨率档内区分是否传入 video。SDK 创建视频任务时不需要手动传计费字段,网关会根据请求和模型配置自动计算。


错误处理

OpenAI / Anthropic 接口

这两个接口直接返回 SDK 实例,错误由上游 SDK 原生处理:

try {
  const res = await rb.openai().chat.completions.create({ ... });
} catch (err) {
  if (err instanceof OpenAI.APIError) {
    console.error('OpenAI API Error:', err.status, err.message);
  }
}

图片生成接口

ImageResponse.json() 会自动检查 HTTP 状态码,非 2xx 时解析上游错误信息并抛出:

try {
  const result = await rb.image({
    model: 'dall-e-3',
    prompt: '',
  }).json();  // prompt 为空时会触发上游错误
} catch (err) {
  console.error('Image generation failed:', (err as Error).message);
  // 例如: "prompt is required and must not be empty"
}

如果需要手动处理 HTTP 状态码:

const img = rb.image({ model: 'dall-e-3', prompt: '...' });

const status = await img.httpStatus();
if (status !== 200) {
  console.warn('Unexpected status:', status);
}

const result = await img.json(); // 非 2xx 仍会抛错

视频生成接口

VideoResponse.json()VideoResponse.task() 会自动检查 HTTP 状态码,非 2xx 时解析网关错误信息并抛出:

try {
  const result = await rb.video({
    model: 'wan2.1-t2v-turbo',
    prompt: '',
  }).task();
} catch (err) {
  console.error('Video generation failed:', (err as Error).message);
}

自定义请求头

OpenAI / Anthropic 接口

通过 SDK 原生能力传递自定义请求头(取决于上游 SDK 支持)。

图片生成接口

支持透传自定义 Header:

const result = await rb.image({
  model: 'dall-e-3',
  prompt: '测试图片',
  headers: {
    'x-trace-id': 'trace-001',      // 链路追踪 ID
    'x-user-id': 'user-123',        // 用户标识
    'x-agent-name': 'my-agent',     // Agent 名称
  },
}).json();

视频生成接口

同样支持透传自定义 Header:

const result = await rb.video({
  model: 'wan2.1-t2v-turbo',
  prompt: '测试视频',
  headers: {
    'x-trace-id': 'trace-001',
    'x-user-id': 'user-123',
    'x-agent-name': 'my-agent',
  },
}).task();

TypeScript 类型

SDK 导出了所有公共类型:

import {
  RouterBrain,
  RouterBrainConfigs,
  ModelCatalogType,
  TextModelItem,
  TextModelsQueryParams,
  TextModelsResponse,
  TextModelEndpointItem,
  TextModelEndpointsResponse,
  TextProviderItem,
  TextProvidersQueryParams,
  TextProvidersResponse,
  ImageBillingMethod,
  ImageModelDrive,
  ImageCreditPrice,
  ImageTokenPrice,
  ImageModelItem,
  ImageModelsQueryParams,
  ImageModelsResponse,
  ImageModelEndpointItem,
  ImageModelEndpointPricing,
  ImageModelEndpointsResponse,
  ImageProviderItem,
  ImageProvidersQueryParams,
  ImageProvidersResponse,
  VideoBillingMethod,
  VideoDurationPrice,
  VideoDurationTierPrice,
  VideoModelDrive,
  VideoModelItem,
  VideoModelPricingItem,
  VideoModelsQueryParams,
  VideoModelsResponse,
  VideoModelEndpointItem,
  VideoModelEndpointPricing,
  VideoModelEndpointsResponse,
  VideoModalityTokenPrice,
  VideoModalityTokenTierPrice,
  VideoProviderItem,
  VideoProvidersQueryParams,
  VideoProvidersResponse,
  VideoResponse,
  VideoResponseJson,
  VideoTaskData,
  VideoTaskError,
  VideoTaskResponseJson,
  VideoTaskStatus,
  VideoTokenPrice,
  VideoTokenTierPrice,
  VideoAdapterProps,
  VideoURL,
  RerankCreateParams,
  RerankResponse,
  RerankResultItem,
  ImageResponse,
  ImageResponseJson,
  ImageTaskResponseJson,
  ImageResponseUsage,
  ImageAdapterProps,
  ImageAdapterImage,
  ImageData,
} from '@router-brain/sdk';

| 导出 | 类型 | 说明 | |------|------|------| | RouterBrain | class | 主入口类 | | RouterBrainConfigs | interface | 构造参数:{ apiKey, baseUrl? } | | ModelCatalogType | type | 模型目录类型:'text' \| 'image' \| 'video' | | TextModelsQueryParams | interface | 文本模型列表查询参数 | | TextModelsResponse | interface | 文本模型列表响应 | | TextModelItem | interface | 单个文本模型信息(含定价、架构、标签) | | TextModelEndpointsResponse | interface | 单个文本模型端点详情 | | TextModelEndpointItem | interface | 文本模型单条上游路由信息(含延迟、可用率) | | TextProviderItem | interface | 文本供应商目录项 | | TextProvidersQueryParams | interface | 文本供应商目录查询参数 | | TextProvidersResponse | interface | 文本供应商目录响应 | | ImageBillingMethod | type | 图片模型计费方式:'images' \| 'tokens' | | ImageModelDrive | interface | 图片模型驱动信息 | | ImageCreditPrice | interface | 按图片计费价格结构 | | ImageTokenPrice | interface | 按 token 计费价格结构 | | ImageModelsQueryParams | interface | 图片模型列表查询参数 | | ImageModelsResponse | interface | 图片模型列表响应 | | ImageModelItem | interface | 单个图片模型信息 | | ImageModelEndpointsResponse | interface | 单个图片模型端点详情 | | ImageModelEndpointItem | interface | 图片模型单条上游路由信息 | | ImageModelEndpointPricing | type | 图片模型 endpoint 价格结构 | | ImageProviderItem | interface | 图片驱动目录项 | | ImageProvidersQueryParams | interface | 图片驱动目录查询参数 | | ImageProvidersResponse | interface | 图片驱动目录响应 | | VideoBillingMethod | type | 视频模型计费方式:'duration' \| 'tokens' \| 'modality_tokens' | | VideoDurationPrice | interface | 按视频时长计费价格结构 | | VideoDurationTierPrice | interface | 按视频时长计费的单个分辨率价格档 | | VideoTokenPrice | interface | 按 token 计费价格结构 | | VideoTokenTierPrice | interface | 普通 token 计费的单个分辨率价格档 | | VideoModalityTokenPrice | interface | 按输入模态区分的 token 计费价格结构 | | VideoModalityTokenTierPrice | interface | modality_tokens 的单个分辨率价格档 | | VideoModelsQueryParams | interface | 视频模型列表查询参数 | | VideoModelsResponse | interface | 视频模型列表响应 | | VideoModelItem | interface | 单个视频模型信息 | | VideoModelPricingItem | type | 单个视频模型的一种驱动计费价格结构 | | VideoModelEndpointsResponse | interface | 单个视频模型端点详情 | | VideoModelEndpointItem | interface | 视频模型单条上游路由信息 | | VideoModelEndpointPricing | type | 视频模型 endpoint 价格结构 | | VideoProviderItem | interface | 视频驱动目录项 | | VideoProvidersQueryParams | interface | 视频驱动目录查询参数 | | VideoProvidersResponse | interface | 视频驱动目录响应 | | VideoResponse | class | 视频响应包装器 | | VideoResponseJson | interface | 视频创建任务响应体结构 | | VideoTaskResponseJson | interface | 视频任务轮询响应体结构 | | VideoTaskData | interface | 视频任务结果数据项 | | VideoTaskError | interface | 视频任务错误结构 | | VideoAdapterProps | interface | 视频生成请求参数 | | VideoURL | interface | 视频生成多模态输入 URL 参数 | | RerankCreateParams | interface | Rerank 请求参数 | | RerankResponse | interface | Rerank 响应体 | | RerankResultItem | interface | 单条重排结果 | | ImageResponse | class | 图片响应包装器 | | ImageResponseJson | interface | 非流式图片响应体结构 | | ImageTaskResponseJson | interface | 异步任务轮询响应体结构 | | ImageResponseUsage | interface | 图片生成用量 | | ImageAdapterProps | interface | 图片生成请求参数 | | ImageAdapterImage | type | 参考图片参数 | | ImageData | interface | 单张图片数据 |


开发与构建

# 安装依赖
pnpm install

# 构建
pnpm build

# 产物在 dist/ 目录
#   dist/index.js         — 入口 JS
#   dist/index.d.ts       — 类型声明
#   dist/image-response.js — ImageResponse 类
#   dist/image-response.d.ts
#   dist/video-response.js — VideoResponse 类
#   dist/video-response.d.ts
#   dist/types.js         — 类型定义
#   dist/types.d.ts

发布

该 SDK 发布到私有 npm 仓库(阿里云 CodeUp):

pnpm publish

发布前请确认 package.json 中的 version 字段已正确更新。自动跟随语义化版本。