@router-brain/sdk
v1.0.3
Published
Router Brain SDK
Readme
@router-brain/sdk
Router Brain 的官方 Node.js SDK。通过统一入口调用 LLM 网关(OpenAI 兼容接口)、Anthropic 接口、图片、视频和音频生成接口。
目录
安装
pnpm add @router-brain/sdkSDK 已声明 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 audio = await rb.audio({
model: 'cosyvoice-v2',
prompt: '欢迎使用 Router Brain',
voice: 'longxiaochun',
stream: false,
task: false,
}).json();
console.log(audio.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.completions、embeddings、responses、images、models等)都可用。
暂未实现的接口
以下 OpenAI 标准接口网关已注册路由但尚未实现,调用会返回 501 错误:
| 接口 | 状态 |
|------|------|
| POST /v1/audio/speech | ❌ 暂不支持 OpenAI Speech 协议;音频生成请使用 rb.audio() |
| 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 官方支持的方法(messages、stream等)都可用。
Models 接口
RouterBrain 提供统一的模型目录方法,第一个参数用于区分目录类型。当前支持 text、image、video 和 audio。
接口速览
| 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.models('audio', params) | GET /audio/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.endpoints('audio', code) | GET /audio/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.providers('audio', params) | GET /audio/v1/providers | 音频生成驱动及能力聚合 |
搜索模型列表
通过 rb.models(type, params) 查询可用模型。type='text' 请求 GET {baseUrl}/v1/models,响应格式与 OpenRouter /api/v1/models 兼容;其他类型分别请求 {baseUrl}/image/v1/models、{baseUrl}/video/v1/models 和 {baseUrl}/audio/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) 获取单个模型的上游路由信息。text、image、video、audio 分别请求各自的 /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);
}图片和视频目录的每个 pricing 项及 endpoint 都包含 discount。价格对象同时提供原价字段与对应的 discounted_* 折后字段;模型和 endpoint 详情还包含可为空的 readme 与 reference_url。
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;
readme: string | null;
reference_url: string | null;
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;
readme: string | null;
reference_url: string | null;
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: true,
}).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: true,
}).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'。任务查询遇到网络错误、408、429或5xx时会以最长 30 秒的退避间隔继续轮询。
ImageResponse 方法说明
| 方法 | 返回类型 | 说明 |
|------|---------|------|
| json() | Promise<ImageResponseJson> | 解析为非流式 JSON 响应。非 2xx 时自动抛错 |
| stream() | Promise<ReadableStream<Uint8Array> \| null> | 获取流式响应的原始字节流;非 2xx 时自动抛错 |
| 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 流式响应
task?: boolean; // 是否请求异步任务模式
n?: number; // 生成图片数量
user?: string; // 调用方用户标识
response_format?: 'url' | 'b64_json'; // 输出格式,默认 'url'
upstream_options?: Record<string, any>; // 透传给上游驱动的额外参数
headers?: Record<string, string | string[]>; // 自定义 HTTP 请求头
}ImageAdapterImage:
type ImageAdapterImage = string
| { image_url: string; file_id?: never }
| { file_id: string; image_url?: never };图片尺寸参考:
| 模型 | 支持尺寸 |
|------|---------|
| dall-e-3 | 1024x1024、1792x1024、1024x1792 |
| dall-e-2 | 1024x1024、512x512、256x256 |
| 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 编码的图片数据
revised_prompt?: string; // 上游修订后的提示词
provider_metadata?: Record<string, unknown>; // 上游扩展元数据
}
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 | null; // 任务完成时间戳
created: number | null; // 请求创建时间戳
task_id: string; // 任务唯一标识
task_status: 'pending' | 'running' | 'success' | 'failed'; // 当前状态
data: Array<{ url?: string; b64_json?: string }>; // success 时有值
usage?: ImageResponseUsage; // 用量信息
error: { code: string; message: string } | null; // failed 时有值
model: string; // 使用的模型
updated: number | null; // 最后更新时间戳
}视频生成接口
通过 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> | 轮询直到终态;网络错误、408、429、5xx 会退避重试 |
| 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:9、9:16、1:1 |
| resolution | 输出分辨率,如 480p、720p、1080p、4k |
| 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 时有值)
usage?: VideoTaskUsage; // 本地任务记录还原的用量
error: VideoTaskError | null; // 错误信息(failed / cancelled 时有值)
}
interface VideoTaskData {
url?: string; // 视频下载 URL
[key: string]: unknown; // 驱动扩展字段
}
interface VideoTaskError {
code: string; // 错误码
message: string; // 错误描述
}
interface VideoTaskUsage {
duration: number;
resolution: number | null;
input_tokens: number;
output_tokens: number;
cached_tokens: number;
total_tokens: number;
input_seconds?: number;
output_seconds?: number;
input_image_count?: number;
total_seconds?: number;
}任务状态说明:
| 状态 | 说明 |
|------|------|
| 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;
discounted_duration: string;
discounted_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;
discounted_input: string;
discounted_input_fiat: string;
discounted_output: string;
discounted_output_fiat: string;
discounted_cached: string;
discounted_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;
discounted_output: string;
discounted_output_fiat: string;
discounted_input_video_output: string;
discounted_input_video_output_fiat: string;
}>;
}modality_tokens 的价格按分辨率分档,并在每个分辨率档内区分是否传入 video。SDK 创建视频任务时不需要手动传计费字段,网关会根据请求和模型配置自动计算。
音频生成接口
rb.audio() 沿用视频生成的响应包装器模式,请求统一发送到 {baseUrl}/audio/v1/generations。stream 和 task 是网关必填字段,且不能同时为 true:
- 同步:
stream: false, task: false - SSE:
stream: true, task: false - 异步任务:
stream: false, task: true
同步生成
const result = await rb.audio({
model: 'cosyvoice-v2',
prompt: '这是一段同步生成的语音',
voice: 'longxiaochun',
stream: false,
task: false,
upstream_options: { format: 'mp3' },
}).json();
console.log(result.data[0]?.url);
console.log(result.usage); // duration 或 charactersSSE 流式生成
stream() 返回原始 SSE 字节流,事件类型包括 audio、timeline、complete 和错误事件。
const stream = await rb.audio({
model: 'cosyvoice-v2',
prompt: '这是一段流式生成的语音',
stream: true,
task: false,
}).stream();
for await (const chunk of stream ?? []) {
process.stdout.write(Buffer.from(chunk));
}异步任务
与 VideoResponse.task() 一致,AudioResponse.task() 先读取创建响应中的本地 task_id,再轮询 GET /audio/v1/tasks/:task_id,成功时返回任务结果,失败或取消时抛错。任务查询遇到网络错误、408、429 或 5xx 时会以最长 30 秒的退避间隔继续轮询;可通过 signal 中止任务查询和等待阶段(不影响调用 audio() 时已经发出的创建请求)。
const result = await rb.audio({
model: 'async-tts-model',
prompt: '需要异步合成的长文本',
stream: false,
task: true,
upstream_options: { unique_id: 'order-20260806-001' },
}).task({ pollInterval: 2000 });
console.log(result.task_status, result.data[0]?.url);音频模型目录
const models = await rb.models('audio', {
q: 'tts',
billingMethods: ['characters'],
sort: 'drive',
});
const endpoints = await rb.endpoints('audio', models.data[0].id);
const providers = await rb.providers('audio', { includeEmpty: true });音频目录的计费方式为 duration(credits/second)或 characters(credits/character);provider 项同时声明 supports_stream 和 supports_task。
错误处理
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() 和 .stream() 会自动检查 HTTP 状态码,非 2xx 时解析上游错误信息并抛出;.task() 对任务查询的网络错误、408、429 和 5xx 进行退避重试,其他非 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() 会自动检查 HTTP 状态码;VideoResponse.task() 对任务查询的网络错误、408、429 和 5xx 进行退避重试,其他非 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);
}音频生成接口
AudioResponse.json()、.stream() 和 .task() 会解析网关的 error.message。任务进入 failed 或 cancelled 时,.task() 会抛出任务错误。
自定义请求头
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();音频生成接口
const result = await rb.audio({
model: 'cosyvoice-v2',
prompt: '测试音频',
stream: false,
task: false,
headers: {
'x-trace-id': 'trace-001',
'x-user-id': 'user-123',
'x-agent-name': 'my-agent',
},
}).json();TypeScript 类型
SDK 导出了所有公共类型:
import {
RouterBrain,
RouterBrainConfigs,
ModelCatalogType,
AudioAdapterProps,
AudioBillingMethod,
AudioCharactersPrice,
AudioData,
AudioDurationPrice,
AudioModelDrive,
AudioModelEndpointItem,
AudioModelEndpointPricing,
AudioModelEndpointsResponse,
AudioModelItem,
AudioModelPricingItem,
AudioModelsQueryParams,
AudioModelsResponse,
AudioProviderItem,
AudioProvidersQueryParams,
AudioProvidersResponse,
AudioResponse,
AudioResponseJson,
AudioStreamEvent,
AudioTaskResponseJson,
AudioTaskStatus,
AudioUsage,
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,
VideoTaskUsage,
VideoTokenPrice,
VideoTokenTierPrice,
VideoAdapterProps,
VideoURL,
RerankCreateParams,
RerankResponse,
RerankResultItem,
ImageResponse,
ImageResponseJson,
ImageTaskData,
ImageTaskError,
ImageTaskResponseJson,
ImageTaskStatus,
ImageResponseUsage,
ImageAdapterProps,
ImageAdapterImage,
ImageData,
} from '@router-brain/sdk';| 导出 | 类型 | 说明 |
|------|------|------|
| RouterBrain | class | 主入口类 |
| RouterBrainConfigs | interface | 构造参数:{ apiKey, baseUrl? } |
| ModelCatalogType | type | 模型目录类型:'text' \| 'image' \| 'video' \| 'audio' |
| AudioBillingMethod | type | 音频模型计费方式:'duration' \| 'characters' |
| AudioDurationPrice | interface | 按音频时长计费的价格结构 |
| AudioCharactersPrice | interface | 按字符数计费的价格结构 |
| AudioModelDrive | interface | 音频模型驱动信息 |
| AudioModelItem | interface | 单个音频模型信息 |
| AudioModelPricingItem | type | 单个音频模型的一种驱动计费价格结构 |
| AudioModelEndpointItem | interface | 音频模型单条上游路由信息 |
| AudioModelEndpointPricing | type | 音频模型 endpoint 价格结构 |
| AudioProviderItem | interface | 音频驱动目录项及模式能力 |
| AudioProvidersQueryParams | interface | 音频驱动目录查询参数 |
| 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 | 视频任务错误结构 |
| VideoTaskUsage | interface | 视频任务用量结构 |
| VideoAdapterProps | interface | 视频生成请求参数 |
| VideoURL | interface | 视频生成多模态输入 URL 参数 |
| AudioResponse | class | 音频响应包装器,支持 JSON、SSE 和异步任务轮询 |
| AudioAdapterProps | interface | 音频生成请求参数 |
| AudioResponseJson | interface | 音频同步或任务创建响应 |
| AudioTaskResponseJson | interface | 音频任务轮询响应 |
| AudioTaskStatus | type | 音频异步任务状态 |
| AudioData | interface | 音频结果及时间轴数据 |
| AudioStreamEvent | type | 音频 SSE 事件结构 |
| AudioUsage | type | 按时长或字符数计费的音频用量 |
| AudioModelsQueryParams | interface | 音频模型列表查询参数 |
| AudioModelsResponse | interface | 音频模型列表响应 |
| AudioModelEndpointsResponse | interface | 单个音频模型端点详情 |
| AudioProvidersResponse | interface | 音频驱动目录响应 |
| RerankCreateParams | interface | Rerank 请求参数 |
| RerankResponse | interface | Rerank 响应体 |
| RerankResultItem | interface | 单条重排结果 |
| ImageResponse | class | 图片响应包装器 |
| ImageResponseJson | interface | 非流式图片响应体结构 |
| ImageTaskResponseJson | interface | 异步任务轮询响应体结构 |
| ImageTaskStatus | type | 图片异步任务状态 |
| ImageTaskData | interface | 图片异步任务结果项 |
| ImageTaskError | 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/audio-response.js — AudioResponse 类
# dist/audio-response.d.ts
# dist/types.js — 类型定义
# dist/types.d.ts发布
该 SDK 发布到私有 npm 仓库(阿里云 CodeUp):
pnpm publish发布前请确认 package.json 中的 version 字段已正确更新。自动跟随语义化版本。
