JavaScript 与 curl

从当前图像和机器人状态发起一次云端调用,并读取动作序列。

本页使用相同的输入分别演示 Node.js 和 curl 调用。示例读取并打印动作序列,不驱动机器人。自行接入设备时,由你的控制程序校验和执行这些动作;使用 RoboAPI 时,向本地 HTTP API提交任务指令,由运行程序完成采集、推理与执行循环。

准备

先按账户与 API Key配置 PLATFORM_BASE_URL 和 PLATFORM_API_KEY,然后查询可用模型:

curl --fail-with-body "$PLATFORM_BASE_URL/models" \
  -H "Authorization: Bearer $PLATFORM_API_KEY"

将响应中选定的模型 id 填入 PLATFORM_MODEL,将指令改为你的任务:

export PLATFORM_MODEL="<MODEL_ID>"
export ROBOT_INSTRUCTION="Unfold the blue shirt"

在工作目录准备两个文件:

  • input.png:当前相机观测,RGB PNG 格式。
  • state.json:与该图像对应的机器人状态,内容为 8 个数值的 JSON 数组。顺序和坐标要求见观测与动作。

JavaScript

使用 Node.js 22 或更新版本,将以下代码保存为 infer.mjs 后运行。

infer.mjs
import { readFileSync } from "node:fs";

function env(name) {
  const value = process.env[name];
  if (!value) throw new Error(`Set ${name} first`);
  return value;
}
const baseUrl = env("PLATFORM_BASE_URL").replace(/\/$/, "");
const state = JSON.parse(readFileSync("state.json", "utf8"));
if (!Array.isArray(state) || state.length !== 8 || !state.every(Number.isFinite)) {
  throw new Error("state.json must contain an array of 8 finite numbers");
}
const image = readFileSync("input.png").toString("base64");
const response = await fetch(`${baseUrl}/chat/completions`, {
  method: "POST",
  signal: AbortSignal.timeout(60_000),
  headers: {
    Authorization: `Bearer ${env("PLATFORM_API_KEY")}`,
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    model: env("PLATFORM_MODEL"),
    messages: [{
      role: "user",
      content: [
        { type: "text", text: JSON.stringify({
          instruction: env("ROBOT_INSTRUCTION"), state
        }) },
        { type: "image_url", image_url: {
          url: `data:image/png;base64,${image}`
        } }
      ]
    }]
  })
});
const requestId = response.headers.get("x-request-id");
console.log("Request ID:", requestId);
const result = await response.json();
if (!response.ok) {
  throw new Error(`HTTP ${response.status}: ${result.error?.message ?? "Request failed"}`);
}
const call = result.choices?.[0]?.message?.tool_calls?.find(
  (item) => item.function?.name === "execute_actions"
);
if (!call) throw new Error("Missing execute_actions result");
const { output } = JSON.parse(call.function.arguments);
if (!Array.isArray(output) || output.length === 0 || !output.every(
  (row) => Array.isArray(row) && row.length === 8 && row.every(Number.isFinite)
)) {
  throw new Error("Expected an action array with 8 finite numbers per row");
}
console.log(output);
node infer.mjs

curl

以下命令使用 Bash 或 Zsh,以及 jq。使用上面设置的环境变量和两个输入文件,生成请求并保存响应:

jq -n \
  --arg model "$PLATFORM_MODEL" \
  --arg instruction "$ROBOT_INSTRUCTION" \
  --rawfile image <(base64 < input.png | tr -d '\r\n') \
  --slurpfile state state.json \
  '{model: $model, messages: [{role: "user", content: [
    {type: "text", text: ({instruction: $instruction, state: $state[0]} | tojson)},
    {type: "image_url", image_url: {url: ("data:image/png;base64," + $image)}}
  ]}]}' > request.json

curl --fail-with-body --max-time 60 \
  "$PLATFORM_BASE_URL/chat/completions" \
  -H "Authorization: Bearer $PLATFORM_API_KEY" \
  -H "Content-Type: application/json" \
  --data-binary @request.json \
  --dump-header response.headers \
  --output response.json

请求成功后,解析 execute_actions 中的动作:

jq -e '
  [.choices[0].message.tool_calls[]?
    | select(.function.name == "execute_actions")][0]
  // error("Missing execute_actions result")
  | .function.arguments | fromjson | .output
' response.json

响应头保存在 response.headers。读取其中的 X-Request-ID,用于查询请求状态和用量:

REQUEST_ID=$(awk 'tolower($1) == "x-request-id:" {gsub("\r", "", $2); print $2}' response.headers | tail -n 1)
printf 'Request ID: %s\n' "$REQUEST_ID"

动作数组的行数以本次响应为准。若调用失败,先根据云端调用错误处理 HTTP 状态,再发起新的请求。

本页内容