runninghub-sdk-node
v0.1.0
Published
RunningHub Node.js and TypeScript SDK
Maintainers
Readme
runninghub-sdk-node
RunningHub 的 Node.js / TypeScript SDK,适用于 Node.js 18 及以上环境。
适合这些场景:
- 调用 AI App
- 调用 Workflow / Comfy 工作流
- 轮询任务状态并获取结果
- 上传文件、下载结果、查询资源和账户信息
安装
npm install runninghub-sdk-node要求:
- Node.js
>=18
准备 API Key
推荐使用环境变量:
RUNNINGHUB_API_KEY=your_runninghub_api_key如果不使用 .env 加载工具,也可以直接在命令前传入:
RUNNINGHUB_API_KEY=your_runninghub_api_key node your-script.js快速开始
下面这个例子会直接调用一个工作流并等待结果返回:
import { modifyNodes, RunningHubClient } from 'runninghub-sdk-node';
const client = new RunningHubClient(process.env.RUNNINGHUB_API_KEY ?? '');
const result = await client.runWorkflowAndWait(
'2044675520398368770',
modifyNodes()
.text('6', 'a quiet seaside road at sunrise, painterly illustration')
.seed('10', 123456)
.steps('10', 12)
.cfg('10', 1)
.size('11', 1024, 1024),
{ pollIntervalMs: 2_000 },
);
console.log(result.status);
console.log(result.results[0]?.url);选哪个接口
AI App
适合已经发布好的应用接口。
runAIApp()runAIAppWithModifier()runAIAppAndWait()
Workflow / Comfy 工作流
适合直接调用某个 workflow ID,并按节点修改参数。
runWorkflow()runWorkflowWithModifier()runWorkflowAndWait()run()runWithModifier()asyncRun()asyncRunWithModifier()
说明:
runWorkflow*()走/openapi/v2/run/workflow/{id}run*()走/task/openapi/create- 两种方式都能提交工作流任务;如果更想贴近 RunningHub 的通用建任务接口,优先用
run()/runWithModifier()
标准模型接口
适合直接调用平台暴露的标准模型,例如文生图模型接口。
runStandardModel()pricePreview()
初始化客户端
import { RunningHubClient } from 'runninghub-sdk-node';
const client = new RunningHubClient(process.env.RUNNINGHUB_API_KEY ?? '', {
baseURL: 'https://www.runninghub.cn',
hostOverride: 'www.runninghub.cn',
userAgent: 'my-app/1.0.0',
timeoutMs: 60_000,
maxBodyBytes: 10 << 20,
});支持的配置项:
baseURL: API 基础地址hostOverride: 自定义请求 HostuserAgent: 自定义 User-AgenttimeoutMs: 单次请求超时时间,单位毫秒maxBodyBytes: 响应体最大读取字节数fetch: 自定义fetch实现headers: 默认附加请求头
Workflow 教程
推荐流程是:先找出工作流里可改的节点参数,再用 modifyNodes() 提交。
1. 查看工作流参数
import { RunningHubClient } from 'runninghub-sdk-node';
const client = new RunningHubClient(process.env.RUNNINGHUB_API_KEY ?? '');
const params = await client.getWorkflowParams('2044675520398368770');
console.log(params);返回结果包含:
nodeIdnodeTypenodeTitlefieldNamefieldTypevalue
如果还想看节点之间的连接关系:
const inspection = await client.inspectWorkflow('2044675520398368770');
console.log(inspection.nodes.find((node) => node.nodeId === '10'));inspectWorkflow() 会额外返回 linkedInputs,比如 positive 连接到哪个节点、model 来自哪个节点。
2. 提交工作流任务
import { modifyNodes, RunningHubClient } from 'runninghub-sdk-node';
const client = new RunningHubClient(process.env.RUNNINGHUB_API_KEY ?? '');
const modifier = modifyNodes()
.text('6', 'a cinematic seaside road at sunrise')
.seed('10', 601240929502329)
.steps('10', 8)
.cfg('10', 1)
.sizeWithBatch('11', 1024, 1024, 1);
const task = await client.runWithModifier('2044675520398368770', modifier, {
instanceType: 'default',
addMetadata: true,
});
const result = await client.waitForCompletion(task, {
pollIntervalMs: 2_000,
timeoutMs: 600_000,
onStatusChange: (status) => console.log('status:', status),
});
console.log(result.results[0]?.url);3. async 风格别名
如果你想在命名上区分“提交任务”和“等待完成”,可以使用这组别名:
const task = await client.asyncRunWithModifier('2044675520398368770', modifier);
const result = await client.asyncWaitForCompletion(task, { pollIntervalMs: 2_000 });这些 async* 方法是对现有稳定实现的别名,不会引入另一套执行逻辑。
AI App 教程
import { RunningHubClient } from 'runninghub-sdk-node';
const client = new RunningHubClient(process.env.RUNNINGHUB_API_KEY ?? '');
const task = await client.runAIApp('2050082405557514242', {
nodeInfoList: [
{
nodeId: '2',
fieldName: 'resolution',
fieldValue: '2k',
description: '选择分辨率',
},
],
instanceType: 'default',
usePersonalQueue: false,
});
const result = await client.waitForTask(task.taskId);
console.log(JSON.stringify(result, null, 2));如果也想用链式写法:
import { modifyNodes, RunningHubClient } from 'runninghub-sdk-node';
const client = new RunningHubClient(process.env.RUNNINGHUB_API_KEY ?? '');
const result = await client.runAIAppAndWait(
'2050082405557514242',
modifyNodes().set('2', 'resolution', '2k'),
{ pollIntervalMs: 2_000 },
);
console.log(result.status);标准模型接口
import { RunningHubClient } from 'runninghub-sdk-node';
const client = new RunningHubClient(process.env.RUNNINGHUB_API_KEY ?? '');
const task = await client.runStandardModel('/openapi/v2/seedream-v4/text-to-image', {
prompt: '一只戴着护目镜的柯基犬在月球上驾驶复古摩托车,电影感光影,超细节,4k',
negativePrompt: 'blurry, low quality, distorted, extra fingers',
width: 1024,
height: 1024,
numImages: 1,
});
const result = await client.waitForTask(task.taskId);
console.log(result.results);价格预估:
const preview = await client.pricePreview('/openapi/v2/seedream-v4/text-to-image', {
prompt: 'a cat astronaut',
width: 1024,
height: 1024,
numImages: 1,
});
console.log(preview.priceText);NodeModifier
modifyNodes() 用来构建 nodeInfoList。
通用写法:
const modifier = modifyNodes()
.set('6', 'text', 'hello world')
.set('10', 'steps', 8)
.set('11', 'width', 1024);常用快捷方法:
text(nodeId, value)negativeText(nodeId, value)image(nodeId, value)video(nodeId, value)audio(nodeId, value)seed(nodeId, value)steps(nodeId, value)cfg(nodeId, value)denoise(nodeId, value)sampler(nodeId, value)scheduler(nodeId, value)width(nodeId, value)height(nodeId, value)size(nodeId, width, height)sizeWithBatch(nodeId, width, height, batchSize)batchSize(nodeId, value)lora(nodeId, value)loraStrength(nodeId, value)checkpoint(nodeId, value)
批量操作:
const modifier = modifyNodes()
.append({ nodeId: '6', fieldName: 'text', fieldValue: 'prompt' })
.addMany([
{ nodeId: '10', fieldName: 'steps', fieldValue: 8 },
{ nodeId: '11', fieldName: 'width', fieldValue: 1024 },
]);
console.log(modifier.length);
console.log(modifier.toList());任务状态与结果
等待完成:
const result = await client.waitForTask(taskId, {
pollIntervalMs: 2_000,
timeoutMs: 600_000,
onStatusChange: (status, response) => {
console.log('status:', status, 'task:', response.taskId);
},
});查询状态:
const status = await client.getStatus('task_id');
console.log(status);获取输出:
const outputs = await client.getOutputs('task_id');
console.log(outputs);查询完整任务信息:
const detail = await client.queryTaskV2('task_id');
console.log(detail);常见状态值:
CREATEQUEUEDRUNNINGSUCCESSFAILEDCANCELLED
文件上传与结果下载
上传二进制内容:
const uploaded = await client.uploadBinary(fileBuffer, 'input.png');
console.log(uploaded.download_url);这些方法是等价别名:
uploadBinary(input, filename)uploadBinaryReader(input, filename)uploadFile(input, filename)uploadImage(input, filename)
上传本地文件:
const uploaded = await client.uploadFilePath('/tmp/input.png');
console.log(uploaded.download_url);也可以使用:
uploadBinaryFile(filePath)uploadImageFile(filePath)
下载任务结果:
const result = await client.waitForTask(taskId);
const files = await client.downloadTaskResults(result, './outputs');
console.log(files);账户与资源
const account = await client.accountStatus();
const keys = await client.apiKeyList();
const queue = await client.queueStatus();
const resources = await client.listPublicResources({
resourceType: 'LORA',
current: 1,
size: 20,
});Comfy 兼容接口
这些接口主要用于兼容旧调用方式,或者需要直接操作工作流 JSON 的场景:
createComfyTaskSimple(workflowId, options)cancel(taskId)cancelComfyTask(taskId)getTaskStatusDeprecated(taskId)getTaskOutputsDeprecated(taskId)getWorkflowJSONPrompt(workflowId)getWorkflowJSON(workflowId)
说明:
getWorkflowJSONPrompt()返回原始 JSON 字符串getWorkflowJSON()返回解析后的对象inspectWorkflow()/getWorkflowParams()是在getWorkflowJSON()基础上做的高层封装
子路径导入
import { RunningHubClient } from 'runninghub-sdk-node/client';
import type { RunAIAppRequest } from 'runninghub-sdk-node/types';
import { RunningHubAPIError } from 'runninghub-sdk-node/errors';可用导出:
runninghub-sdk-noderunninghub-sdk-node/clientrunninghub-sdk-node/typesrunninghub-sdk-node/errors
错误处理
SDK 会抛出以下错误类型:
RunningHubAPIError: 接口返回业务错误RunningHubHTTPError: HTTP 状态码异常RunningHubConfigError: 参数或本地配置错误RunningHubTimeoutError: 等待任务超时
import {
RunningHubAPIError,
RunningHubConfigError,
RunningHubHTTPError,
RunningHubTimeoutError,
} from 'runninghub-sdk-node/errors';
try {
const result = await client.queryTaskV2('task_id');
console.log(result.status);
} catch (error) {
if (error instanceof RunningHubAPIError) {
console.error(error.code, error.message, error.details);
} else if (error instanceof RunningHubHTTPError) {
console.error(error.statusCode, error.body);
} else if (error instanceof RunningHubTimeoutError) {
console.error(error.taskId, error.timeoutMs);
} else if (error instanceof RunningHubConfigError) {
console.error(error.message);
} else {
console.error(error);
}
}示例
示例代码位于 examples/ 目录:
examples/ai-app.ts: AI App 调用示例examples/text-to-image.ts: 标准模型文生图示例examples/workflow.ts: 基础 workflow 调用示例examples/workflow-from-template.ts: 推荐的工作流调用示例,直接基于workflowId + nodeInfoList运行,不依赖本地 JSON 模板参与提交
进入 examples/ 目录后,可以直接运行:
cd examples
npm run ai-app
npm run text-to-image
npm run workflow
npm run workflow-from-templateworkflow-from-template.ts 支持以下环境变量覆盖默认参数:
RUNNINGHUB_WORKFLOW_IDRUNNINGHUB_NODE_6_TEXTRUNNINGHUB_NODE_10_SEEDRUNNINGHUB_NODE_10_STEPSRUNNINGHUB_NODE_10_CFGRUNNINGHUB_NODE_11_WIDTHRUNNINGHUB_NODE_11_HEIGHT
例如:
cd examples
RUNNINGHUB_NODE_6_TEXT='a futuristic city at dawn' npm run workflow-from-templateAPI 总表
提交任务:
asyncRun(workflowId, modifierOrNodeInfoList?, options?)asyncRunWithModifier(workflowId, modifier, options?)run(workflowId, modifierOrNodeInfoList?, options?)runWithModifier(workflowId, modifier, options?)runAIApp(appIdOrPath, request)runAIAppWithModifier(appIdOrPath, modifier, options)runAIAppAndWait(appIdOrPath, requestOrModifier, waitOptions)runWorkflow(workflowIdOrPath, request)runWorkflowWithModifier(workflowIdOrPath, modifier, options)runWorkflowAndWait(workflowIdOrPath, requestOrModifier, waitOptions)runStandardModel(modelPath, request)pricePreview(modelPath, request)
查询任务和工作流:
asyncWaitForCompletion(taskOrTaskId, options)getWorkflowParams(workflowId)inspectWorkflow(workflowId)getStatus(taskId)getOutputs(taskId)queryTaskV2(taskId)waitForTask(taskId, options)waitForCompletion(taskOrTaskId, options)
文件与资源:
uploadFile(input, filename)uploadImage(input, filename)uploadBinary(input, filename)uploadBinaryReader(input, filename)uploadBinaryFile(filePath)uploadFilePath(filePath)uploadImageFile(filePath)downloadFile(fileURL, destPath)downloadTaskResults(task, outputDir)accountStatus()apiKeyList()queueStatus()listPublicResources(request)
构建
npm run check
npm run build