@sogni-ai/sogni-client 4.0.0-alpha.9 → 4.0.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.
Files changed (95) hide show
  1. package/CHANGELOG.md +268 -0
  2. package/README.md +262 -27
  3. package/dist/Account/index.d.ts +18 -16
  4. package/dist/Account/index.js +31 -20
  5. package/dist/Account/index.js.map +1 -1
  6. package/dist/ApiClient/WebSocketClient/BrowserWebSocketClient/ChannelCoordinator.d.ts +66 -0
  7. package/dist/ApiClient/WebSocketClient/BrowserWebSocketClient/ChannelCoordinator.js +332 -0
  8. package/dist/ApiClient/WebSocketClient/BrowserWebSocketClient/ChannelCoordinator.js.map +1 -0
  9. package/dist/ApiClient/WebSocketClient/BrowserWebSocketClient/index.d.ts +28 -0
  10. package/dist/ApiClient/WebSocketClient/BrowserWebSocketClient/index.js +203 -0
  11. package/dist/ApiClient/WebSocketClient/BrowserWebSocketClient/index.js.map +1 -0
  12. package/dist/ApiClient/WebSocketClient/events.d.ts +12 -0
  13. package/dist/ApiClient/WebSocketClient/index.d.ts +2 -2
  14. package/dist/ApiClient/WebSocketClient/index.js +13 -3
  15. package/dist/ApiClient/WebSocketClient/index.js.map +1 -1
  16. package/dist/ApiClient/WebSocketClient/types.d.ts +13 -0
  17. package/dist/ApiClient/index.d.ts +4 -4
  18. package/dist/ApiClient/index.js +23 -4
  19. package/dist/ApiClient/index.js.map +1 -1
  20. package/dist/Projects/Job.d.ts +44 -4
  21. package/dist/Projects/Job.js +83 -16
  22. package/dist/Projects/Job.js.map +1 -1
  23. package/dist/Projects/Project.d.ts +18 -0
  24. package/dist/Projects/Project.js +38 -10
  25. package/dist/Projects/Project.js.map +1 -1
  26. package/dist/Projects/createJobRequestMessage.js +170 -13
  27. package/dist/Projects/createJobRequestMessage.js.map +1 -1
  28. package/dist/Projects/index.d.ts +112 -11
  29. package/dist/Projects/index.js +473 -45
  30. package/dist/Projects/index.js.map +1 -1
  31. package/dist/Projects/types/ComfySamplerParams.d.ts +28 -0
  32. package/dist/Projects/types/ComfySamplerParams.js +36 -0
  33. package/dist/Projects/types/ComfySamplerParams.js.map +1 -0
  34. package/dist/Projects/types/ComfySchedulerParams.d.ts +17 -0
  35. package/dist/Projects/types/ComfySchedulerParams.js +23 -0
  36. package/dist/Projects/types/ComfySchedulerParams.js.map +1 -0
  37. package/dist/Projects/types/EstimationResponse.d.ts +2 -0
  38. package/dist/Projects/types/ForgeSamplerParams.d.ts +27 -0
  39. package/dist/Projects/types/ForgeSamplerParams.js +39 -0
  40. package/dist/Projects/types/ForgeSamplerParams.js.map +1 -0
  41. package/dist/Projects/types/ForgeSchedulerParams.d.ts +17 -0
  42. package/dist/Projects/types/ForgeSchedulerParams.js +28 -0
  43. package/dist/Projects/types/ForgeSchedulerParams.js.map +1 -0
  44. package/dist/Projects/types/events.d.ts +5 -1
  45. package/dist/Projects/types/index.d.ts +205 -38
  46. package/dist/Projects/types/index.js +17 -0
  47. package/dist/Projects/types/index.js.map +1 -1
  48. package/dist/Projects/utils.d.ts +19 -1
  49. package/dist/Projects/utils.js +68 -0
  50. package/dist/Projects/utils.js.map +1 -1
  51. package/dist/index.d.ts +12 -4
  52. package/dist/index.js +14 -4
  53. package/dist/index.js.map +1 -1
  54. package/dist/lib/AuthManager/TokenAuthManager.js +0 -2
  55. package/dist/lib/AuthManager/TokenAuthManager.js.map +1 -1
  56. package/dist/lib/DataEntity.js +4 -2
  57. package/dist/lib/DataEntity.js.map +1 -1
  58. package/dist/lib/RestClient.js +15 -2
  59. package/dist/lib/RestClient.js.map +1 -1
  60. package/dist/lib/validation.d.ts +26 -2
  61. package/dist/lib/validation.js +95 -10
  62. package/dist/lib/validation.js.map +1 -1
  63. package/package.json +4 -4
  64. package/src/Account/index.ts +30 -19
  65. package/src/ApiClient/WebSocketClient/BrowserWebSocketClient/ChannelCoordinator.ts +426 -0
  66. package/src/ApiClient/WebSocketClient/BrowserWebSocketClient/index.ts +237 -0
  67. package/src/ApiClient/WebSocketClient/events.ts +14 -0
  68. package/src/ApiClient/WebSocketClient/index.ts +15 -5
  69. package/src/ApiClient/WebSocketClient/types.ts +16 -0
  70. package/src/ApiClient/index.ts +30 -8
  71. package/src/Projects/Job.ts +97 -16
  72. package/src/Projects/Project.ts +46 -13
  73. package/src/Projects/createJobRequestMessage.ts +222 -35
  74. package/src/Projects/index.ts +504 -49
  75. package/src/Projects/types/ComfySamplerParams.ts +34 -0
  76. package/src/Projects/types/ComfySchedulerParams.ts +21 -0
  77. package/src/Projects/types/EstimationResponse.ts +2 -0
  78. package/src/Projects/types/ForgeSamplerParams.ts +37 -0
  79. package/src/Projects/types/ForgeSchedulerParams.ts +26 -0
  80. package/src/Projects/types/events.ts +6 -0
  81. package/src/Projects/types/index.ts +243 -39
  82. package/src/Projects/utils.ts +66 -1
  83. package/src/index.ts +60 -8
  84. package/src/lib/AuthManager/TokenAuthManager.ts +0 -2
  85. package/src/lib/DataEntity.ts +4 -2
  86. package/src/lib/RestClient.ts +16 -2
  87. package/src/lib/validation.ts +111 -14
  88. package/dist/Projects/types/SamplerParams.d.ts +0 -12
  89. package/dist/Projects/types/SamplerParams.js +0 -21
  90. package/dist/Projects/types/SamplerParams.js.map +0 -1
  91. package/dist/Projects/types/SchedulerParams.d.ts +0 -13
  92. package/dist/Projects/types/SchedulerParams.js +0 -19
  93. package/dist/Projects/types/SchedulerParams.js.map +0 -1
  94. package/src/Projects/types/SamplerParams.ts +0 -19
  95. package/src/Projects/types/SchedulerParams.ts +0 -17
@@ -1,11 +1,71 @@
1
- import { ProjectParams } from './types';
1
+ import {
2
+ ImageProjectParams,
3
+ isImageParams,
4
+ isVideoParams,
5
+ ProjectParams,
6
+ VideoProjectParams
7
+ } from './types';
2
8
  import { ControlNetParams, ControlNetParamsRaw } from './types/ControlNetParams';
3
9
  import {
4
10
  validateNumber,
5
11
  validateCustomImageSize,
6
- validateSampler,
7
- validateScheduler
12
+ validateForgeSampler,
13
+ validateForgeScheduler,
14
+ validateVideoSize,
15
+ validateTeacacheThreshold,
16
+ validateComfySampler,
17
+ validateComfyScheduler,
18
+ isComfyModel,
19
+ validateVideoDuration
8
20
  } from '../lib/validation';
21
+ import { getVideoWorkflowType, isVideoModel, VIDEO_WORKFLOW_ASSETS } from './utils';
22
+ import { ApiError } from '../ApiClient';
23
+
24
+ /**
25
+ * Validate that the provided assets match the workflow requirements.
26
+ * Throws an error if required assets are missing or forbidden assets are provided.
27
+ */
28
+ function validateVideoWorkflowAssets(params: VideoProjectParams): void {
29
+ const workflowType = getVideoWorkflowType(params.modelId);
30
+ if (!workflowType) return;
31
+
32
+ const requirements = VIDEO_WORKFLOW_ASSETS[workflowType];
33
+ if (!requirements) return;
34
+
35
+ // Special case for i2v: at least ONE of referenceImage or referenceImageEnd required
36
+ if (workflowType === 'i2v') {
37
+ if (!params.referenceImage && !params.referenceImageEnd) {
38
+ throw new ApiError(400, {
39
+ status: 'error',
40
+ errorCode: 0,
41
+ message:
42
+ 'i2v workflow requires at least one of referenceImage or referenceImageEnd. Please provide this asset.'
43
+ });
44
+ }
45
+ }
46
+
47
+ // Check for missing required assets and forbidden assets
48
+ for (const [asset, requirement] of Object.entries(requirements)) {
49
+ const assetKey = asset as keyof VideoProjectParams;
50
+ const hasAsset = !!params[assetKey];
51
+
52
+ if (requirement === 'required' && !hasAsset) {
53
+ throw new ApiError(400, {
54
+ status: 'error',
55
+ errorCode: 0,
56
+ message: `${workflowType} workflow requires ${assetKey}. Please provide this asset.`
57
+ });
58
+ }
59
+
60
+ if (requirement === 'forbidden' && hasAsset) {
61
+ throw new ApiError(400, {
62
+ status: 'error',
63
+ errorCode: 0,
64
+ message: `${workflowType} workflow does not support ${assetKey}. Please remove this asset.`
65
+ });
66
+ }
67
+ }
68
+ }
9
69
 
10
70
  // Mac worker can't process the data if some of the fields are missing, so we need to provide a default template
11
71
  function getTemplate() {
@@ -118,49 +178,176 @@ function getControlNet(params: ControlNetParams): ControlNetParamsRaw[] {
118
178
  return [cn];
119
179
  }
120
180
 
181
+ function applyImageParams(inputKeyframe: Record<string, any>, params: ImageProjectParams) {
182
+ const keyFrame: Record<string, any> = {
183
+ ...inputKeyframe,
184
+ sizePreset: params.sizePreset,
185
+ hasContextImage1: !!params.contextImages?.[0],
186
+ hasContextImage2: !!params.contextImages?.[1],
187
+ hasContextImage3: !!params.contextImages?.[2]
188
+ };
189
+
190
+ // Handle sampler/scheduler: ComfyUI models use comfySampler/comfyScheduler,
191
+ // legacy models use sampler/scheduler (mapped to scheduler/timeStepSpacing)
192
+ if (isComfyModel(params.modelId)) {
193
+ if (params.sampler !== undefined) {
194
+ keyFrame.comfySampler = validateComfySampler(params.sampler);
195
+ }
196
+ if (params.scheduler !== undefined) {
197
+ keyFrame.comfyScheduler = validateComfyScheduler(params.scheduler);
198
+ }
199
+ } else {
200
+ if (params.sampler !== undefined) {
201
+ keyFrame.scheduler = validateForgeSampler(params.sampler);
202
+ }
203
+ if (params.scheduler !== undefined) {
204
+ keyFrame.timeStepSpacing = validateForgeScheduler(params.scheduler);
205
+ }
206
+ }
207
+
208
+ if (params.startingImage) {
209
+ keyFrame.hasStartingImage = true;
210
+ keyFrame.strengthIsEnabled = true;
211
+ keyFrame.strength = 1 - (Number(params.startingImageStrength) || 0.5);
212
+ }
213
+
214
+ if (params.controlNet) {
215
+ keyFrame.currentControlNetsJob = getControlNet(params.controlNet);
216
+ }
217
+
218
+ // Set sizePreset to 'custom' if width/height are provided but sizePreset is not set
219
+ let effectiveSizePreset = params.sizePreset;
220
+ if (params.width && params.height && !params.sizePreset) {
221
+ effectiveSizePreset = 'custom';
222
+ }
223
+ keyFrame.sizePreset = effectiveSizePreset;
224
+
225
+ if (effectiveSizePreset === 'custom' && params.width && params.height) {
226
+ keyFrame.width = validateCustomImageSize(params.width);
227
+ keyFrame.height = validateCustomImageSize(params.height);
228
+ }
229
+ return keyFrame;
230
+ }
231
+
232
+ function applyVideoParams(inputKeyframe: Record<string, any>, params: VideoProjectParams) {
233
+ if (!isVideoModel(params.modelId)) {
234
+ throw new ApiError(400, {
235
+ status: 'error',
236
+ errorCode: 0,
237
+ message: 'Video generation is only supported for video models.'
238
+ });
239
+ }
240
+ validateVideoWorkflowAssets(params);
241
+ const keyFrame: Record<string, any> = { ...inputKeyframe };
242
+ if (params.referenceImage) {
243
+ keyFrame.hasReferenceImage = true;
244
+ }
245
+ if (params.referenceImageEnd) {
246
+ keyFrame.hasReferenceImageEnd = true;
247
+ }
248
+ if (params.referenceAudio) {
249
+ keyFrame.hasReferenceAudio = true;
250
+ }
251
+ if (params.referenceVideo) {
252
+ keyFrame.hasReferenceVideo = true;
253
+ }
254
+
255
+ // Video generation parameters
256
+ if (params.frames !== undefined) {
257
+ keyFrame.frames = params.frames;
258
+ }
259
+ if (params.duration !== undefined) {
260
+ const duration = validateVideoDuration(params.duration);
261
+ keyFrame.frames = duration * 16 + 1;
262
+ }
263
+ if (params.fps !== undefined) {
264
+ keyFrame.fps = params.fps;
265
+ }
266
+ if (params.shift !== undefined) {
267
+ keyFrame.shift = params.shift;
268
+ }
269
+ if (params.teacacheThreshold !== undefined) {
270
+ const validatedThreshold = validateTeacacheThreshold(params.teacacheThreshold);
271
+ if (validatedThreshold !== undefined) {
272
+ keyFrame.teacacheThreshold = validatedThreshold;
273
+ }
274
+ }
275
+
276
+ // S2V audio parameters
277
+ if (params.audioStart !== undefined) {
278
+ keyFrame.audioStart = params.audioStart;
279
+ }
280
+ if (params.audioDuration !== undefined) {
281
+ keyFrame.audioDuration = params.audioDuration;
282
+ }
283
+
284
+ // Animate video parameters (for animate-move, animate-replace)
285
+ if (params.videoStart !== undefined) {
286
+ keyFrame.videoStart = params.videoStart;
287
+ }
288
+
289
+ // Validate and set video dimensions (minimum 480px for Wan 2.2 models)
290
+ if (params.width && params.height) {
291
+ keyFrame.width = validateVideoSize(params.width, 'width');
292
+ keyFrame.height = validateVideoSize(params.height, 'height');
293
+ }
294
+
295
+ // Video models are ComfyUI models - only accept comfySampler/comfyScheduler
296
+ // Legacy sampler/scheduler fields are NOT supported for video models
297
+ if (params.sampler !== undefined) {
298
+ keyFrame.comfySampler = validateComfySampler(params.sampler);
299
+ }
300
+ if (params.scheduler !== undefined) {
301
+ keyFrame.comfyScheduler = validateComfyScheduler(params.scheduler);
302
+ }
303
+
304
+ return keyFrame;
305
+ }
306
+
121
307
  function createJobRequestMessage(id: string, params: ProjectParams) {
122
308
  const template = getTemplate();
309
+ // Base keyFrame with common params
310
+ let keyFrame: Record<string, any> = {
311
+ ...template.keyFrames[0],
312
+ steps: params.steps,
313
+ guidanceScale: params.guidance,
314
+ modelID: params.modelId,
315
+ negativePrompt: params.negativePrompt,
316
+ seed: params.seed,
317
+ positivePrompt: params.positivePrompt,
318
+ stylePrompt: params.stylePrompt
319
+ };
320
+
321
+ switch (params.type) {
322
+ case 'image':
323
+ keyFrame = applyImageParams(keyFrame, params);
324
+ break;
325
+ case 'video':
326
+ keyFrame = applyVideoParams(keyFrame, params);
327
+ break;
328
+ default:
329
+ throw new ApiError(400, {
330
+ status: 'error',
331
+ errorCode: 0,
332
+ message: 'Invalid project type. Must be "image" or "video".'
333
+ });
334
+ }
335
+
123
336
  const jobRequest: Record<string, any> = {
124
337
  ...template,
125
- keyFrames: [
126
- {
127
- ...template.keyFrames[0],
128
- scheduler: validateSampler(params.sampler),
129
- timeStepSpacing: validateScheduler(params.scheduler),
130
- steps: params.steps,
131
- guidanceScale: params.guidance,
132
- modelID: params.modelId,
133
- negativePrompt: params.negativePrompt,
134
- seed: params.seed,
135
- positivePrompt: params.positivePrompt,
136
- stylePrompt: params.stylePrompt,
137
- hasStartingImage: !!params.startingImage,
138
- hasContextImage1: !!params.contextImages?.[0],
139
- hasContextImage2: !!params.contextImages?.[1],
140
- strengthIsEnabled: !!params.startingImage,
141
- strength: !!params.startingImage
142
- ? 1 - (Number(params.startingImageStrength) || 0.5)
143
- : undefined,
144
- sizePreset: params.sizePreset
145
- }
146
- ],
147
- previews: params.numberOfPreviews || 0,
148
- numberOfImages: params.numberOfImages,
338
+ keyFrames: [keyFrame],
339
+ previews: isImageParams(params) ? params.numberOfPreviews || 0 : 0,
340
+ numberOfImages: params.numberOfMedia || 1,
149
341
  jobID: id,
150
342
  disableSafety: !!params.disableNSFWFilter,
151
343
  tokenType: params.tokenType,
152
- outputFormat: params.outputFormat || 'png'
344
+ outputFormat: params.outputFormat || (isVideoParams(params) ? 'mp4' : 'png')
153
345
  };
346
+
154
347
  if (params.network) {
155
348
  jobRequest.network = params.network;
156
349
  }
157
- if (params.controlNet) {
158
- jobRequest.keyFrames[0].currentControlNetsJob = getControlNet(params.controlNet);
159
- }
160
- if (params.sizePreset === 'custom') {
161
- jobRequest.keyFrames[0].width = validateCustomImageSize(params.width);
162
- jobRequest.keyFrames[0].height = validateCustomImageSize(params.height);
163
- }
350
+
164
351
  return jobRequest;
165
352
  }
166
353