jbilcke-hf HF staff commited on
Commit
3a86e21
·
1 Parent(s): 451df29

let's up the game

Browse files
src/app/main.tsx CHANGED
@@ -34,11 +34,13 @@ import { getParam } from '@/lib/utils/getParam'
34
  import { GenerationStage } from '@/types'
35
  import { FileContent } from 'use-file-picker/dist/interfaces'
36
  import { generateRandomStory } from '@/lib/utils/generateRandomStory'
 
37
 
38
  export function Main() {
39
  const [storyPromptDraft, setStoryPromptDraft] = useLocalStorage<string>(
40
  "AI_STORIES_FACTORY_STORY_PROMPT_DRAFT",
41
- "Yesterday I was walking in SF when I saw a zebra"
 
42
  )
43
  const promptDraftRef = useRef("")
44
  promptDraftRef.current = storyPromptDraft
@@ -143,7 +145,7 @@ export function Main() {
143
  setCurrentClap(clap)
144
  setStoryGenerationStatus("finished")
145
 
146
- console.log("-------- GENERATED STORY --------")
147
  console.table(clap.segments, [
148
  // 'startTimeInMs',
149
  'endTimeInMs',
@@ -168,14 +170,14 @@ export function Main() {
168
  // generating entities requires a "smart" LLM
169
  turbo: false,
170
  // turbo: true,
171
- })
172
 
173
  if (!clap) { throw new Error(`failed to edit the entities`) }
174
 
175
  console.log(`handleSubmit(): received a clap with entities = `, clap)
176
  setCurrentClap(clap)
177
  setAssetGenerationStatus("finished")
178
- console.log("-------- GENERATED ENTITIES --------")
179
  console.table(clap.entities, [
180
  'category',
181
  'label',
@@ -205,7 +207,7 @@ export function Main() {
205
  console.log(`handleSubmit(): received a clap with music = `, clap)
206
  setCurrentClap(clap)
207
  setMusicGenerationStatus("finished")
208
- console.log("-------- GENERATED MUSIC --------")
209
  console.table(clap.segments.filter(s => s.category === ClapSegmentCategory.MUSIC), [
210
  'endTimeInMs',
211
  'prompt',
@@ -227,7 +229,7 @@ export function Main() {
227
  // the turbo is mandatory here,
228
  // since this uses a model with character consistency,
229
  // which is not the case for the non-turbo one
230
- turbo: true
231
  }).then(r => r.promise)
232
 
233
  if (!clap) { throw new Error(`failed to edit the storyboards`) }
@@ -236,7 +238,18 @@ export function Main() {
236
  console.log(`handleSubmit(): received a clap with images = `, clap)
237
  setCurrentClap(clap)
238
  setImageGenerationStatus("finished")
239
- console.log("-------- GENERATED STORYBOARDS --------")
 
 
 
 
 
 
 
 
 
 
 
240
  console.table(clap.segments.filter(s => s.category === ClapSegmentCategory.STORYBOARD), [
241
  'endTimeInMs',
242
  'prompt',
@@ -264,7 +277,7 @@ export function Main() {
264
  console.log(`handleSubmit(): received a clap with videos = `, clap)
265
  setCurrentClap(clap)
266
  setVideoGenerationStatus("finished")
267
- console.log("-------- GENERATED VIDEOS --------")
268
  console.table(clap.segments.filter(s => s.category === ClapSegmentCategory.VIDEO), [
269
  'endTimeInMs',
270
  'prompt',
@@ -277,6 +290,13 @@ export function Main() {
277
  }
278
  }
279
 
 
 
 
 
 
 
 
280
  const generateDialogues = async (clap: ClapProject): Promise<ClapProject> => {
281
  try {
282
  // setProgress(70)
@@ -284,14 +304,14 @@ export function Main() {
284
  clap = await editClapDialogues({
285
  clap,
286
  turbo: true
287
- })
288
 
289
  if (!clap) { throw new Error(`failed to edit the dialogues`) }
290
 
291
  console.log(`handleSubmit(): received a clap with dialogues = `, clap)
292
  setCurrentClap(clap)
293
  setVoiceGenerationStatus("finished")
294
- console.log("-------- GENERATED DIALOGUES --------")
295
  console.table(clap.segments.filter(s => s.category === ClapSegmentCategory.DIALOGUE), [
296
  'endTimeInMs',
297
  'prompt',
@@ -319,7 +339,7 @@ export function Main() {
319
 
320
  if (assetUrl.length < 128) { throw new Error(`handleSubmit(): the generated video is too small, so we failed`) }
321
 
322
- console.log(`handleSubmit(): received a video: ${assetUrl.slice(0, 60)}...`)
323
  setFinalGenerationStatus("finished")
324
  return assetUrl
325
  } catch (err) {
@@ -336,12 +356,14 @@ export function Main() {
336
  try {
337
  let clap = await generateStory()
338
 
339
- const claps = await Promise.all([
340
  generateMusic(clap),
341
- generateVideos(clap)
342
- ])
343
 
344
- console.log("finished processing the 2 tasks in parallel")
 
 
345
 
346
  for (const newerClap of claps) {
347
  clap = await updateClap(clap, newerClap, {
@@ -379,6 +401,9 @@ export function Main() {
379
  // clap = await generateVideos(clap)
380
  // clap = await generateDialogues(clap)
381
 
 
 
 
382
  await generateFinalVideo(clap)
383
 
384
  setStatus("finished")
@@ -644,7 +669,8 @@ export function Main() {
644
  setStoryPromptDraft(e.target.value)
645
  promptDraftRef.current = e.target.value
646
  }}
647
- placeholder="Yesterday I was at my favorite pizza place and.."
 
648
  inputClassName="
649
  transition-all duration-200 ease-in-out
650
  h-32 md:h-56 lg:h-64
@@ -873,7 +899,7 @@ export function Main() {
873
  : imageGenerationStatus === "generating" ? "Creating storyboards.."
874
  : videoGenerationStatus === "generating" ? "Filming shots.."
875
  : voiceGenerationStatus === "generating" ? "Recording dialogues.."
876
- : finalGenerationStatus === "generating" ? "Assembling final cut.."
877
  : "Please wait.."
878
  )
879
  : status === "error"
@@ -914,7 +940,7 @@ export function Main() {
914
  Powered by
915
  </span>
916
  <span className="ml-1 mr-0.5">
917
- <Image src={HFLogo} alt="Hugging Face" width="14" height="14" />
918
  </span>
919
  <span className="text-stone-100/80 text-3xs font-semibold"
920
  style={{ textShadow: "rgb(0 0 0 / 80%) 0px 0px 2px" }}>Hugging Face</span>
 
34
  import { GenerationStage } from '@/types'
35
  import { FileContent } from 'use-file-picker/dist/interfaces'
36
  import { generateRandomStory } from '@/lib/utils/generateRandomStory'
37
+ import { logImage } from '@/lib/utils/logImage'
38
 
39
  export function Main() {
40
  const [storyPromptDraft, setStoryPromptDraft] = useLocalStorage<string>(
41
  "AI_STORIES_FACTORY_STORY_PROMPT_DRAFT",
42
+ // "Yesterday I was walking in SF when I saw a zebra"
43
+ "underwater footage, coral, fishes"
44
  )
45
  const promptDraftRef = useRef("")
46
  promptDraftRef.current = storyPromptDraft
 
145
  setCurrentClap(clap)
146
  setStoryGenerationStatus("finished")
147
 
148
+ console.log("---------------- GENERATED STORY ----------------")
149
  console.table(clap.segments, [
150
  // 'startTimeInMs',
151
  'endTimeInMs',
 
170
  // generating entities requires a "smart" LLM
171
  turbo: false,
172
  // turbo: true,
173
+ }).then(r => r.promise)
174
 
175
  if (!clap) { throw new Error(`failed to edit the entities`) }
176
 
177
  console.log(`handleSubmit(): received a clap with entities = `, clap)
178
  setCurrentClap(clap)
179
  setAssetGenerationStatus("finished")
180
+ console.log("---------------- GENERATED ENTITIES ----------------")
181
  console.table(clap.entities, [
182
  'category',
183
  'label',
 
207
  console.log(`handleSubmit(): received a clap with music = `, clap)
208
  setCurrentClap(clap)
209
  setMusicGenerationStatus("finished")
210
+ console.log("---------------- GENERATED MUSIC ----------------")
211
  console.table(clap.segments.filter(s => s.category === ClapSegmentCategory.MUSIC), [
212
  'endTimeInMs',
213
  'prompt',
 
229
  // the turbo is mandatory here,
230
  // since this uses a model with character consistency,
231
  // which is not the case for the non-turbo one
232
+ turbo: false
233
  }).then(r => r.promise)
234
 
235
  if (!clap) { throw new Error(`failed to edit the storyboards`) }
 
238
  console.log(`handleSubmit(): received a clap with images = `, clap)
239
  setCurrentClap(clap)
240
  setImageGenerationStatus("finished")
241
+ console.log("---------------- GENERATED STORYBOARDS ----------------")
242
+ clap.segments
243
+ .filter(s => s.category === ClapSegmentCategory.STORYBOARD)
244
+ .forEach((s, i) => {
245
+ if (s.status === "completed" && s.assetUrl) {
246
+ // console.log(` [${i}] storyboard: ${s.prompt}`)
247
+ logImage(s.assetUrl, 0.35)
248
+ } else {
249
+ console.log(` [${i}] failed to generate storyboard`)
250
+ }
251
+ // console.log(`------------------`)
252
+ })
253
  console.table(clap.segments.filter(s => s.category === ClapSegmentCategory.STORYBOARD), [
254
  'endTimeInMs',
255
  'prompt',
 
277
  console.log(`handleSubmit(): received a clap with videos = `, clap)
278
  setCurrentClap(clap)
279
  setVideoGenerationStatus("finished")
280
+ console.log("---------------- GENERATED VIDEOS ----------------")
281
  console.table(clap.segments.filter(s => s.category === ClapSegmentCategory.VIDEO), [
282
  'endTimeInMs',
283
  'prompt',
 
290
  }
291
  }
292
 
293
+ const generateStoryboardsThenVideos = async (clap: ClapProject): Promise<ClapProject> => {
294
+ clap = await generateStoryboards(clap)
295
+ clap = await generateVideos(clap)
296
+ return clap
297
+ }
298
+
299
+
300
  const generateDialogues = async (clap: ClapProject): Promise<ClapProject> => {
301
  try {
302
  // setProgress(70)
 
304
  clap = await editClapDialogues({
305
  clap,
306
  turbo: true
307
+ }).then(r => r.promise)
308
 
309
  if (!clap) { throw new Error(`failed to edit the dialogues`) }
310
 
311
  console.log(`handleSubmit(): received a clap with dialogues = `, clap)
312
  setCurrentClap(clap)
313
  setVoiceGenerationStatus("finished")
314
+ console.log("---------------- GENERATED DIALOGUES ----------------")
315
  console.table(clap.segments.filter(s => s.category === ClapSegmentCategory.DIALOGUE), [
316
  'endTimeInMs',
317
  'prompt',
 
339
 
340
  if (assetUrl.length < 128) { throw new Error(`handleSubmit(): the generated video is too small, so we failed`) }
341
 
342
+ console.log(`handleSubmit(): received a video: ${assetUrl.slice(0, 120)}...`)
343
  setFinalGenerationStatus("finished")
344
  return assetUrl
345
  } catch (err) {
 
356
  try {
357
  let clap = await generateStory()
358
 
359
+ const tasks = [
360
  generateMusic(clap),
361
+ generateStoryboardsThenVideos(clap)
362
+ ]
363
 
364
+ const claps = await Promise.all(tasks)
365
+
366
+ console.log(`finished processing ${tasks.length} tasks in parallel`)
367
 
368
  for (const newerClap of claps) {
369
  clap = await updateClap(clap, newerClap, {
 
401
  // clap = await generateVideos(clap)
402
  // clap = await generateDialogues(clap)
403
 
404
+
405
+
406
+ console.log("final clap: ", clap)
407
  await generateFinalVideo(clap)
408
 
409
  setStatus("finished")
 
669
  setStoryPromptDraft(e.target.value)
670
  promptDraftRef.current = e.target.value
671
  }}
672
+ // placeholder="Yesterday I was at my favorite pizza place and.."
673
+ placeholder="underwater footage, coral, fishes"
674
  inputClassName="
675
  transition-all duration-200 ease-in-out
676
  h-32 md:h-56 lg:h-64
 
899
  : imageGenerationStatus === "generating" ? "Creating storyboards.."
900
  : videoGenerationStatus === "generating" ? "Filming shots.."
901
  : voiceGenerationStatus === "generating" ? "Recording dialogues.."
902
+ : finalGenerationStatus === "generating" ? "Editing final cut.."
903
  : "Please wait.."
904
  )
905
  : status === "error"
 
940
  Powered by
941
  </span>
942
  <span className="ml-1 mr-0.5">
943
+ <Image src={HFLogo} alt="Hugging Face" width={14} height={13} />
944
  </span>
945
  <span className="text-stone-100/80 text-3xs font-semibold"
946
  style={{ textShadow: "rgb(0 0 0 / 80%) 0px 0px 2px" }}>Hugging Face</span>
src/app/server/aitube/config.ts CHANGED
@@ -3,5 +3,9 @@ export const serverHuggingfaceApiKey = `${process.env.HF_API_TOKEN || ""}`
3
 
4
  // initially I used 1024x512 (a 2:1 ratio)
5
  // but that is a bit too extreme, most phones only take 16:9
6
- export const RESOLUTION_LONG = 1024
7
- export const RESOLUTION_SHORT = 576
 
 
 
 
 
3
 
4
  // initially I used 1024x512 (a 2:1 ratio)
5
  // but that is a bit too extreme, most phones only take 16:9
6
+ // we can also try this
7
+ // > 896x512
8
+ export const RESOLUTION_LONG = 896 // 832 // 768
9
+ export const RESOLUTION_SHORT = 512 // 448 // 384
10
+
11
+ // ValueError: `height` and `width` have to be divisible by 8 but are 512 and 1.
src/app/server/aitube/editClapDialogues.ts CHANGED
@@ -4,6 +4,7 @@ import { ClapProject } from "@aitube/clap"
4
  import { editClapDialogues as apiEditClapDialogues, ClapCompletionMode } from "@aitube/client"
5
 
6
  import { getToken } from "./getToken"
 
7
 
8
  export async function editClapDialogues({
9
  clap,
@@ -11,13 +12,17 @@ export async function editClapDialogues({
11
  }: {
12
  clap: ClapProject
13
  turbo?: boolean
14
- }): Promise<ClapProject> {
15
- const newClap: ClapProject = await apiEditClapDialogues({
16
- clap,
17
- completionMode: ClapCompletionMode.MERGE,
18
- turbo,
19
- token: await getToken()
20
- })
 
 
21
 
22
- return newClap
 
 
23
  }
 
4
  import { editClapDialogues as apiEditClapDialogues, ClapCompletionMode } from "@aitube/client"
5
 
6
  import { getToken } from "./getToken"
7
+ import { Workaround } from "./types"
8
 
9
  export async function editClapDialogues({
10
  clap,
 
12
  }: {
13
  clap: ClapProject
14
  turbo?: boolean
15
+ }): Workaround<ClapProject> {
16
+ async function promise() {
17
+ return await apiEditClapDialogues({
18
+ clap,
19
+ completionMode: ClapCompletionMode.MERGE,
20
+ turbo,
21
+ token: await getToken()
22
+ })
23
+ }
24
 
25
+ return {
26
+ promise: promise()
27
+ }
28
  }
src/app/server/aitube/editClapEntities.ts CHANGED
@@ -4,6 +4,7 @@ import { ClapProject } from "@aitube/clap"
4
  import { editClapEntities as apiEditClapEntities, ClapCompletionMode, ClapEntityPrompt } from "@aitube/client"
5
 
6
  import { getToken } from "./getToken"
 
7
 
8
  export async function editClapEntities({
9
  clap,
@@ -13,14 +14,18 @@ export async function editClapEntities({
13
  clap: ClapProject
14
  entityPrompts?: ClapEntityPrompt[]
15
  turbo?: boolean
16
- }): Promise<ClapProject> {
17
- const newClap: ClapProject = await apiEditClapEntities({
18
- clap,
19
- entityPrompts,
20
- completionMode: ClapCompletionMode.MERGE,
21
- turbo,
22
- token: await getToken()
23
- })
 
 
24
 
25
- return newClap
 
 
26
  }
 
4
  import { editClapEntities as apiEditClapEntities, ClapCompletionMode, ClapEntityPrompt } from "@aitube/client"
5
 
6
  import { getToken } from "./getToken"
7
+ import { Workaround } from "./types"
8
 
9
  export async function editClapEntities({
10
  clap,
 
14
  clap: ClapProject
15
  entityPrompts?: ClapEntityPrompt[]
16
  turbo?: boolean
17
+ }): Workaround<ClapProject> {
18
+ async function promise() {
19
+ return await apiEditClapEntities({
20
+ clap,
21
+ entityPrompts,
22
+ completionMode: ClapCompletionMode.MERGE,
23
+ turbo,
24
+ token: await getToken()
25
+ })
26
+ }
27
 
28
+ return {
29
+ promise: promise()
30
+ }
31
  }
src/app/store.ts CHANGED
@@ -67,7 +67,8 @@ export const useStore = create<{
67
  }>((set, get) => ({
68
  mainCharacterImage: "",
69
  mainCharacterVoice: "",
70
- storyPromptDraft: "Yesterday I was at my favorite pizza place and..",
 
71
  storyPrompt: "",
72
  orientation: ClapMediaOrientation.PORTRAIT,
73
  status: "idle",
@@ -207,7 +208,7 @@ export const useStore = create<{
207
 
208
  const cleanStoryPrompt = firstPartOfStoryPrompt.replace(/([^a-z0-9, ]+)/gi, "_")
209
 
210
- const cleanName = `${cleanStoryPrompt.slice(0, 50)}`
211
 
212
  anchor.download = `${cleanName}.mp4`
213
 
@@ -238,7 +239,7 @@ export const useStore = create<{
238
 
239
  const cleanStoryPrompt = firstPartOfStoryPrompt.replace(/([^a-z0-9, ]+)/gi, "_")
240
 
241
- const cleanName = `${cleanStoryPrompt.slice(0, 50)}`
242
 
243
  anchor.download = `${cleanName}.clap`
244
 
 
67
  }>((set, get) => ({
68
  mainCharacterImage: "",
69
  mainCharacterVoice: "",
70
+ // storyPromptDraft: "Yesterday I was at my favorite pizza place and..",
71
+ storyPromptDraft: "underwater footage, coral, fishes",
72
  storyPrompt: "",
73
  orientation: ClapMediaOrientation.PORTRAIT,
74
  status: "idle",
 
208
 
209
  const cleanStoryPrompt = firstPartOfStoryPrompt.replace(/([^a-z0-9, ]+)/gi, "_")
210
 
211
+ const cleanName = `${cleanStoryPrompt.slice(0, 120)}`
212
 
213
  anchor.download = `${cleanName}.mp4`
214
 
 
239
 
240
  const cleanStoryPrompt = firstPartOfStoryPrompt.replace(/([^a-z0-9, ]+)/gi, "_")
241
 
242
+ const cleanName = `${cleanStoryPrompt.slice(0, 120)}`
243
 
244
  anchor.download = `${cleanName}.clap`
245
 
src/lib/utils/logImage.ts ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ export async function logImage(uri: string, scale = 1.0): Promise<void> {
2
+ // Create an image element
3
+ const img = new Image();
4
+
5
+ // Load the image asynchronously
6
+ img.src = uri;
7
+ await new Promise<void>((resolve, reject) => {
8
+ img.onload = () => resolve();
9
+ img.onerror = (error) => reject(error);
10
+ });
11
+
12
+ // Get the image dimensions
13
+ let { width, height } = img;
14
+ width *= scale
15
+ height *= scale
16
+
17
+ // Log the image in the console
18
+ console.log(
19
+ "%c+",
20
+ `font-size: 1px; padding: ${Math.floor(height / 4)}px ${Math.floor(width / 2)}px; line-height: ${Math.round(height * 0.52)}px; background: url('${uri}'); background-size: ${width}px ${height}px; background-repeat: no-repeat; color: transparent;`
21
+ );
22
+ }
23
+
24
+ (async function() {
25
+
26
+ if (typeof window !== "undefined") {
27
+ // Add the logImage function to the console object
28
+ (console as any).image = logImage;
29
+
30
+ // Example usage
31
+ // console.image('https://example.com/path/to/your/image.jpg');
32
+ }
33
+ })()