@sogni-ai/sogni-client 4.0.0-alpha.36 → 4.0.0-alpha.38

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 (50) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/ApiClient/WebSocketClient/events.d.ts +1 -0
  3. package/dist/Projects/createJobRequestMessage.js +34 -2
  4. package/dist/Projects/createJobRequestMessage.js.map +1 -1
  5. package/dist/Projects/index.d.ts +2 -0
  6. package/dist/Projects/index.js +68 -19
  7. package/dist/Projects/index.js.map +1 -1
  8. package/dist/Projects/types/ComfySamplerParams.d.ts +26 -0
  9. package/dist/Projects/types/ComfySamplerParams.js +33 -0
  10. package/dist/Projects/types/ComfySamplerParams.js.map +1 -0
  11. package/dist/Projects/types/ComfySchedulerParams.d.ts +17 -0
  12. package/dist/Projects/types/ComfySchedulerParams.js +23 -0
  13. package/dist/Projects/types/ComfySchedulerParams.js.map +1 -0
  14. package/dist/Projects/types/ForgeSamplerParams.d.ts +27 -0
  15. package/dist/Projects/types/ForgeSamplerParams.js +39 -0
  16. package/dist/Projects/types/ForgeSamplerParams.js.map +1 -0
  17. package/dist/Projects/types/ForgeSchedulerParams.d.ts +17 -0
  18. package/dist/Projects/types/ForgeSchedulerParams.js +28 -0
  19. package/dist/Projects/types/ForgeSchedulerParams.js.map +1 -0
  20. package/dist/Projects/types/index.d.ts +30 -7
  21. package/dist/Projects/types/index.js +9 -5
  22. package/dist/Projects/types/index.js.map +1 -1
  23. package/dist/index.d.ts +2 -2
  24. package/dist/index.js +5 -3
  25. package/dist/index.js.map +1 -1
  26. package/dist/lib/RestClient.js +15 -2
  27. package/dist/lib/RestClient.js.map +1 -1
  28. package/dist/lib/validation.d.ts +15 -2
  29. package/dist/lib/validation.js +62 -13
  30. package/dist/lib/validation.js.map +1 -1
  31. package/package.json +1 -1
  32. package/src/ApiClient/WebSocketClient/events.ts +1 -0
  33. package/src/Projects/createJobRequestMessage.ts +41 -5
  34. package/src/Projects/index.ts +78 -24
  35. package/src/Projects/types/ComfySamplerParams.ts +31 -0
  36. package/src/Projects/types/ComfySchedulerParams.ts +21 -0
  37. package/src/Projects/types/ForgeSamplerParams.ts +37 -0
  38. package/src/Projects/types/ForgeSchedulerParams.ts +26 -0
  39. package/src/Projects/types/index.ts +37 -7
  40. package/src/index.ts +14 -3
  41. package/src/lib/RestClient.ts +16 -2
  42. package/src/lib/validation.ts +73 -12
  43. package/dist/Projects/types/SamplerParams.d.ts +0 -13
  44. package/dist/Projects/types/SamplerParams.js +0 -26
  45. package/dist/Projects/types/SamplerParams.js.map +0 -1
  46. package/dist/Projects/types/SchedulerParams.d.ts +0 -14
  47. package/dist/Projects/types/SchedulerParams.js +0 -24
  48. package/dist/Projects/types/SchedulerParams.js.map +0 -1
  49. package/src/Projects/types/SamplerParams.ts +0 -24
  50. package/src/Projects/types/SchedulerParams.ts +0 -22
@@ -11,7 +11,15 @@ import {
11
11
  SupportedModel,
12
12
  ImageProjectParams,
13
13
  VideoProjectParams,
14
- VideoEstimateRequest
14
+ VideoEstimateRequest,
15
+ SupportedComfySamplers,
16
+ SupportedForgeSamplers,
17
+ SupportedComfySchedulers,
18
+ SupportedForgeSchedulers,
19
+ ComfyScheduler,
20
+ ForgeScheduler,
21
+ ComfySampler,
22
+ ForgeSampler
15
23
  } from './types';
16
24
  import {
17
25
  JobErrorData,
@@ -39,7 +47,7 @@ import {
39
47
  VIDEO_WORKFLOW_ASSETS
40
48
  } from './utils';
41
49
  import { TokenType } from '../types/token';
42
- import { validateSampler } from '../lib/validation';
50
+ import { isComfyModel, validateSampler } from '../lib/validation';
43
51
 
44
52
  const sizePresetCache = new Cache<SizePreset[]>(10 * 60 * 1000);
45
53
  const GARBAGE_COLLECT_TIMEOUT = 30000;
@@ -61,17 +69,17 @@ function getFileContentType(file: File | Buffer | Blob): string | undefined {
61
69
  * Convert file to a format compatible with fetch body.
62
70
  * Converts Node.js Buffer to Blob for cross-platform compatibility.
63
71
  */
64
- function toFetchBody(file: File | Buffer | Blob) {
72
+ function toFetchBody(file: File | Buffer | Blob): BodyInit {
65
73
  // Node.js Buffer is not supported in browsers, so we can skip this conversion
66
74
  if (typeof Buffer === 'undefined') {
67
- return file;
75
+ return file as BodyInit;
68
76
  }
69
77
  if (Buffer.isBuffer(file)) {
70
78
  // Copy Buffer data to a new ArrayBuffer to ensure type compatibility
71
79
  const arrayBuffer = file.buffer.slice(file.byteOffset, file.byteOffset + file.byteLength);
72
80
  return new Blob([arrayBuffer as ArrayBuffer]);
73
81
  }
74
- return file;
82
+ return file as BodyInit;
75
83
  }
76
84
 
77
85
  function mapErrorCodes(code: string): number {
@@ -126,7 +134,11 @@ class ProjectsApi extends ApiGroup<ProjectApiEvents> {
126
134
  this.client.socket.on('jobProgress', this.handleJobProgress.bind(this));
127
135
  this.client.socket.on('jobETA', this.handleJobETA.bind(this));
128
136
  this.client.socket.on('jobError', this.handleJobError.bind(this));
129
- this.client.socket.on('jobResult', this.handleJobResult.bind(this));
137
+ this.client.socket.on('jobResult', (data: any) => {
138
+ this.handleJobResult(data).catch((err) => {
139
+ this.client.logger.error('Error in handleJobResult:', err);
140
+ });
141
+ });
130
142
  // Listen to the server disconnect event
131
143
  this.client.on('disconnected', this.handleServerDisconnected.bind(this));
132
144
  // Listen to project and job events and update project and job instances
@@ -245,27 +257,47 @@ class ProjectsApi extends ApiGroup<ProjectApiEvents> {
245
257
  private async handleJobResult(data: JobResultData) {
246
258
  const project = this.projects.find((p) => p.id === data.jobID);
247
259
  const passNSFWCheck = !data.triggeredNSFWFilter || !project || project.params.disableNSFWFilter;
248
- let downloadUrl = null;
249
- // If NSFW filter is triggered, image will be only available for download if user explicitly
250
- // disabled the filter for this project
251
- if (passNSFWCheck && !data.userCanceled) {
260
+ let downloadUrl = data.resultUrl || null; // Use resultUrl from event if provided
261
+
262
+ // If no resultUrl provided and NSFW check passes, generate download URL
263
+ if (!downloadUrl && passNSFWCheck && !data.userCanceled) {
252
264
  // Use media endpoint for video models, image endpoint for image models
253
265
  const isVideo = project && this.isVideoModelId(project.params.modelId);
254
- if (isVideo) {
255
- downloadUrl = await this.mediaDownloadUrl({
256
- jobId: data.jobID,
257
- id: data.imgID,
258
- type: 'complete'
259
- });
260
- } else {
261
- downloadUrl = await this.downloadUrl({
262
- jobId: data.jobID,
263
- imageId: data.imgID,
264
- type: 'complete'
266
+ try {
267
+ if (isVideo) {
268
+ downloadUrl = await this.mediaDownloadUrl({
269
+ jobId: data.jobID,
270
+ id: data.imgID,
271
+ type: 'complete'
272
+ });
273
+ } else {
274
+ downloadUrl = await this.downloadUrl({
275
+ jobId: data.jobID,
276
+ imageId: data.imgID,
277
+ type: 'complete'
278
+ });
279
+ }
280
+ } catch (error: any) {
281
+ // Continue with null downloadUrl - the event will indicate failure
282
+ }
283
+ }
284
+
285
+ // Update the job directly with the result URL to prevent duplicate API calls
286
+ if (project) {
287
+ const job = project.job(data.imgID);
288
+ if (job) {
289
+ job._update({
290
+ status: data.userCanceled ? 'canceled' : 'completed',
291
+ step: data.performedStepCount,
292
+ seed: Number(data.lastSeed),
293
+ resultUrl: downloadUrl,
294
+ isNSFW: data.triggeredNSFWFilter,
295
+ userCanceled: data.userCanceled
265
296
  });
266
297
  }
267
298
  }
268
299
 
300
+ // Emit job completion event with the generated download URL
269
301
  this.emit('job', {
270
302
  type: 'completed',
271
303
  projectId: data.jobID,
@@ -494,6 +526,7 @@ class ProjectsApi extends ApiGroup<ProjectApiEvents> {
494
526
  async create(data: ProjectParams): Promise<Project> {
495
527
  const project = new Project({ ...data }, { api: this, logger: this.client.logger });
496
528
  const request = createJobRequestMessage(project.id, data);
529
+
497
530
  switch (data.type) {
498
531
  case 'image':
499
532
  await this._processImageAssets(project, data);
@@ -650,9 +683,10 @@ class ProjectsApi extends ApiGroup<ProjectApiEvents> {
650
683
  jobId: projectId,
651
684
  type: `contextImage${imageIndex}`
652
685
  });
686
+ const body = toFetchBody(file);
653
687
  const res = await fetch(presignedUrl, {
654
688
  method: 'PUT',
655
- body: toFetchBody(file)
689
+ body
656
690
  });
657
691
  if (!res.ok) {
658
692
  throw new ApiError(res.status, {
@@ -825,7 +859,7 @@ class ProjectsApi extends ApiGroup<ProjectApiEvents> {
825
859
  if (sampler) {
826
860
  apiVersion = 3;
827
861
  pathParams.push(guidance || 0);
828
- pathParams.push(validateSampler(sampler)!);
862
+ pathParams.push(validateSampler(model, sampler)!);
829
863
  pathParams.push(contextImages || 0);
830
864
  }
831
865
  const r = await this.client.socket.get<EstimationResponse>(
@@ -880,7 +914,7 @@ class ProjectsApi extends ApiGroup<ProjectApiEvents> {
880
914
  params.model,
881
915
  params.width,
882
916
  params.height,
883
- params.frames,
917
+ params.frames ? params.frames : params.duration * 16 + 1,
884
918
  params.fps,
885
919
  params.steps,
886
920
  params.numberOfMedia
@@ -922,6 +956,9 @@ class ProjectsApi extends ApiGroup<ProjectApiEvents> {
922
956
  `/v1/image/downloadUrl`,
923
957
  params
924
958
  );
959
+ if (!r?.data?.downloadUrl) {
960
+ throw new Error(`API returned no downloadUrl: ${JSON.stringify(r)}`);
961
+ }
925
962
  return r.data.downloadUrl;
926
963
  }
927
964
 
@@ -946,6 +983,9 @@ class ProjectsApi extends ApiGroup<ProjectApiEvents> {
946
983
  `/v1/media/downloadUrl`,
947
984
  params
948
985
  );
986
+ if (!r?.data?.downloadUrl) {
987
+ throw new Error(`API returned no downloadUrl: ${JSON.stringify(r)}`);
988
+ }
949
989
  return r.data.downloadUrl;
950
990
  }
951
991
 
@@ -1064,6 +1104,20 @@ class ProjectsApi extends ApiGroup<ProjectApiEvents> {
1064
1104
  };
1065
1105
  });
1066
1106
  }
1107
+
1108
+ async getSamplers(modelId: string) {
1109
+ if (isComfyModel(modelId)) {
1110
+ return Object.keys(SupportedComfySamplers) as ComfySampler[];
1111
+ }
1112
+ return Object.keys(SupportedForgeSamplers) as ForgeSampler[];
1113
+ }
1114
+
1115
+ async getSchedulers(modelId: string) {
1116
+ if (isComfyModel(modelId)) {
1117
+ return Object.keys(SupportedComfySchedulers) as ComfyScheduler[];
1118
+ }
1119
+ return Object.keys(SupportedForgeSchedulers) as ForgeScheduler[];
1120
+ }
1067
1121
  }
1068
1122
 
1069
1123
  export default ProjectsApi;
@@ -0,0 +1,31 @@
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
+ };
26
+
27
+ export function isComfySampler(sampler: string): sampler is ComfySampler {
28
+ return sampler in SupportedComfySamplers;
29
+ }
30
+
31
+ export type ComfySampler = keyof typeof SupportedComfySamplers;
@@ -0,0 +1,21 @@
1
+ /**
2
+ * ComfyUI scheduler 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 SupportedComfySchedulers = {
6
+ simple: 'simple',
7
+ normal: 'normal',
8
+ karras: 'karras',
9
+ exponential: 'exponential',
10
+ sgm_uniform: 'sgm_uniform',
11
+ ddim_uniform: 'ddim_uniform',
12
+ beta: 'beta',
13
+ linear_quadratic: 'linear_quadratic',
14
+ kl_optimal: 'kl_optimal'
15
+ };
16
+
17
+ export function isComfyScheduler(scheduler: string): scheduler is ComfyScheduler {
18
+ return scheduler in SupportedComfySchedulers;
19
+ }
20
+
21
+ export type ComfyScheduler = keyof typeof SupportedComfySchedulers;
@@ -0,0 +1,37 @@
1
+ export const SupportedForgeSamplers = {
2
+ euler: 'Euler',
3
+ euler_ancestral: 'Euler Ancestral',
4
+ heun: 'Heun',
5
+ dpmpp_2m: 'DPM++ 2M',
6
+ dpmpp_2m_sde: 'DPM++ 2M SDE',
7
+ dpmpp_sde: 'DPM++ SDE',
8
+ dpmpp_3m_sde: 'DPM++ 3M SDE',
9
+ uni_pc: 'UniPC',
10
+ lcm: 'LCM (Latent Consistency Model)',
11
+ // Legacy/other supported samplers
12
+ lms: 'LMS',
13
+ dpm_2: 'DPM 2',
14
+ dpm_2_ancestral: 'DPM 2 Ancestral',
15
+ dpm_fast: 'DPM Fast',
16
+ dpm_adaptive: 'DPM Adaptive',
17
+ dpmpp_2s_ancestral: 'DPM++ 2S Ancestral',
18
+ ddpm: 'DDPM',
19
+ // SDK compatibility aliases
20
+ dfs_sd3: 'Discrete Flow Scheduler (SD3)',
21
+ dpm_pp: 'DPM Solver Multistep (DPM-Solver++)',
22
+ dpm_pp_sde: 'DPM++ SDE',
23
+ dpm_pp_2m: 'DPM++ 2M',
24
+ euler_a: 'Euler a',
25
+ pndm_plms: 'PNDM (Pseudo-linear multi-step)'
26
+ };
27
+
28
+ export function isForgeSampler(sampler: string): sampler is ForgeSampler {
29
+ return sampler in SupportedForgeSamplers;
30
+ }
31
+
32
+ export function isRawForgeSampler(sampler: string): boolean {
33
+ const samplers = Object.values(SupportedForgeSamplers);
34
+ return samplers.includes(sampler);
35
+ }
36
+
37
+ export type ForgeSampler = keyof typeof SupportedForgeSamplers;
@@ -0,0 +1,26 @@
1
+ export const SupportedForgeSchedulers = {
2
+ simple: 'Simple',
3
+ normal: 'Normal',
4
+ karras: 'Karras',
5
+ exponential: 'Exponential',
6
+ sgm_uniform: 'SGM Uniform',
7
+ ddim_uniform: 'DDIM Uniform',
8
+ beta: 'Beta',
9
+ linear_quadratic: 'Linear Quadratic',
10
+ kl_optimal: 'KL Optimal',
11
+ // Legacy aliases
12
+ ddim: 'DDIM',
13
+ leading: 'Leading',
14
+ linear: 'Linear'
15
+ };
16
+
17
+ export function isForgeScheduler(scheduler: string): scheduler is ForgeScheduler {
18
+ return scheduler in SupportedForgeSchedulers;
19
+ }
20
+
21
+ export function isRawForgeScheduler(scheduler: string): boolean {
22
+ const schedulers = Object.values(SupportedForgeSchedulers);
23
+ return schedulers.includes(scheduler);
24
+ }
25
+
26
+ export type ForgeScheduler = keyof typeof SupportedForgeSchedulers;
@@ -1,8 +1,10 @@
1
1
  import { SupernetType } from '../../ApiClient/WebSocketClient/types';
2
2
  import { ControlNetParams } from './ControlNetParams';
3
3
  import { TokenType } from '../../types/token';
4
- import { Sampler, SupportedSamplers } from './SamplerParams';
5
- import { Scheduler, SupportedSchedulers } from './SchedulerParams';
4
+ import { ForgeSampler, SupportedForgeSamplers } from './ForgeSamplerParams';
5
+ import { ForgeScheduler, SupportedForgeSchedulers } from './ForgeSchedulerParams';
6
+ import { ComfySampler, SupportedComfySamplers } from './ComfySamplerParams';
7
+ import { ComfyScheduler, SupportedComfySchedulers } from './ComfySchedulerParams';
6
8
 
7
9
  export interface SupportedModel {
8
10
  id: string;
@@ -33,9 +35,18 @@ export interface SizePreset {
33
35
  aspect: string;
34
36
  }
35
37
 
36
- export type { Sampler, Scheduler };
38
+ export type Sampler = ForgeSampler | ComfySampler;
37
39
 
38
- export { SupportedSamplers, SupportedSchedulers };
40
+ export type Scheduler = ForgeScheduler | ComfyScheduler;
41
+
42
+ export type { ForgeSampler, ForgeScheduler, ComfySampler, ComfyScheduler };
43
+
44
+ export {
45
+ SupportedForgeSamplers,
46
+ SupportedForgeSchedulers,
47
+ SupportedComfySamplers,
48
+ SupportedComfySchedulers
49
+ };
39
50
 
40
51
  export type ImageOutputFormat = 'png' | 'jpg';
41
52
  export type VideoOutputFormat = 'mp4';
@@ -152,6 +163,18 @@ export interface VideoProjectParams extends BaseProjectParams {
152
163
  * Output video height. Only used if `sizePreset` is "custom"
153
164
  */
154
165
  height?: number;
166
+ /**
167
+ * ComfyUI sampler for video generation.
168
+ * Uses ComfyUI's native lowercase format: euler, euler_ancestral, dpmpp_2m, etc.
169
+ * Default: euler (or uni_pc for s2v models)
170
+ */
171
+ sampler?: ComfySampler;
172
+ /**
173
+ * ComfyUI scheduler for video generation.
174
+ * Uses ComfyUI's native lowercase format: simple, normal, karras, sgm_uniform, etc.
175
+ * Default: simple
176
+ */
177
+ scheduler?: ComfyScheduler;
155
178
  /**
156
179
  * Output video format. For now only 'mp4' is supported, defaults to 'mp4'.
157
180
  */
@@ -184,11 +207,13 @@ export interface ImageProjectParams extends BaseProjectParams {
184
207
  */
185
208
  contextImages?: InputMedia[];
186
209
  /**
187
- * Scheduler to use
210
+ * Legacy sampler for non-ComfyUI models (Automatic1111 workers).
211
+ * Not supported for ComfyUI models - use comfySampler instead.
188
212
  */
189
213
  sampler?: Sampler;
190
214
  /**
191
- * Time step spacing method
215
+ * Legacy scheduler for non-ComfyUI models (Automatic1111 workers).
216
+ * Not supported for ComfyUI models - use comfyScheduler instead.
192
217
  */
193
218
  scheduler?: Scheduler;
194
219
  /**
@@ -329,7 +354,12 @@ export interface VideoEstimateRequest {
329
354
  model: string;
330
355
  width: number;
331
356
  height: number;
332
- frames: number;
357
+ duration: number;
358
+ /**
359
+ * Number of frames to generate.
360
+ * @deprecated Use duration instead
361
+ */
362
+ frames?: number;
333
363
  fps: number;
334
364
  steps: number;
335
365
  numberOfMedia: number;
package/src/index.ts CHANGED
@@ -19,8 +19,10 @@ import {
19
19
  ProjectParams,
20
20
  Sampler,
21
21
  Scheduler,
22
- SupportedSamplers,
23
- SupportedSchedulers,
22
+ SupportedForgeSamplers,
23
+ SupportedForgeSchedulers,
24
+ SupportedComfySamplers,
25
+ SupportedComfySchedulers,
24
26
  VideoProjectParams,
25
27
  AudioFormat,
26
28
  VideoFormat,
@@ -56,7 +58,16 @@ export type {
56
58
  VideoWorkflowType
57
59
  };
58
60
 
59
- export { ApiError, CurrentAccount, Job, Project, SupportedSamplers, SupportedSchedulers };
61
+ export {
62
+ ApiError,
63
+ CurrentAccount,
64
+ Job,
65
+ Project,
66
+ SupportedComfySchedulers,
67
+ SupportedComfySamplers,
68
+ SupportedForgeSchedulers,
69
+ SupportedForgeSamplers
70
+ };
60
71
 
61
72
  export interface SogniClientConfig {
62
73
  /**
@@ -30,7 +30,21 @@ class RestClient<E extends EventMap = never> extends TypedEventEmitter<E> {
30
30
 
31
31
  private async request<T = JSONValue>(url: string, options: RequestInit = {}): Promise<T> {
32
32
  const init = await this.auth.authenticateRequest(options);
33
- return fetch(url, init).then((r) => this.processResponse(r) as T);
33
+
34
+ // Add a timeout to detect hanging requests
35
+ const controller = new AbortController();
36
+ const timeoutId = setTimeout(() => {
37
+ controller.abort();
38
+ }, 30000);
39
+
40
+ try {
41
+ const response = await fetch(url, { ...init, signal: controller.signal });
42
+ clearTimeout(timeoutId);
43
+ return this.processResponse(response) as T;
44
+ } catch (fetchError: any) {
45
+ clearTimeout(timeoutId);
46
+ throw fetchError;
47
+ }
34
48
  }
35
49
 
36
50
  private async processResponse(response: Response): Promise<JSONValue> {
@@ -52,7 +66,7 @@ class RestClient<E extends EventMap = never> extends TypedEventEmitter<E> {
52
66
  }
53
67
 
54
68
  get<T = JSONValue>(path: string, query: Record<string, any> = {}): Promise<T> {
55
- return this.request<T>(this.formatUrl(path, query), query);
69
+ return this.request<T>(this.formatUrl(path, query));
56
70
  }
57
71
 
58
72
  post<T = JSONValue>(path: string, body: Record<string, unknown> = {}): Promise<T> {
@@ -1,5 +1,15 @@
1
- import { isRawSampler, isSampler, SupportedSamplers } from '../Projects/types/SamplerParams';
2
- import { isScheduler, SupportedSchedulers } from '../Projects/types/SchedulerParams';
1
+ import {
2
+ isRawForgeSampler,
3
+ isForgeSampler,
4
+ SupportedForgeSamplers
5
+ } from '../Projects/types/ForgeSamplerParams';
6
+ import {
7
+ isForgeScheduler,
8
+ isRawForgeScheduler,
9
+ SupportedForgeSchedulers
10
+ } from '../Projects/types/ForgeSchedulerParams';
11
+ import { isComfySampler, SupportedComfySamplers } from '../Projects/types/ComfySamplerParams';
12
+ import { isComfyScheduler, SupportedComfySchedulers } from '../Projects/types/ComfySchedulerParams';
3
13
 
4
14
  export function validateCustomImageSize(value: any): number {
5
15
  return validateNumber(value, { min: 256, max: 2048, propertyName: 'Width and height' });
@@ -54,33 +64,33 @@ export function validateNumber(
54
64
  return number;
55
65
  }
56
66
 
57
- export function validateSampler(value?: string) {
67
+ export function validateForgeSampler(value?: string) {
58
68
  if (!value) {
59
69
  return null;
60
70
  }
61
- if (isRawSampler(value)) {
71
+ if (isRawForgeSampler(value)) {
62
72
  return value;
63
73
  }
64
- if (isSampler(value)) {
65
- return SupportedSamplers[value];
74
+ if (isForgeSampler(value)) {
75
+ return SupportedForgeSamplers[value];
66
76
  }
67
77
  throw new Error(
68
- `Invalid sampler: ${value}. Supported options: ${Object.keys(SupportedSamplers).join(', ')}`
78
+ `Invalid sampler: ${value}. Supported options: ${Object.keys(SupportedForgeSamplers).join(', ')}`
69
79
  );
70
80
  }
71
81
 
72
- export function validateScheduler(value?: string) {
82
+ export function validateForgeScheduler(value?: string) {
73
83
  if (!value) {
74
84
  return null;
75
85
  }
76
- if (isRawSampler(value)) {
86
+ if (isRawForgeScheduler(value)) {
77
87
  return value;
78
88
  }
79
- if (isScheduler(value)) {
80
- return SupportedSchedulers[value];
89
+ if (isForgeScheduler(value)) {
90
+ return SupportedForgeSchedulers[value];
81
91
  }
82
92
  throw new Error(
83
- `Invalid scheduler: ${value}. Supported options: ${Object.keys(SupportedSchedulers).join(', ')}`
93
+ `Invalid scheduler: ${value}. Supported options: ${Object.keys(SupportedForgeSchedulers).join(', ')}`
84
94
  );
85
95
  }
86
96
 
@@ -101,3 +111,54 @@ export function validateTeacacheThreshold(value?: number): number | undefined {
101
111
  }
102
112
  return num;
103
113
  }
114
+
115
+ /**
116
+ * Validate ComfyUI sampler for video models.
117
+ * Returns the sampler string directly (no mapping needed).
118
+ */
119
+ export function validateComfySampler(value?: string): string | undefined {
120
+ if (!value) {
121
+ return undefined;
122
+ }
123
+ if (isComfySampler(value)) {
124
+ return SupportedComfySamplers[value];
125
+ }
126
+ throw new Error(
127
+ `Invalid comfySampler: ${value}. Supported options: ${Object.keys(SupportedComfySamplers).join(', ')}`
128
+ );
129
+ }
130
+
131
+ /**
132
+ * Validate ComfyUI scheduler for video models.
133
+ * Returns the scheduler string directly (no mapping needed).
134
+ */
135
+ export function validateComfyScheduler(value?: string): string | undefined {
136
+ if (!value) {
137
+ return undefined;
138
+ }
139
+ if (isComfyScheduler(value)) {
140
+ return SupportedComfySchedulers[value];
141
+ }
142
+ throw new Error(
143
+ `Invalid comfyScheduler: ${value}. Supported options: ${Object.keys(SupportedComfySchedulers).join(', ')}`
144
+ );
145
+ }
146
+
147
+ export function isComfyModel(modelId: string): boolean {
148
+ const COMFY_PREFIXES = ['z_image_', 'qwen_image_', 'flux2_', 'wan_'];
149
+ return COMFY_PREFIXES.some((prefix) => modelId.startsWith(prefix));
150
+ }
151
+
152
+ export function validateSampler(modelId: string, sampler: string) {
153
+ if (isComfyModel(modelId)) {
154
+ return validateComfySampler(sampler);
155
+ }
156
+ return validateForgeSampler(sampler);
157
+ }
158
+
159
+ export function validateScheduler(modelId: string, scheduler: string) {
160
+ if (isComfyModel(modelId)) {
161
+ return validateComfyScheduler(scheduler);
162
+ }
163
+ return validateForgeScheduler(scheduler);
164
+ }
@@ -1,13 +0,0 @@
1
- export declare const SupportedSamplers: {
2
- dfs_sd3: string;
3
- dpm_pp: string;
4
- dpm_pp_sde: string;
5
- dpm_pp_2m: string;
6
- euler: string;
7
- euler_a: string;
8
- lcm: string;
9
- pndm_plms: string;
10
- };
11
- export declare function isSampler(sampler: string): sampler is Sampler;
12
- export declare function isRawSampler(sampler: string): boolean;
13
- export type Sampler = keyof typeof SupportedSamplers;
@@ -1,26 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SupportedSamplers = void 0;
4
- exports.isSampler = isSampler;
5
- exports.isRawSampler = isRawSampler;
6
- exports.SupportedSamplers = {
7
- dfs_sd3: 'Discrete Flow Scheduler (SD3)',
8
- dpm_pp: 'DPM Solver Multistep (DPM-Solver++)',
9
- dpm_pp_sde: 'DPM++ SDE',
10
- dpm_pp_2m: 'DPM++ 2M',
11
- //dpm_pp_2m_sde: 'DPM++ 2M SDE',
12
- euler: 'Euler',
13
- euler_a: 'Euler a',
14
- //heun: 'Heun',
15
- lcm: 'LCM (Latent Consistency Model)',
16
- pndm_plms: 'PNDM (Pseudo-linear multi-step)'
17
- //uni_pc: 'UniPC'
18
- };
19
- function isSampler(sampler) {
20
- return sampler in exports.SupportedSamplers;
21
- }
22
- function isRawSampler(sampler) {
23
- const samplers = Object.values(exports.SupportedSamplers);
24
- return samplers.includes(sampler);
25
- }
26
- //# sourceMappingURL=SamplerParams.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"SamplerParams.js","sourceRoot":"","sources":["../../../src/Projects/types/SamplerParams.ts"],"names":[],"mappings":";;;AAcA,8BAEC;AAED,oCAGC;AArBY,QAAA,iBAAiB,GAAG;IAC/B,OAAO,EAAE,+BAA+B;IACxC,MAAM,EAAE,qCAAqC;IAC7C,UAAU,EAAE,WAAW;IACvB,SAAS,EAAE,UAAU;IACrB,gCAAgC;IAChC,KAAK,EAAE,OAAO;IACd,OAAO,EAAE,SAAS;IAClB,eAAe;IACf,GAAG,EAAE,gCAAgC;IACrC,SAAS,EAAE,iCAAiC;IAC5C,iBAAiB;CAClB,CAAC;AAEF,SAAgB,SAAS,CAAC,OAAe;IACvC,OAAO,OAAO,IAAI,yBAAiB,CAAC;AACtC,CAAC;AAED,SAAgB,YAAY,CAAC,OAAe;IAC1C,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,yBAAiB,CAAC,CAAC;IAClD,OAAO,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;AACpC,CAAC"}
@@ -1,14 +0,0 @@
1
- export declare const SupportedSchedulers: {
2
- beta: string;
3
- ddim: string;
4
- karras: string;
5
- kl_optimal: string;
6
- leading: string;
7
- linear: string;
8
- normal: string;
9
- sgm_uniform: string;
10
- simple: string;
11
- };
12
- export declare function isScheduler(scheduler: string): scheduler is Scheduler;
13
- export declare function isRawScheduler(scheduler: string): boolean;
14
- export type Scheduler = keyof typeof SupportedSchedulers;
@@ -1,24 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SupportedSchedulers = void 0;
4
- exports.isScheduler = isScheduler;
5
- exports.isRawScheduler = isRawScheduler;
6
- exports.SupportedSchedulers = {
7
- beta: 'Beta',
8
- ddim: 'DDIM',
9
- karras: 'Karras',
10
- kl_optimal: 'KL Optimal',
11
- leading: 'Leading',
12
- linear: 'Linear',
13
- normal: 'Normal',
14
- sgm_uniform: 'SGM Uniform',
15
- simple: 'Simple'
16
- };
17
- function isScheduler(scheduler) {
18
- return scheduler in exports.SupportedSchedulers;
19
- }
20
- function isRawScheduler(scheduler) {
21
- const schedulers = Object.values(exports.SupportedSchedulers);
22
- return schedulers.includes(scheduler);
23
- }
24
- //# sourceMappingURL=SchedulerParams.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"SchedulerParams.js","sourceRoot":"","sources":["../../../src/Projects/types/SchedulerParams.ts"],"names":[],"mappings":";;;AAYA,kCAEC;AAED,wCAGC;AAnBY,QAAA,mBAAmB,GAAG;IACjC,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,MAAM;IACZ,MAAM,EAAE,QAAQ;IAChB,UAAU,EAAE,YAAY;IACxB,OAAO,EAAE,SAAS;IAClB,MAAM,EAAE,QAAQ;IAChB,MAAM,EAAE,QAAQ;IAChB,WAAW,EAAE,aAAa;IAC1B,MAAM,EAAE,QAAQ;CACjB,CAAC;AAEF,SAAgB,WAAW,CAAC,SAAiB;IAC3C,OAAO,SAAS,IAAI,2BAAmB,CAAC;AAC1C,CAAC;AAED,SAAgB,cAAc,CAAC,SAAiB;IAC9C,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,2BAAmB,CAAC,CAAC;IACtD,OAAO,UAAU,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;AACxC,CAAC"}