mcpField
E
editframe-api

editframe-api

github.com/editframe创意与媒体19134 次安装2 周前更新
代码仓库

关于 editframe-api

面向 JavaScript/TypeScript 开发者的 Editframe API 客户端和命令行工具,用于视频渲染、媒体上传处理及本地项目导出。命令行工具通过已安装的 Editframe 运行时连接编辑器和本地桥接程序。

主要功能

  1. 01创建渲染任务并查看进度
  2. 02上传视频、图片和字幕文件
  3. 03通过流水线转录音频
  4. 04为媒体访问签署 URL
  5. 05打开编辑器并提交本地导出任务

适用场景

  1. 01从 Editframe 合成内容生成视频
  2. 02上传并处理媒体素材
  3. 03通过流水线生成语音标注
  4. 04在本地项目中提交并检查导出

MCP 相关

CLI 的 `mcp` 命令通过 MCP stdio 将 Agent 连接到本地 bridge。Editframe 的 Agent 安装包包含主机配置。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/editframe/skills --skill editframe-api

安装后在 Claude Code 中输入/editframe-api确认已加载。

详细介绍

Editframe API 和 CLI

@editframe/api 是 Editframe 云视频 API 的 JavaScript/TypeScript 客户端。可用它从 Editframe 合成中渲染视频、上传和处理媒体文件、运行转录音频的流水线,以及管理对 CDN 资源的经过身份验证的浏览器访问。

editframe CLI 是已安装的 Editframe 运行时的轻量客户端。它会打开浏览器编辑器,并请求导出本地项目。请参阅 CLI。

快速入门

import { Client, createRender, getRenderProgress, downloadRender } from "@editframe/api";

const client = new Client(process.env.EDITFRAME_API_KEY);

const render = await createRender(client, {
  html: `<ef-timegroup mode="contain" class="w-[1920px] h-[1080px]">
    <ef-video src="https://assets.editframe.com/bars-n-tone.mp4"></ef-video>
  </ef-timegroup>`,
  width: 1920,
  height: 1080,
  fps: 30,
});

for await (const event of await getRenderProgress(client, render.id)) {
  if (event.type === "progress") console.log(`Progress: ${(event.data.progress * 100).toFixed(0)}%`);
}

const response = await downloadRender(client, render.id);
const buffer = await response.arrayBuffer();

客户端和身份验证

import { Client } from "@editframe/api";

const client = new Client(process.env.EDITFRAME_API_KEY);      // server-side: Bearer token
const client = new Client();                                    // browser: session cookie (credentials: "include")
const client = new Client(apiKey, "https://staging.editframe.com"); // optional second arg overrides the host (default https://editframe.com)

API 密钥的格式为 ef_<secret>_<keyid>。客户端会在本地验证此格式。请在 Editframe 控制面板的 API → API Keys 中获取密钥。错误行为因 SDK 函数而异。请处理被拒绝的请求和文档中说明的结果状态。

切勿在客户端代码中暴露 API 密钥。 如需在浏览器中播放经过身份验证的媒体,请改用 URL 签名。密钥由服务器持有。浏览器只会收到短期、限定范围的令牌。

@editframe/api 仍导出较早的、按类型区分的资源:createImageFile、createCaptionFile、createISOBMFFFile 等。这些 API 已标记为 @deprecated,建议改用统一的 createFile/type: "video"|"image"|"caption" API。请勿在新代码中使用它们。如需了解已停用的转录函数,请参阅 转录。

统一文件 API

所有文件类型——视频、图像、字幕——都使用同一组端点。type 字段用于选择端点行为:

类型格式最大大小处理方式
videoMP4、MOV、WebM、MKV1GB自动转换为 ISOBMFF(支持帧精确定位和自适应流式传输)
imageJPEG、PNG、WebP、SVG16MB立即就绪
captionVTT、SRT2MB立即就绪

状态生命周期:created → uploading → processing → ready(图像/字幕会跳过 processing),或进入 → failed。

import { Client, createFile, uploadFile, getFileProcessingProgress } from "@editframe/api";
import { createReadStream } from "node:fs";
import { stat } from "node:fs/promises";
import { Readable } from "node:stream";

const client = new Client(process.env.EDITFRAME_API_KEY);
const fileStats = await stat("video.mp4");

const file = await createFile(client, { filename: "video.mp4", type: "video", byte_size: fileStats.size });

for await (const event of uploadFile(client, { id: file.id, byte_size: fileStats.size, type: "video" }, Readable.toWeb(createReadStream("video.mp4")))) {
  if (event.type === "progress") console.log(`Upload: ${(event.progress * 100).toFixed(1)}%`);
}

for await (const event of await getFileProcessingProgress(client, file.id)) {
  if (event.type === "complete") break;
}

uploadFile 接收 Web ReadableStream。如上所示,使用 Readable.toWeb 转换 Node 流。浏览器文件可通过 file.stream() 提供兼容的流。

Node 辅助函数会创建文件记录,并返回一个惰性上传迭代器。使用该迭代器即可上传字节:

import { Client, upload, getFileProcessingProgress } from "@editframe/api/node";

const client = new Client(process.env.EDITFRAME_API_KEY);
const { file, uploadIterator } = await upload(client, "video.mp4");
for await (const event of uploadIterator) {
  console.log(`Upload: ${(event.progress * 100).toFixed(1)}%`);
}
for await (const event of await getFileProcessingProgress(client, file.id)) {
  if (event.type === "complete") break;
}

上传完成和媒体处理完成是两个不同的状态。

上传前请检查文件是否已存在。调用 lookupFileByMd5(client, md5)。如果没有匹配的文件,该函数会返回 null。

通过 file-id 在合成中使用该文件:

<ef-configuration api-host="https://editframe.com">
  <ef-video file-id="uuid-of-processed-video"></ef-video>
  <ef-image file-id="uuid-of-uploaded-image" class="w-24 h-24"></ef-image>
</ef-configuration>

createFile 会将 file-id 设为稳定的 UUID。在上传、处理和播放期间,它都保持不变。

保留期限(expires_at)

createFile 和 createRender 都接受可选的 expires_at:一个 ISO 8601 日期,且最多只能设为未来 30 天内。省略此字段表示永久保留。输入无效时会返回 400,并附带以下错误之一:invalid_datetime、must_be_future 或 exceeds_max_retention。getFileDetail 和 getRenderInfo 会返回 expires_at;null 表示永久保留。远程 URL 渲染导入(见下文)使用固定且不可配置的 1 小时 TTL,与此字段无关。

渲染

const render = await createRender(client, {
  html: `<ef-timegroup mode="contain" class="w-[1920px] h-[1080px]"><ef-video src="..."></ef-video></ef-timegroup>`,
  width: 1920,
  height: 1080,
  fps: 30,          // default 30
  output: { container: "mp4", video: { codec: "h264" }, audio: { codec: "aac" } }, // default shown
});

输出容器:mp4(video.codec: "h264",audio.codec: "aac")、jpeg(quality 为 1–100,默认值为 80)、png(compression 为 1–100,默认值为 80;transparency 为布尔值)、webp(quality 为 1–100,默认值为 80;compression 为 0–6,默认值为 4;transparency 为布尔值)。

createRender 还接受以下高级选项:

  • 服务端配置决定执行后端。SDK 的 backend 字段不会覆盖当前服务端标志。
  • work_slice_ms:将渲染拆分为此长度的片段,单位为毫秒。在 "cpu" 上默认为 4000,在 "gpu" 上默认为 15000。最大值为 60000。
  • strategy:为未来的渲染策略保留。目前仅有 "v1",且它是默认值。
  • duration_ms:覆盖检测到的渲染时长,单位为毫秒。
  • metadata:任意 Record<string, string>。getRenderInfo 和渲染 Webhook 会将其原样返回。

组合中的 ef-video、ef-audio 和 ef-image 元素可以直接使用 https:// src 值。Editframe 会在渲染前下载并导入这些资源,并设置一个临时的 expires_at,时长约为一小时。这与通过 createFile 注册的文件不同。

如果要复用之前的渲染结果,请显式调用 lookupRenderByMd5。createRender 不会执行此查找。

根据完整的渲染输入计算哈希,包括输出设置和稳定的资源版本。仅对 HTML 计算哈希会遗漏这些差异。

复用前,请检查渲染的完成状态、输出设置和保留期限。哈希匹配并不保证结果仍然可用。

getRenderProgress 会先生成 { type: "progress", data: { progress } },其中 progress 的范围为 0 到 1,然后生成 { type: "complete" }。如果渲染失败,则会抛出错误。deleteRender 会立即删除记录以及所有 GCS 输出和中间文件。如果渲染仍处于活动状态(queued、rendering 或 recovering),则删除会失败。

要注册自行渲染的视频,请跳过 html,直接上传文件:

import { createReadStream } from "node:fs";
import { Readable } from "node:stream";

const render = await createRender(client, { width: 1920, height: 1080, fps: 30 });
await uploadRender(client, render.id, Readable.toWeb(createReadStream("my-video.mp4")));

转录

要转录文件,请使用 transcribe 步骤启动流水线运行。请参阅流水线。此步骤会写入 speech.segment 和 speech.word 注释。使用 getPipelineRunOutputs(client, runId, namespace) 读取这些注释。

旧版转录已停用。transcribeFile、transcribeISOBMFFFile 和 createTranscription 均已标记为 @deprecated。其端点会返回 410 Gone 和错误 transcription_retired。请勿使用这些端点。

getFileTranscription 仍会报告旧版转录的状态:id、status、completed_at、failed_at 和 work_slice_ms。它不会返回转录片段。对于没有旧版转录的文件,它会返回 null。

ef-captions 需要从 captions-src、captions-script 或 captions.captionsData 获取字幕数据。target 仅将字幕时间同步到所引用的 ef-video/ef-audio 元素的本地时间,不会获取转录数据。请参阅 composition 技能中的 ef-captions 参考。

URL 签名

当浏览器直接播放由 Editframe 托管的媒体时,请使用 URL 签名,例如 <ef-video src="https://editframe.com/api/v1/transcode/...">。如果所有渲染和播放都通过 createRender/downloadRender 在服务器端完成,则无需使用。

服务器保管 API 密钥,并公开一个调用 createURLToken 的端点。

在祖先级 ef-configuration 上设置 HTML 属性 signing-url。JavaScript 属性名称为 signingURL。

在签发令牌之前,先对调用方进行身份验证,并验证其是否有权访问所请求的媒体。

浏览器向该端点发送 { url },并将返回的令牌附加到媒体请求中。

令牌有效期约为一小时。浏览器会按 URL 缓存每个令牌。对于转码或 HLS 端点,一个令牌可用于清单及其所有分段。

// Inside your authenticated application router, authorize access to the requested media URL.
import { Client, createURLToken } from "@editframe/api";
const client = new Client(process.env.EDITFRAME_API_KEY);
app.post("/sign-url", async (req, res) => res.json({ token: await createURLToken(client, req.body.url) }));

<ef-configuration api-host="https://editframe.com" signing-url="/sign-url">
  <ef-video src="https://editframe.com/api/v1/transcode/manifest.m3u8?url=..."></ef-video>
</ef-configuration>

如果使用 editframe.com 会话 Cookie 而不是 API 密钥,请改用 POST /ef-sign-url,并设置 credentials: "include",且不带 Authorization 标头。这是等效的匿名令牌流程。大多数应用使用上文的 API 密钥服务器路由。

CLI

editframe CLI 是已安装 Editframe 运行时的轻量客户端。它不会打包桥接程序、编辑器或渲染依赖项。请先从 https://editframe.com/agent 安装运行时。

npm install -D @editframe/cli   # already included in the html/react scaffolds

每个本地命令都需要 --project 和桥接程序。使用 --bridge、--component、EDITFRAME_BRIDGE_PATH 或 EDITFRAME_COMPONENT_ROOT 选择桥接程序。每个命令都会输出 JSON。

export EDITFRAME_BRIDGE_PATH=/absolute/editframe-bridge
npx editframe start --project .
npx editframe open --project .           # prints an editor URL; keep it private
npx editframe compositions --project .
npx editframe context --project . --composition COMPOSITION_ID

context 会返回当前修订 ID 和受支持的导出设置。要导出,请使用新的 operation_id、该 revision_id 和受支持的设置编写请求文件:

{
  "operation_id": "export-demo-001",
  "revision_id": "REPLACE_WITH_CURRENT_REVISION_ID",
  "execution_target": "local",
  "settings": { "container": "mp4", "video_codec": "h264", "audio_codec": "aac", "width": 1280, "height": 720, "fps": 30 }
}
npx editframe export --project . --composition COMPOSITION_ID --input export.json
npx editframe job --project . --job JOB_ID
  • 本地导出期间请保持浏览器编辑器打开。编辑器就是渲染器。
  • CLI 会提交并检查作业,但不会写入视频文件。请从编辑器获取文件。
  • 仅在完全相同的重试中重复使用 operation_id。新的修订或设置需要新的 operation_id。
  • command 会应用一次带修订版本的合成编辑。其 --input 文件需要包含 operation_id、base_revision_id、kind 和 label。发生修订冲突后,请重新读取 context 并使用新的 operation_id。
  • mcp 通过 MCP stdio 将 Agent 连接到本地桥接程序。https://editframe.com/agent 上的原生 Agent 软件包包含主机配置。

对于已启用的托管运行时,请将 --project 和桥接程序替换为 --endpoint 和 --project-id。在环境中设置 EDITFRAME_TOKEN。旧版 CLI 的 EF_TOKEN 变量不能用于运行时登录。

本文件末尾生成的表格列出了 @editframe/cli 解析器的每个选项和命令。

旧版命令

以下命令名称现在会失败并返回 CLI_MIGRATION_REQUIRED:

旧版命令当前路径
preview、dev、dev-server使用 start 和 open,或 Vite 和 Next.js 适配器。请参阅 dev-server 技能。
render使用 export,或从浏览器编辑器导出
auth、cloud-render、sync使用 @editframe/api:createRender 和统一文件 API
webhook更改 API 密钥的 webhook URL。请参阅 webhooks 技能。
check、process、process-file、transcribeCLI 无对应替代项。请使用浏览器编辑器。应用构建使用 @editframe/build-adapter。

Pipelines

Editframe 会为每个组织启用流水线。要获取流水线,请通过 https://editframe.com/factory#contact 告知 Editframe 您的素材。对于没有流水线的组织,每个流水线路由都会返回 404。

从 @editframe/api/pipelines 导入流水线函数。此入口点处于实验阶段,可在不升级主版本的情况下发生变化。本文件末尾的函数索引不会列出它。

流水线是由步骤组成、具有不可变版本的命名图。一次运行会通过一个版本处理一个 video 文件。某个步骤会在其 needs 中的步骤完成后启动。每个步骤都会将其输出写入文件的一个命名空间。

import { Client, createPipeline, createPipelineRun, getPipelineRun, isPipelineRunTerminal } from "@editframe/api/pipelines";

const client = new Client(process.env.EDITFRAME_API_KEY);
const pipeline = await createPipeline(client, {
  name: "speech-check",
  definition: {
    steps: {
      probe: { type: "probe" },
      transcript: { type: "transcribe", needs: ["probe"] },
      has_speech: { type: "filter", needs: ["transcript"], when: { path: "transcript.metadata.word_count", op: "gt", value: 0 } },
      publish: { type: "publish", needs: ["has_speech"] },
    },
  },
});
const { run } = await createPipelineRun(client, { pipeline_id: pipeline.id, file_id: fileId }, { idempotencyKey: `speech-check:${fileId}` });
let current = await getPipelineRun(client, run.id);
while (!isPipelineRunTerminal(current)) {
  await new Promise((resolve) => setTimeout(resolve, 5000));
  current = await getPipelineRun(client, run.id);
}
定义

定义的格式为 { steps: { <key>: step } },包含 1–64 个步骤。步骤键和命名空间必须匹配 ^[a-z][a-z0-9_]{0,62}$。未知字段会导致 422 错误。

步骤字段规则
type必填。使用下方列出的类型之一。
needs必须先完成的步骤的键,最多 16 个。默认为 []。不允许循环依赖。
namespace必须唯一。默认值:步骤键。
granularity{ mode: "file" }(默认值),或 { mode: "segment", window_ms: 1000–3600000, overlap_ms: 0 to window_ms/2 }
with该类型的选项
whenfilter 必填。其他类型不允许使用。
类型with(默认值)输出
probe不允许元数据 duration_ms、width、height、has_video、has_audio、source、tracks
transcribe不允许speech.segment 和 speech.word 注释。元数据 word_count、segment_count、truncated 等。
sample_framesevery_ms 100–600000(1000)第一个视频轨道的 JPEG 帧
detect_scenesthreshold 0.01–1(0.3)scene.cut 注释。元数据 cut_count。
endpointendpoint_id(必填),max_concurrency 1–1024(8)服务的输出
filter不允许无输出。该步骤成功或跳过。
reviewinstructions 1–2000 个字符,expires_after_ms 60000–2592000000(604800000),on_expiry 为 fail/approve/reject(fail)决策和修正后的注释
redact_renderkinds:1–32 种注释类型(必填),captions 布尔值(false),title:{ text: 1–120 characters, duration_ms: 1000–15000 (4000) }元数据 render_id、status、output_url、output_file_id 和计数
publishformats:hls 和/或 dash(["hls"])元数据 file_id、source_url、hls_url、dash_url

请遵守以下规则:

  • 仅对 transcribe、sample_frames、detect_scenes 和 endpoint 使用 segment 粒度。
  • 若要在上传完成前启动分段步骤,需将其所有 needs 都设为分段步骤。文件步骤会等待整个文件处理完毕。
  • 窗口从片段边界开始。窗口可以长于 window_ms。分段注释必须保持在其窗口内。
  • publish 会返回输入文件的播放 URL。如果 publish 依赖 redact_render 步骤,则播放已遮盖的文件。如果遮盖步骤被 skipped,则播放输入文件。file_id 是其播放的文件。publish 最多只能直接或间接依赖一个 redact_render 步骤。依赖多个会在其 needs 处导致 not_allowed。
  • redact_render 会模糊带有 keyframes 的注释,并静音不带 keyframes 的注释。它会创建一个占用渲染分钟数的普通渲染,然后将该渲染作为新文件添加到组织中,文件 ID 为 output_file_id。该文件就绪后,步骤才会成功。渲染或文件失败时不会自动重试。重试运行时会重新渲染。
  • 设置 captions: true 时,redact_render 会从 transcribe 步骤的转录内容中烧录字幕。该步骤必须直接或间接依赖且仅依赖一个 transcribe 步骤。没有 transcribe 步骤会在 with.captions 处导致 not_upstream。依赖多个则会导致 not_allowed。字幕不会显示被静音的词,而会在其位置显示 ▇▇▇。
  • 设置 title 时,redact_render 会在视频顶部显示 title.text。标题会在 duration_ms 时淡出。Editframe 会删除文本开头和结尾处的空白。
  • 带有字幕或标题的 redact_render 步骤始终会进行渲染,即使没有任何内容需要遮盖。其元数据还会包含 caption_count 和 title_applied。
  • Editframe 会规范化定义并记录 sha256: 摘要。等效定义具有相同的摘要。
筛选器

筛选器会评估 when。谓词为真时,筛选器通过;谓词为假时,将跳过该筛选器及其后的所有步骤。

  • 叶节点的格式为 { path, op, value }。path 的格式为 <namespace>.metadata.<field>... 或 <namespace>.annotations...。数字段用于选择数组项。
  • op 可以是 exists、non_empty、eq、ne、gt、gte、lt、lte、in(1–64 个标量)或 contains。
  • 使用 { all: [...] }、{ any: [...] }(1–16 个子项)和 { not: predicate } 组合叶节点。最大深度为 4。
  • 当 path 没有值时,每个叶节点的结果都为假,包括 ne。
  • 筛选器只能读取其直接或间接依赖的步骤所在的命名空间。读取其他路径会导致 not_upstream。
  • 对于分段步骤,筛选器会读取所有窗口的注释。对于每个元数据字段,读取最后一个设置该字段的窗口中的值。

最终步骤是指没有其他步骤依赖的步骤。至少有一个最终步骤成功时,运行以 succeeded 结束。如果筛选器或审核在所有分支到达最终步骤前将其停止,运行以 filtered 结束。使用两个互补筛选器时,所选分支完成后,运行以 succeeded 结束。Editframe 始终会跳过同时依赖两个分支的步骤。

审核

审核步骤会创建审核任务,并进入 waiting_review 状态等待。

  • approvePipelineReview(client, id, { metadata_patch }) 会使该步骤成功。补丁的格式为 { annotations, reviewed_kinds? }。补丁中的每种类型都会替换后续步骤所用的该类型的旧注释。reviewed_kinds 中列出但未提供注释的类型,会从后续步骤中移除。
  • rejectPipelineReview(client, id, { reason }) 会跳过该步骤及其后的步骤。reason 最多为 2000 个字符。
  • 到期时,on_expiry: "approve" 会使该步骤成功,"reject" 会跳过该步骤,"fail" 会使运行失败。重试运行时会创建新的审核任务。
  • 第二次作出不同决定会返回 409 review_conflict。逾期决定会返回 409 review_expired 或 409 review_not_pending。再次作出相同决定会返回已记录的决定。
  • getPipelineReview 会按照运行中 steps 的顺序返回 input_namespaces。使用 getPipelineRunOutputs(client, review.run_id, namespace) 读取每个命名空间。
端点步骤

createPipelineEndpoint(client, { url, headers, timeout_ms, callback_timeout_ms, max_concurrency }) 用于注册你的服务。

  • url 必须使用 HTTPS,并解析到公共地址。最多可设置 16 个 headers。
  • 默认值:timeout_ms 为 30000(1000–600000),callback_timeout_ms 为 3600000(1000–2592000000),max_concurrency 为 8(1–1024,适用于所有运行)。
  • 响应中仅会返回一次 signing_secret(whsec_...)。请立即妥善保存。
  • 如需更改限制,请使用 updatePipelineEndpoint(client, id, { timeout_ms, callback_timeout_ms, max_concurrency })。只发送要更改的限制。取值范围不变。更改后发送的请求将使用新限制。
  • 请求正文为空或值超出范围时,会返回 422 invalid_request。已归档的端点会返回 409 endpoint_archived。
  • 你不能更改 URL、请求头或签名密钥。如需更改,请创建新端点和新流水线版本,然后归档旧端点。
  • 如果某次运行所指定的版本引用了已归档的端点,该运行会失败,并返回 endpoint_not_found。

Editframe 会发送带有 Standard Webhooks 请求头的签名 POST 请求。请求正文包含 file、window(文件步骤时为 null)、media URL、metadata(按命名空间列出的所需步骤输出)、idempotency_key 和 callback。媒体 URL 无需 API 密钥,并会在 media.expires_at 时过期,最长不超过四小时。

import { postPipelineCallback, verifyPipelineEndpointRequest } from "@editframe/api/pipelines";

// Pass the raw body bytes. Re-serialized JSON does not verify.
const request = await verifyPipelineEndpointRequest({ secret: process.env.EDITFRAME_ENDPOINT_SECRET!, headers: req.headers, body: rawBody });
// Option 1: answer 200 with { metadata, annotations }.
// Option 2: answer 202, and then post the result:
await postPipelineCallback(request.callback.url, { status: "succeeded", output: { metadata: {}, annotations: [] } });
  • 除 202 外的 2xx 响应会提供输出。响应正文为空时,输出也为空。
  • 408、429 或 5xx 响应、超时或连接错误都会触发重试。最长一小时的 Retry-After 会设定延迟时间。
  • 重定向或其他 4xx 响应会使步骤失败,且不会重试。
  • 收到 202 后,请在截止时间之前发送 { status: "heartbeat" },以将截止时间延长 callback_timeout_ms。
  • 如需报告失败,请发送 { status: "failed", error: { message, code?, retryable } }。
  • 对于无需等待的尝试,其回调会返回 409 step_not_waiting。

输出格式为 { metadata?, annotations? },大小最多为 1 MiB,且最多包含 10,000 个注释。注释包含 kind、start_ms 和 end_ms。还可以包含 label、text、confidence(0–1)、track_id 和 keyframes。关键帧格式为 { t_ms, x, y, w, h },坐标采用归一化的 0–1 帧坐标。

运行、分组和输出
  • createPipelineRun(client, { pipeline_id, version?, group_id?, file_id, external_id?, metadata? }, { idempotencyKey }) 会返回 { run, created }。文件类型必须为 video。默认使用最新版本。
  • 仅当请求完全相同时,才可复用 idempotencyKey。请求正文不同会返回 409 idempotency_conflict。
  • metadata 是一个字符串映射:最多 32 个键,每个键为 1–256 字节,值最多为 1024 字节,紧凑 JSON 总大小为 8192 字节。创建运行后无法更改。它不是步骤写入的文件元数据。
  • listPipelineRuns(client, { status, pipeline_id, file_id, group_id, metadata }) 会按时间从新到旧返回运行。使用 metadata 筛选时,只会返回包含所有指定条目的运行。
  • 流水线、版本、端点、运行和分组都包含 created_by 和 created_via。created_by 的格式为 { type: "api_key" | "user", id }:前者表示发送请求的 API 密钥,后者表示使用控制面板或未使用 API 密钥发送请求的用户。created_via 为 "api" 或 "dashboard"。如果 Editframe 未记录创建者,这两个字段均为 null。

一个分组包含同一流水线版本的多个运行。你可以使用分组跟踪一组运行、限制同时运行的运行数量,并在所有运行完成时接收一个事件。

  • createPipelineGroup(client, { pipeline_id, version?, runs?, close?, max_in_flight?, external_id?, metadata? }, { idempotencyKey }) 返回 { group, created }。runs 包含 0–1000 个不同文件的条目:{ file_id, external_id?, metadata? }。运行不会继承其分组的元数据。
  • max_in_flight 的范围为 1–100000(默认值为 100)。其他运行会保持 pending 状态,并按最早创建的顺序启动。
  • 如需更改此限制,请使用 updatePipelineGroup(client, id, { max_in_flight }) 或 editframe pipelines groups update GROUP_ID --max-in-flight N。分组处于任何状态时都可以更改。提高限制后,等待中的运行会立即启动。降低限制后,正在运行的运行会继续执行。
  • Editframe 会记录每次关闭操作和每次 max_in_flight 更改,以及执行操作的 API 密钥或用户。仪表板会显示此更改历史记录。如果更改后的值与当前值相同,则不会记录。
  • 如需稍后添加运行,请使用 group_id 调用 createPipelineRun。该运行使用分组的版本。错误:404 group_not_found、409 group_closed,以及当 pipeline_id 或 version 与分组不同时返回的 409 group_version_mismatch。
  • 分组状态:open(接受运行)、closed(不接受运行,且部分运行尚未完成)和 completed(已关闭,且所有运行均已完成)。
  • 开放分组不会自动完成。最后一个运行后,请调用 closePipelineGroup(client, id),或创建分组时设置 close: true。如果分组中的所有运行都已完成,则关闭分组后分组会完成。
  • 重试已完成分组中的运行会使分组状态再次变为 closed。completion_count 用于统计完成次数。
  • listPipelineGroups(client, { status, pipeline_id, metadata }) 和 getPipelineGroup(client, id) 会返回包含运行计数的分组。
  • getPipelineGroupReport(client, id) 会返回各状态的运行计数、queue_wait_ms 和 run_duration_ms(p50、p95、max)、输入的 media_minutes、包含最常见的五个错误代码的 step_failures,以及 usage。

运行和步骤:

  • 运行状态:pending、running、succeeded、failed、filtered、cancelled。filtered 表示筛选器或审核在所有分支到达最终步骤之前将其停止。这不属于错误。如果某个分支已停止,但最终步骤成功,则运行状态为 succeeded。
  • 步骤状态:pending、ready、running、waiting_external、waiting_review、succeeded、failed、skipped、cancelled。
  • getPipelineRun 按深度排序,再按步骤键排序返回 steps。不带 needs 的步骤深度为 0。其他步骤的深度比其 needs 中最大深度大 1。因此,每个步骤都排在其依赖步骤之后。
  • 每个步骤或窗口有 3 次尝试。重试间隔从 10 秒开始,每次翻倍,最长为 10 分钟。
  • 如果解码器停止(例如工作进程内存不足),transcribe、sample_frames 或 detect_scenes 的某次尝试会因 decoder_killed 而失败。此失败会启动重试。无法由步骤解码的文件会因 decode_failed 而失败,且不会启动重试。
  • 对于已成功、失败或以 filtered 结束的运行,cancelPipelineRun 会返回 409 run_not_cancellable。
  • retryPipelineRun 仅适用于状态为 failed 和 cancelled 的运行。其他运行会返回 409 run_not_retryable。成功的步骤会保留其输出。
  • getPipelineRunOutputs(client, runId, namespace) 会返回分页输出,每个分段步骤窗口对应一页。
  • getFilePipelineMetadata(client, fileId, namespace) 会返回文件在任何运行中产生的最新输出。
  • 请求失败时会抛出 PipelineApiError,其中包含 status、code 和 issues([{ path, code }])。

如需在上传完成前启动运行,请使用 @editframe/api/pipelines/upload 中的 uploadFragmented 上传。在 onCreated 中启动运行。片段步骤会在媒体到达时处理各个窗口。

import { uploadFragmented } from "@editframe/api/pipelines/upload";

await uploadFragmented(client, "dashcam.mp4", {
  onCreated: async (file) => {
    await createPipelineRun(client, { pipeline_id: pipelineId, file_id: file.id }, { idempotencyKey: `upload:${file.id}` });
  },
});

有关管道 Webhook 主题,请参阅 webhooks 技能。

暂停流水线

要停止新任务并保留运行记录,请暂停流水线。暂停操作适用于流水线的所有版本。

import { pausePipeline, resumePipeline } from "@editframe/api/pipelines";

const paused = await pausePipeline(client, pipelineId); // paused.paused_at is the time of the pause.
await resumePipeline(client, pipelineId); // paused_at is null again.
  • 暂停的流水线仍接受新版本、运行和组。新的运行会保持 pending 状态。
  • 恢复流水线之前,不会启动任何运行、步骤、尝试或片段窗口。
  • 暂停前已启动的尝试会继续执行。Editframe 会记录其端点回调和审核决定。
  • 未启动的步骤不会获得截止时间,因此暂停不会导致超时。
  • 你可以取消并重试运行。重试的运行会保持 pending 状态,直到恢复流水线。
  • 恢复流水线后,等待中的运行和步骤会立即启动。
  • 再次暂停或恢复不会改变任何内容,也不会记录任何操作。已归档的流水线会返回 409 pipeline_archived。
  • Editframe 会记录每次暂停和恢复操作,以及执行操作的 API 密钥或用户。仪表板会显示此变更历史。
  • 暂停和恢复不会发送 Webhook。未启动的运行不会记录用量。
  • listPipelines(client, { paused: true }) 仅返回已暂停的流水线。
流水线 CLI

editframe pipelines 直接调用云 API。它会从 EDITFRAME_TOKEN 读取 API 密钥。它不会使用 --project、--bridge 或其他运行时选项。

export EDITFRAME_TOKEN="$EDITFRAME_API_KEY"
npx editframe pipelines create speech-check --definition speech-check.json
npx editframe pipelines runs create PIPELINE_ID FILE_ID --watch
npx editframe pipelines upload dashcam.mp4 --run PIPELINE_ID --watch
npx editframe pipelines reviews approve REVIEW_ID --patch corrections.json
npx editframe pipelines pause PIPELINE_ID
npx editframe pipelines resume PIPELINE_ID
  • 如果运行失败或已取消,--watch 会以状态码 1 退出。
  • --json 会以 JSON 格式打印 API 响应。
  • 运行 npx editframe pipelines --help 查看所有命令。

发送反馈

向 Editframe 反馈问题和改进建议:

  • 如果 Editframe 或 Editframe 技能导致问题,请找到变通方法并继续任务。然后报告问题及变通方法。
  • 如果发现有助于其他任务(而不仅仅是当前任务)的改进,请发送建议。例如,建议改进说明、补充示例、优化默认设置或添加新功能。

每个不同的问题或建议分别提交一份报告。如果报告提交失败,请继续任务。

const headers: Record<string, string> = { "Content-Type": "application/json" };
if (process.env.EDITFRAME_API_KEY) headers.Authorization = `Bearer ${process.env.EDITFRAME_API_KEY}`;

const response = await fetch("https://editframe.com/api/v1/feedback", {
  method: "POST",
  headers,
  body: JSON.stringify({
    category: "feature_request",
    skill: "editframe-api",
    summary: "Add a function that cancels a render",
    details: "A render started with the wrong input. No function stops it, so the render uses time and quota.",
    workaround: "I let the render finish and ignored the output.",
    context: { render_id: render.id, package: "@editframe/api" },
  }),
});

将请求正文设为 application/json。

字段必填限制内容
category是—以下类别之一
summary是200 个字符用一行概述问题或建议
details是10,000 个字符对于问题:操作步骤、预期结果、实际结果和错误消息。对于建议:变更内容及其帮助。
workaround否10,000 个字符针对问题所采用的变通方法
skill否100 个字符所用技能,例如 composition
context否20 个条目仅限字符串值,例如 render_id、file_id 或软件包版本。键长为 1–64 个字符。值最长为 1,000 个字符。
类别用途
bugEditframe 的运行方式与文档所述不符。
documentation技能或文档有误、不清晰或不完整。
feature_requestEditframe 缺少你需要的功能。
performance操作速度慢或占用资源过多。
other其他所有问题和建议,例如有关工作流或 API 设计的问题。

请求正文上限为 256 KiB。未知字段会导致错误。

Authorization 标头为可选项。提供有效 API 密钥的报告会标识你的组织。未提供密钥的报告为匿名报告。请勿在报告中填写机密信息、API 密钥或个人数据。

状态正文操作
201{ "id", "created_at" }无需操作。Editframe 已收到报告。
400{ "error": "invalid_json" | "invalid_feedback", "message" }根据 message 修正报告并重新发送。
401UnauthorizedAPI 密钥无效。移除 Authorization 标头后重新发送报告。
413{ "error": "payload_too_large", "message" }缩短报告。
415{ "error": "unsupported_media_type", "message" }设置 Content-Type: application/json。
429{ "error": "rate_limited", "message" }在 Retry-After 指定的间隔内不要发送更多报告。
503{ "error": "unavailable", "message" }在 Retry-After 指定的间隔后,再发送一次报告。

函数索引

字幕文件
  • createCaptionFile(client: Client, payload: CreateCaptionFilePayload) — 创建字幕文件
  • lookupCaptionFileByMd5(client: Client, md5: string)
  • uploadCaptionFile(client: Client, fileId: string, fileStream: ReadableStream, fileSize: number)
文件
  • createFile(client: Client, payload: CreateFilePayload)
  • createFileTrack(client: Client, fileId: string, payload: CreateISOBMFFTrackPayload)
  • deleteFile(client: Client, id: string)
  • getFileDetail(client: Client, id: string)
  • getFileProcessingProgress(client: Client, id: string)
  • getFileTranscription(client: Client, id: string)
  • lookupFileByMd5(client: Client, md5: string)
  • transcribeFile(client: Client, id: string, options?: { trackId?: number }) — 请勿使用。该端点会返回 410 Gone。要转录文件,请启动一个包含 transcribe 步骤的流水线运行。
  • uploadFile(client: Client, uploadDetails: { id: string; byte_size: number; type: FileType }, fileStream: ReadableStream)
  • uploadFileIndex(client: Client, fileId: string, fileStream: ReadableStream, fileSize: number)
  • uploadFileTrack(client: Client, fileId: string, trackId: number, byteSize: number, fileStream: ReadableStream)
图像文件
  • createImageFile(client: Client, payload: CreateImageFilePayload)
  • getImageFileMetadata(client: Client, id: string)
  • lookupImageFileByMd5(client: Client, md5: string)
  • uploadImageFile(client: Client, uploadDetails: { id: string; byte_size: number; }, fileStream: ReadableStream, chunkSizeBytes?: number)
Isobmff 文件
  • createISOBMFFFile(client: Client, payload: CreateISOBMFFFilePayload)
  • getISOBMFFFileTranscription(client: Client, id: string)
  • lookupISOBMFFFileByMd5(client: Client, md5: string)
  • transcribeISOBMFFFile(client: Client, id: string, payload?: TranscribeISOBMFFFilePayload) — 请勿使用。该端点会返回 410 Gone。要转录文件,请启动一个包含 transcribe 步骤的流水线运行。
  • uploadFragmentIndex(client: Client, fileId: string, fileStream: ReadableStream, fileSize: number)
Isobmff 轨道
  • createISOBMFFTrack(client: Client, payload: CreateISOBMFFTrackPayload)
  • uploadISOBMFFTrack(client: Client, fileId: string, trackId: number, fileStream: ReadableStream, trackSize: number)
Node
  • createImageFileFromPath(client: Client, path: string)
  • createUnprocessedFileFromPath(client: Client, path: string)
  • upload(client: Client, filePath: string)
  • uploadUnprocessedFile(client: Client, uploadDetails: UnprocessedFileUploadDetails, path: string)
Isobmff 处理
  • getIsobmffProcessInfo(client: Client, id: string)
  • getIsobmffProcessProgress(client: Client, id: string)
渲染
  • createRender(client: Client, payload: CreateRenderPayload)
  • defaultWorkSliceMs()
  • deleteRender(client: Client, id: string)
  • downloadRender(client: Client, id: string)
  • getRenderInfo(client: Client, id: string)
  • getRenderProgress(client: Client, id: string)
  • lookupRenderByMd5(client: Client, md5: string)
  • uploadRender(client: Client, renderId: string, fileStream: ReadableStream)
转录
  • createTranscription(client: Client, payload: CreateTranscriptionPayload) — 请勿使用。该端点会返回 410 Gone。要转录文件,请启动一个包含 transcribe 步骤的流水线运行。
  • getTranscriptionInfo(client: Client, id: string)
  • getTranscriptionProgress(client: Client, id: string)
未处理文件
  • createUnprocessedFile(client: Client, payload: CreateUnprocessedFilePayload)
  • lookupUnprocessedFileByMd5(client: Client, md5: string)
  • processIsobmffFile(client: Client, id: string)
  • uploadUnprocessedReadableStream(client: Client, uploadDetails: UnprocessedFileUploadDetails, fileStream: ReadableStream)
URL 令牌
  • createURLToken(client: Client, url: string)

CLI 命令

全局选项:

选项默认值说明
-h, --help—显示用法
--version—显示 CLI 版本
--project <value>—本地项目的绝对目录
--bridge <value>—已安装的桥接可执行文件
--component <value>—已安装的已签名组件目录
--registry <value>—本地桥接注册表目录
--editor <value>—已验证的编辑器资源目录
--editor-version <value>—已验证的编辑器版本
--compiler-pack <value>—已验证的编译器包文件
--compiler-pack-sha256 <value>—预期的编译器包 SHA-256
--endpoint <value>—托管运行时 API 端点
--project-id <value>—托管项目标识符
--composition <value>—合成标识符
--input <value>—包含显式操作标识和修订版本的 JSON 请求文件
--job <value>—作业标识符
-o, --output <value>—渲染时写入的 MP4 文件(默认值为 output.mp4)
命令用途
editframe command应用显式指定修订版本的合成命令
editframe compositions列出所选项目中的合成
editframe context读取合成的修订版本和编辑上下文
editframe export请求导出所选合成
editframe job读取一个项目作业
editframe jobs列出项目作业
editframe mcp通过 MCP stdio 将 Agent 连接到本地桥接
editframe open打开本地浏览器编辑器
editframe pipelines管理云端管道、运行、分组和审核
editframe projects列出可访问的项目
editframe render通过本地运行时和无头 Chrome 将合成渲染为 MP4
editframe start为项目启动已安装的本地桥接
editframe status显示本地桥接状态
editframe stop停止项目的本地桥接

评论

支持 Markdown