makefx 1.5.0 → 1.6.1
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/README.md +1 -1
- package/makefx.mjs +278 -42
- package/package.json +1 -1
package/README.md
CHANGED
package/makefx.mjs
CHANGED
|
@@ -621,9 +621,85 @@ function isProviderAuthMessage(message, providerErrorCode, provider) {
|
|
|
621
621
|
return providerErrorCode?.toLowerCase() === "api_key_invalid" || message.includes("api_key_invalid") || message.includes("api key not valid") || message.includes("invalid api key") || message.includes("api key is required") || message.includes("not configured") || message.includes("unauthenticated");
|
|
622
622
|
}
|
|
623
623
|
//#endregion
|
|
624
|
+
//#region src/shared/generation-blockers.ts
|
|
625
|
+
var GENERATION_BLOCKER_CODES = [
|
|
626
|
+
"SUBSCRIPTION_REQUIRED",
|
|
627
|
+
"PROVIDER_KEY_REQUIRED",
|
|
628
|
+
"BYOK_CREDENTIAL_FAILED",
|
|
629
|
+
"MANAGED_AI_UNAVAILABLE"
|
|
630
|
+
];
|
|
631
|
+
var PROVIDER_LABELS = {
|
|
632
|
+
google_ai: "Google AI",
|
|
633
|
+
elevenlabs: "ElevenLabs",
|
|
634
|
+
lyria: "Lyria",
|
|
635
|
+
kling: "Kling",
|
|
636
|
+
fal: "fal.ai",
|
|
637
|
+
replicate: "Replicate"
|
|
638
|
+
};
|
|
639
|
+
function isGenerationBlockerCode(code) {
|
|
640
|
+
return GENERATION_BLOCKER_CODES.includes(code);
|
|
641
|
+
}
|
|
642
|
+
function inferGenerationBlockerProvider(message) {
|
|
643
|
+
const normalized = message?.toLowerCase() ?? "";
|
|
644
|
+
if (normalized.includes("google ai") || normalized.includes("gemini") || normalized.includes("veo")) return "google_ai";
|
|
645
|
+
if (normalized.includes("elevenlabs")) return "elevenlabs";
|
|
646
|
+
if (normalized.includes("lyria")) return "lyria";
|
|
647
|
+
if (normalized.includes("kling")) return "kling";
|
|
648
|
+
if (normalized.includes("fal.ai") || normalized.includes("fal provider")) return "fal";
|
|
649
|
+
if (normalized.includes("replicate")) return "replicate";
|
|
650
|
+
}
|
|
651
|
+
function generationBlockerProviderFromService(provider) {
|
|
652
|
+
if (provider === "google_ai" || provider === "veo") return "google_ai";
|
|
653
|
+
if (provider === "elevenlabs" || provider === "lyria" || provider === "kling" || provider === "fal" || provider === "replicate") return provider;
|
|
654
|
+
}
|
|
655
|
+
function getGenerationBlockerPresentation(code, serverMessage, provider) {
|
|
656
|
+
if (!isGenerationBlockerCode(code)) return null;
|
|
657
|
+
if (code === "SUBSCRIPTION_REQUIRED") return {
|
|
658
|
+
code,
|
|
659
|
+
message: "A Make Effects Platform subscription is required before generation can start.",
|
|
660
|
+
retryable: false,
|
|
661
|
+
actionLabel: "View billing",
|
|
662
|
+
actionPath: "/profile#billing",
|
|
663
|
+
remediation: "Start or restore the Make Effects Platform subscription at https://makefx.app/profile#billing, then try again."
|
|
664
|
+
};
|
|
665
|
+
if (code === "MANAGED_AI_UNAVAILABLE") return {
|
|
666
|
+
code,
|
|
667
|
+
message: "Managed generation is coming soon and cannot be selected yet.",
|
|
668
|
+
retryable: false,
|
|
669
|
+
remediation: "Connect your provider account and choose a supported model. Managed generation is not available yet."
|
|
670
|
+
};
|
|
671
|
+
const resolvedProvider = provider ?? inferGenerationBlockerProvider(serverMessage);
|
|
672
|
+
const providerLabel = resolvedProvider ? PROVIDER_LABELS[resolvedProvider] : "provider";
|
|
673
|
+
const actionPath = resolvedProvider ? `/profile#provider-key-${resolvedProvider}` : "/profile#provider-keys";
|
|
674
|
+
const setupUrl = `https://makefx.app${actionPath}`;
|
|
675
|
+
if (code === "PROVIDER_KEY_REQUIRED") return {
|
|
676
|
+
code,
|
|
677
|
+
message: `A ${providerLabel} account key is required before generation can start.`,
|
|
678
|
+
retryable: false,
|
|
679
|
+
actionLabel: "Configure key",
|
|
680
|
+
actionPath,
|
|
681
|
+
remediation: `Configure the ${providerLabel} account key at ${setupUrl}, then try again.`,
|
|
682
|
+
...resolvedProvider ? { provider: resolvedProvider } : {}
|
|
683
|
+
};
|
|
684
|
+
return {
|
|
685
|
+
code,
|
|
686
|
+
message: `The ${providerLabel} account key could not be used. Replace or reconnect it before trying again.`,
|
|
687
|
+
retryable: false,
|
|
688
|
+
actionLabel: "Reconnect key",
|
|
689
|
+
actionPath,
|
|
690
|
+
remediation: `Replace or reconnect the ${providerLabel} account key at ${setupUrl}, then try again.`,
|
|
691
|
+
...resolvedProvider ? { provider: resolvedProvider } : {}
|
|
692
|
+
};
|
|
693
|
+
}
|
|
694
|
+
function formatGenerationBlockerForTerminal(code, message) {
|
|
695
|
+
const blocker = getGenerationBlockerPresentation(code, message);
|
|
696
|
+
if (!blocker) return `${code}: ${message}`;
|
|
697
|
+
return `${blocker.code}: ${blocker.message}\n${blocker.remediation}`;
|
|
698
|
+
}
|
|
699
|
+
//#endregion
|
|
624
700
|
//#region src/cli/lib/error-format.ts
|
|
625
701
|
function formatServerErrorMessage(code, message) {
|
|
626
|
-
return
|
|
702
|
+
return formatGenerationBlockerForTerminal(code, formatGenerationFailureMessage(message));
|
|
627
703
|
}
|
|
628
704
|
function formatGenerationFailureMessage(message, providerMetadata) {
|
|
629
705
|
return sanitizeGenerationFailureMessage(message, providerMetadata);
|
|
@@ -631,6 +707,9 @@ function formatGenerationFailureMessage(message, providerMetadata) {
|
|
|
631
707
|
function getGenerationFailureCode(providerMetadata) {
|
|
632
708
|
return extractGenerationDiagnostic(providerMetadata)?.code ?? "GENERATION_FAILED";
|
|
633
709
|
}
|
|
710
|
+
function getGenerationFailureProvider(providerMetadata) {
|
|
711
|
+
return extractGenerationDiagnostic(providerMetadata)?.provider;
|
|
712
|
+
}
|
|
634
713
|
//#endregion
|
|
635
714
|
//#region src/shared/compact-references.ts
|
|
636
715
|
var COMPACT_ID_LENGTH = 8;
|
|
@@ -4358,6 +4437,16 @@ var import_websocket = /* @__PURE__ */ __toESM(require_websocket(), 1);
|
|
|
4358
4437
|
require_websocket_server();
|
|
4359
4438
|
var wrapper_default = import_websocket.default;
|
|
4360
4439
|
//#endregion
|
|
4440
|
+
//#region src/cli/version.ts
|
|
4441
|
+
var CLI_VERSION = "1.6.1+00259d259e65";
|
|
4442
|
+
var CLI_VERSION_HEADER = "X-MakeFX-CLI-Version";
|
|
4443
|
+
function cliVersionHeaders() {
|
|
4444
|
+
return {
|
|
4445
|
+
[CLI_VERSION_HEADER]: CLI_VERSION,
|
|
4446
|
+
"User-Agent": `makefx/${CLI_VERSION}`
|
|
4447
|
+
};
|
|
4448
|
+
}
|
|
4449
|
+
//#endregion
|
|
4361
4450
|
//#region src/cli/lib/websocket-client.ts
|
|
4362
4451
|
/**
|
|
4363
4452
|
* WebSocket Client for CLI
|
|
@@ -4444,7 +4533,10 @@ var WebSocketClient = class WebSocketClient {
|
|
|
4444
4533
|
return new Promise((resolve, reject) => {
|
|
4445
4534
|
const protocol = this.baseUrl.startsWith("https") ? "wss" : "ws";
|
|
4446
4535
|
const url = `${protocol}://${this.baseUrl.replace(/^https?:\/\//, "")}/api/spaces/${this.spaceId}/ws`;
|
|
4447
|
-
const wsOptions = { headers: {
|
|
4536
|
+
const wsOptions = { headers: {
|
|
4537
|
+
"Authorization": `Bearer ${this.accessToken}`,
|
|
4538
|
+
...cliVersionHeaders()
|
|
4539
|
+
} };
|
|
4448
4540
|
if (this.env === "local" && protocol === "wss") wsOptions.agent = new https.Agent({ rejectUnauthorized: false });
|
|
4449
4541
|
else if (this.env === "local" && protocol === "ws") wsOptions.agent = new http.Agent();
|
|
4450
4542
|
this.ws = new wrapper_default(url, wsOptions);
|
|
@@ -4722,7 +4814,8 @@ var WebSocketClient = class WebSocketClient {
|
|
|
4722
4814
|
success: variant.status === "completed",
|
|
4723
4815
|
variant: variant.status === "completed" ? variant : void 0,
|
|
4724
4816
|
error: variant.status === "failed" ? formatGenerationFailureMessage(variant.error_message, variant.provider_metadata) : void 0,
|
|
4725
|
-
errorCode: variant.status === "failed" ? getGenerationFailureCode(variant.provider_metadata) : void 0
|
|
4817
|
+
errorCode: variant.status === "failed" ? getGenerationFailureCode(variant.provider_metadata) : void 0,
|
|
4818
|
+
errorProvider: variant.status === "failed" ? getGenerationFailureProvider(variant.provider_metadata) : void 0
|
|
4726
4819
|
});
|
|
4727
4820
|
}
|
|
4728
4821
|
return handled;
|
|
@@ -5017,7 +5110,9 @@ var WebSocketClient = class WebSocketClient {
|
|
|
5017
5110
|
videoDurationSeconds: params.videoDurationSeconds,
|
|
5018
5111
|
videoTier: params.videoTier,
|
|
5019
5112
|
seedanceDuration: params.seedanceDuration,
|
|
5020
|
-
seedanceBitrateMode: params.seedanceBitrateMode
|
|
5113
|
+
seedanceBitrateMode: params.seedanceBitrateMode,
|
|
5114
|
+
avatarResolution: params.avatarResolution,
|
|
5115
|
+
avatarMode: params.avatarMode
|
|
5021
5116
|
};
|
|
5022
5117
|
try {
|
|
5023
5118
|
this.send(message);
|
|
@@ -5870,6 +5965,16 @@ function readIsoBmffVideoMetadata(bytes) {
|
|
|
5870
5965
|
return durationMs ? { durationMs } : {};
|
|
5871
5966
|
}
|
|
5872
5967
|
//#endregion
|
|
5968
|
+
//#region src/shared/avatarGenerationOptions.ts
|
|
5969
|
+
var AVATAR_MODEL_IDS = ["kling-avatar-v2"];
|
|
5970
|
+
var AVATAR_MODES = ["standard", "pro"];
|
|
5971
|
+
function isAvatarModelId(value) {
|
|
5972
|
+
return typeof value === "string" && AVATAR_MODEL_IDS.includes(value);
|
|
5973
|
+
}
|
|
5974
|
+
function isAvatarMode(value) {
|
|
5975
|
+
return typeof value === "string" && AVATAR_MODES.includes(value);
|
|
5976
|
+
}
|
|
5977
|
+
//#endregion
|
|
5873
5978
|
//#region src/shared/seedance2Capabilities.ts
|
|
5874
5979
|
var SEEDANCE_2_ASPECT_RATIOS = [
|
|
5875
5980
|
"auto",
|
|
@@ -6381,6 +6486,20 @@ var MEDIA_OPERATION_MATRIX = [
|
|
|
6381
6486
|
cliCommands: ["generate"],
|
|
6382
6487
|
cliSupportsRefs: true
|
|
6383
6488
|
},
|
|
6489
|
+
{
|
|
6490
|
+
mode: "avatar",
|
|
6491
|
+
label: "Avatar",
|
|
6492
|
+
shortLabel: "Avatar",
|
|
6493
|
+
mediaKind: "video",
|
|
6494
|
+
assetType: "avatar",
|
|
6495
|
+
promptNoun: "avatar video",
|
|
6496
|
+
inheritsReferenceAssetType: false,
|
|
6497
|
+
compatibleSlotMediaKinds: ["image", "audio"],
|
|
6498
|
+
supportsBatch: false,
|
|
6499
|
+
cliNamespace: null,
|
|
6500
|
+
cliCommands: [],
|
|
6501
|
+
cliSupportsRefs: false
|
|
6502
|
+
},
|
|
6384
6503
|
{
|
|
6385
6504
|
mode: "speech",
|
|
6386
6505
|
label: "Speech",
|
|
@@ -6621,7 +6740,8 @@ var CLI_GENERATION_MEDIA_OPTIONS = {
|
|
|
6621
6740
|
"last-frame",
|
|
6622
6741
|
"image-refs",
|
|
6623
6742
|
"video-refs",
|
|
6624
|
-
"audio-refs"
|
|
6743
|
+
"audio-refs",
|
|
6744
|
+
"mode"
|
|
6625
6745
|
]
|
|
6626
6746
|
};
|
|
6627
6747
|
function rejectUnknownGenerationOptions(options, mediaKind) {
|
|
@@ -6669,12 +6789,12 @@ function validateAudioModeRequiredVoiceOptions(options, mode) {
|
|
|
6669
6789
|
if (mode === "dialogue" && !normalizeCliOption(options["dialogue-voices"] ?? options.dialogueVoices)) throw new Error("Dialogue generation requires --dialogue-voices <voice_id,voice_id>. Run: makefx audio voices");
|
|
6670
6790
|
}
|
|
6671
6791
|
async function executeGenerate(parsed, ctx, client, deps, mediaKind, followOptions = {}) {
|
|
6672
|
-
const
|
|
6792
|
+
const videoOptions = parseVideoGenerationOptions(parsed, mediaKind);
|
|
6793
|
+
const prompt = isAvatarModelId(videoOptions.model) ? parsed.positionals.join(" ").trim() : getPrompt(parsed, "generate");
|
|
6673
6794
|
const outputPath = getOutputPath(parsed);
|
|
6674
6795
|
const name = requireOption(parsed, "name");
|
|
6675
6796
|
const assetType = requireOption(parsed, "type");
|
|
6676
6797
|
const musicProvider = parseMusicProviderOption(parsed, mediaKind, assetType);
|
|
6677
|
-
const videoOptions = parseVideoGenerationOptions(parsed, mediaKind);
|
|
6678
6798
|
const effectiveVideoModel = videoOptions.model ?? getVideoGenerationModelForSelection();
|
|
6679
6799
|
const seedanceCapability = mediaKind === "video" ? getSeedance2CapabilityByEndpoint(effectiveVideoModel) : void 0;
|
|
6680
6800
|
const videoFrameRefs = parseVideoFrameReferenceOptions(parsed, "generate", mediaKind).refs;
|
|
@@ -6693,7 +6813,7 @@ async function executeGenerate(parsed, ctx, client, deps, mediaKind, followOptio
|
|
|
6693
6813
|
...deps,
|
|
6694
6814
|
waitForReferenceVariant: (variant) => waitForReferenceVariant(client, variant)
|
|
6695
6815
|
};
|
|
6696
|
-
const resolvedSeedanceRefs = state && seedanceReferenceCount > 0 ? await resolveSeedanceReferenceIds(seedanceRefs, ctx, referenceDeps, state) : {
|
|
6816
|
+
const resolvedSeedanceRefs = state && seedanceReferenceCount > 0 ? isAvatarModelId(effectiveVideoModel) ? await resolveAvatarReferenceIds(seedanceRefs, ctx, referenceDeps, state) : await resolveSeedanceReferenceIds(seedanceRefs, ctx, referenceDeps, state) : {
|
|
6697
6817
|
refs: [],
|
|
6698
6818
|
ids: []
|
|
6699
6819
|
};
|
|
@@ -6847,6 +6967,10 @@ function parseSeedanceReferenceOptions(parsed) {
|
|
|
6847
6967
|
};
|
|
6848
6968
|
}
|
|
6849
6969
|
function validateSeedanceReferenceOptions(options, model, command) {
|
|
6970
|
+
if (isAvatarModelId(model)) {
|
|
6971
|
+
if (options.imageRefs.length !== 1 || options.audioRefs.length !== 1 || options.videoRefs.length !== 0) throw new Error("Avatar generation requires exactly one --image-refs portrait and one --audio-refs input");
|
|
6972
|
+
return;
|
|
6973
|
+
}
|
|
6850
6974
|
const capability = getSeedance2CapabilityByEndpoint(model);
|
|
6851
6975
|
const total = options.imageRefs.length + options.videoRefs.length + options.audioRefs.length;
|
|
6852
6976
|
if (!capability) {
|
|
@@ -6864,6 +6988,15 @@ function validateSeedanceReferenceOptions(options, model, command) {
|
|
|
6864
6988
|
});
|
|
6865
6989
|
if (error) throw new Error(error.message);
|
|
6866
6990
|
}
|
|
6991
|
+
async function resolveAvatarReferenceIds(options, ctx, deps, state) {
|
|
6992
|
+
const resolve = (refs, kind) => resolveReferenceVariantIds(refs, ctx, deps, state.variants, "video", state.assets, kind);
|
|
6993
|
+
const imageIds = await resolve(options.imageRefs, "image");
|
|
6994
|
+
const audioIds = await resolve(options.audioRefs, "audio");
|
|
6995
|
+
return {
|
|
6996
|
+
refs: [...options.imageRefs, ...options.audioRefs],
|
|
6997
|
+
ids: [...imageIds, ...audioIds]
|
|
6998
|
+
};
|
|
6999
|
+
}
|
|
6867
7000
|
async function resolveSeedanceReferenceIds(options, ctx, deps, state, implicitVideoReferenceIds = []) {
|
|
6868
7001
|
await preflightLocalSeedanceReferences({
|
|
6869
7002
|
...options,
|
|
@@ -7141,7 +7274,9 @@ function compactStartedVariantRef(started) {
|
|
|
7141
7274
|
}
|
|
7142
7275
|
function formatTerminalGenerationError(result) {
|
|
7143
7276
|
const message = result.error || "Generation failed without a completed variant";
|
|
7144
|
-
|
|
7277
|
+
if (!result.errorCode) return message;
|
|
7278
|
+
const blocker = getGenerationBlockerPresentation(result.errorCode, message, generationBlockerProviderFromService(result.errorProvider));
|
|
7279
|
+
return blocker ? `${blocker.code}: ${blocker.message}\n${blocker.remediation}` : formatGenerationBlockerForTerminal(result.errorCode, message);
|
|
7145
7280
|
}
|
|
7146
7281
|
function throwGenerationWaitErrorIfNeeded(input, params) {
|
|
7147
7282
|
if (!isGenerationWaitTimeout(input)) throw input;
|
|
@@ -7196,7 +7331,7 @@ function validateVideoAudioOptions(parsed, mediaKind) {
|
|
|
7196
7331
|
const model = parseVideoModelOption(modelValue, videoTier, parsed);
|
|
7197
7332
|
if (parsed.options.audio !== void 0 && (isGeminiOmniVideoGenerationModel(model) || isFalSeedanceV1VideoGenerationModel(model))) throw new Error("--audio is only supported with --model veo-3.1, kling, or Seedance 2");
|
|
7198
7333
|
if (parsed.options["no-audio"] !== void 0) {
|
|
7199
|
-
if (!doesVideoGenerationModelSupportAudioToggle(model) && !isFalSeedance2VideoGenerationModel(model)) throw new Error(`${model} does not support --no-audio. Use the default audio-enabled output or omit the flag.`);
|
|
7334
|
+
if (isAvatarModelId(model) || !doesVideoGenerationModelSupportAudioToggle(model) && !isFalSeedance2VideoGenerationModel(model)) throw new Error(`${model} does not support --no-audio. Use the default audio-enabled output or omit the flag.`);
|
|
7200
7335
|
}
|
|
7201
7336
|
}
|
|
7202
7337
|
function parseVideoAudioOptions(parsed, mediaKind) {
|
|
@@ -7211,6 +7346,7 @@ function parseVideoGenerationOptions(parsed, mediaKind) {
|
|
|
7211
7346
|
const durationValue = readOptionalOption(parsed, "duration");
|
|
7212
7347
|
const tierValue = readOptionalOption(parsed, "tier");
|
|
7213
7348
|
const bitrateValue = readOptionalOption(parsed, "bitrate");
|
|
7349
|
+
const modeValue = readOptionalOption(parsed, "mode");
|
|
7214
7350
|
const modelValue = mediaKind === "video" ? readOptionalOption(parsed, "model") : void 0;
|
|
7215
7351
|
const aspectValue = mediaKind === "video" ? readOptionalOption(parsed, "aspect") : void 0;
|
|
7216
7352
|
if (mediaKind !== "video" && resolutionValue === void 0 && durationValue === void 0 && tierValue === void 0 && aspectValue === void 0 && bitrateValue === void 0) return {};
|
|
@@ -7220,6 +7356,17 @@ function parseVideoGenerationOptions(parsed, mediaKind) {
|
|
|
7220
7356
|
const videoTier = tierValue === void 0 ? void 0 : normalizeVideoGenerationTier(tierValue);
|
|
7221
7357
|
if (tierValue !== void 0 && !videoTier) throw new Error("--tier must be generate, fast, or lite");
|
|
7222
7358
|
const model = parseVideoModelOption(modelValue, videoTier, parsed);
|
|
7359
|
+
if (isAvatarModelId(model)) {
|
|
7360
|
+
if (parsed.options.refs !== void 0 || parsed.options["first-frame"] !== void 0 || parsed.options["last-frame"] !== void 0) throw new Error("Avatar models accept only --image-refs and --audio-refs");
|
|
7361
|
+
if (aspectValue !== void 0 || durationValue !== void 0 || tierValue !== void 0 || bitrateValue !== void 0 || parsed.options.audio !== void 0 || parsed.options["no-audio"] !== void 0) throw new Error("Avatar models do not accept --aspect, --duration, --tier, --bitrate, --audio, or --no-audio");
|
|
7362
|
+
if (resolutionValue !== void 0) throw new Error("--resolution is not supported by Avatar models");
|
|
7363
|
+
if (modeValue !== void 0 && !isAvatarMode(modeValue)) throw new Error(`--mode must be ${AVATAR_MODES.join(" or ")}`);
|
|
7364
|
+
return {
|
|
7365
|
+
model,
|
|
7366
|
+
...modeValue ? { avatarMode: modeValue } : {}
|
|
7367
|
+
};
|
|
7368
|
+
}
|
|
7369
|
+
if (modeValue !== void 0) throw new Error("--mode is only supported by --model kling-avatar-v2");
|
|
7223
7370
|
const seedanceCapability = getSeedance2CapabilityByEndpoint(model);
|
|
7224
7371
|
const seedanceDuration = durationValue === void 0 ? void 0 : durationValue === "auto" ? "auto" : normalizeVideoGenerationDurationSeconds(durationValue);
|
|
7225
7372
|
const videoDurationSeconds = durationValue === void 0 || durationValue === "auto" ? void 0 : normalizeVideoGenerationDurationSeconds(durationValue);
|
|
@@ -7315,6 +7462,7 @@ function parseVideoModelOption(value, tier, parsed) {
|
|
|
7315
7462
|
const normalized = normalizeCliOption(value);
|
|
7316
7463
|
const effectiveTier = tier ?? "generate";
|
|
7317
7464
|
if (!normalized) return getVideoGenerationModelForSelection(DEFAULT_VIDEO_MODEL_SELECTION, effectiveTier);
|
|
7465
|
+
if (isAvatarModelId(normalized)) return normalized;
|
|
7318
7466
|
if (normalized === "seedance-2" || normalized === "seedance-2-fast") {
|
|
7319
7467
|
const hasFrames = Boolean(parsed?.options["first-frame"] || parsed?.options["last-frame"]);
|
|
7320
7468
|
const hasReferences = Boolean(parsed?.options.refs || parsed?.options["image-refs"] || parsed?.options["video-refs"] || parsed?.options["audio-refs"]);
|
|
@@ -7322,7 +7470,7 @@ function parseVideoModelOption(value, tier, parsed) {
|
|
|
7322
7470
|
}
|
|
7323
7471
|
const selection = normalizeVideoModelSelection(normalized === "seedance-1" ? "fal-seedance" : normalized);
|
|
7324
7472
|
if (selection) return getVideoGenerationModelForSelection(selection, effectiveTier);
|
|
7325
|
-
throw new Error("--model must be veo-3.1, omni-flash, kling, seedance-1, seedance-2,
|
|
7473
|
+
throw new Error("--model must be veo-3.1, omni-flash, kling, seedance-1, seedance-2, seedance-2-fast, or kling-avatar-v2");
|
|
7326
7474
|
}
|
|
7327
7475
|
function parseImageModelOption(value) {
|
|
7328
7476
|
if (!value) return void 0;
|
|
@@ -7360,6 +7508,10 @@ function validateImageModelOperation(command, mediaKind, model) {
|
|
|
7360
7508
|
function validateVideoModelOperation(command, mediaKind, model) {
|
|
7361
7509
|
if (mediaKind !== "video") return;
|
|
7362
7510
|
const effectiveModel = model ?? getVideoGenerationModelForSelection();
|
|
7511
|
+
if (isAvatarModelId(effectiveModel)) {
|
|
7512
|
+
if (command === "generate") return;
|
|
7513
|
+
throw new Error(`--model ${effectiveModel} does not support video ${command}`);
|
|
7514
|
+
}
|
|
7363
7515
|
if (isVideoOperationSupportedByModel(effectiveModel, command)) return;
|
|
7364
7516
|
throw new Error(`--model ${getVideoModelSelectionForModel(effectiveModel) ?? effectiveModel} does not support video ${command}`);
|
|
7365
7517
|
}
|
|
@@ -7435,7 +7587,8 @@ async function executeRegenerate(mediaKind, parsed, deps = defaultDeps$11, audio
|
|
|
7435
7587
|
headers: {
|
|
7436
7588
|
Authorization: `Bearer ${config.token.accessToken}`,
|
|
7437
7589
|
Accept: "application/json",
|
|
7438
|
-
"Content-Type": "application/json"
|
|
7590
|
+
"Content-Type": "application/json",
|
|
7591
|
+
...cliVersionHeaders()
|
|
7439
7592
|
},
|
|
7440
7593
|
body: JSON.stringify(body)
|
|
7441
7594
|
});
|
|
@@ -7799,14 +7952,14 @@ async function handleBilling(parsed) {
|
|
|
7799
7952
|
}
|
|
7800
7953
|
function printBillingHelp() {
|
|
7801
7954
|
console.log(`
|
|
7802
|
-
Billing Commands -
|
|
7955
|
+
Billing Commands - Platform Subscription Operations
|
|
7803
7956
|
|
|
7804
7957
|
Usage:
|
|
7805
7958
|
makefx billing <subcommand> [--env <environment>]
|
|
7806
7959
|
|
|
7807
7960
|
Subcommands:
|
|
7808
7961
|
status Show sync status (pending, failed, synced events)
|
|
7809
|
-
check Run operational checks for workers, Polar
|
|
7962
|
+
check Run operational checks for workers, Polar product, and sync health
|
|
7810
7963
|
reconcile Compare local billable usage with Polar usage for one user
|
|
7811
7964
|
retry-failed Reset failed events for retry (next cron will sync them)
|
|
7812
7965
|
|
|
@@ -7953,6 +8106,16 @@ function secondsSummary(seconds) {
|
|
|
7953
8106
|
const remainingSeconds = seconds % 60;
|
|
7954
8107
|
return remainingSeconds > 0 ? `${minutes}m ${remainingSeconds}s` : `${minutes}m`;
|
|
7955
8108
|
}
|
|
8109
|
+
function resolveBillingOpsResult(options) {
|
|
8110
|
+
const statuses = [
|
|
8111
|
+
...options.workerStatuses,
|
|
8112
|
+
options.billingStatus,
|
|
8113
|
+
options.webhookStatus
|
|
8114
|
+
];
|
|
8115
|
+
if (statuses.includes("critical")) return "critical";
|
|
8116
|
+
if (statuses.includes("warning")) return "warning";
|
|
8117
|
+
return "ok";
|
|
8118
|
+
}
|
|
7956
8119
|
async function handleBillingOpsCheck(env) {
|
|
7957
8120
|
console.log(`Running billing operational checks for ${env}...\n`);
|
|
7958
8121
|
const workerChecks = await checkWorkerHealth(env);
|
|
@@ -7969,22 +8132,22 @@ async function handleBillingOpsCheck(env) {
|
|
|
7969
8132
|
process$1.exitCode = 1;
|
|
7970
8133
|
return;
|
|
7971
8134
|
}
|
|
7972
|
-
const
|
|
7973
|
-
console.log("\
|
|
7974
|
-
|
|
7975
|
-
|
|
7976
|
-
|
|
7977
|
-
if (
|
|
7978
|
-
|
|
7979
|
-
|
|
7980
|
-
|
|
7981
|
-
|
|
7982
|
-
|
|
7983
|
-
|
|
7984
|
-
|
|
7985
|
-
|
|
7986
|
-
|
|
7987
|
-
}
|
|
8135
|
+
const productCheck = billingChecks.checks.platformSubscriptionProduct;
|
|
8136
|
+
console.log("\nPlatform subscription product:");
|
|
8137
|
+
const product = productCheck.product;
|
|
8138
|
+
console.log(` ${statusLabel(productCheck.status)} configured=${product?.configured ?? false} recurring=${product?.isRecurring ?? "n/a"} archived=${product?.isArchived ?? "n/a"}`);
|
|
8139
|
+
console.log(` Environment: ${productCheck.actualEnvironment} (expected ${productCheck.expectedEnvironment})`);
|
|
8140
|
+
if (product?.productId) console.log(` Product: ${product.productId}${product.name ? ` (${product.name})` : ""}`);
|
|
8141
|
+
if (product?.fixedPrices.length) console.log(` Fixed price: ${product.fixedPrices.map((price) => `${price.amount} ${price.currency}/${price.interval ?? "one-time"}`).join(", ")}`);
|
|
8142
|
+
for (const error of productCheck.errors) console.log(` Error: ${error}`);
|
|
8143
|
+
const webhookCheck = billingChecks.checks.webhook ?? {
|
|
8144
|
+
status: "critical",
|
|
8145
|
+
configured: false,
|
|
8146
|
+
error: "Webhook readiness was not reported by the application Worker"
|
|
8147
|
+
};
|
|
8148
|
+
console.log("\nWebhook verifier:");
|
|
8149
|
+
console.log(` ${statusLabel(webhookCheck.status)} configured=${webhookCheck.configured}`);
|
|
8150
|
+
if (webhookCheck.error) console.log(` Error: ${webhookCheck.error}`);
|
|
7988
8151
|
const syncCheck = billingChecks.checks.syncHealth;
|
|
7989
8152
|
console.log("\nSync health:");
|
|
7990
8153
|
console.log(` ${statusLabel(syncCheck.status)} pending=${syncCheck.events.pending} failed=${syncCheck.events.failed} synced=${syncCheck.events.synced}`);
|
|
@@ -7993,13 +8156,15 @@ async function handleBillingOpsCheck(env) {
|
|
|
7993
8156
|
const internalCheck = billingChecks.checks.internalUsers;
|
|
7994
8157
|
console.log("\nInternal users:");
|
|
7995
8158
|
console.log(` ${statusLabel(internalCheck.status)} users=${internalCheck.internalUsers} nonBillableEvents=${internalCheck.nonBillableEvents} billableEvents=${internalCheck.billableEvents}`);
|
|
7996
|
-
const
|
|
7997
|
-
|
|
7998
|
-
|
|
7999
|
-
|
|
8159
|
+
const resultStatus = resolveBillingOpsResult({
|
|
8160
|
+
workerStatuses: workerChecks.map((check) => check.status),
|
|
8161
|
+
billingStatus: billingChecks.status,
|
|
8162
|
+
webhookStatus: webhookCheck.status
|
|
8163
|
+
});
|
|
8164
|
+
if (resultStatus === "critical") {
|
|
8000
8165
|
console.log("\nResult: CRITICAL - billing operations need attention.");
|
|
8001
8166
|
process$1.exitCode = 1;
|
|
8002
|
-
} else if (
|
|
8167
|
+
} else if (resultStatus === "warning") console.log("\nResult: WARNING - billing is operational but has lag or cleanup work.");
|
|
8003
8168
|
else console.log("\nResult: OK - billing workers, meters, and sync health are ready.");
|
|
8004
8169
|
}
|
|
8005
8170
|
async function handleBillingReconcile(env, parsed) {
|
|
@@ -8537,7 +8702,6 @@ function imageGenerator(capability) {
|
|
|
8537
8702
|
id: `image/${capability.selection}`,
|
|
8538
8703
|
label: capability.label,
|
|
8539
8704
|
mediaKind: "image",
|
|
8540
|
-
provider: capability.provider === "gemini" ? "google_ai" : "fal",
|
|
8541
8705
|
modelIds: [capability.modelId],
|
|
8542
8706
|
defaultModelId: capability.modelId,
|
|
8543
8707
|
operations,
|
|
@@ -8617,7 +8781,6 @@ function videoGenerator(selection) {
|
|
|
8617
8781
|
id: `video/${selection}`,
|
|
8618
8782
|
label: VIDEO_MODEL_LABELS[selection],
|
|
8619
8783
|
mediaKind: "video",
|
|
8620
|
-
provider: selection === "kling" ? "kling" : selection === "fal-seedance" ? "fal" : "google_ai",
|
|
8621
8784
|
modelIds,
|
|
8622
8785
|
defaultModelId: defaultModel,
|
|
8623
8786
|
operations,
|
|
@@ -8714,7 +8877,6 @@ function seedanceVideoGenerator(capability) {
|
|
|
8714
8877
|
id: capability.generatorId,
|
|
8715
8878
|
label: capability.label,
|
|
8716
8879
|
mediaKind: "video",
|
|
8717
|
-
provider: "fal",
|
|
8718
8880
|
modelIds: [capability.endpointId],
|
|
8719
8881
|
defaultModelId: capability.endpointId,
|
|
8720
8882
|
operations,
|
|
@@ -8743,6 +8905,72 @@ function seedanceVideoGenerator(capability) {
|
|
|
8743
8905
|
]
|
|
8744
8906
|
};
|
|
8745
8907
|
}
|
|
8908
|
+
function avatarVideoGenerator(model) {
|
|
8909
|
+
const parameters = [input("mode", "string", false, "Generation quality.", {
|
|
8910
|
+
allowedValues: AVATAR_MODES,
|
|
8911
|
+
defaultValue: "standard"
|
|
8912
|
+
})];
|
|
8913
|
+
return {
|
|
8914
|
+
id: `video/${model}`,
|
|
8915
|
+
label: "Kling Avatar V2",
|
|
8916
|
+
mediaKind: "video",
|
|
8917
|
+
modelIds: [model],
|
|
8918
|
+
defaultModelId: model,
|
|
8919
|
+
operations: [{
|
|
8920
|
+
operation: "derive",
|
|
8921
|
+
tool: "generate_video",
|
|
8922
|
+
description: "Create an Avatar video from one portrait image and one audio Variant.",
|
|
8923
|
+
inputs: [
|
|
8924
|
+
SPACE_INPUT,
|
|
8925
|
+
fixedInput("generator_id", `video/${model}`, "Selects this Avatar generator."),
|
|
8926
|
+
NAME_INPUT,
|
|
8927
|
+
input("asset_type", "string", true, "Asset classification stored in the Space."),
|
|
8928
|
+
input("prompt", "string", false, "Optional motion and expression guidance."),
|
|
8929
|
+
...parameters,
|
|
8930
|
+
input("image_reference_variant_refs", "string_array", true, "Exactly one completed portrait image Variant.", {
|
|
8931
|
+
minItems: 1,
|
|
8932
|
+
maxItems: 1
|
|
8933
|
+
}),
|
|
8934
|
+
input("audio_reference_variant_refs", "string_array", true, "Exactly one completed audio Variant.", {
|
|
8935
|
+
minItems: 1,
|
|
8936
|
+
maxItems: 1
|
|
8937
|
+
})
|
|
8938
|
+
]
|
|
8939
|
+
}],
|
|
8940
|
+
referenceRules: {
|
|
8941
|
+
mediaKind: null,
|
|
8942
|
+
completedOnly: true,
|
|
8943
|
+
maxCount: 2,
|
|
8944
|
+
maxTotalCount: 2,
|
|
8945
|
+
modalities: [{
|
|
8946
|
+
mediaKind: "image",
|
|
8947
|
+
minCount: 1,
|
|
8948
|
+
maxCount: 1,
|
|
8949
|
+
promptLabel: "Portrait",
|
|
8950
|
+
acceptedMimeTypes: [
|
|
8951
|
+
"image/jpeg",
|
|
8952
|
+
"image/png",
|
|
8953
|
+
"image/webp"
|
|
8954
|
+
],
|
|
8955
|
+
maxBytesPerFile: 10 * 1024 * 1024
|
|
8956
|
+
}, {
|
|
8957
|
+
mediaKind: "audio",
|
|
8958
|
+
minCount: 1,
|
|
8959
|
+
maxCount: 1,
|
|
8960
|
+
promptLabel: "Audio",
|
|
8961
|
+
acceptedMimeTypes: [
|
|
8962
|
+
"audio/mpeg",
|
|
8963
|
+
"audio/wav",
|
|
8964
|
+
"audio/x-wav",
|
|
8965
|
+
"audio/mp4",
|
|
8966
|
+
"audio/aac"
|
|
8967
|
+
],
|
|
8968
|
+
maxBytesPerFile: 5 * 1024 * 1024
|
|
8969
|
+
}]
|
|
8970
|
+
},
|
|
8971
|
+
notes: ["Outputs an ordinary video Variant. Provider routing remains internal."]
|
|
8972
|
+
};
|
|
8973
|
+
}
|
|
8746
8974
|
function audioGenerator(input_) {
|
|
8747
8975
|
const inputs = [
|
|
8748
8976
|
SPACE_INPUT,
|
|
@@ -8758,7 +8986,6 @@ function audioGenerator(input_) {
|
|
|
8758
8986
|
id: input_.id,
|
|
8759
8987
|
label: input_.label,
|
|
8760
8988
|
mediaKind: "audio",
|
|
8761
|
-
provider: input_.provider,
|
|
8762
8989
|
modelIds: [input_.modelId],
|
|
8763
8990
|
defaultModelId: input_.modelId,
|
|
8764
8991
|
operations: [{
|
|
@@ -8784,6 +9011,7 @@ function getGeneratorCatalog(overrides = {}) {
|
|
|
8784
9011
|
...Object.values(IMAGE_MODEL_CAPABILITIES).map(imageGenerator),
|
|
8785
9012
|
...VIDEO_MODEL_SELECTIONS.map(videoGenerator),
|
|
8786
9013
|
...SEEDANCE_2_SELECTIONS.map((selection) => seedanceVideoGenerator(SEEDANCE_2_CAPABILITIES[selection])),
|
|
9014
|
+
...AVATAR_MODEL_IDS.map(avatarVideoGenerator),
|
|
8787
9015
|
audioGenerator({
|
|
8788
9016
|
id: "audio/elevenlabs-speech",
|
|
8789
9017
|
label: "ElevenLabs Speech",
|
|
@@ -8863,6 +9091,11 @@ var DRAFT_RECIPE_INPUT_KEYS = {
|
|
|
8863
9091
|
duration: "seedanceDuration",
|
|
8864
9092
|
bitrate_mode: "seedanceBitrateMode"
|
|
8865
9093
|
};
|
|
9094
|
+
function draftRecipeInputKey(inputName, generatorId) {
|
|
9095
|
+
if (generatorId === "video/p-video-avatar" && inputName === "resolution") return "avatarResolution";
|
|
9096
|
+
if (generatorId === "video/kling-avatar-v2" && inputName === "mode") return "avatarMode";
|
|
9097
|
+
return DRAFT_RECIPE_INPUT_KEYS[inputName];
|
|
9098
|
+
}
|
|
8866
9099
|
var DRAFT_REFERENCE_FIELD = /(?:_variant_refs?|VariantRefs?)$/;
|
|
8867
9100
|
/**
|
|
8868
9101
|
* The one slot-naming convention used while authoring and resolving Bindings.
|
|
@@ -8883,6 +9116,7 @@ function generatorIdForDraftRecipe(mediaMode, recipe) {
|
|
|
8883
9116
|
}
|
|
8884
9117
|
if (mediaMode === "video") {
|
|
8885
9118
|
const model = typeof recipe.model === "string" ? recipe.model : "veo-3.1";
|
|
9119
|
+
if (isAvatarModelId(model)) return `video/${model}`;
|
|
8886
9120
|
const seedance = getSeedance2CapabilityByEndpoint(model);
|
|
8887
9121
|
if (seedance) return seedance.generatorId;
|
|
8888
9122
|
const selection = getVideoModelSelectionForModel(model);
|
|
@@ -8905,7 +9139,7 @@ function buildDraftMapping(args) {
|
|
|
8905
9139
|
if (!operationDefinition) throw new Error(`${generatorId} does not support ${operation} drafts`);
|
|
8906
9140
|
const recipeTemplate = { operation };
|
|
8907
9141
|
for (const input of operationDefinition.inputs) {
|
|
8908
|
-
const key =
|
|
9142
|
+
const key = draftRecipeInputKey(input.name, generatorId);
|
|
8909
9143
|
if (!key) continue;
|
|
8910
9144
|
const value = recipe[key];
|
|
8911
9145
|
if (value !== void 0) recipeTemplate[key] = value;
|
|
@@ -10094,7 +10328,7 @@ async function executeModels(parsed, deps = defaultDeps$5) {
|
|
|
10094
10328
|
const { models } = await response.json();
|
|
10095
10329
|
if (parsed.options.json === "true") deps.print(JSON.stringify(models, null, 2));
|
|
10096
10330
|
else for (const model of models) {
|
|
10097
|
-
const readiness = model.availability.available ? "ready" : model.availability.reason
|
|
10331
|
+
const readiness = model.availability.available ? "ready" : [model.availability.code, model.availability.reason].filter(Boolean).join(": ") || "unavailable";
|
|
10098
10332
|
deps.print(`${model.id.padEnd(20)} ${model.media_kind.padEnd(6)} ${readiness}`);
|
|
10099
10333
|
}
|
|
10100
10334
|
return models;
|
|
@@ -10117,6 +10351,7 @@ function formatModelDetail(model) {
|
|
|
10117
10351
|
`Availability: ${model.availability.available ? "ready" : model.availability.reason ?? "unavailable"}`,
|
|
10118
10352
|
"Operations:"
|
|
10119
10353
|
];
|
|
10354
|
+
if (!model.availability.available && model.availability.guidance) lines.splice(3, 0, `Next step: ${model.availability.guidance}`);
|
|
10120
10355
|
for (const operation of model.operations) {
|
|
10121
10356
|
if (typeof operation === "string") {
|
|
10122
10357
|
lines.push(` - ${operation}`);
|
|
@@ -11253,6 +11488,8 @@ var HELP = {
|
|
|
11253
11488
|
[--refs <variant-ref-or-file,...>] [--first-frame <ref>] [--last-frame <ref>] [--image-refs <refs>] [--video-refs <refs>] [--audio-refs <refs>]
|
|
11254
11489
|
[--aspect <ratio>] [--resolution 480p|720p|1080p|4k] [--duration <seconds|auto>] [--tier generate|fast|lite] [--bitrate standard|high]
|
|
11255
11490
|
[--audio | --no-audio] [--collection <id>] [--space <id>]
|
|
11491
|
+
makefx video generate ["prompt"] --model kling-avatar-v2 --image-refs <portrait-ref> --audio-refs <audio-ref>
|
|
11492
|
+
--name <name> --type <type> -o <file> [--mode standard|pro] [--collection <id>] [--space <id>]
|
|
11256
11493
|
makefx video regenerate <variant-ref> ["prompt"] [--model <model>] [--aspect <ratio>] [--resolution <value>] [--duration <seconds>] [--tier <tier>] [--bitrate standard|high] [--audio | --no-audio] [--image-refs <refs>] [--video-refs <refs>] [--audio-refs <refs>] [--no-activate] [--wait]
|
|
11257
11494
|
|
|
11258
11495
|
Seedance mode is inferred: first/last frame selects frame mode, image/video/audio refs select reference mode, and no references selects text mode.`,
|
|
@@ -11333,7 +11570,6 @@ compact variant refs, each optionally suffixed :derived, :refined, or :forked
|
|
|
11333
11570
|
};
|
|
11334
11571
|
//#endregion
|
|
11335
11572
|
//#region src/cli/index.ts
|
|
11336
|
-
var CLI_VERSION = "1.5.0+27ffb5049678";
|
|
11337
11573
|
function printHelp() {
|
|
11338
11574
|
console.log(TOP_LEVEL_HELP);
|
|
11339
11575
|
}
|