jbilcke-hf HF staff commited on
Commit
ca5fb80
1 Parent(s): 5bf59c5

this is neat

Browse files
src/app/main.tsx CHANGED
@@ -30,6 +30,7 @@ import { Field } from '@/components/form/field'
30
  import { Label } from '@/components/form/label'
31
  import { getParam } from '@/lib/utils/getParam'
32
  import { GenerationStage } from '@/types'
 
33
 
34
  export function Main() {
35
  const [_isPending, startTransition] = useTransition()
@@ -79,104 +80,35 @@ export function Main() {
79
 
80
  const isBusy = useStore(s => s.isBusy)
81
 
82
- const { openFilePicker, filesContent } = useFilePicker({
83
- accept: '.clap',
84
- readAs: "ArrayBuffer"
85
- })
86
- const fileData = filesContent[0]
87
-
88
- useEffect(() => {
89
- const fn = async () => {
90
- if (!fileData?.name) { return }
91
 
92
- const {
93
- setStatus,
94
- setProgress,
95
- setParseGenerationStatus,
96
- setFinalGenerationStatus,
97
- } = useStore.getState()
98
 
99
- let clap: ClapProject | undefined = undefined
100
-
101
- setStatus("generating")
102
- setProgress(25)
103
- setParseGenerationStatus("generating")
104
 
105
- try {
106
- const blob = new Blob([fileData.content])
107
- clap = await loadClap(blob, fileData.name)
108
- } catch (err) {
109
- console.error("failed to load the Clap file:", err)
110
- setError(`${err}`)
111
- }
112
 
113
- if (!clap) {
114
- setParseGenerationStatus("error")
115
- setStatus("error")
116
- setProgress(0)
117
- return
118
- }
119
 
 
120
  setParseGenerationStatus("finished")
 
 
 
 
 
 
 
 
121
 
122
- /*
123
- try {
124
- setProgress(60)
125
- setVoiceGenerationStatus("generating")
126
- clap = await editClapDialogues({
127
- clap,
128
- turbo: true,
129
- })
130
-
131
- if (!clap) { throw new Error(`failed to edit the dialogues`) }
132
-
133
- console.log(`handleSubmit(): received a clap with dialogues = `, clap)
134
- setCurrentClap(clap)
135
- setVoiceGenerationStatus("finished")
136
- } catch (err) {
137
- setVoiceGenerationStatus("error")
138
- setStatus("error")
139
- setError(`${err}`)
140
- return
141
- }
142
- if (!clap) {
143
- return
144
- }
145
- */
146
-
147
- setFinalGenerationStatus("generating")
148
-
149
- let assetUrl = ""
150
- try {
151
- assetUrl = await exportClapToVideo({
152
- clap,
153
- turbo: true
154
- })
155
- } catch (err) {
156
- console.error("failed to render the Clap file:", err)
157
- setError(`${err}`)
158
- }
159
-
160
- if (!assetUrl) {
161
- setFinalGenerationStatus("error")
162
- setStatus("error")
163
- setProgress(0)
164
- return
165
- }
166
-
167
- setFinalGenerationStatus("finished")
168
 
169
- setProgress(80)
170
-
171
- console.log(`loadClap(): generated a video: ${assetUrl.slice(0, 60)}...`)
172
-
173
- setCurrentVideo(assetUrl)
174
- setStatus("finished")
175
- setError("")
176
- }
177
- fn()
178
- }, [fileData?.name])
179
-
180
  const generateStory = async (): Promise<ClapProject> => {
181
 
182
  let clap: ClapProject | undefined = undefined
@@ -219,7 +151,7 @@ export function Main() {
219
 
220
  const generateEntities = async (clap: ClapProject): Promise<ClapProject> => {
221
  try {
222
- setProgress(20)
223
  setAssetGenerationStatus("generating")
224
  clap = await editClapEntities({
225
  clap,
@@ -251,13 +183,13 @@ export function Main() {
251
 
252
  const generateMusic = async (clap: ClapProject): Promise<ClapProject> => {
253
  try {
254
- setProgress(30)
255
  setMusicGenerationStatus("generating")
256
 
257
  clap = await editClapMusic({
258
  clap,
259
  turbo: true
260
- })
261
 
262
  if (!clap) { throw new Error(`failed to edit the music`) }
263
 
@@ -279,7 +211,7 @@ export function Main() {
279
 
280
  const generateStoryboards = async (clap: ClapProject): Promise<ClapProject> => {
281
  try {
282
- setProgress(40)
283
  setImageGenerationStatus("generating")
284
  clap = await editClapStoryboards({
285
  clap,
@@ -287,7 +219,7 @@ export function Main() {
287
  // since this uses a model with character consistency,
288
  // which is not the case for the non-turbo one
289
  turbo: true
290
- })
291
 
292
  if (!clap) { throw new Error(`failed to edit the storyboards`) }
293
 
@@ -310,13 +242,13 @@ export function Main() {
310
 
311
  const generateVideos = async (clap: ClapProject): Promise<ClapProject> => {
312
  try {
313
- setProgress(50)
314
  setVideoGenerationStatus("generating")
315
 
316
  clap = await editClapVideos({
317
  clap,
318
  turbo: true
319
- })
320
 
321
  if (!clap) { throw new Error(`failed to edit the videos`) }
322
 
@@ -338,7 +270,7 @@ export function Main() {
338
 
339
  const generateDialogues = async (clap: ClapProject): Promise<ClapProject> => {
340
  try {
341
- setProgress(70)
342
  setVoiceGenerationStatus("generating")
343
  clap = await editClapDialogues({
344
  clap,
@@ -367,7 +299,7 @@ export function Main() {
367
 
368
  let assetUrl = ""
369
  try {
370
- setProgress(85)
371
  setFinalGenerationStatus("generating")
372
  assetUrl = await exportClapToVideo({
373
  clap,
@@ -397,14 +329,14 @@ export function Main() {
397
  generateVideos(clap)
398
  ])
399
 
 
 
400
  for (const newerClap of claps) {
401
- console.log("newerClap:", newerClap)
402
  clap = await updateClap(clap, newerClap, {
403
  overwriteMeta: false,
404
  inlineReplace: true,
405
  })
406
  }
407
- console.log("finalClap: ", clap)
408
 
409
  /*
410
  clap = await claps.reduce(async (existingClap, newerClap) =>
@@ -447,6 +379,54 @@ export function Main() {
447
  })
448
  }
449
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
450
  // note: we are interested in the *current* video orientation,
451
  // not the requested video orientation requested for the next video
452
  const isLandscape = currentVideoOrientation === ClapMediaOrientation.LANDSCAPE
@@ -496,10 +476,12 @@ export function Main() {
496
  })
497
  */
498
  useStore.setState({
499
- progress: Math.min(maxProgressPerStage[stage], progress + 1)
 
500
  })
501
 
502
- timerRef.current = setTimeout(timerFn, progressDelayInMsPerStage[stage])
 
503
  }
504
 
505
  useEffect(() => {
 
30
  import { Label } from '@/components/form/label'
31
  import { getParam } from '@/lib/utils/getParam'
32
  import { GenerationStage } from '@/types'
33
+ import { FileContent } from 'use-file-picker/dist/interfaces'
34
 
35
  export function Main() {
36
  const [_isPending, startTransition] = useTransition()
 
80
 
81
  const isBusy = useStore(s => s.isBusy)
82
 
83
+ const importStory = async (fileData: FileContent<ArrayBuffer>): Promise<ClapProject> => {
84
+ if (!fileData?.name) { throw new Error(`invalid file (missing file name)`) }
 
 
 
 
 
 
 
85
 
86
+ const {
87
+ setStatus,
88
+ setProgress,
89
+ setParseGenerationStatus,
90
+ } = useStore.getState()
 
91
 
92
+ let clap: ClapProject | undefined = undefined
 
 
 
 
93
 
94
+ setParseGenerationStatus("generating")
 
 
 
 
 
 
95
 
96
+ try {
97
+ const blob = new Blob([fileData.content])
98
+ clap = await loadClap(blob, fileData.name)
 
 
 
99
 
100
+ if (!clap) { throw new Error(`failed to load the clap file`) }
101
  setParseGenerationStatus("finished")
102
+ setCurrentClap(clap)
103
+ return clap
104
+ } catch (err) {
105
+ console.error("failed to load the Clap file:", err)
106
+ setParseGenerationStatus("error")
107
+ throw err
108
+ }
109
+ }
110
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
111
 
 
 
 
 
 
 
 
 
 
 
 
112
  const generateStory = async (): Promise<ClapProject> => {
113
 
114
  let clap: ClapProject | undefined = undefined
 
151
 
152
  const generateEntities = async (clap: ClapProject): Promise<ClapProject> => {
153
  try {
154
+ // setProgress(20)
155
  setAssetGenerationStatus("generating")
156
  clap = await editClapEntities({
157
  clap,
 
183
 
184
  const generateMusic = async (clap: ClapProject): Promise<ClapProject> => {
185
  try {
186
+ // setProgress(30)
187
  setMusicGenerationStatus("generating")
188
 
189
  clap = await editClapMusic({
190
  clap,
191
  turbo: true
192
+ }).then(r => r.promise)
193
 
194
  if (!clap) { throw new Error(`failed to edit the music`) }
195
 
 
211
 
212
  const generateStoryboards = async (clap: ClapProject): Promise<ClapProject> => {
213
  try {
214
+ // setProgress(40)
215
  setImageGenerationStatus("generating")
216
  clap = await editClapStoryboards({
217
  clap,
 
219
  // since this uses a model with character consistency,
220
  // which is not the case for the non-turbo one
221
  turbo: true
222
+ }).then(r => r.promise)
223
 
224
  if (!clap) { throw new Error(`failed to edit the storyboards`) }
225
 
 
242
 
243
  const generateVideos = async (clap: ClapProject): Promise<ClapProject> => {
244
  try {
245
+ // setProgress(50)
246
  setVideoGenerationStatus("generating")
247
 
248
  clap = await editClapVideos({
249
  clap,
250
  turbo: true
251
+ }).then(r => r.promise)
252
 
253
  if (!clap) { throw new Error(`failed to edit the videos`) }
254
 
 
270
 
271
  const generateDialogues = async (clap: ClapProject): Promise<ClapProject> => {
272
  try {
273
+ // setProgress(70)
274
  setVoiceGenerationStatus("generating")
275
  clap = await editClapDialogues({
276
  clap,
 
299
 
300
  let assetUrl = ""
301
  try {
302
+ // setProgress(85)
303
  setFinalGenerationStatus("generating")
304
  assetUrl = await exportClapToVideo({
305
  clap,
 
329
  generateVideos(clap)
330
  ])
331
 
332
+ console.log("finished processing the 2 tasks in parallel")
333
+
334
  for (const newerClap of claps) {
 
335
  clap = await updateClap(clap, newerClap, {
336
  overwriteMeta: false,
337
  inlineReplace: true,
338
  })
339
  }
 
340
 
341
  /*
342
  clap = await claps.reduce(async (existingClap, newerClap) =>
 
379
  })
380
  }
381
 
382
+
383
+ const { openFilePicker, filesContent } = useFilePicker({
384
+ accept: '.clap',
385
+ readAs: "ArrayBuffer"
386
+ })
387
+ const fileData = filesContent[0]
388
+
389
+ useEffect(() => {
390
+ const fn = async () => {
391
+ if (!fileData?.name) { return }
392
+
393
+ const { setStatus, setProgress } = useStore.getState()
394
+
395
+ setProgress(0)
396
+ setStatus("generating")
397
+
398
+ try {
399
+ let clap = await importStory(fileData)
400
+
401
+ const claps = await Promise.all([
402
+ generateMusic(clap),
403
+ generateVideos(clap)
404
+ ])
405
+
406
+ // console.log("finished processing the 2 tasks in parallel")
407
+
408
+ for (const newerClap of claps) {
409
+ clap = await updateClap(clap, newerClap, {
410
+ overwriteMeta: false,
411
+ inlineReplace: true,
412
+ })
413
+ }
414
+
415
+ await generateFinalVideo(clap)
416
+
417
+ setStatus("finished")
418
+ setProgress(100)
419
+ setError("")
420
+ } catch (err) {
421
+ console.error(`failed to import: `, err)
422
+ setStatus("error")
423
+ setError(`${err}`)
424
+ }
425
+
426
+ }
427
+ fn()
428
+ }, [fileData?.name])
429
+
430
  // note: we are interested in the *current* video orientation,
431
  // not the requested video orientation requested for the next video
432
  const isLandscape = currentVideoOrientation === ClapMediaOrientation.LANDSCAPE
 
476
  })
477
  */
478
  useStore.setState({
479
+ // progress: Math.min(maxProgressPerStage[stage], progress + 1)
480
+ progress: Math.min(100, progress + 1)
481
  })
482
 
483
+ // timerRef.current = setTimeout(timerFn, progressDelayInMsPerStage[stage])
484
+ timerRef.current = setTimeout(timerFn, 750)
485
  }
486
 
487
  useEffect(() => {
src/app/server/aitube/editClapMusic.ts CHANGED
@@ -4,6 +4,7 @@ import { ClapProject } from "@aitube/clap"
4
  import { editClapMusic as apiEditClapMusic, ClapCompletionMode } from "@aitube/client"
5
 
6
  import { getToken } from "./getToken"
 
7
 
8
  export async function editClapMusic({
9
  clap,
@@ -11,13 +12,16 @@ export async function editClapMusic({
11
  }: {
12
  clap: ClapProject
13
  turbo?: boolean
14
- }): Promise<ClapProject> {
15
- const newClap: ClapProject = await apiEditClapMusic({
16
- clap,
17
- completionMode: ClapCompletionMode.MERGE,
18
- turbo,
19
- token: await getToken()
20
- })
21
-
22
- return newClap
 
 
 
23
  }
 
4
  import { editClapMusic as apiEditClapMusic, ClapCompletionMode } from "@aitube/client"
5
 
6
  import { getToken } from "./getToken"
7
+ import { Workaround } from "./types"
8
 
9
  export async function editClapMusic({
10
  clap,
 
12
  }: {
13
  clap: ClapProject
14
  turbo?: boolean
15
+ }): Workaround<ClapProject> {
16
+ async function promise() {
17
+ return await apiEditClapMusic({
18
+ clap,
19
+ completionMode: ClapCompletionMode.MERGE,
20
+ turbo,
21
+ token: await getToken()
22
+ })
23
+ }
24
+ return {
25
+ promise: promise()
26
+ }
27
  }
src/app/server/aitube/editClapStoryboards.ts CHANGED
@@ -4,6 +4,7 @@ import { ClapProject } from "@aitube/clap"
4
  import { editClapStoryboards as apiEditClapStoryboards, ClapCompletionMode } from "@aitube/client"
5
 
6
  import { getToken } from "./getToken"
 
7
 
8
  export async function editClapStoryboards({
9
  clap,
@@ -11,13 +12,16 @@ export async function editClapStoryboards({
11
  }: {
12
  clap: ClapProject
13
  turbo?: boolean
14
- }): Promise<ClapProject> {
15
- const newClap: ClapProject = await apiEditClapStoryboards({
16
- clap,
17
- completionMode: ClapCompletionMode.MERGE,
18
- turbo,
19
- token: await getToken()
20
- })
21
-
22
- return newClap
 
 
 
23
  }
 
4
  import { editClapStoryboards as apiEditClapStoryboards, ClapCompletionMode } from "@aitube/client"
5
 
6
  import { getToken } from "./getToken"
7
+ import { Workaround } from "./types"
8
 
9
  export async function editClapStoryboards({
10
  clap,
 
12
  }: {
13
  clap: ClapProject
14
  turbo?: boolean
15
+ }): Workaround<ClapProject> {
16
+ async function promise() {
17
+ return await apiEditClapStoryboards({
18
+ clap,
19
+ completionMode: ClapCompletionMode.MERGE,
20
+ turbo,
21
+ token: await getToken()
22
+ })
23
+ }
24
+ return {
25
+ promise: promise()
26
+ }
27
  }
src/app/server/aitube/editClapVideos.ts CHANGED
@@ -4,6 +4,7 @@ import { ClapProject } from "@aitube/clap"
4
  import { editClapVideos as apiEditClapVideos, ClapCompletionMode } from "@aitube/client"
5
 
6
  import { getToken } from "./getToken"
 
7
 
8
  export async function editClapVideos({
9
  clap,
@@ -11,13 +12,16 @@ export async function editClapVideos({
11
  }: {
12
  clap: ClapProject
13
  turbo?: boolean
14
- }): Promise<ClapProject> {
15
- const newClap: ClapProject = await apiEditClapVideos({
16
- clap,
17
- completionMode: ClapCompletionMode.MERGE,
18
- turbo,
19
- token: await getToken()
20
- })
21
-
22
- return newClap
 
 
 
23
  }
 
4
  import { editClapVideos as apiEditClapVideos, ClapCompletionMode } from "@aitube/client"
5
 
6
  import { getToken } from "./getToken"
7
+ import { Workaround } from "./types"
8
 
9
  export async function editClapVideos({
10
  clap,
 
12
  }: {
13
  clap: ClapProject
14
  turbo?: boolean
15
+ }): Workaround<ClapProject> {
16
+ async function promise() {
17
+ return await apiEditClapVideos({
18
+ clap,
19
+ completionMode: ClapCompletionMode.MERGE,
20
+ turbo,
21
+ token: await getToken()
22
+ })
23
+ }
24
+ return {
25
+ promise: promise()
26
+ }
27
  }
src/app/server/aitube/types.ts ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ // "Server Actions are designed for mutations that update server-side state; they are not recommended for data fetching. Accordingly, frameworks implementing Server Actions typically process one action at a time and do not have a way to cache the return value."
2
+ // well, lol
3
+ // https://www.youtube.com/watch?v=CDZg3maL9q0
4
+ export type Workaround<T> = Promise<{ promise: Promise<T> }>