vidspotai-shared 1.0.124 → 1.0.126
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/lib/globals/aiModels/enums.d.ts +38 -0
- package/lib/globals/aiModels/enums.d.ts.map +1 -1
- package/lib/globals/aiModels/enums.js +49 -1
- package/lib/globals/aiModels/index.d.ts.map +1 -1
- package/lib/globals/aiModels/index.js +2 -0
- package/lib/globals/aiModels/providers/alibaba.d.ts.map +1 -1
- package/lib/globals/aiModels/providers/alibaba.js +460 -53
- package/lib/globals/aiModels/providers/bytedance.d.ts.map +1 -1
- package/lib/globals/aiModels/providers/bytedance.js +221 -39
- package/lib/globals/aiModels/providers/google.d.ts.map +1 -1
- package/lib/globals/aiModels/providers/google.js +178 -32
- package/lib/globals/aiModels/providers/kling.d.ts.map +1 -1
- package/lib/globals/aiModels/providers/kling.js +86 -12
- package/lib/globals/aiModels/providers/minimax.d.ts.map +1 -1
- package/lib/globals/aiModels/providers/minimax.js +77 -0
- package/lib/globals/aiModels/providers/openai.d.ts.map +1 -1
- package/lib/globals/aiModels/providers/openai.js +12 -0
- package/lib/globals/aiModels/providers/pixverse.d.ts.map +1 -1
- package/lib/globals/aiModels/providers/pixverse.js +101 -28
- package/lib/globals/aiModels/providers/runway.d.ts.map +1 -1
- package/lib/globals/aiModels/providers/runway.js +450 -24
- package/lib/globals/aiModels/providers/xai.d.ts +4 -0
- package/lib/globals/aiModels/providers/xai.d.ts.map +1 -0
- package/lib/globals/aiModels/providers/xai.js +72 -0
- package/lib/globals/aiModels/tierHelpers.d.ts +10 -0
- package/lib/globals/aiModels/tierHelpers.d.ts.map +1 -1
- package/lib/globals/aiModels/tierHelpers.js +48 -7
- package/lib/globals/aiModels/types.d.ts +21 -0
- package/lib/globals/aiModels/types.d.ts.map +1 -1
- package/lib/models/image.model.d.ts +24 -0
- package/lib/models/image.model.d.ts.map +1 -1
- package/lib/models/image.model.js +12 -0
- package/lib/models/index.d.ts +1 -0
- package/lib/models/index.d.ts.map +1 -1
- package/lib/models/index.js +1 -0
- package/lib/models/klingElement.model.d.ts +52 -0
- package/lib/models/klingElement.model.d.ts.map +1 -0
- package/lib/models/klingElement.model.js +24 -0
- package/lib/models/user.model.d.ts +7 -1
- package/lib/models/user.model.d.ts.map +1 -1
- package/lib/models/video.model.d.ts +11 -0
- package/lib/models/video.model.d.ts.map +1 -1
- package/lib/schemas/videoPlan.schema.d.ts +88 -0
- package/lib/schemas/videoPlan.schema.d.ts.map +1 -1
- package/lib/schemas/videoPlan.schema.js +27 -1
- package/lib/services/agent/executor/visual.d.ts.map +1 -1
- package/lib/services/agent/executor/visual.js +40 -2
- package/lib/services/agent/mentionedRefs.d.ts.map +1 -1
- package/lib/services/agent/mentionedRefs.js +4 -1
- package/lib/services/agent/planner/structuralRules.d.ts.map +1 -1
- package/lib/services/agent/planner/structuralRules.js +8 -3
- package/lib/services/agent/poster/posterAgent.schema.d.ts +3 -3
- package/lib/services/agent/providerFallback/chains.d.ts +25 -0
- package/lib/services/agent/providerFallback/chains.d.ts.map +1 -1
- package/lib/services/agent/providerFallback/chains.js +59 -5
- package/lib/services/agent/repair/strategies/llmRepair.strategy.d.ts.map +1 -1
- package/lib/services/agent/repair/strategies/llmRepair.strategy.js +2 -0
- package/lib/services/agent/tools/animateImage.tool.d.ts +31 -0
- package/lib/services/agent/tools/animateImage.tool.d.ts.map +1 -1
- package/lib/services/agent/tools/animateImage.tool.js +10 -3
- package/lib/services/agent/tools/generateImage.tool.d.ts +8 -4
- package/lib/services/agent/tools/generateImage.tool.d.ts.map +1 -1
- package/lib/services/agent/tools/generateImage.tool.js +24 -7
- package/lib/services/agent/tools/generateVideo.tool.d.ts +32 -0
- package/lib/services/agent/tools/generateVideo.tool.d.ts.map +1 -1
- package/lib/services/agent/tools/generateVideo.tool.js +37 -9
- package/lib/services/agent/tools/planVideo.tool.d.ts +19 -0
- package/lib/services/agent/tools/planVideo.tool.d.ts.map +1 -1
- package/lib/services/aiGen/aiGenFactory.service.d.ts.map +1 -1
- package/lib/services/aiGen/aiGenFactory.service.js +40 -0
- package/lib/services/aiGen/canonicalAdapters/cameraControl.types.d.ts +6 -3
- package/lib/services/aiGen/canonicalAdapters/cameraControl.types.d.ts.map +1 -1
- package/lib/services/aiGen/canonicalAdapters/cameraControl.types.js +35 -0
- package/lib/services/aiGen/canonicalAdapters/cameraDirection.d.ts +36 -0
- package/lib/services/aiGen/canonicalAdapters/cameraDirection.d.ts.map +1 -0
- package/lib/services/aiGen/canonicalAdapters/cameraDirection.js +168 -0
- package/lib/services/aiGen/canonicalAdapters/index.d.ts +1 -0
- package/lib/services/aiGen/canonicalAdapters/index.d.ts.map +1 -1
- package/lib/services/aiGen/canonicalAdapters/index.js +1 -0
- package/lib/services/aiGen/canonicalAdapters/multiShot.types.d.ts +3 -2
- package/lib/services/aiGen/canonicalAdapters/multiShot.types.d.ts.map +1 -1
- package/lib/services/aiGen/helpers.d.ts +40 -0
- package/lib/services/aiGen/helpers.d.ts.map +1 -1
- package/lib/services/aiGen/helpers.js +48 -2
- package/lib/services/aiGen/index.d.ts +1 -0
- package/lib/services/aiGen/index.d.ts.map +1 -1
- package/lib/services/aiGen/index.js +3 -0
- package/lib/services/aiGen/providers/alibaba/alibaba.d.ts +13 -1
- package/lib/services/aiGen/providers/alibaba/alibaba.d.ts.map +1 -1
- package/lib/services/aiGen/providers/alibaba/alibaba.js +313 -33
- package/lib/services/aiGen/providers/bytedance/bytedance.service.d.ts +29 -1
- package/lib/services/aiGen/providers/bytedance/bytedance.service.d.ts.map +1 -1
- package/lib/services/aiGen/providers/bytedance/bytedance.service.js +371 -54
- package/lib/services/aiGen/providers/google/google.service.d.ts +16 -0
- package/lib/services/aiGen/providers/google/google.service.d.ts.map +1 -1
- package/lib/services/aiGen/providers/google/google.service.js +372 -116
- package/lib/services/aiGen/providers/google/googleKeyPool.d.ts +6 -0
- package/lib/services/aiGen/providers/google/googleKeyPool.d.ts.map +1 -1
- package/lib/services/aiGen/providers/google/googleKeyPool.js +8 -0
- package/lib/services/aiGen/providers/kling/kling.service.d.ts +17 -1
- package/lib/services/aiGen/providers/kling/kling.service.d.ts.map +1 -1
- package/lib/services/aiGen/providers/kling/kling.service.js +59 -3
- package/lib/services/aiGen/providers/kling/klingCredits.d.ts +1 -1
- package/lib/services/aiGen/providers/kling/klingCredits.d.ts.map +1 -1
- package/lib/services/aiGen/providers/kling/klingCredits.js +19 -1
- package/lib/services/aiGen/providers/kling/klingRequests.d.ts +37 -7
- package/lib/services/aiGen/providers/kling/klingRequests.d.ts.map +1 -1
- package/lib/services/aiGen/providers/kling/klingRequests.js +191 -13
- package/lib/services/aiGen/providers/kling/types.d.ts +78 -0
- package/lib/services/aiGen/providers/kling/types.d.ts.map +1 -1
- package/lib/services/aiGen/providers/minimax/minimax.service.d.ts +11 -2
- package/lib/services/aiGen/providers/minimax/minimax.service.d.ts.map +1 -1
- package/lib/services/aiGen/providers/minimax/minimax.service.js +168 -2
- package/lib/services/aiGen/providers/minimax/types.d.ts +63 -0
- package/lib/services/aiGen/providers/minimax/types.d.ts.map +1 -1
- package/lib/services/aiGen/providers/pixverse/pixverse.service.d.ts +12 -0
- package/lib/services/aiGen/providers/pixverse/pixverse.service.d.ts.map +1 -1
- package/lib/services/aiGen/providers/pixverse/pixverse.service.js +131 -17
- package/lib/services/aiGen/providers/runway/hostedModels.d.ts +84 -0
- package/lib/services/aiGen/providers/runway/hostedModels.d.ts.map +1 -0
- package/lib/services/aiGen/providers/runway/hostedModels.js +266 -0
- package/lib/services/aiGen/providers/runway/index.d.ts +1 -0
- package/lib/services/aiGen/providers/runway/index.d.ts.map +1 -1
- package/lib/services/aiGen/providers/runway/index.js +1 -0
- package/lib/services/aiGen/providers/runway/runway.service.d.ts +1 -1
- package/lib/services/aiGen/providers/runway/runway.service.d.ts.map +1 -1
- package/lib/services/aiGen/providers/runway/runway.service.js +118 -21
- package/lib/services/aiGen/providers/runway/types.d.ts +18 -3
- package/lib/services/aiGen/providers/runway/types.d.ts.map +1 -1
- package/lib/services/aiGen/providers/runway/types.js +31 -3
- package/lib/services/aiGen/providers/types.d.ts +55 -0
- package/lib/services/aiGen/providers/types.d.ts.map +1 -1
- package/lib/services/aiGen/providers/xai/xai.service.d.ts +19 -0
- package/lib/services/aiGen/providers/xai/xai.service.d.ts.map +1 -0
- package/lib/services/aiGen/providers/xai/xai.service.js +205 -0
- package/lib/services/firestore.service.d.ts +4 -0
- package/lib/services/firestore.service.d.ts.map +1 -1
- package/lib/services/firestore.service.js +5 -0
- package/lib/services/index.d.ts +2 -0
- package/lib/services/index.d.ts.map +1 -1
- package/lib/services/index.js +2 -0
- package/lib/services/klingElements/klingElementLibrary.service.d.ts +37 -0
- package/lib/services/klingElements/klingElementLibrary.service.d.ts.map +1 -0
- package/lib/services/klingElements/klingElementLibrary.service.js +179 -0
- package/lib/services/trialGuard/index.d.ts +2 -0
- package/lib/services/trialGuard/index.d.ts.map +1 -0
- package/lib/services/trialGuard/index.js +17 -0
- package/lib/services/trialGuard/trialSignals.d.ts +88 -0
- package/lib/services/trialGuard/trialSignals.d.ts.map +1 -0
- package/lib/services/trialGuard/trialSignals.js +160 -0
- package/lib/utils/helpers.d.ts.map +1 -1
- package/lib/utils/helpers.js +5 -1
- package/package.json +2 -1
|
@@ -3,6 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.modelSupportsLastFrame = modelSupportsLastFrame;
|
|
4
4
|
exports.getModelsSupportingLastFrame = getModelsSupportingLastFrame;
|
|
5
5
|
exports.modelDeclaresField = modelDeclaresField;
|
|
6
|
+
exports.getInputVideoBilling = getInputVideoBilling;
|
|
7
|
+
exports.isModelRetired = isModelRetired;
|
|
6
8
|
exports.validateParams = validateParams;
|
|
7
9
|
const aiModels_1 = require("../../globals/aiModels");
|
|
8
10
|
const errors_1 = require("../../utils/errors");
|
|
@@ -37,11 +39,50 @@ function modelDeclaresField(modelKey, field) {
|
|
|
37
39
|
const cfg = aiModels_1.aiModelConfigs[modelKey];
|
|
38
40
|
return !!cfg?.fields && field in cfg.fields;
|
|
39
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* Input-video billing for getCreditUsed. Providers that bill input seconds
|
|
44
|
+
* (Wan 3.0, HappyHorse edit, MiniMax, Seedance 2.0) charge for EVERY video the
|
|
45
|
+
* request carries — the source clip and each reference clip — so both count.
|
|
46
|
+
* An unmeasured clip falls back to the output duration (the same conservative
|
|
47
|
+
* proxy the source clip always used). Every billing call site (precheck,
|
|
48
|
+
* upfront deduction, multi-scene true-up, reconcile) must go through this so
|
|
49
|
+
* the estimate and the reconcile agree.
|
|
50
|
+
*/
|
|
51
|
+
function getInputVideoBilling(src) {
|
|
52
|
+
const numInputImages = (src.inputImageUrl ? 1 : 0) +
|
|
53
|
+
(src.lastFrameImageUrl ? 1 : 0) +
|
|
54
|
+
(src.referenceImageUrls?.length ?? 0);
|
|
55
|
+
const numInputAudios = src.referenceAudioUrls?.length ?? 0;
|
|
56
|
+
const fallback = src.duration ?? 0;
|
|
57
|
+
let seconds = 0;
|
|
58
|
+
let clips = 0;
|
|
59
|
+
if (src.inputVideoUrl) {
|
|
60
|
+
seconds += src.inputVideoDurationSec ?? fallback;
|
|
61
|
+
clips += 1;
|
|
62
|
+
}
|
|
63
|
+
(src.referenceVideoUrls ?? []).forEach((_, i) => {
|
|
64
|
+
seconds += src.referenceVideoDurationsSec?.[i] ?? fallback;
|
|
65
|
+
clips += 1;
|
|
66
|
+
});
|
|
67
|
+
// return clips ? { hasInputVideo: true, inputVideoDurationSec: seconds } : { hasInputVideo: false }; // REMOVED FOR v2 — now also counts input images
|
|
68
|
+
return clips
|
|
69
|
+
? { hasInputVideo: true, inputVideoDurationSec: seconds, numInputImages, numInputAudios }
|
|
70
|
+
: { hasInputVideo: false, numInputImages, numInputAudios };
|
|
71
|
+
}
|
|
72
|
+
function isModelRetired(modelKey) {
|
|
73
|
+
const cfg = aiModels_1.aiModelConfigs[modelKey];
|
|
74
|
+
return !!cfg?.retired;
|
|
75
|
+
}
|
|
40
76
|
function validateParams(params) {
|
|
41
77
|
const modelConfig = aiModels_1.aiModelConfigs[params.modelKey];
|
|
42
78
|
if (!modelConfig) {
|
|
43
79
|
throw new Error(`Unsupported model: ${params.modelKey}`);
|
|
44
80
|
}
|
|
81
|
+
// 0. Retired upstream — fail fast with a user-facing, non-paging error
|
|
82
|
+
// instead of a billed round-trip to a dead endpoint.
|
|
83
|
+
if (modelConfig.retired) {
|
|
84
|
+
throw new errors_1.UserFacingError(`Model ${params.modelKey} is no longer available: ${modelConfig.retired.reason} Please pick a different model.`, errors_1.USER_FACING_ERROR_CODES.CAPABILITY_MISMATCH);
|
|
85
|
+
}
|
|
45
86
|
const errors = [];
|
|
46
87
|
// 1. Field-level validation (required + allowedValues)
|
|
47
88
|
for (const [field, rules] of Object.entries(modelConfig.fields)) {
|
|
@@ -84,8 +125,13 @@ function validateParams(params) {
|
|
|
84
125
|
(!modelConfig.type.includes("image-to-video") || !params.inputImageUrl)) {
|
|
85
126
|
errors.push(`Model ${params.modelKey} requires imageUrl for image-to-video mode`);
|
|
86
127
|
}
|
|
87
|
-
|
|
88
|
-
|
|
128
|
+
// REMOVED FOR v2 — kept for reference: inverted — it rejected every
|
|
129
|
+
// video-to-video request on a model that DOES declare video-to-video.
|
|
130
|
+
// if (
|
|
131
|
+
// params.type === "video-to-video" &&
|
|
132
|
+
// (modelConfig.type.includes("video-to-video") || !params.inputVideoUrl)
|
|
133
|
+
// ) {
|
|
134
|
+
if (params.type === "video-to-video" && !params.inputVideoUrl) {
|
|
89
135
|
errors.push(`Model ${params.modelKey} requires videoUrl for video-to-video mode`);
|
|
90
136
|
}
|
|
91
137
|
if (modelConfig.type.includes("text-to-video") && !params.prompt) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/services/aiGen/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC;AACvC,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,kBAAkB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/services/aiGen/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC;AACvC,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,kBAAkB,CAAC;AACjC,OAAO,EAAE,oBAAoB,EAAE,MAAM,qCAAqC,CAAC"}
|
|
@@ -14,8 +14,11 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.applyCameraDirection = void 0;
|
|
17
18
|
__exportStar(require("./aiGenFactory.service"), exports);
|
|
18
19
|
__exportStar(require("./types"), exports);
|
|
19
20
|
__exportStar(require("./helpers"), exports);
|
|
20
21
|
__exportStar(require("./providers"), exports);
|
|
21
22
|
__exportStar(require("./transientRetry"), exports);
|
|
23
|
+
var cameraDirection_1 = require("./canonicalAdapters/cameraDirection");
|
|
24
|
+
Object.defineProperty(exports, "applyCameraDirection", { enumerable: true, get: function () { return cameraDirection_1.applyCameraDirection; } });
|
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
import { BaseAiGenProviderService } from "../baseAiGenProvider.service";
|
|
2
2
|
import { CreditUsageParams, ImageGenerationParams, ImageGenerationResult, VideoGenerationParams, VideoGenerationResult, VideoStatusParams, VideoStatusResult } from "../types";
|
|
3
|
+
/**
|
|
4
|
+
* Build the `{input, parameters}` body for the media-array models. Mode is
|
|
5
|
+
* driven by the model id (HappyHorse ships one model per mode) and, for the
|
|
6
|
+
* all-in-one Wan 3.0, by which inputs are present. Reference order matters:
|
|
7
|
+
* the prompt cites media as "Image 1" / "Video 1" / "Audio 1" (Wan 3.0) or
|
|
8
|
+
* "[Image 1]" (HappyHorse) in array order, per type.
|
|
9
|
+
*/
|
|
10
|
+
export declare function buildMediaArrayVideoBody(modelId: string, params: VideoGenerationParams): {
|
|
11
|
+
input: Record<string, unknown>;
|
|
12
|
+
parameters: Record<string, unknown>;
|
|
13
|
+
};
|
|
3
14
|
/**
|
|
4
15
|
* Map a canonical "W:H" aspect ratio to a DashScope pixel `size` string.
|
|
5
16
|
* Returns undefined for unparseable input so the caller simply omits `size`
|
|
@@ -17,6 +28,7 @@ export declare class AlibabaService extends BaseAiGenProviderService {
|
|
|
17
28
|
*/
|
|
18
29
|
private request;
|
|
19
30
|
generateVideo(params: VideoGenerationParams): Promise<VideoGenerationResult>;
|
|
31
|
+
private submitVideo;
|
|
20
32
|
checkVideoStatus({ task, outputFilename, outputFilePath, modelKey, }: VideoStatusParams): Promise<VideoStatusResult>;
|
|
21
33
|
/**
|
|
22
34
|
* DashScope image generation. Three dispatch paths (verified live 2026-06-06):
|
|
@@ -51,6 +63,6 @@ export declare class AlibabaService extends BaseAiGenProviderService {
|
|
|
51
63
|
* and text2image/image-synthesis (legacy Qwen).
|
|
52
64
|
*/
|
|
53
65
|
private generateImageAsync;
|
|
54
|
-
getCreditUsed({ modelKey, resolution, aspectRatio, duration, multiClip, numImages, creditFloor, }: CreditUsageParams): number;
|
|
66
|
+
getCreditUsed({ modelKey, resolution, aspectRatio, duration, multiClip, numImages, creditFloor, hasInputVideo, inputVideoDurationSec, audio, numInputImages, }: CreditUsageParams): number;
|
|
55
67
|
}
|
|
56
68
|
//# sourceMappingURL=alibaba.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"alibaba.d.ts","sourceRoot":"","sources":["../../../../../src/services/aiGen/providers/alibaba/alibaba.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AACxE,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,iBAAiB,EACjB,iBAAiB,EAClB,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"alibaba.d.ts","sourceRoot":"","sources":["../../../../../src/services/aiGen/providers/alibaba/alibaba.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AACxE,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,iBAAiB,EACjB,iBAAiB,EAClB,MAAM,UAAU,CAAC;AAwFlB;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,qBAAqB,GAC5B;IAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CAgJzE;AA2CD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,GAClB,MAAM,GAAG,SAAS,CAmBpB;AAED,qBAAa,cAAe,SAAQ,wBAAwB;IAE1D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAwB;IAChD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;;IAiBjC;;;;OAIG;YACW,OAAO;IAwDf,aAAa,CACjB,MAAM,EAAE,qBAAqB,GAC5B,OAAO,CAAC,qBAAqB,CAAC;YAyInB,WAAW;IAwBnB,gBAAgB,CAAC,EACrB,IAAI,EACJ,cAAc,EACd,cAAyB,EACzB,QAAQ,GACT,EAAE,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAqEjD;;;;;;;;;;;;;;;;;;;;;OAqBG;IACG,aAAa,CACjB,MAAM,EAAE,qBAAqB,GAC5B,OAAO,CAAC,qBAAqB,CAAC;IA6EjC;;;OAGG;YACW,iBAAiB;IAoD/B;;;OAGG;YACW,kBAAkB;IA6DhC,aAAa,CAAC,EACZ,QAAQ,EACR,UAAU,EACV,WAAW,EACX,QAAQ,EACR,SAAiB,EACjB,SAAa,EACb,WAAW,EACX,aAAa,EACb,qBAAqB,EACrB,KAAK,EACL,cAAc,GACf,EAAE,iBAAiB,GAAG,MAAM;CA4C9B"}
|
|
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.AlibabaService = void 0;
|
|
7
|
+
exports.buildMediaArrayVideoBody = buildMediaArrayVideoBody;
|
|
7
8
|
exports.resolveDashScopeSize = resolveDashScopeSize;
|
|
8
9
|
const axios_1 = __importDefault(require("axios"));
|
|
9
10
|
const types_1 = require("../../../../globals/types");
|
|
@@ -29,7 +30,14 @@ const errors_1 = require("../../../../utils/errors");
|
|
|
29
30
|
// S2V (wan2.2-s2v) is China-region only and cannot be reached with an intl
|
|
30
31
|
// DashScope key; the model key is intentionally kept but rejected at submit
|
|
31
32
|
// with a UserFacingError. Same for kolors-v2 (Kuaishou model, not Alibaba).
|
|
32
|
-
|
|
33
|
+
//
|
|
34
|
+
// Host: Alibaba now recommends the workspace domain
|
|
35
|
+
// https://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api/v1 and says the
|
|
36
|
+
// DashScope domain gets no NEW features after 2026-09-30 (existing models keep
|
|
37
|
+
// working). ALIBABA_API_BASE_URL switches hosts without a code change; the
|
|
38
|
+
// same API key works on both.
|
|
39
|
+
// const ALIBABA_BASE_URL = "https://dashscope-intl.aliyuncs.com/api/v1"; // REMOVED FOR v2 — now env-overridable
|
|
40
|
+
const ALIBABA_BASE_URL = (process.env.ALIBABA_API_BASE_URL || "https://dashscope-intl.aliyuncs.com/api/v1").replace(/\/+$/, "");
|
|
33
41
|
const ALIBABA_BASE = `${ALIBABA_BASE_URL}/services/aigc`;
|
|
34
42
|
const ENDPOINT_VIDEO_ASYNC = `${ALIBABA_BASE}/video-generation/video-synthesis`;
|
|
35
43
|
const ENDPOINT_IMAGE_T2I_ASYNC = `${ALIBABA_BASE}/text2image/image-synthesis`;
|
|
@@ -53,6 +61,7 @@ const INTL_UNAVAILABLE_MODEL_IDS = new Set([
|
|
|
53
61
|
// - Legacy qwen-image, qwen-image-plus.
|
|
54
62
|
function isSyncMultimodalImageModel(modelId) {
|
|
55
63
|
return (modelId.startsWith("qwen-image-2") ||
|
|
64
|
+
modelId.startsWith("qwen-image-3") ||
|
|
56
65
|
modelId.startsWith("qwen-image-max") ||
|
|
57
66
|
modelId.startsWith("qwen-image-edit") ||
|
|
58
67
|
modelId.startsWith("wan2.7-image"));
|
|
@@ -60,6 +69,165 @@ function isSyncMultimodalImageModel(modelId) {
|
|
|
60
69
|
function isAsyncWanImageModel(modelId) {
|
|
61
70
|
return modelId.startsWith("wan2.7-image") || modelId.startsWith("wan2.6-image");
|
|
62
71
|
}
|
|
72
|
+
/**
|
|
73
|
+
* Wan 3.0, HappyHorse and Wan 2.7 r2v / videoedit take every input as
|
|
74
|
+
* `input.media[{type,url}]` and pick size with `resolution` ("1080P") +
|
|
75
|
+
* `ratio` instead of a pixel `size`. Only the Wan 2.7 pair take a negative prompt. HappyHorse also watermarks by DEFAULT, so we always
|
|
76
|
+
* send an explicit `watermark`.
|
|
77
|
+
*/
|
|
78
|
+
function isMediaArrayVideoModel(modelId) {
|
|
79
|
+
// return modelId.startsWith("wan3") || modelId.startsWith("happyhorse"); // REMOVED FOR v2 — + Wan 2.7 r2v / videoedit
|
|
80
|
+
return (modelId.startsWith("wan3") ||
|
|
81
|
+
modelId.startsWith("happyhorse") ||
|
|
82
|
+
modelId.startsWith("wan2.7-r2v") ||
|
|
83
|
+
modelId.startsWith("wan2.7-videoedit"));
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Build the `{input, parameters}` body for the media-array models. Mode is
|
|
87
|
+
* driven by the model id (HappyHorse ships one model per mode) and, for the
|
|
88
|
+
* all-in-one Wan 3.0, by which inputs are present. Reference order matters:
|
|
89
|
+
* the prompt cites media as "Image 1" / "Video 1" / "Audio 1" (Wan 3.0) or
|
|
90
|
+
* "[Image 1]" (HappyHorse) in array order, per type.
|
|
91
|
+
*/
|
|
92
|
+
function buildMediaArrayVideoBody(modelId, params) {
|
|
93
|
+
const media = [];
|
|
94
|
+
const refImages = params.referenceImageUrls ?? [];
|
|
95
|
+
const refVideos = [
|
|
96
|
+
...(params.inputVideoUrl ? [params.inputVideoUrl] : []),
|
|
97
|
+
...(params.referenceVideoUrls ?? []),
|
|
98
|
+
];
|
|
99
|
+
const refAudios = params.referenceAudioUrls ?? [];
|
|
100
|
+
const isHappyHorse = modelId.startsWith("happyhorse");
|
|
101
|
+
const isVideoEdit = modelId === "happyhorse-1.0-video-edit";
|
|
102
|
+
// const isHappyHorseI2V = modelId === "happyhorse-1.1-i2v"; // REMOVED FOR v2 — suffix covers 1.0 + 1.1
|
|
103
|
+
// HappyHorse ships one model per mode; the id suffix names it (-t2v/-i2v/-r2v).
|
|
104
|
+
const isHappyHorseI2V = isHappyHorse && modelId.endsWith("-i2v");
|
|
105
|
+
const isWan27R2V = modelId.startsWith("wan2.7-r2v");
|
|
106
|
+
const isWan27VideoEdit = modelId.startsWith("wan2.7-videoedit");
|
|
107
|
+
const hasFrames = !!params.inputImageUrl || !!params.lastFrameImageUrl;
|
|
108
|
+
const hasDocOrLink = !!params.referenceDocumentUrl || !!params.referenceWebPageUrl;
|
|
109
|
+
const hasRefs = refImages.length + refVideos.length + refAudios.length > 0 || hasDocOrLink;
|
|
110
|
+
if (isWan27R2V) {
|
|
111
|
+
// ≤1 first frame + 1–5 subjects (images + videos combined); each subject
|
|
112
|
+
// may carry a voice. Voices map in send order: videos first, then images.
|
|
113
|
+
const subjects = [
|
|
114
|
+
...(params.referenceVideoUrls ?? []).map((url) => ({ type: "reference_video", url })),
|
|
115
|
+
...refImages.map((url) => ({ type: "reference_image", url })),
|
|
116
|
+
];
|
|
117
|
+
if (subjects.length < 1 || subjects.length > 5) {
|
|
118
|
+
throw new errors_1.UserFacingError(`${modelId} needs 1–5 reference images and videos in total (got ${subjects.length}).`, errors_1.USER_FACING_ERROR_CODES.CAPABILITY_MISMATCH);
|
|
119
|
+
}
|
|
120
|
+
if (refAudios.length > subjects.length) {
|
|
121
|
+
throw new errors_1.UserFacingError(`${modelId} takes one voice per reference subject: ${refAudios.length} voices for ${subjects.length} subjects.`, errors_1.USER_FACING_ERROR_CODES.CAPABILITY_MISMATCH);
|
|
122
|
+
}
|
|
123
|
+
if ((params.referenceVideoUrls?.length ?? 0) > 0 && (params.duration ?? 5) > 10) {
|
|
124
|
+
throw new errors_1.UserFacingError(`${modelId} is limited to 10s when a reference video is used.`, errors_1.USER_FACING_ERROR_CODES.CAPABILITY_MISMATCH);
|
|
125
|
+
}
|
|
126
|
+
if (params.inputImageUrl)
|
|
127
|
+
media.push({ type: "first_frame", url: params.inputImageUrl });
|
|
128
|
+
subjects.forEach((m, i) => media.push(refAudios[i] ? { ...m, reference_voice: refAudios[i] } : m));
|
|
129
|
+
}
|
|
130
|
+
else if (isWan27VideoEdit) {
|
|
131
|
+
if (!params.inputVideoUrl) {
|
|
132
|
+
throw new errors_1.UserFacingError(`${modelId} needs the video to edit (inputVideoUrl).`, errors_1.USER_FACING_ERROR_CODES.CAPABILITY_MISMATCH);
|
|
133
|
+
}
|
|
134
|
+
media.push({ type: "video", url: params.inputVideoUrl });
|
|
135
|
+
for (const url of refImages.slice(0, 4))
|
|
136
|
+
media.push({ type: "reference_image", url });
|
|
137
|
+
}
|
|
138
|
+
else if (isVideoEdit) {
|
|
139
|
+
if (!params.inputVideoUrl) {
|
|
140
|
+
throw new errors_1.UserFacingError(`${modelId} needs the video to edit (inputVideoUrl).`, errors_1.USER_FACING_ERROR_CODES.CAPABILITY_MISMATCH);
|
|
141
|
+
}
|
|
142
|
+
media.push({ type: "video", url: params.inputVideoUrl });
|
|
143
|
+
for (const url of refImages.slice(0, 5))
|
|
144
|
+
media.push({ type: "reference_image", url });
|
|
145
|
+
}
|
|
146
|
+
else if (isHappyHorseI2V) {
|
|
147
|
+
media.push({ type: "first_frame", url: params.inputImageUrl });
|
|
148
|
+
}
|
|
149
|
+
else if (isHappyHorse) {
|
|
150
|
+
// r2v: 1–9 reference images; t2v: no media.
|
|
151
|
+
for (const url of refImages.slice(0, 9))
|
|
152
|
+
media.push({ type: "reference_image", url });
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
// Wan 3.0: first/last frame XOR references (the API rejects mixing them).
|
|
156
|
+
if (hasFrames && hasRefs) {
|
|
157
|
+
throw new errors_1.UserFacingError(`${modelId} can't combine first/last frame images with reference images, videos, audio, documents or web pages. Use one or the other.`, errors_1.USER_FACING_ERROR_CODES.CAPABILITY_MISMATCH);
|
|
158
|
+
}
|
|
159
|
+
if (params.referenceDocumentUrl && params.referenceWebPageUrl) {
|
|
160
|
+
throw new errors_1.UserFacingError(`${modelId} takes a reference document OR a web page, not both.`, errors_1.USER_FACING_ERROR_CODES.CAPABILITY_MISMATCH);
|
|
161
|
+
}
|
|
162
|
+
if (params.inputImageUrl)
|
|
163
|
+
media.push({ type: "first_frame", url: params.inputImageUrl });
|
|
164
|
+
if (params.lastFrameImageUrl)
|
|
165
|
+
media.push({ type: "last_frame", url: params.lastFrameImageUrl });
|
|
166
|
+
for (const url of refImages.slice(0, 10))
|
|
167
|
+
media.push({ type: "reference_image", url });
|
|
168
|
+
for (const url of refVideos.slice(0, 5))
|
|
169
|
+
media.push({ type: "reference_video", url });
|
|
170
|
+
for (const url of refAudios.slice(0, 5))
|
|
171
|
+
media.push({ type: "reference_audio", url });
|
|
172
|
+
if (params.referenceDocumentUrl)
|
|
173
|
+
media.push({ type: "file", url: params.referenceDocumentUrl });
|
|
174
|
+
if (params.referenceWebPageUrl)
|
|
175
|
+
media.push({ type: "link", url: params.referenceWebPageUrl });
|
|
176
|
+
}
|
|
177
|
+
const input = {};
|
|
178
|
+
if (params.prompt)
|
|
179
|
+
input.prompt = params.prompt;
|
|
180
|
+
if (media.length)
|
|
181
|
+
input.media = media;
|
|
182
|
+
// Wan 2.7 takes a negative prompt; Wan 3.0 / HappyHorse don't.
|
|
183
|
+
if ((isWan27R2V || isWan27VideoEdit) && params.negativePrompt) {
|
|
184
|
+
input.negative_prompt = params.negativePrompt;
|
|
185
|
+
}
|
|
186
|
+
const parameters = {
|
|
187
|
+
watermark: params.watermark ?? false,
|
|
188
|
+
};
|
|
189
|
+
if (params.resolution)
|
|
190
|
+
parameters.resolution = params.resolution.toUpperCase();
|
|
191
|
+
if (params.seed !== undefined)
|
|
192
|
+
parameters.seed = params.seed;
|
|
193
|
+
if (isWan27VideoEdit) {
|
|
194
|
+
// Output = the whole input clip by default; `duration` truncates from 0s,
|
|
195
|
+
// so it's only sent when we know it's shorter than the clip.
|
|
196
|
+
if (params.duration &&
|
|
197
|
+
params.inputVideoDurationSec !== undefined &&
|
|
198
|
+
params.duration < params.inputVideoDurationSec) {
|
|
199
|
+
parameters.duration = params.duration;
|
|
200
|
+
}
|
|
201
|
+
if (params.aspectRatio)
|
|
202
|
+
parameters.ratio = params.aspectRatio;
|
|
203
|
+
parameters.audio_setting = params.audio === false ? "origin" : "auto";
|
|
204
|
+
parameters.prompt_extend = params.promptOptimizer ?? true;
|
|
205
|
+
return { input, parameters };
|
|
206
|
+
}
|
|
207
|
+
if (isVideoEdit) {
|
|
208
|
+
// Output length follows the input clip; no duration/ratio. `audio: false`
|
|
209
|
+
// keeps the source audio, otherwise the model decides.
|
|
210
|
+
parameters.audio_setting = params.audio === false ? "origin" : "auto";
|
|
211
|
+
return { input, parameters };
|
|
212
|
+
}
|
|
213
|
+
parameters.duration = params.duration || 5;
|
|
214
|
+
// Frame-driven output follows the image, so ratio is only sent without a
|
|
215
|
+
// first frame (Wan 3.0 defaults to "adaptive"; HappyHorse i2v has no ratio).
|
|
216
|
+
if (params.aspectRatio && !params.inputImageUrl && !isHappyHorseI2V) {
|
|
217
|
+
parameters.ratio = params.aspectRatio;
|
|
218
|
+
}
|
|
219
|
+
if (isWan27R2V) {
|
|
220
|
+
// Always generates audio; no `audio` switch.
|
|
221
|
+
parameters.prompt_extend = params.promptOptimizer ?? true;
|
|
222
|
+
}
|
|
223
|
+
else if (!isHappyHorse) {
|
|
224
|
+
if (params.audio !== undefined)
|
|
225
|
+
parameters.audio = params.audio;
|
|
226
|
+
// Document / web-page inputs require prompt_extend=true (API rule).
|
|
227
|
+
parameters.prompt_extend = hasDocOrLink ? true : params.promptOptimizer ?? true;
|
|
228
|
+
}
|
|
229
|
+
return { input, parameters };
|
|
230
|
+
}
|
|
63
231
|
/**
|
|
64
232
|
* DashScope's `size` parameter is "WIDTH*HEIGHT" in PIXELS — it is NOT an
|
|
65
233
|
* aspect-ratio string. We used to assign `parameters.size = params.aspectRatio`
|
|
@@ -105,7 +273,8 @@ function round16(n) {
|
|
|
105
273
|
* and lets DashScope apply its own default (better than sending a bad value).
|
|
106
274
|
*/
|
|
107
275
|
function resolveDashScopeSize(modelId, aspectRatio) {
|
|
108
|
-
const family = modelId.startsWith("qwen-image-2") ? "large" : "standard";
|
|
276
|
+
// REMOVED FOR v2 — kept for reference: const family = modelId.startsWith("qwen-image-2") ? "large" : "standard";
|
|
277
|
+
const family = modelId.startsWith("qwen-image-2") || modelId.startsWith("qwen-image-3") ? "large" : "standard";
|
|
109
278
|
const preset = DASHSCOPE_SIZE_PRESETS[family][aspectRatio];
|
|
110
279
|
if (preset)
|
|
111
280
|
return preset;
|
|
@@ -192,52 +361,131 @@ class AlibabaService extends baseAiGenProvider_service_1.BaseAiGenProviderServic
|
|
|
192
361
|
if (INTL_UNAVAILABLE_MODEL_IDS.has(modelId)) {
|
|
193
362
|
throw new errors_1.UserFacingError(`Model "${modelId}" is not available on the intl DashScope endpoint (dashscope-intl.aliyuncs.com). It is hosted only in the China region and requires a separate Beijing-region API key.`, errors_1.USER_FACING_ERROR_CODES.PROVIDER_AUTH_ERROR);
|
|
194
363
|
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
364
|
+
if (isMediaArrayVideoModel(modelId)) {
|
|
365
|
+
const { input, parameters } = buildMediaArrayVideoBody(modelId, params);
|
|
366
|
+
return this.submitVideo({ model: modelId, input, parameters });
|
|
367
|
+
}
|
|
368
|
+
// REMOVED FOR v2 — kept for reference. Sent a pixel `size` to wan2.7-t2v
|
|
369
|
+
// (which replaced it with resolution + ratio), never sent `resolution` for
|
|
370
|
+
// I2V (so every I2V ran at the 1080P default whatever we billed), and
|
|
371
|
+
// ignored first_clip / driving audio.
|
|
372
|
+
// // T2V and I2V share a single endpoint. The model + presence of img_url
|
|
373
|
+
// // determines mode. S2V is unavailable on intl (gated above).
|
|
374
|
+
// const isI2V = !!params.inputImageUrl;
|
|
375
|
+
// const input: Record<string, unknown> = {};
|
|
376
|
+
// if (params.prompt) input.prompt = params.prompt;
|
|
377
|
+
// if (params.negativePrompt) input.negative_prompt = params.negativePrompt;
|
|
378
|
+
// if (isI2V) {
|
|
379
|
+
// // wan2.7-i2v moved to a media[] array ({type,url}) instead of the
|
|
380
|
+
// // legacy img_url/last_frame_url fields — confirmed against Alibaba's
|
|
381
|
+
// // "Wan 2.7 - image-to-video API" reference (2026-08-20); wan2.6-i2v(-flash)
|
|
382
|
+
// // and older versions still use img_url/last_frame_url.
|
|
383
|
+
// if (modelId.startsWith("wan2.7")) {
|
|
384
|
+
// const media: Array<{ type: string; url: string }> = [
|
|
385
|
+
// { type: "first_frame", url: params.inputImageUrl! },
|
|
386
|
+
// ];
|
|
387
|
+
// if (params.lastFrameImageUrl) {
|
|
388
|
+
// media.push({ type: "last_frame", url: params.lastFrameImageUrl });
|
|
389
|
+
// }
|
|
390
|
+
// input.media = media;
|
|
391
|
+
// } else {
|
|
392
|
+
// input.img_url = params.inputImageUrl;
|
|
393
|
+
// // wan2.6-i2v supports first-last-frame interpolation
|
|
394
|
+
// if (params.lastFrameImageUrl) input.last_frame_url = params.lastFrameImageUrl;
|
|
395
|
+
// }
|
|
396
|
+
// }
|
|
397
|
+
// const parameters: Record<string, unknown> = {
|
|
398
|
+
// duration: params.duration || 5,
|
|
399
|
+
// prompt_extend: params.promptOptimizer ?? true,
|
|
400
|
+
// };
|
|
401
|
+
// // T2V requires explicit size; I2V derives dimensions from the input image.
|
|
402
|
+
// if (!isI2V) {
|
|
403
|
+
// const size = getAlibabaDimensions(params.resolution!, params.aspectRatio!);
|
|
404
|
+
// if (!size) {
|
|
405
|
+
// throw new Error(
|
|
406
|
+
// `Invalid resolution/aspect ratio combination: ${params.resolution} ${params.aspectRatio}`
|
|
407
|
+
// );
|
|
408
|
+
// }
|
|
409
|
+
// parameters.size = size;
|
|
410
|
+
// }
|
|
411
|
+
// if (params.seed !== undefined) parameters.seed = params.seed;
|
|
412
|
+
// if (params.watermark !== undefined) parameters.watermark = params.watermark;
|
|
413
|
+
// T2V and I2V share a single endpoint. The model + inputs determine mode.
|
|
414
|
+
const isWan27 = modelId.startsWith("wan2.7");
|
|
415
|
+
const isI2V = !!params.inputImageUrl || (isWan27 && !!params.inputVideoUrl);
|
|
416
|
+
const resolutionTier = params.resolution ? params.resolution.toUpperCase() : undefined;
|
|
417
|
+
if (modelId.startsWith("wan2.7-i2v") && !isI2V) {
|
|
418
|
+
throw new errors_1.UserFacingError(`${modelId} needs a first-frame image or a first video clip to continue.`, errors_1.USER_FACING_ERROR_CODES.CAPABILITY_MISMATCH);
|
|
419
|
+
}
|
|
198
420
|
const input = {};
|
|
199
421
|
if (params.prompt)
|
|
200
422
|
input.prompt = params.prompt;
|
|
201
423
|
if (params.negativePrompt)
|
|
202
424
|
input.negative_prompt = params.negativePrompt;
|
|
203
|
-
if (isI2V) {
|
|
204
|
-
// wan2.7-i2v moved to a media[] array ({type,url}) instead of the
|
|
205
|
-
// legacy img_url/last_frame_url fields — confirmed against Alibaba's
|
|
206
|
-
// "Wan 2.7 - image-to-video API" reference (2026-08-20); wan2.6-i2v(-flash)
|
|
207
|
-
// and older versions still use img_url/last_frame_url.
|
|
208
|
-
if (modelId.startsWith("wan2.7")) {
|
|
209
|
-
const media = [
|
|
210
|
-
{ type: "first_frame", url: params.inputImageUrl },
|
|
211
|
-
];
|
|
212
|
-
if (params.lastFrameImageUrl) {
|
|
213
|
-
media.push({ type: "last_frame", url: params.lastFrameImageUrl });
|
|
214
|
-
}
|
|
215
|
-
input.media = media;
|
|
216
|
-
}
|
|
217
|
-
else {
|
|
218
|
-
input.img_url = params.inputImageUrl;
|
|
219
|
-
// wan2.6-i2v supports first-last-frame interpolation
|
|
220
|
-
if (params.lastFrameImageUrl)
|
|
221
|
-
input.last_frame_url = params.lastFrameImageUrl;
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
425
|
const parameters = {
|
|
225
426
|
duration: params.duration || 5,
|
|
226
427
|
prompt_extend: params.promptOptimizer ?? true,
|
|
227
428
|
};
|
|
228
|
-
|
|
229
|
-
|
|
429
|
+
if (isI2V && isWan27) {
|
|
430
|
+
// wan2.7-i2v: everything in media[] ({type,url}); each type at most once.
|
|
431
|
+
// first_frame [+ last_frame] [+ driving_audio] or first_clip [+ last_frame]
|
|
432
|
+
// Output aspect follows the first frame / clip, so no ratio.
|
|
433
|
+
const media = [];
|
|
434
|
+
if (params.inputVideoUrl) {
|
|
435
|
+
media.push({ type: "first_clip", url: params.inputVideoUrl });
|
|
436
|
+
}
|
|
437
|
+
else {
|
|
438
|
+
media.push({ type: "first_frame", url: params.inputImageUrl });
|
|
439
|
+
}
|
|
440
|
+
if (params.lastFrameImageUrl) {
|
|
441
|
+
media.push({ type: "last_frame", url: params.lastFrameImageUrl });
|
|
442
|
+
}
|
|
443
|
+
if (params.inputAudioUrl && !params.inputVideoUrl) {
|
|
444
|
+
media.push({ type: "driving_audio", url: params.inputAudioUrl });
|
|
445
|
+
}
|
|
446
|
+
input.media = media;
|
|
447
|
+
if (resolutionTier)
|
|
448
|
+
parameters.resolution = resolutionTier;
|
|
449
|
+
}
|
|
450
|
+
else if (isI2V) {
|
|
451
|
+
// wan2.6 and older: img_url / last_frame_url, `resolution` tier.
|
|
452
|
+
input.img_url = params.inputImageUrl;
|
|
453
|
+
// REMOVED FOR v2 — the legacy I2V API has no last_frame_url (only wan2.7 does FLF):
|
|
454
|
+
// if (params.lastFrameImageUrl) input.last_frame_url = params.lastFrameImageUrl;
|
|
455
|
+
if (params.inputAudioUrl)
|
|
456
|
+
input.audio_url = params.inputAudioUrl;
|
|
457
|
+
if (resolutionTier)
|
|
458
|
+
parameters.resolution = resolutionTier;
|
|
459
|
+
}
|
|
460
|
+
else if (isWan27) {
|
|
461
|
+
// wan2.7-t2v: resolution + ratio replace the pixel `size`.
|
|
462
|
+
if (params.inputAudioUrl)
|
|
463
|
+
input.audio_url = params.inputAudioUrl;
|
|
464
|
+
if (resolutionTier)
|
|
465
|
+
parameters.resolution = resolutionTier;
|
|
466
|
+
if (params.aspectRatio)
|
|
467
|
+
parameters.ratio = params.aspectRatio;
|
|
468
|
+
}
|
|
469
|
+
else {
|
|
470
|
+
// wan2.6-t2v and older T2V: pixel `size` ("1920*1080").
|
|
471
|
+
if (params.inputAudioUrl)
|
|
472
|
+
input.audio_url = params.inputAudioUrl;
|
|
230
473
|
const size = (0, helpers_1.getAlibabaDimensions)(params.resolution, params.aspectRatio);
|
|
231
474
|
if (!size) {
|
|
232
475
|
throw new Error(`Invalid resolution/aspect ratio combination: ${params.resolution} ${params.aspectRatio}`);
|
|
233
476
|
}
|
|
234
477
|
parameters.size = size;
|
|
235
478
|
}
|
|
479
|
+
if (params.audio !== undefined && modelId === "wan2.6-i2v-flash") {
|
|
480
|
+
parameters.audio = params.audio; // silent video is half price
|
|
481
|
+
}
|
|
236
482
|
if (params.seed !== undefined)
|
|
237
483
|
parameters.seed = params.seed;
|
|
238
484
|
if (params.watermark !== undefined)
|
|
239
485
|
parameters.watermark = params.watermark;
|
|
240
|
-
|
|
486
|
+
return this.submitVideo({ model: modelId, input, parameters });
|
|
487
|
+
}
|
|
488
|
+
async submitVideo(body) {
|
|
241
489
|
const result = await this.request(body, "POST", ENDPOINT_VIDEO_ASYNC, true);
|
|
242
490
|
// DashScope returns { output: { task_id, ... } } on async submit.
|
|
243
491
|
const taskId = result?.output?.task_id || result?.request_id;
|
|
@@ -341,7 +589,10 @@ class AlibabaService extends baseAiGenProvider_service_1.BaseAiGenProviderServic
|
|
|
341
589
|
...(params.inputImageUrls ?? []),
|
|
342
590
|
];
|
|
343
591
|
const isEdit = modelId.startsWith("qwen-image-edit") ||
|
|
344
|
-
(refs.length > 0 &&
|
|
592
|
+
(refs.length > 0 &&
|
|
593
|
+
(modelId.startsWith("wan2.7-image") ||
|
|
594
|
+
modelId.startsWith("qwen-image-2") ||
|
|
595
|
+
modelId.startsWith("qwen-image-3")));
|
|
345
596
|
if (isEdit && !refs.length) {
|
|
346
597
|
throw new Error(`${modelId}: edit/reference mode requires at least one input image`);
|
|
347
598
|
}
|
|
@@ -406,6 +657,12 @@ class AlibabaService extends baseAiGenProvider_service_1.BaseAiGenProviderServic
|
|
|
406
657
|
parameters.prompt_extend = params.promptOptimizer;
|
|
407
658
|
if (params.seed !== undefined)
|
|
408
659
|
parameters.seed = params.seed;
|
|
660
|
+
// Qwen-Image 2.x / 3.x return up to 6 images per call. `n` was never sent,
|
|
661
|
+
// so a multi-image request was billed for N and returned one.
|
|
662
|
+
if ((modelId.startsWith("qwen-image-2") || modelId.startsWith("qwen-image-3")) &&
|
|
663
|
+
(params.numImages ?? 1) > 1) {
|
|
664
|
+
parameters.n = Math.min(6, params.numImages);
|
|
665
|
+
}
|
|
409
666
|
// `size` is WIDTH*HEIGHT pixels, never a ratio string — see
|
|
410
667
|
// resolveDashScopeSize. An explicit imageSize (already in pixel form) wins.
|
|
411
668
|
if (params.aspectRatio) {
|
|
@@ -475,11 +732,34 @@ class AlibabaService extends baseAiGenProvider_service_1.BaseAiGenProviderServic
|
|
|
475
732
|
const urls = results.map((r) => r.url).filter((u) => !!u);
|
|
476
733
|
return { urls, taskId };
|
|
477
734
|
}
|
|
478
|
-
getCreditUsed({ modelKey, resolution, aspectRatio, duration, multiClip = false, numImages = 1, creditFloor, }) {
|
|
735
|
+
getCreditUsed({ modelKey, resolution, aspectRatio, duration, multiClip = false, numImages = 1, creditFloor, hasInputVideo, inputVideoDurationSec, audio, numInputImages, }) {
|
|
479
736
|
const modelConfig = aiModels_1.aiModelConfigs[modelKey];
|
|
480
|
-
//
|
|
737
|
+
// Wan 3.0 / HappyHorse — per second by output resolution, plus input
|
|
738
|
+
// video seconds where the model bills them (Wan 3.0 references, video edit).
|
|
739
|
+
const perSecond = modelConfig?.cost?.perSecondByResolution;
|
|
740
|
+
if (perSecond) {
|
|
741
|
+
const res = resolution && resolution.toLowerCase() in perSecond
|
|
742
|
+
? resolution.toLowerCase()
|
|
743
|
+
: String(modelConfig.fields.resolution?.default ?? "");
|
|
744
|
+
const silent = modelConfig.cost?.silentPerSecondByResolution;
|
|
745
|
+
const rate = (audio === false ? silent?.[res] : undefined) ?? perSecond[res];
|
|
746
|
+
if (rate !== undefined) {
|
|
747
|
+
const seconds = duration ?? Number(modelConfig.fields.duration?.default ?? 5);
|
|
748
|
+
const videoInRate = modelConfig.cost?.inputVideoPerSecond?.[res] ?? 0;
|
|
749
|
+
// Some models cap billable input seconds (Wan 2.7 r2v: 5s total).
|
|
750
|
+
const maxIn = typeof modelConfig.cost?.inputVideoBillableMaxSec === "number"
|
|
751
|
+
? modelConfig.cost.inputVideoBillableMaxSec
|
|
752
|
+
: Infinity;
|
|
753
|
+
// const videoIn = hasInputVideo ? videoInRate * (inputVideoDurationSec ?? 0) : 0; // REMOVED FOR v2 — uncapped
|
|
754
|
+
const videoIn = hasInputVideo ? videoInRate * Math.min(inputVideoDurationSec ?? 0, maxIn) : 0;
|
|
755
|
+
return (0, utils_1.getCreditsFromCost)(rate * seconds + videoIn, !multiClip);
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
// Image-gen — flat per-image cost (Kolors / Qwen-Image), plus input
|
|
759
|
+
// images where the model bills them (Qwen-Image 3.0: $0.003 each).
|
|
481
760
|
if (modelConfig?.cost?.fixed !== undefined) {
|
|
482
|
-
|
|
761
|
+
const perInput = typeof modelConfig.cost.perInputImage === "number" ? modelConfig.cost.perInputImage : 0;
|
|
762
|
+
return (0, utils_1.getCreditsFromCost)(modelConfig.cost.fixed * Math.max(1, numImages) + perInput * (numInputImages ?? 0), !multiClip, creditFloor);
|
|
483
763
|
}
|
|
484
764
|
const dimensions = (0, helpers_1.getAlibabaDimensions)(resolution, aspectRatio);
|
|
485
765
|
const cost = modelConfig.cost?.table?.[dimensions]?.[duration];
|
|
@@ -1,11 +1,39 @@
|
|
|
1
1
|
import { BaseAiGenProviderService } from "../baseAiGenProvider.service";
|
|
2
|
-
import { CreditUsageParams, VideoGenerationParams, VideoGenerationResult, VideoStatusParams, VideoStatusResult } from "../types";
|
|
2
|
+
import { CreditUsageParams, ImageGenerationParams, ImageGenerationResult, VideoGenerationParams, VideoGenerationResult, VideoStatusParams, VideoStatusResult } from "../types";
|
|
3
|
+
/**
|
|
4
|
+
* Explicit "WxH" for a ratio at a size tier: tier² pixels in the requested
|
|
5
|
+
* shape, floored to multiples of 16. Every tier's pixel count sits inside the
|
|
6
|
+
* range the models that offer it accept (e.g. 5.0 lite: [2560×1440, 4096²]),
|
|
7
|
+
* and flooring never drops below it, so any ratio in [1/16, 16] is valid —
|
|
8
|
+
* including ones a model's aspect list doesn't name (the agent's 4:5).
|
|
9
|
+
*/
|
|
10
|
+
export declare function seedreamSize(aspectRatio: string, tier: string): string | undefined;
|
|
3
11
|
export declare class ByteDanceService extends BaseAiGenProviderService {
|
|
4
12
|
private readonly baseUrl;
|
|
5
13
|
private sanitizePrompt;
|
|
6
14
|
private isSeedance2;
|
|
7
15
|
generateVideo(params: VideoGenerationParams): Promise<VideoGenerationResult>;
|
|
8
16
|
checkVideoStatus({ task, outputFilename, outputFilePath, }: VideoStatusParams): Promise<VideoStatusResult>;
|
|
17
|
+
/**
|
|
18
|
+
* Seedream text-to-image / image-to-image. Three modes, each gated on the
|
|
19
|
+
* model declaring the field:
|
|
20
|
+
* - default: one request per output image, run in parallel, so numImages
|
|
21
|
+
* is exact.
|
|
22
|
+
* - `imageSet` (5.0 lite / 4.x): one `sequential_image_generation: "auto"`
|
|
23
|
+
* request returning a set of related images, at most numImages (the model
|
|
24
|
+
* picks the count; the worker refunds the unused share).
|
|
25
|
+
* - `layerDecomposition` (5.0 pro / flash): one input image → base image +
|
|
26
|
+
* up to 16 transparent PNG layers, returned with their stacking order and
|
|
27
|
+
* bounding boxes.
|
|
28
|
+
*/
|
|
29
|
+
generateImage(params: ImageGenerationParams): Promise<ImageGenerationResult>;
|
|
30
|
+
/** Copy a layer decomposition's outputs into our storage, base image first. */
|
|
31
|
+
private storeSeedreamLayers;
|
|
32
|
+
/**
|
|
33
|
+
* One /images/generations call → its successful items (failed ones aren't
|
|
34
|
+
* billed) plus `usage.generated_images`, the count BytePlus bills.
|
|
35
|
+
*/
|
|
36
|
+
private requestSeedream;
|
|
9
37
|
getCreditUsed(params: CreditUsageParams): number;
|
|
10
38
|
}
|
|
11
39
|
//# sourceMappingURL=bytedance.service.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bytedance.service.d.ts","sourceRoot":"","sources":["../../../../../src/services/aiGen/providers/bytedance/bytedance.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AACxE,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,qBAAqB,EACrB,iBAAiB,EACjB,iBAAiB,EAClB,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"bytedance.service.d.ts","sourceRoot":"","sources":["../../../../../src/services/aiGen/providers/bytedance/bytedance.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AACxE,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,iBAAiB,EACjB,iBAAiB,EAClB,MAAM,UAAU,CAAC;AA6BlB;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAQlF;AAsBD,qBAAa,gBAAiB,SAAQ,wBAAwB;IAC5D,OAAO,CAAC,QAAQ,CAAC,OAAO,CACsD;IAQ9E,OAAO,CAAC,cAAc;IAYtB,OAAO,CAAC,WAAW;IAIb,aAAa,CACjB,MAAM,EAAE,qBAAqB,GAC5B,OAAO,CAAC,qBAAqB,CAAC;IAoP3B,gBAAgB,CAAC,EACrB,IAAI,EACJ,cAAc,EACd,cAAyB,GAC1B,EAAE,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAqIjD;;;;;;;;;;;OAWG;IACG,aAAa,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAyIlF,+EAA+E;YACjE,mBAAmB;IAoCjC;;;OAGG;YACW,eAAe;IAgD7B,aAAa,CAAC,MAAM,EAAE,iBAAiB,GAAG,MAAM;CAsFjD"}
|