@sogni-ai/sogni-client 4.0.0-alpha.45 → 4.0.0-alpha.47
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 +21 -0
- package/README.md +32 -27
- package/dist/Projects/createJobRequestMessage.d.ts +2 -1
- package/dist/Projects/createJobRequestMessage.js +29 -27
- package/dist/Projects/createJobRequestMessage.js.map +1 -1
- package/dist/Projects/index.d.ts +4 -2
- package/dist/Projects/index.js +45 -17
- package/dist/Projects/index.js.map +1 -1
- package/dist/Projects/types/ComfySamplerParams.d.ts +0 -28
- package/dist/Projects/types/ComfySamplerParams.js +0 -34
- package/dist/Projects/types/ComfySamplerParams.js.map +1 -1
- package/dist/Projects/types/ModelOptions.d.ts +31 -0
- package/dist/Projects/types/ModelOptions.js +56 -0
- package/dist/Projects/types/ModelOptions.js.map +1 -0
- package/dist/Projects/types/ModelTiersRaw.d.ts +67 -0
- package/dist/Projects/types/ModelTiersRaw.js +15 -0
- package/dist/Projects/types/ModelTiersRaw.js.map +1 -0
- package/dist/Projects/types/index.d.ts +16 -24
- package/dist/Projects/types/index.js +0 -9
- package/dist/Projects/types/index.js.map +1 -1
- package/dist/Projects/{utils.d.ts → utils/index.d.ts} +1 -1
- package/dist/Projects/{utils.js → utils/index.js} +1 -1
- package/dist/Projects/utils/index.js.map +1 -0
- package/dist/Projects/utils/samplers.d.ts +6 -0
- package/dist/Projects/utils/samplers.js +38 -0
- package/dist/Projects/utils/samplers.js.map +1 -0
- package/dist/Projects/utils/scheduler.d.ts +6 -0
- package/dist/Projects/utils/scheduler.js +30 -0
- package/dist/Projects/utils/scheduler.js.map +1 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +1 -6
- package/dist/index.js.map +1 -1
- package/dist/lib/{utils.js → utils/index.js} +1 -1
- package/dist/lib/utils/index.js.map +1 -0
- package/dist/lib/validation.d.ts +16 -11
- package/dist/lib/validation.js +45 -63
- package/dist/lib/validation.js.map +1 -1
- package/package.json +1 -1
- package/src/Projects/createJobRequestMessage.ts +43 -33
- package/src/Projects/index.ts +54 -28
- package/src/Projects/types/ComfySamplerParams.ts +0 -34
- package/src/Projects/types/ModelOptions.ts +92 -0
- package/src/Projects/types/ModelTiersRaw.ts +86 -0
- package/src/Projects/types/index.ts +16 -33
- package/src/Projects/{utils.ts → utils/index.ts} +1 -1
- package/src/Projects/utils/samplers.ts +35 -0
- package/src/Projects/utils/scheduler.ts +27 -0
- package/src/index.ts +1 -26
- package/src/lib/validation.ts +53 -77
- package/dist/Projects/types/ComfySchedulerParams.d.ts +0 -17
- package/dist/Projects/types/ComfySchedulerParams.js +0 -23
- package/dist/Projects/types/ComfySchedulerParams.js.map +0 -1
- package/dist/Projects/types/ForgeSamplerParams.d.ts +0 -27
- package/dist/Projects/types/ForgeSamplerParams.js +0 -39
- package/dist/Projects/types/ForgeSamplerParams.js.map +0 -1
- package/dist/Projects/types/ForgeSchedulerParams.d.ts +0 -17
- package/dist/Projects/types/ForgeSchedulerParams.js +0 -28
- package/dist/Projects/types/ForgeSchedulerParams.js.map +0 -1
- package/dist/Projects/utils.js.map +0 -1
- package/dist/lib/utils.js.map +0 -1
- package/src/Projects/types/ComfySchedulerParams.ts +0 -21
- package/src/Projects/types/ForgeSamplerParams.ts +0 -37
- package/src/Projects/types/ForgeSchedulerParams.ts +0 -26
- /package/dist/lib/{utils.d.ts → utils/index.d.ts} +0 -0
- /package/src/lib/{utils.ts → utils/index.ts} +0 -0
package/dist/lib/validation.js
CHANGED
|
@@ -4,18 +4,12 @@ exports.validateCustomImageSize = validateCustomImageSize;
|
|
|
4
4
|
exports.validateVideoSize = validateVideoSize;
|
|
5
5
|
exports.validateVideoDuration = validateVideoDuration;
|
|
6
6
|
exports.validateNumber = validateNumber;
|
|
7
|
-
exports.validateForgeSampler = validateForgeSampler;
|
|
8
|
-
exports.validateForgeScheduler = validateForgeScheduler;
|
|
9
7
|
exports.validateTeacacheThreshold = validateTeacacheThreshold;
|
|
10
|
-
exports.validateComfySampler = validateComfySampler;
|
|
11
|
-
exports.validateComfyScheduler = validateComfyScheduler;
|
|
12
8
|
exports.isComfyModel = isComfyModel;
|
|
9
|
+
exports.getMaxContextImages = getMaxContextImages;
|
|
13
10
|
exports.validateSampler = validateSampler;
|
|
14
11
|
exports.validateScheduler = validateScheduler;
|
|
15
|
-
const
|
|
16
|
-
const ForgeSchedulerParams_1 = require("../Projects/types/ForgeSchedulerParams");
|
|
17
|
-
const ComfySamplerParams_1 = require("../Projects/types/ComfySamplerParams");
|
|
18
|
-
const ComfySchedulerParams_1 = require("../Projects/types/ComfySchedulerParams");
|
|
12
|
+
const ApiClient_1 = require("../ApiClient");
|
|
19
13
|
function validateCustomImageSize(value) {
|
|
20
14
|
return validateNumber(value, { min: 256, max: 2048, propertyName: 'Width and height' });
|
|
21
15
|
}
|
|
@@ -55,30 +49,6 @@ function validateNumber(value, { min, max, propertyName, defaultValue } = {}) {
|
|
|
55
49
|
}
|
|
56
50
|
return number;
|
|
57
51
|
}
|
|
58
|
-
function validateForgeSampler(value) {
|
|
59
|
-
if (!value) {
|
|
60
|
-
return null;
|
|
61
|
-
}
|
|
62
|
-
if ((0, ForgeSamplerParams_1.isRawForgeSampler)(value)) {
|
|
63
|
-
return value;
|
|
64
|
-
}
|
|
65
|
-
if ((0, ForgeSamplerParams_1.isForgeSampler)(value)) {
|
|
66
|
-
return ForgeSamplerParams_1.SupportedForgeSamplers[value];
|
|
67
|
-
}
|
|
68
|
-
throw new Error(`Invalid sampler: ${value}. Supported options: ${Object.keys(ForgeSamplerParams_1.SupportedForgeSamplers).join(', ')}`);
|
|
69
|
-
}
|
|
70
|
-
function validateForgeScheduler(value) {
|
|
71
|
-
if (!value) {
|
|
72
|
-
return null;
|
|
73
|
-
}
|
|
74
|
-
if ((0, ForgeSchedulerParams_1.isRawForgeScheduler)(value)) {
|
|
75
|
-
return value;
|
|
76
|
-
}
|
|
77
|
-
if ((0, ForgeSchedulerParams_1.isForgeScheduler)(value)) {
|
|
78
|
-
return ForgeSchedulerParams_1.SupportedForgeSchedulers[value];
|
|
79
|
-
}
|
|
80
|
-
throw new Error(`Invalid scheduler: ${value}. Supported options: ${Object.keys(ForgeSchedulerParams_1.SupportedForgeSchedulers).join(', ')}`);
|
|
81
|
-
}
|
|
82
52
|
/**
|
|
83
53
|
* Validate teacacheThreshold for T2V and I2V models.
|
|
84
54
|
* Range: 0.0-1.0. 0.0 = disabled.
|
|
@@ -96,46 +66,58 @@ function validateTeacacheThreshold(value) {
|
|
|
96
66
|
}
|
|
97
67
|
return num;
|
|
98
68
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
*/
|
|
103
|
-
function validateComfySampler(value) {
|
|
104
|
-
if (!value) {
|
|
105
|
-
return undefined;
|
|
106
|
-
}
|
|
107
|
-
if ((0, ComfySamplerParams_1.isComfySampler)(value)) {
|
|
108
|
-
return ComfySamplerParams_1.SupportedComfySamplers[value];
|
|
109
|
-
}
|
|
110
|
-
throw new Error(`Invalid comfySampler: ${value}. Supported options: ${Object.keys(ComfySamplerParams_1.SupportedComfySamplers).join(', ')}`);
|
|
69
|
+
function isComfyModel(modelId) {
|
|
70
|
+
const COMFY_PREFIXES = ['z_image_', 'qwen_image_', 'flux2_', 'wan_'];
|
|
71
|
+
return COMFY_PREFIXES.some((prefix) => modelId.startsWith(prefix));
|
|
111
72
|
}
|
|
112
73
|
/**
|
|
113
|
-
*
|
|
114
|
-
*
|
|
74
|
+
* Get the maximum number of context images supported by a model.
|
|
75
|
+
* - Flux.2 Dev: 6 images
|
|
76
|
+
* - Qwen Image Edit: 3 images
|
|
77
|
+
* - Flux Kontext: 2 images
|
|
78
|
+
* - Default: 3 images
|
|
115
79
|
*/
|
|
116
|
-
function
|
|
117
|
-
if (
|
|
118
|
-
return
|
|
80
|
+
function getMaxContextImages(modelId) {
|
|
81
|
+
if (modelId.startsWith('flux2_')) {
|
|
82
|
+
return 6;
|
|
119
83
|
}
|
|
120
|
-
if (
|
|
121
|
-
return
|
|
84
|
+
if (modelId.startsWith('qwen_image_')) {
|
|
85
|
+
return 3;
|
|
122
86
|
}
|
|
123
|
-
|
|
87
|
+
if (modelId.includes('kontext')) {
|
|
88
|
+
return 2;
|
|
89
|
+
}
|
|
90
|
+
// Default fallback for other models that might support context images
|
|
91
|
+
return 3;
|
|
124
92
|
}
|
|
125
|
-
function
|
|
126
|
-
|
|
127
|
-
|
|
93
|
+
function validateOption(value, options, errorMessage) {
|
|
94
|
+
if (!options.includes(value)) {
|
|
95
|
+
throw new ApiClient_1.ApiError(400, {
|
|
96
|
+
status: 'error',
|
|
97
|
+
errorCode: 0,
|
|
98
|
+
message: errorMessage
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
return value;
|
|
128
102
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
103
|
+
/**
|
|
104
|
+
* Validate sampler value against allowed options.
|
|
105
|
+
* Returns the validated value unchanged - sogni-socket handles normalization.
|
|
106
|
+
*/
|
|
107
|
+
function validateSampler(value, options) {
|
|
108
|
+
if (!options.sampler.allowed.length || !value) {
|
|
109
|
+
return null;
|
|
132
110
|
}
|
|
133
|
-
return
|
|
111
|
+
return validateOption(value, options.sampler.allowed, `Invalid sampler ${value}. Must be one of "${options.sampler.allowed.join('", "')}".`);
|
|
134
112
|
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
113
|
+
/**
|
|
114
|
+
* Validate scheduler value against allowed options.
|
|
115
|
+
* Returns the validated value unchanged - sogni-socket handles normalization.
|
|
116
|
+
*/
|
|
117
|
+
function validateScheduler(value, options) {
|
|
118
|
+
if (!options.scheduler.allowed.length || !value) {
|
|
119
|
+
return null;
|
|
138
120
|
}
|
|
139
|
-
return
|
|
121
|
+
return validateOption(value, options.scheduler.allowed, `Invalid scheduler ${value}. Must be one of "${options.scheduler.allowed.join('", "')}".`);
|
|
140
122
|
}
|
|
141
123
|
//# sourceMappingURL=validation.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validation.js","sourceRoot":"","sources":["../../src/lib/validation.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"validation.js","sourceRoot":"","sources":["../../src/lib/validation.ts"],"names":[],"mappings":";;AAGA,0DAEC;AAMD,8CAEC;AAED,sDAEC;AASD,wCA4BC;AAMD,8DAYC;AAED,oCAGC;AASD,kDAYC;AAiBD,0CASC;AAMD,8CASC;AA3ID,4CAAwC;AAGxC,SAAgB,uBAAuB,CAAC,KAAU;IAChD,OAAO,cAAc,CAAC,KAAK,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,YAAY,EAAE,kBAAkB,EAAE,CAAC,CAAC;AAC1F,CAAC;AAED;;;GAGG;AACH,SAAgB,iBAAiB,CAAC,KAAU,EAAE,YAAgC;IAC5E,OAAO,cAAc,CAAC,KAAK,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,YAAY,EAAE,SAAS,YAAY,EAAE,EAAE,CAAC,CAAC;AACpF,CAAC;AAED,SAAgB,qBAAqB,CAAC,KAAU;IAC9C,OAAO,cAAc,CAAC,KAAK,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,YAAY,EAAE,gBAAgB,EAAE,CAAC,CAAC;AACpF,CAAC;AASD,SAAgB,cAAc,CAC5B,KAAU,EACV,EAAE,GAAG,EAAE,GAAG,EAAE,YAAY,EAAE,YAAY,KAA8B,EAAE;IAEtE,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC7B,MAAM,eAAe,GAAG,YAAY,KAAK,SAAS,CAAC;IACnD,IAAI,YAAY,EAAE,CAAC;QACjB,YAAY,GAAG,OAAO,CAAC;IACzB,CAAC;IACD,IAAI,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;QAClB,IAAI,eAAe,EAAE,CAAC;YACpB,OAAO,YAAY,CAAC;QACtB,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,GAAG,YAAY,0BAA0B,KAAK,EAAE,CAAC,CAAC;IACpE,CAAC;IACD,IAAI,GAAG,KAAK,SAAS,IAAI,MAAM,GAAG,GAAG,EAAE,CAAC;QACtC,IAAI,eAAe,EAAE,CAAC;YACpB,OAAO,YAAY,CAAC;QACtB,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,GAAG,YAAY,0BAA0B,GAAG,SAAS,MAAM,EAAE,CAAC,CAAC;IACjF,CAAC;IACD,IAAI,GAAG,KAAK,SAAS,IAAI,MAAM,GAAG,GAAG,EAAE,CAAC;QACtC,IAAI,eAAe,EAAE,CAAC;YACpB,OAAO,YAAY,CAAC;QACtB,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,GAAG,YAAY,0BAA0B,GAAG,SAAS,MAAM,EAAE,CAAC,CAAC;IACjF,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;GAGG;AACH,SAAgB,yBAAyB,CAAC,KAAc;IACtD,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QAC1C,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC1B,IAAI,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,2CAA2C,KAAK,EAAE,CAAC,CAAC;IACtE,CAAC;IACD,IAAI,GAAG,GAAG,GAAG,IAAI,GAAG,GAAG,GAAG,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,sDAAsD,GAAG,GAAG,CAAC,CAAC;IAChF,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAgB,YAAY,CAAC,OAAe;IAC1C,MAAM,cAAc,GAAG,CAAC,UAAU,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;IACrE,OAAO,cAAc,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;AACrE,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,mBAAmB,CAAC,OAAe;IACjD,IAAI,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QACjC,OAAO,CAAC,CAAC;IACX,CAAC;IACD,IAAI,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;QACtC,OAAO,CAAC,CAAC;IACX,CAAC;IACD,IAAI,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QAChC,OAAO,CAAC,CAAC;IACX,CAAC;IACD,sEAAsE;IACtE,OAAO,CAAC,CAAC;AACX,CAAC;AAED,SAAS,cAAc,CAAc,KAAQ,EAAE,OAAY,EAAE,YAAoB;IAC/E,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,oBAAQ,CAAC,GAAG,EAAE;YACtB,MAAM,EAAE,OAAO;YACf,SAAS,EAAE,CAAC;YACZ,OAAO,EAAE,YAAY;SACtB,CAAC,CAAC;IACL,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;GAGG;AACH,SAAgB,eAAe,CAAC,KAAyB,EAAE,OAAqB;IAC9E,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;QAC9C,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,cAAc,CACnB,KAAK,EACL,OAAO,CAAC,OAAO,CAAC,OAAO,EACvB,mBAAmB,KAAK,qBAAqB,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CACtF,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,SAAgB,iBAAiB,CAAC,KAAyB,EAAE,OAAqB;IAChF,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;QAChD,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,cAAc,CACnB,KAAK,EACL,OAAO,CAAC,SAAS,CAAC,OAAO,EACzB,qBAAqB,KAAK,qBAAqB,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAC1F,CAAC;AACJ,CAAC"}
|
package/package.json
CHANGED
|
@@ -9,17 +9,16 @@ import { ControlNetParams, ControlNetParamsRaw } from './types/ControlNetParams'
|
|
|
9
9
|
import {
|
|
10
10
|
validateNumber,
|
|
11
11
|
validateCustomImageSize,
|
|
12
|
-
validateForgeSampler,
|
|
13
|
-
validateForgeScheduler,
|
|
14
12
|
validateVideoSize,
|
|
15
13
|
validateTeacacheThreshold,
|
|
16
|
-
validateComfySampler,
|
|
17
|
-
validateComfyScheduler,
|
|
18
14
|
isComfyModel,
|
|
19
|
-
validateVideoDuration
|
|
15
|
+
validateVideoDuration,
|
|
16
|
+
validateSampler,
|
|
17
|
+
validateScheduler
|
|
20
18
|
} from '../lib/validation';
|
|
21
19
|
import { getVideoWorkflowType, isVideoModel, VIDEO_WORKFLOW_ASSETS } from './utils';
|
|
22
20
|
import { ApiError } from '../ApiClient';
|
|
21
|
+
import { ImageModelOptions, ModelOptions, VideoModelOptions } from './types/ModelOptions';
|
|
23
22
|
|
|
24
23
|
/**
|
|
25
24
|
* Validate that the provided assets match the workflow requirements.
|
|
@@ -178,7 +177,11 @@ function getControlNet(params: ControlNetParams): ControlNetParamsRaw[] {
|
|
|
178
177
|
return [cn];
|
|
179
178
|
}
|
|
180
179
|
|
|
181
|
-
function applyImageParams(
|
|
180
|
+
function applyImageParams(
|
|
181
|
+
inputKeyframe: Record<string, any>,
|
|
182
|
+
params: ImageProjectParams,
|
|
183
|
+
options: ImageModelOptions
|
|
184
|
+
) {
|
|
182
185
|
const keyFrame: Record<string, any> = {
|
|
183
186
|
...inputKeyframe,
|
|
184
187
|
sizePreset: params.sizePreset,
|
|
@@ -189,23 +192,16 @@ function applyImageParams(inputKeyframe: Record<string, any>, params: ImageProje
|
|
|
189
192
|
hasContextImage5: !!params.contextImages?.[4],
|
|
190
193
|
hasContextImage6: !!params.contextImages?.[5]
|
|
191
194
|
};
|
|
192
|
-
|
|
193
|
-
//
|
|
194
|
-
// legacy models use sampler/scheduler (mapped to scheduler/timeStepSpacing)
|
|
195
|
+
// Sampler/scheduler handling: SDK validates and passes through as-is.
|
|
196
|
+
// sogni-socket normalizes values for both ComfyUI and Forge workers.
|
|
195
197
|
if (isComfyModel(params.modelId)) {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
if (params.scheduler !== undefined) {
|
|
200
|
-
keyFrame.comfyScheduler = validateComfyScheduler(params.scheduler);
|
|
201
|
-
}
|
|
198
|
+
// ComfyUI models use comfySampler/comfyScheduler fields
|
|
199
|
+
keyFrame.comfySampler = validateSampler(params.sampler, options);
|
|
200
|
+
keyFrame.comfyScheduler = validateScheduler(params.scheduler, options);
|
|
202
201
|
} else {
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
if (params.scheduler !== undefined) {
|
|
207
|
-
keyFrame.timeStepSpacing = validateForgeScheduler(params.scheduler);
|
|
208
|
-
}
|
|
202
|
+
// Legacy Forge models use scheduler/timeStepSpacing fields
|
|
203
|
+
keyFrame.scheduler = validateSampler(params.sampler, options);
|
|
204
|
+
keyFrame.timeStepSpacing = validateScheduler(params.scheduler, options);
|
|
209
205
|
}
|
|
210
206
|
|
|
211
207
|
if (params.startingImage) {
|
|
@@ -232,7 +228,11 @@ function applyImageParams(inputKeyframe: Record<string, any>, params: ImageProje
|
|
|
232
228
|
return keyFrame;
|
|
233
229
|
}
|
|
234
230
|
|
|
235
|
-
function applyVideoParams(
|
|
231
|
+
function applyVideoParams(
|
|
232
|
+
inputKeyframe: Record<string, any>,
|
|
233
|
+
params: VideoProjectParams,
|
|
234
|
+
options: VideoModelOptions
|
|
235
|
+
) {
|
|
236
236
|
if (!isVideoModel(params.modelId)) {
|
|
237
237
|
throw new ApiError(400, {
|
|
238
238
|
status: 'error',
|
|
@@ -295,19 +295,13 @@ function applyVideoParams(inputKeyframe: Record<string, any>, params: VideoProje
|
|
|
295
295
|
keyFrame.height = validateVideoSize(params.height, 'height');
|
|
296
296
|
}
|
|
297
297
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
if (params.sampler !== undefined) {
|
|
301
|
-
keyFrame.comfySampler = validateComfySampler(params.sampler);
|
|
302
|
-
}
|
|
303
|
-
if (params.scheduler !== undefined) {
|
|
304
|
-
keyFrame.comfyScheduler = validateComfyScheduler(params.scheduler);
|
|
305
|
-
}
|
|
298
|
+
keyFrame.comfySampler = validateSampler(params.sampler, options);
|
|
299
|
+
keyFrame.comfyScheduler = validateScheduler(params.scheduler, options);
|
|
306
300
|
|
|
307
301
|
return keyFrame;
|
|
308
302
|
}
|
|
309
303
|
|
|
310
|
-
function createJobRequestMessage(id: string, params: ProjectParams) {
|
|
304
|
+
function createJobRequestMessage(id: string, params: ProjectParams, options: ModelOptions) {
|
|
311
305
|
const template = getTemplate();
|
|
312
306
|
// Base keyFrame with common params
|
|
313
307
|
let keyFrame: Record<string, any> = {
|
|
@@ -323,10 +317,26 @@ function createJobRequestMessage(id: string, params: ProjectParams) {
|
|
|
323
317
|
|
|
324
318
|
switch (params.type) {
|
|
325
319
|
case 'image':
|
|
326
|
-
|
|
320
|
+
if (options.type !== 'image') {
|
|
321
|
+
throw new ApiError(400, {
|
|
322
|
+
status: 'error',
|
|
323
|
+
errorCode: 0,
|
|
324
|
+
message:
|
|
325
|
+
'Invalid model type. Model does not support image generation. Please use a different model.'
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
keyFrame = applyImageParams(keyFrame, params, options);
|
|
327
329
|
break;
|
|
328
330
|
case 'video':
|
|
329
|
-
|
|
331
|
+
if (options.type !== 'video') {
|
|
332
|
+
throw new ApiError(400, {
|
|
333
|
+
status: 'error',
|
|
334
|
+
errorCode: 0,
|
|
335
|
+
message:
|
|
336
|
+
'Invalid model type. Model does not support video generation. Please use a different model.'
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
keyFrame = applyVideoParams(keyFrame, params, options);
|
|
330
340
|
break;
|
|
331
341
|
default:
|
|
332
342
|
throw new ApiError(400, {
|
package/src/Projects/index.ts
CHANGED
|
@@ -11,15 +11,7 @@ import {
|
|
|
11
11
|
SupportedModel,
|
|
12
12
|
ImageProjectParams,
|
|
13
13
|
VideoProjectParams,
|
|
14
|
-
VideoEstimateRequest
|
|
15
|
-
SupportedComfySamplers,
|
|
16
|
-
SupportedForgeSamplers,
|
|
17
|
-
SupportedComfySchedulers,
|
|
18
|
-
SupportedForgeSchedulers,
|
|
19
|
-
ComfyScheduler,
|
|
20
|
-
ForgeScheduler,
|
|
21
|
-
ComfySampler,
|
|
22
|
-
ForgeSampler
|
|
14
|
+
VideoEstimateRequest
|
|
23
15
|
} from './types';
|
|
24
16
|
import {
|
|
25
17
|
JobErrorData,
|
|
@@ -47,7 +39,9 @@ import {
|
|
|
47
39
|
VIDEO_WORKFLOW_ASSETS
|
|
48
40
|
} from './utils';
|
|
49
41
|
import { TokenType } from '../types/token';
|
|
50
|
-
import {
|
|
42
|
+
import { getMaxContextImages, validateSampler } from '../lib/validation';
|
|
43
|
+
import ModelTiersRaw, { isComfyImageTier, isImageTier, isVideoTier } from './types/ModelTiersRaw';
|
|
44
|
+
import { mapComfyImageTier, mapImageTier, mapVideoTier, ModelOptions } from './types/ModelOptions';
|
|
51
45
|
|
|
52
46
|
const sizePresetCache = new Cache<SizePreset[]>(10 * 60 * 1000);
|
|
53
47
|
const GARBAGE_COLLECT_TIMEOUT = 30000;
|
|
@@ -106,6 +100,13 @@ class ProjectsApi extends ApiGroup<ProjectApiEvents> {
|
|
|
106
100
|
data: null,
|
|
107
101
|
updatedAt: new Date(0)
|
|
108
102
|
};
|
|
103
|
+
private _modelTiers: {
|
|
104
|
+
data: ModelTiersRaw;
|
|
105
|
+
updatedAt: Date;
|
|
106
|
+
} = {
|
|
107
|
+
data: {},
|
|
108
|
+
updatedAt: new Date(0)
|
|
109
|
+
};
|
|
109
110
|
|
|
110
111
|
get availableModels() {
|
|
111
112
|
return this._availableModels;
|
|
@@ -524,7 +525,8 @@ class ProjectsApi extends ApiGroup<ProjectApiEvents> {
|
|
|
524
525
|
*/
|
|
525
526
|
async create(data: ProjectParams): Promise<Project> {
|
|
526
527
|
const project = new Project({ ...data }, { api: this, logger: this.client.logger });
|
|
527
|
-
const
|
|
528
|
+
const modelOptions = await this.getModelOptions(data.modelId);
|
|
529
|
+
const request = createJobRequestMessage(project.id, data, modelOptions);
|
|
528
530
|
|
|
529
531
|
switch (data.type) {
|
|
530
532
|
case 'image':
|
|
@@ -550,19 +552,20 @@ class ProjectsApi extends ApiGroup<ProjectApiEvents> {
|
|
|
550
552
|
await this.uploadCNImage(project.id, data.controlNet.image);
|
|
551
553
|
}
|
|
552
554
|
|
|
553
|
-
// Context images (Flux.2 Dev
|
|
555
|
+
// Context images (Flux.2 Dev supports up to 6; Qwen Image Edit Plus supports up to 3; Flux Kontext supports up to 2)
|
|
554
556
|
if (data.contextImages?.length) {
|
|
555
|
-
|
|
557
|
+
const maxContextImages = getMaxContextImages(data.modelId);
|
|
558
|
+
if (data.contextImages.length > maxContextImages) {
|
|
556
559
|
throw new ApiError(500, {
|
|
557
560
|
status: 'error',
|
|
558
561
|
errorCode: 0,
|
|
559
|
-
message: `Up to
|
|
562
|
+
message: `Up to ${maxContextImages} context images are supported for this model`
|
|
560
563
|
});
|
|
561
564
|
}
|
|
562
565
|
await Promise.all(
|
|
563
566
|
data.contextImages.map((image, index) => {
|
|
564
567
|
if (image && image !== true) {
|
|
565
|
-
return this.uploadContextImage(project.id, index as 0 | 1 | 2, image);
|
|
568
|
+
return this.uploadContextImage(project.id, index as 0 | 1 | 2 | 3 | 4 | 5, image);
|
|
566
569
|
}
|
|
567
570
|
})
|
|
568
571
|
);
|
|
@@ -672,11 +675,11 @@ class ProjectsApi extends ApiGroup<ProjectApiEvents> {
|
|
|
672
675
|
|
|
673
676
|
private async uploadContextImage(
|
|
674
677
|
projectId: string,
|
|
675
|
-
index: 0 | 1 | 2,
|
|
678
|
+
index: 0 | 1 | 2 | 3 | 4 | 5,
|
|
676
679
|
file: File | Buffer | Blob
|
|
677
680
|
) {
|
|
678
681
|
const imageId = getUUID();
|
|
679
|
-
const imageIndex = (index + 1) as 1 | 2 | 3;
|
|
682
|
+
const imageIndex = (index + 1) as 1 | 2 | 3 | 4 | 5 | 6;
|
|
680
683
|
const presignedUrl = await this.uploadUrl({
|
|
681
684
|
imageId,
|
|
682
685
|
jobId: projectId,
|
|
@@ -833,6 +836,7 @@ class ProjectsApi extends ApiGroup<ProjectApiEvents> {
|
|
|
833
836
|
contextImages
|
|
834
837
|
}: EstimateRequest): Promise<CostEstimation> {
|
|
835
838
|
let apiVersion = 2;
|
|
839
|
+
const modelOptions = await this.getModelOptions(model);
|
|
836
840
|
const pathParams = [
|
|
837
841
|
tokenType || 'spark',
|
|
838
842
|
network,
|
|
@@ -858,7 +862,7 @@ class ProjectsApi extends ApiGroup<ProjectApiEvents> {
|
|
|
858
862
|
if (sampler) {
|
|
859
863
|
apiVersion = 3;
|
|
860
864
|
pathParams.push(guidance || 0);
|
|
861
|
-
pathParams.push(validateSampler(
|
|
865
|
+
pathParams.push(validateSampler(sampler, modelOptions)!);
|
|
862
866
|
pathParams.push(contextImages || 0);
|
|
863
867
|
}
|
|
864
868
|
const r = await this.client.socket.get<EstimationResponse>(
|
|
@@ -1005,6 +1009,19 @@ class ProjectsApi extends ApiGroup<ProjectApiEvents> {
|
|
|
1005
1009
|
return models;
|
|
1006
1010
|
}
|
|
1007
1011
|
|
|
1012
|
+
private async _getModelTiers(forceRefresh = false) {
|
|
1013
|
+
if (
|
|
1014
|
+
this._modelTiers.data &&
|
|
1015
|
+
!forceRefresh &&
|
|
1016
|
+
Date.now() - this._modelTiers.updatedAt.getTime() < MODELS_REFRESH_INTERVAL
|
|
1017
|
+
) {
|
|
1018
|
+
return this._modelTiers.data;
|
|
1019
|
+
}
|
|
1020
|
+
const tiers = await this.client.socket.get<ModelTiersRaw>(`/api/v2/models/tiers`);
|
|
1021
|
+
this._modelTiers = { data: tiers, updatedAt: new Date() };
|
|
1022
|
+
return tiers;
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1008
1025
|
/**
|
|
1009
1026
|
* Get supported size presets for the model and network. Size presets are cached for 10 minutes.
|
|
1010
1027
|
*
|
|
@@ -1104,18 +1121,27 @@ class ProjectsApi extends ApiGroup<ProjectApiEvents> {
|
|
|
1104
1121
|
});
|
|
1105
1122
|
}
|
|
1106
1123
|
|
|
1107
|
-
async
|
|
1108
|
-
|
|
1109
|
-
|
|
1124
|
+
async getModelOptions(modelId: string): Promise<ModelOptions> {
|
|
1125
|
+
const models = await this.getSupportedModels();
|
|
1126
|
+
const tiers = await this._getModelTiers();
|
|
1127
|
+
const model = models.find((m) => m.id === modelId);
|
|
1128
|
+
if (!model) {
|
|
1129
|
+
throw new Error(`Model ${modelId} not supported`);
|
|
1110
1130
|
}
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
if (
|
|
1116
|
-
return
|
|
1131
|
+
const tier = tiers[model.tier];
|
|
1132
|
+
if (!tier) {
|
|
1133
|
+
throw new Error(`Unable to find model tier "${model.tier}" please contact support`);
|
|
1134
|
+
}
|
|
1135
|
+
if (isImageTier(tier)) {
|
|
1136
|
+
return mapImageTier(tier);
|
|
1137
|
+
}
|
|
1138
|
+
if (isVideoTier(tier)) {
|
|
1139
|
+
return mapVideoTier(tier);
|
|
1140
|
+
}
|
|
1141
|
+
if (isComfyImageTier(tier)) {
|
|
1142
|
+
return mapComfyImageTier(tier);
|
|
1117
1143
|
}
|
|
1118
|
-
|
|
1144
|
+
throw new Error(`Unsupported model tier "${model.tier}"`);
|
|
1119
1145
|
}
|
|
1120
1146
|
}
|
|
1121
1147
|
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ComfyUI sampler parameters for video models and ComfyUI-based image models.
|
|
3
|
-
* These use lowercase underscore format directly matching ComfyUI's internal names.
|
|
4
|
-
*/
|
|
5
|
-
export const SupportedComfySamplers = {
|
|
6
|
-
euler: 'euler',
|
|
7
|
-
euler_ancestral: 'euler_ancestral',
|
|
8
|
-
heun: 'heun',
|
|
9
|
-
dpmpp_2m: 'dpmpp_2m',
|
|
10
|
-
dpmpp_2m_sde: 'dpmpp_2m_sde',
|
|
11
|
-
dpmpp_sde: 'dpmpp_sde',
|
|
12
|
-
dpmpp_3m_sde: 'dpmpp_3m_sde',
|
|
13
|
-
uni_pc: 'uni_pc',
|
|
14
|
-
lcm: 'lcm',
|
|
15
|
-
// Additional ComfyUI samplers
|
|
16
|
-
lms: 'lms',
|
|
17
|
-
dpm_2: 'dpm_2',
|
|
18
|
-
dpm_2_ancestral: 'dpm_2_ancestral',
|
|
19
|
-
dpm_fast: 'dpm_fast',
|
|
20
|
-
dpm_adaptive: 'dpm_adaptive',
|
|
21
|
-
dpmpp_2s_ancestral: 'dpmpp_2s_ancestral',
|
|
22
|
-
ddpm: 'ddpm',
|
|
23
|
-
ddim: 'ddim',
|
|
24
|
-
uni_pc_bh2: 'uni_pc_bh2',
|
|
25
|
-
// Z-Image specific samplers
|
|
26
|
-
res_multistep: 'res_multistep',
|
|
27
|
-
res_multistep_cfg_pp: 'res_multistep_cfg_pp'
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
export function isComfySampler(sampler: string): sampler is ComfySampler {
|
|
31
|
-
return sampler in SupportedComfySamplers;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export type ComfySampler = keyof typeof SupportedComfySamplers;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { ComfyImageTier, ImageTier, NumericDefaults, VideoTier } from './ModelTiersRaw';
|
|
2
|
+
import { samplerValueToAlias } from '../utils/samplers';
|
|
3
|
+
import { schedulerValueToAlias } from '../utils/scheduler';
|
|
4
|
+
|
|
5
|
+
interface NumRange {
|
|
6
|
+
min: number;
|
|
7
|
+
max: number;
|
|
8
|
+
step: number;
|
|
9
|
+
default: number;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
interface Options<T> {
|
|
13
|
+
allowed: T[];
|
|
14
|
+
default: T | null;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface NumOptions {
|
|
18
|
+
options: number[];
|
|
19
|
+
default: number;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface ImageModelOptions {
|
|
23
|
+
type: 'image';
|
|
24
|
+
steps: NumRange;
|
|
25
|
+
guidance: NumRange;
|
|
26
|
+
scheduler: Options<string>;
|
|
27
|
+
sampler: Options<string>;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface VideoModelOptions {
|
|
31
|
+
type: 'video';
|
|
32
|
+
steps: NumRange;
|
|
33
|
+
guidance: NumRange;
|
|
34
|
+
fps: Options<number>;
|
|
35
|
+
sampler: Options<string>;
|
|
36
|
+
scheduler: Options<string>;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export type ModelOptions = ImageModelOptions | VideoModelOptions;
|
|
40
|
+
|
|
41
|
+
function mapRange(data: NumericDefaults): NumRange {
|
|
42
|
+
return {
|
|
43
|
+
min: data.min,
|
|
44
|
+
max: data.max,
|
|
45
|
+
step: data.decimals ? Math.pow(10, 0 - data.decimals) : data.step || 1,
|
|
46
|
+
default: data.default
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function mapOptions<T>(data: Options<T> | undefined, mapper = (value: T) => value): Options<T> {
|
|
51
|
+
if (!data) {
|
|
52
|
+
return {
|
|
53
|
+
allowed: [],
|
|
54
|
+
default: null
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
allowed: data.allowed.map(mapper),
|
|
59
|
+
default: data.default !== null ? mapper(data.default) : null
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function mapImageTier(tier: ImageTier): ImageModelOptions {
|
|
64
|
+
return {
|
|
65
|
+
type: 'image',
|
|
66
|
+
steps: mapRange(tier.steps),
|
|
67
|
+
guidance: mapRange(tier.guidance),
|
|
68
|
+
scheduler: mapOptions(tier.scheduler, schedulerValueToAlias),
|
|
69
|
+
sampler: mapOptions(tier.sampler, samplerValueToAlias)
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function mapComfyImageTier(tier: ComfyImageTier): ImageModelOptions {
|
|
74
|
+
return {
|
|
75
|
+
type: 'image',
|
|
76
|
+
steps: mapRange(tier.steps),
|
|
77
|
+
guidance: mapRange(tier.guidance),
|
|
78
|
+
scheduler: mapOptions(tier.comfyScheduler, schedulerValueToAlias),
|
|
79
|
+
sampler: mapOptions(tier.comfySampler, samplerValueToAlias)
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function mapVideoTier(tier: VideoTier): VideoModelOptions {
|
|
84
|
+
return {
|
|
85
|
+
type: 'video',
|
|
86
|
+
steps: mapRange(tier.steps),
|
|
87
|
+
guidance: mapRange(tier.guidance),
|
|
88
|
+
scheduler: mapOptions(tier.comfyScheduler, schedulerValueToAlias),
|
|
89
|
+
sampler: mapOptions(tier.comfySampler, samplerValueToAlias),
|
|
90
|
+
fps: tier.fps
|
|
91
|
+
};
|
|
92
|
+
}
|