关于 editframe-api
面向 JavaScript/TypeScript 开发者的 Editframe API 客户端和命令行工具,用于视频渲染、媒体上传处理及本地项目导出。命令行工具通过已安装的 Editframe 运行时连接编辑器和本地桥接程序。
主要功能
- 01创建渲染任务并查看进度
- 02上传视频、图片和字幕文件
- 03通过流水线转录音频
- 04为媒体访问签署 URL
- 05打开编辑器并提交本地导出任务
适用场景
- 01从 Editframe 合成内容生成视频
- 02上传并处理媒体素材
- 03通过流水线生成语音标注
- 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 字段用于选择端点行为:
| 类型 | 格式 | 最大大小 | 处理方式 |
|---|---|---|---|
video | MP4、MOV、WebM、MKV | 1GB | 自动转换为 ISOBMFF(支持帧精确定位和自适应流式传输) |
image | JPEG、PNG、WebP、SVG | 16MB | 立即就绪 |
caption | VTT、SRT | 2MB | 立即就绪 |
状态生命周期: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、transcribe | CLI 无对应替代项。请使用浏览器编辑器。应用构建使用 @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 | 该类型的选项 |
when | filter 必填。其他类型不允许使用。 |
| 类型 | with(默认值) | 输出 |
|---|---|---|
probe | 不允许 | 元数据 duration_ms、width、height、has_video、has_audio、source、tracks |
transcribe | 不允许 | speech.segment 和 speech.word 注释。元数据 word_count、segment_count、truncated 等。 |
sample_frames | every_ms 100–600000(1000) | 第一个视频轨道的 JPEG 帧 |
detect_scenes | threshold 0.01–1(0.3) | scene.cut 注释。元数据 cut_count。 |
endpoint | endpoint_id(必填),max_concurrency 1–1024(8) | 服务的输出 |
filter | 不允许 | 无输出。该步骤成功或跳过。 |
review | instructions 1–2000 个字符,expires_after_ms 60000–2592000000(604800000),on_expiry 为 fail/approve/reject(fail) | 决策和修正后的注释 |
redact_render | kinds:1–32 种注释类型(必填),captions 布尔值(false),title:{ text: 1–120 characters, duration_ms: 1000–15000 (4000) } | 元数据 render_id、status、output_url、output_file_id 和计数 |
publish | formats: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 个字符。 |
| 类别 | 用途 |
|---|---|
bug | Editframe 的运行方式与文档所述不符。 |
documentation | 技能或文档有误、不清晰或不完整。 |
feature_request | Editframe 缺少你需要的功能。 |
performance | 操作速度慢或占用资源过多。 |
other | 其他所有问题和建议,例如有关工作流或 API 设计的问题。 |
请求正文上限为 256 KiB。未知字段会导致错误。
Authorization 标头为可选项。提供有效 API 密钥的报告会标识你的组织。未提供密钥的报告为匿名报告。请勿在报告中填写机密信息、API 密钥或个人数据。
| 状态 | 正文 | 操作 |
|---|---|---|
201 | { "id", "created_at" } | 无需操作。Editframe 已收到报告。 |
400 | { "error": "invalid_json" | "invalid_feedback", "message" } | 根据 message 修正报告并重新发送。 |
401 | Unauthorized | API 密钥无效。移除 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 | 停止项目的本地桥接 |