jbilcke-hf HF staff commited on
Commit
89b09eb
1 Parent(s): 5566043

disable timeline scale change for now, fix loaders

Browse files
Files changed (48) hide show
  1. package-lock.json +346 -311
  2. package.json +4 -2
  3. src/app/api/resolve/providers/falai/index.ts +4 -1
  4. src/app/api/resolve/providers/stabilityai/index.ts +75 -0
  5. src/app/api/resolve/providers/stabilityai/performRequest.ts +65 -0
  6. src/app/api/resolve/route.ts +3 -0
  7. src/components/dialogs/loader/LoadingDialog.tsx +2 -1
  8. src/components/settings/constants.ts +39 -1
  9. src/components/settings/provider.tsx +54 -0
  10. src/components/tasks/types.ts +28 -28
  11. src/components/tasks/useTasks.tsx +29 -33
  12. src/components/toolbars/top-menu/assistant/index.tsx +6 -2
  13. src/components/toolbars/top-menu/file/index.tsx +12 -19
  14. src/components/toolbars/top-menu/image/index.tsx +7 -2
  15. src/components/toolbars/top-menu/lists/AssistantModelList.tsx +8 -1
  16. src/components/toolbars/top-menu/lists/ImageGenerationModelList.tsx +8 -1
  17. src/components/toolbars/top-menu/lists/ImageUpscalingModelList.tsx +8 -1
  18. src/components/toolbars/top-menu/lists/MusicGenerationModelList.tsx +8 -1
  19. src/components/toolbars/top-menu/lists/ProviderList.tsx +13 -1
  20. src/components/toolbars/top-menu/lists/SoundGenerationModelList.tsx +7 -0
  21. src/components/toolbars/top-menu/lists/VideoGenerationModelList.tsx +13 -2
  22. src/components/toolbars/top-menu/lists/VideoUpscalingModelList.tsx +7 -0
  23. src/components/toolbars/top-menu/lists/VoiceGenerationModelList.tsx +7 -0
  24. src/components/toolbars/top-menu/lists/hasNoPublicAPI.ts +24 -0
  25. src/components/toolbars/top-menu/music/index.tsx +6 -2
  26. src/components/toolbars/top-menu/sound/index.tsx +6 -2
  27. src/components/toolbars/top-menu/video/index.tsx +7 -2
  28. src/components/toolbars/top-menu/view/index.tsx +4 -0
  29. src/components/toolbars/top-menu/voice/index.tsx +6 -2
  30. src/controllers/io/parseFileName.ts +16 -0
  31. src/controllers/io/types.ts +6 -0
  32. src/controllers/io/useIO.ts +191 -18
  33. src/controllers/metrics/constants.ts +18 -0
  34. src/controllers/metrics/getDefaultMetricsPerProvider.ts +18 -0
  35. src/controllers/monitor/useMonitor.ts +8 -3
  36. src/controllers/renderer/types.ts +4 -0
  37. src/controllers/renderer/useRenderLoop.ts +1 -0
  38. src/controllers/renderer/useRenderer.ts +5 -0
  39. src/controllers/resolver/useResolver.ts +5 -7
  40. src/controllers/settings/getDefaultSettingsState.ts +3 -2
  41. src/controllers/settings/types.ts +2 -0
  42. src/controllers/settings/useSettings.ts +5 -1
  43. src/lib/core/constants.ts +1 -1
  44. src/lib/hooks/index.ts +1 -2
  45. src/lib/hooks/{useClapFilePicker.ts → useOpenFilePicker.ts} +37 -10
  46. src/lib/hooks/useScreenplayFilePicker.ts +0 -41
  47. src/lib/utils/parsePdfToIndentedText.ts +10 -0
  48. src/types.ts +24 -0
package-lock.json CHANGED
@@ -1,16 +1,16 @@
1
  {
2
  "name": "@aitube/clapper",
3
- "version": "0.0.0",
4
  "lockfileVersion": 3,
5
  "requires": true,
6
  "packages": {
7
  "": {
8
  "name": "@aitube/clapper",
9
- "version": "0.0.0",
10
  "dependencies": {
11
  "@aitube/clap": "0.0.26",
12
  "@aitube/engine": "0.0.19",
13
- "@aitube/timeline": "file:/Users/jbilcke/Projects/Typescript_Libraries/aitube-timeline",
14
  "@fal-ai/serverless-client": "^0.10.3",
15
  "@huggingface/hub": "^0.15.1",
16
  "@huggingface/inference": "^2.7.0",
@@ -56,12 +56,14 @@
56
  "@upstash/ratelimit": "^1.1.3",
57
  "@upstash/redis": "^1.31.1",
58
  "autoprefixer": "10.4.17",
 
59
  "class-variance-authority": "^0.7.0",
60
  "clsx": "^2.1.0",
61
  "cmdk": "^0.2.1",
62
  "eslint": "8.57.0",
63
  "eslint-config-next": "14.1.0",
64
  "fluent-ffmpeg": "^2.1.3",
 
65
  "fs-extra": "^11.2.0",
66
  "lucide-react": "^0.334.0",
67
  "mlt-xml": "^2.0.2",
@@ -102,46 +104,6 @@
102
  "@types/fluent-ffmpeg": "^2.1.24"
103
  }
104
  },
105
- "../Typescript_Libraries/aitube-timeline": {
106
- "name": "@aitube/timeline",
107
- "version": "0.0.23",
108
- "license": "MIT",
109
- "dependencies": {
110
- "date-fns": "^3.6.0",
111
- "react-virtualized-auto-sizer": "^1.0.24"
112
- },
113
- "devDependencies": {
114
- "@types/react": "*",
115
- "@types/react-dom": "*",
116
- "@typescript-eslint/eslint-plugin": "^7.12.0",
117
- "@typescript-eslint/parser": "^7.12.0",
118
- "@vitejs/plugin-react": "^4.3.0",
119
- "bun-types": "latest",
120
- "eslint": "^8.57.0",
121
- "eslint-plugin-react-hooks": "^4.6.2",
122
- "eslint-plugin-react-refresh": "^0.4.7",
123
- "prettier": "^3.3.2",
124
- "rimraf": "^5.0.7",
125
- "typescript": "^5.4.5",
126
- "vite": "^5.2.13"
127
- },
128
- "peerDependencies": {
129
- "@aitube/clap": "0.0.26",
130
- "@radix-ui/react-slider": "^1.1.2",
131
- "@react-spring/three": "^9.7.3",
132
- "@react-spring/types": "^9.7.3",
133
- "@react-three/drei": "^9.105.4",
134
- "@react-three/fiber": "^8.16.2",
135
- "clsx": "^2.1.1",
136
- "react": "*",
137
- "react-dom": "*",
138
- "tailwind-merge": "^2.3.0",
139
- "tailwindcss": "^3.4.3",
140
- "three": "^0.164.1",
141
- "typescript": "^5.4.5",
142
- "zustand": "4.5.2"
143
- }
144
- },
145
  "node_modules/@aitube/clap": {
146
  "version": "0.0.26",
147
  "resolved": "https://registry.npmjs.org/@aitube/clap/-/clap-0.0.26.tgz",
@@ -162,8 +124,29 @@
162
  }
163
  },
164
  "node_modules/@aitube/timeline": {
165
- "resolved": "../Typescript_Libraries/aitube-timeline",
166
- "link": true
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
167
  },
168
  "node_modules/@alloc/quick-lru": {
169
  "version": "5.2.0",
@@ -304,16 +287,16 @@
304
  "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
305
  },
306
  "node_modules/@aws-sdk/client-cognito-identity": {
307
- "version": "3.592.0",
308
- "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.592.0.tgz",
309
- "integrity": "sha512-mk3JOBsk5hlrLTZFuoGIhFKFflOdxqMKmOgyUFs5+gBLuH0/lN3wNWJxk+BiY1nHzkxhBND1hDHc5dvZRugBJA==",
310
  "dependencies": {
311
  "@aws-crypto/sha256-browser": "3.0.0",
312
  "@aws-crypto/sha256-js": "3.0.0",
313
- "@aws-sdk/client-sso-oidc": "3.592.0",
314
- "@aws-sdk/client-sts": "3.592.0",
315
  "@aws-sdk/core": "3.592.0",
316
- "@aws-sdk/credential-provider-node": "3.592.0",
317
  "@aws-sdk/middleware-host-header": "3.577.0",
318
  "@aws-sdk/middleware-logger": "3.577.0",
319
  "@aws-sdk/middleware-recursion-detection": "3.577.0",
@@ -355,16 +338,16 @@
355
  }
356
  },
357
  "node_modules/@aws-sdk/client-sagemaker": {
358
- "version": "3.595.0",
359
- "resolved": "https://registry.npmjs.org/@aws-sdk/client-sagemaker/-/client-sagemaker-3.595.0.tgz",
360
- "integrity": "sha512-9Ba++g6/QAjwugA3NnQjRrdZunwWVQyCRrBvRzA8qzlh3fA20yMwZzwjVNmSLP/DJ2++eAV0v0lvrN2X5WY4Bw==",
361
  "dependencies": {
362
  "@aws-crypto/sha256-browser": "3.0.0",
363
  "@aws-crypto/sha256-js": "3.0.0",
364
- "@aws-sdk/client-sso-oidc": "3.592.0",
365
- "@aws-sdk/client-sts": "3.592.0",
366
  "@aws-sdk/core": "3.592.0",
367
- "@aws-sdk/credential-provider-node": "3.592.0",
368
  "@aws-sdk/middleware-host-header": "3.577.0",
369
  "@aws-sdk/middleware-logger": "3.577.0",
370
  "@aws-sdk/middleware-recursion-detection": "3.577.0",
@@ -456,15 +439,15 @@
456
  }
457
  },
458
  "node_modules/@aws-sdk/client-sso-oidc": {
459
- "version": "3.592.0",
460
- "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.592.0.tgz",
461
- "integrity": "sha512-11Zvm8nm0s/UF3XCjzFRpQU+8FFVW5rcr3BHfnH6xAe5JEoN6bJN/n+wOfnElnjek+90hh+Qc7s141AMrCjiiw==",
462
  "dependencies": {
463
  "@aws-crypto/sha256-browser": "3.0.0",
464
  "@aws-crypto/sha256-js": "3.0.0",
465
- "@aws-sdk/client-sts": "3.592.0",
466
  "@aws-sdk/core": "3.592.0",
467
- "@aws-sdk/credential-provider-node": "3.592.0",
468
  "@aws-sdk/middleware-host-header": "3.577.0",
469
  "@aws-sdk/middleware-logger": "3.577.0",
470
  "@aws-sdk/middleware-recursion-detection": "3.577.0",
@@ -506,15 +489,15 @@
506
  }
507
  },
508
  "node_modules/@aws-sdk/client-sts": {
509
- "version": "3.592.0",
510
- "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.592.0.tgz",
511
- "integrity": "sha512-KUrOdszZfcrlpKr4dpdkGibZ/qq3Lnfu1rjv1U+V1QJQ9OuMo9J3sDWpWV9tigNqY0aGllarWH5cJbz9868W/w==",
512
  "dependencies": {
513
  "@aws-crypto/sha256-browser": "3.0.0",
514
  "@aws-crypto/sha256-js": "3.0.0",
515
- "@aws-sdk/client-sso-oidc": "3.592.0",
516
  "@aws-sdk/core": "3.592.0",
517
- "@aws-sdk/credential-provider-node": "3.592.0",
518
  "@aws-sdk/middleware-host-header": "3.577.0",
519
  "@aws-sdk/middleware-logger": "3.577.0",
520
  "@aws-sdk/middleware-recursion-detection": "3.577.0",
@@ -594,11 +577,11 @@
594
  }
595
  },
596
  "node_modules/@aws-sdk/credential-provider-cognito-identity": {
597
- "version": "3.592.0",
598
- "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.592.0.tgz",
599
- "integrity": "sha512-uHiMPCkFhZOhlSfKgVqPhMdruiOuVkLUn07gQqvxHYhFKkEOPV+6BZbPKBwBTXr8TIREztQzCMPswa5pGk2zbQ==",
600
  "dependencies": {
601
- "@aws-sdk/client-cognito-identity": "3.592.0",
602
  "@aws-sdk/types": "3.577.0",
603
  "@smithy/property-provider": "^3.1.0",
604
  "@smithy/types": "^3.0.0",
@@ -623,9 +606,9 @@
623
  }
624
  },
625
  "node_modules/@aws-sdk/credential-provider-http": {
626
- "version": "3.587.0",
627
- "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.587.0.tgz",
628
- "integrity": "sha512-Su1SRWVRCuR1e32oxX3C1V4c5hpPN20WYcRfdcr2wXwHqSvys5DrnmuCC+JoEnS/zt3adUJhPliTqpfKgSdMrA==",
629
  "dependencies": {
630
  "@aws-sdk/types": "3.577.0",
631
  "@smithy/fetch-http-handler": "^3.0.1",
@@ -642,12 +625,12 @@
642
  }
643
  },
644
  "node_modules/@aws-sdk/credential-provider-ini": {
645
- "version": "3.592.0",
646
- "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.592.0.tgz",
647
- "integrity": "sha512-3kG6ngCIOPbLJZZ3RV+NsU7HVK6vX1+1DrPJKj9fVlPYn7IXsk8NAaUT5885yC7+jKizjv0cWLrLKvAJV5gfUA==",
648
  "dependencies": {
649
  "@aws-sdk/credential-provider-env": "3.587.0",
650
- "@aws-sdk/credential-provider-http": "3.587.0",
651
  "@aws-sdk/credential-provider-process": "3.587.0",
652
  "@aws-sdk/credential-provider-sso": "3.592.0",
653
  "@aws-sdk/credential-provider-web-identity": "3.587.0",
@@ -662,17 +645,17 @@
662
  "node": ">=16.0.0"
663
  },
664
  "peerDependencies": {
665
- "@aws-sdk/client-sts": "^3.592.0"
666
  }
667
  },
668
  "node_modules/@aws-sdk/credential-provider-node": {
669
- "version": "3.592.0",
670
- "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.592.0.tgz",
671
- "integrity": "sha512-BguihBGTrEjVBQ07hm+ZsO29eNJaxwBwUZMftgGAm2XcMIEClNPfm5hydxu2BmA4ouIJQJ6nG8pNYghEumM+Aw==",
672
  "dependencies": {
673
  "@aws-sdk/credential-provider-env": "3.587.0",
674
- "@aws-sdk/credential-provider-http": "3.587.0",
675
- "@aws-sdk/credential-provider-ini": "3.592.0",
676
  "@aws-sdk/credential-provider-process": "3.587.0",
677
  "@aws-sdk/credential-provider-sso": "3.592.0",
678
  "@aws-sdk/credential-provider-web-identity": "3.587.0",
@@ -737,18 +720,18 @@
737
  }
738
  },
739
  "node_modules/@aws-sdk/credential-providers": {
740
- "version": "3.592.0",
741
- "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.592.0.tgz",
742
- "integrity": "sha512-fHAt001Aemiy9p8VtLKWiPQ36g1YgiLC1pm31W+WmKxU663dbt2yYTIAyVOB1nQC7HrVCOZEg2FU0TtuZt/wXQ==",
743
  "dependencies": {
744
- "@aws-sdk/client-cognito-identity": "3.592.0",
745
  "@aws-sdk/client-sso": "3.592.0",
746
- "@aws-sdk/client-sts": "3.592.0",
747
- "@aws-sdk/credential-provider-cognito-identity": "3.592.0",
748
  "@aws-sdk/credential-provider-env": "3.587.0",
749
- "@aws-sdk/credential-provider-http": "3.587.0",
750
- "@aws-sdk/credential-provider-ini": "3.592.0",
751
- "@aws-sdk/credential-provider-node": "3.592.0",
752
  "@aws-sdk/credential-provider-process": "3.587.0",
753
  "@aws-sdk/credential-provider-sso": "3.592.0",
754
  "@aws-sdk/credential-provider-web-identity": "3.587.0",
@@ -1195,6 +1178,12 @@
1195
  "semver": "bin/semver.js"
1196
  }
1197
  },
 
 
 
 
 
 
1198
  "node_modules/@babel/helper-environment-visitor": {
1199
  "version": "7.24.7",
1200
  "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz",
@@ -2614,9 +2603,9 @@
2614
  }
2615
  },
2616
  "node_modules/@preact/signals-core": {
2617
- "version": "1.6.0",
2618
- "resolved": "https://registry.npmjs.org/@preact/signals-core/-/signals-core-1.6.0.tgz",
2619
- "integrity": "sha512-O/XGxwP85h1F7+ouqTMOIZ3+V1whfaV9ToIVcuyGriD4JkSD00cQo54BKdqjvBJxbenvp7ynfqRHEwI6e+NIhw==",
2620
  "funding": {
2621
  "type": "opencollective",
2622
  "url": "https://opencollective.com/preact"
@@ -4035,11 +4024,11 @@
4035
  "integrity": "sha512-qC/xYId4NMebE6w/V33Fh9gWxLgURiNYgVNObbJl2LZv0GUUItCcCqC5axQSwRaAgaxl2mELq1rMzlswaQ0Zxg=="
4036
  },
4037
  "node_modules/@smithy/abort-controller": {
4038
- "version": "3.0.0",
4039
- "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-3.0.0.tgz",
4040
- "integrity": "sha512-p6GlFGBt9K4MYLu72YuJ523NVR4A8oHlC5M2JO6OmQqN8kAc/uh1JqLE+FizTokrSJGg0CSvC+BrsmGzKtsZKA==",
4041
  "dependencies": {
4042
- "@smithy/types": "^3.0.0",
4043
  "tslib": "^2.6.2"
4044
  },
4045
  "engines": {
@@ -4047,14 +4036,14 @@
4047
  }
4048
  },
4049
  "node_modules/@smithy/config-resolver": {
4050
- "version": "3.0.1",
4051
- "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-3.0.1.tgz",
4052
- "integrity": "sha512-hbkYJc20SBDz2qqLzttjI/EqXemtmWk0ooRznLsiXp3066KQRTvuKHa7U4jCZCJq6Dozqvy0R1/vNESC9inPJg==",
4053
  "dependencies": {
4054
- "@smithy/node-config-provider": "^3.1.0",
4055
- "@smithy/types": "^3.0.0",
4056
  "@smithy/util-config-provider": "^3.0.0",
4057
- "@smithy/util-middleware": "^3.0.0",
4058
  "tslib": "^2.6.2"
4059
  },
4060
  "engines": {
@@ -4062,17 +4051,17 @@
4062
  }
4063
  },
4064
  "node_modules/@smithy/core": {
4065
- "version": "2.2.0",
4066
- "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.2.0.tgz",
4067
- "integrity": "sha512-ygLZSSKgt9bR8HAxR9mK+U5obvAJBr6zlQuhN5soYWx/amjDoQN4dTkydTypgKe6rIbUjTILyLU+W5XFwXr4kg==",
4068
- "dependencies": {
4069
- "@smithy/middleware-endpoint": "^3.0.1",
4070
- "@smithy/middleware-retry": "^3.0.3",
4071
- "@smithy/middleware-serde": "^3.0.0",
4072
- "@smithy/protocol-http": "^4.0.0",
4073
- "@smithy/smithy-client": "^3.1.1",
4074
- "@smithy/types": "^3.0.0",
4075
- "@smithy/util-middleware": "^3.0.0",
4076
  "tslib": "^2.6.2"
4077
  },
4078
  "engines": {
@@ -4080,14 +4069,14 @@
4080
  }
4081
  },
4082
  "node_modules/@smithy/credential-provider-imds": {
4083
- "version": "3.1.0",
4084
- "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-3.1.0.tgz",
4085
- "integrity": "sha512-q4A4d38v8pYYmseu/jTS3Z5I3zXlEOe5Obi+EJreVKgSVyWUHOd7/yaVCinC60QG4MRyCs98tcxBH1IMC0bu7Q==",
4086
  "dependencies": {
4087
- "@smithy/node-config-provider": "^3.1.0",
4088
- "@smithy/property-provider": "^3.1.0",
4089
- "@smithy/types": "^3.0.0",
4090
- "@smithy/url-parser": "^3.0.0",
4091
  "tslib": "^2.6.2"
4092
  },
4093
  "engines": {
@@ -4128,23 +4117,23 @@
4128
  }
4129
  },
4130
  "node_modules/@smithy/fetch-http-handler": {
4131
- "version": "3.0.1",
4132
- "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-3.0.1.tgz",
4133
- "integrity": "sha512-uaH74i5BDj+rBwoQaXioKpI0SHBJFtOVwzrCpxZxphOW0ki5jhj7dXvDMYM2IJem8TpdFvS2iC08sjOblfFGFg==",
4134
  "dependencies": {
4135
- "@smithy/protocol-http": "^4.0.0",
4136
- "@smithy/querystring-builder": "^3.0.0",
4137
- "@smithy/types": "^3.0.0",
4138
  "@smithy/util-base64": "^3.0.0",
4139
  "tslib": "^2.6.2"
4140
  }
4141
  },
4142
  "node_modules/@smithy/hash-node": {
4143
- "version": "3.0.0",
4144
- "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-3.0.0.tgz",
4145
- "integrity": "sha512-84qXstNemP3XS5jcof0el6+bDfjzuvhJPQTEfro3lgtbCtKgzPm3MgiS6ehXVPjeQ5+JS0HqmTz8f/RYfzHVxw==",
4146
  "dependencies": {
4147
- "@smithy/types": "^3.0.0",
4148
  "@smithy/util-buffer-from": "^3.0.0",
4149
  "@smithy/util-utf8": "^3.0.0",
4150
  "tslib": "^2.6.2"
@@ -4154,11 +4143,11 @@
4154
  }
4155
  },
4156
  "node_modules/@smithy/invalid-dependency": {
4157
- "version": "3.0.0",
4158
- "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-3.0.0.tgz",
4159
- "integrity": "sha512-F6wBBaEFgJzj0s4KUlliIGPmqXemwP6EavgvDqYwCH40O5Xr2iMHvS8todmGVZtuJCorBkXsYLyTu4PuizVq5g==",
4160
  "dependencies": {
4161
- "@smithy/types": "^3.0.0",
4162
  "tslib": "^2.6.2"
4163
  }
4164
  },
@@ -4174,12 +4163,12 @@
4174
  }
4175
  },
4176
  "node_modules/@smithy/middleware-content-length": {
4177
- "version": "3.0.0",
4178
- "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-3.0.0.tgz",
4179
- "integrity": "sha512-3C4s4d/iGobgCtk2tnWW6+zSTOBg1PRAm2vtWZLdriwTroFbbWNSr3lcyzHdrQHnEXYCC5K52EbpfodaIUY8sg==",
4180
  "dependencies": {
4181
- "@smithy/protocol-http": "^4.0.0",
4182
- "@smithy/types": "^3.0.0",
4183
  "tslib": "^2.6.2"
4184
  },
4185
  "engines": {
@@ -4187,16 +4176,16 @@
4187
  }
4188
  },
4189
  "node_modules/@smithy/middleware-endpoint": {
4190
- "version": "3.0.1",
4191
- "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-3.0.1.tgz",
4192
- "integrity": "sha512-lQ/UOdGD4KM5kLZiAl0q8Qy3dPbynvAXKAdXnYlrA1OpaUwr+neSsVokDZpY6ZVb5Yx8jnus29uv6XWpM9P4SQ==",
4193
- "dependencies": {
4194
- "@smithy/middleware-serde": "^3.0.0",
4195
- "@smithy/node-config-provider": "^3.1.0",
4196
- "@smithy/shared-ini-file-loader": "^3.1.0",
4197
- "@smithy/types": "^3.0.0",
4198
- "@smithy/url-parser": "^3.0.0",
4199
- "@smithy/util-middleware": "^3.0.0",
4200
  "tslib": "^2.6.2"
4201
  },
4202
  "engines": {
@@ -4204,17 +4193,17 @@
4204
  }
4205
  },
4206
  "node_modules/@smithy/middleware-retry": {
4207
- "version": "3.0.3",
4208
- "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.3.tgz",
4209
- "integrity": "sha512-Wve1qzJb83VEU/6q+/I0cQdAkDnuzELC6IvIBwDzUEiGpKqXgX1v10FUuZGbRS6Ov/P+HHthcAoHOJZQvZNAkA==",
4210
- "dependencies": {
4211
- "@smithy/node-config-provider": "^3.1.0",
4212
- "@smithy/protocol-http": "^4.0.0",
4213
- "@smithy/service-error-classification": "^3.0.0",
4214
- "@smithy/smithy-client": "^3.1.1",
4215
- "@smithy/types": "^3.0.0",
4216
- "@smithy/util-middleware": "^3.0.0",
4217
- "@smithy/util-retry": "^3.0.0",
4218
  "tslib": "^2.6.2",
4219
  "uuid": "^9.0.1"
4220
  },
@@ -4223,11 +4212,11 @@
4223
  }
4224
  },
4225
  "node_modules/@smithy/middleware-serde": {
4226
- "version": "3.0.0",
4227
- "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-3.0.0.tgz",
4228
- "integrity": "sha512-I1vKG1foI+oPgG9r7IMY1S+xBnmAn1ISqployvqkwHoSb8VPsngHDTOgYGYBonuOKndaWRUGJZrKYYLB+Ane6w==",
4229
  "dependencies": {
4230
- "@smithy/types": "^3.0.0",
4231
  "tslib": "^2.6.2"
4232
  },
4233
  "engines": {
@@ -4235,11 +4224,11 @@
4235
  }
4236
  },
4237
  "node_modules/@smithy/middleware-stack": {
4238
- "version": "3.0.0",
4239
- "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-3.0.0.tgz",
4240
- "integrity": "sha512-+H0jmyfAyHRFXm6wunskuNAqtj7yfmwFB6Fp37enytp2q047/Od9xetEaUbluyImOlGnGpaVGaVfjwawSr+i6Q==",
4241
  "dependencies": {
4242
- "@smithy/types": "^3.0.0",
4243
  "tslib": "^2.6.2"
4244
  },
4245
  "engines": {
@@ -4247,13 +4236,13 @@
4247
  }
4248
  },
4249
  "node_modules/@smithy/node-config-provider": {
4250
- "version": "3.1.0",
4251
- "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-3.1.0.tgz",
4252
- "integrity": "sha512-ngfB8QItUfTFTfHMvKuc2g1W60V1urIgZHqD1JNFZC2tTWXahqf2XvKXqcBS7yZqR7GqkQQZy11y/lNOUWzq7Q==",
4253
  "dependencies": {
4254
- "@smithy/property-provider": "^3.1.0",
4255
- "@smithy/shared-ini-file-loader": "^3.1.0",
4256
- "@smithy/types": "^3.0.0",
4257
  "tslib": "^2.6.2"
4258
  },
4259
  "engines": {
@@ -4261,14 +4250,14 @@
4261
  }
4262
  },
4263
  "node_modules/@smithy/node-http-handler": {
4264
- "version": "3.0.0",
4265
- "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-3.0.0.tgz",
4266
- "integrity": "sha512-3trD4r7NOMygwLbUJo4eodyQuypAWr7uvPnebNJ9a70dQhVn+US8j/lCnvoJS6BXfZeF7PkkkI0DemVJw+n+eQ==",
4267
  "dependencies": {
4268
- "@smithy/abort-controller": "^3.0.0",
4269
- "@smithy/protocol-http": "^4.0.0",
4270
- "@smithy/querystring-builder": "^3.0.0",
4271
- "@smithy/types": "^3.0.0",
4272
  "tslib": "^2.6.2"
4273
  },
4274
  "engines": {
@@ -4276,11 +4265,11 @@
4276
  }
4277
  },
4278
  "node_modules/@smithy/property-provider": {
4279
- "version": "3.1.0",
4280
- "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.0.tgz",
4281
- "integrity": "sha512-Tj3+oVhqdZgemjCiWjFlADfhvLF4C/uKDuKo7/tlEsRQ9+3emCreR2xndj970QSRSsiCEU8hZW3/8JQu+n5w4Q==",
4282
  "dependencies": {
4283
- "@smithy/types": "^3.0.0",
4284
  "tslib": "^2.6.2"
4285
  },
4286
  "engines": {
@@ -4288,11 +4277,11 @@
4288
  }
4289
  },
4290
  "node_modules/@smithy/protocol-http": {
4291
- "version": "4.0.0",
4292
- "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.0.0.tgz",
4293
- "integrity": "sha512-qOQZOEI2XLWRWBO9AgIYuHuqjZ2csyr8/IlgFDHDNuIgLAMRx2Bl8ck5U5D6Vh9DPdoaVpuzwWMa0xcdL4O/AQ==",
4294
  "dependencies": {
4295
- "@smithy/types": "^3.0.0",
4296
  "tslib": "^2.6.2"
4297
  },
4298
  "engines": {
@@ -4300,11 +4289,11 @@
4300
  }
4301
  },
4302
  "node_modules/@smithy/querystring-builder": {
4303
- "version": "3.0.0",
4304
- "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-3.0.0.tgz",
4305
- "integrity": "sha512-bW8Fi0NzyfkE0TmQphDXr1AmBDbK01cA4C1Z7ggwMAU5RDz5AAv/KmoRwzQAS0kxXNf/D2ALTEgwK0U2c4LtRg==",
4306
  "dependencies": {
4307
- "@smithy/types": "^3.0.0",
4308
  "@smithy/util-uri-escape": "^3.0.0",
4309
  "tslib": "^2.6.2"
4310
  },
@@ -4313,11 +4302,11 @@
4313
  }
4314
  },
4315
  "node_modules/@smithy/querystring-parser": {
4316
- "version": "3.0.0",
4317
- "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-3.0.0.tgz",
4318
- "integrity": "sha512-UzHwthk0UEccV4dHzPySnBy34AWw3V9lIqUTxmozQ+wPDAO9csCWMfOLe7V9A2agNYy7xE+Pb0S6K/J23JSzfQ==",
4319
  "dependencies": {
4320
- "@smithy/types": "^3.0.0",
4321
  "tslib": "^2.6.2"
4322
  },
4323
  "engines": {
@@ -4325,22 +4314,22 @@
4325
  }
4326
  },
4327
  "node_modules/@smithy/service-error-classification": {
4328
- "version": "3.0.0",
4329
- "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-3.0.0.tgz",
4330
- "integrity": "sha512-3BsBtOUt2Gsnc3X23ew+r2M71WwtpHfEDGhHYHSDg6q1t8FrWh15jT25DLajFV1H+PpxAJ6gqe9yYeRUsmSdFA==",
4331
  "dependencies": {
4332
- "@smithy/types": "^3.0.0"
4333
  },
4334
  "engines": {
4335
  "node": ">=16.0.0"
4336
  }
4337
  },
4338
  "node_modules/@smithy/shared-ini-file-loader": {
4339
- "version": "3.1.0",
4340
- "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-3.1.0.tgz",
4341
- "integrity": "sha512-dAM7wSX0NR3qTNyGVN/nwwpEDzfV9T/3AN2eABExWmda5VqZKSsjlINqomO5hjQWGv+IIkoXfs3u2vGSNz8+Rg==",
4342
  "dependencies": {
4343
- "@smithy/types": "^3.0.0",
4344
  "tslib": "^2.6.2"
4345
  },
4346
  "engines": {
@@ -4348,14 +4337,14 @@
4348
  }
4349
  },
4350
  "node_modules/@smithy/signature-v4": {
4351
- "version": "3.0.0",
4352
- "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-3.0.0.tgz",
4353
- "integrity": "sha512-kXFOkNX+BQHe2qnLxpMEaCRGap9J6tUGLzc3A9jdn+nD4JdMwCKTJ+zFwQ20GkY+mAXGatyTw3HcoUlR39HwmA==",
4354
  "dependencies": {
4355
  "@smithy/is-array-buffer": "^3.0.0",
4356
- "@smithy/types": "^3.0.0",
4357
  "@smithy/util-hex-encoding": "^3.0.0",
4358
- "@smithy/util-middleware": "^3.0.0",
4359
  "@smithy/util-uri-escape": "^3.0.0",
4360
  "@smithy/util-utf8": "^3.0.0",
4361
  "tslib": "^2.6.2"
@@ -4365,15 +4354,15 @@
4365
  }
4366
  },
4367
  "node_modules/@smithy/smithy-client": {
4368
- "version": "3.1.1",
4369
- "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.1.tgz",
4370
- "integrity": "sha512-tj4Ku7MpzZR8cmVuPcSbrLFVxmptWktmJMwST/uIEq4sarabEdF8CbmQdYB7uJ/X51Qq2EYwnRsoS7hdR4B7rA==",
4371
- "dependencies": {
4372
- "@smithy/middleware-endpoint": "^3.0.1",
4373
- "@smithy/middleware-stack": "^3.0.0",
4374
- "@smithy/protocol-http": "^4.0.0",
4375
- "@smithy/types": "^3.0.0",
4376
- "@smithy/util-stream": "^3.0.1",
4377
  "tslib": "^2.6.2"
4378
  },
4379
  "engines": {
@@ -4381,9 +4370,9 @@
4381
  }
4382
  },
4383
  "node_modules/@smithy/types": {
4384
- "version": "3.0.0",
4385
- "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.0.0.tgz",
4386
- "integrity": "sha512-VvWuQk2RKFuOr98gFhjca7fkBS+xLLURT8bUjk5XQoV0ZLm7WPwWPPY3/AwzTLuUBDeoKDCthfe1AsTUWaSEhw==",
4387
  "dependencies": {
4388
  "tslib": "^2.6.2"
4389
  },
@@ -4392,12 +4381,12 @@
4392
  }
4393
  },
4394
  "node_modules/@smithy/url-parser": {
4395
- "version": "3.0.0",
4396
- "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-3.0.0.tgz",
4397
- "integrity": "sha512-2XLazFgUu+YOGHtWihB3FSLAfCUajVfNBXGGYjOaVKjLAuAxx3pSBY3hBgLzIgB17haf59gOG3imKqTy8mcrjw==",
4398
  "dependencies": {
4399
- "@smithy/querystring-parser": "^3.0.0",
4400
- "@smithy/types": "^3.0.0",
4401
  "tslib": "^2.6.2"
4402
  }
4403
  },
@@ -4457,13 +4446,13 @@
4457
  }
4458
  },
4459
  "node_modules/@smithy/util-defaults-mode-browser": {
4460
- "version": "3.0.3",
4461
- "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.3.tgz",
4462
- "integrity": "sha512-3DFON2bvXJAukJe+qFgPV/rorG7ZD3m4gjCXHD1V5z/tgKQp5MCTCLntrd686tX6tj8Uli3lefWXJudNg5WmCA==",
4463
  "dependencies": {
4464
- "@smithy/property-provider": "^3.1.0",
4465
- "@smithy/smithy-client": "^3.1.1",
4466
- "@smithy/types": "^3.0.0",
4467
  "bowser": "^2.11.0",
4468
  "tslib": "^2.6.2"
4469
  },
@@ -4472,16 +4461,16 @@
4472
  }
4473
  },
4474
  "node_modules/@smithy/util-defaults-mode-node": {
4475
- "version": "3.0.3",
4476
- "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.3.tgz",
4477
- "integrity": "sha512-D0b8GJXecT00baoSQ3Iieu3k3mZ7GY8w1zmg8pdogYrGvWJeLcIclqk2gbkG4K0DaBGWrO6v6r20iwIFfDYrmA==",
4478
- "dependencies": {
4479
- "@smithy/config-resolver": "^3.0.1",
4480
- "@smithy/credential-provider-imds": "^3.1.0",
4481
- "@smithy/node-config-provider": "^3.1.0",
4482
- "@smithy/property-provider": "^3.1.0",
4483
- "@smithy/smithy-client": "^3.1.1",
4484
- "@smithy/types": "^3.0.0",
4485
  "tslib": "^2.6.2"
4486
  },
4487
  "engines": {
@@ -4489,12 +4478,12 @@
4489
  }
4490
  },
4491
  "node_modules/@smithy/util-endpoints": {
4492
- "version": "2.0.1",
4493
- "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-2.0.1.tgz",
4494
- "integrity": "sha512-ZRT0VCOnKlVohfoABMc8lWeQo/JEFuPWctfNRXgTHbyOVssMOLYFUNWukxxiHRGVAhV+n3c0kPW+zUqckjVPEA==",
4495
  "dependencies": {
4496
- "@smithy/node-config-provider": "^3.1.0",
4497
- "@smithy/types": "^3.0.0",
4498
  "tslib": "^2.6.2"
4499
  },
4500
  "engines": {
@@ -4513,11 +4502,11 @@
4513
  }
4514
  },
4515
  "node_modules/@smithy/util-middleware": {
4516
- "version": "3.0.0",
4517
- "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-3.0.0.tgz",
4518
- "integrity": "sha512-q5ITdOnV2pXHSVDnKWrwgSNTDBAMHLptFE07ua/5Ty5WJ11bvr0vk2a7agu7qRhrCFRQlno5u3CneU5EELK+DQ==",
4519
  "dependencies": {
4520
- "@smithy/types": "^3.0.0",
4521
  "tslib": "^2.6.2"
4522
  },
4523
  "engines": {
@@ -4525,12 +4514,12 @@
4525
  }
4526
  },
4527
  "node_modules/@smithy/util-retry": {
4528
- "version": "3.0.0",
4529
- "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-3.0.0.tgz",
4530
- "integrity": "sha512-nK99bvJiziGv/UOKJlDvFF45F00WgPLKVIGUfAK+mDhzVN2hb/S33uW2Tlhg5PVBoqY7tDVqL0zmu4OxAHgo9g==",
4531
  "dependencies": {
4532
- "@smithy/service-error-classification": "^3.0.0",
4533
- "@smithy/types": "^3.0.0",
4534
  "tslib": "^2.6.2"
4535
  },
4536
  "engines": {
@@ -4538,13 +4527,13 @@
4538
  }
4539
  },
4540
  "node_modules/@smithy/util-stream": {
4541
- "version": "3.0.1",
4542
- "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-3.0.1.tgz",
4543
- "integrity": "sha512-7F7VNNhAsfMRA8I986YdOY5fE0/T1/ZjFF6OLsqkvQVNP3vZ/szYDfGCyphb7ioA09r32K/0qbSFfNFU68aSzA==",
4544
  "dependencies": {
4545
- "@smithy/fetch-http-handler": "^3.0.1",
4546
- "@smithy/node-http-handler": "^3.0.0",
4547
- "@smithy/types": "^3.0.0",
4548
  "@smithy/util-base64": "^3.0.0",
4549
  "@smithy/util-buffer-from": "^3.0.0",
4550
  "@smithy/util-hex-encoding": "^3.0.0",
@@ -4579,12 +4568,12 @@
4579
  }
4580
  },
4581
  "node_modules/@smithy/util-waiter": {
4582
- "version": "3.0.0",
4583
- "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-3.0.0.tgz",
4584
- "integrity": "sha512-+fEXJxGDLCoqRKVSmo0auGxaqbiCo+8oph+4auefYjaNxjOLKSY2MxVQfRzo65PaZv4fr+5lWg+au7vSuJJ/zw==",
4585
  "dependencies": {
4586
- "@smithy/abort-controller": "^3.0.0",
4587
- "@smithy/types": "^3.0.0",
4588
  "tslib": "^2.6.2"
4589
  },
4590
  "engines": {
@@ -4898,17 +4887,17 @@
4898
  }
4899
  },
4900
  "node_modules/@upstash/ratelimit": {
4901
- "version": "1.2.0",
4902
- "resolved": "https://registry.npmjs.org/@upstash/ratelimit/-/ratelimit-1.2.0.tgz",
4903
- "integrity": "sha512-03mNBUNz9EvIJCxhU0OtFWO3OSQE4gShFBlGph+hDPm9k7O75We1NYS/tCXSdmLVXtOvUGSmi5fyKQLBTEGWxw==",
4904
  "dependencies": {
4905
  "@upstash/core-analytics": "^0.0.9"
4906
  }
4907
  },
4908
  "node_modules/@upstash/redis": {
4909
- "version": "1.31.4",
4910
- "resolved": "https://registry.npmjs.org/@upstash/redis/-/redis-1.31.4.tgz",
4911
- "integrity": "sha512-roJjsdAOUWGVCuiA5R2ajkR41n0KrO4DGil2ZbRaj3m0F2bMUMZ3d5KaUGgDQshPpGkW2+nwFLzN5M5VQoR1pQ==",
4912
  "dependencies": {
4913
  "crypto-js": "^4.2.0"
4914
  }
@@ -5323,6 +5312,16 @@
5323
  "node": ">=4"
5324
  }
5325
  },
 
 
 
 
 
 
 
 
 
 
5326
  "node_modules/axobject-query": {
5327
  "version": "3.2.1",
5328
  "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz",
@@ -5569,9 +5568,9 @@
5569
  }
5570
  },
5571
  "node_modules/caniuse-lite": {
5572
- "version": "1.0.30001632",
5573
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001632.tgz",
5574
- "integrity": "sha512-udx3o7yHJfUxMLkGohMlVHCvFvWmirKh9JAH/d7WOLPetlH+LTL5cocMZ0t7oZx/mdlOWXti97xLZWc8uURRHg==",
5575
  "funding": [
5576
  {
5577
  "type": "opencollective",
@@ -6233,6 +6232,15 @@
6233
  "url": "https://github.com/sponsors/ljharb"
6234
  }
6235
  },
 
 
 
 
 
 
 
 
 
6236
  "node_modules/debounce": {
6237
  "version": "1.2.1",
6238
  "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz",
@@ -6473,9 +6481,9 @@
6473
  }
6474
  },
6475
  "node_modules/electron-to-chromium": {
6476
- "version": "1.4.799",
6477
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.799.tgz",
6478
- "integrity": "sha512-3D3DwWkRTzrdEpntY0hMLYwj7SeBk1138CkPE8sBDSj3WzrzOiG2rHm3luw8jucpf+WiyLBCZyU9lMHyQI9M9Q=="
6479
  },
6480
  "node_modules/emoji-regex": {
6481
  "version": "9.2.2",
@@ -7336,6 +7344,25 @@
7336
  "which": "bin/which"
7337
  }
7338
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7339
  "node_modules/for-each": {
7340
  "version": "0.3.3",
7341
  "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
@@ -7703,22 +7730,6 @@
7703
  "node": ">=12"
7704
  }
7705
  },
7706
- "node_modules/google-auth-library/node_modules/lru-cache": {
7707
- "version": "6.0.0",
7708
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
7709
- "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
7710
- "dependencies": {
7711
- "yallist": "^4.0.0"
7712
- },
7713
- "engines": {
7714
- "node": ">=10"
7715
- }
7716
- },
7717
- "node_modules/google-auth-library/node_modules/yallist": {
7718
- "version": "4.0.0",
7719
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
7720
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
7721
- },
7722
  "node_modules/google-p12-pem": {
7723
  "version": "4.0.1",
7724
  "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-4.0.1.tgz",
@@ -8757,11 +8768,14 @@
8757
  }
8758
  },
8759
  "node_modules/lru-cache": {
8760
- "version": "10.2.2",
8761
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz",
8762
- "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==",
 
 
 
8763
  "engines": {
8764
- "node": "14 || >=16.14"
8765
  }
8766
  },
8767
  "node_modules/lucide-react": {
@@ -9308,9 +9322,9 @@
9308
  }
9309
  },
9310
  "node_modules/openai": {
9311
- "version": "4.50.0",
9312
- "resolved": "https://registry.npmjs.org/openai/-/openai-4.50.0.tgz",
9313
- "integrity": "sha512-2ADkNIU6Q589oYHr5pn9k7SbUcrBTK9X0rIXrYqwMVSoqOj1yK9/1OO0ExaWsqOOpD7o58UmRjeKlx9gKAcuKQ==",
9314
  "dependencies": {
9315
  "@types/node": "^18.11.18",
9316
  "@types/node-fetch": "^2.6.4",
@@ -9546,6 +9560,14 @@
9546
  "url": "https://github.com/sponsors/isaacs"
9547
  }
9548
  },
 
 
 
 
 
 
 
 
9549
  "node_modules/path-type": {
9550
  "version": "4.0.0",
9551
  "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
@@ -9822,6 +9844,11 @@
9822
  "react-is": "^16.13.1"
9823
  }
9824
  },
 
 
 
 
 
9825
  "node_modules/punycode": {
9826
  "version": "2.3.1",
9827
  "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
@@ -10158,6 +10185,15 @@
10158
  "react-dom": ">=16.13"
10159
  }
10160
  },
 
 
 
 
 
 
 
 
 
10161
  "node_modules/read-cache": {
10162
  "version": "1.0.0",
10163
  "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
@@ -11896,10 +11932,9 @@
11896
  "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
11897
  },
11898
  "node_modules/yallist": {
11899
- "version": "3.1.1",
11900
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
11901
- "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
11902
- "peer": true
11903
  },
11904
  "node_modules/yaml": {
11905
  "version": "2.4.5",
 
1
  {
2
  "name": "@aitube/clapper",
3
+ "version": "0.0.1",
4
  "lockfileVersion": 3,
5
  "requires": true,
6
  "packages": {
7
  "": {
8
  "name": "@aitube/clapper",
9
+ "version": "0.0.1",
10
  "dependencies": {
11
  "@aitube/clap": "0.0.26",
12
  "@aitube/engine": "0.0.19",
13
+ "@aitube/timeline": "0.0.24",
14
  "@fal-ai/serverless-client": "^0.10.3",
15
  "@huggingface/hub": "^0.15.1",
16
  "@huggingface/inference": "^2.7.0",
 
56
  "@upstash/ratelimit": "^1.1.3",
57
  "@upstash/redis": "^1.31.1",
58
  "autoprefixer": "10.4.17",
59
+ "axios": "^1.7.2",
60
  "class-variance-authority": "^0.7.0",
61
  "clsx": "^2.1.0",
62
  "cmdk": "^0.2.1",
63
  "eslint": "8.57.0",
64
  "eslint-config-next": "14.1.0",
65
  "fluent-ffmpeg": "^2.1.3",
66
+ "form-data": "^4.0.0",
67
  "fs-extra": "^11.2.0",
68
  "lucide-react": "^0.334.0",
69
  "mlt-xml": "^2.0.2",
 
104
  "@types/fluent-ffmpeg": "^2.1.24"
105
  }
106
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
107
  "node_modules/@aitube/clap": {
108
  "version": "0.0.26",
109
  "resolved": "https://registry.npmjs.org/@aitube/clap/-/clap-0.0.26.tgz",
 
124
  }
125
  },
126
  "node_modules/@aitube/timeline": {
127
+ "version": "0.0.24",
128
+ "resolved": "https://registry.npmjs.org/@aitube/timeline/-/timeline-0.0.24.tgz",
129
+ "integrity": "sha512-CkR9xge1yaoKVCwMuz0Vp80YOylbTcynyNM/IcnWnbAaRahfaUhs+UhBpxVMV4Wd9gj+czevL1wjcoU7vboj9A==",
130
+ "dependencies": {
131
+ "date-fns": "^3.6.0",
132
+ "react-virtualized-auto-sizer": "^1.0.24"
133
+ },
134
+ "peerDependencies": {
135
+ "@aitube/clap": "0.0.26",
136
+ "@radix-ui/react-slider": "^1.1.2",
137
+ "@react-spring/three": "^9.7.3",
138
+ "@react-spring/types": "^9.7.3",
139
+ "@react-three/drei": "^9.105.4",
140
+ "@react-three/fiber": "^8.16.2",
141
+ "clsx": "^2.1.1",
142
+ "react": "*",
143
+ "react-dom": "*",
144
+ "tailwind-merge": "^2.3.0",
145
+ "tailwindcss": "^3.4.3",
146
+ "three": "^0.164.1",
147
+ "typescript": "^5.4.5",
148
+ "zustand": "4.5.2"
149
+ }
150
  },
151
  "node_modules/@alloc/quick-lru": {
152
  "version": "5.2.0",
 
287
  "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
288
  },
289
  "node_modules/@aws-sdk/client-cognito-identity": {
290
+ "version": "3.596.0",
291
+ "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.596.0.tgz",
292
+ "integrity": "sha512-EnMebSL120H1V3CvxlSDu7xVg/c/U19J2pw5t3TbgWdP0bWR4gmaf2m7wczyi5XtPel0NIklnpPhlDJqr6T4Eg==",
293
  "dependencies": {
294
  "@aws-crypto/sha256-browser": "3.0.0",
295
  "@aws-crypto/sha256-js": "3.0.0",
296
+ "@aws-sdk/client-sso-oidc": "3.596.0",
297
+ "@aws-sdk/client-sts": "3.596.0",
298
  "@aws-sdk/core": "3.592.0",
299
+ "@aws-sdk/credential-provider-node": "3.596.0",
300
  "@aws-sdk/middleware-host-header": "3.577.0",
301
  "@aws-sdk/middleware-logger": "3.577.0",
302
  "@aws-sdk/middleware-recursion-detection": "3.577.0",
 
338
  }
339
  },
340
  "node_modules/@aws-sdk/client-sagemaker": {
341
+ "version": "3.596.0",
342
+ "resolved": "https://registry.npmjs.org/@aws-sdk/client-sagemaker/-/client-sagemaker-3.596.0.tgz",
343
+ "integrity": "sha512-VDEo+pVw4fl9X18mEz0uj2rULke8QQ2QvpFWJ5oXGUqYCQRBqYOHaYtUvC+4kvj4vLmrmhTxYA6mO91tGbNadg==",
344
  "dependencies": {
345
  "@aws-crypto/sha256-browser": "3.0.0",
346
  "@aws-crypto/sha256-js": "3.0.0",
347
+ "@aws-sdk/client-sso-oidc": "3.596.0",
348
+ "@aws-sdk/client-sts": "3.596.0",
349
  "@aws-sdk/core": "3.592.0",
350
+ "@aws-sdk/credential-provider-node": "3.596.0",
351
  "@aws-sdk/middleware-host-header": "3.577.0",
352
  "@aws-sdk/middleware-logger": "3.577.0",
353
  "@aws-sdk/middleware-recursion-detection": "3.577.0",
 
439
  }
440
  },
441
  "node_modules/@aws-sdk/client-sso-oidc": {
442
+ "version": "3.596.0",
443
+ "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.596.0.tgz",
444
+ "integrity": "sha512-KnTWtKzO0N+rMdIrVwbewFp4FAvVWBV/ekCAh5w7EN+uAvBHxMoFElE2RwlcRF/gH1/F715OspPMvOxPom6bMA==",
445
  "dependencies": {
446
  "@aws-crypto/sha256-browser": "3.0.0",
447
  "@aws-crypto/sha256-js": "3.0.0",
448
+ "@aws-sdk/client-sts": "3.596.0",
449
  "@aws-sdk/core": "3.592.0",
450
+ "@aws-sdk/credential-provider-node": "3.596.0",
451
  "@aws-sdk/middleware-host-header": "3.577.0",
452
  "@aws-sdk/middleware-logger": "3.577.0",
453
  "@aws-sdk/middleware-recursion-detection": "3.577.0",
 
489
  }
490
  },
491
  "node_modules/@aws-sdk/client-sts": {
492
+ "version": "3.596.0",
493
+ "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.596.0.tgz",
494
+ "integrity": "sha512-37+WQDjgmqS/YXj3vPzIVIrbXaFcZ1WXk715AMGIPBZn9Y2/wr2bmSTpX7bsMyn0G8+LxmoIxFcG7n1Gu0nvLg==",
495
  "dependencies": {
496
  "@aws-crypto/sha256-browser": "3.0.0",
497
  "@aws-crypto/sha256-js": "3.0.0",
498
+ "@aws-sdk/client-sso-oidc": "3.596.0",
499
  "@aws-sdk/core": "3.592.0",
500
+ "@aws-sdk/credential-provider-node": "3.596.0",
501
  "@aws-sdk/middleware-host-header": "3.577.0",
502
  "@aws-sdk/middleware-logger": "3.577.0",
503
  "@aws-sdk/middleware-recursion-detection": "3.577.0",
 
577
  }
578
  },
579
  "node_modules/@aws-sdk/credential-provider-cognito-identity": {
580
+ "version": "3.596.0",
581
+ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.596.0.tgz",
582
+ "integrity": "sha512-ps/1P+wwEbzOryIdnPGkfo83AH5+kFPe0UKTc6Lhsc4l4zhfvyU3WV/JzrCINEKqo3bEZdUt6tl/IpsyC+nggQ==",
583
  "dependencies": {
584
+ "@aws-sdk/client-cognito-identity": "3.596.0",
585
  "@aws-sdk/types": "3.577.0",
586
  "@smithy/property-provider": "^3.1.0",
587
  "@smithy/types": "^3.0.0",
 
606
  }
607
  },
608
  "node_modules/@aws-sdk/credential-provider-http": {
609
+ "version": "3.596.0",
610
+ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.596.0.tgz",
611
+ "integrity": "sha512-nnmvEsz1KJgRmfSZJPWuzbxPRXu8Y+/78Ifa1jY3fQKSKdEJfXMDsjPljJvMDBl4dZ8pf5Hwx+S/ONnMEDwYEA==",
612
  "dependencies": {
613
  "@aws-sdk/types": "3.577.0",
614
  "@smithy/fetch-http-handler": "^3.0.1",
 
625
  }
626
  },
627
  "node_modules/@aws-sdk/credential-provider-ini": {
628
+ "version": "3.596.0",
629
+ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.596.0.tgz",
630
+ "integrity": "sha512-c7PLtd7GbnOVAc5sk3sVlHxLvEsM8RF96rsBGlRo4AVpil/lXLKyNv9VarS4w/ZZZoRbJRyZ+m92PjNcLvpTDQ==",
631
  "dependencies": {
632
  "@aws-sdk/credential-provider-env": "3.587.0",
633
+ "@aws-sdk/credential-provider-http": "3.596.0",
634
  "@aws-sdk/credential-provider-process": "3.587.0",
635
  "@aws-sdk/credential-provider-sso": "3.592.0",
636
  "@aws-sdk/credential-provider-web-identity": "3.587.0",
 
645
  "node": ">=16.0.0"
646
  },
647
  "peerDependencies": {
648
+ "@aws-sdk/client-sts": "^3.596.0"
649
  }
650
  },
651
  "node_modules/@aws-sdk/credential-provider-node": {
652
+ "version": "3.596.0",
653
+ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.596.0.tgz",
654
+ "integrity": "sha512-F4MLyXpQyie1AnJS9n7TIRL0aF7YH8tKMIJXDsM5OXpSZi2en+yR6SzsxvHf5dwS2Ga8LUdEJyiyS2NoebaJGA==",
655
  "dependencies": {
656
  "@aws-sdk/credential-provider-env": "3.587.0",
657
+ "@aws-sdk/credential-provider-http": "3.596.0",
658
+ "@aws-sdk/credential-provider-ini": "3.596.0",
659
  "@aws-sdk/credential-provider-process": "3.587.0",
660
  "@aws-sdk/credential-provider-sso": "3.592.0",
661
  "@aws-sdk/credential-provider-web-identity": "3.587.0",
 
720
  }
721
  },
722
  "node_modules/@aws-sdk/credential-providers": {
723
+ "version": "3.596.0",
724
+ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.596.0.tgz",
725
+ "integrity": "sha512-EsbkylyO08P3alxXTpanKT1rPTh5/vXu7r/GoKbPl+7Laqheme41CYg0jtwAou/w7/6RFxqMn5ey5vg/qopNVA==",
726
  "dependencies": {
727
+ "@aws-sdk/client-cognito-identity": "3.596.0",
728
  "@aws-sdk/client-sso": "3.592.0",
729
+ "@aws-sdk/client-sts": "3.596.0",
730
+ "@aws-sdk/credential-provider-cognito-identity": "3.596.0",
731
  "@aws-sdk/credential-provider-env": "3.587.0",
732
+ "@aws-sdk/credential-provider-http": "3.596.0",
733
+ "@aws-sdk/credential-provider-ini": "3.596.0",
734
+ "@aws-sdk/credential-provider-node": "3.596.0",
735
  "@aws-sdk/credential-provider-process": "3.587.0",
736
  "@aws-sdk/credential-provider-sso": "3.592.0",
737
  "@aws-sdk/credential-provider-web-identity": "3.587.0",
 
1178
  "semver": "bin/semver.js"
1179
  }
1180
  },
1181
+ "node_modules/@babel/helper-compilation-targets/node_modules/yallist": {
1182
+ "version": "3.1.1",
1183
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
1184
+ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
1185
+ "peer": true
1186
+ },
1187
  "node_modules/@babel/helper-environment-visitor": {
1188
  "version": "7.24.7",
1189
  "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz",
 
2603
  }
2604
  },
2605
  "node_modules/@preact/signals-core": {
2606
+ "version": "1.6.1",
2607
+ "resolved": "https://registry.npmjs.org/@preact/signals-core/-/signals-core-1.6.1.tgz",
2608
+ "integrity": "sha512-KXEEmJoKDlo0Igju/cj9YvKIgyaWFDgnprShQjzimUd5VynAAdTWMshawEOjUVeKbsI0aR58V6WOQp+DNcKApw==",
2609
  "funding": {
2610
  "type": "opencollective",
2611
  "url": "https://opencollective.com/preact"
 
4024
  "integrity": "sha512-qC/xYId4NMebE6w/V33Fh9gWxLgURiNYgVNObbJl2LZv0GUUItCcCqC5axQSwRaAgaxl2mELq1rMzlswaQ0Zxg=="
4025
  },
4026
  "node_modules/@smithy/abort-controller": {
4027
+ "version": "3.0.1",
4028
+ "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-3.0.1.tgz",
4029
+ "integrity": "sha512-Jb7jg4E+C+uvrUQi+h9kbILY6ts6fglKZzseMCHlH9ayq+1f5QdpYf8MV/xppuiN6DAMJAmwGz53GwP3213dmA==",
4030
  "dependencies": {
4031
+ "@smithy/types": "^3.1.0",
4032
  "tslib": "^2.6.2"
4033
  },
4034
  "engines": {
 
4036
  }
4037
  },
4038
  "node_modules/@smithy/config-resolver": {
4039
+ "version": "3.0.2",
4040
+ "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-3.0.2.tgz",
4041
+ "integrity": "sha512-wUyG6ezpp2sWAvfqmSYTROwFUmJqKV78GLf55WODrosBcT0BAMd9bOLO4HRhynWBgAobPml2cF9ZOdgCe00r+g==",
4042
  "dependencies": {
4043
+ "@smithy/node-config-provider": "^3.1.1",
4044
+ "@smithy/types": "^3.1.0",
4045
  "@smithy/util-config-provider": "^3.0.0",
4046
+ "@smithy/util-middleware": "^3.0.1",
4047
  "tslib": "^2.6.2"
4048
  },
4049
  "engines": {
 
4051
  }
4052
  },
4053
  "node_modules/@smithy/core": {
4054
+ "version": "2.2.1",
4055
+ "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.2.1.tgz",
4056
+ "integrity": "sha512-R8Pzrr2v2oGUoj4CTZtKPr87lVtBsz7IUBGhSwS1kc6Cj0yPwNdYbkzhFsxhoDE9+BPl09VN/6rFsW9GJzWnBA==",
4057
+ "dependencies": {
4058
+ "@smithy/middleware-endpoint": "^3.0.2",
4059
+ "@smithy/middleware-retry": "^3.0.4",
4060
+ "@smithy/middleware-serde": "^3.0.1",
4061
+ "@smithy/protocol-http": "^4.0.1",
4062
+ "@smithy/smithy-client": "^3.1.2",
4063
+ "@smithy/types": "^3.1.0",
4064
+ "@smithy/util-middleware": "^3.0.1",
4065
  "tslib": "^2.6.2"
4066
  },
4067
  "engines": {
 
4069
  }
4070
  },
4071
  "node_modules/@smithy/credential-provider-imds": {
4072
+ "version": "3.1.1",
4073
+ "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-3.1.1.tgz",
4074
+ "integrity": "sha512-htndP0LwHdE3R3Nam9ZyVWhwPYOmD4xCL79kqvNxy8u/bv0huuy574CSiRY4cvEICgimv8jlVfLeZ7zZqbnB2g==",
4075
  "dependencies": {
4076
+ "@smithy/node-config-provider": "^3.1.1",
4077
+ "@smithy/property-provider": "^3.1.1",
4078
+ "@smithy/types": "^3.1.0",
4079
+ "@smithy/url-parser": "^3.0.1",
4080
  "tslib": "^2.6.2"
4081
  },
4082
  "engines": {
 
4117
  }
4118
  },
4119
  "node_modules/@smithy/fetch-http-handler": {
4120
+ "version": "3.0.2",
4121
+ "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-3.0.2.tgz",
4122
+ "integrity": "sha512-0nW6tLK0b7EqSsfKvnOmZCgJqnodBAnvqcrlC5dotKfklLedPTRGsQamSVbVDWyuU/QGg+YbZDJUQ0CUufJXZQ==",
4123
  "dependencies": {
4124
+ "@smithy/protocol-http": "^4.0.1",
4125
+ "@smithy/querystring-builder": "^3.0.1",
4126
+ "@smithy/types": "^3.1.0",
4127
  "@smithy/util-base64": "^3.0.0",
4128
  "tslib": "^2.6.2"
4129
  }
4130
  },
4131
  "node_modules/@smithy/hash-node": {
4132
+ "version": "3.0.1",
4133
+ "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-3.0.1.tgz",
4134
+ "integrity": "sha512-w2ncjgk2EYO2+WhAsSQA8owzoOSY7IL1qVytlwpnL1pFGWTjIoIh5nROkEKXY51unB63bMGZqDiVoXaFbyKDlg==",
4135
  "dependencies": {
4136
+ "@smithy/types": "^3.1.0",
4137
  "@smithy/util-buffer-from": "^3.0.0",
4138
  "@smithy/util-utf8": "^3.0.0",
4139
  "tslib": "^2.6.2"
 
4143
  }
4144
  },
4145
  "node_modules/@smithy/invalid-dependency": {
4146
+ "version": "3.0.1",
4147
+ "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-3.0.1.tgz",
4148
+ "integrity": "sha512-RSNF/32BKygXKKMyS7koyuAq1rcdW5p5c4EFa77QenBFze9As+JiRnV9OWBh2cB/ejGZalEZjvIrMLHwJl7aGA==",
4149
  "dependencies": {
4150
+ "@smithy/types": "^3.1.0",
4151
  "tslib": "^2.6.2"
4152
  }
4153
  },
 
4163
  }
4164
  },
4165
  "node_modules/@smithy/middleware-content-length": {
4166
+ "version": "3.0.1",
4167
+ "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-3.0.1.tgz",
4168
+ "integrity": "sha512-6QdK/VbrCfXD5/QolE2W/ok6VqxD+SM28Ds8iSlEHXZwv4buLsvWyvoEEy0322K/g5uFgPzBmZjGqesTmPL+yQ==",
4169
  "dependencies": {
4170
+ "@smithy/protocol-http": "^4.0.1",
4171
+ "@smithy/types": "^3.1.0",
4172
  "tslib": "^2.6.2"
4173
  },
4174
  "engines": {
 
4176
  }
4177
  },
4178
  "node_modules/@smithy/middleware-endpoint": {
4179
+ "version": "3.0.2",
4180
+ "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-3.0.2.tgz",
4181
+ "integrity": "sha512-gWEaGYB3Bei17Oiy/F2IlUPpBazNXImytoOdJ1xbrUOaJKAOiUhx8/4FOnYLLJHdAwa9PlvJ2ULda2f/Dnwi9w==",
4182
+ "dependencies": {
4183
+ "@smithy/middleware-serde": "^3.0.1",
4184
+ "@smithy/node-config-provider": "^3.1.1",
4185
+ "@smithy/shared-ini-file-loader": "^3.1.1",
4186
+ "@smithy/types": "^3.1.0",
4187
+ "@smithy/url-parser": "^3.0.1",
4188
+ "@smithy/util-middleware": "^3.0.1",
4189
  "tslib": "^2.6.2"
4190
  },
4191
  "engines": {
 
4193
  }
4194
  },
4195
  "node_modules/@smithy/middleware-retry": {
4196
+ "version": "3.0.4",
4197
+ "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.4.tgz",
4198
+ "integrity": "sha512-Tu+FggbLNF5G9L6Wi8o32Mg4bhlBInWlhhaFKyytGRnkfxGopxFVXJQn7sjZdFYJyTz6RZZa06tnlvavUgtoVg==",
4199
+ "dependencies": {
4200
+ "@smithy/node-config-provider": "^3.1.1",
4201
+ "@smithy/protocol-http": "^4.0.1",
4202
+ "@smithy/service-error-classification": "^3.0.1",
4203
+ "@smithy/smithy-client": "^3.1.2",
4204
+ "@smithy/types": "^3.1.0",
4205
+ "@smithy/util-middleware": "^3.0.1",
4206
+ "@smithy/util-retry": "^3.0.1",
4207
  "tslib": "^2.6.2",
4208
  "uuid": "^9.0.1"
4209
  },
 
4212
  }
4213
  },
4214
  "node_modules/@smithy/middleware-serde": {
4215
+ "version": "3.0.1",
4216
+ "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-3.0.1.tgz",
4217
+ "integrity": "sha512-ak6H/ZRN05r5+SR0/IUc5zOSyh2qp3HReg1KkrnaSLXmncy9lwOjNqybX4L4x55/e5mtVDn1uf/gQ6bw5neJPw==",
4218
  "dependencies": {
4219
+ "@smithy/types": "^3.1.0",
4220
  "tslib": "^2.6.2"
4221
  },
4222
  "engines": {
 
4224
  }
4225
  },
4226
  "node_modules/@smithy/middleware-stack": {
4227
+ "version": "3.0.1",
4228
+ "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-3.0.1.tgz",
4229
+ "integrity": "sha512-fS5uT//y1SlBdkzIvgmWQ9FufwMXrHSSbuR25ygMy1CRDIZkcBMoF4oTMYNfR9kBlVBcVzlv7joFdNrFuQirPA==",
4230
  "dependencies": {
4231
+ "@smithy/types": "^3.1.0",
4232
  "tslib": "^2.6.2"
4233
  },
4234
  "engines": {
 
4236
  }
4237
  },
4238
  "node_modules/@smithy/node-config-provider": {
4239
+ "version": "3.1.1",
4240
+ "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-3.1.1.tgz",
4241
+ "integrity": "sha512-z5G7+ysL4yUtMghUd2zrLkecu0mTfnYlt5dR76g/HsFqf7evFazwiZP1ag2EJenGxNBDwDM5g8nm11NPogiUVA==",
4242
  "dependencies": {
4243
+ "@smithy/property-provider": "^3.1.1",
4244
+ "@smithy/shared-ini-file-loader": "^3.1.1",
4245
+ "@smithy/types": "^3.1.0",
4246
  "tslib": "^2.6.2"
4247
  },
4248
  "engines": {
 
4250
  }
4251
  },
4252
  "node_modules/@smithy/node-http-handler": {
4253
+ "version": "3.0.1",
4254
+ "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-3.0.1.tgz",
4255
+ "integrity": "sha512-hlBI6MuREA4o1wBMEt+QNhUzoDtFFvwR6ecufimlx9D79jPybE/r8kNorphXOi91PgSO9S2fxRjcKCLk7Jw8zA==",
4256
  "dependencies": {
4257
+ "@smithy/abort-controller": "^3.0.1",
4258
+ "@smithy/protocol-http": "^4.0.1",
4259
+ "@smithy/querystring-builder": "^3.0.1",
4260
+ "@smithy/types": "^3.1.0",
4261
  "tslib": "^2.6.2"
4262
  },
4263
  "engines": {
 
4265
  }
4266
  },
4267
  "node_modules/@smithy/property-provider": {
4268
+ "version": "3.1.1",
4269
+ "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.1.tgz",
4270
+ "integrity": "sha512-YknOMZcQkB5on+MU0DvbToCmT2YPtTETMXW0D3+/Iln7ezT+Zm1GMHhCW1dOH/X/+LkkQD9aXEoCX/B10s4Xdw==",
4271
  "dependencies": {
4272
+ "@smithy/types": "^3.1.0",
4273
  "tslib": "^2.6.2"
4274
  },
4275
  "engines": {
 
4277
  }
4278
  },
4279
  "node_modules/@smithy/protocol-http": {
4280
+ "version": "4.0.1",
4281
+ "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.0.1.tgz",
4282
+ "integrity": "sha512-eBhm9zwcFPEazc654c0BEWtxYAzrw+OhoSf5pkwKzfftWKXRoqEhwOE2Pvn30v0iAdo7Mfsfb6pi1NnZlGCMpg==",
4283
  "dependencies": {
4284
+ "@smithy/types": "^3.1.0",
4285
  "tslib": "^2.6.2"
4286
  },
4287
  "engines": {
 
4289
  }
4290
  },
4291
  "node_modules/@smithy/querystring-builder": {
4292
+ "version": "3.0.1",
4293
+ "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-3.0.1.tgz",
4294
+ "integrity": "sha512-vKitpnG/2KOMVlx3x1S3FkBH075EROG3wcrcDaNerQNh8yuqnSL23btCD2UyX4i4lpPzNW6VFdxbn2Z25b/g5Q==",
4295
  "dependencies": {
4296
+ "@smithy/types": "^3.1.0",
4297
  "@smithy/util-uri-escape": "^3.0.0",
4298
  "tslib": "^2.6.2"
4299
  },
 
4302
  }
4303
  },
4304
  "node_modules/@smithy/querystring-parser": {
4305
+ "version": "3.0.1",
4306
+ "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-3.0.1.tgz",
4307
+ "integrity": "sha512-Qt8DMC05lVS8NcQx94lfVbZSX+2Ym7032b/JR8AlboAa/D669kPzqb35dkjkvAG6+NWmUchef3ENtrD6F+5n8Q==",
4308
  "dependencies": {
4309
+ "@smithy/types": "^3.1.0",
4310
  "tslib": "^2.6.2"
4311
  },
4312
  "engines": {
 
4314
  }
4315
  },
4316
  "node_modules/@smithy/service-error-classification": {
4317
+ "version": "3.0.1",
4318
+ "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-3.0.1.tgz",
4319
+ "integrity": "sha512-ubFUvIePjDCyIzZ+pLETqNC6KXJ/fc6g+/baqel7Zf6kJI/kZKgjwkCI7zbUhoUuOZ/4eA/87YasVu40b/B4bA==",
4320
  "dependencies": {
4321
+ "@smithy/types": "^3.1.0"
4322
  },
4323
  "engines": {
4324
  "node": ">=16.0.0"
4325
  }
4326
  },
4327
  "node_modules/@smithy/shared-ini-file-loader": {
4328
+ "version": "3.1.1",
4329
+ "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-3.1.1.tgz",
4330
+ "integrity": "sha512-nD6tXIX2126/P9e3wqRY1bm9dTtPZwRDyjVOd18G28o+1UOG+kOVgUwujE795HslSuPlEgqzsH5sgNP1hDjj9g==",
4331
  "dependencies": {
4332
+ "@smithy/types": "^3.1.0",
4333
  "tslib": "^2.6.2"
4334
  },
4335
  "engines": {
 
4337
  }
4338
  },
4339
  "node_modules/@smithy/signature-v4": {
4340
+ "version": "3.0.1",
4341
+ "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-3.0.1.tgz",
4342
+ "integrity": "sha512-ARAmD+E7j6TIEhKLjSZxdzs7wceINTMJRN2BXPM09BiUmJhkXAF1ZZtDXH6fhlk7oehBZeh37wGiPOqtdKjLeg==",
4343
  "dependencies": {
4344
  "@smithy/is-array-buffer": "^3.0.0",
4345
+ "@smithy/types": "^3.1.0",
4346
  "@smithy/util-hex-encoding": "^3.0.0",
4347
+ "@smithy/util-middleware": "^3.0.1",
4348
  "@smithy/util-uri-escape": "^3.0.0",
4349
  "@smithy/util-utf8": "^3.0.0",
4350
  "tslib": "^2.6.2"
 
4354
  }
4355
  },
4356
  "node_modules/@smithy/smithy-client": {
4357
+ "version": "3.1.2",
4358
+ "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.2.tgz",
4359
+ "integrity": "sha512-f3eQpczBOFUtdT/ptw2WpUKu1qH1K7xrssrSiHYtd9TuLXkvFqb88l9mz9FHeUVNSUxSnkW1anJnw6rLwUKzQQ==",
4360
+ "dependencies": {
4361
+ "@smithy/middleware-endpoint": "^3.0.2",
4362
+ "@smithy/middleware-stack": "^3.0.1",
4363
+ "@smithy/protocol-http": "^4.0.1",
4364
+ "@smithy/types": "^3.1.0",
4365
+ "@smithy/util-stream": "^3.0.2",
4366
  "tslib": "^2.6.2"
4367
  },
4368
  "engines": {
 
4370
  }
4371
  },
4372
  "node_modules/@smithy/types": {
4373
+ "version": "3.1.0",
4374
+ "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.1.0.tgz",
4375
+ "integrity": "sha512-qi4SeCVOUPjhSSZrxxB/mB8DrmuSFUcJnD9KXjuP+7C3LV/KFV4kpuUSH3OHDZgQB9TEH/1sO/Fq/5HyaK9MPw==",
4376
  "dependencies": {
4377
  "tslib": "^2.6.2"
4378
  },
 
4381
  }
4382
  },
4383
  "node_modules/@smithy/url-parser": {
4384
+ "version": "3.0.1",
4385
+ "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-3.0.1.tgz",
4386
+ "integrity": "sha512-G140IlNFlzYWVCedC4E2d6NycM1dCUbe5CnsGW1hmGt4hYKiGOw0v7lVru9WAn5T2w09QEjl4fOESWjGmCvVmg==",
4387
  "dependencies": {
4388
+ "@smithy/querystring-parser": "^3.0.1",
4389
+ "@smithy/types": "^3.1.0",
4390
  "tslib": "^2.6.2"
4391
  }
4392
  },
 
4446
  }
4447
  },
4448
  "node_modules/@smithy/util-defaults-mode-browser": {
4449
+ "version": "3.0.4",
4450
+ "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.4.tgz",
4451
+ "integrity": "sha512-sXtin3Mue3A3xo4+XkozpgPptgmRwvNPOqTvb3ANGTCzzoQgAPBNjpE+aXCINaeSMXwHmv7E2oEn2vWdID+SAQ==",
4452
  "dependencies": {
4453
+ "@smithy/property-provider": "^3.1.1",
4454
+ "@smithy/smithy-client": "^3.1.2",
4455
+ "@smithy/types": "^3.1.0",
4456
  "bowser": "^2.11.0",
4457
  "tslib": "^2.6.2"
4458
  },
 
4461
  }
4462
  },
4463
  "node_modules/@smithy/util-defaults-mode-node": {
4464
+ "version": "3.0.4",
4465
+ "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.4.tgz",
4466
+ "integrity": "sha512-CUF6TyxLh3CgBRVYgZNOPDfzHQjeQr0vyALR6/DkQkOm7rNfGEzW1BRFi88C73pndmfvoiIT7ochuT76OPz9Dw==",
4467
+ "dependencies": {
4468
+ "@smithy/config-resolver": "^3.0.2",
4469
+ "@smithy/credential-provider-imds": "^3.1.1",
4470
+ "@smithy/node-config-provider": "^3.1.1",
4471
+ "@smithy/property-provider": "^3.1.1",
4472
+ "@smithy/smithy-client": "^3.1.2",
4473
+ "@smithy/types": "^3.1.0",
4474
  "tslib": "^2.6.2"
4475
  },
4476
  "engines": {
 
4478
  }
4479
  },
4480
  "node_modules/@smithy/util-endpoints": {
4481
+ "version": "2.0.2",
4482
+ "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-2.0.2.tgz",
4483
+ "integrity": "sha512-4zFOcBFQvifd2LSD4a1dKvfIWWwh4sWNtS3oZ7mpob/qPPmJseqKB148iT+hWCDsG//TmI+8vjYPgZdvnkYlTg==",
4484
  "dependencies": {
4485
+ "@smithy/node-config-provider": "^3.1.1",
4486
+ "@smithy/types": "^3.1.0",
4487
  "tslib": "^2.6.2"
4488
  },
4489
  "engines": {
 
4502
  }
4503
  },
4504
  "node_modules/@smithy/util-middleware": {
4505
+ "version": "3.0.1",
4506
+ "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-3.0.1.tgz",
4507
+ "integrity": "sha512-WRODCQtUsO7vIvfrdxS8RFPeLKcewYtaCglZsBsedIKSUGIIvMlZT5oh+pCe72I+1L+OjnZuqRNpN2LKhWA4KQ==",
4508
  "dependencies": {
4509
+ "@smithy/types": "^3.1.0",
4510
  "tslib": "^2.6.2"
4511
  },
4512
  "engines": {
 
4514
  }
4515
  },
4516
  "node_modules/@smithy/util-retry": {
4517
+ "version": "3.0.1",
4518
+ "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-3.0.1.tgz",
4519
+ "integrity": "sha512-5lRtYm+8fNFEUTdqZXg5M4ppVp40rMIJfR1TpbHAhKQgPIDpWT+iYMaqgnwEbtpi9U1smyUOPv5Sg+M1neOBgw==",
4520
  "dependencies": {
4521
+ "@smithy/service-error-classification": "^3.0.1",
4522
+ "@smithy/types": "^3.1.0",
4523
  "tslib": "^2.6.2"
4524
  },
4525
  "engines": {
 
4527
  }
4528
  },
4529
  "node_modules/@smithy/util-stream": {
4530
+ "version": "3.0.2",
4531
+ "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-3.0.2.tgz",
4532
+ "integrity": "sha512-n5Obp5AnlI6qHo8sbupwrcpBe6vFp4qkl0SRNuExKPNrH3ABAMG2ZszRTIUIv2b4AsFrCO+qiy4uH1Q3z1dxTA==",
4533
  "dependencies": {
4534
+ "@smithy/fetch-http-handler": "^3.0.2",
4535
+ "@smithy/node-http-handler": "^3.0.1",
4536
+ "@smithy/types": "^3.1.0",
4537
  "@smithy/util-base64": "^3.0.0",
4538
  "@smithy/util-buffer-from": "^3.0.0",
4539
  "@smithy/util-hex-encoding": "^3.0.0",
 
4568
  }
4569
  },
4570
  "node_modules/@smithy/util-waiter": {
4571
+ "version": "3.0.1",
4572
+ "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-3.0.1.tgz",
4573
+ "integrity": "sha512-wwnrVQdjQxvWGOAiLmqlEhENGCcDIN+XJ/+usPOgSZObAslrCXgKlkX7rNVwIWW2RhPguTKthvF+4AoO0Z6KpA==",
4574
  "dependencies": {
4575
+ "@smithy/abort-controller": "^3.0.1",
4576
+ "@smithy/types": "^3.1.0",
4577
  "tslib": "^2.6.2"
4578
  },
4579
  "engines": {
 
4887
  }
4888
  },
4889
  "node_modules/@upstash/ratelimit": {
4890
+ "version": "1.2.1",
4891
+ "resolved": "https://registry.npmjs.org/@upstash/ratelimit/-/ratelimit-1.2.1.tgz",
4892
+ "integrity": "sha512-o01lV1yFS5Fzj5KONZmNyVch/Qrlj785B2ob+kStUmxn8F6xXk7IHTQqVcHE+Ce3CmT/qQIwvMxDZftyJ5wYpQ==",
4893
  "dependencies": {
4894
  "@upstash/core-analytics": "^0.0.9"
4895
  }
4896
  },
4897
  "node_modules/@upstash/redis": {
4898
+ "version": "1.31.5",
4899
+ "resolved": "https://registry.npmjs.org/@upstash/redis/-/redis-1.31.5.tgz",
4900
+ "integrity": "sha512-2MatqeqftroSJ9Q+pqbyGAIwXX6KEPtUTUna2c/fq09h12ffwvltDTgfppeF+NzJo/SyZfHY8e1RoflduMbz1A==",
4901
  "dependencies": {
4902
  "crypto-js": "^4.2.0"
4903
  }
 
5312
  "node": ">=4"
5313
  }
5314
  },
5315
+ "node_modules/axios": {
5316
+ "version": "1.7.2",
5317
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz",
5318
+ "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==",
5319
+ "dependencies": {
5320
+ "follow-redirects": "^1.15.6",
5321
+ "form-data": "^4.0.0",
5322
+ "proxy-from-env": "^1.1.0"
5323
+ }
5324
+ },
5325
  "node_modules/axobject-query": {
5326
  "version": "3.2.1",
5327
  "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz",
 
5568
  }
5569
  },
5570
  "node_modules/caniuse-lite": {
5571
+ "version": "1.0.30001633",
5572
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001633.tgz",
5573
+ "integrity": "sha512-6sT0yf/z5jqf8tISAgpJDrmwOpLsrpnyCdD/lOZKvKkkJK4Dn0X5i7KF7THEZhOq+30bmhwBlNEaqPUiHiKtZg==",
5574
  "funding": [
5575
  {
5576
  "type": "opencollective",
 
6232
  "url": "https://github.com/sponsors/ljharb"
6233
  }
6234
  },
6235
+ "node_modules/date-fns": {
6236
+ "version": "3.6.0",
6237
+ "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz",
6238
+ "integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==",
6239
+ "funding": {
6240
+ "type": "github",
6241
+ "url": "https://github.com/sponsors/kossnocorp"
6242
+ }
6243
+ },
6244
  "node_modules/debounce": {
6245
  "version": "1.2.1",
6246
  "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz",
 
6481
  }
6482
  },
6483
  "node_modules/electron-to-chromium": {
6484
+ "version": "1.4.802",
6485
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.802.tgz",
6486
+ "integrity": "sha512-TnTMUATbgNdPXVSHsxvNVSG0uEd6cSZsANjm8c9HbvflZVVn1yTRcmVXYT1Ma95/ssB/Dcd30AHweH2TE+dNpA=="
6487
  },
6488
  "node_modules/emoji-regex": {
6489
  "version": "9.2.2",
 
7344
  "which": "bin/which"
7345
  }
7346
  },
7347
+ "node_modules/follow-redirects": {
7348
+ "version": "1.15.6",
7349
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz",
7350
+ "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==",
7351
+ "funding": [
7352
+ {
7353
+ "type": "individual",
7354
+ "url": "https://github.com/sponsors/RubenVerborgh"
7355
+ }
7356
+ ],
7357
+ "engines": {
7358
+ "node": ">=4.0"
7359
+ },
7360
+ "peerDependenciesMeta": {
7361
+ "debug": {
7362
+ "optional": true
7363
+ }
7364
+ }
7365
+ },
7366
  "node_modules/for-each": {
7367
  "version": "0.3.3",
7368
  "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
 
7730
  "node": ">=12"
7731
  }
7732
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7733
  "node_modules/google-p12-pem": {
7734
  "version": "4.0.1",
7735
  "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-4.0.1.tgz",
 
8768
  }
8769
  },
8770
  "node_modules/lru-cache": {
8771
+ "version": "6.0.0",
8772
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
8773
+ "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
8774
+ "dependencies": {
8775
+ "yallist": "^4.0.0"
8776
+ },
8777
  "engines": {
8778
+ "node": ">=10"
8779
  }
8780
  },
8781
  "node_modules/lucide-react": {
 
9322
  }
9323
  },
9324
  "node_modules/openai": {
9325
+ "version": "4.51.0",
9326
+ "resolved": "https://registry.npmjs.org/openai/-/openai-4.51.0.tgz",
9327
+ "integrity": "sha512-UKuWc3/qQyklqhHM8CbdXCv0Z0obap6T0ECdcO5oATQxAbKE5Ky3YCXFQY207z+eGG6ez4U9wvAcuMygxhmStg==",
9328
  "dependencies": {
9329
  "@types/node": "^18.11.18",
9330
  "@types/node-fetch": "^2.6.4",
 
9560
  "url": "https://github.com/sponsors/isaacs"
9561
  }
9562
  },
9563
+ "node_modules/path-scurry/node_modules/lru-cache": {
9564
+ "version": "10.2.2",
9565
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz",
9566
+ "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==",
9567
+ "engines": {
9568
+ "node": "14 || >=16.14"
9569
+ }
9570
+ },
9571
  "node_modules/path-type": {
9572
  "version": "4.0.0",
9573
  "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
 
9844
  "react-is": "^16.13.1"
9845
  }
9846
  },
9847
+ "node_modules/proxy-from-env": {
9848
+ "version": "1.1.0",
9849
+ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
9850
+ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
9851
+ },
9852
  "node_modules/punycode": {
9853
  "version": "2.3.1",
9854
  "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
 
10185
  "react-dom": ">=16.13"
10186
  }
10187
  },
10188
+ "node_modules/react-virtualized-auto-sizer": {
10189
+ "version": "1.0.24",
10190
+ "resolved": "https://registry.npmjs.org/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.24.tgz",
10191
+ "integrity": "sha512-3kCn7N9NEb3FlvJrSHWGQ4iVl+ydQObq2fHMn12i5wbtm74zHOPhz/i64OL3c1S1vi9i2GXtZqNqUJTQ+BnNfg==",
10192
+ "peerDependencies": {
10193
+ "react": "^15.3.0 || ^16.0.0-alpha || ^17.0.0 || ^18.0.0",
10194
+ "react-dom": "^15.3.0 || ^16.0.0-alpha || ^17.0.0 || ^18.0.0"
10195
+ }
10196
+ },
10197
  "node_modules/read-cache": {
10198
  "version": "1.0.0",
10199
  "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
 
11932
  "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
11933
  },
11934
  "node_modules/yallist": {
11935
+ "version": "4.0.0",
11936
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
11937
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
 
11938
  },
11939
  "node_modules/yaml": {
11940
  "version": "2.4.5",
package.json CHANGED
@@ -1,6 +1,6 @@
1
  {
2
  "name": "@aitube/clapper",
3
- "version": "0.0.0",
4
  "private": true,
5
  "description": "🎬 Clapper",
6
  "scripts": {
@@ -12,7 +12,7 @@
12
  "dependencies": {
13
  "@aitube/clap": "0.0.26",
14
  "@aitube/engine": "0.0.19",
15
- "@aitube/timeline": "file:/Users/jbilcke/Projects/Typescript_Libraries/aitube-timeline",
16
  "@fal-ai/serverless-client": "^0.10.3",
17
  "@huggingface/hub": "^0.15.1",
18
  "@huggingface/inference": "^2.7.0",
@@ -58,12 +58,14 @@
58
  "@upstash/ratelimit": "^1.1.3",
59
  "@upstash/redis": "^1.31.1",
60
  "autoprefixer": "10.4.17",
 
61
  "class-variance-authority": "^0.7.0",
62
  "clsx": "^2.1.0",
63
  "cmdk": "^0.2.1",
64
  "eslint": "8.57.0",
65
  "eslint-config-next": "14.1.0",
66
  "fluent-ffmpeg": "^2.1.3",
 
67
  "fs-extra": "^11.2.0",
68
  "lucide-react": "^0.334.0",
69
  "mlt-xml": "^2.0.2",
 
1
  {
2
  "name": "@aitube/clapper",
3
+ "version": "0.0.1",
4
  "private": true,
5
  "description": "🎬 Clapper",
6
  "scripts": {
 
12
  "dependencies": {
13
  "@aitube/clap": "0.0.26",
14
  "@aitube/engine": "0.0.19",
15
+ "@aitube/timeline": "0.0.24",
16
  "@fal-ai/serverless-client": "^0.10.3",
17
  "@huggingface/hub": "^0.15.1",
18
  "@huggingface/inference": "^2.7.0",
 
58
  "@upstash/ratelimit": "^1.1.3",
59
  "@upstash/redis": "^1.31.1",
60
  "autoprefixer": "10.4.17",
61
+ "axios": "^1.7.2",
62
  "class-variance-authority": "^0.7.0",
63
  "clsx": "^2.1.0",
64
  "cmdk": "^0.2.1",
65
  "eslint": "8.57.0",
66
  "eslint-config-next": "14.1.0",
67
  "fluent-ffmpeg": "^2.1.3",
68
+ "form-data": "^4.0.0",
69
  "fs-extra": "^11.2.0",
70
  "lucide-react": "^0.334.0",
71
  "mlt-xml": "^2.0.2",
src/app/api/resolve/providers/falai/index.ts CHANGED
@@ -73,7 +73,10 @@ export async function resolveSegment(request: ResolveRequest): Promise<ClapSegme
73
  prompt: prompts.positivePrompt,
74
  image_size: imageSize,
75
  sync_mode: true,
76
- num_inference_steps: 20,
 
 
 
77
  num_images: 1,
78
  enable_safety_checker: request.settings.censorNotForAllAudiencesContent
79
  },
 
73
  prompt: prompts.positivePrompt,
74
  image_size: imageSize,
75
  sync_mode: true,
76
+ num_inference_steps:
77
+ request.settings.falAiModelForImage === "fal-ai/stable-diffusion-v3-medium"
78
+ ? 40
79
+ : 25,
80
  num_images: 1,
81
  enable_safety_checker: request.settings.censorNotForAllAudiencesContent
82
  },
src/app/api/resolve/providers/stabilityai/index.ts ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import { ResolveRequest, StabilityAiImageSize } from "@/types"
3
+ import { ClapMediaOrientation, ClapSegment, ClapSegmentCategory, ClapSegmentStatus, getClapAssetSourceType } from "@aitube/clap"
4
+ import { decodeOutput } from '@/lib/utils/decodeOutput'
5
+ import { getResolveRequestPrompts } from '@/lib/utils/getResolveRequestPrompts'
6
+ import { performRequest } from "./performRequest"
7
+
8
+ export async function resolveSegment(request: ResolveRequest): Promise<ClapSegment> {
9
+ if (!request.settings.stabilityAiApiKey) {
10
+ throw new Error(`Missing API key for "Stability.ai"`)
11
+ }
12
+
13
+
14
+ const segment: ClapSegment = { ...request.segment }
15
+
16
+ let content = ''
17
+
18
+ const prompts = getResolveRequestPrompts(request)
19
+
20
+ try {
21
+
22
+ // for doc see:
23
+ // https://fal.ai/models/fal-ai/fast-sdxl/api
24
+
25
+ if (request.segment.category === ClapSegmentCategory.STORYBOARD) {
26
+
27
+
28
+ if (!prompts.positivePrompt) {
29
+ console.error(`resolveSegment: cannot resolve a storyboard with an empty prompt`)
30
+ return segment
31
+ }
32
+
33
+ const imageSize: StabilityAiImageSize =
34
+ request.meta.orientation === ClapMediaOrientation.SQUARE
35
+ ? StabilityAiImageSize.SQUARE
36
+ : request.meta.orientation === ClapMediaOrientation.PORTRAIT
37
+ ? StabilityAiImageSize.PORTRAIT_9_16
38
+ : StabilityAiImageSize.LANDSCAPE_16_9
39
+
40
+ const assetUrl = await performRequest({
41
+ modelName: request.settings.imageGenerationModel,
42
+
43
+ // what's cool about the ultra model is its capacity to take in
44
+ // very large prompts, up to 10000 characters apparently?
45
+
46
+ // To control the weight of a given word use the format (word:weight),
47
+ // where word is the word you'd like to control the weight of and weight
48
+ // is a value between 0 and 1.
49
+ // For example: The sky was a crisp (blue:0.3) and (green:0.8) would
50
+ // convey a sky that was blue and green, but more green than blue.
51
+ positivePrompt: prompts.positivePrompt,
52
+ negativePrompt: prompts.negativePrompt,
53
+
54
+ imageSize,
55
+
56
+ apiKey: request.settings.stabilityAiApiKey
57
+ })
58
+
59
+ content = assetUrl
60
+ } else {
61
+ throw new Error(`Clapper doesn't support ${request.segment.category} generation for provider "Stability.ai". Please open a pull request with (working code) to solve this!`)
62
+ }
63
+
64
+ segment.assetUrl = await decodeOutput(content)
65
+ // console.log(`segment.assetUrl = ${segment.assetUrl.slice(0, 80)}..`)
66
+ segment.assetSourceType = getClapAssetSourceType(segment.assetUrl)
67
+ } catch (err) {
68
+ console.error(`failed to call Stability.ai: `, err)
69
+ segment.assetUrl = ''
70
+ segment.assetSourceType = getClapAssetSourceType(segment.assetUrl)
71
+ segment.status = ClapSegmentStatus.TO_GENERATE
72
+ }
73
+
74
+ return segment
75
+ }
src/app/api/resolve/providers/stabilityai/performRequest.ts ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import axios from "axios"
3
+ import FormData from "form-data"
4
+
5
+ import { decodeOutput } from "@/lib/utils/decodeOutput"
6
+ import { StabilityAiImageSize } from "@/types"
7
+
8
+ export async function performRequest({
9
+ positivePrompt,
10
+ negativePrompt,
11
+ modelName,
12
+ imageSize,
13
+ apiKey
14
+ }: {
15
+ positivePrompt: string
16
+ negativePrompt: string
17
+ modelName: string
18
+ imageSize: StabilityAiImageSize
19
+ apiKey: string
20
+ }): Promise<string> {
21
+
22
+ const payload = {
23
+ prompt: positivePrompt,
24
+ output_format: "jpeg", // "webp",
25
+ negative_prompt: negativePrompt,
26
+ aspect_ratio: imageSize,
27
+
28
+
29
+
30
+ // string (GenerationMode)
31
+ // Default: text-to-image
32
+ // Enum: image-to-image text-to-image
33
+ // Controls whether this is a text-to-image or image-to-image generation, which affects which parameters are required:
34
+
35
+ // text-to-image requires only the prompt parameter
36
+ // image-to-image requires the prompt, image, and strength parameters
37
+ // mode: "text-to-image",
38
+
39
+ // "stable-image/generate/sd3" supports this option:
40
+ // model: "", // the model to use ("SD3 Medium", "SD3 Large", or "SD3 Large Turbo")
41
+ };
42
+
43
+ const response = await axios.postForm(
44
+ `https://api.stability.ai/v2beta/${modelName}`,
45
+ axios.toFormData(payload, new FormData()),
46
+ {
47
+ validateStatus: undefined,
48
+ responseType: "arraybuffer",
49
+ headers: {
50
+ Authorization: `Bearer ${apiKey}`,
51
+ Accept: "image/*"
52
+ },
53
+ },
54
+ )
55
+
56
+ if (response.status === 200) {
57
+ console.log("response.data: ", response.data)
58
+ const buffer = Buffer.from(response.data)
59
+ const rawAssetUrl = `data:image/${payload.output_format};base64,${buffer.toString('base64')}`
60
+ const assetUrl = await decodeOutput(rawAssetUrl)
61
+ return assetUrl
62
+ } else {
63
+ throw new Error(`${response.status}: ${response.data.toString()}`);
64
+ }
65
+ }
src/app/api/resolve/route.ts CHANGED
@@ -7,6 +7,7 @@ import { resolveSegment as resolveSegmentUsingReplicate } from "./providers/repl
7
  import { resolveSegment as resolveSegmentUsingComfyComfyIcu } from "./providers/comfy-comfyicu"
8
  import { resolveSegment as resolveSegmentUsingFalAi } from "./providers/falai"
9
  import { resolveSegment as resolveSegmentUsingModelsLab } from "./providers/modelslab"
 
10
 
11
  import { ComputeProvider, ResolveRequest } from "@/types"
12
 
@@ -43,6 +44,8 @@ export async function POST(req: NextRequest) {
43
  ? resolveSegmentUsingReplicate
44
  : provider === ComputeProvider.COMFY_COMFYICU
45
  ? resolveSegmentUsingComfyComfyIcu
 
 
46
  : provider === ComputeProvider.FALAI
47
  ? resolveSegmentUsingFalAi
48
  : provider === ComputeProvider.MODELSLAB
 
7
  import { resolveSegment as resolveSegmentUsingComfyComfyIcu } from "./providers/comfy-comfyicu"
8
  import { resolveSegment as resolveSegmentUsingFalAi } from "./providers/falai"
9
  import { resolveSegment as resolveSegmentUsingModelsLab } from "./providers/modelslab"
10
+ import { resolveSegment as resolveSegmentUsingStabilityAi } from "./providers/stabilityai"
11
 
12
  import { ComputeProvider, ResolveRequest } from "@/types"
13
 
 
44
  ? resolveSegmentUsingReplicate
45
  : provider === ComputeProvider.COMFY_COMFYICU
46
  ? resolveSegmentUsingComfyComfyIcu
47
+ : provider === ComputeProvider.STABILITYAI
48
+ ? resolveSegmentUsingStabilityAi
49
  : provider === ComputeProvider.FALAI
50
  ? resolveSegmentUsingFalAi
51
  : provider === ComputeProvider.MODELSLAB
src/components/dialogs/loader/LoadingDialog.tsx CHANGED
@@ -3,12 +3,13 @@ import { Progress } from "@/components/ui/progress"
3
  import { cn } from "@/lib/utils"
4
 
5
  import { useTasks } from "../../tasks/useTasks"
 
6
 
7
  // a loading dialog that cannot be closed once it's loading
8
  export function LoadingDialog({ className = "" }: { className?: string }) {
9
  const { find } = useTasks()
10
 
11
- const runningBlockerTasks = find({ status: "running", visibility: "blocker" })
12
  const isLoading = runningBlockerTasks.length > 0
13
  const currentMessage = runningBlockerTasks[0]?.currentMessage || ""
14
  const progress = runningBlockerTasks[0]?.progress || 0
 
3
  import { cn } from "@/lib/utils"
4
 
5
  import { useTasks } from "../../tasks/useTasks"
6
+ import { TaskStatus, TaskVisibility } from "@/components/tasks/types"
7
 
8
  // a loading dialog that cannot be closed once it's loading
9
  export function LoadingDialog({ className = "" }: { className?: string }) {
10
  const { find } = useTasks()
11
 
12
+ const runningBlockerTasks = find({ status: TaskStatus.RUNNING, visibility: TaskVisibility.BLOCKER })
13
  const isLoading = runningBlockerTasks.length > 0
14
  const currentMessage = runningBlockerTasks[0]?.currentMessage || ""
15
  const progress = runningBlockerTasks[0]?.progress || 0
src/components/settings/constants.ts CHANGED
@@ -20,6 +20,12 @@ export const computeProviderShortNames = {
20
  [ComputeProvider.OPENAI]: "OpenAI",
21
  [ComputeProvider.REPLICATE]: "Replicate",
22
  [ComputeProvider.STABILITYAI]: "StabilityAI",
 
 
 
 
 
 
23
  }
24
 
25
  export const availableComputeProvidersForAssistant = [
@@ -39,6 +45,7 @@ export const availableComputeProvidersForImages = [
39
  ComputeProvider.FIREWORKSAI,
40
  ComputeProvider.FALAI,
41
  ComputeProvider.MODELSLAB,
 
42
  ]
43
 
44
  export const availableComputeProvidersForVideos = [
@@ -50,6 +57,10 @@ export const availableComputeProvidersForVideos = [
50
  // ComputeProvider.FIREWORKSAI,
51
  ComputeProvider.FALAI,
52
  ComputeProvider.MODELSLAB,
 
 
 
 
53
  ]
54
 
55
  export const availableComputeProvidersForMusic = [
@@ -60,6 +71,8 @@ export const availableComputeProvidersForMusic = [
60
  // ComputeProvider.FIREWORKSAI,
61
  ComputeProvider.FALAI,
62
  ComputeProvider.MODELSLAB,
 
 
63
  ]
64
 
65
  export const availableComputeProvidersForSound = [
@@ -139,6 +152,7 @@ export const availableModelsForAssistantTurbo: Partial<Record<ComputeProvider, s
139
  // so it will have to be taken into account
140
  export const availableModelsForImageGeneration: Partial<Record<ComputeProvider, string[]>> = {
141
  [ComputeProvider.FALAI]: [
 
142
  "fal-ai/fast-sdxl",
143
  "fal-ai/stable-cascade",
144
  "fal-ai/fast-lightning-sdxl",
@@ -158,6 +172,9 @@ export const availableModelsForImageGeneration: Partial<Record<ComputeProvider,
158
  "accounts/stability/models/sd3-turbo",
159
  "fireworks/stable-diffusion-xl-1024-v1-0",
160
  "accounts/fireworks/models/playground-v2-5-1024px-aesthetic",
 
 
 
161
  ]
162
  }
163
 
@@ -178,6 +195,21 @@ export const availableModelsForVideoGeneration: Partial<Record<ComputeProvider,
178
  ],
179
  [ComputeProvider.STABILITYAI]: [
180
  "image-to-video",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
181
  ]
182
  }
183
 
@@ -201,5 +233,11 @@ export const availableModelsForVoiceGeneration: Partial<Record<ComputeProvider,
201
  export const availableModelsForMusicGeneration: Partial<Record<ComputeProvider, string[]>> = {
202
  [ComputeProvider.FALAI]: [
203
  "fal-ai/stable-audio"
204
- ]
 
 
 
 
 
 
205
  }
 
20
  [ComputeProvider.OPENAI]: "OpenAI",
21
  [ComputeProvider.REPLICATE]: "Replicate",
22
  [ComputeProvider.STABILITYAI]: "StabilityAI",
23
+ [ComputeProvider.MIDJOURNEY]: "Midjourney (no image API)",
24
+ [ComputeProvider.SUNO]: "Suno (no music API)",
25
+ [ComputeProvider.UDIO]: "Udio (no music API)",
26
+ [ComputeProvider.LUMALABS]: "LumaLabs (no video API)",
27
+ [ComputeProvider.KUAISHOU]: "KuaiShou (no video API)",
28
+ [ComputeProvider.RUNWAYML]: "RunwayML (no video API)",
29
  }
30
 
31
  export const availableComputeProvidersForAssistant = [
 
45
  ComputeProvider.FIREWORKSAI,
46
  ComputeProvider.FALAI,
47
  ComputeProvider.MODELSLAB,
48
+ ComputeProvider.MIDJOURNEY,
49
  ]
50
 
51
  export const availableComputeProvidersForVideos = [
 
57
  // ComputeProvider.FIREWORKSAI,
58
  ComputeProvider.FALAI,
59
  ComputeProvider.MODELSLAB,
60
+ ComputeProvider.OPENAI,
61
+ ComputeProvider.GOOGLE,
62
+ ComputeProvider.LUMALABS,
63
+ ComputeProvider.KUAISHOU,
64
  ]
65
 
66
  export const availableComputeProvidersForMusic = [
 
71
  // ComputeProvider.FIREWORKSAI,
72
  ComputeProvider.FALAI,
73
  ComputeProvider.MODELSLAB,
74
+ ComputeProvider.SUNO,
75
+ ComputeProvider.UDIO,
76
  ]
77
 
78
  export const availableComputeProvidersForSound = [
 
152
  // so it will have to be taken into account
153
  export const availableModelsForImageGeneration: Partial<Record<ComputeProvider, string[]>> = {
154
  [ComputeProvider.FALAI]: [
155
+ "fal-ai/stable-diffusion-v3-medium",
156
  "fal-ai/fast-sdxl",
157
  "fal-ai/stable-cascade",
158
  "fal-ai/fast-lightning-sdxl",
 
172
  "accounts/stability/models/sd3-turbo",
173
  "fireworks/stable-diffusion-xl-1024-v1-0",
174
  "accounts/fireworks/models/playground-v2-5-1024px-aesthetic",
175
+ ],
176
+ [ComputeProvider.MIDJOURNEY]: [
177
+ "(No public API)",
178
  ]
179
  }
180
 
 
195
  ],
196
  [ComputeProvider.STABILITYAI]: [
197
  "image-to-video",
198
+ ],
199
+ [ComputeProvider.OPENAI]: [
200
+ "Sora is unavailable (no public API)",
201
+ ],
202
+ [ComputeProvider.GOOGLE]: [
203
+ "Veo is unavailable (no public API)",
204
+ ],
205
+ [ComputeProvider.RUNWAYML]: [
206
+ "Gen-3 is unavailable (no public API)",
207
+ ],
208
+ [ComputeProvider.LUMALABS]: [
209
+ "Dream Machine is unavailable (no public API)",
210
+ ],
211
+ [ComputeProvider.KUAISHOU]: [
212
+ "Kling is unavailable (no public API)",
213
  ]
214
  }
215
 
 
233
  export const availableModelsForMusicGeneration: Partial<Record<ComputeProvider, string[]>> = {
234
  [ComputeProvider.FALAI]: [
235
  "fal-ai/stable-audio"
236
+ ],
237
+ [ComputeProvider.SUNO]: [
238
+ "Suno is unavailable (No public API)"
239
+ ],
240
+ [ComputeProvider.UDIO]: [
241
+ "Udio is unavailable (No public API)"
242
+ ],
243
  }
src/components/settings/provider.tsx CHANGED
@@ -39,6 +39,21 @@ export function SettingsSectionProvider() {
39
  const anthropicApiKey = useSettings(s => s.anthropicApiKey)
40
  const setAnthropicApiKey = useSettings(s => s.setAnthropicApiKey)
41
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
  return (
43
  <div className="flex flex-col space-y-6 justify-between">
44
  <FormSection label="Compute providers">
@@ -135,6 +150,45 @@ export function SettingsSectionProvider() {
135
  type="password"
136
  />
137
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
138
  </FormSection>
139
  </div>
140
  )
 
39
  const anthropicApiKey = useSettings(s => s.anthropicApiKey)
40
  const setAnthropicApiKey = useSettings(s => s.setAnthropicApiKey)
41
 
42
+ const cohereApiKey = useSettings(s => s.cohereApiKey)
43
+ const setCohereApiKey = useSettings(s => s.setCohereApiKey)
44
+
45
+ const mistralAiApiKey = useSettings(s => s.mistralAiApiKey)
46
+ const setMistralAiApiKey = useSettings(s => s.setMistralAiApiKey)
47
+
48
+ const stabilityAiApiKey = useSettings(s => s.stabilityAiApiKey)
49
+ const setStabilityAiApiKey = useSettings(s => s.setStabilityAiApiKey)
50
+
51
+ const elevenLabsApiKey = useSettings(s => s.elevenLabsApiKey)
52
+ const setElevenLabsApiKey = useSettings(s => s.setElevenLabsApiKey)
53
+
54
+ const kitsAiApiKey = useSettings(s => s.kitsAiApiKey)
55
+ const setKitsAiApiKey = useSettings(s => s.setKitsAiApiKey)
56
+
57
  return (
58
  <div className="flex flex-col space-y-6 justify-between">
59
  <FormSection label="Compute providers">
 
150
  type="password"
151
  />
152
 
153
+ <FormInput
154
+ label="Cohere API Key"
155
+ value={cohereApiKey}
156
+ defaultValue={defaultSettings.cohereApiKey}
157
+ onChange={setCohereApiKey}
158
+ type="password"
159
+ />
160
+
161
+ <FormInput
162
+ label="MistralAI API Key"
163
+ value={mistralAiApiKey}
164
+ defaultValue={defaultSettings.mistralAiApiKey}
165
+ onChange={setMistralAiApiKey}
166
+ type="password"
167
+ />
168
+
169
+ <FormInput
170
+ label="StabilityAI API Key"
171
+ value={stabilityAiApiKey}
172
+ defaultValue={defaultSettings.stabilityAiApiKey}
173
+ onChange={setStabilityAiApiKey}
174
+ type="password"
175
+ />
176
+
177
+ <FormInput
178
+ label="ElevenLabs API Key"
179
+ value={elevenLabsApiKey}
180
+ defaultValue={defaultSettings.elevenLabsApiKey}
181
+ onChange={setElevenLabsApiKey}
182
+ type="password"
183
+ />
184
+
185
+ <FormInput
186
+ label="KitsAI API Key"
187
+ value={kitsAiApiKey}
188
+ defaultValue={defaultSettings.kitsAiApiKey}
189
+ onChange={setKitsAiApiKey}
190
+ type="password"
191
+ />
192
  </FormSection>
193
  </div>
194
  )
src/components/tasks/types.ts CHANGED
@@ -1,36 +1,36 @@
1
  import { ReactNode } from "react"
2
 
3
- export type TaskVisibility =
4
- | "blocker"
5
- | "background"
6
- | "invisible"
 
7
 
8
- export type TaskProgressType =
9
- | "ratio" // number between 0 and 1
10
- | "percentage" // number between 0 and 100
11
- | "counter" // number between min and max
 
12
 
13
- export type TaskCategory =
14
- | "download"
15
- | "import"
16
- | "analysis"
17
- | "storyboard"
18
- | "video"
19
- | "depth"
20
- | "mesh"
21
- | "splat"
22
- | "phenomenon"
23
- | "interface"
24
- | "generic"
25
 
26
- export type TaskStatus =
27
- | "upcoming"
28
- | "running"
29
- | "paused"
30
- | "cancelled"
31
- | "error"
32
- | "success"
33
- | "deleted"
 
34
 
35
  export type StatusGetter = () => TaskStatus
36
  export type TaskRunner = (getStatus: StatusGetter) => Promise<TaskStatus>
 
1
  import { ReactNode } from "react"
2
 
3
+ export enum TaskVisibility {
4
+ BLOCKER = "BLOCKER",
5
+ BACKGROUND = "BACKGROUND",
6
+ INVISIBLE = "INVISIBLE"
7
+ }
8
 
9
+ export enum TaskProgressType {
10
+ RATIO = "RATIO", // number between 0 and 1
11
+ PERCENTAGE = "PERCENTAGE", // number between 0 and 100
12
+ COUNTER = "COUNTER" // number between min and max
13
+ }
14
 
15
+ export enum TaskCategory {
16
+ DOWNLOAD = "DOWNLOAD",
17
+ EXPORT = "EXPORT",
18
+ IMPORT = "IMPORT",
19
+ ANALYSIS = "ANALYSIS",
20
+ STORYBOARD = "STORYBOARD",
21
+ VIDEO = "VIDEO",
22
+ GENERIC = "GENERIC"
23
+ }
 
 
 
24
 
25
+ export enum TaskStatus {
26
+ UPCOMING = "UPCOMING",
27
+ RUNNING = "RUNNING",
28
+ PAUSED = "PAUSED",
29
+ CANCELLED = "CANCELLED",
30
+ ERROR = "ERROR",
31
+ SUCCESS = "SUCCESS",
32
+ DELETED = "DELETED"
33
+ }
34
 
35
  export type StatusGetter = () => TaskStatus
36
  export type TaskRunner = (getStatus: StatusGetter) => Promise<TaskStatus>
src/components/tasks/useTasks.tsx CHANGED
@@ -11,9 +11,9 @@ import { sleep } from "@/lib/utils/sleep"
11
  // we enforce the impossibility of some transitions
12
  function statusTransition(current: TaskStatus, requested: TaskStatus): TaskStatus {
13
  switch (current) {
14
- case "upcoming":
15
- case "running":
16
- case "paused":
17
  return requested
18
 
19
  default:
@@ -131,25 +131,21 @@ export const useTasks = create<{
131
  return list
132
  },
133
  add: (partialTask: Partial<NewTask>, status?: TaskStatus): TaskRemoteControl => {
134
- const mode: TaskProgressType =
135
- partialTask?.mode === "counter" ? "counter" :
136
- partialTask?.mode === "ratio" ? "ratio" :
137
- partialTask?.mode === "percentage" ? "percentage" :
138
- "percentage"
139
-
140
- const min = mode === "counter" && partialTask?.min ? partialTask.min : 0
141
- const max = mode === "counter" && partialTask?.max ? partialTask.max : mode === "ratio" ? 1 : mode === "percentage" ? 100 : 100
142
 
143
  const id = UUID()
144
 
145
  const newTask: NewTask = {
146
  id,
147
- visibility: partialTask?.visibility || "background",
148
- category: partialTask?.category || "generic",
149
  initialMessage: partialTask?.initialMessage || "Loading..",
150
  successMessage: partialTask?.successMessage || "Task completed!",
151
  priority: partialTask?.priority || 0, // 0 = lowest, 1 or more = more and more important
152
- status: status || "running",
153
  value: partialTask?.value || 0,
154
  progress: partialTask?.progress || 0,
155
  min,
@@ -163,7 +159,7 @@ export const useTasks = create<{
163
  currentMessage: newTask.initialMessage,
164
  startedAt: new Date().toISOString(),
165
  endedAt: "",
166
- promise: Promise.resolve("running"),
167
  }
168
 
169
  task.promise = new Promise<TaskStatus>((resolve, reject) => {
@@ -173,7 +169,7 @@ export const useTasks = create<{
173
  const t = get().get(id)!
174
 
175
  if (!t) {
176
- resolve("success" )
177
  return
178
  }
179
 
@@ -182,15 +178,15 @@ export const useTasks = create<{
182
 
183
  console.log(`useTasks[${id}]: checkStatus: checking task, current status is: "${status}"`)
184
  if (
185
- status === "error" ||
186
- status === "success" ||
187
- status === "deleted" ||
188
- status === "cancelled"
189
  ) {
190
  console.log(`useTasks[${id}]: checkStatus: status is "${status}", interrupting task loop..`)
191
 
192
  // this call might be redundant
193
- if (status === "success") {
194
  get().setProgress(id, { isFinished: true })
195
  }
196
  resolve(status)
@@ -198,8 +194,8 @@ export const useTasks = create<{
198
  console.log(`useTasks[${id}]: checkStatus: task is completed at 100%, interrupting task loop..`)
199
  // this call might be redundant
200
  get().setProgress(id, { isFinished: true })
201
- // get().setStatus("success", id)
202
- resolve("success")
203
  } else {
204
  console.log(`useTasks[${id}]: checkStatus: status is "${status}", continuing task loop..`)
205
  setTimeout(checkStatus, 1000)
@@ -215,7 +211,7 @@ export const useTasks = create<{
215
  toast.promise<TaskStatus>(task.promise, {
216
  loading: <TaskStatusUpdate taskId={id} />,
217
  success: (finalStatus) => {
218
- return finalStatus === "success" ? task.successMessage : `Task ended`;
219
  },
220
  error: 'Task aborted',
221
  });
@@ -257,10 +253,10 @@ export const useTasks = create<{
257
  return remoteControl
258
  },
259
  pause: (taskId?: string) => {
260
- get().setStatus("paused", taskId)
261
  },
262
  continue: (taskId?: string) => {
263
- get().setStatus("running", taskId)
264
  },
265
  setStatus: (status: TaskStatus, taskId?: string) => {
266
  const { tasks } = get()
@@ -304,9 +300,9 @@ export const useTasks = create<{
304
  if (task) {
305
 
306
  let progress =
307
- task.mode === "percentage"
308
  ? value :
309
- task.mode === "ratio"
310
  ? (value * 100)
311
  : ((value - task.min) / (task.max - task.min)) * 100
312
 
@@ -319,7 +315,7 @@ export const useTasks = create<{
319
  [task.id]: {
320
  ...task,
321
  currentMessage,
322
- status: "error",
323
  endedAt: new Date().toISOString(),
324
  }
325
  }
@@ -341,7 +337,7 @@ export const useTasks = create<{
341
  progress,
342
  value,
343
  currentMessage,
344
- status: isFinished ? "success" : "running",
345
  endedAt: isFinished ? new Date().toISOString() : task.endedAt,
346
  }
347
  }
@@ -360,7 +356,7 @@ export const useTasks = create<{
360
  },
361
  success: (taskId: string) => {
362
  get().setProgress(taskId, { isFinished: true })
363
- get().setStatus("success", taskId)
364
  },
365
  fail: (taskId: string, reason?: string) => {
366
  get().setProgress(taskId, {
@@ -368,9 +364,9 @@ export const useTasks = create<{
368
  isFinished: true,
369
  hasFailed: true,
370
  })
371
- get().setStatus("error", taskId)
372
  },
373
  cancel: (taskId?: string) => {
374
- get().setStatus("cancelled", taskId)
375
  }
376
  }))
 
11
  // we enforce the impossibility of some transitions
12
  function statusTransition(current: TaskStatus, requested: TaskStatus): TaskStatus {
13
  switch (current) {
14
+ case TaskStatus.UPCOMING:
15
+ case TaskStatus.RUNNING:
16
+ case TaskStatus.PAUSED:
17
  return requested
18
 
19
  default:
 
131
  return list
132
  },
133
  add: (partialTask: Partial<NewTask>, status?: TaskStatus): TaskRemoteControl => {
134
+ const mode: TaskProgressType = partialTask?.mode || TaskProgressType.PERCENTAGE
135
+
136
+ const min = mode === TaskProgressType.COUNTER && partialTask?.min ? partialTask.min : 0
137
+ const max = mode === TaskProgressType.COUNTER && partialTask?.max ? partialTask.max : mode === TaskProgressType.RATIO ? 1 : mode === TaskProgressType.PERCENTAGE ? 100 : 100
 
 
 
 
138
 
139
  const id = UUID()
140
 
141
  const newTask: NewTask = {
142
  id,
143
+ visibility: partialTask?.visibility || TaskVisibility.BACKGROUND,
144
+ category: partialTask?.category || TaskCategory.GENERIC,
145
  initialMessage: partialTask?.initialMessage || "Loading..",
146
  successMessage: partialTask?.successMessage || "Task completed!",
147
  priority: partialTask?.priority || 0, // 0 = lowest, 1 or more = more and more important
148
+ status: status || TaskStatus.RUNNING,
149
  value: partialTask?.value || 0,
150
  progress: partialTask?.progress || 0,
151
  min,
 
159
  currentMessage: newTask.initialMessage,
160
  startedAt: new Date().toISOString(),
161
  endedAt: "",
162
+ promise: Promise.resolve(TaskStatus.RUNNING),
163
  }
164
 
165
  task.promise = new Promise<TaskStatus>((resolve, reject) => {
 
169
  const t = get().get(id)!
170
 
171
  if (!t) {
172
+ resolve(TaskStatus.SUCCESS)
173
  return
174
  }
175
 
 
178
 
179
  console.log(`useTasks[${id}]: checkStatus: checking task, current status is: "${status}"`)
180
  if (
181
+ status === TaskStatus.ERROR ||
182
+ status === TaskStatus.SUCCESS ||
183
+ status === TaskStatus.DELETED ||
184
+ status === TaskStatus.CANCELLED
185
  ) {
186
  console.log(`useTasks[${id}]: checkStatus: status is "${status}", interrupting task loop..`)
187
 
188
  // this call might be redundant
189
+ if (status === TaskStatus.SUCCESS) {
190
  get().setProgress(id, { isFinished: true })
191
  }
192
  resolve(status)
 
194
  console.log(`useTasks[${id}]: checkStatus: task is completed at 100%, interrupting task loop..`)
195
  // this call might be redundant
196
  get().setProgress(id, { isFinished: true })
197
+ // get().setStatus(TaskStatus.SUCCESS, id)
198
+ resolve(TaskStatus.SUCCESS)
199
  } else {
200
  console.log(`useTasks[${id}]: checkStatus: status is "${status}", continuing task loop..`)
201
  setTimeout(checkStatus, 1000)
 
211
  toast.promise<TaskStatus>(task.promise, {
212
  loading: <TaskStatusUpdate taskId={id} />,
213
  success: (finalStatus) => {
214
+ return finalStatus === TaskStatus.SUCCESS ? task.successMessage : `Task ended`;
215
  },
216
  error: 'Task aborted',
217
  });
 
253
  return remoteControl
254
  },
255
  pause: (taskId?: string) => {
256
+ get().setStatus(TaskStatus.PAUSED, taskId)
257
  },
258
  continue: (taskId?: string) => {
259
+ get().setStatus(TaskStatus.RUNNING, taskId)
260
  },
261
  setStatus: (status: TaskStatus, taskId?: string) => {
262
  const { tasks } = get()
 
300
  if (task) {
301
 
302
  let progress =
303
+ task.mode === TaskProgressType.PERCENTAGE
304
  ? value :
305
+ task.mode === TaskProgressType.RATIO
306
  ? (value * 100)
307
  : ((value - task.min) / (task.max - task.min)) * 100
308
 
 
315
  [task.id]: {
316
  ...task,
317
  currentMessage,
318
+ status: TaskStatus.ERROR,
319
  endedAt: new Date().toISOString(),
320
  }
321
  }
 
337
  progress,
338
  value,
339
  currentMessage,
340
+ status: isFinished ? TaskStatus.SUCCESS : TaskStatus.RUNNING,
341
  endedAt: isFinished ? new Date().toISOString() : task.endedAt,
342
  }
343
  }
 
356
  },
357
  success: (taskId: string) => {
358
  get().setProgress(taskId, { isFinished: true })
359
+ get().setStatus(TaskStatus.SUCCESS, taskId)
360
  },
361
  fail: (taskId: string, reason?: string) => {
362
  get().setProgress(taskId, {
 
364
  isFinished: true,
365
  hasFailed: true,
366
  })
367
+ get().setStatus(TaskStatus.ERROR, taskId)
368
  },
369
  cancel: (taskId?: string) => {
370
+ get().setStatus(TaskStatus.CANCELLED, taskId)
371
  }
372
  }))
src/components/toolbars/top-menu/assistant/index.tsx CHANGED
@@ -16,7 +16,7 @@ import { useUI } from "@/controllers/ui"
16
 
17
  import { ProviderList } from "../lists/ProviderList"
18
  import { availableComputeProvidersForAssistant } from "@/components/settings/constants"
19
- import { SettingsCategory } from "@/types"
20
  import { AssistantModelList } from "../lists/AssistantModelList"
21
 
22
  export function TopMenuAssistant() {
@@ -33,7 +33,11 @@ export function TopMenuAssistant() {
33
  <MenubarItem onClick={() => { setShowSettings(SettingsCategory.ASSISTANT) }}>Show advanced settings</MenubarItem>
34
  <MenubarSeparator />
35
  <AssistantModelList provider={assistantProvider} current={assistantModel} setter={setAssistantModel} />
36
- <ProviderList providers={availableComputeProvidersForAssistant} current={assistantProvider} setter={setAssistantProvider} />
 
 
 
 
37
  <MenubarSeparator />
38
  <MenubarItem
39
  disabled
 
16
 
17
  import { ProviderList } from "../lists/ProviderList"
18
  import { availableComputeProvidersForAssistant } from "@/components/settings/constants"
19
+ import { ComputeProvider, SettingsCategory } from "@/types"
20
  import { AssistantModelList } from "../lists/AssistantModelList"
21
 
22
  export function TopMenuAssistant() {
 
33
  <MenubarItem onClick={() => { setShowSettings(SettingsCategory.ASSISTANT) }}>Show advanced settings</MenubarItem>
34
  <MenubarSeparator />
35
  <AssistantModelList provider={assistantProvider} current={assistantModel} setter={setAssistantModel} />
36
+ <ProviderList providers={availableComputeProvidersForAssistant} current={assistantProvider} setter={(newProvider: ComputeProvider) => {
37
+ if (assistantProvider === newProvider) { return }
38
+ setAssistantProvider(newProvider)
39
+ setAssistantModel(undefined)
40
+ }} />
41
  <MenubarSeparator />
42
  <MenubarItem
43
  disabled
src/components/toolbars/top-menu/file/index.tsx CHANGED
@@ -4,7 +4,7 @@ import { useTimeline } from "@aitube/timeline"
4
  import { useHotkeys } from "react-hotkeys-hook"
5
 
6
  import { MenubarContent, MenubarItem, MenubarMenu, MenubarSeparator, MenubarShortcut, MenubarTrigger } from "@/components/ui/menubar"
7
- import { useClapFilePicker, useQueryStringParams, useScreenplayFilePicker } from "@/lib/hooks"
8
  import { Loader } from "@/components/dialogs/loader"
9
  import { IframeWarning } from "@/components/dialogs/iframe-warning"
10
  import { useIO } from "@/controllers/io/useIO"
@@ -22,10 +22,9 @@ export function TopMenuFile() {
22
  //const saveClapAs = useTimeline(s => s.saveClapAs)
23
  //const setFullVideo = useTimeline(s => s.fullVideo)
24
 
25
- const clapPicker = useClapFilePicker()
26
- const screenplayPicker = useScreenplayFilePicker()
27
 
28
- const isLoading = isTimelineLoading || clapPicker.isLoading || screenplayPicker.isLoading
29
 
30
  const openClapUrl = useIO(s => s.openClapUrl)
31
  const saveClap = useIO(s => s.saveClap)
@@ -43,8 +42,8 @@ export function TopMenuFile() {
43
  }, [clapUrl])
44
 
45
  // const setShowSettings = useUISettings(s => s.setShowSettings)
46
- useHotkeys('ctrl+o', () => clapPicker.openFilePicker(), { preventDefault: true }, [])
47
- useHotkeys('meta+o', () => clapPicker.openFilePicker(), { preventDefault: true }, [])
48
  // useHotkeys('ctrl+s', () => saveClapAs({ embedded: true }), { preventDefault: true }, [])
49
  // useHotkeys('meta+s', () => saveClapAs({ embedded: true }), { preventDefault: true }, [])
50
  useHotkeys('ctrl+s', () => saveClap(), { preventDefault: true }, [])
@@ -57,9 +56,9 @@ export function TopMenuFile() {
57
  <MenubarTrigger>File</MenubarTrigger>
58
  <MenubarContent>
59
  <MenubarItem onClick={() => {
60
- clapPicker.openFilePicker()
61
  }}>
62
- Open project (.clap)<MenubarShortcut>⌘O</MenubarShortcut>
63
  </MenubarItem>
64
  <MenubarItem
65
  onClick={() => {
@@ -72,13 +71,7 @@ export function TopMenuFile() {
72
  onClick={() => {
73
  saveVideoFile()
74
  }}>
75
- Render project (.mp4)
76
- </MenubarItem>
77
- <MenubarSeparator />
78
- <MenubarItem onClick={() => {
79
- screenplayPicker.openFilePicker()
80
- }}>
81
- Import screenplay (.txt)
82
  </MenubarItem>
83
  <MenubarSeparator />
84
  {/*
@@ -92,14 +85,14 @@ export function TopMenuFile() {
92
  <MenubarItem
93
  disabled
94
  onClick={() => {
95
- screenplayPicker.openFilePicker()
96
  }}>
97
  Import .fountain (not implemented)
98
  </MenubarItem>
99
  <MenubarItem
100
  disabled
101
  onClick={() => {
102
- screenplayPicker.openFilePicker()
103
  }}>
104
  Export .fountain (not implemented)
105
  </MenubarItem>
@@ -107,14 +100,14 @@ export function TopMenuFile() {
107
  <MenubarItem
108
  disabled
109
  onClick={() => {
110
- screenplayPicker.openFilePicker()
111
  }}>
112
  Import .fdx (not implemented)
113
  </MenubarItem>
114
  <MenubarItem
115
  disabled
116
  onClick={() => {
117
- screenplayPicker.openFilePicker()
118
  }}>
119
  Export .fdx (not implemented)
120
  </MenubarItem>
 
4
  import { useHotkeys } from "react-hotkeys-hook"
5
 
6
  import { MenubarContent, MenubarItem, MenubarMenu, MenubarSeparator, MenubarShortcut, MenubarTrigger } from "@/components/ui/menubar"
7
+ import { useOpenFilePicker, useQueryStringParams } from "@/lib/hooks"
8
  import { Loader } from "@/components/dialogs/loader"
9
  import { IframeWarning } from "@/components/dialogs/iframe-warning"
10
  import { useIO } from "@/controllers/io/useIO"
 
22
  //const saveClapAs = useTimeline(s => s.saveClapAs)
23
  //const setFullVideo = useTimeline(s => s.fullVideo)
24
 
25
+ const { openFilePicker, isLoading: filePickerIsLoading } = useOpenFilePicker()
 
26
 
27
+ const isLoading = isTimelineLoading || filePickerIsLoading
28
 
29
  const openClapUrl = useIO(s => s.openClapUrl)
30
  const saveClap = useIO(s => s.saveClap)
 
42
  }, [clapUrl])
43
 
44
  // const setShowSettings = useUISettings(s => s.setShowSettings)
45
+ useHotkeys('ctrl+o', () => openFilePicker(), { preventDefault: true }, [])
46
+ useHotkeys('meta+o', () => openFilePicker(), { preventDefault: true }, [])
47
  // useHotkeys('ctrl+s', () => saveClapAs({ embedded: true }), { preventDefault: true }, [])
48
  // useHotkeys('meta+s', () => saveClapAs({ embedded: true }), { preventDefault: true }, [])
49
  useHotkeys('ctrl+s', () => saveClap(), { preventDefault: true }, [])
 
56
  <MenubarTrigger>File</MenubarTrigger>
57
  <MenubarContent>
58
  <MenubarItem onClick={() => {
59
+ openFilePicker()
60
  }}>
61
+ Open file (.clap, .txt)<MenubarShortcut>⌘O</MenubarShortcut>
62
  </MenubarItem>
63
  <MenubarItem
64
  onClick={() => {
 
71
  onClick={() => {
72
  saveVideoFile()
73
  }}>
74
+ Export project to MP4
 
 
 
 
 
 
75
  </MenubarItem>
76
  <MenubarSeparator />
77
  {/*
 
85
  <MenubarItem
86
  disabled
87
  onClick={() => {
88
+
89
  }}>
90
  Import .fountain (not implemented)
91
  </MenubarItem>
92
  <MenubarItem
93
  disabled
94
  onClick={() => {
95
+
96
  }}>
97
  Export .fountain (not implemented)
98
  </MenubarItem>
 
100
  <MenubarItem
101
  disabled
102
  onClick={() => {
103
+
104
  }}>
105
  Import .fdx (not implemented)
106
  </MenubarItem>
107
  <MenubarItem
108
  disabled
109
  onClick={() => {
110
+
111
  }}>
112
  Export .fdx (not implemented)
113
  </MenubarItem>
src/components/toolbars/top-menu/image/index.tsx CHANGED
@@ -19,7 +19,7 @@ import { RenderingStrategyList } from "../lists/RenderingStrategyList"
19
  import { availableComputeProvidersForImages } from "@/components/settings/constants"
20
  import { ImageGenerationModelList } from "../lists/ImageGenerationModelList"
21
  import { ImageUpscalingModelList } from "../lists/ImageUpscalingModelList"
22
- import { SettingsCategory } from "@/types"
23
 
24
  export function TopMenuImage() {
25
  const setShowSettings = useUI(s => s.setShowSettings)
@@ -40,7 +40,12 @@ export function TopMenuImage() {
40
  <MenubarSeparator />
41
  <ImageGenerationModelList provider={imageProvider} current={imageGenerationModel} setter={setImageGenerationModel} />
42
  <ImageUpscalingModelList provider={imageProvider} current={imageUpscalingModel} setter={setImageUpscalingModel} />
43
- <ProviderList providers={availableComputeProvidersForImages} current={imageProvider} setter={setImageProvider} />
 
 
 
 
 
44
  <RenderingStrategyList current={imageRenderingStrategy} setter={setImageRenderingStrategy} />
45
  <MenubarSeparator />
46
  <MenubarItem
 
19
  import { availableComputeProvidersForImages } from "@/components/settings/constants"
20
  import { ImageGenerationModelList } from "../lists/ImageGenerationModelList"
21
  import { ImageUpscalingModelList } from "../lists/ImageUpscalingModelList"
22
+ import { ComputeProvider, SettingsCategory } from "@/types"
23
 
24
  export function TopMenuImage() {
25
  const setShowSettings = useUI(s => s.setShowSettings)
 
40
  <MenubarSeparator />
41
  <ImageGenerationModelList provider={imageProvider} current={imageGenerationModel} setter={setImageGenerationModel} />
42
  <ImageUpscalingModelList provider={imageProvider} current={imageUpscalingModel} setter={setImageUpscalingModel} />
43
+ <ProviderList providers={availableComputeProvidersForImages} current={imageProvider} setter={(newProvider: ComputeProvider) => {
44
+ if (imageProvider === newProvider) { return }
45
+ setImageProvider(newProvider)
46
+ setImageGenerationModel(undefined)
47
+ setImageUpscalingModel(undefined)
48
+ }} />
49
  <RenderingStrategyList current={imageRenderingStrategy} setter={setImageRenderingStrategy} />
50
  <MenubarSeparator />
51
  <MenubarItem
src/components/toolbars/top-menu/lists/AssistantModelList.tsx CHANGED
@@ -15,6 +15,7 @@ import { TagColor } from "@/components/tags/types"
15
  import { Tag } from "@/components/tags/Tag"
16
  import { ComputeProvider } from "@/types"
17
  import { availableModelsForAssistant } from "@/components/settings/constants"
 
18
 
19
  export function AssistantModelList({
20
  provider,
@@ -32,7 +33,7 @@ export function AssistantModelList({
32
  return (
33
  <MenubarSub>
34
  <MenubarSubTrigger>
35
- <Tag size="lg" color={TagColor.GREEN}>ai&nbsp;assistant</Tag>
36
  {current || "None"}
37
  </MenubarSubTrigger>
38
  <MenubarSubContent>
@@ -40,7 +41,13 @@ export function AssistantModelList({
40
  <MenubarCheckboxItem
41
  key={model}
42
  checked={current === model}
 
43
  onClick={(e) => {
 
 
 
 
 
44
  setter(model)
45
  e.stopPropagation()
46
  e.preventDefault()
 
15
  import { Tag } from "@/components/tags/Tag"
16
  import { ComputeProvider } from "@/types"
17
  import { availableModelsForAssistant } from "@/components/settings/constants"
18
+ import { hasNoPublicAPI } from "./hasNoPublicAPI"
19
 
20
  export function AssistantModelList({
21
  provider,
 
33
  return (
34
  <MenubarSub>
35
  <MenubarSubTrigger>
36
+ <Tag size="lg" color={TagColor.FUCHSIA}>ai&nbsp;assistant</Tag>
37
  {current || "None"}
38
  </MenubarSubTrigger>
39
  <MenubarSubContent>
 
41
  <MenubarCheckboxItem
42
  key={model}
43
  checked={current === model}
44
+ disabled={hasNoPublicAPI(model)}
45
  onClick={(e) => {
46
+ if (hasNoPublicAPI(model)) {
47
+ e.stopPropagation()
48
+ e.preventDefault()
49
+ return false
50
+ }
51
  setter(model)
52
  e.stopPropagation()
53
  e.preventDefault()
src/components/toolbars/top-menu/lists/ImageGenerationModelList.tsx CHANGED
@@ -15,6 +15,7 @@ import { TagColor } from "@/components/tags/types"
15
  import { Tag } from "@/components/tags/Tag"
16
  import { ComputeProvider } from "@/types"
17
  import { availableModelsForImageGeneration } from "@/components/settings/constants"
 
18
 
19
  export function ImageGenerationModelList({
20
  provider,
@@ -32,7 +33,7 @@ export function ImageGenerationModelList({
32
  return (
33
  <MenubarSub>
34
  <MenubarSubTrigger>
35
- <Tag size="lg" color={TagColor.SKY}>generate&nbsp;image</Tag>
36
  {current || "None"}
37
  </MenubarSubTrigger>
38
  <MenubarSubContent>
@@ -40,7 +41,13 @@ export function ImageGenerationModelList({
40
  <MenubarCheckboxItem
41
  key={model}
42
  checked={current === model}
 
43
  onClick={(e) => {
 
 
 
 
 
44
  setter(model)
45
  e.stopPropagation()
46
  e.preventDefault()
 
15
  import { Tag } from "@/components/tags/Tag"
16
  import { ComputeProvider } from "@/types"
17
  import { availableModelsForImageGeneration } from "@/components/settings/constants"
18
+ import { hasNoPublicAPI } from "./hasNoPublicAPI"
19
 
20
  export function ImageGenerationModelList({
21
  provider,
 
33
  return (
34
  <MenubarSub>
35
  <MenubarSubTrigger>
36
+ <Tag size="lg" color={TagColor.BLUE}>generate&nbsp;image</Tag>
37
  {current || "None"}
38
  </MenubarSubTrigger>
39
  <MenubarSubContent>
 
41
  <MenubarCheckboxItem
42
  key={model}
43
  checked={current === model}
44
+ disabled={hasNoPublicAPI(model)}
45
  onClick={(e) => {
46
+ if (hasNoPublicAPI(model)) {
47
+ e.stopPropagation()
48
+ e.preventDefault()
49
+ return false
50
+ }
51
  setter(model)
52
  e.stopPropagation()
53
  e.preventDefault()
src/components/toolbars/top-menu/lists/ImageUpscalingModelList.tsx CHANGED
@@ -15,6 +15,7 @@ import { TagColor } from "@/components/tags/types"
15
  import { Tag } from "@/components/tags/Tag"
16
  import { ComputeProvider } from "@/types"
17
  import { availableModelsForImageUpscaling } from "@/components/settings/constants"
 
18
 
19
  export function ImageUpscalingModelList({
20
  provider,
@@ -32,7 +33,7 @@ export function ImageUpscalingModelList({
32
  return (
33
  <MenubarSub>
34
  <MenubarSubTrigger>
35
- <Tag size="lg" color={TagColor.BLUE}>upscale&nbsp;image</Tag>
36
  {current || "None"}
37
  </MenubarSubTrigger>
38
  <MenubarSubContent>
@@ -40,7 +41,13 @@ export function ImageUpscalingModelList({
40
  <MenubarCheckboxItem
41
  key={model}
42
  checked={current === model}
 
43
  onClick={(e) => {
 
 
 
 
 
44
  setter(model)
45
  e.stopPropagation()
46
  e.preventDefault()
 
15
  import { Tag } from "@/components/tags/Tag"
16
  import { ComputeProvider } from "@/types"
17
  import { availableModelsForImageUpscaling } from "@/components/settings/constants"
18
+ import { hasNoPublicAPI } from "./hasNoPublicAPI"
19
 
20
  export function ImageUpscalingModelList({
21
  provider,
 
33
  return (
34
  <MenubarSub>
35
  <MenubarSubTrigger>
36
+ <Tag size="lg" color={TagColor.INDIGO}>upscale&nbsp;image</Tag>
37
  {current || "None"}
38
  </MenubarSubTrigger>
39
  <MenubarSubContent>
 
41
  <MenubarCheckboxItem
42
  key={model}
43
  checked={current === model}
44
+ disabled={hasNoPublicAPI(model)}
45
  onClick={(e) => {
46
+ if (hasNoPublicAPI(model)) {
47
+ e.stopPropagation()
48
+ e.preventDefault()
49
+ return false
50
+ }
51
  setter(model)
52
  e.stopPropagation()
53
  e.preventDefault()
src/components/toolbars/top-menu/lists/MusicGenerationModelList.tsx CHANGED
@@ -15,6 +15,7 @@ import { TagColor } from "@/components/tags/types"
15
  import { Tag } from "@/components/tags/Tag"
16
  import { ComputeProvider } from "@/types"
17
  import { availableModelsForMusicGeneration } from "@/components/settings/constants"
 
18
 
19
  export function MusicGenerationModelList({
20
  provider,
@@ -32,7 +33,7 @@ export function MusicGenerationModelList({
32
  return (
33
  <MenubarSub>
34
  <MenubarSubTrigger>
35
- <Tag size="lg" color={TagColor.GREEN}>generate&nbsp;music</Tag>
36
  {current || "None"}
37
  </MenubarSubTrigger>
38
  <MenubarSubContent>
@@ -40,7 +41,13 @@ export function MusicGenerationModelList({
40
  <MenubarCheckboxItem
41
  key={model}
42
  checked={current === model}
 
43
  onClick={(e) => {
 
 
 
 
 
44
  setter(model)
45
  e.stopPropagation()
46
  e.preventDefault()
 
15
  import { Tag } from "@/components/tags/Tag"
16
  import { ComputeProvider } from "@/types"
17
  import { availableModelsForMusicGeneration } from "@/components/settings/constants"
18
+ import { hasNoPublicAPI } from "./hasNoPublicAPI"
19
 
20
  export function MusicGenerationModelList({
21
  provider,
 
33
  return (
34
  <MenubarSub>
35
  <MenubarSubTrigger>
36
+ <Tag size="lg" color={TagColor.LIME}>generate&nbsp;music</Tag>
37
  {current || "None"}
38
  </MenubarSubTrigger>
39
  <MenubarSubContent>
 
41
  <MenubarCheckboxItem
42
  key={model}
43
  checked={current === model}
44
+ disabled={hasNoPublicAPI(model)}
45
  onClick={(e) => {
46
+ if (hasNoPublicAPI(model)) {
47
+ e.stopPropagation()
48
+ e.preventDefault()
49
+ return false
50
+ }
51
  setter(model)
52
  e.stopPropagation()
53
  e.preventDefault()
src/components/toolbars/top-menu/lists/ProviderList.tsx CHANGED
@@ -16,6 +16,7 @@ import { computeProviderShortNames } from "@/components/settings/constants"
16
  import { ComputeProvider } from "@/types"
17
  import { TagColor } from "@/components/tags/types"
18
  import { Tag } from "@/components/tags/Tag"
 
19
 
20
  const defaultProviders: ComputeProvider[] = Object.keys(computeProviderShortNames) as ComputeProvider[]
21
 
@@ -37,9 +38,20 @@ export function ProviderList({
37
  <MenubarSubContent>
38
  {providers.map(provider => (
39
  <MenubarCheckboxItem
40
- key={provider}
41
  checked={current === provider}
 
 
 
 
 
 
42
  onClick={(e) => {
 
 
 
 
 
43
  setter(provider)
44
  e.stopPropagation()
45
  e.preventDefault()
 
16
  import { ComputeProvider } from "@/types"
17
  import { TagColor } from "@/components/tags/types"
18
  import { Tag } from "@/components/tags/Tag"
19
+ import { hasNoPublicAPI } from "./hasNoPublicAPI"
20
 
21
  const defaultProviders: ComputeProvider[] = Object.keys(computeProviderShortNames) as ComputeProvider[]
22
 
 
38
  <MenubarSubContent>
39
  {providers.map(provider => (
40
  <MenubarCheckboxItem
41
+ key={provider}
42
  checked={current === provider}
43
+ disabled={hasNoPublicAPI(provider)}
44
+ className={
45
+ (hasNoPublicAPI(provider) || hasNoPublicAPI(computeProviderShortNames[provider]))
46
+ ? "opacity-50"
47
+ : "opacity-100"
48
+ }
49
  onClick={(e) => {
50
+ if (hasNoPublicAPI(provider) || hasNoPublicAPI(computeProviderShortNames[provider])) {
51
+ e.stopPropagation()
52
+ e.preventDefault()
53
+ return false
54
+ }
55
  setter(provider)
56
  e.stopPropagation()
57
  e.preventDefault()
src/components/toolbars/top-menu/lists/SoundGenerationModelList.tsx CHANGED
@@ -15,6 +15,7 @@ import { TagColor } from "@/components/tags/types"
15
  import { Tag } from "@/components/tags/Tag"
16
  import { ComputeProvider } from "@/types"
17
  import { availableModelsForSoundGeneration } from "@/components/settings/constants"
 
18
 
19
  export function SoundGenerationModelList({
20
  provider,
@@ -40,7 +41,13 @@ export function SoundGenerationModelList({
40
  <MenubarCheckboxItem
41
  key={model}
42
  checked={current === model}
 
43
  onClick={(e) => {
 
 
 
 
 
44
  setter(model)
45
  e.stopPropagation()
46
  e.preventDefault()
 
15
  import { Tag } from "@/components/tags/Tag"
16
  import { ComputeProvider } from "@/types"
17
  import { availableModelsForSoundGeneration } from "@/components/settings/constants"
18
+ import { hasNoPublicAPI } from "./hasNoPublicAPI"
19
 
20
  export function SoundGenerationModelList({
21
  provider,
 
41
  <MenubarCheckboxItem
42
  key={model}
43
  checked={current === model}
44
+ disabled={hasNoPublicAPI(model)}
45
  onClick={(e) => {
46
+ if (hasNoPublicAPI(model)) {
47
+ e.stopPropagation()
48
+ e.preventDefault()
49
+ return false
50
+ }
51
  setter(model)
52
  e.stopPropagation()
53
  e.preventDefault()
src/components/toolbars/top-menu/lists/VideoGenerationModelList.tsx CHANGED
@@ -15,6 +15,7 @@ import { TagColor } from "@/components/tags/types"
15
  import { Tag } from "@/components/tags/Tag"
16
  import { ComputeProvider } from "@/types"
17
  import { availableModelsForVideoGeneration } from "@/components/settings/constants"
 
18
 
19
  export function VideoGenerationModelList({
20
  provider,
@@ -32,7 +33,7 @@ export function VideoGenerationModelList({
32
  return (
33
  <MenubarSub>
34
  <MenubarSubTrigger>
35
- <Tag size="lg" color={TagColor.VIOLET}>generate&nbsp;video</Tag>
36
  {current || "None"}
37
  </MenubarSubTrigger>
38
  <MenubarSubContent>
@@ -40,13 +41,23 @@ export function VideoGenerationModelList({
40
  <MenubarCheckboxItem
41
  key={model}
42
  checked={current === model}
 
43
  onClick={(e) => {
 
 
 
 
 
44
  setter(model)
45
  e.stopPropagation()
46
  e.preventDefault()
47
  return false
48
  }}>
49
- {model}
 
 
 
 
50
  </MenubarCheckboxItem>
51
  ))}
52
  </MenubarSubContent>
 
15
  import { Tag } from "@/components/tags/Tag"
16
  import { ComputeProvider } from "@/types"
17
  import { availableModelsForVideoGeneration } from "@/components/settings/constants"
18
+ import { hasNoPublicAPI } from "./hasNoPublicAPI"
19
 
20
  export function VideoGenerationModelList({
21
  provider,
 
33
  return (
34
  <MenubarSub>
35
  <MenubarSubTrigger>
36
+ <Tag size="lg" color={TagColor.RED}>generate&nbsp;video</Tag>
37
  {current || "None"}
38
  </MenubarSubTrigger>
39
  <MenubarSubContent>
 
41
  <MenubarCheckboxItem
42
  key={model}
43
  checked={current === model}
44
+ disabled={hasNoPublicAPI(model)}
45
  onClick={(e) => {
46
+ if (hasNoPublicAPI(model)) {
47
+ e.stopPropagation()
48
+ e.preventDefault()
49
+ return false
50
+ }
51
  setter(model)
52
  e.stopPropagation()
53
  e.preventDefault()
54
  return false
55
  }}>
56
+ {
57
+ // if the model is unavailable, we should add a tooltip like this:
58
+ // https://x.com/flngr/status/1800968844581929094
59
+ model
60
+ }
61
  </MenubarCheckboxItem>
62
  ))}
63
  </MenubarSubContent>
src/components/toolbars/top-menu/lists/VideoUpscalingModelList.tsx CHANGED
@@ -15,6 +15,7 @@ import { TagColor } from "@/components/tags/types"
15
  import { Tag } from "@/components/tags/Tag"
16
  import { ComputeProvider } from "@/types"
17
  import { availableModelsForVideoUpscaling } from "@/components/settings/constants"
 
18
 
19
  export function VideoUpscalingModelList({
20
  provider,
@@ -40,7 +41,13 @@ export function VideoUpscalingModelList({
40
  <MenubarCheckboxItem
41
  key={model}
42
  checked={current === model}
 
43
  onClick={(e) => {
 
 
 
 
 
44
  setter(model)
45
  e.stopPropagation()
46
  e.preventDefault()
 
15
  import { Tag } from "@/components/tags/Tag"
16
  import { ComputeProvider } from "@/types"
17
  import { availableModelsForVideoUpscaling } from "@/components/settings/constants"
18
+ import { hasNoPublicAPI } from "./hasNoPublicAPI"
19
 
20
  export function VideoUpscalingModelList({
21
  provider,
 
41
  <MenubarCheckboxItem
42
  key={model}
43
  checked={current === model}
44
+ disabled={hasNoPublicAPI(model)}
45
  onClick={(e) => {
46
+ if (hasNoPublicAPI(model)) {
47
+ e.stopPropagation()
48
+ e.preventDefault()
49
+ return false
50
+ }
51
  setter(model)
52
  e.stopPropagation()
53
  e.preventDefault()
src/components/toolbars/top-menu/lists/VoiceGenerationModelList.tsx CHANGED
@@ -15,6 +15,7 @@ import { TagColor } from "@/components/tags/types"
15
  import { Tag } from "@/components/tags/Tag"
16
  import { ComputeProvider } from "@/types"
17
  import { availableModelsForVoiceGeneration } from "@/components/settings/constants"
 
18
 
19
  export function VoiceGenerationModelList({
20
  provider,
@@ -40,7 +41,13 @@ export function VoiceGenerationModelList({
40
  <MenubarCheckboxItem
41
  key={model}
42
  checked={current === model}
 
43
  onClick={(e) => {
 
 
 
 
 
44
  setter(model)
45
  e.stopPropagation()
46
  e.preventDefault()
 
15
  import { Tag } from "@/components/tags/Tag"
16
  import { ComputeProvider } from "@/types"
17
  import { availableModelsForVoiceGeneration } from "@/components/settings/constants"
18
+ import { hasNoPublicAPI } from "./hasNoPublicAPI"
19
 
20
  export function VoiceGenerationModelList({
21
  provider,
 
41
  <MenubarCheckboxItem
42
  key={model}
43
  checked={current === model}
44
+ disabled={hasNoPublicAPI(model)}
45
  onClick={(e) => {
46
+ if (hasNoPublicAPI(model)) {
47
+ e.stopPropagation()
48
+ e.preventDefault()
49
+ return false
50
+ }
51
  setter(model)
52
  e.stopPropagation()
53
  e.preventDefault()
src/components/toolbars/top-menu/lists/hasNoPublicAPI.ts ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { ComputeProvider } from "@/types"
2
+
3
+ export function hasNoPublicAPI(model: string) {
4
+ model = model.toLowerCase()
5
+ if (
6
+ model.includes("no public api") ||
7
+ model.includes("no api") ||
8
+ model.includes("not available") ||
9
+ model.includes("no image api") ||
10
+ model.includes("no video api") ||
11
+ model.includes("no music api") ||
12
+ model.includes("no sound api") ||
13
+ model.includes("no voice api") ||
14
+ model.includes("unavailable") ||
15
+ model === ComputeProvider.SUNO ||
16
+ model === ComputeProvider.KUAISHOU ||
17
+ model === ComputeProvider.RUNWAYML ||
18
+ model === ComputeProvider.LUMALABS ||
19
+ model === ComputeProvider.UDIO
20
+ ) {
21
+ return true
22
+ }
23
+ return false
24
+ }
src/components/toolbars/top-menu/music/index.tsx CHANGED
@@ -17,7 +17,7 @@ import { useUI } from "@/controllers/ui"
17
  import { ProviderList } from "../lists/ProviderList"
18
  import { RenderingStrategyList } from "../lists/RenderingStrategyList"
19
  import { availableComputeProvidersForMusic } from "@/components/settings/constants"
20
- import { SettingsCategory } from "@/types"
21
  import { MusicGenerationModelList } from "../lists/MusicGenerationModelList"
22
 
23
  export function TopMenuMusic() {
@@ -37,7 +37,11 @@ export function TopMenuMusic() {
37
  <MenubarItem onClick={() => { setShowSettings(SettingsCategory.MUSIC) }}>Show advanced settings</MenubarItem>
38
  <MenubarSeparator />
39
  <MusicGenerationModelList provider={musicProvider} current={musicGenerationModel} setter={setMusicGenerationModel} />
40
- <ProviderList providers={availableComputeProvidersForMusic} current={musicProvider} setter={setMusicProvider} />
 
 
 
 
41
  <RenderingStrategyList current={musicRenderingStrategy} setter={setMusicRenderingStrategy} />
42
  <MenubarSeparator />
43
  <MenubarItem
 
17
  import { ProviderList } from "../lists/ProviderList"
18
  import { RenderingStrategyList } from "../lists/RenderingStrategyList"
19
  import { availableComputeProvidersForMusic } from "@/components/settings/constants"
20
+ import { ComputeProvider, SettingsCategory } from "@/types"
21
  import { MusicGenerationModelList } from "../lists/MusicGenerationModelList"
22
 
23
  export function TopMenuMusic() {
 
37
  <MenubarItem onClick={() => { setShowSettings(SettingsCategory.MUSIC) }}>Show advanced settings</MenubarItem>
38
  <MenubarSeparator />
39
  <MusicGenerationModelList provider={musicProvider} current={musicGenerationModel} setter={setMusicGenerationModel} />
40
+ <ProviderList providers={availableComputeProvidersForMusic} current={musicProvider} setter={(newProvider: ComputeProvider) => {
41
+ if (musicProvider === newProvider) { return }
42
+ setMusicProvider(newProvider)
43
+ setMusicGenerationModel(undefined)
44
+ }} />
45
  <RenderingStrategyList current={musicRenderingStrategy} setter={setMusicRenderingStrategy} />
46
  <MenubarSeparator />
47
  <MenubarItem
src/components/toolbars/top-menu/sound/index.tsx CHANGED
@@ -17,7 +17,7 @@ import { useUI } from "@/controllers/ui"
17
  import { ProviderList } from "../lists/ProviderList"
18
  import { RenderingStrategyList } from "../lists/RenderingStrategyList"
19
  import { availableComputeProvidersForSound } from "@/components/settings/constants"
20
- import { SettingsCategory } from "@/types"
21
  import { SoundGenerationModelList } from "../lists/SoundGenerationModelList"
22
 
23
  export function TopMenuSound() {
@@ -36,7 +36,11 @@ export function TopMenuSound() {
36
  <MenubarItem onClick={() => { setShowSettings(SettingsCategory.SOUND) }}>Show advanced settings</MenubarItem>
37
  <MenubarSeparator />
38
  <SoundGenerationModelList provider={soundProvider} current={soundGenerationModel} setter={setSoundGenerationModel} />
39
- <ProviderList providers={availableComputeProvidersForSound} current={soundProvider} setter={setSoundProvider} />
 
 
 
 
40
  <RenderingStrategyList current={soundRenderingStrategy} setter={setSoundRenderingStrategy} />
41
  <MenubarSeparator />
42
  <MenubarItem
 
17
  import { ProviderList } from "../lists/ProviderList"
18
  import { RenderingStrategyList } from "../lists/RenderingStrategyList"
19
  import { availableComputeProvidersForSound } from "@/components/settings/constants"
20
+ import { ComputeProvider, SettingsCategory } from "@/types"
21
  import { SoundGenerationModelList } from "../lists/SoundGenerationModelList"
22
 
23
  export function TopMenuSound() {
 
36
  <MenubarItem onClick={() => { setShowSettings(SettingsCategory.SOUND) }}>Show advanced settings</MenubarItem>
37
  <MenubarSeparator />
38
  <SoundGenerationModelList provider={soundProvider} current={soundGenerationModel} setter={setSoundGenerationModel} />
39
+ <ProviderList providers={availableComputeProvidersForSound} current={soundProvider} setter={(newProvider: ComputeProvider) => {
40
+ if (soundProvider === newProvider) { return }
41
+ setSoundProvider(newProvider)
42
+ setSoundGenerationModel(undefined)
43
+ }} />
44
  <RenderingStrategyList current={soundRenderingStrategy} setter={setSoundRenderingStrategy} />
45
  <MenubarSeparator />
46
  <MenubarItem
src/components/toolbars/top-menu/video/index.tsx CHANGED
@@ -19,7 +19,7 @@ import { RenderingStrategyList } from "../lists/RenderingStrategyList"
19
  import { availableComputeProvidersForVideos } from "@/components/settings/constants"
20
  import { VideoGenerationModelList } from "../lists/VideoGenerationModelList"
21
  import { VideoUpscalingModelList } from "../lists/VideoUpscalingModelList"
22
- import { SettingsCategory } from "@/types"
23
 
24
  export function TopMenuVideo() {
25
  const setShowSettings = useUI(s => s.setShowSettings)
@@ -40,7 +40,12 @@ export function TopMenuVideo() {
40
  <MenubarSeparator />
41
  <VideoGenerationModelList provider={videoProvider} current={videoGenerationModel} setter={setVideoGenerationModel} />
42
  <VideoUpscalingModelList provider={videoProvider} current={videoUpscalingModel} setter={setVideoUpscalingModel} />
43
- <ProviderList providers={availableComputeProvidersForVideos} current={videoProvider} setter={setVideoProvider} />
 
 
 
 
 
44
  <RenderingStrategyList current={videoRenderingStrategy} setter={setVideoRenderingStrategy} />
45
  <MenubarSeparator />
46
  <MenubarItem
 
19
  import { availableComputeProvidersForVideos } from "@/components/settings/constants"
20
  import { VideoGenerationModelList } from "../lists/VideoGenerationModelList"
21
  import { VideoUpscalingModelList } from "../lists/VideoUpscalingModelList"
22
+ import { ComputeProvider, SettingsCategory } from "@/types"
23
 
24
  export function TopMenuVideo() {
25
  const setShowSettings = useUI(s => s.setShowSettings)
 
40
  <MenubarSeparator />
41
  <VideoGenerationModelList provider={videoProvider} current={videoGenerationModel} setter={setVideoGenerationModel} />
42
  <VideoUpscalingModelList provider={videoProvider} current={videoUpscalingModel} setter={setVideoUpscalingModel} />
43
+ <ProviderList providers={availableComputeProvidersForVideos} current={videoProvider} setter={(newProvider: ComputeProvider) => {
44
+ if (videoProvider === newProvider) { return }
45
+ setVideoProvider(newProvider)
46
+ setVideoGenerationModel(undefined)
47
+ setVideoUpscalingModel(undefined)
48
+ }} />
49
  <RenderingStrategyList current={videoRenderingStrategy} setter={setVideoRenderingStrategy} />
50
  <MenubarSeparator />
51
  <MenubarItem
src/components/toolbars/top-menu/view/index.tsx CHANGED
@@ -78,14 +78,18 @@ export function TopMenuView() {
78
  }}
79
  >Show asset explorer</MenubarCheckboxItem>
80
  */}
 
81
  <MenubarCheckboxItem
82
  checked={showChat}
 
 
83
  onClick={(e) => {
84
  setShowChat(!showChat)
85
  e.stopPropagation()
86
  e.preventDefault()
87
  return false
88
  }}
 
89
  >Show chat assistant</MenubarCheckboxItem>
90
  {/*
91
  <MenubarCheckboxItem
 
78
  }}
79
  >Show asset explorer</MenubarCheckboxItem>
80
  */}
81
+
82
  <MenubarCheckboxItem
83
  checked={showChat}
84
+ disabled
85
+ /*
86
  onClick={(e) => {
87
  setShowChat(!showChat)
88
  e.stopPropagation()
89
  e.preventDefault()
90
  return false
91
  }}
92
+ */
93
  >Show chat assistant</MenubarCheckboxItem>
94
  {/*
95
  <MenubarCheckboxItem
src/components/toolbars/top-menu/voice/index.tsx CHANGED
@@ -18,7 +18,7 @@ import { ProviderList } from "../lists/ProviderList"
18
  import { RenderingStrategyList } from "../lists/RenderingStrategyList"
19
  import { availableComputeProvidersForVoice } from "@/components/settings/constants"
20
  import { VoiceGenerationModelList } from "../lists/VoiceGenerationModelList"
21
- import { SettingsCategory } from "@/types"
22
 
23
  export function TopMenuVoice() {
24
  const setShowSettings = useUI(s => s.setShowSettings)
@@ -36,7 +36,11 @@ export function TopMenuVoice() {
36
  <MenubarItem onClick={() => { setShowSettings(SettingsCategory.VOICE) }}>Show advanced settings</MenubarItem>
37
  <MenubarSeparator />
38
  <VoiceGenerationModelList provider={voiceProvider} current={voiceGenerationModel} setter={setVoiceGenerationModel} />
39
- <ProviderList providers={availableComputeProvidersForVoice} current={voiceProvider} setter={setVoiceProvider} />
 
 
 
 
40
  <RenderingStrategyList current={voiceRenderingStrategy} setter={setVoiceRenderingStrategy} />
41
  <MenubarSeparator />
42
  <MenubarItem
 
18
  import { RenderingStrategyList } from "../lists/RenderingStrategyList"
19
  import { availableComputeProvidersForVoice } from "@/components/settings/constants"
20
  import { VoiceGenerationModelList } from "../lists/VoiceGenerationModelList"
21
+ import { ComputeProvider, SettingsCategory } from "@/types"
22
 
23
  export function TopMenuVoice() {
24
  const setShowSettings = useUI(s => s.setShowSettings)
 
36
  <MenubarItem onClick={() => { setShowSettings(SettingsCategory.VOICE) }}>Show advanced settings</MenubarItem>
37
  <MenubarSeparator />
38
  <VoiceGenerationModelList provider={voiceProvider} current={voiceGenerationModel} setter={setVoiceGenerationModel} />
39
+ <ProviderList providers={availableComputeProvidersForVoice} current={voiceProvider} setter={(newProvider: ComputeProvider) => {
40
+ if (voiceProvider === newProvider) { return }
41
+ setVoiceProvider(newProvider)
42
+ setVoiceGenerationModel(undefined)
43
+ }} />
44
  <RenderingStrategyList current={voiceRenderingStrategy} setter={setVoiceRenderingStrategy} />
45
  <MenubarSeparator />
46
  <MenubarItem
src/controllers/io/parseFileName.ts ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ export function parseFileName(input: any): {
2
+ projectName: string,
3
+ fileName: string,
4
+ extension: string
5
+ } {
6
+ const fileName = `${input || ""}`
7
+ const bits = fileName.split(".")
8
+ const extension = `${bits.pop() || ""}`.toLowerCase()
9
+ const projectName = bits.join(" ")
10
+
11
+ return {
12
+ projectName,
13
+ fileName,
14
+ extension
15
+ }
16
+ }
src/controllers/io/types.ts CHANGED
@@ -30,10 +30,16 @@ export type IOState = {
30
  }
31
 
32
  export type IOControls = {
 
 
 
33
  openFiles: (files: File[]) => Promise<void>
34
 
 
 
35
  saveAnyFile: (blob: Blob, fileName: string) => void
36
  openClapUrl: (url: string) => Promise<void>
 
37
  saveClap: () => Promise<void>
38
  saveVideoFile: () => Promise<void>
39
 
 
30
  }
31
 
32
  export type IOControls = {
33
+
34
+ clear: () => void
35
+
36
  openFiles: (files: File[]) => Promise<void>
37
 
38
+ openScreenplay: (projectName: string, fileName: string, fileContent: string | Blob) => Promise<void>
39
+
40
  saveAnyFile: (blob: Blob, fileName: string) => void
41
  openClapUrl: (url: string) => Promise<void>
42
+ openClapBlob: (projectName: string, fileName: string, blob: Blob) => Promise<void>
43
  saveClap: () => Promise<void>
44
  saveVideoFile: () => Promise<void>
45
 
src/controllers/io/useIO.ts CHANGED
@@ -1,7 +1,7 @@
1
  "use client"
2
 
3
- import { ClapProject, ClapSegment, ClapSegmentCategory, ClapSegmentFilteringMode, ClapSegmentStatus, filterSegments, getClapAssetSourceType, newSegment, parseClap, serializeClap } from "@aitube/clap"
4
- import { Track, Tracks, useTimeline } from "@aitube/timeline"
5
  import { create } from "zustand"
6
  import { mltToXml } from "mlt-xml"
7
 
@@ -10,6 +10,10 @@ import { IOStore } from "./types"
10
 
11
  import { blobToBase64DataUri } from "@/lib/utils/blobToBase64DataUri"
12
  import { parseFileIntoSegments } from "./parseFileIntoSegments"
 
 
 
 
13
  // import { Entry, Project } from "@/lib/kdenlive"
14
  // import { formatDuration } from "@/lib/utils/formatDuration"
15
 
@@ -17,24 +21,47 @@ import { parseFileIntoSegments } from "./parseFileIntoSegments"
17
  export const useIO = create<IOStore>((set, get) => ({
18
  ...getDefaultIOState(),
19
 
 
 
 
 
 
 
 
 
20
  openFiles: async (files: File[]) => {
 
21
  const segments: ClapSegment[] = useTimeline.getState().segments
22
-
23
- console.log("File", File)
24
- if (Array.isArray(File)) {
25
- console.log("user tried to drop some files:", File)
26
 
27
  // for now let's simplify things, and only import the first file
28
- const file = File.at(0)
29
  if (!file) { return }
30
 
31
- console.log(`file type: ${file.type}`)
 
 
 
 
 
 
 
32
 
33
- const isClapFile = file.name.endsWith(".clap")
34
- const isAudioFile = file.type.startsWith("audio/")
35
- const isVideoFile = file.type.startsWith("video/")
36
- const isTextFile = file.type.startsWith("text/")
 
 
 
 
 
 
37
 
 
 
38
  // TODO: detect the type of file, and do a different treatment based on this
39
  // screenplay files: -> analyze (if there is existing data, show a modal asking to save or not)
40
  // mp3 file: ->
@@ -45,6 +72,9 @@ export const useIO = create<IOStore>((set, get) => ({
45
  })
46
  }
47
 
 
 
 
48
  // for the moment let's not care of the coordinates at all
49
  /*
50
  parseFilesIntoSegments({
@@ -57,6 +87,60 @@ export const useIO = create<IOStore>((set, get) => ({
57
  */
58
  }
59
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
  saveAnyFile: (blob: Blob, fileName: string) => {
61
  // Create an object URL for the compressed clap blob
62
  // object urls are short-lived urls, with the benefit of having a short id too
@@ -76,12 +160,82 @@ export const useIO = create<IOStore>((set, get) => ({
76
  URL.revokeObjectURL(objectUrl)
77
  document.body.removeChild(anchor)
78
  },
 
79
  openClapUrl: async (url: string) => {
80
- const { setClap } = useTimeline.getState()
81
- const res = await fetch(url)
82
- const blob = await res.blob()
83
- const clap = await parseClap(blob)
84
- await setClap(clap)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85
  },
86
  saveClap: async () => {
87
  const { saveAnyFile } = get()
@@ -89,6 +243,18 @@ export const useIO = create<IOStore>((set, get) => ({
89
 
90
  if (!clap) { throw new Error(`cannot save a clap.. if there is no clap`) }
91
 
 
 
 
 
 
 
 
 
 
 
 
 
92
  // make sure we update the total duration
93
  for (const s of clap.segments) {
94
  if (s.endTimeInMs > clap.meta.durationInMs) {
@@ -96,8 +262,15 @@ export const useIO = create<IOStore>((set, get) => ({
96
  }
97
  }
98
 
 
 
 
 
 
99
  const blob: Blob = await serializeClap(clap)
100
- saveAnyFile(blob, `my_project.clap`)
 
 
101
  },
102
 
103
  saveVideoFile: async () => {
 
1
  "use client"
2
 
3
+ import { ClapProject, ClapSegment, ClapSegmentCategory, ClapSegmentStatus, getClapAssetSourceType, newSegment, parseClap, serializeClap } from "@aitube/clap"
4
+ import { TimelineStore, useTimeline } from "@aitube/timeline"
5
  import { create } from "zustand"
6
  import { mltToXml } from "mlt-xml"
7
 
 
10
 
11
  import { blobToBase64DataUri } from "@/lib/utils/blobToBase64DataUri"
12
  import { parseFileIntoSegments } from "./parseFileIntoSegments"
13
+ import { useTasks } from "@/components/tasks/useTasks"
14
+ import { Task, TaskCategory, TaskVisibility } from "@/components/tasks/types"
15
+ import { parseFileName } from "./parseFileName"
16
+ import { useRenderer } from "../renderer"
17
  // import { Entry, Project } from "@/lib/kdenlive"
18
  // import { formatDuration } from "@/lib/utils/formatDuration"
19
 
 
21
  export const useIO = create<IOStore>((set, get) => ({
22
  ...getDefaultIOState(),
23
 
24
+ clear: () => {
25
+ const renderer = useRenderer.getState()
26
+ const timeline: TimelineStore = useTimeline.getState()
27
+
28
+ // reset various things
29
+ renderer.clear()
30
+ timeline.clear()
31
+ },
32
  openFiles: async (files: File[]) => {
33
+ const { openClapBlob, openScreenplay } = get()
34
  const segments: ClapSegment[] = useTimeline.getState().segments
35
+
36
+ if (Array.isArray(files)) {
37
+ console.log("user tried to drop some files:", files)
 
38
 
39
  // for now let's simplify things, and only import the first file
40
+ const file: File | undefined = files.at(0)
41
  if (!file) { return }
42
 
43
+ const input = `${file.name || ""}`
44
+ const { fileName, projectName, extension } = parseFileName(input)
45
+
46
+ const fileType = `${file.type || ""}`
47
+
48
+ console.log(`file type: ${fileType}`)
49
+
50
+ const isClapFile = extension === "clap"
51
 
52
+ if (isClapFile) {
53
+ await openClapBlob(projectName, fileName, file)
54
+ return
55
+ }
56
+
57
+ const isTextFile = fileType.startsWith("text/")
58
+ if (isTextFile) {
59
+ await openScreenplay(projectName, fileName, file)
60
+ return
61
+ }
62
 
63
+ const isAudioFile = fileType.startsWith("audio/")
64
+
65
  // TODO: detect the type of file, and do a different treatment based on this
66
  // screenplay files: -> analyze (if there is existing data, show a modal asking to save or not)
67
  // mp3 file: ->
 
72
  })
73
  }
74
 
75
+ const isVideoFile = fileType.startsWith("video/")
76
+
77
+
78
  // for the moment let's not care of the coordinates at all
79
  /*
80
  parseFilesIntoSegments({
 
87
  */
88
  }
89
  },
90
+ openScreenplay: async (projectName: string, fileName: string, fileContent: string | Blob): Promise<void> => {
91
+ const plainText =
92
+ typeof fileContent === "string"
93
+ ? fileContent :
94
+ (await new Response(fileContent).text())
95
+
96
+ const timeline: TimelineStore = useTimeline.getState()
97
+ const task = useTasks.getState().add({
98
+ category: TaskCategory.IMPORT,
99
+ visibility: TaskVisibility.BLOCKER,
100
+ initialMessage: `Loading ${fileName}`,
101
+ successMessage: `Successfully loaded the screenplay!`,
102
+ value: 0,
103
+ })
104
+ task.setProgress({
105
+ message: "Analyzing screenplay..",
106
+ value: 10
107
+ })
108
+ try {
109
+ const res = await fetch("https://jbilcke-hf-broadway-api.hf.space", {
110
+ method: "POST",
111
+ headers: { 'Content-Type': 'text/plain' },
112
+ body: plainText,
113
+ })
114
+ const blob = await res.blob()
115
+ task.setProgress({
116
+ message: "Loading scenes..",
117
+ value: 50
118
+ })
119
+ // TODO: parseClap should feature a progress callback
120
+ const clap = await parseClap(blob)
121
+
122
+ clap.meta.title = `${projectName || ""}`
123
+
124
+ task.setProgress({
125
+ message: "Loading rendering engine..",
126
+ value: 70
127
+ })
128
+
129
+ await timeline.setClap(clap)
130
+
131
+ task.setProgress({
132
+ message: "Nearly there..",
133
+ value: 95
134
+ })
135
+
136
+ task.success()
137
+ } catch (err) {
138
+ console.error("failed to import the screenplay:", err)
139
+ task.fail(`${err || "unknown screenplay import error"}`)
140
+ } finally {
141
+
142
+ }
143
+ },
144
  saveAnyFile: (blob: Blob, fileName: string) => {
145
  // Create an object URL for the compressed clap blob
146
  // object urls are short-lived urls, with the benefit of having a short id too
 
160
  URL.revokeObjectURL(objectUrl)
161
  document.body.removeChild(anchor)
162
  },
163
+
164
  openClapUrl: async (url: string) => {
165
+ const timeline: TimelineStore = useTimeline.getState()
166
+ const { setClap } = timeline
167
+
168
+ const { fileName, projectName } = parseFileName(`${url.split("/").pop() || url}`)
169
+
170
+ const task = useTasks.getState().add({
171
+ category: TaskCategory.IMPORT,
172
+ visibility: TaskVisibility.BLOCKER,
173
+ initialMessage: `Loading ${fileName}`,
174
+ successMessage: `Successfully downloaded the project!`,
175
+ value: 0,
176
+ })
177
+
178
+ task.setProgress({
179
+ message: "Downloading file..",
180
+ value: 10
181
+ })
182
+
183
+ try {
184
+ const res = await fetch(url)
185
+ const blob = await res.blob()
186
+
187
+ task.setProgress({
188
+ message: "Loading scenes..",
189
+ value: 30
190
+ })
191
+
192
+ const clap = await parseClap(blob)
193
+ clap.meta.title = `${projectName}`
194
+
195
+ task.setProgress({
196
+ message: "Loading rendering engine..",
197
+ value: 70
198
+ })
199
+
200
+ await setClap(clap)
201
+
202
+ task.success()
203
+ } catch (err) {
204
+ task.fail(`${err || "unknown error"}`)
205
+ }
206
+ },
207
+ openClapBlob: async (projectName: string, fileName: string, blob: Blob) => {
208
+ const timeline: TimelineStore = useTimeline.getState()
209
+ const { setClap } = timeline
210
+
211
+ const task = useTasks.getState().add({
212
+ category: TaskCategory.IMPORT,
213
+ visibility: TaskVisibility.BLOCKER,
214
+ initialMessage: `Loading ${fileName}`,
215
+ successMessage: `Successfully loaded the project!`,
216
+ value: 0,
217
+ })
218
+ try {
219
+
220
+ task.setProgress({
221
+ message: "Loading scenes..",
222
+ value: 30
223
+ })
224
+
225
+ const clap = await parseClap(blob)
226
+ clap.meta.title = `${projectName}`
227
+
228
+ task.setProgress({
229
+ message: "Loading rendering engine..",
230
+ value: 70
231
+ })
232
+
233
+ await setClap(clap)
234
+
235
+ task.success()
236
+ } catch (err) {
237
+ task.fail(`${err || "unknown error"}`)
238
+ }
239
  },
240
  saveClap: async () => {
241
  const { saveAnyFile } = get()
 
243
 
244
  if (!clap) { throw new Error(`cannot save a clap.. if there is no clap`) }
245
 
246
+ const tasks = useTasks.getState()
247
+
248
+ const task = tasks.add({
249
+ category: TaskCategory.EXPORT,
250
+ visibility: TaskVisibility.BLOCKER,
251
+ initialMessage: `Exporting project to OpenClap..`,
252
+ successMessage: `Successfully exported the project!`
253
+ // mode: "percentage", // default
254
+ // min: 0, // default
255
+ // max: 100 // default
256
+ })
257
+
258
  // make sure we update the total duration
259
  for (const s of clap.segments) {
260
  if (s.endTimeInMs > clap.meta.durationInMs) {
 
262
  }
263
  }
264
 
265
+ // TODO: serializeClap should have a progress callback, so that we can
266
+ // track the progression.
267
+ //
268
+ // also, I'm 100% aware that at some point we will just want to use the
269
+ // desktop version of Clapper, so that we can write the gzip stream directly to the disk
270
  const blob: Blob = await serializeClap(clap)
271
+ saveAnyFile(blob, `my_project.clap`) // <-- TODO use the project filename
272
+
273
+ task.success()
274
  },
275
 
276
  saveVideoFile: async () => {
src/controllers/metrics/constants.ts CHANGED
@@ -101,4 +101,22 @@ export const estimatedMetrics: Record<ComputeProvider, Record<string, ProviderMe
101
  [ComputeProvider.MODELSLAB]: {
102
  // TODO list the most popular models
103
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
104
  }
 
101
  [ComputeProvider.MODELSLAB]: {
102
  // TODO list the most popular models
103
  },
104
+ [ComputeProvider.MIDJOURNEY]: {
105
+ // TODO list the most popular models
106
+ },
107
+ [ComputeProvider.SUNO]: {
108
+ // TODO list the most popular models
109
+ },
110
+ [ComputeProvider.UDIO]: {
111
+ // TODO list the most popular models
112
+ },
113
+ [ComputeProvider.LUMALABS]: {
114
+ // TODO list the most popular models
115
+ },
116
+ [ComputeProvider.KUAISHOU]: {
117
+ // TODO list the most popular models
118
+ },
119
+ [ComputeProvider.RUNWAYML]: {
120
+ // TODO list the most popular models
121
+ },
122
  }
src/controllers/metrics/getDefaultMetricsPerProvider.ts CHANGED
@@ -62,6 +62,24 @@ export function getDefaultMetricsPerProvider(): MetricsPerProvider {
62
  [ComputeProvider.COHERE]: {
63
  ...getDefaultComputeProviderMetrics(),
64
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65
  }
66
  return metricsPerProvider
67
  }
 
62
  [ComputeProvider.COHERE]: {
63
  ...getDefaultComputeProviderMetrics(),
64
  },
65
+ [ComputeProvider.MIDJOURNEY]: {
66
+ ...getDefaultComputeProviderMetrics(),
67
+ },
68
+ [ComputeProvider.SUNO]: {
69
+ ...getDefaultComputeProviderMetrics(),
70
+ },
71
+ [ComputeProvider.UDIO]: {
72
+ ...getDefaultComputeProviderMetrics(),
73
+ },
74
+ [ComputeProvider.LUMALABS]: {
75
+ ...getDefaultComputeProviderMetrics(),
76
+ },
77
+ [ComputeProvider.KUAISHOU]: {
78
+ ...getDefaultComputeProviderMetrics(),
79
+ },
80
+ [ComputeProvider.RUNWAYML]: {
81
+ ...getDefaultComputeProviderMetrics(),
82
+ },
83
  }
84
  return metricsPerProvider
85
  }
src/controllers/monitor/useMonitor.ts CHANGED
@@ -8,6 +8,7 @@ import { useTimeline } from "@aitube/timeline"
8
  import { useAudio } from "../audio/useAudio"
9
  import { MonitoringMode, MonitorStore } from "./types"
10
  import { getDefaultMonitorState } from "./getDefaultMonitorState"
 
11
 
12
  export const useMonitor = create<MonitorStore>((set, get) => ({
13
  ...getDefaultMonitorState(),
@@ -108,20 +109,24 @@ export const useMonitor = create<MonitorStore>((set, get) => ({
108
  jumpAt: (timeInMs: number = 0) => {
109
  const { isPlaying, mode, staticVideoRef } = get()
110
 
 
111
  const { setCursorTimestampAtInMs } = useTimeline.getState()
112
 
113
  setCursorTimestampAtInMs(timeInMs)
114
 
115
- if (mode === MonitoringMode.NONE || !staticVideoRef) {
116
  return
117
  }
118
 
119
  if (mode === MonitoringMode.STATIC) {
 
 
 
120
  // console.log("resetting static video current time")
121
  staticVideoRef.currentTime = timeInMs / 1000
122
  } else if (mode === MonitoringMode.DYNAMIC) {
123
- // console.log(`TODO Julian: implement jump`)
124
- // for audio I think it will be automatic
125
  }
126
  },
127
 
 
8
  import { useAudio } from "../audio/useAudio"
9
  import { MonitoringMode, MonitorStore } from "./types"
10
  import { getDefaultMonitorState } from "./getDefaultMonitorState"
11
+ import { useRenderer } from "../renderer"
12
 
13
  export const useMonitor = create<MonitorStore>((set, get) => ({
14
  ...getDefaultMonitorState(),
 
109
  jumpAt: (timeInMs: number = 0) => {
110
  const { isPlaying, mode, staticVideoRef } = get()
111
 
112
+ const { renderLoop } = useRenderer.getState()
113
  const { setCursorTimestampAtInMs } = useTimeline.getState()
114
 
115
  setCursorTimestampAtInMs(timeInMs)
116
 
117
+ if (mode === MonitoringMode.NONE) {
118
  return
119
  }
120
 
121
  if (mode === MonitoringMode.STATIC) {
122
+ if (!staticVideoRef) {
123
+ return
124
+ }
125
  // console.log("resetting static video current time")
126
  staticVideoRef.currentTime = timeInMs / 1000
127
  } else if (mode === MonitoringMode.DYNAMIC) {
128
+ // we force a state update
129
+ renderLoop()
130
  }
131
  },
132
 
src/controllers/renderer/types.ts CHANGED
@@ -23,6 +23,10 @@ export type RendererState = {
23
  }
24
 
25
  export type RendererControls = {
 
 
 
 
26
  // this will be called at 60 FPS - and yes, it is expensive
27
  // we could probably improve things by using a temporal tree index
28
 
 
23
  }
24
 
25
  export type RendererControls = {
26
+
27
+ // used to clear the renderer eg. when we load a new project
28
+ clear: () => void
29
+
30
  // this will be called at 60 FPS - and yes, it is expensive
31
  // we could probably improve things by using a temporal tree index
32
 
src/controllers/renderer/useRenderLoop.ts CHANGED
@@ -3,6 +3,7 @@ import { useRenderer } from "./useRenderer"
3
  import { useAudio } from "@/controllers/audio/useAudio"
4
  import { useMonitor } from "../monitor/useMonitor"
5
 
 
6
  /**
7
  * Runs a rendering loop
8
  *
 
3
  import { useAudio } from "@/controllers/audio/useAudio"
4
  import { useMonitor } from "../monitor/useMonitor"
5
 
6
+ let globalState = { isInstalled: false }
7
  /**
8
  * Runs a rendering loop
9
  *
src/controllers/renderer/useRenderer.ts CHANGED
@@ -15,6 +15,11 @@ import { getDefaultBufferedSegments } from "./getDefaultBufferedSegments"
15
  export const useRenderer = create<RendererStore>((set, get) => ({
16
  ...getDefaultRendererState(),
17
 
 
 
 
 
 
18
 
19
  // this will be called at 60 FPS - and yes, it is expensive
20
  // we could probably improve things by using a temporal tree index
 
15
  export const useRenderer = create<RendererStore>((set, get) => ({
16
  ...getDefaultRendererState(),
17
 
18
+ clear: () => {
19
+ set({
20
+ ...getDefaultRendererState(),
21
+ })
22
+ },
23
 
24
  // this will be called at 60 FPS - and yes, it is expensive
25
  // we could probably improve things by using a temporal tree index
src/controllers/resolver/useResolver.ts CHANGED
@@ -266,12 +266,12 @@ export const useResolver = create<ResolverStore>((set, get) => ({
266
 
267
  const settings = useSettings.getState().getSettings()
268
 
269
- const timelineState: TimelineStore = useTimeline.getState()
270
 
271
  // note: do NOT use the visibleSegments here
272
  // that's because resolveSegment is 100% asynchronous,
273
  // meaning it might be called on invisible segments too!
274
- const { clap, segments: allSegments } = timelineState
275
 
276
  if (!clap?.meta || !allSegments.length) {
277
  return segment
@@ -349,17 +349,15 @@ export const useResolver = create<ResolverStore>((set, get) => ({
349
  status
350
  })
351
 
352
-
 
353
  return newSegment
354
  } catch (err) {
355
  console.error(`useResolver.resolveSegment(): error: ${err}`)
356
-
357
  // we could do that in a future version to improve error tracking
358
  // segment.status = ClapSegmentStatus.ERROR
359
- } finally {
360
- segment.status = ClapSegmentStatus.COMPLETED
361
  }
362
-
363
  return segment
364
  }
365
 
 
266
 
267
  const settings = useSettings.getState().getSettings()
268
 
269
+ const timeline: TimelineStore = useTimeline.getState()
270
 
271
  // note: do NOT use the visibleSegments here
272
  // that's because resolveSegment is 100% asynchronous,
273
  // meaning it might be called on invisible segments too!
274
+ const { clap, segments: allSegments, trackSilentChangeInSegment } = timeline
275
 
276
  if (!clap?.meta || !allSegments.length) {
277
  return segment
 
349
  status
350
  })
351
 
352
+ newSegment.status = ClapSegmentStatus.COMPLETED
353
+ trackSilentChangeInSegment(newSegment.id)
354
  return newSegment
355
  } catch (err) {
356
  console.error(`useResolver.resolveSegment(): error: ${err}`)
357
+ segment.status = ClapSegmentStatus.TO_GENERATE
358
  // we could do that in a future version to improve error tracking
359
  // segment.status = ClapSegmentStatus.ERROR
 
 
360
  }
 
361
  return segment
362
  }
363
 
src/controllers/settings/getDefaultSettingsState.ts CHANGED
@@ -23,6 +23,7 @@ export function getDefaultSettingsState(): SettingsState {
23
  kitsAiApiKey: "",
24
  cohereApiKey: "",
25
  mistralAiApiKey: "",
 
26
  fireworksAiApiKey: "",
27
 
28
  assistantProvider: ComputeProvider.NONE,
@@ -36,10 +37,10 @@ export function getDefaultSettingsState(): SettingsState {
36
 
37
  imagePromptPrefix: "movie screencap, photo",
38
  imagePromptSuffix: "high quality, beautiful, amazing, intricate details",
39
- imageNegativePrompt: "ugly, imperfect, cropped, low resolution",
40
  videoPromptPrefix: "movie screencap, photo",
41
  videoPromptSuffix: "high quality, beautiful, amazing, intricate details",
42
- videoNegativePrompt: "ugly, imperfect, cropped, low resolution",
43
 
44
  assistantModel: "",
45
  assistantTurboModel: "",
 
23
  kitsAiApiKey: "",
24
  cohereApiKey: "",
25
  mistralAiApiKey: "",
26
+ stabilityAiApiKey: "",
27
  fireworksAiApiKey: "",
28
 
29
  assistantProvider: ComputeProvider.NONE,
 
37
 
38
  imagePromptPrefix: "movie screencap, photo",
39
  imagePromptSuffix: "high quality, beautiful, amazing, intricate details",
40
+ imageNegativePrompt: "black banding, ugly, imperfect, cropped, low resolution",
41
  videoPromptPrefix: "movie screencap, photo",
42
  videoPromptSuffix: "high quality, beautiful, amazing, intricate details",
43
+ videoNegativePrompt: "black banding, ugly, imperfect, cropped, low resolution",
44
 
45
  assistantModel: "",
46
  assistantTurboModel: "",
src/controllers/settings/types.ts CHANGED
@@ -18,6 +18,7 @@ export type SettingsState = {
18
  kitsAiApiKey: string
19
  cohereApiKey: string
20
  mistralAiApiKey: string
 
21
  fireworksAiApiKey: string
22
 
23
  // ------------- CATEGORY PROVIDERS ---------------
@@ -157,6 +158,7 @@ export type SettingsControls = {
157
  setCohereApiKey: (cohereApiKey?: string) => void
158
  setMistralAiApiKey: (mistralAiApiKey?: string) => void
159
  setKitsAiApiKey: (kitsAiApiKey?: string) => void
 
160
 
161
  setAssistantProvider: (assistantProvider?: ComputeProvider) => void
162
  setVideoProvider: (videoProvider?: ComputeProvider) => void
 
18
  kitsAiApiKey: string
19
  cohereApiKey: string
20
  mistralAiApiKey: string
21
+ stabilityAiApiKey: string
22
  fireworksAiApiKey: string
23
 
24
  // ------------- CATEGORY PROVIDERS ---------------
 
158
  setCohereApiKey: (cohereApiKey?: string) => void
159
  setMistralAiApiKey: (mistralAiApiKey?: string) => void
160
  setKitsAiApiKey: (kitsAiApiKey?: string) => void
161
+ setStabilityAiApiKey: (stabilityAiApiKey?: string) => void
162
 
163
  setAssistantProvider: (assistantProvider?: ComputeProvider) => void
164
  setVideoProvider: (videoProvider?: ComputeProvider) => void
src/controllers/settings/useSettings.ts CHANGED
@@ -21,7 +21,7 @@ export const useSettings = create<SettingsStore>()(
21
 
22
  setAssistantProvider: (assistantProvider?: ComputeProvider) => {
23
  const { videoProvider: defaultAssistantProvider } = getDefaultSettingsState()
24
- set({ assistantProvider: parseComputeProvider(assistantProvider, defaultAssistantProvider) })
25
  },
26
  setVideoProvider: (videoProvider?: ComputeProvider) => {
27
  const { videoProvider: defaultVideoProvider } = getDefaultSettingsState()
@@ -96,6 +96,9 @@ export const useSettings = create<SettingsStore>()(
96
  setFireworksAiApiKey: (fireworksAiApiKey?: string) => {
97
  set({ fireworksAiApiKey: getValidString(fireworksAiApiKey, getDefaultSettingsState().fireworksAiApiKey) })
98
  },
 
 
 
99
  setCensorNotForAllAudiencesContent: (censorNotForAllAudiencesContent?: boolean) => {
100
  set({ censorNotForAllAudiencesContent: getValidBoolean(censorNotForAllAudiencesContent, getDefaultSettingsState().censorNotForAllAudiencesContent) })
101
  },
@@ -405,6 +408,7 @@ export const useSettings = create<SettingsStore>()(
405
  mistralAiApiKey: state.mistralAiApiKey || defaultSettings.mistralAiApiKey,
406
  kitsAiApiKey: state.kitsAiApiKey || defaultSettings.kitsAiApiKey,
407
  fireworksAiApiKey: state.fireworksAiApiKey || defaultSettings.fireworksAiApiKey,
 
408
  censorNotForAllAudiencesContent: state.censorNotForAllAudiencesContent || defaultSettings.censorNotForAllAudiencesContent,
409
  imagePromptPrefix: state.imagePromptPrefix || defaultSettings.imagePromptPrefix,
410
  imagePromptSuffix: state.imagePromptSuffix || defaultSettings.imagePromptSuffix,
 
21
 
22
  setAssistantProvider: (assistantProvider?: ComputeProvider) => {
23
  const { videoProvider: defaultAssistantProvider } = getDefaultSettingsState()
24
+ set({assistantProvider: parseComputeProvider(assistantProvider, defaultAssistantProvider) })
25
  },
26
  setVideoProvider: (videoProvider?: ComputeProvider) => {
27
  const { videoProvider: defaultVideoProvider } = getDefaultSettingsState()
 
96
  setFireworksAiApiKey: (fireworksAiApiKey?: string) => {
97
  set({ fireworksAiApiKey: getValidString(fireworksAiApiKey, getDefaultSettingsState().fireworksAiApiKey) })
98
  },
99
+ setStabilityAiApiKey: (stabilityAiApiKey?: string) => {
100
+ set({ stabilityAiApiKey: getValidString(stabilityAiApiKey, getDefaultSettingsState().stabilityAiApiKey) })
101
+ },
102
  setCensorNotForAllAudiencesContent: (censorNotForAllAudiencesContent?: boolean) => {
103
  set({ censorNotForAllAudiencesContent: getValidBoolean(censorNotForAllAudiencesContent, getDefaultSettingsState().censorNotForAllAudiencesContent) })
104
  },
 
408
  mistralAiApiKey: state.mistralAiApiKey || defaultSettings.mistralAiApiKey,
409
  kitsAiApiKey: state.kitsAiApiKey || defaultSettings.kitsAiApiKey,
410
  fireworksAiApiKey: state.fireworksAiApiKey || defaultSettings.fireworksAiApiKey,
411
+ stabilityAiApiKey: state.stabilityAiApiKey || defaultSettings.stabilityAiApiKey,
412
  censorNotForAllAudiencesContent: state.censorNotForAllAudiencesContent || defaultSettings.censorNotForAllAudiencesContent,
413
  imagePromptPrefix: state.imagePromptPrefix || defaultSettings.imagePromptPrefix,
414
  imagePromptSuffix: state.imagePromptSuffix || defaultSettings.imagePromptSuffix,
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 AI"
7
- export const APP_REVISION = "r20240612-0135"
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 AI"
7
+ export const APP_REVISION = "r20240613-1555"
8
 
9
  export const APP_DOMAIN = "Clapper.app"
10
  export const APP_LINK = "https://clapper.app"
src/lib/hooks/index.ts CHANGED
@@ -1,6 +1,5 @@
1
  export { useDebounce } from "./useDebounce"
2
- export { useClapFilePicker } from "./useClapFilePicker"
3
  export { useFullscreenStatus } from "./useFullscreenStatus"
4
  export { useQueryStringParams } from "./useQueryStringParams"
5
  export { useRequestAnimationFrame } from "./useRequestAnimationFrame"
6
- export { useScreenplayFilePicker } from "./useScreenplayFilePicker"
 
1
  export { useDebounce } from "./useDebounce"
2
+ export { useOpenFilePicker } from "./useOpenFilePicker"
3
  export { useFullscreenStatus } from "./useFullscreenStatus"
4
  export { useQueryStringParams } from "./useQueryStringParams"
5
  export { useRequestAnimationFrame } from "./useRequestAnimationFrame"
 
src/lib/hooks/{useClapFilePicker.ts → useOpenFilePicker.ts} RENAMED
@@ -1,15 +1,18 @@
1
- import { useEffect, useState } from "react"
2
  import { useFilePicker } from "use-file-picker"
3
- import { parseClap } from "@aitube/clap"
4
- import { useTimeline } from "@aitube/timeline"
5
 
 
 
6
 
7
- export function useClapFilePicker() {
8
- const setClap = useTimeline(s => s.setClap)
9
  const [isLoading, setIsLoading] = useState(false)
 
 
 
 
10
 
11
  const { openFilePicker, filesContent, loading } = useFilePicker({
12
- accept: '.clap',
13
  readAs: "ArrayBuffer"
14
  })
15
 
@@ -17,12 +20,36 @@ export function useClapFilePicker() {
17
 
18
  useEffect(() => {
19
  const fn = async () => {
20
- if (fileData?.name) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  try {
22
  setIsLoading(true)
23
- const blob = new Blob([fileData.content])
24
- const clap = await parseClap(blob)
25
- await setClap(clap)
26
  } catch (err) {
27
  console.error("failed to load the Clap file:", err)
28
  } finally {
 
1
+ import { useEffect, useState, useTransition } from "react"
2
  import { useFilePicker } from "use-file-picker"
 
 
3
 
4
+ import { parseFileName } from "@/controllers/io/parseFileName"
5
+ import { useIO } from "@/controllers/io/useIO"
6
 
7
+ export function useOpenFilePicker() {
 
8
  const [isLoading, setIsLoading] = useState(false)
9
+ const openClapBlob = useIO(s => s.openClapBlob)
10
+ const openScreenplay = useIO(s => s.openScreenplay)
11
+
12
+ const supportedExtensions = ['clap', 'txt']
13
 
14
  const { openFilePicker, filesContent, loading } = useFilePicker({
15
+ accept: supportedExtensions.map(ext => `.${ext}`),
16
  readAs: "ArrayBuffer"
17
  })
18
 
 
20
 
21
  useEffect(() => {
22
  const fn = async () => {
23
+ const input = `${fileData?.name || ""}`
24
+ if (!input) { return }
25
+
26
+
27
+ const {
28
+ fileName,
29
+ projectName,
30
+ extension
31
+ } = parseFileName(input)
32
+
33
+ if (!supportedExtensions.includes(extension)) {
34
+ console.error(`unsupported extension "${extension}"`)
35
+ return
36
+ }
37
+
38
+ const blob = new Blob([fileData.content])
39
+
40
+ if (extension === "clap") {
41
+ try {
42
+ setIsLoading(true)
43
+ await openClapBlob(projectName, fileName, blob)
44
+ } catch (err) {
45
+ console.error("failed to load the Clap file:", err)
46
+ } finally {
47
+ setIsLoading(false)
48
+ }
49
+ } else if (extension === "txt") {
50
  try {
51
  setIsLoading(true)
52
+ await openScreenplay(projectName, fileName, blob)
 
 
53
  } catch (err) {
54
  console.error("failed to load the Clap file:", err)
55
  } finally {
src/lib/hooks/useScreenplayFilePicker.ts DELETED
@@ -1,41 +0,0 @@
1
- import { useEffect, useState } from "react"
2
- import { useTimeline } from "@aitube/timeline"
3
- import { parseClap } from "@aitube/clap"
4
- import { useFilePicker } from "use-file-picker"
5
-
6
- export function useScreenplayFilePicker() {
7
- const setClap = useTimeline(s => s.setClap)
8
- const [isLoading, setIsLoading] = useState(false)
9
-
10
- const { openFilePicker, filesContent, loading } = useFilePicker({
11
- accept: '.txt',
12
- readAs: "Text"
13
- })
14
-
15
- const fileData = filesContent[0]
16
-
17
- useEffect(() => {
18
- const fn = async () => {
19
- if (fileData?.name) {
20
- try {
21
- setIsLoading(true)
22
- const res = await fetch("https://jbilcke-hf-broadway-api.hf.space", {
23
- method: "POST",
24
- headers: { 'Content-Type': 'text/plain' },
25
- body: fileData.content,
26
- })
27
- const blob = await res.blob()
28
- const clap = await parseClap(blob)
29
- await setClap(clap)
30
- } catch (err) {
31
- console.error("failed to import the screenplay:", err)
32
- } finally {
33
- setIsLoading(false)
34
- }
35
- }
36
- }
37
- fn()
38
- }, [fileData?.name])
39
-
40
- return { openFilePicker, filesContent, fileData, isLoading: loading || isLoading }
41
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/utils/parsePdfToIndentedText.ts ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ // TODO Julian:
2
+ // use pdfjs to parse a PDF, while preserving the indentation
3
+ //
4
+ // this is important, because most tools trim spaces which is..
5
+ // not what I want
6
+ //
7
+ // some references and examples:
8
+ //
9
+ // https://mozilla.github.io/pdf.js/examples/
10
+ // https://github.com/Utkarsh212/react-pdftotext/blob/main/index.ts
src/types.ts CHANGED
@@ -32,6 +32,12 @@ export enum ComputeProvider {
32
  COHERE = "COHERE", // https://cohere.com
33
  FALAI = "FALAI", // https://fal.ai
34
  MODELSLAB = "MODELSLAB", // https://modelslab.com
 
 
 
 
 
 
35
  }
36
 
37
  export enum ComfyIcuAccelerator {
@@ -117,6 +123,7 @@ export type ComfyNode = {
117
  }
118
  }
119
 
 
120
  export enum FalAiImageSize {
121
  SQUARE_HD = "square_hd",
122
  SQUARE = "square",
@@ -126,6 +133,23 @@ export enum FalAiImageSize {
126
  LANDSCAPE_16_9 = "landscape_16_9"
127
  }
128
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
129
  export interface ImageSegment {
130
  id: number;
131
  box: number[];
 
32
  COHERE = "COHERE", // https://cohere.com
33
  FALAI = "FALAI", // https://fal.ai
34
  MODELSLAB = "MODELSLAB", // https://modelslab.com
35
+ MIDJOURNEY = "MIDJOURNEY",
36
+ SUNO = "SUNO",
37
+ UDIO = "UDIO",
38
+ LUMALABS = "LUMALABS",
39
+ KUAISHOU = "KUAISHOU",
40
+ RUNWAYML = "RUNWAYML",
41
  }
42
 
43
  export enum ComfyIcuAccelerator {
 
123
  }
124
  }
125
 
126
+ // note: they keep the high digit first in all cases
127
  export enum FalAiImageSize {
128
  SQUARE_HD = "square_hd",
129
  SQUARE = "square",
 
133
  LANDSCAPE_16_9 = "landscape_16_9"
134
  }
135
 
136
+ export enum StabilityAiImageSize {
137
+ SQUARE = "1:1",
138
+ PORTRAIT_2_3 = "2:3",
139
+ PORTRAIT_4_5 = "4:5",
140
+ PORTRAIT_9_16 = "9:16",
141
+ PORTRAIT_9_21 = "9:21",
142
+ LANDSCAPE_3_2 = "3:2",
143
+ LANDSCAPE_5_4 = "5:4",
144
+ LANDSCAPE_16_9 = "16:9",
145
+ LANDSCAPE_21_9 = "21:9"
146
+ }
147
+
148
+ export enum StabilityAiGenerationMode {
149
+ "TEXT_TO_IMAGE" = "text-to-image",
150
+ "IMAGE_TO_IMAGE" = "image-to-image"
151
+ }
152
+
153
  export interface ImageSegment {
154
  id: number;
155
  box: number[];