jbilcke-hf HF staff commited on
Commit
cdd4011
1 Parent(s): ac29ac4

adding some new settings

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. package-lock.json +608 -155
  2. package.json +3 -1
  3. src/app/api/render/providers/comfy-comfyicu/index.ts +32 -0
  4. src/app/api/render/providers/comfy-huggingface/index.ts +30 -0
  5. src/app/api/render/providers/comfy-replicate/index.ts +30 -0
  6. src/{server/comfy/replicate.ts → app/api/render/providers/comfy-replicate/runWorkflow.ts} +5 -4
  7. src/{server → app/api/render/providers}/comfy/getComfyWorkflow.ts +14 -6
  8. src/app/api/render/providers/falai/index.ts +67 -0
  9. src/app/api/render/providers/huggingface/index.ts +37 -0
  10. src/app/api/render/providers/modelslab/index.ts +30 -0
  11. src/app/api/render/providers/replicate/index.ts +42 -0
  12. src/app/api/render/route.ts +56 -0
  13. src/app/main.tsx +10 -2
  14. src/components/form/form-file.tsx +1 -1
  15. src/components/form/form-input.tsx +1 -1
  16. src/components/form/form-select.tsx +1 -1
  17. src/components/interface/loader/index.tsx +1 -1
  18. src/components/interface/timeline/index.tsx +56 -2
  19. src/components/interface/top-menu/index.tsx +3 -8
  20. src/components/interface/top-menu/{rendering → settings}/index.tsx +3 -3
  21. src/components/interface/top-menu/view/index.tsx +4 -0
  22. src/components/settings/SettingsSectionRendering.tsx +0 -68
  23. src/components/settings/assistant.tsx +35 -0
  24. src/components/settings/constants.ts +78 -0
  25. src/components/settings/index.tsx +24 -6
  26. src/components/settings/music.tsx +87 -0
  27. src/components/settings/provider.tsx +97 -0
  28. src/components/settings/sound.tsx +87 -0
  29. src/components/settings/speech.tsx +87 -0
  30. src/components/settings/storyboard.tsx +99 -0
  31. src/components/settings/video.tsx +103 -0
  32. src/components/ui/input.tsx +1 -1
  33. src/lib/core/DEPRECATED_getSettings.txt +0 -26
  34. src/lib/core/DEPRECATED_localStorageKeys.txt +0 -13
  35. src/lib/core/constants.ts +1 -1
  36. src/lib/core/getDefaultSettings.ts +0 -13
  37. src/lib/utils/blobToBase64DataUri.ts +4 -0
  38. src/lib/utils/fetchContentToBase64.ts +15 -0
  39. src/lib/utils/getValidComfyWorkflowTemplate.ts +13 -0
  40. src/lib/utils/index.ts +2 -2
  41. src/lib/utils/parseComfyIcuAccelerator.ts +43 -0
  42. src/lib/utils/parseComfyVendor.ts +0 -28
  43. src/lib/utils/parseComputeProvider.ts +50 -0
  44. src/lib/utils/parseRenderingStrategy.ts +0 -31
  45. src/server/comfy/huggingface.ts +0 -15
  46. src/server/comfy/index.ts +0 -24
  47. src/settings/rendering/getDefaultSettingsRendering.ts +58 -5
  48. src/settings/rendering/types.ts +109 -7
  49. src/settings/rendering/useSettingsRendering.ts +261 -14
  50. src/settings/rendering/workflows/storyboard.ts +110 -0
package-lock.json CHANGED
@@ -10,8 +10,10 @@
10
  "dependencies": {
11
  "@aitube/clap": "0.0.24",
12
  "@aitube/engine": "0.0.15",
13
- "@aitube/timeline": "0.0.8",
 
14
  "@huggingface/hub": "^0.15.0",
 
15
  "@radix-ui/react-accordion": "^1.1.2",
16
  "@radix-ui/react-avatar": "^1.0.4",
17
  "@radix-ui/react-checkbox": "^1.0.4",
@@ -100,9 +102,9 @@
100
  }
101
  },
102
  "node_modules/@aitube/timeline": {
103
- "version": "0.0.8",
104
- "resolved": "https://registry.npmjs.org/@aitube/timeline/-/timeline-0.0.8.tgz",
105
- "integrity": "sha512-+Eqhdr2tGCU46r9mJ+H/so+QB6BObqerI5j3oG2iSaMSalFIgP1K8zuigMhN/FzKkESF3ORY77ciZnZupcmBDA==",
106
  "dependencies": {
107
  "date-fns": "^3.6.0",
108
  "react-virtualized-auto-sizer": "^1.0.24"
@@ -149,11 +151,11 @@
149
  }
150
  },
151
  "node_modules/@babel/code-frame": {
152
- "version": "7.24.6",
153
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.6.tgz",
154
- "integrity": "sha512-ZJhac6FkEd1yhG2AHOmfcXG4ceoLltoCVJjN5XsWN9BifBQr+cHJbWi0h68HZuSORq+3WtJ2z0hwF2NG1b5kcA==",
155
  "dependencies": {
156
- "@babel/highlight": "^7.24.6",
157
  "picocolors": "^1.0.0"
158
  },
159
  "engines": {
@@ -161,30 +163,30 @@
161
  }
162
  },
163
  "node_modules/@babel/compat-data": {
164
- "version": "7.24.6",
165
- "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.6.tgz",
166
- "integrity": "sha512-aC2DGhBq5eEdyXWqrDInSqQjO0k8xtPRf5YylULqx8MCd6jBtzqfta/3ETMRpuKIc5hyswfO80ObyA1MvkCcUQ==",
167
  "peer": true,
168
  "engines": {
169
  "node": ">=6.9.0"
170
  }
171
  },
172
  "node_modules/@babel/core": {
173
- "version": "7.24.6",
174
- "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.6.tgz",
175
- "integrity": "sha512-qAHSfAdVyFmIvl0VHELib8xar7ONuSHrE2hLnsaWkYNTI68dmi1x8GYDhJjMI/e7XWal9QBlZkwbOnkcw7Z8gQ==",
176
  "peer": true,
177
  "dependencies": {
178
  "@ampproject/remapping": "^2.2.0",
179
- "@babel/code-frame": "^7.24.6",
180
- "@babel/generator": "^7.24.6",
181
- "@babel/helper-compilation-targets": "^7.24.6",
182
- "@babel/helper-module-transforms": "^7.24.6",
183
- "@babel/helpers": "^7.24.6",
184
- "@babel/parser": "^7.24.6",
185
- "@babel/template": "^7.24.6",
186
- "@babel/traverse": "^7.24.6",
187
- "@babel/types": "^7.24.6",
188
  "convert-source-map": "^2.0.0",
189
  "debug": "^4.1.0",
190
  "gensync": "^1.0.0-beta.2",
@@ -209,11 +211,11 @@
209
  }
210
  },
211
  "node_modules/@babel/generator": {
212
- "version": "7.24.6",
213
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.6.tgz",
214
- "integrity": "sha512-S7m4eNa6YAPJRHmKsLHIDJhNAGNKoWNiWefz1MBbpnt8g9lvMDl1hir4P9bo/57bQEmuwEhnRU/AMWsD0G/Fbg==",
215
  "dependencies": {
216
- "@babel/types": "^7.24.6",
217
  "@jridgewell/gen-mapping": "^0.3.5",
218
  "@jridgewell/trace-mapping": "^0.3.25",
219
  "jsesc": "^2.5.1"
@@ -223,24 +225,24 @@
223
  }
224
  },
225
  "node_modules/@babel/helper-annotate-as-pure": {
226
- "version": "7.24.6",
227
- "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.6.tgz",
228
- "integrity": "sha512-DitEzDfOMnd13kZnDqns1ccmftwJTS9DMkyn9pYTxulS7bZxUxpMly3Nf23QQ6NwA4UB8lAqjbqWtyvElEMAkg==",
229
  "dependencies": {
230
- "@babel/types": "^7.24.6"
231
  },
232
  "engines": {
233
  "node": ">=6.9.0"
234
  }
235
  },
236
  "node_modules/@babel/helper-compilation-targets": {
237
- "version": "7.24.6",
238
- "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.6.tgz",
239
- "integrity": "sha512-VZQ57UsDGlX/5fFA7GkVPplZhHsVc+vuErWgdOiysI9Ksnw0Pbbd6pnPiR/mmJyKHgyIW0c7KT32gmhiF+cirg==",
240
  "peer": true,
241
  "dependencies": {
242
- "@babel/compat-data": "^7.24.6",
243
- "@babel/helper-validator-option": "^7.24.6",
244
  "browserslist": "^4.22.2",
245
  "lru-cache": "^5.1.1",
246
  "semver": "^6.3.1"
@@ -268,58 +270,62 @@
268
  }
269
  },
270
  "node_modules/@babel/helper-environment-visitor": {
271
- "version": "7.24.6",
272
- "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.6.tgz",
273
- "integrity": "sha512-Y50Cg3k0LKLMjxdPjIl40SdJgMB85iXn27Vk/qbHZCFx/o5XO3PSnpi675h1KEmmDb6OFArfd5SCQEQ5Q4H88g==",
 
 
 
274
  "engines": {
275
  "node": ">=6.9.0"
276
  }
277
  },
278
  "node_modules/@babel/helper-function-name": {
279
- "version": "7.24.6",
280
- "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.6.tgz",
281
- "integrity": "sha512-xpeLqeeRkbxhnYimfr2PC+iA0Q7ljX/d1eZ9/inYbmfG2jpl8Lu3DyXvpOAnrS5kxkfOWJjioIMQsaMBXFI05w==",
282
  "dependencies": {
283
- "@babel/template": "^7.24.6",
284
- "@babel/types": "^7.24.6"
285
  },
286
  "engines": {
287
  "node": ">=6.9.0"
288
  }
289
  },
290
  "node_modules/@babel/helper-hoist-variables": {
291
- "version": "7.24.6",
292
- "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.6.tgz",
293
- "integrity": "sha512-SF/EMrC3OD7dSta1bLJIlrsVxwtd0UpjRJqLno6125epQMJ/kyFmpTT4pbvPbdQHzCHg+biQ7Syo8lnDtbR+uA==",
294
  "dependencies": {
295
- "@babel/types": "^7.24.6"
296
  },
297
  "engines": {
298
  "node": ">=6.9.0"
299
  }
300
  },
301
  "node_modules/@babel/helper-module-imports": {
302
- "version": "7.24.6",
303
- "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.6.tgz",
304
- "integrity": "sha512-a26dmxFJBF62rRO9mmpgrfTLsAuyHk4e1hKTUkD/fcMfynt8gvEKwQPQDVxWhca8dHoDck+55DFt42zV0QMw5g==",
305
  "dependencies": {
306
- "@babel/types": "^7.24.6"
 
307
  },
308
  "engines": {
309
  "node": ">=6.9.0"
310
  }
311
  },
312
  "node_modules/@babel/helper-module-transforms": {
313
- "version": "7.24.6",
314
- "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.6.tgz",
315
- "integrity": "sha512-Y/YMPm83mV2HJTbX1Qh2sjgjqcacvOlhbzdCCsSlblOKjSYmQqEbO6rUniWQyRo9ncyfjT8hnUjlG06RXDEmcA==",
316
  "peer": true,
317
  "dependencies": {
318
- "@babel/helper-environment-visitor": "^7.24.6",
319
- "@babel/helper-module-imports": "^7.24.6",
320
- "@babel/helper-simple-access": "^7.24.6",
321
- "@babel/helper-split-export-declaration": "^7.24.6",
322
- "@babel/helper-validator-identifier": "^7.24.6"
323
  },
324
  "engines": {
325
  "node": ">=6.9.0"
@@ -329,80 +335,81 @@
329
  }
330
  },
331
  "node_modules/@babel/helper-plugin-utils": {
332
- "version": "7.24.6",
333
- "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.6.tgz",
334
- "integrity": "sha512-MZG/JcWfxybKwsA9N9PmtF2lOSFSEMVCpIRrbxccZFLJPrJciJdG/UhSh5W96GEteJI2ARqm5UAHxISwRDLSNg==",
335
  "engines": {
336
  "node": ">=6.9.0"
337
  }
338
  },
339
  "node_modules/@babel/helper-simple-access": {
340
- "version": "7.24.6",
341
- "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.6.tgz",
342
- "integrity": "sha512-nZzcMMD4ZhmB35MOOzQuiGO5RzL6tJbsT37Zx8M5L/i9KSrukGXWTjLe1knIbb/RmxoJE9GON9soq0c0VEMM5g==",
343
  "peer": true,
344
  "dependencies": {
345
- "@babel/types": "^7.24.6"
 
346
  },
347
  "engines": {
348
  "node": ">=6.9.0"
349
  }
350
  },
351
  "node_modules/@babel/helper-split-export-declaration": {
352
- "version": "7.24.6",
353
- "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.6.tgz",
354
- "integrity": "sha512-CvLSkwXGWnYlF9+J3iZUvwgAxKiYzK3BWuo+mLzD/MDGOZDj7Gq8+hqaOkMxmJwmlv0iu86uH5fdADd9Hxkymw==",
355
  "dependencies": {
356
- "@babel/types": "^7.24.6"
357
  },
358
  "engines": {
359
  "node": ">=6.9.0"
360
  }
361
  },
362
  "node_modules/@babel/helper-string-parser": {
363
- "version": "7.24.6",
364
- "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.6.tgz",
365
- "integrity": "sha512-WdJjwMEkmBicq5T9fm/cHND3+UlFa2Yj8ALLgmoSQAJZysYbBjw+azChSGPN4DSPLXOcooGRvDwZWMcF/mLO2Q==",
366
  "engines": {
367
  "node": ">=6.9.0"
368
  }
369
  },
370
  "node_modules/@babel/helper-validator-identifier": {
371
- "version": "7.24.6",
372
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.6.tgz",
373
- "integrity": "sha512-4yA7s865JHaqUdRbnaxarZREuPTHrjpDT+pXoAZ1yhyo6uFnIEpS8VMu16siFOHDpZNKYv5BObhsB//ycbICyw==",
374
  "engines": {
375
  "node": ">=6.9.0"
376
  }
377
  },
378
  "node_modules/@babel/helper-validator-option": {
379
- "version": "7.24.6",
380
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.6.tgz",
381
- "integrity": "sha512-Jktc8KkF3zIkePb48QO+IapbXlSapOW9S+ogZZkcO6bABgYAxtZcjZ/O005111YLf+j4M84uEgwYoidDkXbCkQ==",
382
  "peer": true,
383
  "engines": {
384
  "node": ">=6.9.0"
385
  }
386
  },
387
  "node_modules/@babel/helpers": {
388
- "version": "7.24.6",
389
- "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.6.tgz",
390
- "integrity": "sha512-V2PI+NqnyFu1i0GyTd/O/cTpxzQCYioSkUIRmgo7gFEHKKCg5w46+r/A6WeUR1+P3TeQ49dspGPNd/E3n9AnnA==",
391
  "peer": true,
392
  "dependencies": {
393
- "@babel/template": "^7.24.6",
394
- "@babel/types": "^7.24.6"
395
  },
396
  "engines": {
397
  "node": ">=6.9.0"
398
  }
399
  },
400
  "node_modules/@babel/highlight": {
401
- "version": "7.24.6",
402
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.6.tgz",
403
- "integrity": "sha512-2YnuOp4HAk2BsBrJJvYCbItHx0zWscI1C3zgWkz+wDyD9I7GIVrfnLyrR4Y1VR+7p+chAEcrgRQYZAGIKMV7vQ==",
404
  "dependencies": {
405
- "@babel/helper-validator-identifier": "^7.24.6",
406
  "chalk": "^2.4.2",
407
  "js-tokens": "^4.0.0",
408
  "picocolors": "^1.0.0"
@@ -457,9 +464,9 @@
457
  }
458
  },
459
  "node_modules/@babel/parser": {
460
- "version": "7.24.6",
461
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.6.tgz",
462
- "integrity": "sha512-eNZXdfU35nJC2h24RznROuOpO94h6x8sg9ju0tT9biNtLZ2vuP8SduLqqV+/8+cebSLV9SJEAN5Z3zQbJG/M+Q==",
463
  "bin": {
464
  "parser": "bin/babel-parser.js"
465
  },
@@ -468,11 +475,11 @@
468
  }
469
  },
470
  "node_modules/@babel/plugin-syntax-jsx": {
471
- "version": "7.24.6",
472
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.6.tgz",
473
- "integrity": "sha512-lWfvAIFNWMlCsU0DRUun2GpFwZdGTukLaHJqRh1JRb80NdAP5Sb1HDHB5X9P9OtgZHQl089UzQkpYlBq2VTPRw==",
474
  "dependencies": {
475
- "@babel/helper-plugin-utils": "^7.24.6"
476
  },
477
  "engines": {
478
  "node": ">=6.9.0"
@@ -482,9 +489,9 @@
482
  }
483
  },
484
  "node_modules/@babel/runtime": {
485
- "version": "7.24.6",
486
- "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.6.tgz",
487
- "integrity": "sha512-Ja18XcETdEl5mzzACGd+DKgaGJzPTCow7EglgwTmHdwokzDFYh/MHua6lU6DV/hjF2IaOJ4oX2nqnjG7RElKOw==",
488
  "dependencies": {
489
  "regenerator-runtime": "^0.14.0"
490
  },
@@ -493,31 +500,31 @@
493
  }
494
  },
495
  "node_modules/@babel/template": {
496
- "version": "7.24.6",
497
- "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.6.tgz",
498
- "integrity": "sha512-3vgazJlLwNXi9jhrR1ef8qiB65L1RK90+lEQwv4OxveHnqC3BfmnHdgySwRLzf6akhlOYenT+b7AfWq+a//AHw==",
499
  "dependencies": {
500
- "@babel/code-frame": "^7.24.6",
501
- "@babel/parser": "^7.24.6",
502
- "@babel/types": "^7.24.6"
503
  },
504
  "engines": {
505
  "node": ">=6.9.0"
506
  }
507
  },
508
  "node_modules/@babel/traverse": {
509
- "version": "7.24.6",
510
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.6.tgz",
511
- "integrity": "sha512-OsNjaJwT9Zn8ozxcfoBc+RaHdj3gFmCmYoQLUII1o6ZrUwku0BMg80FoOTPx+Gi6XhcQxAYE4xyjPTo4SxEQqw==",
512
- "dependencies": {
513
- "@babel/code-frame": "^7.24.6",
514
- "@babel/generator": "^7.24.6",
515
- "@babel/helper-environment-visitor": "^7.24.6",
516
- "@babel/helper-function-name": "^7.24.6",
517
- "@babel/helper-hoist-variables": "^7.24.6",
518
- "@babel/helper-split-export-declaration": "^7.24.6",
519
- "@babel/parser": "^7.24.6",
520
- "@babel/types": "^7.24.6",
521
  "debug": "^4.3.1",
522
  "globals": "^11.1.0"
523
  },
@@ -534,12 +541,12 @@
534
  }
535
  },
536
  "node_modules/@babel/types": {
537
- "version": "7.24.6",
538
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.6.tgz",
539
- "integrity": "sha512-WaMsgi6Q8zMgMth93GvWPXkhAIEobfsIkLTacoVZoK1J0CevIPGYY2Vo5YvJGqyHqXM6P4ppOYGsIRU8MM9pFQ==",
540
  "dependencies": {
541
- "@babel/helper-string-parser": "^7.24.6",
542
- "@babel/helper-validator-identifier": "^7.24.6",
543
  "to-fast-properties": "^2.0.0"
544
  },
545
  "engines": {
@@ -566,6 +573,15 @@
566
  "@jridgewell/sourcemap-codec": "^1.4.10"
567
  }
568
  },
 
 
 
 
 
 
 
 
 
569
  "node_modules/@emotion/is-prop-valid": {
570
  "version": "1.2.2",
571
  "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.2.tgz",
@@ -641,6 +657,20 @@
641
  "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
642
  }
643
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
644
  "node_modules/@floating-ui/core": {
645
  "version": "1.6.2",
646
  "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.2.tgz",
@@ -687,10 +717,21 @@
687
  "node": ">=18"
688
  }
689
  },
 
 
 
 
 
 
 
 
 
 
 
690
  "node_modules/@huggingface/tasks": {
691
- "version": "0.10.9",
692
- "resolved": "https://registry.npmjs.org/@huggingface/tasks/-/tasks-0.10.9.tgz",
693
- "integrity": "sha512-KdGnpw7sTLgr9nUwH6NrMHi/6/yBe5HdeXeKWauajseKZXwyrTYwNYIzMnh8/hE7Qa2UnseAdFMpCqe54vGd4A=="
694
  },
695
  "node_modules/@humanwhocodes/config-array": {
696
  "version": "0.11.14",
@@ -747,6 +788,31 @@
747
  "@img/sharp-libvips-darwin-arm64": "1.0.2"
748
  }
749
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
750
  "node_modules/@img/sharp-libvips-darwin-arm64": {
751
  "version": "1.0.2",
752
  "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.2.tgz",
@@ -768,6 +834,366 @@
768
  "url": "https://opencollective.com/libvips"
769
  }
770
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
771
  "node_modules/@isaacs/cliui": {
772
  "version": "8.0.2",
773
  "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
@@ -868,6 +1294,14 @@
868
  "three": ">= 0.159.0"
869
  }
870
  },
 
 
 
 
 
 
 
 
871
  "node_modules/@next/env": {
872
  "version": "14.2.3",
873
  "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.3.tgz",
@@ -1058,9 +1492,9 @@
1058
  }
1059
  },
1060
  "node_modules/@pmndrs/uikit": {
1061
- "version": "0.3.4",
1062
- "resolved": "https://registry.npmjs.org/@pmndrs/uikit/-/uikit-0.3.4.tgz",
1063
- "integrity": "sha512-2TlnuS+aYq62Sz3U+l/D+e8DDxt2v0Q8qMrILWXJWLh+42TtKUSpjugnDKgJXC9fjxrgtWFC7/Y4oREVsHALdA==",
1064
  "dependencies": {
1065
  "@preact/signals-core": "^1.5.1",
1066
  "inline-style-parser": "^0.2.3",
@@ -2443,18 +2877,19 @@
2443
  }
2444
  },
2445
  "node_modules/@react-three/uikit": {
2446
- "version": "0.3.4",
2447
- "resolved": "https://registry.npmjs.org/@react-three/uikit/-/uikit-0.3.4.tgz",
2448
- "integrity": "sha512-AYI4HIg1nJ8Z+fgcqqUWZog/TgUiemdJBr6fF2/3KP4UNb+6KsWi2PH02EZDqJ/aL0x/zZDgT5TynB9rwCEefg==",
2449
  "dependencies": {
2450
- "@pmndrs/uikit": "^0.3.4",
2451
  "@preact/signals-core": "^1.5.1",
2452
  "chalk": "^5.3.0",
2453
  "commander": "^12.0.0",
2454
  "ora": "^8.0.1",
2455
  "prettier": "^3.2.5",
2456
  "prompts": "^2.4.2",
2457
- "zod": "^3.22.4"
 
2458
  },
2459
  "bin": {
2460
  "uikit": "dist/cli/index.js"
@@ -2465,11 +2900,11 @@
2465
  }
2466
  },
2467
  "node_modules/@react-three/uikit-lucide": {
2468
- "version": "0.3.4",
2469
- "resolved": "https://registry.npmjs.org/@react-three/uikit-lucide/-/uikit-lucide-0.3.4.tgz",
2470
- "integrity": "sha512-f8TlmmZsJW/o4Lvan2B6gl9YA4qy9cUmjqJv5s+BC4Pad2GHyE4Y/YgVnGUKwFXtEA0XZDmRrICK0xZv/dlF4A==",
2471
  "dependencies": {
2472
- "@react-three/uikit": "^0.3.4"
2473
  }
2474
  },
2475
  "node_modules/@rushstack/eslint-patch": {
@@ -3315,9 +3750,9 @@
3315
  }
3316
  },
3317
  "node_modules/caniuse-lite": {
3318
- "version": "1.0.30001627",
3319
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001627.tgz",
3320
- "integrity": "sha512-4zgNiB8nTyV/tHhwZrFs88ryjls/lHiqFhrxCW4qSTeuRByBVnPYpDInchOIySWknznucaf31Z4KYqjfbrecVw==",
3321
  "funding": [
3322
  {
3323
  "type": "opencollective",
@@ -4100,9 +4535,9 @@
4100
  "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="
4101
  },
4102
  "node_modules/electron-to-chromium": {
4103
- "version": "1.4.789",
4104
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.789.tgz",
4105
- "integrity": "sha512-0VbyiaXoT++Fi2vHGo2ThOeS6X3vgRCWrjPeO2FeIAWL6ItiSJ9BqlH8LfCXe3X1IdcG+S0iLoNaxQWhfZoGzQ=="
4106
  },
4107
  "node_modules/emoji-regex": {
4108
  "version": "9.2.2",
@@ -4110,9 +4545,9 @@
4110
  "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="
4111
  },
4112
  "node_modules/enhanced-resolve": {
4113
- "version": "5.16.1",
4114
- "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.16.1.tgz",
4115
- "integrity": "sha512-4U5pNsuDl0EhuZpq46M5xPslstkviJuhrdobaRDBk2Jy2KO37FDAJl4lb2KlNabxT0m4MTK2UHNrsAcphE8nyw==",
4116
  "dependencies": {
4117
  "graceful-fs": "^4.2.4",
4118
  "tapable": "^2.2.0"
@@ -4755,6 +5190,14 @@
4755
  "node": ">=0.8.x"
4756
  }
4757
  },
 
 
 
 
 
 
 
 
4758
  "node_modules/extend": {
4759
  "version": "3.0.2",
4760
  "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
@@ -5809,9 +6252,9 @@
5809
  }
5810
  },
5811
  "node_modules/jiti": {
5812
- "version": "1.21.0",
5813
- "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz",
5814
- "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==",
5815
  "bin": {
5816
  "jiti": "bin/jiti.js"
5817
  }
@@ -6819,9 +7262,9 @@
6819
  }
6820
  },
6821
  "node_modules/prettier": {
6822
- "version": "3.3.0",
6823
- "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.0.tgz",
6824
- "integrity": "sha512-J9odKxERhCQ10OC2yb93583f6UnYutOeiV5i0zEDS7UGTdUt0u+y8erxl3lBKvwo/JHyyoEdXjwp4dke9oyZ/g==",
6825
  "bin": {
6826
  "prettier": "bin/prettier.cjs"
6827
  },
@@ -7380,6 +7823,11 @@
7380
  "url": "https://github.com/sponsors/isaacs"
7381
  }
7382
  },
 
 
 
 
 
7383
  "node_modules/run-parallel": {
7384
  "version": "1.2.0",
7385
  "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
@@ -8234,9 +8682,9 @@
8234
  }
8235
  },
8236
  "node_modules/tslib": {
8237
- "version": "2.6.2",
8238
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
8239
- "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
8240
  },
8241
  "node_modules/tunnel-rat": {
8242
  "version": "0.1.2",
@@ -8584,6 +9032,11 @@
8584
  "uuid": "dist/bin/uuid"
8585
  }
8586
  },
 
 
 
 
 
8587
  "node_modules/v8-compile-cache-lib": {
8588
  "version": "3.0.1",
8589
  "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
 
10
  "dependencies": {
11
  "@aitube/clap": "0.0.24",
12
  "@aitube/engine": "0.0.15",
13
+ "@aitube/timeline": "0.0.11",
14
+ "@fal-ai/serverless-client": "^0.10.3",
15
  "@huggingface/hub": "^0.15.0",
16
+ "@huggingface/inference": "^2.7.0",
17
  "@radix-ui/react-accordion": "^1.1.2",
18
  "@radix-ui/react-avatar": "^1.0.4",
19
  "@radix-ui/react-checkbox": "^1.0.4",
 
102
  }
103
  },
104
  "node_modules/@aitube/timeline": {
105
+ "version": "0.0.11",
106
+ "resolved": "https://registry.npmjs.org/@aitube/timeline/-/timeline-0.0.11.tgz",
107
+ "integrity": "sha512-/ndCCCdh0kY4gSObxS+cSdN+G5B2fdDKHgcAT5lrtifsenERFuWza4nUd7JbGQCS1/8AKs7OFrE6lvP243KBvw==",
108
  "dependencies": {
109
  "date-fns": "^3.6.0",
110
  "react-virtualized-auto-sizer": "^1.0.24"
 
151
  }
152
  },
153
  "node_modules/@babel/code-frame": {
154
+ "version": "7.24.7",
155
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz",
156
+ "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==",
157
  "dependencies": {
158
+ "@babel/highlight": "^7.24.7",
159
  "picocolors": "^1.0.0"
160
  },
161
  "engines": {
 
163
  }
164
  },
165
  "node_modules/@babel/compat-data": {
166
+ "version": "7.24.7",
167
+ "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.7.tgz",
168
+ "integrity": "sha512-qJzAIcv03PyaWqxRgO4mSU3lihncDT296vnyuE2O8uA4w3UHWI4S3hgeZd1L8W1Bft40w9JxJ2b412iDUFFRhw==",
169
  "peer": true,
170
  "engines": {
171
  "node": ">=6.9.0"
172
  }
173
  },
174
  "node_modules/@babel/core": {
175
+ "version": "7.24.7",
176
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.7.tgz",
177
+ "integrity": "sha512-nykK+LEK86ahTkX/3TgauT0ikKoNCfKHEaZYTUVupJdTLzGNvrblu4u6fa7DhZONAltdf8e662t/abY8idrd/g==",
178
  "peer": true,
179
  "dependencies": {
180
  "@ampproject/remapping": "^2.2.0",
181
+ "@babel/code-frame": "^7.24.7",
182
+ "@babel/generator": "^7.24.7",
183
+ "@babel/helper-compilation-targets": "^7.24.7",
184
+ "@babel/helper-module-transforms": "^7.24.7",
185
+ "@babel/helpers": "^7.24.7",
186
+ "@babel/parser": "^7.24.7",
187
+ "@babel/template": "^7.24.7",
188
+ "@babel/traverse": "^7.24.7",
189
+ "@babel/types": "^7.24.7",
190
  "convert-source-map": "^2.0.0",
191
  "debug": "^4.1.0",
192
  "gensync": "^1.0.0-beta.2",
 
211
  }
212
  },
213
  "node_modules/@babel/generator": {
214
+ "version": "7.24.7",
215
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.7.tgz",
216
+ "integrity": "sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA==",
217
  "dependencies": {
218
+ "@babel/types": "^7.24.7",
219
  "@jridgewell/gen-mapping": "^0.3.5",
220
  "@jridgewell/trace-mapping": "^0.3.25",
221
  "jsesc": "^2.5.1"
 
225
  }
226
  },
227
  "node_modules/@babel/helper-annotate-as-pure": {
228
+ "version": "7.24.7",
229
+ "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz",
230
+ "integrity": "sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==",
231
  "dependencies": {
232
+ "@babel/types": "^7.24.7"
233
  },
234
  "engines": {
235
  "node": ">=6.9.0"
236
  }
237
  },
238
  "node_modules/@babel/helper-compilation-targets": {
239
+ "version": "7.24.7",
240
+ "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.7.tgz",
241
+ "integrity": "sha512-ctSdRHBi20qWOfy27RUb4Fhp07KSJ3sXcuSvTrXrc4aG8NSYDo1ici3Vhg9bg69y5bj0Mr1lh0aeEgTvc12rMg==",
242
  "peer": true,
243
  "dependencies": {
244
+ "@babel/compat-data": "^7.24.7",
245
+ "@babel/helper-validator-option": "^7.24.7",
246
  "browserslist": "^4.22.2",
247
  "lru-cache": "^5.1.1",
248
  "semver": "^6.3.1"
 
270
  }
271
  },
272
  "node_modules/@babel/helper-environment-visitor": {
273
+ "version": "7.24.7",
274
+ "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz",
275
+ "integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==",
276
+ "dependencies": {
277
+ "@babel/types": "^7.24.7"
278
+ },
279
  "engines": {
280
  "node": ">=6.9.0"
281
  }
282
  },
283
  "node_modules/@babel/helper-function-name": {
284
+ "version": "7.24.7",
285
+ "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz",
286
+ "integrity": "sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==",
287
  "dependencies": {
288
+ "@babel/template": "^7.24.7",
289
+ "@babel/types": "^7.24.7"
290
  },
291
  "engines": {
292
  "node": ">=6.9.0"
293
  }
294
  },
295
  "node_modules/@babel/helper-hoist-variables": {
296
+ "version": "7.24.7",
297
+ "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz",
298
+ "integrity": "sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==",
299
  "dependencies": {
300
+ "@babel/types": "^7.24.7"
301
  },
302
  "engines": {
303
  "node": ">=6.9.0"
304
  }
305
  },
306
  "node_modules/@babel/helper-module-imports": {
307
+ "version": "7.24.7",
308
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz",
309
+ "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==",
310
  "dependencies": {
311
+ "@babel/traverse": "^7.24.7",
312
+ "@babel/types": "^7.24.7"
313
  },
314
  "engines": {
315
  "node": ">=6.9.0"
316
  }
317
  },
318
  "node_modules/@babel/helper-module-transforms": {
319
+ "version": "7.24.7",
320
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.7.tgz",
321
+ "integrity": "sha512-1fuJEwIrp+97rM4RWdO+qrRsZlAeL1lQJoPqtCYWv0NL115XM93hIH4CSRln2w52SqvmY5hqdtauB6QFCDiZNQ==",
322
  "peer": true,
323
  "dependencies": {
324
+ "@babel/helper-environment-visitor": "^7.24.7",
325
+ "@babel/helper-module-imports": "^7.24.7",
326
+ "@babel/helper-simple-access": "^7.24.7",
327
+ "@babel/helper-split-export-declaration": "^7.24.7",
328
+ "@babel/helper-validator-identifier": "^7.24.7"
329
  },
330
  "engines": {
331
  "node": ">=6.9.0"
 
335
  }
336
  },
337
  "node_modules/@babel/helper-plugin-utils": {
338
+ "version": "7.24.7",
339
+ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.7.tgz",
340
+ "integrity": "sha512-Rq76wjt7yz9AAc1KnlRKNAi/dMSVWgDRx43FHoJEbcYU6xOWaE2dVPwcdTukJrjxS65GITyfbvEYHvkirZ6uEg==",
341
  "engines": {
342
  "node": ">=6.9.0"
343
  }
344
  },
345
  "node_modules/@babel/helper-simple-access": {
346
+ "version": "7.24.7",
347
+ "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz",
348
+ "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==",
349
  "peer": true,
350
  "dependencies": {
351
+ "@babel/traverse": "^7.24.7",
352
+ "@babel/types": "^7.24.7"
353
  },
354
  "engines": {
355
  "node": ">=6.9.0"
356
  }
357
  },
358
  "node_modules/@babel/helper-split-export-declaration": {
359
+ "version": "7.24.7",
360
+ "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz",
361
+ "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==",
362
  "dependencies": {
363
+ "@babel/types": "^7.24.7"
364
  },
365
  "engines": {
366
  "node": ">=6.9.0"
367
  }
368
  },
369
  "node_modules/@babel/helper-string-parser": {
370
+ "version": "7.24.7",
371
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz",
372
+ "integrity": "sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==",
373
  "engines": {
374
  "node": ">=6.9.0"
375
  }
376
  },
377
  "node_modules/@babel/helper-validator-identifier": {
378
+ "version": "7.24.7",
379
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz",
380
+ "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==",
381
  "engines": {
382
  "node": ">=6.9.0"
383
  }
384
  },
385
  "node_modules/@babel/helper-validator-option": {
386
+ "version": "7.24.7",
387
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.7.tgz",
388
+ "integrity": "sha512-yy1/KvjhV/ZCL+SM7hBrvnZJ3ZuT9OuZgIJAGpPEToANvc3iM6iDvBnRjtElWibHU6n8/LPR/EjX9EtIEYO3pw==",
389
  "peer": true,
390
  "engines": {
391
  "node": ">=6.9.0"
392
  }
393
  },
394
  "node_modules/@babel/helpers": {
395
+ "version": "7.24.7",
396
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.7.tgz",
397
+ "integrity": "sha512-NlmJJtvcw72yRJRcnCmGvSi+3jDEg8qFu3z0AFoymmzLx5ERVWyzd9kVXr7Th9/8yIJi2Zc6av4Tqz3wFs8QWg==",
398
  "peer": true,
399
  "dependencies": {
400
+ "@babel/template": "^7.24.7",
401
+ "@babel/types": "^7.24.7"
402
  },
403
  "engines": {
404
  "node": ">=6.9.0"
405
  }
406
  },
407
  "node_modules/@babel/highlight": {
408
+ "version": "7.24.7",
409
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz",
410
+ "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==",
411
  "dependencies": {
412
+ "@babel/helper-validator-identifier": "^7.24.7",
413
  "chalk": "^2.4.2",
414
  "js-tokens": "^4.0.0",
415
  "picocolors": "^1.0.0"
 
464
  }
465
  },
466
  "node_modules/@babel/parser": {
467
+ "version": "7.24.7",
468
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.7.tgz",
469
+ "integrity": "sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==",
470
  "bin": {
471
  "parser": "bin/babel-parser.js"
472
  },
 
475
  }
476
  },
477
  "node_modules/@babel/plugin-syntax-jsx": {
478
+ "version": "7.24.7",
479
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.7.tgz",
480
+ "integrity": "sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ==",
481
  "dependencies": {
482
+ "@babel/helper-plugin-utils": "^7.24.7"
483
  },
484
  "engines": {
485
  "node": ">=6.9.0"
 
489
  }
490
  },
491
  "node_modules/@babel/runtime": {
492
+ "version": "7.24.7",
493
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.7.tgz",
494
+ "integrity": "sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==",
495
  "dependencies": {
496
  "regenerator-runtime": "^0.14.0"
497
  },
 
500
  }
501
  },
502
  "node_modules/@babel/template": {
503
+ "version": "7.24.7",
504
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz",
505
+ "integrity": "sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==",
506
  "dependencies": {
507
+ "@babel/code-frame": "^7.24.7",
508
+ "@babel/parser": "^7.24.7",
509
+ "@babel/types": "^7.24.7"
510
  },
511
  "engines": {
512
  "node": ">=6.9.0"
513
  }
514
  },
515
  "node_modules/@babel/traverse": {
516
+ "version": "7.24.7",
517
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.7.tgz",
518
+ "integrity": "sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA==",
519
+ "dependencies": {
520
+ "@babel/code-frame": "^7.24.7",
521
+ "@babel/generator": "^7.24.7",
522
+ "@babel/helper-environment-visitor": "^7.24.7",
523
+ "@babel/helper-function-name": "^7.24.7",
524
+ "@babel/helper-hoist-variables": "^7.24.7",
525
+ "@babel/helper-split-export-declaration": "^7.24.7",
526
+ "@babel/parser": "^7.24.7",
527
+ "@babel/types": "^7.24.7",
528
  "debug": "^4.3.1",
529
  "globals": "^11.1.0"
530
  },
 
541
  }
542
  },
543
  "node_modules/@babel/types": {
544
+ "version": "7.24.7",
545
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.7.tgz",
546
+ "integrity": "sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==",
547
  "dependencies": {
548
+ "@babel/helper-string-parser": "^7.24.7",
549
+ "@babel/helper-validator-identifier": "^7.24.7",
550
  "to-fast-properties": "^2.0.0"
551
  },
552
  "engines": {
 
573
  "@jridgewell/sourcemap-codec": "^1.4.10"
574
  }
575
  },
576
+ "node_modules/@emnapi/runtime": {
577
+ "version": "1.2.0",
578
+ "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.2.0.tgz",
579
+ "integrity": "sha512-bV21/9LQmcQeCPEg3BDFtvwL6cwiTMksYNWQQ4KOxCZikEGalWtenoZ0wCiukJINlGCIi2KXx01g4FoH/LxpzQ==",
580
+ "optional": true,
581
+ "dependencies": {
582
+ "tslib": "^2.4.0"
583
+ }
584
+ },
585
  "node_modules/@emotion/is-prop-valid": {
586
  "version": "1.2.2",
587
  "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.2.tgz",
 
657
  "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
658
  }
659
  },
660
+ "node_modules/@fal-ai/serverless-client": {
661
+ "version": "0.10.3",
662
+ "resolved": "https://registry.npmjs.org/@fal-ai/serverless-client/-/serverless-client-0.10.3.tgz",
663
+ "integrity": "sha512-Mi1TU9zjrDNuRf462fVBu8PTL4dSuIwOJYn56HQvOHx+ABhbsKD0azCALSANglRx0L6KAXSeQKXZpIAJdvowCQ==",
664
+ "dependencies": {
665
+ "@msgpack/msgpack": "^3.0.0-beta2",
666
+ "eventsource-parser": "^1.1.2",
667
+ "robot3": "^0.4.1",
668
+ "uuid-random": "^1.3.2"
669
+ },
670
+ "engines": {
671
+ "node": ">=18.0.0"
672
+ }
673
+ },
674
  "node_modules/@floating-ui/core": {
675
  "version": "1.6.2",
676
  "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.2.tgz",
 
717
  "node": ">=18"
718
  }
719
  },
720
+ "node_modules/@huggingface/inference": {
721
+ "version": "2.7.0",
722
+ "resolved": "https://registry.npmjs.org/@huggingface/inference/-/inference-2.7.0.tgz",
723
+ "integrity": "sha512-u7Fn637Q3f7nUB1tajM4CgzhvoFQkOQr5W5Fm+2wT9ETgGoLBh25BLlYPTJRjAd2WY01s71v0lqAwNvHHCc3mg==",
724
+ "dependencies": {
725
+ "@huggingface/tasks": "^0.10.0"
726
+ },
727
+ "engines": {
728
+ "node": ">=18"
729
+ }
730
+ },
731
  "node_modules/@huggingface/tasks": {
732
+ "version": "0.10.11",
733
+ "resolved": "https://registry.npmjs.org/@huggingface/tasks/-/tasks-0.10.11.tgz",
734
+ "integrity": "sha512-talNbXgxT8fsqt8DhhF7mNZxfeCc8fAJWe1yquBzd4pA4PH/J504Z41uijo36HNoI8q3KGZ89A884sIcG3ak6Q=="
735
  },
736
  "node_modules/@humanwhocodes/config-array": {
737
  "version": "0.11.14",
 
788
  "@img/sharp-libvips-darwin-arm64": "1.0.2"
789
  }
790
  },
791
+ "node_modules/@img/sharp-darwin-x64": {
792
+ "version": "0.33.4",
793
+ "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.4.tgz",
794
+ "integrity": "sha512-0l7yRObwtTi82Z6ebVI2PnHT8EB2NxBgpK2MiKJZJ7cz32R4lxd001ecMhzzsZig3Yv9oclvqqdV93jo9hy+Dw==",
795
+ "cpu": [
796
+ "x64"
797
+ ],
798
+ "optional": true,
799
+ "os": [
800
+ "darwin"
801
+ ],
802
+ "engines": {
803
+ "glibc": ">=2.26",
804
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0",
805
+ "npm": ">=9.6.5",
806
+ "pnpm": ">=7.1.0",
807
+ "yarn": ">=3.2.0"
808
+ },
809
+ "funding": {
810
+ "url": "https://opencollective.com/libvips"
811
+ },
812
+ "optionalDependencies": {
813
+ "@img/sharp-libvips-darwin-x64": "1.0.2"
814
+ }
815
+ },
816
  "node_modules/@img/sharp-libvips-darwin-arm64": {
817
  "version": "1.0.2",
818
  "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.2.tgz",
 
834
  "url": "https://opencollective.com/libvips"
835
  }
836
  },
837
+ "node_modules/@img/sharp-libvips-darwin-x64": {
838
+ "version": "1.0.2",
839
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.2.tgz",
840
+ "integrity": "sha512-Ofw+7oaWa0HiiMiKWqqaZbaYV3/UGL2wAPeLuJTx+9cXpCRdvQhCLG0IH8YGwM0yGWGLpsF4Su9vM1o6aer+Fw==",
841
+ "cpu": [
842
+ "x64"
843
+ ],
844
+ "optional": true,
845
+ "os": [
846
+ "darwin"
847
+ ],
848
+ "engines": {
849
+ "macos": ">=10.13",
850
+ "npm": ">=9.6.5",
851
+ "pnpm": ">=7.1.0",
852
+ "yarn": ">=3.2.0"
853
+ },
854
+ "funding": {
855
+ "url": "https://opencollective.com/libvips"
856
+ }
857
+ },
858
+ "node_modules/@img/sharp-libvips-linux-arm": {
859
+ "version": "1.0.2",
860
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.2.tgz",
861
+ "integrity": "sha512-iLWCvrKgeFoglQxdEwzu1eQV04o8YeYGFXtfWU26Zr2wWT3q3MTzC+QTCO3ZQfWd3doKHT4Pm2kRmLbupT+sZw==",
862
+ "cpu": [
863
+ "arm"
864
+ ],
865
+ "optional": true,
866
+ "os": [
867
+ "linux"
868
+ ],
869
+ "engines": {
870
+ "glibc": ">=2.28",
871
+ "npm": ">=9.6.5",
872
+ "pnpm": ">=7.1.0",
873
+ "yarn": ">=3.2.0"
874
+ },
875
+ "funding": {
876
+ "url": "https://opencollective.com/libvips"
877
+ }
878
+ },
879
+ "node_modules/@img/sharp-libvips-linux-arm64": {
880
+ "version": "1.0.2",
881
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.2.tgz",
882
+ "integrity": "sha512-x7kCt3N00ofFmmkkdshwj3vGPCnmiDh7Gwnd4nUwZln2YjqPxV1NlTyZOvoDWdKQVDL911487HOueBvrpflagw==",
883
+ "cpu": [
884
+ "arm64"
885
+ ],
886
+ "optional": true,
887
+ "os": [
888
+ "linux"
889
+ ],
890
+ "engines": {
891
+ "glibc": ">=2.26",
892
+ "npm": ">=9.6.5",
893
+ "pnpm": ">=7.1.0",
894
+ "yarn": ">=3.2.0"
895
+ },
896
+ "funding": {
897
+ "url": "https://opencollective.com/libvips"
898
+ }
899
+ },
900
+ "node_modules/@img/sharp-libvips-linux-s390x": {
901
+ "version": "1.0.2",
902
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.2.tgz",
903
+ "integrity": "sha512-cmhQ1J4qVhfmS6szYW7RT+gLJq9dH2i4maq+qyXayUSn9/3iY2ZeWpbAgSpSVbV2E1JUL2Gg7pwnYQ1h8rQIog==",
904
+ "cpu": [
905
+ "s390x"
906
+ ],
907
+ "optional": true,
908
+ "os": [
909
+ "linux"
910
+ ],
911
+ "engines": {
912
+ "glibc": ">=2.28",
913
+ "npm": ">=9.6.5",
914
+ "pnpm": ">=7.1.0",
915
+ "yarn": ">=3.2.0"
916
+ },
917
+ "funding": {
918
+ "url": "https://opencollective.com/libvips"
919
+ }
920
+ },
921
+ "node_modules/@img/sharp-libvips-linux-x64": {
922
+ "version": "1.0.2",
923
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.2.tgz",
924
+ "integrity": "sha512-E441q4Qdb+7yuyiADVi5J+44x8ctlrqn8XgkDTwr4qPJzWkaHwD489iZ4nGDgcuya4iMN3ULV6NwbhRZJ9Z7SQ==",
925
+ "cpu": [
926
+ "x64"
927
+ ],
928
+ "optional": true,
929
+ "os": [
930
+ "linux"
931
+ ],
932
+ "engines": {
933
+ "glibc": ">=2.26",
934
+ "npm": ">=9.6.5",
935
+ "pnpm": ">=7.1.0",
936
+ "yarn": ">=3.2.0"
937
+ },
938
+ "funding": {
939
+ "url": "https://opencollective.com/libvips"
940
+ }
941
+ },
942
+ "node_modules/@img/sharp-libvips-linuxmusl-arm64": {
943
+ "version": "1.0.2",
944
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.2.tgz",
945
+ "integrity": "sha512-3CAkndNpYUrlDqkCM5qhksfE+qSIREVpyoeHIU6jd48SJZViAmznoQQLAv4hVXF7xyUB9zf+G++e2v1ABjCbEQ==",
946
+ "cpu": [
947
+ "arm64"
948
+ ],
949
+ "optional": true,
950
+ "os": [
951
+ "linux"
952
+ ],
953
+ "engines": {
954
+ "musl": ">=1.2.2",
955
+ "npm": ">=9.6.5",
956
+ "pnpm": ">=7.1.0",
957
+ "yarn": ">=3.2.0"
958
+ },
959
+ "funding": {
960
+ "url": "https://opencollective.com/libvips"
961
+ }
962
+ },
963
+ "node_modules/@img/sharp-libvips-linuxmusl-x64": {
964
+ "version": "1.0.2",
965
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.2.tgz",
966
+ "integrity": "sha512-VI94Q6khIHqHWNOh6LLdm9s2Ry4zdjWJwH56WoiJU7NTeDwyApdZZ8c+SADC8OH98KWNQXnE01UdJ9CSfZvwZw==",
967
+ "cpu": [
968
+ "x64"
969
+ ],
970
+ "optional": true,
971
+ "os": [
972
+ "linux"
973
+ ],
974
+ "engines": {
975
+ "musl": ">=1.2.2",
976
+ "npm": ">=9.6.5",
977
+ "pnpm": ">=7.1.0",
978
+ "yarn": ">=3.2.0"
979
+ },
980
+ "funding": {
981
+ "url": "https://opencollective.com/libvips"
982
+ }
983
+ },
984
+ "node_modules/@img/sharp-linux-arm": {
985
+ "version": "0.33.4",
986
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.4.tgz",
987
+ "integrity": "sha512-RUgBD1c0+gCYZGCCe6mMdTiOFS0Zc/XrN0fYd6hISIKcDUbAW5NtSQW9g/powkrXYm6Vzwd6y+fqmExDuCdHNQ==",
988
+ "cpu": [
989
+ "arm"
990
+ ],
991
+ "optional": true,
992
+ "os": [
993
+ "linux"
994
+ ],
995
+ "engines": {
996
+ "glibc": ">=2.28",
997
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0",
998
+ "npm": ">=9.6.5",
999
+ "pnpm": ">=7.1.0",
1000
+ "yarn": ">=3.2.0"
1001
+ },
1002
+ "funding": {
1003
+ "url": "https://opencollective.com/libvips"
1004
+ },
1005
+ "optionalDependencies": {
1006
+ "@img/sharp-libvips-linux-arm": "1.0.2"
1007
+ }
1008
+ },
1009
+ "node_modules/@img/sharp-linux-arm64": {
1010
+ "version": "0.33.4",
1011
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.4.tgz",
1012
+ "integrity": "sha512-2800clwVg1ZQtxwSoTlHvtm9ObgAax7V6MTAB/hDT945Tfyy3hVkmiHpeLPCKYqYR1Gcmv1uDZ3a4OFwkdBL7Q==",
1013
+ "cpu": [
1014
+ "arm64"
1015
+ ],
1016
+ "optional": true,
1017
+ "os": [
1018
+ "linux"
1019
+ ],
1020
+ "engines": {
1021
+ "glibc": ">=2.26",
1022
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0",
1023
+ "npm": ">=9.6.5",
1024
+ "pnpm": ">=7.1.0",
1025
+ "yarn": ">=3.2.0"
1026
+ },
1027
+ "funding": {
1028
+ "url": "https://opencollective.com/libvips"
1029
+ },
1030
+ "optionalDependencies": {
1031
+ "@img/sharp-libvips-linux-arm64": "1.0.2"
1032
+ }
1033
+ },
1034
+ "node_modules/@img/sharp-linux-s390x": {
1035
+ "version": "0.33.4",
1036
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.4.tgz",
1037
+ "integrity": "sha512-h3RAL3siQoyzSoH36tUeS0PDmb5wINKGYzcLB5C6DIiAn2F3udeFAum+gj8IbA/82+8RGCTn7XW8WTFnqag4tQ==",
1038
+ "cpu": [
1039
+ "s390x"
1040
+ ],
1041
+ "optional": true,
1042
+ "os": [
1043
+ "linux"
1044
+ ],
1045
+ "engines": {
1046
+ "glibc": ">=2.31",
1047
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0",
1048
+ "npm": ">=9.6.5",
1049
+ "pnpm": ">=7.1.0",
1050
+ "yarn": ">=3.2.0"
1051
+ },
1052
+ "funding": {
1053
+ "url": "https://opencollective.com/libvips"
1054
+ },
1055
+ "optionalDependencies": {
1056
+ "@img/sharp-libvips-linux-s390x": "1.0.2"
1057
+ }
1058
+ },
1059
+ "node_modules/@img/sharp-linux-x64": {
1060
+ "version": "0.33.4",
1061
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.4.tgz",
1062
+ "integrity": "sha512-GoR++s0XW9DGVi8SUGQ/U4AeIzLdNjHka6jidVwapQ/JebGVQIpi52OdyxCNVRE++n1FCLzjDovJNozif7w/Aw==",
1063
+ "cpu": [
1064
+ "x64"
1065
+ ],
1066
+ "optional": true,
1067
+ "os": [
1068
+ "linux"
1069
+ ],
1070
+ "engines": {
1071
+ "glibc": ">=2.26",
1072
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0",
1073
+ "npm": ">=9.6.5",
1074
+ "pnpm": ">=7.1.0",
1075
+ "yarn": ">=3.2.0"
1076
+ },
1077
+ "funding": {
1078
+ "url": "https://opencollective.com/libvips"
1079
+ },
1080
+ "optionalDependencies": {
1081
+ "@img/sharp-libvips-linux-x64": "1.0.2"
1082
+ }
1083
+ },
1084
+ "node_modules/@img/sharp-linuxmusl-arm64": {
1085
+ "version": "0.33.4",
1086
+ "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.4.tgz",
1087
+ "integrity": "sha512-nhr1yC3BlVrKDTl6cO12gTpXMl4ITBUZieehFvMntlCXFzH2bvKG76tBL2Y/OqhupZt81pR7R+Q5YhJxW0rGgQ==",
1088
+ "cpu": [
1089
+ "arm64"
1090
+ ],
1091
+ "optional": true,
1092
+ "os": [
1093
+ "linux"
1094
+ ],
1095
+ "engines": {
1096
+ "musl": ">=1.2.2",
1097
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0",
1098
+ "npm": ">=9.6.5",
1099
+ "pnpm": ">=7.1.0",
1100
+ "yarn": ">=3.2.0"
1101
+ },
1102
+ "funding": {
1103
+ "url": "https://opencollective.com/libvips"
1104
+ },
1105
+ "optionalDependencies": {
1106
+ "@img/sharp-libvips-linuxmusl-arm64": "1.0.2"
1107
+ }
1108
+ },
1109
+ "node_modules/@img/sharp-linuxmusl-x64": {
1110
+ "version": "0.33.4",
1111
+ "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.4.tgz",
1112
+ "integrity": "sha512-uCPTku0zwqDmZEOi4ILyGdmW76tH7dm8kKlOIV1XC5cLyJ71ENAAqarOHQh0RLfpIpbV5KOpXzdU6XkJtS0daw==",
1113
+ "cpu": [
1114
+ "x64"
1115
+ ],
1116
+ "optional": true,
1117
+ "os": [
1118
+ "linux"
1119
+ ],
1120
+ "engines": {
1121
+ "musl": ">=1.2.2",
1122
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0",
1123
+ "npm": ">=9.6.5",
1124
+ "pnpm": ">=7.1.0",
1125
+ "yarn": ">=3.2.0"
1126
+ },
1127
+ "funding": {
1128
+ "url": "https://opencollective.com/libvips"
1129
+ },
1130
+ "optionalDependencies": {
1131
+ "@img/sharp-libvips-linuxmusl-x64": "1.0.2"
1132
+ }
1133
+ },
1134
+ "node_modules/@img/sharp-wasm32": {
1135
+ "version": "0.33.4",
1136
+ "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.4.tgz",
1137
+ "integrity": "sha512-Bmmauh4sXUsUqkleQahpdNXKvo+wa1V9KhT2pDA4VJGKwnKMJXiSTGphn0gnJrlooda0QxCtXc6RX1XAU6hMnQ==",
1138
+ "cpu": [
1139
+ "wasm32"
1140
+ ],
1141
+ "optional": true,
1142
+ "dependencies": {
1143
+ "@emnapi/runtime": "^1.1.1"
1144
+ },
1145
+ "engines": {
1146
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0",
1147
+ "npm": ">=9.6.5",
1148
+ "pnpm": ">=7.1.0",
1149
+ "yarn": ">=3.2.0"
1150
+ },
1151
+ "funding": {
1152
+ "url": "https://opencollective.com/libvips"
1153
+ }
1154
+ },
1155
+ "node_modules/@img/sharp-win32-ia32": {
1156
+ "version": "0.33.4",
1157
+ "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.4.tgz",
1158
+ "integrity": "sha512-99SJ91XzUhYHbx7uhK3+9Lf7+LjwMGQZMDlO/E/YVJ7Nc3lyDFZPGhjwiYdctoH2BOzW9+TnfqcaMKt0jHLdqw==",
1159
+ "cpu": [
1160
+ "ia32"
1161
+ ],
1162
+ "optional": true,
1163
+ "os": [
1164
+ "win32"
1165
+ ],
1166
+ "engines": {
1167
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0",
1168
+ "npm": ">=9.6.5",
1169
+ "pnpm": ">=7.1.0",
1170
+ "yarn": ">=3.2.0"
1171
+ },
1172
+ "funding": {
1173
+ "url": "https://opencollective.com/libvips"
1174
+ }
1175
+ },
1176
+ "node_modules/@img/sharp-win32-x64": {
1177
+ "version": "0.33.4",
1178
+ "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.4.tgz",
1179
+ "integrity": "sha512-3QLocdTRVIrFNye5YocZl+KKpYKP+fksi1QhmOArgx7GyhIbQp/WrJRu176jm8IxromS7RIkzMiMINVdBtC8Aw==",
1180
+ "cpu": [
1181
+ "x64"
1182
+ ],
1183
+ "optional": true,
1184
+ "os": [
1185
+ "win32"
1186
+ ],
1187
+ "engines": {
1188
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0",
1189
+ "npm": ">=9.6.5",
1190
+ "pnpm": ">=7.1.0",
1191
+ "yarn": ">=3.2.0"
1192
+ },
1193
+ "funding": {
1194
+ "url": "https://opencollective.com/libvips"
1195
+ }
1196
+ },
1197
  "node_modules/@isaacs/cliui": {
1198
  "version": "8.0.2",
1199
  "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
 
1294
  "three": ">= 0.159.0"
1295
  }
1296
  },
1297
+ "node_modules/@msgpack/msgpack": {
1298
+ "version": "3.0.0-beta2",
1299
+ "resolved": "https://registry.npmjs.org/@msgpack/msgpack/-/msgpack-3.0.0-beta2.tgz",
1300
+ "integrity": "sha512-y+l1PNV0XDyY8sM3YtuMLK5vE3/hkfId+Do8pLo/OPxfxuFAUwcGz3oiiUuV46/aBpwTzZ+mRWVMtlSKbradhw==",
1301
+ "engines": {
1302
+ "node": ">= 14"
1303
+ }
1304
+ },
1305
  "node_modules/@next/env": {
1306
  "version": "14.2.3",
1307
  "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.3.tgz",
 
1492
  }
1493
  },
1494
  "node_modules/@pmndrs/uikit": {
1495
+ "version": "0.3.6",
1496
+ "resolved": "https://registry.npmjs.org/@pmndrs/uikit/-/uikit-0.3.6.tgz",
1497
+ "integrity": "sha512-TGcOV2cJTdNFUyEWfTlxuiZmb+jZtBe+CS5ZdR7Weco3BE0m830x0M2UEkPGdw+6Ch8IzPKf5w2pEPtVPCA6QQ==",
1498
  "dependencies": {
1499
  "@preact/signals-core": "^1.5.1",
1500
  "inline-style-parser": "^0.2.3",
 
2877
  }
2878
  },
2879
  "node_modules/@react-three/uikit": {
2880
+ "version": "0.3.6",
2881
+ "resolved": "https://registry.npmjs.org/@react-three/uikit/-/uikit-0.3.6.tgz",
2882
+ "integrity": "sha512-kDKcFR+XbfUIfS7tnViMzJetA01TysZTVXJm2x3Ve+/viYJuX9ISCKFABNQ76iVWNYMhobS2VAb0/8l+shUJLA==",
2883
  "dependencies": {
2884
+ "@pmndrs/uikit": "^0.3.6",
2885
  "@preact/signals-core": "^1.5.1",
2886
  "chalk": "^5.3.0",
2887
  "commander": "^12.0.0",
2888
  "ora": "^8.0.1",
2889
  "prettier": "^3.2.5",
2890
  "prompts": "^2.4.2",
2891
+ "zod": "^3.22.4",
2892
+ "zustand": "^4.5.2"
2893
  },
2894
  "bin": {
2895
  "uikit": "dist/cli/index.js"
 
2900
  }
2901
  },
2902
  "node_modules/@react-three/uikit-lucide": {
2903
+ "version": "0.3.6",
2904
+ "resolved": "https://registry.npmjs.org/@react-three/uikit-lucide/-/uikit-lucide-0.3.6.tgz",
2905
+ "integrity": "sha512-cWzzVX7EC2in5A+NOj1i7yzAkvgYjSIM7/ZxFmMCmsB2Hw55m/Cj/IPJwx/0uzJB03EBwWc5mV+C1UTmX4ZuVA==",
2906
  "dependencies": {
2907
+ "@react-three/uikit": "^0.3.6"
2908
  }
2909
  },
2910
  "node_modules/@rushstack/eslint-patch": {
 
3750
  }
3751
  },
3752
  "node_modules/caniuse-lite": {
3753
+ "version": "1.0.30001628",
3754
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001628.tgz",
3755
+ "integrity": "sha512-S3BnR4Kh26TBxbi5t5kpbcUlLJb9lhtDXISDPwOfI+JoC+ik0QksvkZtUVyikw3hjnkgkMPSJ8oIM9yMm9vflA==",
3756
  "funding": [
3757
  {
3758
  "type": "opencollective",
 
4535
  "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="
4536
  },
4537
  "node_modules/electron-to-chromium": {
4538
+ "version": "1.4.790",
4539
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.790.tgz",
4540
+ "integrity": "sha512-eVGeQxpaBYbomDBa/Mehrs28MdvCXfJmEFzaMFsv8jH/MJDLIylJN81eTJ5kvx7B7p18OiPK0BkC06lydEy63A=="
4541
  },
4542
  "node_modules/emoji-regex": {
4543
  "version": "9.2.2",
 
4545
  "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="
4546
  },
4547
  "node_modules/enhanced-resolve": {
4548
+ "version": "5.17.0",
4549
+ "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.0.tgz",
4550
+ "integrity": "sha512-dwDPwZL0dmye8Txp2gzFmA6sxALaSvdRDjPH0viLcKrtlOL3tw62nWWweVD1SdILDTJrbrL6tdWVN58Wo6U3eA==",
4551
  "dependencies": {
4552
  "graceful-fs": "^4.2.4",
4553
  "tapable": "^2.2.0"
 
5190
  "node": ">=0.8.x"
5191
  }
5192
  },
5193
+ "node_modules/eventsource-parser": {
5194
+ "version": "1.1.2",
5195
+ "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-1.1.2.tgz",
5196
+ "integrity": "sha512-v0eOBUbiaFojBu2s2NPBfYUoRR9GjcDNvCXVaqEf5vVfpIAh9f8RCo4vXTP8c63QRKCFwoLpMpTdPwwhEKVgzA==",
5197
+ "engines": {
5198
+ "node": ">=14.18"
5199
+ }
5200
+ },
5201
  "node_modules/extend": {
5202
  "version": "3.0.2",
5203
  "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
 
6252
  }
6253
  },
6254
  "node_modules/jiti": {
6255
+ "version": "1.21.3",
6256
+ "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.3.tgz",
6257
+ "integrity": "sha512-uy2bNX5zQ+tESe+TiC7ilGRz8AtRGmnJH55NC5S0nSUjvvvM2hJHmefHErugGXN4pNv4Qx7vLsnNw9qJ9mtIsw==",
6258
  "bin": {
6259
  "jiti": "bin/jiti.js"
6260
  }
 
7262
  }
7263
  },
7264
  "node_modules/prettier": {
7265
+ "version": "3.3.1",
7266
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.1.tgz",
7267
+ "integrity": "sha512-7CAwy5dRsxs8PHXT3twixW9/OEll8MLE0VRPCJyl7CkS6VHGPSlsVaWTiASPTyGyYRyApxlaWTzwUxVNrhcwDg==",
7268
  "bin": {
7269
  "prettier": "bin/prettier.cjs"
7270
  },
 
7823
  "url": "https://github.com/sponsors/isaacs"
7824
  }
7825
  },
7826
+ "node_modules/robot3": {
7827
+ "version": "0.4.1",
7828
+ "resolved": "https://registry.npmjs.org/robot3/-/robot3-0.4.1.tgz",
7829
+ "integrity": "sha512-hzjy826lrxzx8eRgv80idkf8ua1JAepRc9Efdtj03N3KNJuznQCPlyCJ7gnUmDFwZCLQjxy567mQVKmdv2BsXQ=="
7830
+ },
7831
  "node_modules/run-parallel": {
7832
  "version": "1.2.0",
7833
  "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
 
8682
  }
8683
  },
8684
  "node_modules/tslib": {
8685
+ "version": "2.6.3",
8686
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz",
8687
+ "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ=="
8688
  },
8689
  "node_modules/tunnel-rat": {
8690
  "version": "0.1.2",
 
9032
  "uuid": "dist/bin/uuid"
9033
  }
9034
  },
9035
+ "node_modules/uuid-random": {
9036
+ "version": "1.3.2",
9037
+ "resolved": "https://registry.npmjs.org/uuid-random/-/uuid-random-1.3.2.tgz",
9038
+ "integrity": "sha512-UOzej0Le/UgkbWEO8flm+0y+G+ljUon1QWTEZOq1rnMAsxo2+SckbiZdKzAHHlVh6gJqI1TjC/xwgR50MuCrBQ=="
9039
+ },
9040
  "node_modules/v8-compile-cache-lib": {
9041
  "version": "3.0.1",
9042
  "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
package.json CHANGED
@@ -12,8 +12,10 @@
12
  "dependencies": {
13
  "@aitube/clap": "0.0.24",
14
  "@aitube/engine": "0.0.15",
15
- "@aitube/timeline": "0.0.8",
 
16
  "@huggingface/hub": "^0.15.0",
 
17
  "@radix-ui/react-accordion": "^1.1.2",
18
  "@radix-ui/react-avatar": "^1.0.4",
19
  "@radix-ui/react-checkbox": "^1.0.4",
 
12
  "dependencies": {
13
  "@aitube/clap": "0.0.24",
14
  "@aitube/engine": "0.0.15",
15
+ "@aitube/timeline": "0.0.11",
16
+ "@fal-ai/serverless-client": "^0.10.3",
17
  "@huggingface/hub": "^0.15.0",
18
+ "@huggingface/inference": "^2.7.0",
19
  "@radix-ui/react-accordion": "^1.1.2",
20
  "@radix-ui/react-avatar": "^1.0.4",
21
  "@radix-ui/react-checkbox": "^1.0.4",
src/app/api/render/providers/comfy-comfyicu/index.ts ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import Replicate from 'replicate'
2
+
3
+ import { RenderRequest } from "@/types"
4
+ import { ClapSegment, ClapSegmentCategory, ClapSegmentStatus, getClapAssetSourceType } from "@aitube/clap"
5
+ import { getVideoPrompt } from "@aitube/engine"
6
+
7
+ export async function renderSegment(request: RenderRequest): Promise<ClapSegment> {
8
+
9
+ if (request.segment.category !== ClapSegmentCategory.STORYBOARD) {
10
+ throw new Error(`Clapper doesn't support ${request.segment.category} generation for provider "Comfy.icu". Please open a pull request with (working code) to solve this!`)
11
+ }
12
+
13
+ const segment: ClapSegment = { ...request.segment }
14
+
15
+ const visualPrompt = getVideoPrompt(
16
+ request.segments,
17
+ request.entities
18
+ )
19
+
20
+ try {
21
+
22
+ throw new Error(`Not Implemented!`)
23
+
24
+ } catch (err) {
25
+ console.error(`failed to call Comfy.icu: `, err)
26
+ segment.assetUrl = ''
27
+ segment.assetSourceType = getClapAssetSourceType(segment.assetUrl)
28
+ segment.status = ClapSegmentStatus.TO_GENERATE
29
+ }
30
+
31
+ return segment
32
+ }
src/app/api/render/providers/comfy-huggingface/index.ts ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { RenderRequest } from "@/types"
2
+ import { ClapSegment, ClapSegmentCategory, ClapSegmentStatus, getClapAssetSourceType } from "@aitube/clap"
3
+ import { getVideoPrompt } from "@aitube/engine"
4
+
5
+ export async function renderSegment(request: RenderRequest): Promise<ClapSegment> {
6
+
7
+ if (request.segment.category !== ClapSegmentCategory.STORYBOARD) {
8
+ throw new Error(`Clapper doesn't support ${request.segment.category} generation for provider "Comfy Hugging Face". Please open a pull request with (working code) to solve this!`)
9
+ }
10
+
11
+ const segment: ClapSegment = { ...request.segment }
12
+
13
+ const visualPrompt = getVideoPrompt(
14
+ request.segments,
15
+ request.entities
16
+ )
17
+
18
+ try {
19
+
20
+ throw new Error(`Not Implemented!`)
21
+
22
+ } catch (err) {
23
+ console.error(`failed to call Hugging Face: `, err)
24
+ segment.assetUrl = ''
25
+ segment.assetSourceType = getClapAssetSourceType(segment.assetUrl)
26
+ segment.status = ClapSegmentStatus.TO_GENERATE
27
+ }
28
+
29
+ return segment
30
+ }
src/app/api/render/providers/comfy-replicate/index.ts ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { ClapSegment, ClapSegmentStatus, getClapAssetSourceType } from "@aitube/clap"
2
+
3
+ import { RenderRequest } from "@/types"
4
+ import { getComfyWorkflow } from "../comfy/getComfyWorkflow"
5
+ import { runWorkflow } from "./runWorkflow"
6
+
7
+ export async function renderSegment(request: RenderRequest): Promise<ClapSegment> {
8
+
9
+ const workflow = getComfyWorkflow(request)
10
+
11
+ // TODO support Hugging Face as well
12
+ // const await runWithHuggingFace({
13
+ const segment: ClapSegment = { ...request.segment }
14
+
15
+ try {
16
+ segment.assetUrl = await runWorkflow({
17
+ apiKey: request.settings.replicateApiKey,
18
+ workflow,
19
+ })
20
+ segment.assetSourceType = getClapAssetSourceType(segment.assetUrl)
21
+ } catch (err) {
22
+ console.error(`failed to call Replicate: `, err)
23
+ segment.assetUrl = ''
24
+ segment.assetSourceType = getClapAssetSourceType(segment.assetUrl)
25
+ segment.status = ClapSegmentStatus.TO_GENERATE
26
+ // request.segment.status = ClapSegmentStatus.ERROR
27
+ }
28
+
29
+ return segment
30
+ }
src/{server/comfy/replicate.ts → app/api/render/providers/comfy-replicate/runWorkflow.ts} RENAMED
@@ -1,8 +1,7 @@
1
- "use server"
2
 
3
  import Replicate from 'replicate'
4
 
5
- export async function run({
6
  apiKey,
7
  workflow
8
  }: {
@@ -13,6 +12,8 @@ export async function run({
13
  const replicate = new Replicate({ auth: apiKey })
14
 
15
  // https://replicate.com/fofr/any-comfyui-workflow
 
 
16
  const cogId = "fofr/any-comfyui-workflow:74f12621dc9f9b7cdca50d03941b8ddb3a368d7f5a1bb16fb7e1b87f05d96bf5"
17
 
18
  const output = await replicate.run(cogId, {
@@ -21,7 +22,7 @@ export async function run({
21
  }
22
  })
23
 
24
- console.log(`response:`, output)
25
 
26
- return ""
27
  }
 
 
1
 
2
  import Replicate from 'replicate'
3
 
4
+ export async function runWorkflow({
5
  apiKey,
6
  workflow
7
  }: {
 
12
  const replicate = new Replicate({ auth: apiKey })
13
 
14
  // https://replicate.com/fofr/any-comfyui-workflow
15
+ // https://replicate.com/guides/comfyui/run-comfyui-on-replicate
16
+
17
  const cogId = "fofr/any-comfyui-workflow:74f12621dc9f9b7cdca50d03941b8ddb3a368d7f5a1bb16fb7e1b87f05d96bf5"
18
 
19
  const output = await replicate.run(cogId, {
 
22
  }
23
  })
24
 
25
+ console.log(`response from Replicate:`, output)
26
 
27
+ return output as any
28
  }
src/{server → app/api/render/providers}/comfy/getComfyWorkflow.ts RENAMED
@@ -9,9 +9,9 @@ export function getComfyWorkflow(request: RenderRequest) {
9
  let comfyWorkflow = "{}"
10
 
11
  if (request.segment.category === ClapSegmentCategory.STORYBOARD) {
12
- comfyWorkflow = request.storyboardWorkflow
13
  } else if (request.segment.category === ClapSegmentCategory.VIDEO) {
14
- comfyWorkflow = request.videoWorkflow
15
  }
16
 
17
  // parse the node array from the ComfyUI workflow
@@ -22,13 +22,21 @@ export function getComfyWorkflow(request: RenderRequest) {
22
  request.entities
23
  )
24
 
25
- for (const node of nodes) {
 
 
26
  if (typeof node.inputs.text === "string") {
27
  if (node._meta.title.includes("Prompt")) {
28
  node.inputs.text = visualPrompt
29
  }
30
  }
31
- }
32
-
33
- return JSON.stringify(nodes)
 
 
 
 
 
 
34
  }
 
9
  let comfyWorkflow = "{}"
10
 
11
  if (request.segment.category === ClapSegmentCategory.STORYBOARD) {
12
+ comfyWorkflow = request.settings.comfyWorkflowForStoryboard
13
  } else if (request.segment.category === ClapSegmentCategory.VIDEO) {
14
+ comfyWorkflow = request.settings.comfyWorkflowForVideo
15
  }
16
 
17
  // parse the node array from the ComfyUI workflow
 
22
  request.entities
23
  )
24
 
25
+ const output: Record<string, ComfyNode> = {}
26
+
27
+ nodes.forEach((node, i) => {
28
  if (typeof node.inputs.text === "string") {
29
  if (node._meta.title.includes("Prompt")) {
30
  node.inputs.text = visualPrompt
31
  }
32
  }
33
+ output[`${i}`] = node
34
+ })
35
+
36
+ console.log("DEBUG:", {
37
+ nodes,
38
+ output
39
+ })
40
+
41
+ return JSON.stringify(output)
42
  }
src/app/api/render/providers/falai/index.ts ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import * as fal from '@fal-ai/serverless-client'
2
+
3
+ import { RenderRequest } from "@/types"
4
+ import { ClapSegment, ClapSegmentCategory, ClapSegmentStatus, getClapAssetSourceType } from "@aitube/clap"
5
+ import { getVideoPrompt } from "@aitube/engine"
6
+ import { fetchContentToBase64 } from '@/lib/utils/fetchContentToBase64'
7
+
8
+ export async function renderSegment(request: RenderRequest): Promise<ClapSegment> {
9
+
10
+ if (request.segment.category !== ClapSegmentCategory.STORYBOARD) {
11
+ throw new Error(`Clapper doesn't support ${request.segment.category} generation for provider "Fal.ai". Please open a pull request with (working code) to solve this!`)
12
+ }
13
+
14
+ fal.config({
15
+ credentials: request.settings.falAiApiKey
16
+ })
17
+
18
+ const segment: ClapSegment = { ...request.segment }
19
+
20
+ const visualPrompt = getVideoPrompt(
21
+ request.segments,
22
+ request.entities
23
+ )
24
+
25
+ try {
26
+
27
+ const result = await fal.subscribe(request.settings.falAiModelForImage, {
28
+ input: {
29
+ prompt: visualPrompt
30
+ },
31
+ logs: true,
32
+ onQueueUpdate: (update) => {
33
+ if (update.status === "IN_PROGRESS") {
34
+ update.logs?.map((log) => log.message).forEach(console.log);
35
+ }
36
+ },
37
+ }) as {
38
+ prompt: string;
39
+ images: { url: string; content_type: string }[]
40
+ }
41
+
42
+ // {
43
+ // "images": [
44
+ // {
45
+ // "url": "",
46
+ // "content_type": "image/jpeg"
47
+ // }
48
+ // ],
49
+ // "prompt": ""
50
+ // }
51
+
52
+ console.log(`response from Fal.ai:`, result)
53
+
54
+ // TODO: this might be also in videos, since we are gonna generate videos as well
55
+ const content = result.images[0]?.url || ""
56
+
57
+ segment.assetUrl = await fetchContentToBase64(content)
58
+ segment.assetSourceType = getClapAssetSourceType(segment.assetUrl)
59
+ } catch (err) {
60
+ console.error(`failed to call Fal.ai: `, err)
61
+ segment.assetUrl = ''
62
+ segment.assetSourceType = getClapAssetSourceType(segment.assetUrl)
63
+ segment.status = ClapSegmentStatus.TO_GENERATE
64
+ }
65
+
66
+ return segment
67
+ }
src/app/api/render/providers/huggingface/index.ts ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { HfInference, HfInferenceEndpoint } from "@huggingface/inference"
2
+
3
+ import { RenderRequest } from "@/types"
4
+ import { ClapSegment, ClapSegmentCategory, ClapSegmentStatus, getClapAssetSourceType } from "@aitube/clap"
5
+ import { getVideoPrompt } from "@aitube/engine"
6
+ import { blobToBase64DataUri } from "@/lib/utils/blobToBase64DataUri"
7
+
8
+ export async function renderSegment(request: RenderRequest): Promise<ClapSegment> {
9
+
10
+ const hf: HfInferenceEndpoint = new HfInference(request.settings.huggingFaceApiKey)
11
+
12
+ if (request.segment.category !== ClapSegmentCategory.STORYBOARD) {
13
+ throw new Error(`Clapper doesn't support ${request.segment.category} generation for provider "Hugging Face". Please open a pull request with (working code) to solve this!`)
14
+ }
15
+
16
+ const segment: ClapSegment = { ...request.segment }
17
+
18
+ try {
19
+ const blob: Blob = await hf.textToImage({
20
+ model: request.settings.huggingFaceModelForImage,
21
+ inputs: getVideoPrompt(
22
+ request.segments,
23
+ request.entities
24
+ )
25
+ })
26
+
27
+ segment.assetUrl = await blobToBase64DataUri(blob)
28
+ segment.assetSourceType = getClapAssetSourceType(segment.assetUrl)
29
+ } catch (err) {
30
+ console.error(`failed to call Replicate: `, err)
31
+ segment.assetUrl = ''
32
+ segment.assetSourceType = getClapAssetSourceType(segment.assetUrl)
33
+ segment.status = ClapSegmentStatus.TO_GENERATE
34
+ }
35
+
36
+ return segment
37
+ }
src/app/api/render/providers/modelslab/index.ts ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { RenderRequest } from "@/types"
2
+ import { ClapSegment, ClapSegmentCategory, ClapSegmentStatus, getClapAssetSourceType } from "@aitube/clap"
3
+ import { getVideoPrompt } from "@aitube/engine"
4
+
5
+ export async function renderSegment(request: RenderRequest): Promise<ClapSegment> {
6
+
7
+ if (request.segment.category !== ClapSegmentCategory.STORYBOARD) {
8
+ throw new Error(`Clapper doesn't support ${request.segment.category} generation for provider "ModelsLab". Please open a pull request with (working code) to solve this!`)
9
+ }
10
+
11
+ const segment: ClapSegment = { ...request.segment }
12
+
13
+ const visualPrompt = getVideoPrompt(
14
+ request.segments,
15
+ request.entities
16
+ )
17
+
18
+ try {
19
+
20
+ throw new Error(`Not Implemented!`)
21
+
22
+ } catch (err) {
23
+ console.error(`failed to call ModelsLab: `, err)
24
+ segment.assetUrl = ''
25
+ segment.assetSourceType = getClapAssetSourceType(segment.assetUrl)
26
+ segment.status = ClapSegmentStatus.TO_GENERATE
27
+ }
28
+
29
+ return segment
30
+ }
src/app/api/render/providers/replicate/index.ts ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import Replicate from 'replicate'
2
+
3
+ import { RenderRequest } from "@/types"
4
+ import { ClapSegment, ClapSegmentCategory, ClapSegmentStatus, getClapAssetSourceType } from "@aitube/clap"
5
+ import { getVideoPrompt } from "@aitube/engine"
6
+ import { fetchContentToBase64 } from '@/lib/utils/fetchContentToBase64'
7
+
8
+ export async function renderSegment(request: RenderRequest): Promise<ClapSegment> {
9
+
10
+ const replicate = new Replicate({ auth: request.settings.huggingFaceApiKey })
11
+
12
+ if (request.segment.category !== ClapSegmentCategory.STORYBOARD) {
13
+ throw new Error(`Clapper doesn't support ${request.segment.category} generation for provider "Replicate". Please open a pull request with (working code) to solve this!`)
14
+ }
15
+
16
+ const segment: ClapSegment = { ...request.segment }
17
+
18
+ try {
19
+
20
+ const output = await replicate.run(
21
+ request.settings.replicateModelForImage as any, {
22
+ input: {
23
+ prompt: getVideoPrompt(
24
+ request.segments,
25
+ request.entities
26
+ )
27
+ }
28
+ })
29
+
30
+ console.log(`Replicate replied: `, output)
31
+
32
+ segment.assetUrl = await fetchContentToBase64(`${output}`)
33
+ segment.assetSourceType = getClapAssetSourceType(segment.assetUrl)
34
+ } catch (err) {
35
+ console.error(`failed to call Replicate: `, err)
36
+ segment.assetUrl = ''
37
+ segment.assetSourceType = getClapAssetSourceType(segment.assetUrl)
38
+ segment.status = ClapSegmentStatus.TO_GENERATE
39
+ }
40
+
41
+ return segment
42
+ }
src/app/api/render/route.ts ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { NextResponse, NextRequest } from "next/server"
2
+
3
+ import { renderSegment as renderSegmentUsingHuggingFace } from "./providers/huggingface"
4
+ import { renderSegment as renderSegmentUsingComfyReplicate } from "./providers/comfy-replicate"
5
+ import { renderSegment as renderSegmentUsingReplicate } from "./providers/replicate"
6
+ import { renderSegment as renderSegmentUsingComfyComfyIcu } from "./providers/comfy-comfyicu"
7
+ import { renderSegment as renderSegmentUsingFalAi } from "./providers/falai"
8
+ import { renderSegment as renderSegmentUsingModelsLab } from "./providers/modelslab"
9
+
10
+ import { ComputeProvider, RenderRequest } from "@/types"
11
+ import { ClapSegmentCategory } from "@aitube/clap"
12
+
13
+ export async function POST(req: NextRequest) {
14
+ // do we really need to secure it?
15
+ // I mean.. in the end, the user is using their own credentials,
16
+ // so they cannot siphon free OpenAI, HF, Replicate tokens
17
+ console.log(`TODO Julian: secure the endpoint`)
18
+ // await throwIfInvalidToken(req.headers.get("Authorization"))
19
+ const request = (await req.json()) as RenderRequest
20
+
21
+ const provider =
22
+ request.segment.category === ClapSegmentCategory.STORYBOARD
23
+ ? request.settings.storyboardProvider
24
+ : request.segment.category === ClapSegmentCategory.VIDEO
25
+ ? request.settings.videoProvider
26
+ : request.segment.category === ClapSegmentCategory.DIALOGUE
27
+ ? request.settings.speechProvider
28
+ : request.segment.category === ClapSegmentCategory.SOUND
29
+ ? request.settings.soundProvider
30
+ : request.segment.category === ClapSegmentCategory.MUSIC
31
+ ? request.settings.musicProvider
32
+ : null
33
+
34
+ if (!provider) { throw new Error(`Segments of category ${request.segment.category} are not supported yet`)}
35
+
36
+ const renderSegment =
37
+ provider === ComputeProvider.HUGGINGFACE
38
+ ? renderSegmentUsingHuggingFace
39
+ : provider === ComputeProvider.COMFY_HUGGINGFACE
40
+ ? renderSegmentUsingComfyReplicate
41
+ : provider === ComputeProvider.REPLICATE
42
+ ? renderSegmentUsingReplicate
43
+ : provider === ComputeProvider.COMFY_COMFYICU
44
+ ? renderSegmentUsingComfyComfyIcu
45
+ : provider === ComputeProvider.FALAI
46
+ ? renderSegmentUsingFalAi
47
+ : provider === ComputeProvider.MODELSLAB
48
+ ? renderSegmentUsingModelsLab
49
+ : null
50
+
51
+ if (!renderSegment) { throw new Error(`Provider ${provider} is not supported yet`)}
52
+
53
+ const segment = await renderSegment(request)
54
+
55
+ return NextResponse.json(segment)
56
+ }
src/app/main.tsx CHANGED
@@ -16,9 +16,12 @@ import { TopBar } from "@/components/interface/top-bar"
16
  import { useTimelineState } from "@aitube/timeline"
17
  import { SettingsDialog } from "@/components/settings"
18
  import { LoadingDialog } from "@/components/interface/loader/LoadingDialog"
 
19
 
20
  export function Main() {
21
  const isEmpty = useTimelineState(s => s.isEmpty)
 
 
22
  return (
23
  <TooltipProvider>
24
  <div className={cn(`
@@ -42,11 +45,16 @@ export function Main() {
42
  isEmpty ? "opacity-0" : "opacity-100"
43
  )}>
44
  <ReflexContainer orientation="horizontal">
45
- <ReflexElement>
 
46
  <RenderClap />
47
  </ReflexElement>
48
  <ReflexSplitter />
49
- <ReflexElement>
 
 
 
 
50
  <Timeline />
51
  </ReflexElement>
52
  </ReflexContainer>
 
16
  import { useTimelineState } from "@aitube/timeline"
17
  import { SettingsDialog } from "@/components/settings"
18
  import { LoadingDialog } from "@/components/interface/loader/LoadingDialog"
19
+ import { useSettingsView } from "@/settings/view"
20
 
21
  export function Main() {
22
  const isEmpty = useTimelineState(s => s.isEmpty)
23
+ const showTimeline = useSettingsView((s) => s.showTimeline)
24
+
25
  return (
26
  <TooltipProvider>
27
  <div className={cn(`
 
45
  isEmpty ? "opacity-0" : "opacity-100"
46
  )}>
47
  <ReflexContainer orientation="horizontal">
48
+ <ReflexElement
49
+ >
50
  <RenderClap />
51
  </ReflexElement>
52
  <ReflexSplitter />
53
+ <ReflexElement
54
+ size={showTimeline ? 600 : 1}
55
+ minSize={showTimeline ? 150 : 1}
56
+ maxSize={showTimeline ? 1200 : 1}
57
+ >
58
  <Timeline />
59
  </ReflexElement>
60
  </ReflexContainer>
src/components/form/form-file.tsx CHANGED
@@ -47,7 +47,7 @@ export function FormFile({
47
  <Input
48
  ref={ref}
49
  placeholder={`${placeholder || ""}`}
50
- className={cn(`w-full md:w-52 lg:w-56 xl:w-64 font-light text-base`, className)}
51
  disabled={disabled}
52
  onChange={handleChange}
53
  type="file"
 
47
  <Input
48
  ref={ref}
49
  placeholder={`${placeholder || ""}`}
50
+ className={cn(`w-full md:w-60 lg:w-64 xl:w-80 font-light text-base`, className)}
51
  disabled={disabled}
52
  onChange={handleChange}
53
  type="file"
src/components/form/form-input.tsx CHANGED
@@ -93,7 +93,7 @@ export function FormInput<T>({
93
  <Input
94
  ref={ref}
95
  placeholder={`${placeholder || defaultValue || ""}`}
96
- className={cn(`w-full md:w-52 lg:w-56 xl:w-64 font-light text-base`, className)}
97
  disabled={disabled}
98
  onChange={handleChange}
99
  // {...props}
 
93
  <Input
94
  ref={ref}
95
  placeholder={`${placeholder || defaultValue || ""}`}
96
+ className={cn(`w-full md:w-60 lg:w-64 xl:w-80 font-light text-base`, className)}
97
  disabled={disabled}
98
  onChange={handleChange}
99
  // {...props}
src/components/form/form-select.tsx CHANGED
@@ -49,7 +49,7 @@ export function FormSelect<T>({
49
  onSelect(selectedItem?.value)
50
  }}
51
  defaultValue={selectedItemId}>
52
- <SelectTrigger className="w-full md:w-52 lg:w-56 xl:w-64 font-light text-base">
53
  <SelectValue placeholder={selectedItemLabel} />
54
  </SelectTrigger>
55
  <SelectContent>
 
49
  onSelect(selectedItem?.value)
50
  }}
51
  defaultValue={selectedItemId}>
52
+ <SelectTrigger className="w-full md:w-60 lg:w-64 xl:w-80 font-light text-base">
53
  <SelectValue placeholder={selectedItemLabel} />
54
  </SelectTrigger>
55
  <SelectContent>
src/components/interface/loader/index.tsx CHANGED
@@ -12,7 +12,7 @@ export function Loader({
12
  return (
13
  <div className={cn(`
14
  fixed
15
- z-50
16
  flex
17
  w-screen h-screen
18
  top-0 left-0 right-0 bottom-0
 
12
  return (
13
  <div className={cn(`
14
  fixed
15
+ z-[100]
16
  flex
17
  w-screen h-screen
18
  top-0 left-0 right-0 bottom-0
src/components/interface/timeline/index.tsx CHANGED
@@ -1,8 +1,62 @@
1
- import { ClapTimeline } from "@aitube/timeline"
2
-
 
3
  import { cn } from "@/lib/utils"
4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
  export function Timeline() {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
  return (
7
  <ClapTimeline
8
  showFPS={false}
 
1
+ import { useEffect, useTransition } from "react"
2
+ import { ClapSegment } from "@aitube/clap"
3
+ import { ClapTimeline, useTimelineState, SegmentRenderer } from "@aitube/timeline"
4
  import { cn } from "@/lib/utils"
5
 
6
+ import { useSettingsRendering } from "@/settings/rendering"
7
+ import { RenderRequest } from "@/types"
8
+
9
+ const segmentRenderer: SegmentRenderer = async ({
10
+ segment,
11
+ segments,
12
+ entities,
13
+ }) => {
14
+
15
+ console.log(`custom segmentRender() called with:`, { segment, segments, entities })
16
+ const request: RenderRequest = {
17
+ settings: useSettingsRendering.getState().getSettings(),
18
+ segment,
19
+ segments,
20
+ entities,
21
+ }
22
+
23
+ const res = await fetch("/api/render", {
24
+ method: "POST",
25
+ headers: {
26
+ "Content-Type": "application/json",
27
+ },
28
+ body: JSON.stringify(request)
29
+ })
30
+
31
+ const newSegment = (await res.json()) as ClapSegment
32
+
33
+ return newSegment
34
+ }
35
+
36
  export function Timeline() {
37
+ const [_isPending, startTransition] = useTransition()
38
+
39
+ const isReady = useTimelineState(s => s.isReady)
40
+
41
+ const storyboardRenderingStrategy = useSettingsRendering(s => s.storyboardRenderingStrategy)
42
+ const setStoryboardRenderingStrategy = useTimelineState(s => s.setStoryboardRenderingStrategy)
43
+ useEffect(() => {
44
+ if (isReady) setStoryboardRenderingStrategy(storyboardRenderingStrategy)
45
+ }, [isReady, setStoryboardRenderingStrategy, storyboardRenderingStrategy])
46
+
47
+ const videoRenderingStrategy = useSettingsRendering(s => s.videoRenderingStrategy)
48
+ const setVideoRenderingStrategy = useTimelineState(s => s.setVideoRenderingStrategy)
49
+ useEffect(() => {
50
+ if (isReady) setVideoRenderingStrategy(videoRenderingStrategy)
51
+ }, [isReady, setVideoRenderingStrategy, videoRenderingStrategy])
52
+
53
+ const getSettings = useSettingsRendering(s => s.getSettings)
54
+ const setSegmentRenderer = useTimelineState(s => s.setSegmentRenderer)
55
+
56
+ useEffect(() => {
57
+ setSegmentRenderer(segmentRenderer)
58
+ }, [isReady])
59
+
60
  return (
61
  <ClapTimeline
62
  showFPS={false}
src/components/interface/top-menu/index.tsx CHANGED
@@ -2,19 +2,14 @@ import { Menubar } from "@/components/ui/menubar"
2
 
3
  import { TopMenuFile } from "./file"
4
  import { TopMenuView } from "./view"
5
- import { TopMenuRendering } from "./rendering"
6
 
7
  export function TopMenu() {
8
  return (
9
  <Menubar>
10
  <TopMenuFile />
11
- {/*
12
- <TopMenuEdit />
13
- <TopMenuPlayback />
14
- <TopMenuAssistant />
15
- */}
16
- <TopMenuRendering />
17
- {/*<TopMenuView />*/}
18
  </Menubar>
19
  )
20
  }
 
2
 
3
  import { TopMenuFile } from "./file"
4
  import { TopMenuView } from "./view"
5
+ import { TopMenuSettings } from "./settings"
6
 
7
  export function TopMenu() {
8
  return (
9
  <Menubar>
10
  <TopMenuFile />
11
+ <TopMenuSettings />
12
+ <TopMenuView />
 
 
 
 
 
13
  </Menubar>
14
  )
15
  }
src/components/interface/top-menu/{rendering → settings}/index.tsx RENAMED
@@ -14,10 +14,10 @@ import {
14
  MenubarTrigger
15
  } from "@/components/ui/menubar"
16
  import { useSettingsRendering } from "@/settings/rendering"
17
- import { RenderingStrategy } from "@/types"
18
  import { useSettingsView } from "@/settings/view"
19
 
20
- export function TopMenuRendering() {
21
  const setShowSettings = useSettingsView(s => s.setShowSettings)
22
 
23
  const storyboardRenderingStrategy = useSettingsRendering((s) => s.storyboardRenderingStrategy)
@@ -35,7 +35,7 @@ export function TopMenuRendering() {
35
 
36
  return (
37
  <MenubarMenu>
38
- <MenubarTrigger>Rendering</MenubarTrigger>
39
  <MenubarContent>
40
 
41
  <MenubarSub>
 
14
  MenubarTrigger
15
  } from "@/components/ui/menubar"
16
  import { useSettingsRendering } from "@/settings/rendering"
17
+ import { RenderingStrategy } from "@aitube/timeline"
18
  import { useSettingsView } from "@/settings/view"
19
 
20
+ export function TopMenuSettings() {
21
  const setShowSettings = useSettingsView(s => s.setShowSettings)
22
 
23
  const storyboardRenderingStrategy = useSettingsRendering((s) => s.storyboardRenderingStrategy)
 
35
 
36
  return (
37
  <MenubarMenu>
38
+ <MenubarTrigger>Settings</MenubarTrigger>
39
  <MenubarContent>
40
 
41
  <MenubarSub>
src/components/interface/top-menu/view/index.tsx CHANGED
@@ -55,6 +55,8 @@ export function TopMenuView() {
55
  }}>
56
  Toggle fullscreen
57
  </MenubarCheckboxItem>
 
 
58
  <MenubarSeparator />
59
  <MenubarCheckboxItem
60
  checked={showTimeline}
@@ -65,6 +67,7 @@ export function TopMenuView() {
65
  return false
66
  }}
67
  >Show timeline</MenubarCheckboxItem>
 
68
  <MenubarCheckboxItem
69
  checked={showExplorer}
70
  onClick={(e) => {
@@ -92,6 +95,7 @@ export function TopMenuView() {
92
  return false
93
  }}
94
  >Show video player</MenubarCheckboxItem>
 
95
  </MenubarContent>
96
  </MenubarMenu>
97
  )
 
55
  }}>
56
  Toggle fullscreen
57
  </MenubarCheckboxItem>
58
+
59
+ {/*
60
  <MenubarSeparator />
61
  <MenubarCheckboxItem
62
  checked={showTimeline}
 
67
  return false
68
  }}
69
  >Show timeline</MenubarCheckboxItem>
70
+
71
  <MenubarCheckboxItem
72
  checked={showExplorer}
73
  onClick={(e) => {
 
95
  return false
96
  }}
97
  >Show video player</MenubarCheckboxItem>
98
+ */}
99
  </MenubarContent>
100
  </MenubarMenu>
101
  )
src/components/settings/SettingsSectionRendering.tsx DELETED
@@ -1,68 +0,0 @@
1
- import { FormSection } from "@/components/form/form-section"
2
- import { useSettingsRendering } from "@/settings/rendering"
3
- import { FormSelect } from "../form/form-select"
4
- import { ComfyVendor } from "@/types"
5
- import { FormInput } from "../form/form-input"
6
- import { APP_NAME } from "@/lib/core/constants"
7
-
8
- export function SettingsSectionRendering() {
9
-
10
- const comfyUiApiVendor = useSettingsRendering(s => s.comfyUiApiVendor)
11
- const setComfyUiApiVendor = useSettingsRendering(s => s.setComfyUiApiVendor)
12
-
13
- const comfyUiApiKey = useSettingsRendering(s => s.comfyUiApiKey)
14
- const setComfyUiApiKey = useSettingsRendering(s => s.setComfyUiApiKey)
15
-
16
- const storyboardRenderingStrategy = useSettingsRendering(s => s.storyboardRenderingStrategy)
17
- const setStoryboardRenderingStrategy = useSettingsRendering(s => s.setStoryboardRenderingStrategy)
18
-
19
- const videoRenderingStrategy = useSettingsRendering(s => s.videoRenderingStrategy)
20
- const setVideoRenderingStrategy = useSettingsRendering(s => s.setVideoRenderingStrategy)
21
-
22
- const maxNbAssetsToGenerateInParallel = useSettingsRendering(s => s.maxNbAssetsToGenerateInParallel)
23
- const setMaxNbAssetsToGenerateInParallel = useSettingsRendering(s => s.setMaxNbAssetsToGenerateInParallel)
24
-
25
- const availableComfyUiApiVendors = {
26
- [ComfyVendor.NONE]: "No provider",
27
- // [ComfyVendor.REPLICATE]: "Replicate",
28
- // [ComfyVendor.HUGGINGFACE]: "HuggingFace",
29
- // [ComfyVendor.CUSTOM]: "Custom server",
30
- }
31
-
32
- return (
33
- <div className="flex flex-col space-y-6 justify-between">
34
- <FormSection label="Rendering service provider">
35
- <FormSelect<ComfyVendor>
36
- label="Service provider for ComfyUI"
37
- selectedItemId={comfyUiApiVendor}
38
- selectedItemLabel={
39
- (availableComfyUiApiVendors as any)[comfyUiApiVendor]
40
- || ComfyVendor.NONE
41
- }
42
- items={Object.entries(availableComfyUiApiVendors).map(([vendor, label]) => ({
43
- id: vendor,
44
- label,
45
- disabled: (vendor as ComfyVendor) === ComfyVendor.HUGGINGFACE || (vendor as ComfyVendor) === ComfyVendor.CUSTOM,
46
- value: vendor as ComfyVendor,
47
- }))}
48
- onSelect={setComfyUiApiVendor}
49
- horizontal
50
- />
51
-
52
- {comfyUiApiVendor === ComfyVendor.REPLICATE && (
53
- <>
54
- <FormInput
55
- label="Replicate API key"
56
- value={comfyUiApiKey}
57
- defaultValue={""}
58
- onChange={setComfyUiApiKey}
59
- />
60
- <p className="italic text-sm text-stone-500">
61
- Note: preferences and credentials are stored inside your browser local storage. {APP_NAME} uses them to perform API calls on your behalf, then forget them immediately.
62
- </p>
63
- </>
64
- )}
65
- </FormSection>
66
- </div>
67
- )
68
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/components/settings/assistant.tsx ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { FormSection } from "@/components/form/form-section"
2
+ import { useSettingsRendering } from "@/settings/rendering"
3
+ import { ComputeProvider } from "@/types"
4
+
5
+ import { FormSelect } from "../form/form-select"
6
+ import { availableComputeProvidersForAssistant } from "./constants"
7
+
8
+ export function SettingsSectionAssistant() {
9
+ const assistantProvider = useSettingsRendering(s => s.assistantProvider)
10
+ const setAssistantProvider = useSettingsRendering(s => s.setAssistantProvider)
11
+
12
+ return (
13
+ <div className="flex flex-col space-y-6 justify-between">
14
+ <FormSection label="AI Assistant">
15
+
16
+ <FormSelect<ComputeProvider>
17
+ label="Assistant provider"
18
+ selectedItemId={assistantProvider}
19
+ selectedItemLabel={
20
+ (availableComputeProvidersForAssistant as any)[assistantProvider]
21
+ || ComputeProvider.NONE
22
+ }
23
+ items={Object.entries(availableComputeProvidersForAssistant).map(([provider, label]) => ({
24
+ id: provider,
25
+ label,
26
+ disabled: false,
27
+ value: provider as ComputeProvider,
28
+ }))}
29
+ onSelect={setAssistantProvider}
30
+ horizontal
31
+ />
32
+ </FormSection>
33
+ </div>
34
+ )
35
+ }
src/components/settings/constants.ts ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { ComfyIcuAccelerator, ComputeProvider } from "@/types"
2
+
3
+ export const availableComputeProviders = {
4
+ [ComputeProvider.NONE]: "No default provider",
5
+ [ComputeProvider.HUGGINGFACE]: "HuggingFace",
6
+ [ComputeProvider.REPLICATE]: "Replicate (Cog & ComfyUI)",
7
+ [ComputeProvider.COMFY_COMFYICU]: "Comfy.icu (ComfyUI workflow)",
8
+ [ComputeProvider.FALAI]: "Fal.ai",
9
+ [ComputeProvider.MODELSLAB]: "ModelsLab",
10
+ // [ComputeProvider.CUSTOM]: "Custom server",
11
+ }
12
+
13
+ export const availableComputeProvidersForAssistant = {
14
+ [ComputeProvider.NONE]: "No assistant provider",
15
+ [ComputeProvider.HUGGINGFACE]: "Hugging Face (Inference API)",
16
+ [ComputeProvider.GROQ]: "Groq",
17
+ [ComputeProvider.OPENAI]: "OpenAI (ChatGPT)",
18
+ }
19
+
20
+ export const availableComputeProvidersForStoryboards = {
21
+ [ComputeProvider.NONE]: "No storyboard provider",
22
+ [ComputeProvider.HUGGINGFACE]: "HuggingFace",
23
+ [ComputeProvider.REPLICATE]: "Replicate (Cog API)",
24
+ [ComputeProvider.COMFY_REPLICATE]: "Replicate (Comfy API)",
25
+ [ComputeProvider.COMFY_COMFYICU]: "Comfy.icu (Comfy API)",
26
+ [ComputeProvider.FALAI]: "Fal.ai",
27
+ [ComputeProvider.MODELSLAB]: "ModelsLab.com",
28
+ }
29
+
30
+ export const availableComputeProvidersForVideos = {
31
+ [ComputeProvider.NONE]: "No video provider",
32
+ [ComputeProvider.HUGGINGFACE]: "HuggingFace",
33
+ [ComputeProvider.REPLICATE]: "Replicate (Cog API)",
34
+ [ComputeProvider.COMFY_REPLICATE]: "Replicate (Comfy API)",
35
+ [ComputeProvider.COMFY_COMFYICU]: "Comfy.icu (Comfy API)",
36
+ [ComputeProvider.FALAI]: "Fal.ai",
37
+ [ComputeProvider.MODELSLAB]: "ModelsLab.com",
38
+ }
39
+
40
+ export const availableComputeProvidersForMusic = {
41
+ [ComputeProvider.NONE]: "No music provider",
42
+ [ComputeProvider.HUGGINGFACE]: "HuggingFace",
43
+ [ComputeProvider.COMFY_REPLICATE]: "Replicate (Comfy API)",
44
+ [ComputeProvider.COMFY_COMFYICU]: "Comfy.icu (Comfy API)",
45
+ [ComputeProvider.STABILITYAI]: "StabilityAI (Stable Audio API)",
46
+ [ComputeProvider.FALAI]: "Fal.ai",
47
+ [ComputeProvider.MODELSLAB]: "ModelsLab.com",
48
+ }
49
+
50
+ export const availableComputeProvidersForSound = {
51
+ [ComputeProvider.NONE]: "No sound provider",
52
+ [ComputeProvider.HUGGINGFACE]: "HuggingFace",
53
+ [ComputeProvider.COMFY_REPLICATE]: "Replicate (Comfy API)",
54
+ [ComputeProvider.COMFY_COMFYICU]: "Comfy.icu (Comfy API)",
55
+ [ComputeProvider.STABILITYAI]: "StabilityAI (Stable Audio API)",
56
+ [ComputeProvider.ELEVENLABS]: "Eleven Labs (Sound Effects API)",
57
+
58
+ }
59
+
60
+ export const availableComputeProvidersForSpeech = {
61
+ [ComputeProvider.NONE]: "No speech provider",
62
+ [ComputeProvider.ELEVENLABS]: "Eleven Labs (TTS API)",
63
+ [ComputeProvider.STABILITYAI]: "StabilityAI (Stable Audio API)",
64
+ [ComputeProvider.HUGGINGFACE]: "HuggingFace",
65
+ [ComputeProvider.COMFY_REPLICATE]: "Replicate (Comfy API)",
66
+ [ComputeProvider.COMFY_COMFYICU]: "Comfy.icu (Comfy API)",
67
+ [ComputeProvider.FALAI]: "Fal.ai",
68
+ [ComputeProvider.MODELSLAB]: "ModelsLab.com",
69
+ }
70
+
71
+ export const availableComfyIcuAccelerators = {
72
+ [ComfyIcuAccelerator.L4]: "L4",
73
+ [ComfyIcuAccelerator.T4]: "T4",
74
+ [ComfyIcuAccelerator.A10]: "A10",
75
+ [ComfyIcuAccelerator.A100_40GB]: "A100 (40 GB)",
76
+ [ComfyIcuAccelerator.A100_80GB]: "A100 (80 GB)",
77
+ [ComfyIcuAccelerator.H100]: "H100",
78
+ }
src/components/settings/index.tsx CHANGED
@@ -6,7 +6,13 @@ import { ScrollArea } from "@/components/ui/scroll-area"
6
  import { cn } from "@/lib/utils"
7
  import { useSettingsView } from "@/settings/view"
8
 
9
- import { SettingsSectionRendering } from "./SettingsSectionRendering"
 
 
 
 
 
 
10
 
11
  export function SettingsDialog() {
12
 
@@ -15,21 +21,33 @@ export function SettingsDialog() {
15
  const [_isPending, startTransition] = useTransition()
16
 
17
  const panels = {
18
- rendering: <SettingsSectionRendering />,
 
 
 
 
 
 
19
  }
20
 
21
  const panelLabels = {
22
- rendering: "Rendering",
 
 
 
 
 
 
23
  } as any
24
 
25
- const [configPanel, setConfigPanel] = useState<keyof typeof panels>("rendering")
26
 
27
  return (
28
  <Dialog open={showSettings} onOpenChange={setShowSettings}>
29
  <DialogContent className={cn(
30
  `select-none`,
31
  // DialogContent comes with some hardcoded values so we need to override them
32
- `w-[95w] md:w-[45vw] max-w-6xl h-[60%]`,
33
  `flex flex-row`
34
  )}>
35
  <ScrollArea className="flex flex-col h-full w-44">
@@ -46,7 +64,7 @@ export function SettingsDialog() {
46
 
47
  <div className="
48
  select-none
49
- flex flex-col h-full flex-grow justify-between max-w-[calc(100%-200px)]
50
  border-l border-stone-800
51
  pl-8
52
  ">
 
6
  import { cn } from "@/lib/utils"
7
  import { useSettingsView } from "@/settings/view"
8
 
9
+ import { SettingsSectionProvider } from "./provider"
10
+ import { SettingsSectionAssistant } from "./assistant"
11
+ import { SettingsSectionStoryboard } from "./storyboard"
12
+ import { SettingsSectionVideo } from "./video"
13
+ import { SettingsSectionSound } from "./sound"
14
+ import { SettingsSectionMusic } from "./music"
15
+ import { SettingsSectionSpeech } from "./speech"
16
 
17
  export function SettingsDialog() {
18
 
 
21
  const [_isPending, startTransition] = useTransition()
22
 
23
  const panels = {
24
+ provider: <SettingsSectionProvider />,
25
+ assistant: <SettingsSectionAssistant />,
26
+ storyboard: <SettingsSectionStoryboard />,
27
+ video: <SettingsSectionVideo />,
28
+ speech: <SettingsSectionSpeech />,
29
+ music: <SettingsSectionMusic />,
30
+ sound: <SettingsSectionSound />,
31
  }
32
 
33
  const panelLabels = {
34
+ provider: "Providers",
35
+ assistant: "Assistant",
36
+ storyboard: "Image",
37
+ video: "Video",
38
+ speech: "Speech",
39
+ music: "Music",
40
+ sound: "Sound",
41
  } as any
42
 
43
+ const [configPanel, setConfigPanel] = useState<keyof typeof panels>("provider")
44
 
45
  return (
46
  <Dialog open={showSettings} onOpenChange={setShowSettings}>
47
  <DialogContent className={cn(
48
  `select-none`,
49
  // DialogContent comes with some hardcoded values so we need to override them
50
+ `w-[95w] md:w-[60vw] max-w-6xl h-[70%]`,
51
  `flex flex-row`
52
  )}>
53
  <ScrollArea className="flex flex-col h-full w-44">
 
64
 
65
  <div className="
66
  select-none
67
+ flex flex-col h-full flex-grow justify-between max-w-[calc(100%-150px)]
68
  border-l border-stone-800
69
  pl-8
70
  ">
src/components/settings/music.tsx ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { FormSection } from "@/components/form/form-section"
2
+ import { getDefaultSettingsRendering, useSettingsRendering } from "@/settings/rendering"
3
+ import { ComputeProvider } from "@/types"
4
+
5
+ import { FormSelect } from "../form/form-select"
6
+ import { availableComputeProvidersForMusic } from "./constants"
7
+ import { FormInput } from "../form/form-input"
8
+
9
+ export function SettingsSectionMusic() {
10
+ const defaultSettings = getDefaultSettingsRendering()
11
+
12
+ const musicProvider = useSettingsRendering(s => s.musicProvider)
13
+ const setMusicProvider = useSettingsRendering(s => s.setMusicProvider)
14
+
15
+ const huggingFaceModelForMusic = useSettingsRendering(s => s.huggingFaceModelForMusic)
16
+ const setHuggingFaceModelForMusic = useSettingsRendering(s => s.setHuggingFaceModelForMusic)
17
+
18
+ const replicateModelForMusic = useSettingsRendering(s => s.replicateModelForMusic)
19
+ const setReplicateModelForMusic = useSettingsRendering(s => s.setReplicateModelForMusic)
20
+
21
+ const falAiModelForMusic = useSettingsRendering(s => s.falAiModelForMusic)
22
+ const setFalAiModelForMusic = useSettingsRendering(s => s.setFalAiModelForMusic)
23
+
24
+ const modelsLabModelForMusic = useSettingsRendering(s => s.modelsLabModelForMusic)
25
+ const setModelsLabModelForMusic = useSettingsRendering(s => s.setModelsLabModelForMusic)
26
+
27
+ const comfyWorkflowForMusic = useSettingsRendering(s => s.comfyWorkflowForMusic)
28
+ const setComfyWorkflowForMusic = useSettingsRendering(s => s.setComfyWorkflowForMusic)
29
+
30
+ return (
31
+ <div className="flex flex-col space-y-6 justify-between">
32
+ <FormSection label="Music rendering">
33
+
34
+ <FormSelect<ComputeProvider>
35
+ label="Music provider"
36
+ selectedItemId={musicProvider}
37
+ selectedItemLabel={
38
+ (availableComputeProvidersForMusic as any)[musicProvider]
39
+ || ComputeProvider.NONE
40
+ }
41
+ items={Object.entries(availableComputeProvidersForMusic).map(([provider, label]) => ({
42
+ id: provider,
43
+ label,
44
+ disabled: false,
45
+ value: provider as ComputeProvider,
46
+ }))}
47
+ onSelect={setMusicProvider}
48
+ horizontal
49
+ />
50
+ {musicProvider.startsWith("COMFY_")
51
+ ? <FormInput
52
+ label="Default Comfy workflow template for music"
53
+ value={comfyWorkflowForMusic}
54
+ defaultValue={defaultSettings.comfyWorkflowForMusic}
55
+ onChange={setComfyWorkflowForMusic}
56
+ />
57
+ : // "proprietary" parameters
58
+ <>
59
+ {musicProvider === ComputeProvider.HUGGINGFACE && <FormInput
60
+ label="HF Model ID (must be compatible with the Inference API)"
61
+ value={huggingFaceModelForMusic}
62
+ defaultValue={defaultSettings.huggingFaceModelForMusic}
63
+ onChange={setHuggingFaceModelForMusic}
64
+ />}
65
+ {musicProvider === ComputeProvider.REPLICATE && <FormInput
66
+ label="Replicate.com model ID"
67
+ value={replicateModelForMusic}
68
+ defaultValue={defaultSettings.replicateModelForMusic}
69
+ onChange={setReplicateModelForMusic}
70
+ />}
71
+ {musicProvider === ComputeProvider.FALAI && <FormInput
72
+ label="Fal.ai model ID"
73
+ value={falAiModelForMusic}
74
+ defaultValue={defaultSettings.falAiModelForMusic}
75
+ onChange={setFalAiModelForMusic}
76
+ />}
77
+ {musicProvider === ComputeProvider.MODELSLAB && <FormInput
78
+ label="ModelsLab.com model ID"
79
+ value={modelsLabModelForMusic}
80
+ defaultValue={defaultSettings.modelsLabModelForMusic}
81
+ onChange={setModelsLabModelForMusic}
82
+ />}
83
+ </>}
84
+ </FormSection>
85
+ </div>
86
+ )
87
+ }
src/components/settings/provider.tsx ADDED
@@ -0,0 +1,97 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { FormSection } from "@/components/form/form-section"
2
+ import { getDefaultSettingsRendering, useSettingsRendering } from "@/settings/rendering"
3
+ import { FormSelect } from "../form/form-select"
4
+ import { ComfyIcuAccelerator } from "@/types"
5
+ import { FormInput } from "../form/form-input"
6
+ import { APP_NAME } from "@/lib/core/constants"
7
+ import { availableComfyIcuAccelerators } from "./constants"
8
+
9
+ export function SettingsSectionProvider() {
10
+ const defaultSettings = getDefaultSettingsRendering()
11
+
12
+ const replicateApiKey = useSettingsRendering(s => s.replicateApiKey)
13
+ const setReplicateApiKey = useSettingsRendering(s => s.setReplicateApiKey)
14
+
15
+ const comfyIcuApiKey = useSettingsRendering(s => s.comfyIcuApiKey)
16
+ const setComfyIcuApiKey = useSettingsRendering(s => s.setComfyIcuApiKey)
17
+
18
+ const comfyIcuAccelerator = useSettingsRendering(s => s.comfyIcuAccelerator)
19
+ const setComfyIcuAccelerator = useSettingsRendering(s => s.setComfyIcuAccelerator)
20
+
21
+ const huggingFaceApiKey = useSettingsRendering(s => s.huggingFaceApiKey)
22
+ const setHuggingFaceApiKey = useSettingsRendering(s => s.setHuggingFaceApiKey)
23
+
24
+ const falAiApiKey = useSettingsRendering(s => s.falAiApiKey)
25
+ const setFalAiApiKey = useSettingsRendering(s => s.setFalAiApiKey)
26
+
27
+ const modelsLabApiKey = useSettingsRendering(s => s.modelsLabApiKey)
28
+ const setModelsLabApiKey = useSettingsRendering(s => s.setModelsLabApiKey)
29
+
30
+ return (
31
+ <div className="flex flex-col space-y-6 justify-between">
32
+ <FormSection label="Compute providers">
33
+
34
+ <p className="italic text-sm text-stone-500 max-w-80">
35
+ Note: preferences and credentials are stored inside your browser local storage.<br/>{APP_NAME} uses them to perform API calls on your behalf, but forgets them immediately.
36
+ </p>
37
+
38
+ <FormInput
39
+ label="Hugging Face API key"
40
+ value={huggingFaceApiKey}
41
+ defaultValue={""}
42
+ onChange={setHuggingFaceApiKey}
43
+ type="password"
44
+ />
45
+
46
+ <FormInput
47
+ label="Replicate API key"
48
+ value={replicateApiKey}
49
+ defaultValue={defaultSettings.replicateApiKey}
50
+ onChange={setReplicateApiKey}
51
+ type="password"
52
+ />
53
+ <FormInput
54
+ label="Comfy.icu API key"
55
+ value={comfyIcuApiKey}
56
+ defaultValue={defaultSettings.comfyIcuApiKey}
57
+ onChange={setComfyIcuApiKey}
58
+ type="password"
59
+ />
60
+
61
+ <FormSelect<ComfyIcuAccelerator>
62
+ label="Comfy.icu hardware accelerator"
63
+ selectedItemId={comfyIcuAccelerator}
64
+ selectedItemLabel={
65
+ (availableComfyIcuAccelerators as any)[comfyIcuAccelerator]
66
+ || ComfyIcuAccelerator.L4
67
+ }
68
+ items={Object.entries(availableComfyIcuAccelerators).map(([accelerator, label]) => ({
69
+ id: accelerator,
70
+ label,
71
+ disabled: false,
72
+ value: accelerator as ComfyIcuAccelerator,
73
+ }))}
74
+ onSelect={setComfyIcuAccelerator}
75
+ horizontal
76
+ />
77
+
78
+ <FormInput
79
+ label="Fal.ai API Key"
80
+ value={falAiApiKey}
81
+ defaultValue={defaultSettings.falAiApiKey}
82
+ onChange={setFalAiApiKey}
83
+ type="password"
84
+ />
85
+
86
+ <FormInput
87
+ label="ModelsLab API Key"
88
+ value={modelsLabApiKey}
89
+ defaultValue={defaultSettings.modelsLabApiKey}
90
+ onChange={setModelsLabApiKey}
91
+ type="password"
92
+ />
93
+
94
+ </FormSection>
95
+ </div>
96
+ )
97
+ }
src/components/settings/sound.tsx ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { FormSection } from "@/components/form/form-section"
2
+ import { getDefaultSettingsRendering, useSettingsRendering } from "@/settings/rendering"
3
+ import { ComputeProvider } from "@/types"
4
+
5
+ import { FormSelect } from "../form/form-select"
6
+ import { availableComputeProvidersForSound } from "./constants"
7
+ import { FormInput } from "../form/form-input"
8
+
9
+ export function SettingsSectionSound() {
10
+ const defaultSettings = getDefaultSettingsRendering()
11
+
12
+ const soundProvider = useSettingsRendering(s => s.soundProvider)
13
+ const setSoundProvider = useSettingsRendering(s => s.setSoundProvider)
14
+
15
+ const huggingFaceModelForSound = useSettingsRendering(s => s.huggingFaceModelForSound)
16
+ const setHuggingFaceModelForSound = useSettingsRendering(s => s.setHuggingFaceModelForSound)
17
+
18
+ const replicateModelForSound = useSettingsRendering(s => s.replicateModelForSound)
19
+ const setReplicateModelForSound = useSettingsRendering(s => s.setReplicateModelForSound)
20
+
21
+ const falAiModelForSound = useSettingsRendering(s => s.falAiModelForSound)
22
+ const setFalAiModelForSound = useSettingsRendering(s => s.setFalAiModelForSound)
23
+
24
+ const modelsLabModelForSound = useSettingsRendering(s => s.modelsLabModelForSound)
25
+ const setModelsLabModelForSound = useSettingsRendering(s => s.setModelsLabModelForSound)
26
+
27
+ const comfyWorkflowForSound = useSettingsRendering(s => s.comfyWorkflowForSound)
28
+ const setComfyWorkflowForSound = useSettingsRendering(s => s.setComfyWorkflowForSound)
29
+
30
+ return (
31
+ <div className="flex flex-col space-y-6 justify-between">
32
+ <FormSection label="Sound rendering">
33
+
34
+ <FormSelect<ComputeProvider>
35
+ label="Sound provider"
36
+ selectedItemId={soundProvider}
37
+ selectedItemLabel={
38
+ (availableComputeProvidersForSound as any)[soundProvider]
39
+ || ComputeProvider.NONE
40
+ }
41
+ items={Object.entries(availableComputeProvidersForSound).map(([provider, label]) => ({
42
+ id: provider,
43
+ label,
44
+ disabled: false,
45
+ value: provider as ComputeProvider,
46
+ }))}
47
+ onSelect={setSoundProvider}
48
+ horizontal
49
+ />
50
+ {soundProvider.startsWith("COMFY_")
51
+ ? <FormInput
52
+ label="Default Comfy workflow template for sound"
53
+ value={comfyWorkflowForSound}
54
+ defaultValue={defaultSettings.comfyWorkflowForSound}
55
+ onChange={setComfyWorkflowForSound}
56
+ />
57
+ : // "proprietary" parameters
58
+ <>
59
+ {soundProvider === ComputeProvider.HUGGINGFACE && <FormInput
60
+ label="HF Model ID (must be compatible with the Inference API)"
61
+ value={huggingFaceModelForSound}
62
+ defaultValue={defaultSettings.huggingFaceModelForSound}
63
+ onChange={setHuggingFaceModelForSound}
64
+ />}
65
+ {soundProvider === ComputeProvider.REPLICATE && <FormInput
66
+ label="Replicate.com model ID"
67
+ value={replicateModelForSound}
68
+ defaultValue={defaultSettings.replicateModelForSound}
69
+ onChange={setReplicateModelForSound}
70
+ />}
71
+ {soundProvider === ComputeProvider.FALAI && <FormInput
72
+ label="Fal.ai model ID"
73
+ value={falAiModelForSound}
74
+ defaultValue={defaultSettings.falAiModelForSound}
75
+ onChange={setFalAiModelForSound}
76
+ />}
77
+ {soundProvider === ComputeProvider.MODELSLAB && <FormInput
78
+ label="ModelsLab.com model ID"
79
+ value={modelsLabModelForSound}
80
+ defaultValue={defaultSettings.modelsLabModelForSound}
81
+ onChange={setModelsLabModelForSound}
82
+ />}
83
+ </>}
84
+ </FormSection>
85
+ </div>
86
+ )
87
+ }
src/components/settings/speech.tsx ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { FormSection } from "@/components/form/form-section"
2
+ import { getDefaultSettingsRendering, useSettingsRendering } from "@/settings/rendering"
3
+ import { ComputeProvider } from "@/types"
4
+
5
+ import { FormSelect } from "../form/form-select"
6
+ import { availableComputeProvidersForSpeech } from "./constants"
7
+ import { FormInput } from "../form/form-input"
8
+
9
+ export function SettingsSectionSpeech() {
10
+ const defaultSettings = getDefaultSettingsRendering()
11
+
12
+ const speechProvider = useSettingsRendering(s => s.speechProvider)
13
+ const setSpeechProvider = useSettingsRendering(s => s.setSpeechProvider)
14
+
15
+ const huggingFaceModelForSpeech = useSettingsRendering(s => s.huggingFaceModelForSpeech)
16
+ const setHuggingFaceModelForSpeech = useSettingsRendering(s => s.setHuggingFaceModelForSpeech)
17
+
18
+ const replicateModelForSpeech = useSettingsRendering(s => s.replicateModelForSpeech)
19
+ const setReplicateModelForSpeech = useSettingsRendering(s => s.setReplicateModelForSpeech)
20
+
21
+ const falAiModelForSpeech = useSettingsRendering(s => s.falAiModelForSpeech)
22
+ const setFalAiModelForSpeech = useSettingsRendering(s => s.setFalAiModelForSpeech)
23
+
24
+ const modelsLabModelForSpeech = useSettingsRendering(s => s.modelsLabModelForSpeech)
25
+ const setModelsLabModelForSpeech = useSettingsRendering(s => s.setModelsLabModelForSpeech)
26
+
27
+ const comfyWorkflowForSpeech = useSettingsRendering(s => s.comfyWorkflowForSpeech)
28
+ const setComfyWorkflowForSpeech = useSettingsRendering(s => s.setComfyWorkflowForSpeech)
29
+
30
+ return (
31
+ <div className="flex flex-col space-y-6 justify-between">
32
+ <FormSection label="Speech rendering">
33
+
34
+ <FormSelect<ComputeProvider>
35
+ label="Speech provider"
36
+ selectedItemId={speechProvider}
37
+ selectedItemLabel={
38
+ (availableComputeProvidersForSpeech as any)[speechProvider]
39
+ || ComputeProvider.NONE
40
+ }
41
+ items={Object.entries(availableComputeProvidersForSpeech).map(([provider, label]) => ({
42
+ id: provider,
43
+ label,
44
+ disabled: false,
45
+ value: provider as ComputeProvider,
46
+ }))}
47
+ onSelect={setSpeechProvider}
48
+ horizontal
49
+ />
50
+ {speechProvider.startsWith("COMFY_")
51
+ ? <FormInput
52
+ label="Default Comfy workflow template for speech"
53
+ value={comfyWorkflowForSpeech}
54
+ defaultValue={defaultSettings.comfyWorkflowForSpeech}
55
+ onChange={setComfyWorkflowForSpeech}
56
+ />
57
+ : // "proprietary" parameters
58
+ <>
59
+ {speechProvider === ComputeProvider.HUGGINGFACE && <FormInput
60
+ label="HF Model ID (must be compatible with the Inference API)"
61
+ value={huggingFaceModelForSpeech}
62
+ defaultValue={defaultSettings.huggingFaceModelForSpeech}
63
+ onChange={setHuggingFaceModelForSpeech}
64
+ />}
65
+ {speechProvider === ComputeProvider.REPLICATE && <FormInput
66
+ label="Replicate.com model ID"
67
+ value={replicateModelForSpeech}
68
+ defaultValue={defaultSettings.replicateModelForSpeech}
69
+ onChange={setReplicateModelForSpeech}
70
+ />}
71
+ {speechProvider === ComputeProvider.FALAI && <FormInput
72
+ label="Fal.ai model ID"
73
+ value={falAiModelForSpeech}
74
+ defaultValue={defaultSettings.falAiModelForSpeech}
75
+ onChange={setFalAiModelForSpeech}
76
+ />}
77
+ {speechProvider === ComputeProvider.MODELSLAB && <FormInput
78
+ label="ModelsLab.com model ID"
79
+ value={modelsLabModelForSpeech}
80
+ defaultValue={defaultSettings.modelsLabModelForSpeech}
81
+ onChange={setModelsLabModelForSpeech}
82
+ />}
83
+ </>}
84
+ </FormSection>
85
+ </div>
86
+ )
87
+ }
src/components/settings/storyboard.tsx ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { FormSection } from "@/components/form/form-section"
2
+ import { getDefaultSettingsRendering, useSettingsRendering } from "@/settings/rendering"
3
+
4
+ import { FormInput } from "../form/form-input"
5
+ import { ComputeProvider } from "@/types"
6
+ import { availableComputeProvidersForStoryboards } from "./constants"
7
+ import { FormSelect } from "../form/form-select"
8
+
9
+ export function SettingsSectionStoryboard() {
10
+ const defaultSettings = getDefaultSettingsRendering()
11
+
12
+ const storyboardProvider = useSettingsRendering(s => s.storyboardProvider)
13
+ const setStoryboardProvider = useSettingsRendering(s => s.setStoryboardProvider)
14
+
15
+ const huggingFaceModelForImage = useSettingsRendering(s => s.huggingFaceModelForImage)
16
+ const setHuggingFaceModelForImage = useSettingsRendering(s => s.setHuggingFaceModelForImage)
17
+
18
+ const replicateModelForImage = useSettingsRendering(s => s.replicateModelForImage)
19
+ const setReplicateModelForImage = useSettingsRendering(s => s.setReplicateModelForImage)
20
+
21
+ const falAiModelForImage = useSettingsRendering(s => s.falAiModelForImage)
22
+ const setFalAiModelForImage = useSettingsRendering(s => s.setFalAiModelForImage)
23
+
24
+ const modelsLabModelForImage = useSettingsRendering(s => s.modelsLabModelForImage)
25
+ const setModelsLabModelForImage = useSettingsRendering(s => s.setModelsLabModelForImage)
26
+
27
+ const maxStoryboardsToGenerateInParallel = useSettingsRendering(s => s.maxStoryboardsToGenerateInParallel)
28
+ const setMaxStoryboardsToGenerateInParallel = useSettingsRendering(s => s.setMaxStoryboardsToGenerateInParallel)
29
+
30
+ const comfyWorkflowForStoryboard = useSettingsRendering(s => s.comfyWorkflowForStoryboard)
31
+ const setComfyWorkflowForStoryboard = useSettingsRendering(s => s.setComfyWorkflowForStoryboard)
32
+
33
+ return (
34
+ <div className="flex flex-col space-y-6 justify-between">
35
+ <FormSection label="Storyboard rendering">
36
+
37
+ <FormSelect<ComputeProvider>
38
+ label="Storyboard provider"
39
+ selectedItemId={storyboardProvider}
40
+ selectedItemLabel={
41
+ (availableComputeProvidersForStoryboards as any)[storyboardProvider]
42
+ || ComputeProvider.NONE
43
+ }
44
+ items={Object.entries(availableComputeProvidersForStoryboards).map(([provider, label]) => ({
45
+ id: provider,
46
+ label,
47
+ disabled: false,
48
+ value: provider as ComputeProvider,
49
+ }))}
50
+ onSelect={setStoryboardProvider}
51
+ horizontal
52
+ />
53
+
54
+ <FormInput
55
+ label="Number of storyboards to render in parallel"
56
+ value={maxStoryboardsToGenerateInParallel}
57
+ defaultValue={defaultSettings.maxStoryboardsToGenerateInParallel}
58
+ onChange={setMaxStoryboardsToGenerateInParallel}
59
+ />
60
+
61
+ {storyboardProvider.startsWith("COMFY_")
62
+ ? <FormInput
63
+ label="Default Comfy workflow template for storyboards"
64
+ value={comfyWorkflowForStoryboard}
65
+ defaultValue={defaultSettings.comfyWorkflowForStoryboard}
66
+ onChange={setComfyWorkflowForStoryboard}
67
+ />
68
+ : // "proprietary" parameters
69
+ <>
70
+ {storyboardProvider === ComputeProvider.HUGGINGFACE && <FormInput
71
+ label="HF Model ID (must be compatible with the Inference API)"
72
+ value={huggingFaceModelForImage}
73
+ defaultValue={defaultSettings.huggingFaceModelForImage}
74
+ onChange={setHuggingFaceModelForImage}
75
+ />}
76
+ {storyboardProvider === ComputeProvider.REPLICATE && <FormInput
77
+ label="Replicate.com model ID"
78
+ value={replicateModelForImage}
79
+ defaultValue={defaultSettings.replicateModelForImage}
80
+ onChange={setReplicateModelForImage}
81
+ />}
82
+ {storyboardProvider === ComputeProvider.FALAI && <FormInput
83
+ label="Fal.ai model ID"
84
+ value={falAiModelForImage}
85
+ defaultValue={defaultSettings.falAiModelForImage}
86
+ onChange={setFalAiModelForImage}
87
+ />}
88
+ {storyboardProvider === ComputeProvider.MODELSLAB && <FormInput
89
+ label="ModelsLab.com model ID"
90
+ value={modelsLabModelForImage}
91
+ defaultValue={defaultSettings.modelsLabModelForImage}
92
+ onChange={setModelsLabModelForImage}
93
+ />}
94
+ </>}
95
+
96
+ </FormSection>
97
+ </div>
98
+ )
99
+ }
src/components/settings/video.tsx ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { FormSection } from "@/components/form/form-section"
2
+ import { getDefaultSettingsRendering, useSettingsRendering } from "@/settings/rendering"
3
+ import { FormSelect } from "../form/form-select"
4
+ import { ComputeProvider } from "@/types"
5
+ import { FormInput } from "../form/form-input"
6
+ import { APP_NAME } from "@/lib/core/constants"
7
+ import { availableComputeProvidersForVideos } from "./constants"
8
+
9
+ export function SettingsSectionVideo() {
10
+ const defaultSettings = getDefaultSettingsRendering()
11
+
12
+ const videoProvider = useSettingsRendering(s => s.videoProvider)
13
+ const setVideoProvider = useSettingsRendering(s => s.setVideoProvider)
14
+
15
+
16
+ const huggingFaceModelForVideo = useSettingsRendering(s => s.huggingFaceModelForVideo)
17
+ const setHuggingFaceModelForVideo = useSettingsRendering(s => s.setHuggingFaceModelForVideo)
18
+
19
+ const replicateModelForVideo = useSettingsRendering(s => s.replicateModelForVideo)
20
+ const setReplicateModelForVideo = useSettingsRendering(s => s.setReplicateModelForVideo)
21
+
22
+ const falAiModelForVideo = useSettingsRendering(s => s.falAiModelForVideo)
23
+ const setFalAiModelForVideo = useSettingsRendering(s => s.setFalAiModelForVideo)
24
+
25
+ const modelsLabModelForVideo = useSettingsRendering(s => s.modelsLabModelForVideo)
26
+ const setModelsLabModelForVideo = useSettingsRendering(s => s.setModelsLabModelForVideo)
27
+
28
+ const videoRenderingStrategy = useSettingsRendering(s => s.videoRenderingStrategy)
29
+ const setVideoRenderingStrategy = useSettingsRendering(s => s.setVideoRenderingStrategy)
30
+
31
+ const maxVideosToGenerateInParallel = useSettingsRendering(s => s.maxVideosToGenerateInParallel)
32
+ const setMaxVideosToGenerateInParallel = useSettingsRendering(s => s.setMaxVideosToGenerateInParallel)
33
+
34
+ const comfyWorkflowForVideo = useSettingsRendering(s => s.comfyWorkflowForVideo)
35
+ const setComfyWorkflowForVideo = useSettingsRendering(s => s.setComfyWorkflowForVideo)
36
+
37
+ return (
38
+ <div className="flex flex-col space-y-6 justify-between">
39
+ <FormSection label="Video rendering">
40
+
41
+ <FormSelect<ComputeProvider>
42
+ label="Video provider"
43
+ selectedItemId={videoProvider}
44
+ selectedItemLabel={
45
+ (availableComputeProvidersForVideos as any)[videoProvider]
46
+ || ComputeProvider.NONE
47
+ }
48
+ items={Object.entries(availableComputeProvidersForVideos).map(([provider, label]) => ({
49
+ id: provider,
50
+ label,
51
+ disabled: false,
52
+ value: provider as ComputeProvider,
53
+ }))}
54
+ onSelect={setVideoProvider}
55
+ horizontal
56
+ />
57
+
58
+ <FormInput
59
+ label="Number of videos to render in parallel"
60
+ value={maxVideosToGenerateInParallel}
61
+ defaultValue={defaultSettings.maxVideosToGenerateInParallel}
62
+ onChange={setMaxVideosToGenerateInParallel}
63
+ />
64
+
65
+ {videoProvider.startsWith("COMFY_")
66
+ ? <FormInput
67
+ label="Default Comfy workflow template for videos"
68
+ value={comfyWorkflowForVideo}
69
+ defaultValue={defaultSettings.comfyWorkflowForVideo}
70
+ onChange={setComfyWorkflowForVideo}
71
+ />
72
+ : // "proprietary" parameters
73
+ <>
74
+ {videoProvider === ComputeProvider.HUGGINGFACE && <FormInput
75
+ label="HF Model ID (must be compatible with the Inference API)"
76
+ value={huggingFaceModelForVideo}
77
+ defaultValue={defaultSettings.huggingFaceModelForVideo}
78
+ onChange={setHuggingFaceModelForVideo}
79
+ />}
80
+ {videoProvider === ComputeProvider.REPLICATE && <FormInput
81
+ label="Replicate.com model ID"
82
+ value={replicateModelForVideo}
83
+ defaultValue={defaultSettings.replicateModelForVideo}
84
+ onChange={setReplicateModelForVideo}
85
+ />}
86
+ {videoProvider === ComputeProvider.FALAI && <FormInput
87
+ label="Fal.ai model ID"
88
+ value={falAiModelForVideo}
89
+ defaultValue={defaultSettings.falAiModelForVideo}
90
+ onChange={setFalAiModelForVideo}
91
+ />}
92
+ {videoProvider === ComputeProvider.MODELSLAB && <FormInput
93
+ label="ModelsLab.com model ID"
94
+ value={modelsLabModelForVideo}
95
+ defaultValue={defaultSettings.modelsLabModelForVideo}
96
+ onChange={setModelsLabModelForVideo}
97
+ />}
98
+ </>}
99
+
100
+ </FormSection>
101
+ </div>
102
+ )
103
+ }
src/components/ui/input.tsx CHANGED
@@ -11,7 +11,7 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
11
  <input
12
  type={type}
13
  className={cn(
14
- "flex h-10 w-full rounded-md border border-stone-200 bg-white px-3 py-2 text-sm ring-offset-white file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-stone-500 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-[rgb(59,134,247)] focus-visible:ring-offset-0 disabled:cursor-not-allowed disabled:opacity-50 dark:border-stone-800 dark:bg-stone-950 dark:ring-offset-stone-950 dark:placeholder:text-stone-400 dark:focus-visible:ring-stone-800",
15
  className
16
  )}
17
  ref={ref}
 
11
  <input
12
  type={type}
13
  className={cn(
14
+ "flex h-10 w-full rounded-md border border-stone-200 bg-white px-3 py-2 text-sm ring-offset-white file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-stone-500 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-[rgb(59,134,247)] focus-visible:ring-offset-0 disabled:cursor-not-allowed disabled:opacity-50 dark:border-stone-800 dark:bg-stone-900 dark:ring-offset-stone-950 dark:placeholder:text-stone-400 dark:focus-visible:ring-stone-800",
15
  className
16
  )}
17
  ref={ref}
src/lib/core/DEPRECATED_getSettings.txt DELETED
@@ -1,26 +0,0 @@
1
- import { getValidNumber } from "@aitube/clap"
2
-
3
- import { ComfyVendor, Settings } from "@/types"
4
- import { localStorageKeys } from "@/components/interface/settings/constants"
5
-
6
- import { getValidString, parseRenderingStrategy } from "../utils"
7
-
8
- import { getDefaultSettings } from "./getDefaultSettings"
9
- import { HARD_LIMIT_NB_MAX_ASSETS_TO_GENERATE_IN_PARALLEL } from "./constants"
10
-
11
- export function getSettings(): Settings {
12
- const defaultSettings = getDefaultSettings()
13
- try {
14
- return {
15
- comfyVendor: getValidString(localStorage?.getItem?.(localStorageKeys.comfyVendor), defaultSettings.comfyVendor) as ComfyVendor,
16
- comfyApiKey: getValidString(localStorage?.getItem?.(localStorageKeys.comfyApiKey), defaultSettings.comfyApiKey),
17
- storyboardGenerationStrategy: parseRenderingStrategy(localStorage?.getItem?.(localStorageKeys.storyboardGenerationStrategy), defaultSettings.storyboardGenerationStrategy),
18
- videoGenerationStrategy: parseRenderingStrategy(localStorage?.getItem?.(localStorageKeys.videoGenerationStrategy), defaultSettings.videoGenerationStrategy),
19
- maxNbAssetsToGenerateInParallel: getValidNumber(localStorage?.getItem?.(localStorageKeys.maxNbAssetsToGenerateInParallel), 1, HARD_LIMIT_NB_MAX_ASSETS_TO_GENERATE_IN_PARALLEL, defaultSettings.maxNbAssetsToGenerateInParallel),
20
- }
21
- } catch (err) {
22
- return {
23
- ...defaultSettings
24
- }
25
- }
26
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/core/DEPRECATED_localStorageKeys.txt DELETED
@@ -1,13 +0,0 @@
1
- import { Settings } from "@/types"
2
-
3
- const version = `CLAP_CONFIG_V0_`
4
-
5
- export const localStorageKeys: Record<keyof Settings, string> = {
6
- comfyVendor: `${version}COMFY_VENDOR`,
7
- comfyApiKey: `${version}COMFY_API_KEY`,
8
-
9
- storyboardGenerationStrategy: `${version}STORYBOARD_GENERATION_STRATEGY`,
10
- videoGenerationStrategy: `${version}VIDEO_GENERATION_STRATEEGY`,
11
-
12
- maxNbAssetsToGenerateInParallel: `${version}MAX_NB_ASSETS_TO_GENERATE_IN_PARQLLEL`,
13
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/core/constants.ts CHANGED
@@ -4,7 +4,7 @@
4
  export const HARD_LIMIT_NB_MAX_ASSETS_TO_GENERATE_IN_PARALLEL = 32
5
 
6
  export const APP_NAME = "Clapper"
7
- export const APP_REVISION = "nightly 20240604"
8
 
9
  export const APP_DOMAIN = "Clapper.app"
10
  export const APP_LINK = "https://clapper.app"
 
4
  export const HARD_LIMIT_NB_MAX_ASSETS_TO_GENERATE_IN_PARALLEL = 32
5
 
6
  export const APP_NAME = "Clapper"
7
+ export const APP_REVISION = "nightly 20240605"
8
 
9
  export const APP_DOMAIN = "Clapper.app"
10
  export const APP_LINK = "https://clapper.app"
src/lib/core/getDefaultSettings.ts DELETED
@@ -1,13 +0,0 @@
1
- import { RenderingStrategy, ComfyVendor, Settings } from "@/types"
2
-
3
- export function getDefaultSettings(): Settings {
4
- return {
5
- comfyVendor: ComfyVendor.CUSTOM,
6
- comfyApiKey: "",
7
-
8
- storyboardGenerationStrategy: RenderingStrategy.ON_DEMAND,
9
- videoGenerationStrategy: RenderingStrategy.ON_DEMAND,
10
-
11
- maxNbAssetsToGenerateInParallel: 1,
12
- }
13
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/utils/blobToBase64DataUri.ts ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ export const blobToBase64DataUri = async (blob: Blob): Promise<string> => {
2
+ const buffer = Buffer.from(await blob.arrayBuffer())
3
+ return "data:" + blob.type + ';base64,' + buffer.toString('base64')
4
+ }
src/lib/utils/fetchContentToBase64.ts ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ export async function fetchContentToBase64(url: string) {
2
+ const res = await fetch(url, {
3
+ method: "GET",
4
+ headers: {
5
+ "Content-Type": "application/json",
6
+ },
7
+ cache: "no-store",
8
+ // we can also use this (see https://vercel.com/blog/vercel-cache-api-nextjs-cache)
9
+ // next: { revalidate: 1 }
10
+ })
11
+ const blob = await res.blob()
12
+ const buffer = Buffer.from(await blob.arrayBuffer())
13
+
14
+ return "data:" + blob.type + ';base64,' + buffer.toString('base64')
15
+ }
src/lib/utils/getValidComfyWorkflowTemplate.ts ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ export function getValidComfyWorkflowTemplate(something: any, defaultComfyWorkflowTemplate: string) {
2
+ const strValue = `${something || defaultComfyWorkflowTemplate}`
3
+ try {
4
+ const workflow = JSON.parse(strValue)
5
+ if (typeof workflow === "object") {
6
+ return strValue
7
+ } else {
8
+ throw new Error(`this doesn't look like a ComfyUI workflow template string`)
9
+ }
10
+ } catch (err) {
11
+ return "{}"
12
+ }
13
+ }
src/lib/utils/index.ts CHANGED
@@ -5,5 +5,5 @@ export { getValidBoolean } from "./getValidBoolean"
5
  export { getValidNumber } from "./getValidNumber"
6
  export { getValidString } from "./getValidString"
7
  export { isValidNumber } from "./isValidNumber"
8
- export { parseComfyVendor } from "./parseComfyVendor"
9
- export { parseRenderingStrategy } from "./parseRenderingStrategy"
 
5
  export { getValidNumber } from "./getValidNumber"
6
  export { getValidString } from "./getValidString"
7
  export { isValidNumber } from "./isValidNumber"
8
+ export { parseComfyIcuAccelerator } from "./parseComfyIcuAccelerator"
9
+ export { parseComputeProvider } from "./parseComputeProvider"
src/lib/utils/parseComfyIcuAccelerator.ts ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { ComfyIcuAccelerator } from "@/types"
2
+
3
+ export function parseComfyIcuAccelerator(input: any, defaultAccelerator?: ComfyIcuAccelerator): ComfyIcuAccelerator {
4
+
5
+ let unknownString = `${input || ""}`.trim()
6
+
7
+ // the "normal" case
8
+ if (Object.values(ComfyIcuAccelerator).includes(unknownString as ComfyIcuAccelerator)) {
9
+ return unknownString as ComfyIcuAccelerator
10
+ }
11
+
12
+ let accelerator: ComfyIcuAccelerator = defaultAccelerator || ComfyIcuAccelerator.T4
13
+
14
+ unknownString = unknownString.toLowerCase()
15
+
16
+ if (unknownString === "none" || unknownString === "undefined" || unknownString === "") {
17
+ accelerator = ComfyIcuAccelerator.L4
18
+ }
19
+ else if (unknownString === "l4") {
20
+ accelerator = ComfyIcuAccelerator.L4
21
+ }
22
+ else if (unknownString === "t4") {
23
+ accelerator = ComfyIcuAccelerator.T4
24
+ }
25
+ else if (unknownString === "a10") {
26
+ accelerator = ComfyIcuAccelerator.A10
27
+ }
28
+ else if (unknownString === "a100_40gb") {
29
+ accelerator = ComfyIcuAccelerator.A100_40GB
30
+ }
31
+ else if (unknownString === "a100_80gb") {
32
+ accelerator = ComfyIcuAccelerator.A100_80GB
33
+ }
34
+ else if (unknownString === "a100") {
35
+ accelerator = ComfyIcuAccelerator.A100_40GB
36
+ }
37
+ else if (unknownString === "h100") {
38
+ accelerator = ComfyIcuAccelerator.H100
39
+ } else {
40
+ accelerator = ComfyIcuAccelerator.L4
41
+ }
42
+ return accelerator
43
+ }
src/lib/utils/parseComfyVendor.ts DELETED
@@ -1,28 +0,0 @@
1
- import { ComfyVendor } from "@/types"
2
-
3
- export function parseComfyVendor(input: any, defaultVendor?: ComfyVendor): ComfyVendor {
4
-
5
- let unknownString = `${input || ""}`.trim()
6
-
7
- // the "normal" case
8
- if (Object.values(ComfyVendor).includes(unknownString as ComfyVendor)) {
9
- return unknownString as ComfyVendor
10
- }
11
-
12
- let vendor: ComfyVendor = defaultVendor || ComfyVendor.NONE
13
-
14
- unknownString = unknownString.toLowerCase()
15
-
16
- if (unknownString === "none" || unknownString === "undefined" || unknownString === "") {
17
- vendor = ComfyVendor.NONE
18
- }
19
- else if (unknownString === "huggingface" || unknownString === "hugging_face") {
20
- vendor = ComfyVendor.HUGGINGFACE
21
- }
22
- else if (unknownString === "replicate") {
23
- vendor = ComfyVendor.REPLICATE
24
- } else {
25
- vendor = ComfyVendor.NONE
26
- }
27
- return vendor
28
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/utils/parseComputeProvider.ts ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { ComputeProvider } from "@/types"
2
+
3
+ export function parseComputeProvider(input: any, defaultVendor?: ComputeProvider): ComputeProvider {
4
+
5
+ let unknownString = `${input || ""}`.trim()
6
+
7
+ // the "normal" case
8
+ if (Object.values(ComputeProvider).includes(unknownString as ComputeProvider)) {
9
+ return unknownString as ComputeProvider
10
+ }
11
+
12
+ let vendor: ComputeProvider = defaultVendor || ComputeProvider.NONE
13
+
14
+ unknownString = unknownString.toLowerCase()
15
+
16
+ if (unknownString === "none" || unknownString === "undefined" || unknownString === "") {
17
+ vendor = ComputeProvider.NONE
18
+ }
19
+ else if (unknownString === "huggingface" || unknownString === "hugging_face") {
20
+ vendor = ComputeProvider.HUGGINGFACE
21
+ }
22
+ else if (unknownString === "replicate") {
23
+ vendor = ComputeProvider.REPLICATE
24
+ }
25
+ else if (unknownString === "comfyicu" || unknownString === "comfy.icu") {
26
+ vendor = ComputeProvider.COMFY_COMFYICU
27
+ }
28
+ else if (unknownString === "eleven labs" || unknownString === "eleven labs") {
29
+ vendor = ComputeProvider.ELEVENLABS
30
+ }
31
+ else if (unknownString === "openai") {
32
+ vendor = ComputeProvider.OPENAI
33
+ }
34
+ else if (unknownString === "stabilityai") {
35
+ vendor = ComputeProvider.STABILITYAI
36
+ }
37
+ else if (unknownString === "groq") {
38
+ vendor = ComputeProvider.GROQ
39
+ }
40
+ else if (unknownString === "falai") {
41
+ vendor = ComputeProvider.FALAI
42
+ }
43
+ else if (unknownString === "modelslab") {
44
+ vendor = ComputeProvider.MODELSLAB
45
+ }
46
+ else {
47
+ vendor = ComputeProvider.NONE
48
+ }
49
+ return vendor
50
+ }
src/lib/utils/parseRenderingStrategy.ts DELETED
@@ -1,31 +0,0 @@
1
- import { RenderingStrategy } from "@/types"
2
-
3
- export function parseRenderingStrategy(input: any, defaultStrategy?: RenderingStrategy): RenderingStrategy {
4
-
5
- let unknownString = `${input || ""}`.trim()
6
-
7
- // the "normal" case
8
- if (Object.values(RenderingStrategy).includes(unknownString as RenderingStrategy)) {
9
- return unknownString as RenderingStrategy
10
- }
11
-
12
- let strategy: RenderingStrategy = defaultStrategy || RenderingStrategy.ON_DEMAND
13
-
14
- unknownString = unknownString.toLowerCase()
15
-
16
- if (unknownString === "on_demand") {
17
- strategy = RenderingStrategy.ON_DEMAND
18
- }
19
- else if (unknownString === "on_screen_only") {
20
- strategy = RenderingStrategy.ON_SCREEN_ONLY
21
- }
22
- else if (unknownString === "on_screen_then_surrounding") {
23
- strategy = RenderingStrategy.ON_SCREEN_THEN_SURROUNDING
24
- }
25
- else if (unknownString === "on_screen_then_all") {
26
- strategy = RenderingStrategy.ON_SCREEN_THEN_ALL
27
- } else {
28
- strategy = RenderingStrategy.ON_DEMAND
29
- }
30
- return strategy
31
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/server/comfy/huggingface.ts DELETED
@@ -1,15 +0,0 @@
1
- "use server"
2
-
3
-
4
- export async function run({
5
- apiKey,
6
- workflow
7
- }: {
8
- apiKey: string
9
- workflow: string
10
- }): Promise<string> {
11
-
12
- // TODO: call Hugging Face
13
-
14
- throw new Error(`Hugging Face isn't supported yet`)
15
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/server/comfy/index.ts DELETED
@@ -1,24 +0,0 @@
1
- "use server"
2
-
3
- import { RenderRequest } from "@/types"
4
-
5
- import { run as runWithReplicate } from "./replicate"
6
- import { run as runWithHuggingFace } from "./huggingface"
7
- import { getComfyWorkflow } from "./getComfyWorkflow"
8
-
9
- // TODO: at some point in the future we will
10
- // move src/server/comfy to @aitube/engine
11
- export async function render(request: RenderRequest): Promise<string> {
12
-
13
- const workflow = getComfyWorkflow(request)
14
-
15
- // TODO support Hugging Face as well
16
- // const await runWithHuggingFace({
17
-
18
- const result = await runWithReplicate({
19
- apiKey: request.comfyUiApiKey,
20
- workflow,
21
- })
22
-
23
- return result
24
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/settings/rendering/getDefaultSettingsRendering.ts CHANGED
@@ -1,15 +1,68 @@
1
- import { ComfyVendor, RenderingStrategy } from "@/types"
 
 
2
 
3
  import { SettingsRenderingState } from "./types"
 
4
 
5
  export function getDefaultSettingsRendering(): SettingsRenderingState {
6
  const state: SettingsRenderingState = {
7
- comfyUiApiVendor: ComfyVendor.NONE,
8
- comfyUiApiKey: "",
 
 
 
 
 
 
 
 
 
 
 
 
9
  storyboardRenderingStrategy: RenderingStrategy.ON_DEMAND,
10
  videoRenderingStrategy: RenderingStrategy.ON_DEMAND,
11
- maxNbAssetsToGenerateInParallel: 1,
12
- }
13
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  return state
15
  }
 
1
+ import { RenderingStrategy } from "@aitube/timeline"
2
+
3
+ import { ComfyIcuAccelerator, ComputeProvider } from "@/types"
4
 
5
  import { SettingsRenderingState } from "./types"
6
+ import { defaultWorkflowForStoryboards } from "./workflows/storyboard"
7
 
8
  export function getDefaultSettingsRendering(): SettingsRenderingState {
9
  const state: SettingsRenderingState = {
10
+ assistantProvider: ComputeProvider.NONE,
11
+ storyboardProvider: ComputeProvider.NONE,
12
+ videoProvider: ComputeProvider.NONE,
13
+ soundProvider: ComputeProvider.NONE,
14
+ speechProvider: ComputeProvider.NONE,
15
+ musicProvider: ComputeProvider.NONE,
16
+
17
+ customComfyUiApiKey: "",
18
+ replicateApiKey: "",
19
+ comfyIcuApiKey: "",
20
+ comfyIcuAccelerator: ComfyIcuAccelerator.L4,
21
+ huggingFaceApiKey: "",
22
+ modelsLabApiKey: "",
23
+ falAiApiKey: "",
24
  storyboardRenderingStrategy: RenderingStrategy.ON_DEMAND,
25
  videoRenderingStrategy: RenderingStrategy.ON_DEMAND,
26
+ maxStoryboardsToGenerateInParallel: 1,
27
+ maxVideosToGenerateInParallel: 1,
28
 
29
+ comfyWorkflowForStoryboard: defaultWorkflowForStoryboards,
30
+ comfyWorkflowForVideo: "{}",
31
+ comfyWorkflowForSpeech: "{}",
32
+ comfyWorkflowForSound: "{}",
33
+ comfyWorkflowForMusic: "{}",
34
+
35
+ huggingFaceModelForImage: "sd-community/sdxl-flash",
36
+ huggingFaceModelForVideo: "",
37
+ huggingFaceModelForSpeech: "",
38
+ huggingFaceModelForSound: "",
39
+ huggingFaceModelForMusic: "",
40
+
41
+ replicateModelForImage: "chenxwh/sdxl-flash:001bb81139b01780380407b4106ac681df46108e002eafbeb9ccb2d8faca42e1",
42
+
43
+ // note: this model doesn't support width and height parameters
44
+ replicateModelForVideo: "camenduru/animatediff-lightning-4-step:be39c6d599942831314b770f03cfd062bfd0faa8cc52e9289bcce830b721fcb6",
45
+ replicateModelForSpeech: "",
46
+ replicateModelForSound: "",
47
+ replicateModelForMusic: "",
48
+
49
+ stabilityAiModelForImage: "",
50
+ stabilityAiModelForVideo: "",
51
+ stabilityAiModelForSpeech: "",
52
+ stabilityAiModelForSound: "",
53
+ stabilityAiModelForMusic: "",
54
+
55
+ falAiModelForImage: "",
56
+ falAiModelForVideo: "",
57
+ falAiModelForSpeech: "",
58
+ falAiModelForSound: "",
59
+ falAiModelForMusic: "",
60
+
61
+ modelsLabModelForImage: "",
62
+ modelsLabModelForVideo: "",
63
+ modelsLabModelForSpeech: "",
64
+ modelsLabModelForSound: "",
65
+ modelsLabModelForMusic: "",
66
+ }
67
  return state
68
  }
src/settings/rendering/types.ts CHANGED
@@ -1,19 +1,121 @@
1
- import { ComfyVendor, RenderingStrategy } from "@/types"
 
 
2
 
3
  export type SettingsRenderingState = {
4
- comfyUiApiVendor: ComfyVendor
5
- comfyUiApiKey: string
 
 
 
 
 
 
 
 
 
 
 
6
  storyboardRenderingStrategy: RenderingStrategy
7
  videoRenderingStrategy: RenderingStrategy
8
- maxNbAssetsToGenerateInParallel: number
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  }
10
 
11
  export type SettingsRenderingControls = {
12
- setComfyUiApiVendor: (comfyUiApiVendor?: ComfyVendor) => void
13
- setComfyUiApiKey: (comfyUiApiKey?: string) => void
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  setStoryboardRenderingStrategy: (storyboardRenderingStrategy?: RenderingStrategy) => void
15
  setVideoRenderingStrategy: (videoRenderingStrategy?: RenderingStrategy) => void
16
- setMaxNbAssetsToGenerateInParallel: (maxNbAssetsToGenerateInParallel?: number) => void
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
  }
18
 
19
  export type SettingsRenderingStore =
 
1
+ import { RenderingStrategy } from "@aitube/timeline"
2
+
3
+ import { ComfyIcuAccelerator, ComputeProvider } from "@/types"
4
 
5
  export type SettingsRenderingState = {
6
+ customComfyUiApiKey: string
7
+ replicateApiKey: string
8
+ comfyIcuApiKey: string
9
+ comfyIcuAccelerator: ComfyIcuAccelerator
10
+ falAiApiKey: string
11
+ modelsLabApiKey: string
12
+ huggingFaceApiKey: string
13
+ assistantProvider: ComputeProvider
14
+ videoProvider: ComputeProvider
15
+ storyboardProvider: ComputeProvider
16
+ speechProvider: ComputeProvider
17
+ soundProvider: ComputeProvider
18
+ musicProvider: ComputeProvider
19
  storyboardRenderingStrategy: RenderingStrategy
20
  videoRenderingStrategy: RenderingStrategy
21
+ maxStoryboardsToGenerateInParallel: number
22
+ maxVideosToGenerateInParallel: number
23
+
24
+ comfyWorkflowForStoryboard: string
25
+ comfyWorkflowForVideo: string
26
+ comfyWorkflowForSpeech: string
27
+ comfyWorkflowForSound: string
28
+ comfyWorkflowForMusic: string
29
+
30
+ huggingFaceModelForImage: string
31
+ huggingFaceModelForVideo: string
32
+ huggingFaceModelForSpeech: string
33
+ huggingFaceModelForSound: string
34
+ huggingFaceModelForMusic: string
35
+
36
+ replicateModelForImage: string
37
+ replicateModelForVideo: string
38
+ replicateModelForSpeech: string
39
+ replicateModelForSound: string
40
+ replicateModelForMusic: string
41
+
42
+ stabilityAiModelForImage: string
43
+ stabilityAiModelForVideo: string
44
+ stabilityAiModelForSpeech: string
45
+ stabilityAiModelForSound: string
46
+ stabilityAiModelForMusic: string
47
+
48
+ falAiModelForImage: string
49
+ falAiModelForVideo: string
50
+ falAiModelForSpeech: string
51
+ falAiModelForSound: string
52
+ falAiModelForMusic: string
53
+
54
+ modelsLabModelForImage: string
55
+ modelsLabModelForVideo: string
56
+ modelsLabModelForSpeech: string
57
+ modelsLabModelForSound: string
58
+ modelsLabModelForMusic: string
59
  }
60
 
61
  export type SettingsRenderingControls = {
62
+ setCustomComfyUiApiKey: (customComfyUiApiKey?: string) => void
63
+ setReplicateApiKey: (replicateApiKey?: string) => void
64
+ setComfyIcuApiKey: (comfyIcuApiKey?: string) => void
65
+ setComfyIcuAccelerator: (comfyIcuAccelerator?: ComfyIcuAccelerator) => void
66
+ setHuggingFaceApiKey: (huggingFaceApiKey?: string) => void
67
+ setModelsLabApiKey: (modelsLabApiKey?: string) => void
68
+ setFalAiApiKey: (falAiApiKey?: string) => void
69
+
70
+ setAssistantProvider: (assistantProvider?: ComputeProvider) => void
71
+ setVideoProvider: (videoProvider?: ComputeProvider) => void
72
+ setStoryboardProvider: (storyboardProvider?: ComputeProvider) => void
73
+ setSpeechProvider: (speechProvider?: ComputeProvider) => void
74
+ setSoundProvider: (soundProvider?: ComputeProvider) => void
75
+ setMusicProvider: (musicProvider?: ComputeProvider) => void
76
+
77
  setStoryboardRenderingStrategy: (storyboardRenderingStrategy?: RenderingStrategy) => void
78
  setVideoRenderingStrategy: (videoRenderingStrategy?: RenderingStrategy) => void
79
+ setMaxStoryboardsToGenerateInParallel: (maxStoryboardsToGenerateInParallel?: number) => void
80
+ setMaxVideosToGenerateInParallel: (maxVideosToGenerateInParallel?: number) => void
81
+
82
+ setComfyWorkflowForStoryboard: (comfyWorkflowForStoryboard?: string) => void
83
+ setComfyWorkflowForVideo: (comfyWorkflowForVideo?: string) => void
84
+ setComfyWorkflowForSpeech: (comfyWorkflowForSpeech?: string) => void
85
+ setComfyWorkflowForSound: (comfyWorkflowForSound?: string) => void
86
+ setComfyWorkflowForMusic: (comfyWorkflowForMusic?: string) => void
87
+
88
+ setHuggingFaceModelForImage: (huggingFaceModelForImage?: string) => void
89
+ setHuggingFaceModelForVideo: (huggingFaceModelForVideo?: string) => void
90
+ setHuggingFaceModelForSpeech: (huggingFaceModelForSpeech?: string) => void
91
+ setHuggingFaceModelForSound: (huggingFaceModelForSound?: string) => void
92
+ setHuggingFaceModelForMusic: (huggingFaceModelForMusic?: string) => void
93
+
94
+ setReplicateModelForImage: (replicateModelForImage?: string) => void
95
+ setReplicateModelForVideo: (replicateModelForVideo?: string) => void
96
+ setReplicateModelForSpeech: (replicateModelForSpeech?: string) => void
97
+ setReplicateModelForSound: (replicateModelForSound?: string) => void
98
+ setReplicateModelForMusic: (replicateModelForMusic?: string) => void
99
+
100
+ setStabilityAiModelForImage: (stabilityAiModelForImage?: string) => void
101
+ setStabilityAiModelForVideo: (stabilityAiModelForVideo?: string) => void
102
+ setStabilityAiModelForSpeech: (stabilityAiModelForSpeech?: string) => void
103
+ setStabilityAiModelForSound: (stabilityAiModelForSound?: string) => void
104
+ setStabilityAiModelForMusic: (stabilityAiModelForMusic?: string) => void
105
+
106
+ setFalAiModelForImage: (falAiModelForImage?: string) => void
107
+ setFalAiModelForVideo: (falAiModelForVideo?: string) => void
108
+ setFalAiModelForSpeech: (falAiModelForSpeech?: string) => void
109
+ setFalAiModelForSound: (falAiModelForSound?: string) => void
110
+ setFalAiModelForMusic: (falAiModelForMusic?: string) => void
111
+
112
+ setModelsLabModelForImage: (modelsLabModelForImage?: string) => void
113
+ setModelsLabModelForVideo: (modelsLabModelForVideo?: string) => void
114
+ setModelsLabModelForSpeech: (modelsLabModelForSpeech?: string) => void
115
+ setModelsLabModelForSound: (modelsLabModelForSound?: string) => void
116
+ setModelsLabModelForMusic: (modelsLabModelForMusic?: string) => void
117
+
118
+ getSettings: () => SettingsRenderingState
119
  }
120
 
121
  export type SettingsRenderingStore =
src/settings/rendering/useSettingsRendering.ts CHANGED
@@ -3,26 +3,71 @@
3
  import { create } from "zustand"
4
  import { persist } from 'zustand/middleware'
5
  import { getValidNumber } from "@aitube/clap"
 
6
 
7
- import { ComfyVendor, RenderingStrategy } from "@/types"
8
- import { getValidString, parseRenderingStrategy, parseComfyVendor } from "@/lib/utils"
9
  import { HARD_LIMIT_NB_MAX_ASSETS_TO_GENERATE_IN_PARALLEL } from "@/lib/core/constants"
10
 
11
- import { SettingsRenderingStore } from "./types"
12
  import { getDefaultSettingsRendering } from "./getDefaultSettingsRendering"
 
 
13
 
14
  export const useSettingsRendering = create<SettingsRenderingStore>()(
15
  persist(
16
  (set, get) => ({
17
  ...getDefaultSettingsRendering(),
18
 
19
- setComfyUiApiVendor: (comfyUiApiVendor?: ComfyVendor) => {
20
- const { comfyUiApiVendor: defaultComfyUiApiVendor } = getDefaultSettingsRendering()
21
- set({ comfyUiApiVendor: parseComfyVendor(comfyUiApiVendor, defaultComfyUiApiVendor) })
22
  },
23
- setComfyUiApiKey: (comfyUiApiKey?: string) => {
24
- const { comfyUiApiKey: defaultComfyUiApiKey } = getDefaultSettingsRendering()
25
- set({ comfyUiApiKey: getValidString(comfyUiApiKey, defaultComfyUiApiKey) })
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
  },
27
  setStoryboardRenderingStrategy: (storyboardRenderingStrategy?: RenderingStrategy) => {
28
  const { storyboardRenderingStrategy: defaulStoryboardRenderingStrategy } = getDefaultSettingsRendering()
@@ -32,17 +77,219 @@ export const useSettingsRendering = create<SettingsRenderingStore>()(
32
  const { videoRenderingStrategy: defaultVideoRenderingStrategy } = getDefaultSettingsRendering()
33
  set({ videoRenderingStrategy: parseRenderingStrategy(videoRenderingStrategy, defaultVideoRenderingStrategy) })
34
  },
35
- setMaxNbAssetsToGenerateInParallel: (maxNbAssetsToGenerateInParallel?: number) => {
36
- const { maxNbAssetsToGenerateInParallel: defaultMaxNbAssetsToGenerateInParallel } = getDefaultSettingsRendering()
37
  set({
38
- maxNbAssetsToGenerateInParallel: getValidNumber(
39
- maxNbAssetsToGenerateInParallel,
40
  1,
41
  HARD_LIMIT_NB_MAX_ASSETS_TO_GENERATE_IN_PARALLEL,
42
- defaultMaxNbAssetsToGenerateInParallel
43
  )
44
  })
45
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
  }),
47
  {
48
  name: 'CLAPPER_REVISION_0_SETTINGS_RENDERING'
 
3
  import { create } from "zustand"
4
  import { persist } from 'zustand/middleware'
5
  import { getValidNumber } from "@aitube/clap"
6
+ import { parseRenderingStrategy, RenderingStrategy } from "@aitube/timeline"
7
 
8
+ import { ComfyIcuAccelerator, ComputeProvider } from "@/types"
9
+ import { getValidString, parseComputeProvider } from "@/lib/utils"
10
  import { HARD_LIMIT_NB_MAX_ASSETS_TO_GENERATE_IN_PARALLEL } from "@/lib/core/constants"
11
 
12
+ import { SettingsRenderingState, SettingsRenderingStore } from "./types"
13
  import { getDefaultSettingsRendering } from "./getDefaultSettingsRendering"
14
+ import { getValidComfyWorkflowTemplate } from "@/lib/utils/getValidComfyWorkflowTemplate"
15
+ import { parseComfyIcuAccelerator } from "@/lib/utils/parseComfyIcuAccelerator"
16
 
17
  export const useSettingsRendering = create<SettingsRenderingStore>()(
18
  persist(
19
  (set, get) => ({
20
  ...getDefaultSettingsRendering(),
21
 
22
+ setAssistantProvider: (assistantProvider?: ComputeProvider) => {
23
+ const { videoProvider: defaultAssistantProvider } = getDefaultSettingsRendering()
24
+ set({ assistantProvider: parseComputeProvider(assistantProvider, defaultAssistantProvider) })
25
  },
26
+ setVideoProvider: (videoProvider?: ComputeProvider) => {
27
+ const { videoProvider: defaultVideoProvider } = getDefaultSettingsRendering()
28
+ set({ videoProvider: parseComputeProvider(videoProvider, defaultVideoProvider) })
29
+ },
30
+ setStoryboardProvider: (storyboardProvider?: ComputeProvider) => {
31
+ const { storyboardProvider: defaultStoryboardProvider } = getDefaultSettingsRendering()
32
+ set({ storyboardProvider: parseComputeProvider(storyboardProvider, defaultStoryboardProvider) })
33
+ },
34
+ setSpeechProvider: (speechProvider?: ComputeProvider) => {
35
+ const { speechProvider: defaultSpeechProvider } = getDefaultSettingsRendering()
36
+ set({ speechProvider: parseComputeProvider(speechProvider, defaultSpeechProvider) })
37
+ },
38
+ setSoundProvider: (soundProvider?: ComputeProvider) => {
39
+ const { soundProvider: defaultSoundProvider } = getDefaultSettingsRendering()
40
+ set({ soundProvider: parseComputeProvider(soundProvider, defaultSoundProvider) })
41
+ },
42
+ setMusicProvider: (musicProvider?: ComputeProvider) => {
43
+ const { musicProvider: defaultMusicProvider } = getDefaultSettingsRendering()
44
+ set({ musicProvider: parseComputeProvider(musicProvider, defaultMusicProvider) })
45
+ },
46
+ setCustomComfyUiApiKey: (customComfyUiApiKey?: string) => {
47
+ const { customComfyUiApiKey: defaulCustomComfyUiApiKey } = getDefaultSettingsRendering()
48
+ set({ customComfyUiApiKey: getValidString(customComfyUiApiKey, defaulCustomComfyUiApiKey) })
49
+ },
50
+ setReplicateApiKey: (replicateApiKey?: string) => {
51
+ const { replicateApiKey: defaultReplicateApiKey } = getDefaultSettingsRendering()
52
+ set({ replicateApiKey: getValidString(replicateApiKey, defaultReplicateApiKey) })
53
+ },
54
+ setComfyIcuApiKey: (comfyIcuApiKey?: string) => {
55
+ const { comfyIcuApiKey: defaultComfyIcuApiKey } = getDefaultSettingsRendering()
56
+ set({ comfyIcuApiKey: getValidString(comfyIcuApiKey, defaultComfyIcuApiKey) })
57
+ },
58
+ setComfyIcuAccelerator: (comfyIcuAccelerator?: ComfyIcuAccelerator) => {
59
+ const { comfyIcuAccelerator: defaulComfyIcuAccelerator } = getDefaultSettingsRendering()
60
+ set({ comfyIcuAccelerator: parseComfyIcuAccelerator(comfyIcuAccelerator, defaulComfyIcuAccelerator) })
61
+ },
62
+ setHuggingFaceApiKey: (huggingFaceApiKey?: string) => {
63
+ const { huggingFaceApiKey: defaultHuggingFaceApiKey } = getDefaultSettingsRendering()
64
+ set({ huggingFaceApiKey: getValidString(huggingFaceApiKey, defaultHuggingFaceApiKey) })
65
+ },
66
+ setFalAiApiKey: (falAiApiKey?: string) => {
67
+ set({ falAiApiKey: getValidString(falAiApiKey, getDefaultSettingsRendering().falAiApiKey) })
68
+ },
69
+ setModelsLabApiKey: (modelsLabApiKey?: string) => {
70
+ set({ modelsLabApiKey: getValidString(modelsLabApiKey, getDefaultSettingsRendering().modelsLabApiKey) })
71
  },
72
  setStoryboardRenderingStrategy: (storyboardRenderingStrategy?: RenderingStrategy) => {
73
  const { storyboardRenderingStrategy: defaulStoryboardRenderingStrategy } = getDefaultSettingsRendering()
 
77
  const { videoRenderingStrategy: defaultVideoRenderingStrategy } = getDefaultSettingsRendering()
78
  set({ videoRenderingStrategy: parseRenderingStrategy(videoRenderingStrategy, defaultVideoRenderingStrategy) })
79
  },
80
+ setMaxStoryboardsToGenerateInParallel: (maxStoryboardsToGenerateInParallel?: number) => {
81
+ const { maxStoryboardsToGenerateInParallel: defaultMaxStoryboardsToGenerateInParallel } = getDefaultSettingsRendering()
82
  set({
83
+ maxStoryboardsToGenerateInParallel: getValidNumber(
84
+ maxStoryboardsToGenerateInParallel,
85
  1,
86
  HARD_LIMIT_NB_MAX_ASSETS_TO_GENERATE_IN_PARALLEL,
87
+ defaultMaxStoryboardsToGenerateInParallel
88
  )
89
  })
90
  },
91
+ setMaxVideosToGenerateInParallel: (maxVideosToGenerateInParallel?: number) => {
92
+ const { maxVideosToGenerateInParallel: defaultMaxVideosToGenerateInParallel } = getDefaultSettingsRendering()
93
+ set({
94
+ maxVideosToGenerateInParallel: getValidNumber(
95
+ maxVideosToGenerateInParallel,
96
+ 1,
97
+ HARD_LIMIT_NB_MAX_ASSETS_TO_GENERATE_IN_PARALLEL,
98
+ defaultMaxVideosToGenerateInParallel
99
+ )
100
+ })
101
+ },
102
+ setComfyWorkflowForStoryboard: (comfyWorkflowForStoryboard?: string) => {
103
+ set({ comfyWorkflowForStoryboard: getValidComfyWorkflowTemplate(comfyWorkflowForStoryboard, getDefaultSettingsRendering().comfyWorkflowForStoryboard) })
104
+ },
105
+ setComfyWorkflowForVideo: (comfyWorkflowForVideo?: string) => {
106
+ set({ comfyWorkflowForVideo: getValidComfyWorkflowTemplate(comfyWorkflowForVideo, getDefaultSettingsRendering().comfyWorkflowForVideo) })
107
+ },
108
+ setComfyWorkflowForSpeech: (comfyWorkflowForSpeech?: string) => {
109
+ set({ comfyWorkflowForSpeech: getValidComfyWorkflowTemplate(comfyWorkflowForSpeech, getDefaultSettingsRendering().comfyWorkflowForSpeech) })
110
+ },
111
+ setComfyWorkflowForSound: (comfyWorkflowForSound?: string) => {
112
+ set({ comfyWorkflowForSound: getValidComfyWorkflowTemplate(comfyWorkflowForSound, getDefaultSettingsRendering().comfyWorkflowForSound) })
113
+ },
114
+ setComfyWorkflowForMusic: (comfyWorkflowForMusic?: string) => {
115
+ set({ comfyWorkflowForMusic: getValidComfyWorkflowTemplate(comfyWorkflowForMusic, getDefaultSettingsRendering().comfyWorkflowForMusic) })
116
+ },
117
+ setHuggingFaceModelForImage: (huggingFaceModelForImage?: string) => {
118
+ set({ huggingFaceModelForImage: getValidString(huggingFaceModelForImage, getDefaultSettingsRendering().huggingFaceModelForImage) })
119
+ },
120
+ setHuggingFaceModelForVideo: (huggingFaceModelForVideo?: string) => {
121
+ set({ huggingFaceModelForVideo: getValidString(huggingFaceModelForVideo, getDefaultSettingsRendering().huggingFaceModelForVideo) })
122
+ },
123
+ setHuggingFaceModelForSpeech: (huggingFaceModelForSpeech?: string) => {
124
+ set({ huggingFaceModelForSpeech: getValidString(huggingFaceModelForSpeech, getDefaultSettingsRendering().huggingFaceModelForSpeech) })
125
+ },
126
+ setHuggingFaceModelForSound: (huggingFaceModelForSound?: string) => {
127
+ set({ huggingFaceModelForSound: getValidString(huggingFaceModelForSound, getDefaultSettingsRendering().huggingFaceModelForSound) })
128
+ },
129
+ setHuggingFaceModelForMusic: (huggingFaceModelForMusic?: string) => {
130
+ set({ huggingFaceModelForMusic: getValidString(huggingFaceModelForMusic, getDefaultSettingsRendering().huggingFaceModelForMusic) })
131
+ },
132
+ setReplicateModelForImage: (replicateModelForImage?: string) => {
133
+ set({ replicateModelForImage: getValidString(replicateModelForImage, getDefaultSettingsRendering().replicateModelForImage) })
134
+ },
135
+ setReplicateModelForVideo: (replicateModelForVideo?: string) => {
136
+ set({ replicateModelForVideo: getValidString(replicateModelForVideo, getDefaultSettingsRendering().replicateModelForVideo) })
137
+ },
138
+ setReplicateModelForSpeech: (replicateModelForSpeech?: string) => {
139
+ set({ replicateModelForSpeech: getValidString(replicateModelForSpeech, getDefaultSettingsRendering().replicateModelForSpeech) })
140
+ },
141
+ setReplicateModelForSound: (replicateModelForSound?: string) => {
142
+ set({ replicateModelForSound: getValidString(replicateModelForSound, getDefaultSettingsRendering().replicateModelForSound) })
143
+ },
144
+ setReplicateModelForMusic: (replicateModelForMusic?: string) => {
145
+ set({ replicateModelForMusic: getValidString(replicateModelForMusic, getDefaultSettingsRendering().replicateModelForMusic) })
146
+ },
147
+ setStabilityAiModelForImage: (stabilityAiModelForImage?: string) => {
148
+ set({ stabilityAiModelForImage: getValidString(stabilityAiModelForImage, getDefaultSettingsRendering().stabilityAiModelForImage) })
149
+ },
150
+ setStabilityAiModelForVideo: (stabilityAiModelForVideo?: string) => {
151
+ set({ stabilityAiModelForVideo: getValidString(stabilityAiModelForVideo, getDefaultSettingsRendering().stabilityAiModelForVideo) })
152
+ },
153
+ setStabilityAiModelForSpeech: (stabilityAiModelForSpeech?: string) => {
154
+ set({ stabilityAiModelForSpeech: getValidString(stabilityAiModelForSpeech, getDefaultSettingsRendering().stabilityAiModelForSpeech) })
155
+ },
156
+ setStabilityAiModelForSound: (stabilityAiModelForSound?: string) => {
157
+ set({ stabilityAiModelForSound: getValidString(stabilityAiModelForSound, getDefaultSettingsRendering().stabilityAiModelForSound) })
158
+ },
159
+ setStabilityAiModelForMusic: (stabilityAiModelForMusic?: string) => {
160
+ set({ stabilityAiModelForMusic: getValidString(stabilityAiModelForMusic, getDefaultSettingsRendering().stabilityAiModelForMusic) })
161
+ },
162
+ setFalAiModelForImage: (falAiModelForImage?: string) => {
163
+ set({ falAiModelForImage: getValidString(falAiModelForImage, getDefaultSettingsRendering().falAiModelForImage) })
164
+ },
165
+ setFalAiModelForVideo: (falAiModelForVideo?: string) => {
166
+ set({ falAiModelForVideo: getValidString(falAiModelForVideo, getDefaultSettingsRendering().falAiModelForVideo) })
167
+ },
168
+ setFalAiModelForSpeech: (falAiModelForSpeech?: string) => {
169
+ set({ falAiModelForSpeech: getValidString(falAiModelForSpeech, getDefaultSettingsRendering().falAiModelForSpeech) })
170
+ },
171
+ setFalAiModelForSound: (falAiModelForSound?: string) => {
172
+ set({ falAiModelForSound: getValidString(falAiModelForSound, getDefaultSettingsRendering().falAiModelForSound) })
173
+ },
174
+ setFalAiModelForMusic: (falAiModelForMusic?: string) => {
175
+ set({ falAiModelForMusic: getValidString(falAiModelForMusic, getDefaultSettingsRendering().falAiModelForMusic) })
176
+ },
177
+ setModelsLabModelForImage: (modelsLabModelForImage?: string) => {
178
+ set({ modelsLabModelForImage: getValidString(modelsLabModelForImage, getDefaultSettingsRendering().modelsLabModelForImage) })
179
+ },
180
+ setModelsLabModelForVideo: (modelsLabModelForVideo?: string) => {
181
+ set({ modelsLabModelForVideo: getValidString(modelsLabModelForVideo, getDefaultSettingsRendering().modelsLabModelForVideo) })
182
+ },
183
+ setModelsLabModelForSpeech: (modelsLabModelForSpeech?: string) => {
184
+ set({ modelsLabModelForSpeech: getValidString(modelsLabModelForSpeech, getDefaultSettingsRendering().modelsLabModelForSpeech) })
185
+ },
186
+ setModelsLabModelForSound: (modelsLabModelForSound?: string) => {
187
+ set({ modelsLabModelForSound: getValidString(modelsLabModelForSound, getDefaultSettingsRendering().modelsLabModelForSound) })
188
+ },
189
+ setModelsLabModelForMusic: (modelsLabModelForMusic?: string) => {
190
+ set({ modelsLabModelForMusic: getValidString(modelsLabModelForMusic, getDefaultSettingsRendering().modelsLabModelForMusic) })
191
+ },
192
+
193
+ getSettings: (): SettingsRenderingState => {
194
+ const {
195
+ assistantProvider,
196
+ storyboardProvider,
197
+ videoProvider,
198
+ soundProvider,
199
+ speechProvider,
200
+ musicProvider,
201
+ customComfyUiApiKey,
202
+ replicateApiKey,
203
+ comfyIcuApiKey,
204
+ comfyIcuAccelerator,
205
+ huggingFaceApiKey,
206
+ falAiApiKey,
207
+ modelsLabApiKey,
208
+ storyboardRenderingStrategy,
209
+ videoRenderingStrategy,
210
+ maxStoryboardsToGenerateInParallel,
211
+ maxVideosToGenerateInParallel,
212
+ comfyWorkflowForStoryboard,
213
+ comfyWorkflowForVideo,
214
+ comfyWorkflowForSpeech,
215
+ comfyWorkflowForSound,
216
+ comfyWorkflowForMusic,
217
+ huggingFaceModelForImage,
218
+ huggingFaceModelForVideo,
219
+ huggingFaceModelForSpeech,
220
+ huggingFaceModelForSound,
221
+ huggingFaceModelForMusic,
222
+ replicateModelForImage,
223
+ replicateModelForVideo,
224
+ replicateModelForSpeech,
225
+ replicateModelForSound,
226
+ replicateModelForMusic,
227
+ stabilityAiModelForImage,
228
+ stabilityAiModelForVideo,
229
+ stabilityAiModelForSpeech,
230
+ stabilityAiModelForSound,
231
+ stabilityAiModelForMusic,
232
+ falAiModelForImage,
233
+ falAiModelForVideo,
234
+ falAiModelForSpeech,
235
+ falAiModelForSound,
236
+ falAiModelForMusic,
237
+ modelsLabModelForImage,
238
+ modelsLabModelForVideo,
239
+ modelsLabModelForSpeech,
240
+ modelsLabModelForSound,
241
+ modelsLabModelForMusic,
242
+ } = get()
243
+ return {
244
+ assistantProvider,
245
+ storyboardProvider,
246
+ videoProvider,
247
+ soundProvider,
248
+ speechProvider,
249
+ musicProvider,
250
+ customComfyUiApiKey,
251
+ replicateApiKey,
252
+ comfyIcuApiKey,
253
+ comfyIcuAccelerator,
254
+ huggingFaceApiKey,
255
+ falAiApiKey,
256
+ modelsLabApiKey,
257
+ storyboardRenderingStrategy,
258
+ videoRenderingStrategy,
259
+ maxStoryboardsToGenerateInParallel,
260
+ maxVideosToGenerateInParallel,
261
+ comfyWorkflowForStoryboard,
262
+ comfyWorkflowForVideo,
263
+ comfyWorkflowForSpeech,
264
+ comfyWorkflowForSound,
265
+ comfyWorkflowForMusic,
266
+ huggingFaceModelForImage,
267
+ huggingFaceModelForVideo,
268
+ huggingFaceModelForSpeech,
269
+ huggingFaceModelForSound,
270
+ huggingFaceModelForMusic,
271
+ replicateModelForImage,
272
+ replicateModelForVideo,
273
+ replicateModelForSpeech,
274
+ replicateModelForSound,
275
+ replicateModelForMusic,
276
+ stabilityAiModelForImage,
277
+ stabilityAiModelForVideo,
278
+ stabilityAiModelForSpeech,
279
+ stabilityAiModelForSound,
280
+ stabilityAiModelForMusic,
281
+ falAiModelForImage,
282
+ falAiModelForVideo,
283
+ falAiModelForSpeech,
284
+ falAiModelForSound,
285
+ falAiModelForMusic,
286
+ modelsLabModelForImage,
287
+ modelsLabModelForVideo,
288
+ modelsLabModelForSpeech,
289
+ modelsLabModelForSound,
290
+ modelsLabModelForMusic,
291
+ }
292
+ },
293
  }),
294
  {
295
  name: 'CLAPPER_REVISION_0_SETTINGS_RENDERING'
src/settings/rendering/workflows/storyboard.ts ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+
3
+ // https://replicate.com/fofr/any-comfyui-workflow/examples#ps4f5zcthdrgm0cfqh586zed7r
4
+ export const defaultWorkflowForStoryboards = JSON.stringify({
5
+ "3": {
6
+ "inputs": {
7
+ "seed": 156680208700286,
8
+ "steps": 10,
9
+ "cfg": 2.5,
10
+ "sampler_name": "dpmpp_2m_sde",
11
+ "scheduler": "karras",
12
+ "denoise": 1,
13
+ "model": [
14
+ "4",
15
+ 0
16
+ ],
17
+ "positive": [
18
+ "6",
19
+ 0
20
+ ],
21
+ "negative": [
22
+ "7",
23
+ 0
24
+ ],
25
+ "latent_image": [
26
+ "5",
27
+ 0
28
+ ]
29
+ },
30
+ "class_type": "KSampler",
31
+ "_meta": {
32
+ "title": "KSampler"
33
+ }
34
+ },
35
+ "4": {
36
+ "inputs": {
37
+ "ckpt_name": "SDXL-Flash.safetensors"
38
+ },
39
+ "class_type": "CheckpointLoaderSimple",
40
+ "_meta": {
41
+ "title": "Load Checkpoint"
42
+ }
43
+ },
44
+ "5": {
45
+ "inputs": {
46
+ "width": 1024,
47
+ "height": 1024,
48
+ "batch_size": 1
49
+ },
50
+ "class_type": "EmptyLatentImage",
51
+ "_meta": {
52
+ "title": "Empty Latent Image"
53
+ }
54
+ },
55
+ "6": {
56
+ "inputs": {
57
+ "text": "beautiful scenery nature glass bottle landscape, purple galaxy bottle,",
58
+ "clip": [
59
+ "4",
60
+ 1
61
+ ]
62
+ },
63
+ "class_type": "CLIPTextEncode",
64
+ "_meta": {
65
+ "title": "CLIP Text Encode (Prompt)"
66
+ }
67
+ },
68
+ "7": {
69
+ "inputs": {
70
+ "text": "text, watermark",
71
+ "clip": [
72
+ "4",
73
+ 1
74
+ ]
75
+ },
76
+ "class_type": "CLIPTextEncode",
77
+ "_meta": {
78
+ "title": "CLIP Text Encode (Prompt)"
79
+ }
80
+ },
81
+ "8": {
82
+ "inputs": {
83
+ "samples": [
84
+ "3",
85
+ 0
86
+ ],
87
+ "vae": [
88
+ "4",
89
+ 2
90
+ ]
91
+ },
92
+ "class_type": "VAEDecode",
93
+ "_meta": {
94
+ "title": "VAE Decode"
95
+ }
96
+ },
97
+ "9": {
98
+ "inputs": {
99
+ "filename_prefix": "ComfyUI",
100
+ "images": [
101
+ "8",
102
+ 0
103
+ ]
104
+ },
105
+ "class_type": "SaveImage",
106
+ "_meta": {
107
+ "title": "Save Image"
108
+ }
109
+ }
110
+ })