@scenario-labs/sdk 2.0.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +40 -0
- package/api-promise.d.mts +1 -0
- package/api-promise.d.mts.map +1 -1
- package/api-promise.d.ts +1 -0
- package/api-promise.d.ts.map +1 -1
- package/api-promise.mjs +1 -0
- package/api-promise.mjs.map +1 -1
- package/client.d.mts.map +1 -1
- package/client.d.ts.map +1 -1
- package/client.mjs.map +1 -1
- package/core/api-promise.d.mts.map +1 -1
- package/core/api-promise.d.ts.map +1 -1
- package/core/api-promise.mjs.map +1 -1
- package/core/error.mjs.map +1 -1
- package/core/pagination.d.mts.map +1 -1
- package/core/pagination.d.ts.map +1 -1
- package/core/pagination.mjs.map +1 -1
- package/core/resource.d.mts.map +1 -1
- package/core/resource.d.ts.map +1 -1
- package/core/uploads.d.mts.map +1 -1
- package/core/uploads.d.ts.map +1 -1
- package/core/uploads.mjs.map +1 -1
- package/error.d.mts +1 -0
- package/error.d.mts.map +1 -1
- package/error.d.ts +1 -0
- package/error.d.ts.map +1 -1
- package/error.mjs +1 -0
- package/error.mjs.map +1 -1
- package/index.d.mts +1 -1
- package/index.d.mts.map +1 -1
- package/index.d.ts +1 -1
- package/index.d.ts.map +1 -1
- package/index.js +6 -1
- package/index.js.map +1 -1
- package/index.mjs +1 -1
- package/index.mjs.map +1 -1
- package/internal/detect-platform.mjs.map +1 -1
- package/internal/headers.mjs.map +1 -1
- package/internal/parse.d.mts.map +1 -1
- package/internal/parse.d.ts.map +1 -1
- package/internal/parse.mjs.map +1 -1
- package/internal/qs/formats.d.mts.map +1 -1
- package/internal/qs/formats.d.ts.map +1 -1
- package/internal/qs/index.d.mts +2 -2
- package/internal/qs/index.d.mts.map +1 -1
- package/internal/qs/index.d.ts +2 -2
- package/internal/qs/index.d.ts.map +1 -1
- package/internal/qs/index.mjs.map +1 -1
- package/internal/qs/stringify.d.mts.map +1 -1
- package/internal/qs/stringify.d.ts.map +1 -1
- package/internal/qs/stringify.mjs.map +1 -1
- package/internal/qs/utils.d.mts.map +1 -1
- package/internal/qs/utils.d.ts.map +1 -1
- package/internal/qs/utils.mjs.map +1 -1
- package/internal/request-options.d.mts.map +1 -1
- package/internal/request-options.d.ts.map +1 -1
- package/internal/shims.d.mts +6 -0
- package/internal/shims.d.mts.map +1 -1
- package/internal/shims.d.ts +6 -0
- package/internal/shims.d.ts.map +1 -1
- package/internal/to-file.d.mts.map +1 -1
- package/internal/to-file.d.ts.map +1 -1
- package/internal/to-file.mjs.map +1 -1
- package/internal/types.d.mts +4 -4
- package/internal/types.d.mts.map +1 -1
- package/internal/types.d.ts +4 -4
- package/internal/types.d.ts.map +1 -1
- package/internal/uploads.d.mts.map +1 -1
- package/internal/uploads.d.ts.map +1 -1
- package/internal/uploads.mjs.map +1 -1
- package/internal/utils/base64.mjs.map +1 -1
- package/internal/utils/log.d.mts.map +1 -1
- package/internal/utils/log.d.ts.map +1 -1
- package/internal/utils/log.mjs.map +1 -1
- package/internal/utils/path.mjs.map +1 -1
- package/internal/utils/query.mjs.map +1 -1
- package/internal/utils/values.mjs.map +1 -1
- package/internal/utils.d.mts.map +1 -1
- package/internal/utils.d.ts.map +1 -1
- package/internal/utils.mjs.map +1 -1
- package/lib/asset.d.mts.map +1 -1
- package/lib/asset.d.ts.map +1 -1
- package/lib/asset.mjs.map +1 -1
- package/lib/generate.d.mts.map +1 -1
- package/lib/generate.d.ts.map +1 -1
- package/lib/generate.mjs.map +1 -1
- package/lib/job.d.mts.map +1 -1
- package/lib/job.d.ts.map +1 -1
- package/lib/job.mjs.map +1 -1
- package/lib/models.d.mts.map +1 -1
- package/lib/models.d.ts.map +1 -1
- package/lib/models.mjs.map +1 -1
- package/lib/scenario.d.mts.map +1 -1
- package/lib/scenario.d.ts.map +1 -1
- package/lib/scenario.mjs.map +1 -1
- package/lib/upload.d.mts.map +1 -1
- package/lib/upload.d.ts.map +1 -1
- package/lib/upload.mjs.map +1 -1
- package/lib/workflow.d.mts.map +1 -1
- package/lib/workflow.d.ts.map +1 -1
- package/lib/workflow.mjs.map +1 -1
- package/lib/workflow_converter.d.mts +58 -2
- package/lib/workflow_converter.d.mts.map +1 -1
- package/lib/workflow_converter.d.ts +58 -2
- package/lib/workflow_converter.d.ts.map +1 -1
- package/lib/workflow_converter.js +350 -35
- package/lib/workflow_converter.js.map +1 -1
- package/lib/workflow_converter.mjs +345 -35
- package/lib/workflow_converter.mjs.map +1 -1
- package/lib/workflow_import_validator.d.mts +1 -1
- package/lib/workflow_import_validator.d.mts.map +1 -1
- package/lib/workflow_import_validator.d.ts +1 -1
- package/lib/workflow_import_validator.d.ts.map +1 -1
- package/lib/workflow_import_validator.js +1 -0
- package/lib/workflow_import_validator.js.map +1 -1
- package/lib/workflow_import_validator.mjs +1 -0
- package/lib/workflow_import_validator.mjs.map +1 -1
- package/package.json +1 -1
- package/pagination.d.mts +1 -0
- package/pagination.d.mts.map +1 -1
- package/pagination.d.ts +1 -0
- package/pagination.d.ts.map +1 -1
- package/pagination.mjs +1 -0
- package/pagination.mjs.map +1 -1
- package/resource.d.mts +1 -0
- package/resource.d.mts.map +1 -1
- package/resource.d.ts +1 -0
- package/resource.d.ts.map +1 -1
- package/resource.mjs +1 -0
- package/resource.mjs.map +1 -1
- package/resources/assets/assets.d.mts +289 -135
- package/resources/assets/assets.d.mts.map +1 -1
- package/resources/assets/assets.d.ts +289 -135
- package/resources/assets/assets.d.ts.map +1 -1
- package/resources/assets/assets.js.map +1 -1
- package/resources/assets/assets.mjs.map +1 -1
- package/resources/assets/download.d.mts.map +1 -1
- package/resources/assets/download.d.ts.map +1 -1
- package/resources/assets/download.mjs.map +1 -1
- package/resources/assets/index.d.mts.map +1 -1
- package/resources/assets/index.d.ts.map +1 -1
- package/resources/assets/index.mjs.map +1 -1
- package/resources/assets.d.mts.map +1 -1
- package/resources/assets.d.ts.map +1 -1
- package/resources/assets.mjs.map +1 -1
- package/resources/collections/assets.d.mts.map +1 -1
- package/resources/collections/assets.d.ts.map +1 -1
- package/resources/collections/assets.mjs.map +1 -1
- package/resources/collections/collections.d.mts.map +1 -1
- package/resources/collections/collections.d.ts.map +1 -1
- package/resources/collections/collections.mjs.map +1 -1
- package/resources/collections/index.d.mts.map +1 -1
- package/resources/collections/index.d.ts.map +1 -1
- package/resources/collections/index.mjs.map +1 -1
- package/resources/collections/models.d.mts.map +1 -1
- package/resources/collections/models.d.ts.map +1 -1
- package/resources/collections/models.mjs.map +1 -1
- package/resources/collections.d.mts.map +1 -1
- package/resources/collections.d.ts.map +1 -1
- package/resources/collections.mjs.map +1 -1
- package/resources/generate.d.mts +86 -48
- package/resources/generate.d.mts.map +1 -1
- package/resources/generate.d.ts +86 -48
- package/resources/generate.d.ts.map +1 -1
- package/resources/generate.mjs.map +1 -1
- package/resources/index.d.mts.map +1 -1
- package/resources/index.d.ts.map +1 -1
- package/resources/index.mjs.map +1 -1
- package/resources/jobs.d.mts +6 -6
- package/resources/jobs.d.mts.map +1 -1
- package/resources/jobs.d.ts +6 -6
- package/resources/jobs.d.ts.map +1 -1
- package/resources/jobs.mjs.map +1 -1
- package/resources/models/description.d.mts +54 -4
- package/resources/models/description.d.mts.map +1 -1
- package/resources/models/description.d.ts +54 -4
- package/resources/models/description.d.ts.map +1 -1
- package/resources/models/description.mjs.map +1 -1
- package/resources/models/examples.d.mts +74 -36
- package/resources/models/examples.d.mts.map +1 -1
- package/resources/models/examples.d.ts +74 -36
- package/resources/models/examples.d.ts.map +1 -1
- package/resources/models/examples.mjs.map +1 -1
- package/resources/models/index.d.mts.map +1 -1
- package/resources/models/index.d.ts.map +1 -1
- package/resources/models/index.mjs.map +1 -1
- package/resources/models/models.d.mts +21 -21
- package/resources/models/models.d.mts.map +1 -1
- package/resources/models/models.d.ts +21 -21
- package/resources/models/models.d.ts.map +1 -1
- package/resources/models/models.js.map +1 -1
- package/resources/models/models.mjs.map +1 -1
- package/resources/models/train.d.mts +8 -8
- package/resources/models/train.d.mts.map +1 -1
- package/resources/models/train.d.ts +8 -8
- package/resources/models/train.d.ts.map +1 -1
- package/resources/models/train.mjs.map +1 -1
- package/resources/models/training-images.d.mts.map +1 -1
- package/resources/models/training-images.d.ts.map +1 -1
- package/resources/models/training-images.mjs.map +1 -1
- package/resources/models.d.mts.map +1 -1
- package/resources/models.d.ts.map +1 -1
- package/resources/models.mjs.map +1 -1
- package/resources/oscu.d.mts.map +1 -1
- package/resources/oscu.d.ts.map +1 -1
- package/resources/oscu.mjs.map +1 -1
- package/resources/pricing/index.d.mts.map +1 -1
- package/resources/pricing/index.d.ts.map +1 -1
- package/resources/pricing/index.mjs.map +1 -1
- package/resources/pricing/oscu.d.mts.map +1 -1
- package/resources/pricing/oscu.d.ts.map +1 -1
- package/resources/pricing/oscu.mjs.map +1 -1
- package/resources/pricing/pricing.d.mts.map +1 -1
- package/resources/pricing/pricing.d.ts.map +1 -1
- package/resources/pricing/pricing.mjs.map +1 -1
- package/resources/pricing.d.mts.map +1 -1
- package/resources/pricing.d.ts.map +1 -1
- package/resources/pricing.mjs.map +1 -1
- package/resources/search.d.mts +6 -0
- package/resources/search.d.mts.map +1 -1
- package/resources/search.d.ts +6 -0
- package/resources/search.d.ts.map +1 -1
- package/resources/search.mjs.map +1 -1
- package/resources/tags.d.mts.map +1 -1
- package/resources/tags.d.ts.map +1 -1
- package/resources/tags.mjs.map +1 -1
- package/resources/uploads.d.mts +4 -4
- package/resources/uploads.d.mts.map +1 -1
- package/resources/uploads.d.ts +4 -4
- package/resources/uploads.d.ts.map +1 -1
- package/resources/uploads.mjs.map +1 -1
- package/resources/usages.d.mts +31 -6
- package/resources/usages.d.mts.map +1 -1
- package/resources/usages.d.ts +31 -6
- package/resources/usages.d.ts.map +1 -1
- package/resources/usages.mjs.map +1 -1
- package/resources/workflows.d.mts +36 -36
- package/resources/workflows.d.mts.map +1 -1
- package/resources/workflows.d.ts +36 -36
- package/resources/workflows.d.ts.map +1 -1
- package/resources/workflows.mjs.map +1 -1
- package/resources.d.mts.map +1 -1
- package/resources.d.ts.map +1 -1
- package/resources.mjs.map +1 -1
- package/src/index.ts +9 -0
- package/src/lib/workflow_converter.ts +487 -28
- package/src/lib/workflow_import_validator.ts +2 -0
- package/src/resources/assets/assets.ts +376 -118
- package/src/resources/generate.ts +106 -44
- package/src/resources/jobs.ts +6 -6
- package/src/resources/models/description.ts +68 -2
- package/src/resources/models/examples.ts +94 -32
- package/src/resources/models/models.ts +21 -14
- package/src/resources/models/train.ts +8 -6
- package/src/resources/search.ts +7 -0
- package/src/resources/uploads.ts +4 -4
- package/src/resources/usages.ts +41 -4
- package/src/resources/workflows.ts +36 -36
- package/src/version.ts +1 -1
- package/uploads.d.mts +1 -0
- package/uploads.d.mts.map +1 -1
- package/uploads.d.ts +1 -0
- package/uploads.d.ts.map +1 -1
- package/uploads.mjs +1 -0
- package/uploads.mjs.map +1 -1
- package/version.d.mts +1 -1
- package/version.d.ts +1 -1
- package/version.js +1 -1
- package/version.mjs +1 -1
|
@@ -2,7 +2,24 @@
|
|
|
2
2
|
// Converts a workflow editor state (nodes + edges) to a flow array suitable for the Scenario API.
|
|
3
3
|
// Ported from fawkes useConvertWorkflowToApp — pure function, no React dependencies.
|
|
4
4
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.ASPECT_RATIO_PRESETS = void 0;
|
|
6
|
+
exports.normalizeAspectRatio = normalizeAspectRatio;
|
|
7
|
+
exports.getAspectRatioModelInputNames = getAspectRatioModelInputNames;
|
|
8
|
+
exports.getAspectRatioBounds = getAspectRatioBounds;
|
|
9
|
+
exports.getDimensionsFromAspectRatio = getDimensionsFromAspectRatio;
|
|
5
10
|
exports.convertWorkflowEditorToFlow = convertWorkflowEditorToFlow;
|
|
11
|
+
const RUNNABLE_TYPES = new Set(['model', 'llm', 'forEach', 'forEachEnd']);
|
|
12
|
+
exports.ASPECT_RATIO_PRESETS = [
|
|
13
|
+
'16:9',
|
|
14
|
+
'3:2',
|
|
15
|
+
'4:3',
|
|
16
|
+
'5:4',
|
|
17
|
+
'1:1',
|
|
18
|
+
'4:5',
|
|
19
|
+
'3:4',
|
|
20
|
+
'2:3',
|
|
21
|
+
'9:16',
|
|
22
|
+
];
|
|
6
23
|
// ---- Utility functions ----
|
|
7
24
|
function nodeIdToFlowId(nodeId) {
|
|
8
25
|
return nodeId.replace(/\s/g, '');
|
|
@@ -33,6 +50,96 @@ function convertValueToList(value) {
|
|
|
33
50
|
function getConditionalInputHandleId(nodeId) {
|
|
34
51
|
return `${nodeId}-source-conditional`;
|
|
35
52
|
}
|
|
53
|
+
function handleTypeIncludes(handleType, value) {
|
|
54
|
+
if (Array.isArray(handleType))
|
|
55
|
+
return handleType.includes(value);
|
|
56
|
+
return handleType === value;
|
|
57
|
+
}
|
|
58
|
+
function parseAspectRatio(aspectRatio) {
|
|
59
|
+
if (!aspectRatio)
|
|
60
|
+
return undefined;
|
|
61
|
+
const [rawWidth, rawHeight] = aspectRatio.split(':');
|
|
62
|
+
const width = Number(rawWidth);
|
|
63
|
+
const height = Number(rawHeight);
|
|
64
|
+
if (!Number.isFinite(width) ||
|
|
65
|
+
!Number.isFinite(height) ||
|
|
66
|
+
width <= 0 ||
|
|
67
|
+
height <= 0 ||
|
|
68
|
+
!Number.isInteger(width) ||
|
|
69
|
+
!Number.isInteger(height)) {
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
return { width, height };
|
|
73
|
+
}
|
|
74
|
+
function getGreatestCommonDivisor(a, b) {
|
|
75
|
+
let x = Math.abs(Math.trunc(a));
|
|
76
|
+
let y = Math.abs(Math.trunc(b));
|
|
77
|
+
while (y) {
|
|
78
|
+
const temp = y;
|
|
79
|
+
y = x % y;
|
|
80
|
+
x = temp;
|
|
81
|
+
}
|
|
82
|
+
return x || 1;
|
|
83
|
+
}
|
|
84
|
+
function makeNumberAMultipleOfX(value, multipleOf) {
|
|
85
|
+
if (multipleOf <= 0)
|
|
86
|
+
return Math.round(value);
|
|
87
|
+
return Math.round(value / multipleOf) * multipleOf;
|
|
88
|
+
}
|
|
89
|
+
function clamp(value, min, max) {
|
|
90
|
+
return Math.min(Math.max(value, min), max);
|
|
91
|
+
}
|
|
92
|
+
function normalizeAspectRatio(aspectRatio) {
|
|
93
|
+
const parsed = parseAspectRatio(aspectRatio);
|
|
94
|
+
if (!parsed)
|
|
95
|
+
return undefined;
|
|
96
|
+
const divisor = getGreatestCommonDivisor(parsed.width, parsed.height);
|
|
97
|
+
return `${parsed.width / divisor}:${parsed.height / divisor}`;
|
|
98
|
+
}
|
|
99
|
+
function getAspectRatioModelInputNames(model) {
|
|
100
|
+
if (!model)
|
|
101
|
+
return {};
|
|
102
|
+
const widthInputName = model.uiConfig?.resolutionComponent?.widthInput ??
|
|
103
|
+
model.inputs?.find((input) => input.name === 'width')?.name;
|
|
104
|
+
const heightInputName = model.uiConfig?.resolutionComponent?.heightInput ??
|
|
105
|
+
model.inputs?.find((input) => input.name === 'height')?.name;
|
|
106
|
+
const aspectRatioInputName = model.inputs?.find((input) => input.name === 'aspectRatio')?.name;
|
|
107
|
+
return { widthInputName, heightInputName, aspectRatioInputName };
|
|
108
|
+
}
|
|
109
|
+
function getAspectRatioBounds(model, { widthInputName, heightInputName }) {
|
|
110
|
+
if (!model || !widthInputName || !heightInputName)
|
|
111
|
+
return undefined;
|
|
112
|
+
const widthInput = model.inputs?.find((input) => input.name === widthInputName);
|
|
113
|
+
const heightInput = model.inputs?.find((input) => input.name === heightInputName);
|
|
114
|
+
const presets = model.uiConfig?.resolutionComponent?.presets;
|
|
115
|
+
const widthPresets = (presets ?? [])
|
|
116
|
+
.map((preset) => preset.width)
|
|
117
|
+
.filter((value) => typeof value === 'number');
|
|
118
|
+
const heightPresets = (presets ?? [])
|
|
119
|
+
.map((preset) => preset.height)
|
|
120
|
+
.filter((value) => typeof value === 'number');
|
|
121
|
+
const multipleOf = widthInput?.step ?? 8;
|
|
122
|
+
return {
|
|
123
|
+
maxWidth: widthInput?.max ?? (widthPresets.length > 0 ? Math.max(...widthPresets) : 2048),
|
|
124
|
+
minWidth: widthInput?.min ?? (widthPresets.length > 0 ? Math.min(...widthPresets) : 64),
|
|
125
|
+
maxHeight: heightInput?.max ?? (heightPresets.length > 0 ? Math.max(...heightPresets) : 2048),
|
|
126
|
+
minHeight: heightInput?.min ?? (heightPresets.length > 0 ? Math.min(...heightPresets) : 64),
|
|
127
|
+
multipleOf,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
function getDimensionsFromAspectRatio(args) {
|
|
131
|
+
const parsed = parseAspectRatio(args.aspectRatio);
|
|
132
|
+
if (!parsed)
|
|
133
|
+
return undefined;
|
|
134
|
+
const ratio = parsed.width / parsed.height;
|
|
135
|
+
let width = ratio >= 1 ? args.bounds.maxWidth : Math.round(args.bounds.maxHeight * ratio);
|
|
136
|
+
let height = ratio >= 1 ? Math.round(args.bounds.maxWidth / ratio) : args.bounds.maxHeight;
|
|
137
|
+
width = makeNumberAMultipleOfX(width, args.bounds.multipleOf);
|
|
138
|
+
height = makeNumberAMultipleOfX(height, args.bounds.multipleOf);
|
|
139
|
+
width = clamp(width, args.bounds.minWidth, args.bounds.maxWidth);
|
|
140
|
+
height = clamp(height, args.bounds.minHeight, args.bounds.maxHeight);
|
|
141
|
+
return { width, height };
|
|
142
|
+
}
|
|
36
143
|
function getForEachFlowListInputDescriptor(args) {
|
|
37
144
|
const { listProvider, outputHandle, inputIndex } = args;
|
|
38
145
|
const isText = listProvider?.type === 'splitText' ||
|
|
@@ -260,11 +367,11 @@ function toStaticInput(name, type, value) {
|
|
|
260
367
|
return undefined;
|
|
261
368
|
return { name, type, value: value };
|
|
262
369
|
}
|
|
263
|
-
function
|
|
370
|
+
function getIsFormArray(value) {
|
|
264
371
|
return (Array.isArray(value) &&
|
|
265
372
|
value.every((item) => typeof item === 'object' && item !== null && !Array.isArray(item)));
|
|
266
373
|
}
|
|
267
|
-
function
|
|
374
|
+
function getIsModelCompose(model) {
|
|
268
375
|
return !!model?.id && (model.tags ?? []).includes('compose');
|
|
269
376
|
}
|
|
270
377
|
function getIsConditionallyExecuted(targetNodeId, nodes, edges) {
|
|
@@ -274,6 +381,87 @@ function getIsConditionallyExecuted(targetNodeId, nodes, edges) {
|
|
|
274
381
|
return (e.source === targetNodeId && e.sourceHandle === conditionalHandleId && sourceNode?.type === 'ifElse');
|
|
275
382
|
});
|
|
276
383
|
}
|
|
384
|
+
function buildDimensionLookupCEL(args) {
|
|
385
|
+
let expression = String(args.fallback);
|
|
386
|
+
for (let i = args.presets.length - 1; i >= 0; i--) {
|
|
387
|
+
const preset = args.presets[i];
|
|
388
|
+
expression = `trim(${args.variable}) == '${preset.aspectRatio}' ? ${preset[args.dimension]} : ${expression}`;
|
|
389
|
+
}
|
|
390
|
+
return expression;
|
|
391
|
+
}
|
|
392
|
+
function applyAspectRatioInputs(args) {
|
|
393
|
+
const modelInputNames = getAspectRatioModelInputNames(args.model);
|
|
394
|
+
const modelBounds = getAspectRatioBounds(args.model, modelInputNames);
|
|
395
|
+
const { widthInputName, heightInputName, aspectRatioInputName } = modelInputNames;
|
|
396
|
+
if (aspectRatioInputName) {
|
|
397
|
+
const transformId = `${args.flowId}_aspectRatio_value`;
|
|
398
|
+
args.flow.push({
|
|
399
|
+
id: transformId,
|
|
400
|
+
type: 'transform',
|
|
401
|
+
logic: { transform: 'trim(aspectRatio)' },
|
|
402
|
+
inputs: [{ name: 'aspectRatio', type: 'string', ref: args.aspectRatioRef }],
|
|
403
|
+
});
|
|
404
|
+
setOrPushFlowInput(args.flowInputs, args.flowInputs.findIndex((inp) => inp.name === aspectRatioInputName), {
|
|
405
|
+
name: aspectRatioInputName,
|
|
406
|
+
type: 'string',
|
|
407
|
+
ref: { node: transformId, name: 'all' },
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
if (widthInputName && heightInputName && modelBounds) {
|
|
411
|
+
const presetDimensions = exports.ASPECT_RATIO_PRESETS.flatMap((preset) => {
|
|
412
|
+
const dims = getDimensionsFromAspectRatio({ aspectRatio: preset, bounds: modelBounds });
|
|
413
|
+
if (!dims)
|
|
414
|
+
return [];
|
|
415
|
+
const normalized = normalizeAspectRatio(preset);
|
|
416
|
+
if (!normalized)
|
|
417
|
+
return [];
|
|
418
|
+
return [{ aspectRatio: normalized, ...dims }];
|
|
419
|
+
});
|
|
420
|
+
const fallbackDimensions = presetDimensions.find((preset) => preset.aspectRatio === '1:1') ??
|
|
421
|
+
presetDimensions[0] ?? {
|
|
422
|
+
width: modelBounds.maxWidth,
|
|
423
|
+
height: modelBounds.maxHeight,
|
|
424
|
+
};
|
|
425
|
+
const widthTransformId = `${args.flowId}_aspectRatio_width`;
|
|
426
|
+
const heightTransformId = `${args.flowId}_aspectRatio_height`;
|
|
427
|
+
args.flow.push({
|
|
428
|
+
id: widthTransformId,
|
|
429
|
+
type: 'transform',
|
|
430
|
+
logic: {
|
|
431
|
+
transform: buildDimensionLookupCEL({
|
|
432
|
+
variable: 'aspectRatio',
|
|
433
|
+
presets: presetDimensions,
|
|
434
|
+
dimension: 'width',
|
|
435
|
+
fallback: fallbackDimensions.width,
|
|
436
|
+
}),
|
|
437
|
+
},
|
|
438
|
+
inputs: [{ name: 'aspectRatio', type: 'string', ref: args.aspectRatioRef }],
|
|
439
|
+
});
|
|
440
|
+
args.flow.push({
|
|
441
|
+
id: heightTransformId,
|
|
442
|
+
type: 'transform',
|
|
443
|
+
logic: {
|
|
444
|
+
transform: buildDimensionLookupCEL({
|
|
445
|
+
variable: 'aspectRatio',
|
|
446
|
+
presets: presetDimensions,
|
|
447
|
+
dimension: 'height',
|
|
448
|
+
fallback: fallbackDimensions.height,
|
|
449
|
+
}),
|
|
450
|
+
},
|
|
451
|
+
inputs: [{ name: 'aspectRatio', type: 'string', ref: args.aspectRatioRef }],
|
|
452
|
+
});
|
|
453
|
+
setOrPushFlowInput(args.flowInputs, args.flowInputs.findIndex((inp) => inp.name === widthInputName), {
|
|
454
|
+
name: widthInputName,
|
|
455
|
+
type: 'number',
|
|
456
|
+
ref: { node: widthTransformId, name: 'all' },
|
|
457
|
+
});
|
|
458
|
+
setOrPushFlowInput(args.flowInputs, args.flowInputs.findIndex((inp) => inp.name === heightInputName), {
|
|
459
|
+
name: heightInputName,
|
|
460
|
+
type: 'number',
|
|
461
|
+
ref: { node: heightTransformId, name: 'all' },
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
}
|
|
277
465
|
function getForEachBodyEditorNodeIds(forEachId, forEachEndId, edges) {
|
|
278
466
|
const bodyNodeIds = new Set();
|
|
279
467
|
const queue = [];
|
|
@@ -325,7 +513,6 @@ function getNodeOutputValue(node, targetHandleId) {
|
|
|
325
513
|
}
|
|
326
514
|
return undefined;
|
|
327
515
|
}
|
|
328
|
-
const RUNNABLE_TYPES = new Set(['model', 'llm', 'forEach', 'forEachEnd']);
|
|
329
516
|
function internalGetConnectedNodes(nodes, edges, startNodeId, direction, isStoppingAtRunnableNodes) {
|
|
330
517
|
const nodesById = new Map(nodes.map((n) => {
|
|
331
518
|
const meta = { id: n.id, type: n.type };
|
|
@@ -365,42 +552,44 @@ function internalGetConnectedNodes(nodes, edges, startNodeId, direction, isStopp
|
|
|
365
552
|
const idSet = new Set(ids);
|
|
366
553
|
return nodes.filter((n) => idSet.has(n.id));
|
|
367
554
|
}
|
|
555
|
+
function resolveIfElseConditionField(field, candidateNodes) {
|
|
556
|
+
const byExactId = candidateNodes.find((n) => n.id === field);
|
|
557
|
+
if (byExactId)
|
|
558
|
+
return { nodeId: field };
|
|
559
|
+
for (const node of candidateNodes) {
|
|
560
|
+
for (const handle of node.data.outputHandles ?? []) {
|
|
561
|
+
if (`${node.id}_${handle.name}` === field) {
|
|
562
|
+
return { nodeId: node.id, targetHandleId: handle.id };
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
return undefined;
|
|
567
|
+
}
|
|
368
568
|
function normalizeNodes(nodes) {
|
|
369
569
|
return nodes.map((node) => {
|
|
370
570
|
if (node.type !== 'model' && node.type !== 'llm')
|
|
371
571
|
return node;
|
|
372
|
-
const hasType = (t, v) => Array.isArray(t) ? t.includes(v) : t === v;
|
|
373
572
|
const inputHandles = (node.data.inputHandles ?? [])
|
|
374
573
|
.flatMap((h) => (h.subHandles ? h.subHandles : [h]))
|
|
375
|
-
.filter((h) =>
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
574
|
+
.filter((h) => handleTypeIncludes(h.type, 'conditional') ||
|
|
575
|
+
handleTypeIncludes(h.type, 'aspectRatio') ||
|
|
576
|
+
handleTypeIncludes(h.type, 'prompt') ||
|
|
577
|
+
handleTypeIncludes(h.type, 'image') ||
|
|
578
|
+
handleTypeIncludes(h.type, 'video') ||
|
|
579
|
+
handleTypeIncludes(h.type, '3d') ||
|
|
580
|
+
handleTypeIncludes(h.type, 'audio') ||
|
|
381
581
|
(node.type === 'llm' && h.name === 'textInputs'));
|
|
382
582
|
return { ...node, data: { ...node.data, inputHandles } };
|
|
383
583
|
});
|
|
384
584
|
}
|
|
385
|
-
// ---- Main function ----
|
|
386
|
-
/**
|
|
387
|
-
* Converts a workflow editor state (nodes, edges, inputKeys) into a flow array
|
|
388
|
-
* ready to be passed to `client.workflows.update({ flow: ... })`.
|
|
389
|
-
*
|
|
390
|
-
* @example
|
|
391
|
-
* ```ts
|
|
392
|
-
* const flow = convertWorkflowEditorToFlow({ nodes, edges, inputKeys, getModel });
|
|
393
|
-
* await client.workflows.update(workflowId, { flow: flow as WorkflowUpdateParams.Flow[] });
|
|
394
|
-
* ```
|
|
395
|
-
*/
|
|
396
585
|
function convertWorkflowEditorToFlow(params) {
|
|
397
586
|
const { edges, inputKeys } = params;
|
|
398
587
|
const nodes = normalizeNodes(params.nodes);
|
|
399
588
|
const inputNodeIds = nodes.filter((n) => !!n.data.isInput).map((n) => n.id);
|
|
400
|
-
const selectedOutputNodes = nodes.filter((n) => (n.type === 'model' || n.type === 'forEachEnd') && !!n.data.isOutput);
|
|
589
|
+
const selectedOutputNodes = nodes.filter((n) => (n.type === 'model' || n.type === 'forEachEnd' || n.type === 'llm') && !!n.data.isOutput);
|
|
401
590
|
const selectedOutputNodeIds = selectedOutputNodes.map((n) => n.id);
|
|
402
591
|
const selectedOutputModelNodeIds = new Set(selectedOutputNodes
|
|
403
|
-
.filter((n) => n.type === 'model')
|
|
592
|
+
.filter((n) => n.type === 'model' || n.type === 'llm')
|
|
404
593
|
.map((n) => n.id));
|
|
405
594
|
// Collect all nodes in branches that lead to selected outputs
|
|
406
595
|
const nodesInSelectedBranches = new Set();
|
|
@@ -434,6 +623,12 @@ function convertWorkflowEditorToFlow(params) {
|
|
|
434
623
|
.filter((n) => !inputNodeIds.includes(n.id) && n.type !== 'forEachEnd')
|
|
435
624
|
.map((n) => [n.id, nodeIdToFlowId(n.id)]));
|
|
436
625
|
const nodeIdToInputNameMap = new Map(inputNodeIds.map((id) => [id, nodeIdToFlowId(id)]));
|
|
626
|
+
const approvalByApprovedNodeId = buildApprovalByApprovedNodeIdMap({
|
|
627
|
+
nodes,
|
|
628
|
+
edges,
|
|
629
|
+
nodesInSelectedBranches,
|
|
630
|
+
selectedOutputNodeIds,
|
|
631
|
+
});
|
|
437
632
|
const nodeHandleTransformMap = new Map();
|
|
438
633
|
const ctx = {
|
|
439
634
|
nodes,
|
|
@@ -507,6 +702,7 @@ function convertWorkflowEditorToFlow(params) {
|
|
|
507
702
|
const model = remoteModel === 'unknown' ? undefined : remoteModel;
|
|
508
703
|
const modelInputs = model?.inputs;
|
|
509
704
|
const conditionalHandleId = getConditionalInputHandleId(node.id);
|
|
705
|
+
const aspectRatioEdges = [];
|
|
510
706
|
const edgesByInput = new Map();
|
|
511
707
|
for (const edge of incomingEdges) {
|
|
512
708
|
if (edge.sourceHandle === conditionalHandleId)
|
|
@@ -514,6 +710,10 @@ function convertWorkflowEditorToFlow(params) {
|
|
|
514
710
|
const handle = getInputHandle(edge, node.data.inputHandles);
|
|
515
711
|
if (!handle?.name)
|
|
516
712
|
continue;
|
|
713
|
+
if (handleTypeIncludes(handle.type, 'aspectRatio')) {
|
|
714
|
+
aspectRatioEdges.push(edge);
|
|
715
|
+
continue;
|
|
716
|
+
}
|
|
517
717
|
const existing = edgesByInput.get(handle.name);
|
|
518
718
|
if (existing)
|
|
519
719
|
existing.push(edge);
|
|
@@ -526,7 +726,7 @@ function convertWorkflowEditorToFlow(params) {
|
|
|
526
726
|
continue;
|
|
527
727
|
const modelInput = modelInputs?.find((inp) => inp.name === key);
|
|
528
728
|
if (modelInput?.type === 'inputs_array') {
|
|
529
|
-
if (!
|
|
729
|
+
if (!getIsFormArray(value))
|
|
530
730
|
continue;
|
|
531
731
|
const nestedInputs = modelInput.inputs ?? [];
|
|
532
732
|
const items = [];
|
|
@@ -547,7 +747,7 @@ function convertWorkflowEditorToFlow(params) {
|
|
|
547
747
|
itemInputs.push(inp);
|
|
548
748
|
}
|
|
549
749
|
}
|
|
550
|
-
const isValid =
|
|
750
|
+
const isValid = getIsModelCompose(model) ? getHasComposeLayerSourceInput(itemInputs) : itemInputs.length > 0;
|
|
551
751
|
if (isValid)
|
|
552
752
|
items.push(itemInputs);
|
|
553
753
|
}
|
|
@@ -565,6 +765,18 @@ function convertWorkflowEditorToFlow(params) {
|
|
|
565
765
|
}
|
|
566
766
|
}
|
|
567
767
|
}
|
|
768
|
+
if (aspectRatioEdges.length > 0 && model) {
|
|
769
|
+
const aspectRatioRef = getSourceRef(aspectRatioEdges[0], ctx);
|
|
770
|
+
if (aspectRatioRef) {
|
|
771
|
+
applyAspectRatioInputs({
|
|
772
|
+
flow,
|
|
773
|
+
flowInputs,
|
|
774
|
+
flowId,
|
|
775
|
+
aspectRatioRef,
|
|
776
|
+
model,
|
|
777
|
+
});
|
|
778
|
+
}
|
|
779
|
+
}
|
|
568
780
|
for (const [inputName, inputEdges] of edgesByInput) {
|
|
569
781
|
const existingIndex = flowInputs.findIndex((inp) => inp.name === inputName);
|
|
570
782
|
const modelInput = modelInputs?.find((inp) => inp.name === inputName);
|
|
@@ -625,7 +837,7 @@ function convertWorkflowEditorToFlow(params) {
|
|
|
625
837
|
const isArr = targetInputType === 'file_array';
|
|
626
838
|
const isRequired = (targetNode?.type === 'asset' &&
|
|
627
839
|
!!targetNode.data.isRequired) ||
|
|
628
|
-
|
|
840
|
+
getIsModelCompose(model);
|
|
629
841
|
transformVariables.push({ name: targetNodeKey, isArray: isArr, isRequired });
|
|
630
842
|
if (!targetNode?.data.isInput &&
|
|
631
843
|
(targetNode?.type === 'asset' || targetNode?.type === 'text')) {
|
|
@@ -696,7 +908,9 @@ function convertWorkflowEditorToFlow(params) {
|
|
|
696
908
|
type: 'custom-model',
|
|
697
909
|
modelId: nodeData.modelId,
|
|
698
910
|
inputs: flowInputs.length > 0 ? flowInputs : undefined,
|
|
699
|
-
includeOutputsInWorkflowJob: node.type === 'model' && selectedOutputModelNodeIds.has(node.id) ?
|
|
911
|
+
includeOutputsInWorkflowJob: (node.type === 'model' || node.type === 'llm') && selectedOutputModelNodeIds.has(node.id) ?
|
|
912
|
+
true
|
|
913
|
+
: undefined,
|
|
700
914
|
});
|
|
701
915
|
ensureInputVideoTransformsAdded();
|
|
702
916
|
if (node.type === 'model' && node.data.type === 'video') {
|
|
@@ -759,6 +973,19 @@ function convertWorkflowEditorToFlow(params) {
|
|
|
759
973
|
addVideoFirstLastFrameTransforms(node.id, flowId, node, edges, flow, nodeHandleTransformMap);
|
|
760
974
|
}
|
|
761
975
|
// ------------------------------------
|
|
976
|
+
// AspectRatio -> transform with ratio literal
|
|
977
|
+
// ------------------------------------
|
|
978
|
+
}
|
|
979
|
+
else if (node.type === 'aspectRatio') {
|
|
980
|
+
const flowInputs = collectConditionalConnectionInputs(incomingEdges, node.id, ctx);
|
|
981
|
+
const value = node.data.output || '1:1';
|
|
982
|
+
flow.push({
|
|
983
|
+
id: flowId,
|
|
984
|
+
type: 'transform',
|
|
985
|
+
logic: { transform: `'${escapeCELString(value)}'` },
|
|
986
|
+
inputs: flowInputs.length > 0 ? flowInputs : undefined,
|
|
987
|
+
});
|
|
988
|
+
// ------------------------------------
|
|
762
989
|
// TransformText -> transform (CEL)
|
|
763
990
|
// ------------------------------------
|
|
764
991
|
}
|
|
@@ -837,7 +1064,7 @@ function convertWorkflowEditorToFlow(params) {
|
|
|
837
1064
|
continue;
|
|
838
1065
|
const outHandle = targetNode.data.outputHandles?.find((h) => h.id === edge.targetHandle);
|
|
839
1066
|
const outHandleName = outHandle?.name ?? 'output';
|
|
840
|
-
const varName =
|
|
1067
|
+
const varName = `${targetNode.id}_${outHandleName}`;
|
|
841
1068
|
const isArr = (targetNode.type === 'asset' && !!targetNode.data.isMultiple) ||
|
|
842
1069
|
targetNode.type === 'groupItems' ||
|
|
843
1070
|
targetNode.type === 'sliceAssets' ||
|
|
@@ -946,17 +1173,47 @@ function convertWorkflowEditorToFlow(params) {
|
|
|
946
1173
|
fieldsUsed.add(condition.field);
|
|
947
1174
|
}
|
|
948
1175
|
}
|
|
949
|
-
|
|
1176
|
+
const edgesIntoIfElse = edges.filter((e) => e.target === node.id);
|
|
1177
|
+
for (const fieldKey of fieldsUsed) {
|
|
1178
|
+
const resolved = resolveIfElseConditionField(fieldKey, nodes);
|
|
1179
|
+
const fieldNodeId = resolved?.nodeId;
|
|
1180
|
+
if (!fieldNodeId)
|
|
1181
|
+
continue;
|
|
1182
|
+
const outputHandleName = resolved?.targetHandleId !== undefined ?
|
|
1183
|
+
nodes
|
|
1184
|
+
.find((n) => n.id === fieldNodeId)
|
|
1185
|
+
?.data.outputHandles?.find((h) => h.id === resolved.targetHandleId)?.name ?? 'output'
|
|
1186
|
+
: 'output';
|
|
1187
|
+
const celVarName = getOutputHandleVarName(fieldNodeId, outputHandleName);
|
|
1188
|
+
nodeIdToInputNameMap.set(fieldKey, celVarName);
|
|
1189
|
+
const edgeToIfElse = edgesIntoIfElse
|
|
1190
|
+
.filter((e) => e.source === fieldNodeId)
|
|
1191
|
+
.find((e) => {
|
|
1192
|
+
if (resolved.targetHandleId === undefined)
|
|
1193
|
+
return true;
|
|
1194
|
+
return e.sourceHandle === resolved.targetHandleId;
|
|
1195
|
+
}) ?? edgesIntoIfElse.find((e) => e.source === fieldNodeId);
|
|
950
1196
|
if (inputNodeIds.includes(fieldNodeId)) {
|
|
951
|
-
const
|
|
952
|
-
if (
|
|
953
|
-
|
|
1197
|
+
const workflowInputName = nodeIdToInputNameMap.get(fieldNodeId);
|
|
1198
|
+
if (workflowInputName) {
|
|
1199
|
+
const ref = edgeToIfElse ?
|
|
1200
|
+
getSourceRef(edgeToIfElse, ctx)
|
|
1201
|
+
: { node: 'workflow', name: workflowInputName };
|
|
1202
|
+
flowInputs.push({
|
|
1203
|
+
name: celVarName,
|
|
1204
|
+
type: 'string',
|
|
1205
|
+
ref: ref ?? { node: 'workflow', name: workflowInputName },
|
|
1206
|
+
});
|
|
1207
|
+
}
|
|
954
1208
|
}
|
|
955
1209
|
else {
|
|
1210
|
+
const refFromEdge = edgeToIfElse ? getSourceRef(edgeToIfElse, ctx) : undefined;
|
|
956
1211
|
const targetFlowId = nodeIdToFlowIdMap.get(fieldNodeId);
|
|
957
|
-
if (
|
|
958
|
-
flowInputs.push({ name:
|
|
959
|
-
|
|
1212
|
+
if (refFromEdge) {
|
|
1213
|
+
flowInputs.push({ name: celVarName, type: 'string', ref: refFromEdge });
|
|
1214
|
+
}
|
|
1215
|
+
else if (targetFlowId) {
|
|
1216
|
+
flowInputs.push({ name: celVarName, type: 'string', ref: { node: targetFlowId, name: 'all' } });
|
|
960
1217
|
}
|
|
961
1218
|
}
|
|
962
1219
|
}
|
|
@@ -990,6 +1247,64 @@ function convertWorkflowEditorToFlow(params) {
|
|
|
990
1247
|
for (const [forEachId, forEachFlowItem] of forEachFlowItemRefs) {
|
|
991
1248
|
forEachFlowItem.loopBodyNodeIds = forEachLoopFlowIds.get(forEachId) ?? [];
|
|
992
1249
|
}
|
|
1250
|
+
applyApprovalsToFlow({ flow, edges, approvalByApprovedNodeId, nodeIdToFlowIdMap });
|
|
993
1251
|
return flow;
|
|
994
1252
|
}
|
|
1253
|
+
function buildApprovalByApprovedNodeIdMap({ nodes, edges, nodesInSelectedBranches, selectedOutputNodeIds, }) {
|
|
1254
|
+
const result = new Map();
|
|
1255
|
+
for (const approvalNode of nodes) {
|
|
1256
|
+
if (approvalNode.type !== 'approval')
|
|
1257
|
+
continue;
|
|
1258
|
+
const approvalEdge = edges.find((e) => e.source === approvalNode.id && e.sourceHandle === `${approvalNode.id}-source-approval`);
|
|
1259
|
+
if (!approvalEdge)
|
|
1260
|
+
continue;
|
|
1261
|
+
const approvedNodeId = approvalEdge.target;
|
|
1262
|
+
if (!nodesInSelectedBranches.has(approvedNodeId) && !selectedOutputNodeIds.includes(approvedNodeId))
|
|
1263
|
+
continue;
|
|
1264
|
+
const approvedNode = nodes.find((n) => n.id === approvedNodeId);
|
|
1265
|
+
if (!approvedNode)
|
|
1266
|
+
continue;
|
|
1267
|
+
const approvedFlowId = approvedNode.type === 'forEachEnd' ?
|
|
1268
|
+
approvedNode.data.parentNodeId ?
|
|
1269
|
+
nodeIdToFlowId(approvedNode.data.parentNodeId)
|
|
1270
|
+
: undefined
|
|
1271
|
+
: nodeIdToFlowId(approvedNodeId);
|
|
1272
|
+
if (!approvedFlowId)
|
|
1273
|
+
continue;
|
|
1274
|
+
result.set(approvedNodeId, {
|
|
1275
|
+
approvalFlowId: nodeIdToFlowId(approvalNode.id),
|
|
1276
|
+
approvedFlowId,
|
|
1277
|
+
message: approvalNode.data.message ?? '',
|
|
1278
|
+
});
|
|
1279
|
+
}
|
|
1280
|
+
return result;
|
|
1281
|
+
}
|
|
1282
|
+
function applyApprovalsToFlow({ flow, edges, approvalByApprovedNodeId, nodeIdToFlowIdMap, }) {
|
|
1283
|
+
if (approvalByApprovedNodeId.size === 0)
|
|
1284
|
+
return;
|
|
1285
|
+
const flowIdToWorkflowNodeId = new Map([...nodeIdToFlowIdMap.entries()].map(([nodeId, flowId]) => [flowId, nodeId]));
|
|
1286
|
+
for (const flowItem of flow) {
|
|
1287
|
+
const workflowNodeId = flowIdToWorkflowNodeId.get(flowItem.id);
|
|
1288
|
+
if (!workflowNodeId)
|
|
1289
|
+
continue;
|
|
1290
|
+
const dependsOn = new Set(flowItem.dependsOn ?? []);
|
|
1291
|
+
const incomingEdges = edges.filter((e) => e.source === workflowNodeId &&
|
|
1292
|
+
!e.data?.isForEachEndEdge);
|
|
1293
|
+
for (const edge of incomingEdges) {
|
|
1294
|
+
const approval = approvalByApprovedNodeId.get(edge.target);
|
|
1295
|
+
if (approval)
|
|
1296
|
+
dependsOn.add(approval.approvalFlowId);
|
|
1297
|
+
}
|
|
1298
|
+
if (dependsOn.size > 0)
|
|
1299
|
+
flowItem.dependsOn = [...dependsOn].sort();
|
|
1300
|
+
}
|
|
1301
|
+
for (const approvalInfo of approvalByApprovedNodeId.values()) {
|
|
1302
|
+
flow.push({
|
|
1303
|
+
id: approvalInfo.approvalFlowId,
|
|
1304
|
+
type: 'user-approval',
|
|
1305
|
+
dependsOn: [approvalInfo.approvedFlowId],
|
|
1306
|
+
label: approvalInfo.message,
|
|
1307
|
+
});
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
995
1310
|
//# sourceMappingURL=workflow_converter.js.map
|