focalapi-cli 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -0
- package/dist/cli.js +78 -65
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.6.0 - 2026-08-26
|
|
4
|
+
|
|
5
|
+
- Retired `gen omni-video` with a local redirect to `gen video -m gemini-omni-flash-preview`: the gateway rejects the Interactions endpoint for this model in every shape (video matrix evidence 2026-08-26). All four capabilities (t2v/first-frame/reference/edit) ride the video facade.
|
|
6
|
+
- Added task-parameter flags to `gen video`, mapped to the task DTO's top-level fields with local enum validation: `--omni-reference-task-type` (seedance 2.5 edit/extend semantics were unreachable — auto-inference conflicts with the default duration), `--voice`/`--avatar` (HeyGen, enums now published by the platform), `--operation` (Bria), `--enhance-model` (HitPaw), and `--upscaler-model` (Topaz).
|
|
7
|
+
- Added local constraint tables for the August video wave (wan2.7 ×4, pixverse-v5, kling-v3-omni, luma-ray-3-2, MiniMax-H3, HeyGen ×2, happyhorse ×4, topaz/hitpaw video, beeble, bria, veo 3.1 ×3): duration tiers and resolutions are validated locally, and source-length families (heygen, topaz/hitpaw video, beeble, bria, happyhorse video-edit) reject `--seconds` up front instead of round-tripping a guaranteed 400.
|
|
8
|
+
|
|
9
|
+
## 0.5.1 - 2026-08-26
|
|
10
|
+
|
|
11
|
+
- Added `@file` support to `--style-references` and `--moodboards`: the JSON array can now be read from a file instead of inline argv. Windows `cmd` mangles embedded double quotes in JSON arguments (matrix-run evidence 2026-08-25), and the file source sidesteps shell quoting entirely.
|
|
12
|
+
|
|
3
13
|
## 0.5.0 - 2026-08-25
|
|
4
14
|
|
|
5
15
|
- Fixed `krea-2-medium/-turbo/large` reference-image validation: the local table said 0 while the platform contract accepts up to 10 reference images (each maps to a Krea style reference), so every `gen image --image` edit was rejected locally without reaching the server (2026-08-25 live audit P01).
|
package/dist/cli.js
CHANGED
|
@@ -176,7 +176,7 @@ function displayWidth(s) {
|
|
|
176
176
|
}
|
|
177
177
|
|
|
178
178
|
// src/lib/version.ts
|
|
179
|
-
var VERSION = true ? "0.
|
|
179
|
+
var VERSION = true ? "0.6.0" : "0.0.0-dev";
|
|
180
180
|
|
|
181
181
|
// src/commands/auth.ts
|
|
182
182
|
import { createInterface } from "readline/promises";
|
|
@@ -1321,6 +1321,42 @@ var VIDEO_CONSTRAINTS = {
|
|
|
1321
1321
|
maxReferenceImages: 2,
|
|
1322
1322
|
supportsGenerateAudio: true
|
|
1323
1323
|
},
|
|
1324
|
+
"wan2.7-t2v": { resolutions: ["720p", "1080p"], minSeconds: 2, maxSeconds: 15 },
|
|
1325
|
+
"wan2.7-i2v": { resolutions: ["720p", "1080p"], minSeconds: 2, maxSeconds: 15 },
|
|
1326
|
+
"wan2.7-r2v": { resolutions: ["720p", "1080p"], minSeconds: 2, maxSeconds: 15 },
|
|
1327
|
+
"wan2.7-videoedit": { resolutions: ["720p", "1080p"], minSeconds: 2, maxSeconds: 10 },
|
|
1328
|
+
"pixverse-v5": { resolutions: ["360p", "540p", "720p", "1080p"], minSeconds: 5, maxSeconds: 8, allowedSeconds: [5, 8] },
|
|
1329
|
+
"kling-v3-omni": { resolutions: ["720p", "1080p", "4k"], minSeconds: 3, maxSeconds: 15 },
|
|
1330
|
+
"luma-ray-3-2": { resolutions: ["540p", "720p", "1080p"], minSeconds: 5, maxSeconds: 10, allowedSeconds: [5, 10] },
|
|
1331
|
+
"MiniMax-H3": { resolutions: ["768p", "2k"], minSeconds: 5, maxSeconds: 15 },
|
|
1332
|
+
"heygen-talking-photo": { resolutions: ["720p", "1080p"], noDuration: true },
|
|
1333
|
+
"heygen-avatar": { resolutions: ["720p", "1080p"], noDuration: true },
|
|
1334
|
+
"happyhorse-1.1-t2v": { resolutions: ["720p", "1080p"], minSeconds: 3, maxSeconds: 15 },
|
|
1335
|
+
"happyhorse-1.1-i2v": { resolutions: ["720p", "1080p"], minSeconds: 3, maxSeconds: 15 },
|
|
1336
|
+
"happyhorse-1.1-r2v": { resolutions: ["720p", "1080p"], minSeconds: 3, maxSeconds: 15 },
|
|
1337
|
+
"happyhorse-1.0-video-edit": { resolutions: ["720p", "1080p"], noDuration: true },
|
|
1338
|
+
"topaz-video-enhance": { resolutions: ["1080p", "2160p"], noDuration: true },
|
|
1339
|
+
"hitpaw-video-enhance": { resolutions: ["original", "720p", "1080p", "2k/qhd", "4k/uhd", "8k"], noDuration: true },
|
|
1340
|
+
"beeble-switchx-video": { resolutions: ["720p", "1080p"], noDuration: true },
|
|
1341
|
+
"bria-video-edit": { noDuration: true },
|
|
1342
|
+
"veo-3.1-generate-preview": {
|
|
1343
|
+
resolutions: ["720p", "1080p"],
|
|
1344
|
+
minSeconds: 4,
|
|
1345
|
+
maxSeconds: 8,
|
|
1346
|
+
allowedSeconds: [4, 6, 8]
|
|
1347
|
+
},
|
|
1348
|
+
"veo-3.1-fast-generate-preview": {
|
|
1349
|
+
resolutions: ["720p", "1080p"],
|
|
1350
|
+
minSeconds: 4,
|
|
1351
|
+
maxSeconds: 8,
|
|
1352
|
+
allowedSeconds: [4, 6, 8]
|
|
1353
|
+
},
|
|
1354
|
+
"veo-3.1-lite-generate-preview": {
|
|
1355
|
+
resolutions: ["720p", "1080p"],
|
|
1356
|
+
minSeconds: 4,
|
|
1357
|
+
maxSeconds: 8,
|
|
1358
|
+
allowedSeconds: [4, 6, 8]
|
|
1359
|
+
},
|
|
1324
1360
|
"flux-3": {
|
|
1325
1361
|
resolutions: ["hd", "fhd"],
|
|
1326
1362
|
ratios: FLUX_VIDEO_RATIOS,
|
|
@@ -1523,6 +1559,9 @@ function validateGeminiImageGeneration(model, input) {
|
|
|
1523
1559
|
function validateVideoGeneration(model, input) {
|
|
1524
1560
|
const constraint = VIDEO_CONSTRAINTS[model.trim()];
|
|
1525
1561
|
if (!constraint) return;
|
|
1562
|
+
if (constraint.noDuration && input.seconds !== void 0) {
|
|
1563
|
+
throw new ApiError("invalid_request", `${model} does not accept a duration; the output length follows the source media`);
|
|
1564
|
+
}
|
|
1526
1565
|
if (constraint.maxPromptRunes !== void 0 && input.promptRunes !== void 0) {
|
|
1527
1566
|
const referenceCount = input.imageCount ?? input.firstFrameCount ?? 0;
|
|
1528
1567
|
if (input.promptRunes + 500 * referenceCount > constraint.maxPromptRunes) {
|
|
@@ -1547,13 +1586,13 @@ function validateVideoGeneration(model, input) {
|
|
|
1547
1586
|
if (input.watermark !== void 0 && constraint.supportsWatermark === false) {
|
|
1548
1587
|
throw new ApiError("invalid_request", `${model} does not support watermark`);
|
|
1549
1588
|
}
|
|
1550
|
-
if (input.seconds !== void 0 && (input.seconds < constraint.minSeconds || input.seconds > constraint.maxSeconds)) {
|
|
1589
|
+
if (input.seconds !== void 0 && constraint.minSeconds !== void 0 && constraint.maxSeconds !== void 0 && (input.seconds < constraint.minSeconds || input.seconds > constraint.maxSeconds)) {
|
|
1551
1590
|
throw new ApiError("invalid_request", `${model} seconds must be ${constraint.minSeconds}-${constraint.maxSeconds} (received: ${input.seconds})`);
|
|
1552
1591
|
}
|
|
1553
1592
|
if (input.seconds !== void 0 && constraint.allowedSeconds && !constraint.allowedSeconds.includes(input.seconds)) {
|
|
1554
1593
|
throw new ApiError("invalid_request", `${model} seconds must be one of ${constraint.allowedSeconds.join(", ")} (received: ${input.seconds})`);
|
|
1555
1594
|
}
|
|
1556
|
-
if (input.resolution && !constraint.resolutions.includes(input.resolution.toLowerCase())) {
|
|
1595
|
+
if (input.resolution && constraint.resolutions && !constraint.resolutions.includes(input.resolution.toLowerCase())) {
|
|
1557
1596
|
throw new ApiError("invalid_request", `${model} resolution must be one of ${constraint.resolutions.join(", ")} (received: ${input.resolution})`);
|
|
1558
1597
|
}
|
|
1559
1598
|
if (input.resolution && (input.imageCount ?? 0) > 0 && constraint.referenceResolutions && !constraint.referenceResolutions.includes(input.resolution.toLowerCase())) {
|
|
@@ -1943,6 +1982,15 @@ function parseJsonArray(raw, option) {
|
|
|
1943
1982
|
throw new ApiError("invalid_request", `--${option} must be a JSON array`);
|
|
1944
1983
|
}
|
|
1945
1984
|
}
|
|
1985
|
+
async function readJsonArrayArgument(raw, option) {
|
|
1986
|
+
if (!raw.startsWith("@")) return parseJsonArray(raw, option);
|
|
1987
|
+
try {
|
|
1988
|
+
return parseJsonArray((await readFile(normalizeHomePath(raw.slice(1)), "utf8")).trim(), option);
|
|
1989
|
+
} catch (error) {
|
|
1990
|
+
if (error instanceof ApiError) throw error;
|
|
1991
|
+
throw new ApiError("invalid_request", `--${option} @file \u65E0\u6CD5\u8BFB\u53D6\uFF1A${raw.slice(1, 120)}`);
|
|
1992
|
+
}
|
|
1993
|
+
}
|
|
1946
1994
|
var MAX_CONTENT_FILE_BYTES = 64 * 1024 * 1024;
|
|
1947
1995
|
async function readContentArgument(raw) {
|
|
1948
1996
|
if (raw === "-") {
|
|
@@ -2046,24 +2094,6 @@ function geminiImagePart(source) {
|
|
|
2046
2094
|
}
|
|
2047
2095
|
return { fileData: { fileUri: source } };
|
|
2048
2096
|
}
|
|
2049
|
-
function geminiOmniImageInput(source) {
|
|
2050
|
-
const dataUri = /^data:([^;,]+);base64,([a-z0-9+/=\r\n]+)$/i.exec(source.trim());
|
|
2051
|
-
if (!dataUri) {
|
|
2052
|
-
throw new ApiError("invalid_request", "--image for Gemini Omni must be a base64 data URI");
|
|
2053
|
-
}
|
|
2054
|
-
const [, mimeType = "", data = ""] = dataUri;
|
|
2055
|
-
return { type: "image", mime_type: mimeType, data: data.replace(/[\r\n]/g, "") };
|
|
2056
|
-
}
|
|
2057
|
-
function extractGeminiOmniVideo(response) {
|
|
2058
|
-
for (const step of response.steps ?? []) {
|
|
2059
|
-
for (const content of step.content ?? []) {
|
|
2060
|
-
if (content.type === "video" && content.data) {
|
|
2061
|
-
return { data: content.data, mimeType: content.mime_type };
|
|
2062
|
-
}
|
|
2063
|
-
}
|
|
2064
|
-
}
|
|
2065
|
-
return void 0;
|
|
2066
|
-
}
|
|
2067
2097
|
function extractGeminiImageItems(response) {
|
|
2068
2098
|
return (response.candidates ?? []).flatMap(
|
|
2069
2099
|
(candidate) => (candidate.content?.parts ?? []).flatMap(
|
|
@@ -2079,8 +2109,8 @@ function registerGen(program) {
|
|
|
2079
2109
|
const model = opts.model ?? (await resolveCreativeModel(auth, "image")).model.id;
|
|
2080
2110
|
if (!opts.model && !g.json) info(`\u5DF2\u81EA\u52A8\u9009\u62E9\u56FE\u50CF\u6A21\u578B\uFF1A${model}`);
|
|
2081
2111
|
const n = clampInt(opts.n, 1, MAX_IMAGE_N, "n");
|
|
2082
|
-
const styleReferences = opts.styleReferences ?
|
|
2083
|
-
const moodboards = opts.moodboards ?
|
|
2112
|
+
const styleReferences = opts.styleReferences ? await readJsonArrayArgument(opts.styleReferences, "style-references") : void 0;
|
|
2113
|
+
const moodboards = opts.moodboards ? await readJsonArrayArgument(opts.moodboards, "moodboards") : void 0;
|
|
2084
2114
|
const referenceImages = await resolveMediaInputs(opts.image ?? []);
|
|
2085
2115
|
const maskImage = (await resolveMediaInputs(opts.mask ? [opts.mask] : []))[0];
|
|
2086
2116
|
validateImageGeneration(model, {
|
|
@@ -2232,49 +2262,10 @@ function registerGen(program) {
|
|
|
2232
2262
|
for (const file of files) info(`\u2713 ${file}`);
|
|
2233
2263
|
}
|
|
2234
2264
|
});
|
|
2235
|
-
gen.command("omni-video").description("\
|
|
2236
|
-
|
|
2237
|
-
const auth = resolveAuth(g);
|
|
2238
|
-
if (opts.aspectRatio && !["16:9", "9:16"].includes(opts.aspectRatio)) {
|
|
2239
|
-
throw new ApiError("invalid_request", "--aspect-ratio must be 16:9 or 9:16");
|
|
2240
|
-
}
|
|
2241
|
-
if (opts.task && !["text_to_video", "image_to_video", "reference_to_video", "edit"].includes(opts.task)) {
|
|
2242
|
-
throw new ApiError("invalid_request", "--task must be text_to_video, image_to_video, reference_to_video, or edit");
|
|
2243
|
-
}
|
|
2244
|
-
const prompt = promptParts.join(" ");
|
|
2245
|
-
const imageInputs = (opts.image ?? []).map(geminiOmniImageInput);
|
|
2246
|
-
const input = imageInputs.length === 0 ? prompt : [...imageInputs, { type: "text", text: prompt }];
|
|
2247
|
-
const res = await withProgress("\u6B63\u5728\u751F\u6210 Gemini Omni \u89C6\u9891", () => request({
|
|
2248
|
-
baseUrl: auth.baseUrl,
|
|
2249
|
-
path: "/v1beta/interactions",
|
|
2250
|
-
apiKey: auth.apiKey,
|
|
2251
|
-
body: {
|
|
2252
|
-
model: "gemini-omni-flash-preview",
|
|
2253
|
-
input,
|
|
2254
|
-
...opts.previousInteractionId ? { previous_interaction_id: opts.previousInteractionId } : {},
|
|
2255
|
-
...opts.aspectRatio ? { response_format: { type: "video", aspect_ratio: opts.aspectRatio } } : {},
|
|
2256
|
-
...opts.task ? { generation_config: { video_config: { task: opts.task } } } : {}
|
|
2257
|
-
},
|
|
2258
|
-
timeoutMs: 6e5
|
|
2259
|
-
}));
|
|
2260
|
-
const video = extractGeminiOmniVideo(res);
|
|
2261
|
-
if (!video) {
|
|
2262
|
-
throw new ApiError("bad_response", "Gemini Omni \u54CD\u5E94\u4E2D\u672A\u627E\u5230\u89C6\u9891\u6570\u636E", { body: res });
|
|
2263
|
-
}
|
|
2264
|
-
const dir = resolve2(opts.out);
|
|
2265
|
-
await mkdir2(dir, { recursive: true });
|
|
2266
|
-
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
2267
|
-
const extension = video.mimeType?.includes("webm") ? ".webm" : ".mp4";
|
|
2268
|
-
const file = join3(dir, `gemini-omni-${timestamp}${extension}`);
|
|
2269
|
-
await writeFile(file, Buffer.from(video.data, "base64"));
|
|
2270
|
-
if (g.json) {
|
|
2271
|
-
printJson({ interaction_id: res.id, file });
|
|
2272
|
-
} else {
|
|
2273
|
-
info(`\u2713 ${file}`);
|
|
2274
|
-
if (res.id) info(`\u4EA4\u4E92 ID\uFF1A${res.id}`);
|
|
2275
|
-
}
|
|
2265
|
+
gen.command("omni-video").description("\u5DF2\u4E0B\u7EBF\uFF1AGemini Omni Flash \u5168\u90E8\u80FD\u529B\u6539\u8D70 gen video \u95E8\u9762").allowUnknownOption().action(async () => {
|
|
2266
|
+
throw new ApiError("invalid_request", "gen omni-video \u5DF2\u4E0B\u7EBF\uFF1Agemini-omni-flash-preview \u7684\u6587\u751F\u89C6\u9891/\u9996\u5E27/\u53C2\u8003/\u7F16\u8F91\u80FD\u529B\u5168\u90E8\u6539\u8D70 `focalapi gen video -m gemini-omni-flash-preview`\uFF08\u652F\u6301 --first-frame/--image/--content\uFF09");
|
|
2276
2267
|
});
|
|
2277
|
-
gen.command("video").description("\u751F\u6210\u89C6\u9891\uFF08\u7701\u7565 --model \u65F6\u81EA\u52A8\u9009\u62E9\u5F53\u524D\u53EF\u7528\u9ED8\u8BA4\u6A21\u578B\uFF09").argument("<prompt...>", "\u63D0\u793A\u8BCD").option("-m, --model <model>", "\u89C6\u9891\u6A21\u578B ID\uFF1B\u7701\u7565\u65F6\u7531 focalapi \u81EA\u52A8\u9009\u62E9").option("--seconds <n>", "\u65F6\u957F\u79D2\u6570\uFF1B--duration \u4E3A\u540C\u4E49\u522B\u540D\u3002\u7CBE\u786E\u8303\u56F4\u8FD0\u884C focalapi models get <model> \u67E5\u770B", (v) => Number.parseInt(v, 10)).option("--duration <n>", "\u65F6\u957F\u79D2\u6570\uFF08--seconds \u7684\u522B\u540D\uFF0C\u4E0E API \u5951\u7EA6\u5B57\u6BB5\u540C\u540D\uFF09", (v) => Number.parseInt(v, 10)).option("--size <size>", "\u5206\u8FA8\u7387\uFF0C\u5982 1280x720").option("--resolution <resolution>", "\u539F\u751F\u8F93\u51FA\u5206\u8FA8\u7387\uFF0C\u5982 480p\u3001720p\u30011080p\u30014k").option("--ratio <ratio>", "\u539F\u751F\u5BBD\u9AD8\u6BD4\uFF0C\u5982 16:9\u30019:16\u3001adaptive").option("--aspect-ratio <ratio>", "\u6A21\u578B\u539F\u751F\u753B\u9762\u6BD4\u4F8B\uFF0C\u5982 16:9\u30019:16\u3001auto").option("--seed <n>", "\u6A21\u578B\u968F\u673A\u79CD\u5B50\uFF08\u975E\u8D1F\u6574\u6570\uFF09", (v) => Number.parseInt(v, 10)).option("--fps <n>", "\u8F93\u51FA\u5E27\u7387\uFF08\u4EC5\u652F\u6301\u8BE5\u53C2\u6570\u7684\u6A21\u578B\u751F\u6548\uFF09", (v) => Number.parseInt(v, 10)).option("--safety-tolerance <n>", "\u5B89\u5168\u5BB9\u5FCD\u5EA6\uFF08\u4EC5\u652F\u6301\u8BE5\u53C2\u6570\u7684\u6A21\u578B\u751F\u6548\uFF09", (v) => Number.parseInt(v, 10)).option("--image <url...>", "\u53C2\u8003\u56FE URL \u6216\u672C\u5730\u8DEF\u5F84\uFF08@C:/path/x.jpg\uFF09\uFF0CGrok \u89C6\u9891\u4E3A reference-to-video \u6A21\u5F0F").option("--first-frame <url>", "\u56FE\u751F\u89C6\u9891\u9996\u5E27\u56FE URL\uFF08image-to-video \u6A21\u5F0F\uFF1B\u4E0E --image \u4E92\u65A5\uFF09").option("--generate-audio <boolean>", "\u662F\u5426\u751F\u6210\u97F3\u9891\uFF08\u53EA\u63A5\u53D7 true \u6216 false\uFF09", (v) => parseBooleanOption(v, "generate-audio")).option("--watermark <boolean>", "\u662F\u5426\u6DFB\u52A0\u6C34\u5370\uFF08\u53EA\u63A5\u53D7 true \u6216 false\uFF09", (v) => parseBooleanOption(v, "watermark")).option("--service-tier <tier>", "\u670D\u52A1\u5C42\u7EA7\uFF08Seedance 2.0 \u9ED8\u8BA4 default\uFF09").option("--priority <n>", "\u4EFB\u52A1\u4F18\u5148\u7EA7\uFF08\u4EC5 Seedance 2.0 \u7CFB\u5217\uFF09", (v) => Number.parseInt(v, 10)).option("--callback-url <url>", "\u4EFB\u52A1\u5B8C\u6210\u56DE\u8C03 URL").option("--return-last-frame <boolean>", "\u662F\u5426\u8FD4\u56DE\u6700\u540E\u4E00\u5E27\uFF08\u53EA\u63A5\u53D7 true \u6216 false\uFF09", (v) => parseBooleanOption(v, "return-last-frame")).option("--execution-expires-after <seconds>", "\u4EFB\u52A1\u8FC7\u671F\u79D2\u6570\uFF083600\u2013259200\uFF09", (v) => Number.parseInt(v, 10)).option("--safety-identifier <identifier>", "Seedance \u5B89\u5168\u6807\u8BC6\u7B26\uFF081\u201364 \u4E2A\u53EF\u6253\u5370 ASCII \u5B57\u7B26\uFF09").option("--no-wait", "\u63D0\u4EA4\u540E\u7ACB\u5373\u8FD4\u56DE task_id\uFF0C\u4E0D\u7B49\u5F85\u5B8C\u6210").option("--idempotency-key <key>", "\u5E42\u7B49\u952E\uFF088\u2013128 \u4E2A\u53EF\u6253\u5370 ASCII \u5B57\u7B26\uFF09\u3002\u540C\u4E00 key \u7684\u91CD\u590D\u63D0\u4EA4\u62FF\u56DE\u539F\u4EFB\u52A1\u800C\u4E0D\u91CD\u590D\u8BA1\u8D39\uFF1B\u7701\u7565\u65F6\u81EA\u52A8\u751F\u6210\u3002\u91CD\u8BD5\u4E0D\u786E\u5B9A\u7684\u63D0\u4EA4\u65F6\u52A1\u5FC5\u590D\u7528\u539F key").option("--poll-interval <ms>", "\u8F6E\u8BE2\u95F4\u9694\u6BEB\u79D2", (v) => Number.parseInt(v, 10), 5e3).option("--timeout <minutes>", "\u6700\u957F\u7B49\u5F85\u5206\u949F", (v) => Number.parseInt(v, 10), 30).option("-o, --out <dir>", "\u8F93\u51FA\u76EE\u5F55", DEFAULT_OUT_DIR).option("--content <json>", "Ark content JSON \u6570\u7EC4\uFF1B\u652F\u6301\u5185\u8054 JSON\u3001@\u6587\u4EF6\u8DEF\u5F84\uFF08\u591A\u56FE base64 \u5FC5\u987B\u8D70\u6587\u4EF6\uFF09\u6216 - \uFF08stdin\uFF09\uFF1B\u8986\u76D6 prompt/image \u95E8\u9762\u5B57\u6BB5").action(
|
|
2268
|
+
gen.command("video").description("\u751F\u6210\u89C6\u9891\uFF08\u7701\u7565 --model \u65F6\u81EA\u52A8\u9009\u62E9\u5F53\u524D\u53EF\u7528\u9ED8\u8BA4\u6A21\u578B\uFF09").argument("<prompt...>", "\u63D0\u793A\u8BCD").option("-m, --model <model>", "\u89C6\u9891\u6A21\u578B ID\uFF1B\u7701\u7565\u65F6\u7531 focalapi \u81EA\u52A8\u9009\u62E9").option("--seconds <n>", "\u65F6\u957F\u79D2\u6570\uFF1B--duration \u4E3A\u540C\u4E49\u522B\u540D\u3002\u7CBE\u786E\u8303\u56F4\u8FD0\u884C focalapi models get <model> \u67E5\u770B", (v) => Number.parseInt(v, 10)).option("--duration <n>", "\u65F6\u957F\u79D2\u6570\uFF08--seconds \u7684\u522B\u540D\uFF0C\u4E0E API \u5951\u7EA6\u5B57\u6BB5\u540C\u540D\uFF09", (v) => Number.parseInt(v, 10)).option("--size <size>", "\u5206\u8FA8\u7387\uFF0C\u5982 1280x720").option("--resolution <resolution>", "\u539F\u751F\u8F93\u51FA\u5206\u8FA8\u7387\uFF0C\u5982 480p\u3001720p\u30011080p\u30014k").option("--ratio <ratio>", "\u539F\u751F\u5BBD\u9AD8\u6BD4\uFF0C\u5982 16:9\u30019:16\u3001adaptive").option("--aspect-ratio <ratio>", "\u6A21\u578B\u539F\u751F\u753B\u9762\u6BD4\u4F8B\uFF0C\u5982 16:9\u30019:16\u3001auto").option("--seed <n>", "\u6A21\u578B\u968F\u673A\u79CD\u5B50\uFF08\u975E\u8D1F\u6574\u6570\uFF09", (v) => Number.parseInt(v, 10)).option("--fps <n>", "\u8F93\u51FA\u5E27\u7387\uFF08\u4EC5\u652F\u6301\u8BE5\u53C2\u6570\u7684\u6A21\u578B\u751F\u6548\uFF09", (v) => Number.parseInt(v, 10)).option("--safety-tolerance <n>", "\u5B89\u5168\u5BB9\u5FCD\u5EA6\uFF08\u4EC5\u652F\u6301\u8BE5\u53C2\u6570\u7684\u6A21\u578B\u751F\u6548\uFF09", (v) => Number.parseInt(v, 10)).option("--image <url...>", "\u53C2\u8003\u56FE URL \u6216\u672C\u5730\u8DEF\u5F84\uFF08@C:/path/x.jpg\uFF09\uFF0CGrok \u89C6\u9891\u4E3A reference-to-video \u6A21\u5F0F").option("--first-frame <url>", "\u56FE\u751F\u89C6\u9891\u9996\u5E27\u56FE URL\uFF08image-to-video \u6A21\u5F0F\uFF1B\u4E0E --image \u4E92\u65A5\uFF09").option("--generate-audio <boolean>", "\u662F\u5426\u751F\u6210\u97F3\u9891\uFF08\u53EA\u63A5\u53D7 true \u6216 false\uFF09", (v) => parseBooleanOption(v, "generate-audio")).option("--watermark <boolean>", "\u662F\u5426\u6DFB\u52A0\u6C34\u5370\uFF08\u53EA\u63A5\u53D7 true \u6216 false\uFF09", (v) => parseBooleanOption(v, "watermark")).option("--service-tier <tier>", "\u670D\u52A1\u5C42\u7EA7\uFF08Seedance 2.0 \u9ED8\u8BA4 default\uFF09").option("--priority <n>", "\u4EFB\u52A1\u4F18\u5148\u7EA7\uFF08\u4EC5 Seedance 2.0 \u7CFB\u5217\uFF09", (v) => Number.parseInt(v, 10)).option("--callback-url <url>", "\u4EFB\u52A1\u5B8C\u6210\u56DE\u8C03 URL").option("--return-last-frame <boolean>", "\u662F\u5426\u8FD4\u56DE\u6700\u540E\u4E00\u5E27\uFF08\u53EA\u63A5\u53D7 true \u6216 false\uFF09", (v) => parseBooleanOption(v, "return-last-frame")).option("--execution-expires-after <seconds>", "\u4EFB\u52A1\u8FC7\u671F\u79D2\u6570\uFF083600\u2013259200\uFF09", (v) => Number.parseInt(v, 10)).option("--safety-identifier <identifier>", "Seedance \u5B89\u5168\u6807\u8BC6\u7B26\uFF081\u201364 \u4E2A\u53EF\u6253\u5370 ASCII \u5B57\u7B26\uFF09").option("--omni-reference-task-type <type>", "Seedance 2.5 \u591A\u6A21\u6001\u4EFB\u52A1\u7C7B\u578B\uFF1Aauto\u3001reference\u3001edit \u6216 extend\uFF08\u7F16\u8F91/\u5EF6\u957F\u53C2\u8003\u89C6\u9891\u65F6\u5FC5\u586B\uFF0Cauto \u4F1A\u4E0E\u9ED8\u8BA4\u65F6\u957F\u51B2\u7A81\uFF09").option("--voice <label>", "HeyGen \u8BED\u97F3\u6807\u7B7E\uFF08talking-photo \u5267\u672C\u5FC5\u586B\uFF1B\u5408\u6CD5\u503C\u89C1 models get heygen-talking-photo \u7684 voice \u679A\u4E3E\uFF09").option("--avatar <label>", "HeyGen Avatar \u5F62\u8C61\u6807\u7B7E\uFF08heygen-avatar \u5FC5\u586B\uFF1B\u5408\u6CD5\u503C\u89C1 models get heygen-avatar \u7684 avatar \u679A\u4E3E\uFF09").option("--operation <op>", "Bria \u89C6\u9891\u64CD\u4F5C\uFF1Aremove_background\u3001green_screen \u6216 replace_background").option("--enhance-model <id>", "HitPaw \u89C6\u9891\u589E\u5F3A\u6A21\u578B\uFF08\u5982 general_restore_2x\uFF1B\u5B8C\u6574\u679A\u4E3E\u89C1 models get hitpaw-video-enhance\uFF09").option("--upscaler-model <family>", "Topaz \u89C6\u9891\u653E\u5927\u6A21\u578B\uFF1Astarlight_fast\u3001starlight_creative\u3001starlight_precise_25 \u6216 astra_2").option("--no-wait", "\u63D0\u4EA4\u540E\u7ACB\u5373\u8FD4\u56DE task_id\uFF0C\u4E0D\u7B49\u5F85\u5B8C\u6210").option("--idempotency-key <key>", "\u5E42\u7B49\u952E\uFF088\u2013128 \u4E2A\u53EF\u6253\u5370 ASCII \u5B57\u7B26\uFF09\u3002\u540C\u4E00 key \u7684\u91CD\u590D\u63D0\u4EA4\u62FF\u56DE\u539F\u4EFB\u52A1\u800C\u4E0D\u91CD\u590D\u8BA1\u8D39\uFF1B\u7701\u7565\u65F6\u81EA\u52A8\u751F\u6210\u3002\u91CD\u8BD5\u4E0D\u786E\u5B9A\u7684\u63D0\u4EA4\u65F6\u52A1\u5FC5\u590D\u7528\u539F key").option("--poll-interval <ms>", "\u8F6E\u8BE2\u95F4\u9694\u6BEB\u79D2", (v) => Number.parseInt(v, 10), 5e3).option("--timeout <minutes>", "\u6700\u957F\u7B49\u5F85\u5206\u949F", (v) => Number.parseInt(v, 10), 30).option("-o, --out <dir>", "\u8F93\u51FA\u76EE\u5F55", DEFAULT_OUT_DIR).option("--content <json>", "Ark content JSON \u6570\u7EC4\uFF1B\u652F\u6301\u5185\u8054 JSON\u3001@\u6587\u4EF6\u8DEF\u5F84\uFF08\u591A\u56FE base64 \u5FC5\u987B\u8D70\u6587\u4EF6\uFF09\u6216 - \uFF08stdin\uFF09\uFF1B\u8986\u76D6 prompt/image \u95E8\u9762\u5B57\u6BB5").action(
|
|
2278
2269
|
async (promptParts, opts, cmd) => {
|
|
2279
2270
|
const g = cmd.optsWithGlobals();
|
|
2280
2271
|
const auth = resolveAuth(g);
|
|
@@ -2309,6 +2300,28 @@ function registerGen(program) {
|
|
|
2309
2300
|
if (opts.returnLastFrame !== void 0) metadata.return_last_frame = opts.returnLastFrame;
|
|
2310
2301
|
if (opts.executionExpiresAfter !== void 0) metadata.execution_expires_after = opts.executionExpiresAfter;
|
|
2311
2302
|
if (opts.safetyIdentifier) metadata.safety_identifier = opts.safetyIdentifier;
|
|
2303
|
+
if (opts.omniReferenceTaskType) {
|
|
2304
|
+
const taskType = opts.omniReferenceTaskType.toLowerCase();
|
|
2305
|
+
if (!["auto", "reference", "edit", "extend"].includes(taskType)) {
|
|
2306
|
+
throw new ApiError("invalid_request", "--omni-reference-task-type must be auto, reference, edit, or extend");
|
|
2307
|
+
}
|
|
2308
|
+
body.omni_reference_task_type = taskType;
|
|
2309
|
+
}
|
|
2310
|
+
if (opts.voice) body.voice = opts.voice;
|
|
2311
|
+
if (opts.avatar) body.avatar = opts.avatar;
|
|
2312
|
+
if (opts.operation) {
|
|
2313
|
+
if (!["remove_background", "green_screen", "replace_background"].includes(opts.operation)) {
|
|
2314
|
+
throw new ApiError("invalid_request", "--operation must be remove_background, green_screen, or replace_background");
|
|
2315
|
+
}
|
|
2316
|
+
body.operation = opts.operation;
|
|
2317
|
+
}
|
|
2318
|
+
if (opts.enhanceModel) body.enhance_model = opts.enhanceModel;
|
|
2319
|
+
if (opts.upscalerModel) {
|
|
2320
|
+
if (!["starlight_fast", "starlight_creative", "starlight_precise_25", "astra_2"].includes(opts.upscalerModel)) {
|
|
2321
|
+
throw new ApiError("invalid_request", "--upscaler-model must be starlight_fast, starlight_creative, starlight_precise_25, or astra_2");
|
|
2322
|
+
}
|
|
2323
|
+
body.upscaler_model = opts.upscalerModel;
|
|
2324
|
+
}
|
|
2312
2325
|
if (opts.content) metadata.content = parseJsonArray(await readContentArgument(opts.content), "content");
|
|
2313
2326
|
validateVideoGeneration(model, {
|
|
2314
2327
|
promptRunes: [...promptParts.join(" ")].length,
|