@sogni-ai/sogni-client 4.0.0-alpha.5 → 4.0.0-alpha.51

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