jbilcke-hf HF staff commited on
Commit
99c03ec
1 Parent(s): 0465776
.nvmrc CHANGED
@@ -1 +1 @@
1
- v20.9.0
 
1
+ v20.17.0
package-lock.json CHANGED
The diff for this file is too large to render. See raw diff
 
package.json CHANGED
@@ -9,8 +9,8 @@
9
  "lint": "next lint"
10
  },
11
  "dependencies": {
12
- "@aitube/clap": "0.1.2",
13
- "@aitube/client": "0.1.2",
14
  "@huggingface/hub": "^0.15.1",
15
  "@radix-ui/react-accordion": "^1.1.2",
16
  "@radix-ui/react-avatar": "^1.0.4",
@@ -46,7 +46,7 @@
46
  "jimp": "^0.22.12",
47
  "jose": "^5.2.4",
48
  "lucide-react": "^0.334.0",
49
- "next": "^14.2.3",
50
  "next-themes": "^0.2.1",
51
  "postcss": "8.4.38",
52
  "qs": "^6.12.1",
 
9
  "lint": "next lint"
10
  },
11
  "dependencies": {
12
+ "@aitube/clap": "0.2.4",
13
+ "@aitube/client": "0.2.4-3",
14
  "@huggingface/hub": "^0.15.1",
15
  "@radix-ui/react-accordion": "^1.1.2",
16
  "@radix-ui/react-avatar": "^1.0.4",
 
46
  "jimp": "^0.22.12",
47
  "jose": "^5.2.4",
48
  "lucide-react": "^0.334.0",
49
+ "next": "^14.2.7",
50
  "next-themes": "^0.2.1",
51
  "postcss": "8.4.38",
52
  "qs": "^6.12.1",
src/app/main.tsx CHANGED
@@ -3,7 +3,7 @@
3
  import React from "react"
4
  import { IoMdPhonePortrait } from "react-icons/io"
5
  import { GiRollingDices } from "react-icons/gi"
6
- import { ClapMediaOrientation } from "@aitube/clap"
7
 
8
  import { Card, CardContent, CardHeader } from "@/components/ui/card"
9
  import { Button } from "@/components/ui/button"
@@ -28,7 +28,7 @@ import { useStore } from "./store"
28
  export function Main() {
29
  const { storyPromptDraft, setStoryPromptDraft, promptDraftRef } = useStoryPromptDraft()
30
  const { isBusy } = useIsBusy()
31
- const { orientation, toggleOrientation } = useOrientation()
32
  const { handleCreateStory, handleExtendStory } = useProcessors()
33
  useQueryStringParams()
34
 
@@ -276,7 +276,7 @@ export function Main() {
276
  >
277
  <div className={cn(
278
  `transition-all duration-200 ease-in-out`,
279
- orientation === ClapMediaOrientation.LANDSCAPE ? `rotate-90` : `rotate-0`
280
  )}>
281
  <IoMdPhonePortrait size={24} />
282
  </div>
 
3
  import React from "react"
4
  import { IoMdPhonePortrait } from "react-icons/io"
5
  import { GiRollingDices } from "react-icons/gi"
6
+ import { ClapImageRatio } from "@aitube/clap"
7
 
8
  import { Card, CardContent, CardHeader } from "@/components/ui/card"
9
  import { Button } from "@/components/ui/button"
 
28
  export function Main() {
29
  const { storyPromptDraft, setStoryPromptDraft, promptDraftRef } = useStoryPromptDraft()
30
  const { isBusy } = useIsBusy()
31
+ const { imageRatio, toggleOrientation } = useOrientation()
32
  const { handleCreateStory, handleExtendStory } = useProcessors()
33
  useQueryStringParams()
34
 
 
276
  >
277
  <div className={cn(
278
  `transition-all duration-200 ease-in-out`,
279
+ imageRatio === ClapImageRatio.LANDSCAPE ? `rotate-90` : `rotate-0`
280
  )}>
281
  <IoMdPhonePortrait size={24} />
282
  </div>
src/app/server/aitube/createClap.ts CHANGED
@@ -3,8 +3,8 @@
3
 
4
  import { Ratelimit } from "@upstash/ratelimit"
5
  import { Redis } from "@upstash/redis"
6
- import { ClapProject, ClapMediaOrientation } from "@aitube/clap"
7
- import { createClap as apiCreateClap } from "@aitube/client"
8
 
9
  import { getToken } from "./getToken"
10
  import { RESOLUTION_LONG, RESOLUTION_SHORT, MAX_PROMPT_LENGTH_IN_CHARS } from "../config"
@@ -14,11 +14,11 @@ const rateLimit = getRateLimit()
14
 
15
  export async function createClap({
16
  prompt = "",
17
- orientation = ClapMediaOrientation.PORTRAIT,
18
  turbo = false,
19
  }: {
20
  prompt: string
21
- orientation?: ClapMediaOrientation
22
  turbo?: boolean
23
  }): Promise<ClapProject> {
24
 
@@ -42,8 +42,8 @@ export async function createClap({
42
  const clap: ClapProject = await apiCreateClap({
43
  prompt: prompt.slice(0, MAX_PROMPT_LENGTH_IN_CHARS),
44
 
45
- height: orientation === ClapMediaOrientation.PORTRAIT ? RESOLUTION_LONG : RESOLUTION_SHORT,
46
- width: orientation === ClapMediaOrientation.PORTRAIT ? RESOLUTION_SHORT : RESOLUTION_LONG,
47
 
48
  turbo,
49
 
 
3
 
4
  import { Ratelimit } from "@upstash/ratelimit"
5
  import { Redis } from "@upstash/redis"
6
+ import { ClapProject, ClapImageRatio } from "@aitube/clap"
7
+ import { createClap as apiCreateClap } from "@aitube/api-client"
8
 
9
  import { getToken } from "./getToken"
10
  import { RESOLUTION_LONG, RESOLUTION_SHORT, MAX_PROMPT_LENGTH_IN_CHARS } from "../config"
 
14
 
15
  export async function createClap({
16
  prompt = "",
17
+ imageRatio = ClapImageRatio.PORTRAIT,
18
  turbo = false,
19
  }: {
20
  prompt: string
21
+ imageRatio?: ClapImageRatio
22
  turbo?: boolean
23
  }): Promise<ClapProject> {
24
 
 
42
  const clap: ClapProject = await apiCreateClap({
43
  prompt: prompt.slice(0, MAX_PROMPT_LENGTH_IN_CHARS),
44
 
45
+ height: imageRatio === ClapImageRatio.PORTRAIT ? RESOLUTION_LONG : RESOLUTION_SHORT,
46
+ width: imageRatio === ClapImageRatio.PORTRAIT ? RESOLUTION_SHORT : RESOLUTION_LONG,
47
 
48
  turbo,
49
 
src/app/server/aitube/editClapDialogues.ts CHANGED
@@ -1,7 +1,7 @@
1
  "use server"
2
 
3
  import { ClapProject, ClapCompletionMode } from "@aitube/clap"
4
- import { editClapDialogues as apiEditClapDialogues } from "@aitube/client"
5
 
6
  import { getToken } from "./getToken"
7
  import { Workaround } from "./types"
 
1
  "use server"
2
 
3
  import { ClapProject, ClapCompletionMode } from "@aitube/clap"
4
+ import { editClapDialogues as apiEditClapDialogues } from "@aitube/api-client"
5
 
6
  import { getToken } from "./getToken"
7
  import { Workaround } from "./types"
src/app/server/aitube/editClapEntities.ts CHANGED
@@ -1,7 +1,7 @@
1
  "use server"
2
 
3
  import { ClapProject, ClapCompletionMode } from "@aitube/clap"
4
- import { editClapEntities as apiEditClapEntities, ClapEntityPrompt } from "@aitube/client"
5
 
6
  import { getToken } from "./getToken"
7
  import { Workaround } from "./types"
 
1
  "use server"
2
 
3
  import { ClapProject, ClapCompletionMode } from "@aitube/clap"
4
+ import { editClapEntities as apiEditClapEntities, ClapEntityPrompt } from "@aitube/api-client"
5
 
6
  import { getToken } from "./getToken"
7
  import { Workaround } from "./types"
src/app/server/aitube/editClapMusic.ts CHANGED
@@ -1,7 +1,7 @@
1
  "use server"
2
 
3
  import { ClapProject, ClapCompletionMode } from "@aitube/clap"
4
- import { editClapMusic as apiEditClapMusic } from "@aitube/client"
5
 
6
  import { getToken } from "./getToken"
7
  import { Workaround } from "./types"
 
1
  "use server"
2
 
3
  import { ClapProject, ClapCompletionMode } from "@aitube/clap"
4
+ import { editClapMusic as apiEditClapMusic } from "@aitube/api-client"
5
 
6
  import { getToken } from "./getToken"
7
  import { Workaround } from "./types"
src/app/server/aitube/editClapSounds.ts CHANGED
@@ -1,7 +1,7 @@
1
  "use server"
2
 
3
  import { ClapProject, ClapCompletionMode } from "@aitube/clap"
4
- import { editClapSounds as apiEditClapSounds } from "@aitube/client"
5
 
6
  import { getToken } from "./getToken"
7
  import { Workaround } from "./types"
 
1
  "use server"
2
 
3
  import { ClapProject, ClapCompletionMode } from "@aitube/clap"
4
+ import { editClapSounds as apiEditClapSounds } from "@aitube/api-client"
5
 
6
  import { getToken } from "./getToken"
7
  import { Workaround } from "./types"
src/app/server/aitube/editClapStory.ts CHANGED
@@ -1,7 +1,7 @@
1
  "use server"
2
 
3
  import { ClapProject, ClapCompletionMode } from "@aitube/clap"
4
- import { editClapStory as apiEditClapStory } from "@aitube/client"
5
 
6
  import { getToken } from "./getToken"
7
  import { Workaround } from "./types"
 
1
  "use server"
2
 
3
  import { ClapProject, ClapCompletionMode } from "@aitube/clap"
4
+ import { editClapStory as apiEditClapStory } from "@aitube/api-client"
5
 
6
  import { getToken } from "./getToken"
7
  import { Workaround } from "./types"
src/app/server/aitube/editClapStoryboards.ts CHANGED
@@ -1,7 +1,7 @@
1
  "use server"
2
 
3
  import { ClapProject, ClapCompletionMode } from "@aitube/clap"
4
- import { editClapStoryboards as apiEditClapStoryboards } from "@aitube/client"
5
 
6
  import { getToken } from "./getToken"
7
  import { Workaround } from "./types"
 
1
  "use server"
2
 
3
  import { ClapProject, ClapCompletionMode } from "@aitube/clap"
4
+ import { editClapStoryboards as apiEditClapStoryboards } from "@aitube/api-client"
5
 
6
  import { getToken } from "./getToken"
7
  import { Workaround } from "./types"
src/app/server/aitube/editClapVideos.ts CHANGED
@@ -1,7 +1,7 @@
1
  "use server"
2
 
3
  import { ClapProject, ClapCompletionMode } from "@aitube/clap"
4
- import { editClapVideos as apiEditClapVideos } from "@aitube/client"
5
 
6
  import { getToken } from "./getToken"
7
  import { Workaround } from "./types"
 
1
  "use server"
2
 
3
  import { ClapProject, ClapCompletionMode } from "@aitube/clap"
4
+ import { editClapVideos as apiEditClapVideos } from "@aitube/api-client"
5
 
6
  import { getToken } from "./getToken"
7
  import { Workaround } from "./types"
src/app/server/aitube/exportClapToVideo.ts CHANGED
@@ -1,7 +1,7 @@
1
  "use server"
2
 
3
  import { ClapProject } from "@aitube/clap"
4
- import { exportClapToVideo as apiExportClapToVideo } from "@aitube/client"
5
 
6
  import { getToken } from "./getToken"
7
  import { removeFinalVideos } from "@/lib/utils/removeFinalVideos"
 
1
  "use server"
2
 
3
  import { ClapProject } from "@aitube/clap"
4
+ import { exportClapToVideo as apiExportClapToVideo } from "@aitube/api-client"
5
 
6
  import { getToken } from "./getToken"
7
  import { removeFinalVideos } from "@/lib/utils/removeFinalVideos"
src/app/store.ts CHANGED
@@ -1,10 +1,10 @@
1
  "use client"
2
 
3
- import { ClapProject, parseClap, serializeClap, ClapMediaOrientation, parseMediaOrientation, ClapSegmentCategory, newSegment, getClapAssetSourceType, ClapSegmentStatus } from "@aitube/clap"
4
  import { create } from "zustand"
5
 
6
  import { GenerationStage, GlobalStatus, TaskStatus } from "@/types"
7
- import { getVideoOrientation } from "@/lib/utils/getVideoOrientation"
8
 
9
  import { RESOLUTION_LONG, RESOLUTION_SHORT } from "./server/config"
10
  import { putTextInTextAreaElement } from "@/lib/utils/putTextInTextAreaElement"
@@ -15,9 +15,9 @@ export const useStore = create<{
15
  mainCharacterVoice: string
16
  storyPrompt: string
17
 
18
- // the desired orientation for the next video
19
- // but this won't impact the actual orientation of the fake device container
20
- orientation: ClapMediaOrientation
21
 
22
  status: GlobalStatus
23
  stage: GenerationStage
@@ -43,16 +43,16 @@ export const useStore = create<{
43
 
44
  currentVideo: string
45
 
46
- // orientation of the currently loaded video (which can be different from `orientation`)
47
- // it will impact the actual orientation of the fake device container
48
- currentVideoOrientation: ClapMediaOrientation
49
  progress: number
50
  error: string
51
  showAuthWall: boolean
52
  setShowAuthWall: (showAuthWall: boolean) => void
53
  toggleOrientation: () => void
54
- setOrientation: (orientation: ClapMediaOrientation) => void
55
- setCurrentVideoOrientation: (currentVideoOrientation: ClapMediaOrientation) => void
56
  setMainCharacterImage: (mainCharacterImage: string) => void
57
  setMainCharacterVoice: (mainCharacterVoice: string) => void
58
  setStoryPrompt: (storyPrompt: string) => void
@@ -70,7 +70,7 @@ export const useStore = create<{
70
  setSkeletonClap: (fullClap?: ClapProject) => void
71
  setFullClap: (fullClap?: ClapProject) => void
72
 
73
- // note: this will preload the video, and compute the orientation too
74
  setCurrentVideo: (currentVideo: string) => Promise<void>
75
 
76
  setProgress: (progress: number) => void
@@ -86,7 +86,7 @@ export const useStore = create<{
86
  mainCharacterVoice: "",
87
  storyPromptDraft: defaultPrompt,
88
  storyPrompt: "",
89
- orientation: ClapMediaOrientation.PORTRAIT,
90
  status: "idle",
91
  stage: "idle",
92
  statusMessage: "",
@@ -103,42 +103,42 @@ export const useStore = create<{
103
  skeletonClap: undefined,
104
  fullClap: undefined,
105
  currentVideo: "",
106
- currentVideoOrientation: ClapMediaOrientation.PORTRAIT,
107
  progress: 0,
108
  error: "",
109
  showAuthWall: false,
110
  setShowAuthWall: (showAuthWall: boolean) => { set({ showAuthWall }) },
111
  toggleOrientation: () => {
112
- const { orientation: previousOrientation, currentVideoOrientation, currentVideo } = get()
113
- const orientation =
114
- previousOrientation === ClapMediaOrientation.LANDSCAPE
115
- ? ClapMediaOrientation.PORTRAIT
116
- : ClapMediaOrientation.LANDSCAPE
117
 
118
  set({
119
- orientation,
120
 
121
- // we normally don't touch the currentVideoOrientation since it will already contain a video
122
- currentVideoOrientation:
123
  currentVideo
124
- ? currentVideoOrientation
125
- : orientation
126
  })
127
  },
128
- setOrientation: (orientation: ClapMediaOrientation) => {
129
- const { currentVideoOrientation, currentVideo } = get()
130
 
131
  set({
132
- orientation,
133
 
134
- // we normally don't touch the currentVideoOrientation since it will already contain a video
135
- currentVideoOrientation:
136
  currentVideo
137
- ? currentVideoOrientation
138
- : orientation
139
  })
140
  },
141
- setCurrentVideoOrientation: (currentVideoOrientation: ClapMediaOrientation) => { set({ currentVideoOrientation }) },
142
  setMainCharacterImage: (mainCharacterImage: string) => { set({ mainCharacterImage }) },
143
  setMainCharacterVoice: (mainCharacterVoice: string) => { set({ mainCharacterVoice }) },
144
  setStoryPrompt: (storyPrompt: string) => { set({ storyPrompt }) },
@@ -231,18 +231,18 @@ export const useStore = create<{
231
  set({
232
  currentVideo,
233
  })
234
- const { currentVideoOrientation } = get()
235
- let orientation: ClapMediaOrientation = currentVideoOrientation
236
  try {
237
- let newOrientation = await getVideoOrientation(currentVideo)
238
  if (newOrientation) {
239
- orientation = newOrientation
240
  }
241
  } catch (err) {
242
- console.error(`failed to get the media orientation`)
243
  }
244
  set({
245
- currentVideoOrientation: orientation
246
  })
247
 
248
  // get().syncStatusAndStageState()
@@ -359,10 +359,10 @@ export const useStore = create<{
359
  storyPrompt
360
  )
361
 
362
- const orientation = parseMediaOrientation(fullClap.meta.orientation)
363
 
364
- fullClap.meta.height = orientation === ClapMediaOrientation.LANDSCAPE ? RESOLUTION_SHORT : RESOLUTION_LONG
365
- fullClap.meta.width = orientation === ClapMediaOrientation.PORTRAIT ? RESOLUTION_SHORT : RESOLUTION_LONG
366
 
367
  const embeddedFinalVideoAssetUrl = fullClap.segments.filter(s =>
368
  s.category === ClapSegmentCategory.VIDEO &&
@@ -374,9 +374,9 @@ export const useStore = create<{
374
  set({
375
  fullClap,
376
  storyPrompt,
377
- orientation,
378
  currentVideo: embeddedFinalVideoAssetUrl || get().currentVideo,
379
- currentVideoOrientation: orientation,
380
  })
381
 
382
  return {
 
1
  "use client"
2
 
3
+ import { ClapProject, parseClap, serializeClap, ClapImageRatio, parseImageRatio, ClapSegmentCategory, newSegment, getClapAssetSourceType, ClapSegmentStatus } from "@aitube/clap"
4
  import { create } from "zustand"
5
 
6
  import { GenerationStage, GlobalStatus, TaskStatus } from "@/types"
7
+ import { getImageRatio } from "@/lib/utils/getImageRatio"
8
 
9
  import { RESOLUTION_LONG, RESOLUTION_SHORT } from "./server/config"
10
  import { putTextInTextAreaElement } from "@/lib/utils/putTextInTextAreaElement"
 
15
  mainCharacterVoice: string
16
  storyPrompt: string
17
 
18
+ // the desired imageRatio for the next video
19
+ // but this won't impact the actual imageRatio of the fake device container
20
+ imageRatio: ClapImageRatio
21
 
22
  status: GlobalStatus
23
  stage: GenerationStage
 
43
 
44
  currentVideo: string
45
 
46
+ // imageRatio of the currently loaded video (which can be different from `imageRatio`)
47
+ // it will impact the actual imageRatio of the fake device container
48
+ currentImageRatio: ClapImageRatio
49
  progress: number
50
  error: string
51
  showAuthWall: boolean
52
  setShowAuthWall: (showAuthWall: boolean) => void
53
  toggleOrientation: () => void
54
+ setImageRatio: (imageRatio: ClapImageRatio) => void
55
+ setCurrentVideoOrientation: (currentImageRatio: ClapImageRatio) => void
56
  setMainCharacterImage: (mainCharacterImage: string) => void
57
  setMainCharacterVoice: (mainCharacterVoice: string) => void
58
  setStoryPrompt: (storyPrompt: string) => void
 
70
  setSkeletonClap: (fullClap?: ClapProject) => void
71
  setFullClap: (fullClap?: ClapProject) => void
72
 
73
+ // note: this will preload the video, and compute the imageRatio too
74
  setCurrentVideo: (currentVideo: string) => Promise<void>
75
 
76
  setProgress: (progress: number) => void
 
86
  mainCharacterVoice: "",
87
  storyPromptDraft: defaultPrompt,
88
  storyPrompt: "",
89
+ imageRatio: ClapImageRatio.PORTRAIT,
90
  status: "idle",
91
  stage: "idle",
92
  statusMessage: "",
 
103
  skeletonClap: undefined,
104
  fullClap: undefined,
105
  currentVideo: "",
106
+ currentImageRatio: ClapImageRatio.PORTRAIT,
107
  progress: 0,
108
  error: "",
109
  showAuthWall: false,
110
  setShowAuthWall: (showAuthWall: boolean) => { set({ showAuthWall }) },
111
  toggleOrientation: () => {
112
+ const { imageRatio: previousOrientation, currentImageRatio, currentVideo } = get()
113
+ const imageRatio =
114
+ previousOrientation === ClapImageRatio.LANDSCAPE
115
+ ? ClapImageRatio.PORTRAIT
116
+ : ClapImageRatio.LANDSCAPE
117
 
118
  set({
119
+ imageRatio,
120
 
121
+ // we normally don't touch the currentImageRatio since it will already contain a video
122
+ currentImageRatio:
123
  currentVideo
124
+ ? currentImageRatio
125
+ : imageRatio
126
  })
127
  },
128
+ setImageRatio: (imageRatio: ClapImageRatio) => {
129
+ const { currentImageRatio, currentVideo } = get()
130
 
131
  set({
132
+ imageRatio,
133
 
134
+ // we normally don't touch the currentImageRatio since it will already contain a video
135
+ currentImageRatio:
136
  currentVideo
137
+ ? currentImageRatio
138
+ : imageRatio
139
  })
140
  },
141
+ setCurrentVideoOrientation: (currentImageRatio: ClapImageRatio) => { set({ currentImageRatio }) },
142
  setMainCharacterImage: (mainCharacterImage: string) => { set({ mainCharacterImage }) },
143
  setMainCharacterVoice: (mainCharacterVoice: string) => { set({ mainCharacterVoice }) },
144
  setStoryPrompt: (storyPrompt: string) => { set({ storyPrompt }) },
 
231
  set({
232
  currentVideo,
233
  })
234
+ const { currentImageRatio } = get()
235
+ let imageRatio: ClapImageRatio = currentImageRatio
236
  try {
237
+ let newOrientation = await getImageRatio(currentVideo)
238
  if (newOrientation) {
239
+ imageRatio = newOrientation
240
  }
241
  } catch (err) {
242
+ console.error(`failed to get the media imageRatio`)
243
  }
244
  set({
245
+ currentImageRatio: imageRatio
246
  })
247
 
248
  // get().syncStatusAndStageState()
 
359
  storyPrompt
360
  )
361
 
362
+ const imageRatio = parseImageRatio(fullClap.meta.imageRatio)
363
 
364
+ fullClap.meta.height = imageRatio === ClapImageRatio.LANDSCAPE ? RESOLUTION_SHORT : RESOLUTION_LONG
365
+ fullClap.meta.width = imageRatio === ClapImageRatio.PORTRAIT ? RESOLUTION_SHORT : RESOLUTION_LONG
366
 
367
  const embeddedFinalVideoAssetUrl = fullClap.segments.filter(s =>
368
  s.category === ClapSegmentCategory.VIDEO &&
 
374
  set({
375
  fullClap,
376
  storyPrompt,
377
+ imageRatio,
378
  currentVideo: embeddedFinalVideoAssetUrl || get().currentVideo,
379
+ currentImageRatio: imageRatio,
380
  })
381
 
382
  return {
src/lib/hooks/useOrientation.ts CHANGED
@@ -1,21 +1,21 @@
1
  import { useStore } from "@/app/store"
2
- import { ClapMediaOrientation } from "@aitube/clap"
3
 
4
  export function useOrientation() {
5
- const orientation = useStore(s => s.orientation)
6
- const setOrientation = useStore(s => s.setOrientation)
7
- const currentVideoOrientation = useStore(s => s.currentVideoOrientation)
8
  const toggleOrientation = useStore(s => s.toggleOrientation)
9
- // note: we are interested in the *current* video orientation,
10
- // not the requested video orientation requested for the next video
11
- const isLandscape = currentVideoOrientation === ClapMediaOrientation.LANDSCAPE
12
- const isPortrait = currentVideoOrientation === ClapMediaOrientation.PORTRAIT
13
- const isSquare = currentVideoOrientation === ClapMediaOrientation.SQUARE
14
 
15
  return {
16
- orientation,
17
- setOrientation,
18
- currentVideoOrientation,
19
  toggleOrientation,
20
  isLandscape,
21
  isPortrait,
 
1
  import { useStore } from "@/app/store"
2
+ import { ClapImageRatio } from "@aitube/clap"
3
 
4
  export function useOrientation() {
5
+ const imageRatio = useStore(s => s.imageRatio)
6
+ const setImageRatio = useStore(s => s.setImageRatio)
7
+ const currentImageRatio = useStore(s => s.currentImageRatio)
8
  const toggleOrientation = useStore(s => s.toggleOrientation)
9
+ // note: we are interested in the *current* video imageRatio,
10
+ // not the requested video imageRatio requested for the next video
11
+ const isLandscape = currentImageRatio === ClapImageRatio.LANDSCAPE
12
+ const isPortrait = currentImageRatio === ClapImageRatio.PORTRAIT
13
+ const isSquare = currentImageRatio === ClapImageRatio.SQUARE
14
 
15
  return {
16
+ imageRatio,
17
+ setImageRatio,
18
+ currentImageRatio,
19
  toggleOrientation,
20
  isLandscape,
21
  isPortrait,
src/lib/hooks/useProcessors.ts CHANGED
@@ -74,7 +74,7 @@ export function useProcessors() {
74
 
75
  clap = await createClap({
76
  prompt: promptDraftRef.current,
77
- orientation: useStore.getState().orientation,
78
 
79
  turbo: false,
80
  })
@@ -264,22 +264,22 @@ export function useProcessors() {
264
  if (!clap) { throw new Error(`failed to edit the storyboards`) }
265
 
266
  // const fusion =
267
- console.log(`generateStoryboards(): received storyboards = `, clap)
268
 
269
  setImageGenerationStatus("finished")
270
- console.log("---------------- GENERATED STORYBOARDS ----------------")
271
  clap.segments
272
- .filter(s => s.category === ClapSegmentCategory.STORYBOARD)
273
  .forEach((s, i) => {
274
  if (s.status === ClapSegmentStatus.COMPLETED && s.assetUrl) {
275
  // console.log(` [${i}] storyboard: ${s.prompt}`)
276
  logImage(s.assetUrl, 0.35)
277
  } else {
278
- console.log(` [${i}] failed to generate storyboard`)
279
  }
280
  // console.log(`------------------`)
281
  })
282
- console.table(clap.segments.filter(s => s.category === ClapSegmentCategory.STORYBOARD), [
283
  'endTimeInMs',
284
  'prompt',
285
  'assetUrl'
@@ -376,14 +376,14 @@ export function useProcessors() {
376
  }
377
 
378
  const injectCharacters = async (clap: ClapProject): Promise<void> => {
379
- const storyboards = clap.segments.filter(s => s.category === ClapSegmentCategory.STORYBOARD)
380
 
381
  let mainCharacter = clap.entities.at(0)
382
 
383
  // let's do something basic for now: we only support 1 entity (character)
384
  // and we apply it to *all* the storyboards (we can always improve this later)
385
  if (mainCharacter) {
386
- console.log(`injectCharacters(): we use the clap's main character's face on all storyboards`)
387
  storyboards.forEach(storyboard => { storyboard.entityId = mainCharacter!.id })
388
  logImage(mainCharacter.imageId, 0.35)
389
  } else if (mainCharacterImage) {
 
74
 
75
  clap = await createClap({
76
  prompt: promptDraftRef.current,
77
+ imageRatio: useStore.getState().imageRatio,
78
 
79
  turbo: false,
80
  })
 
264
  if (!clap) { throw new Error(`failed to edit the storyboards`) }
265
 
266
  // const fusion =
267
+ console.log(`generateStoryboards(): received storyboard images = `, clap)
268
 
269
  setImageGenerationStatus("finished")
270
+ console.log("---------------- GENERATED STORYBOARD IMAGES ----------------")
271
  clap.segments
272
+ .filter(s => s.category === ClapSegmentCategory.IMAGE)
273
  .forEach((s, i) => {
274
  if (s.status === ClapSegmentStatus.COMPLETED && s.assetUrl) {
275
  // console.log(` [${i}] storyboard: ${s.prompt}`)
276
  logImage(s.assetUrl, 0.35)
277
  } else {
278
+ console.log(` [${i}] failed to generate storyboard images`)
279
  }
280
  // console.log(`------------------`)
281
  })
282
+ console.table(clap.segments.filter(s => s.category === ClapSegmentCategory.IMAGE), [
283
  'endTimeInMs',
284
  'prompt',
285
  'assetUrl'
 
376
  }
377
 
378
  const injectCharacters = async (clap: ClapProject): Promise<void> => {
379
+ const storyboards = clap.segments.filter(s => s.category === ClapSegmentCategory.IMAGE)
380
 
381
  let mainCharacter = clap.entities.at(0)
382
 
383
  // let's do something basic for now: we only support 1 entity (character)
384
  // and we apply it to *all* the storyboards (we can always improve this later)
385
  if (mainCharacter) {
386
+ console.log(`injectCharacters(): we use the clap's main character's face on all storyboard images`)
387
  storyboards.forEach(storyboard => { storyboard.entityId = mainCharacter!.id })
388
  logImage(mainCharacter.imageId, 0.35)
389
  } else if (mainCharacterImage) {
src/lib/hooks/useProgressTimer.ts CHANGED
@@ -1,10 +1,12 @@
 
 
1
  import { useStore } from "@/app/store"
2
  import { useEffect, useRef } from "react"
3
  import { useIsBusy } from "./useIsBusy"
4
 
5
  export function useProgressTimer() {
6
  const runningRef = useRef(false)
7
- const timerRef = useRef<NodeJS.Timeout>()
8
 
9
  const progress = useStore(s => s.progress)
10
  const stage = useStore(s => s.stage)
 
1
+ "use client"
2
+
3
  import { useStore } from "@/app/store"
4
  import { useEffect, useRef } from "react"
5
  import { useIsBusy } from "./useIsBusy"
6
 
7
  export function useProgressTimer() {
8
  const runningRef = useRef(false)
9
+ const timerRef = useRef<Timer>()
10
 
11
  const progress = useStore(s => s.progress)
12
  const stage = useStore(s => s.stage)
src/lib/hooks/useQueryStringParams.ts CHANGED
@@ -1,6 +1,6 @@
1
  import { useEffect } from "react"
2
  import { useSearchParams } from "next/navigation"
3
- import { ClapMediaOrientation } from "@aitube/clap"
4
 
5
  import { useStore } from "@/app/store"
6
 
@@ -13,24 +13,24 @@ export function useQueryStringParams() {
13
  const { busyRef } = useIsBusy()
14
  const { handleCreateStory } = useProcessors()
15
 
16
- const setOrientation = useStore(s => s.setOrientation)
17
  // this is how we support query string parameters
18
  // ?prompt=hello <- set a default prompt
19
  // ?prompt=hello&autorun=true <- automatically run the app
20
- // ?orientation=landscape <- can be "landscape" or "portrait" (default)
21
  const searchParams = useSearchParams()
22
  const queryStringPrompt = (searchParams?.get('prompt') as string) || ""
23
  const queryStringAutorun = (searchParams?.get('autorun') as string) || ""
24
- const queryStringOrientation = (searchParams?.get('orientation') as string) || ""
25
 
26
  useEffect(() => {
27
  if (queryStringOrientation?.length > 1) {
28
- console.log(`orientation = "${queryStringOrientation}"`)
29
- const orientation =
30
  queryStringOrientation.trim().toLowerCase() === "landscape"
31
- ? ClapMediaOrientation.LANDSCAPE
32
- : ClapMediaOrientation.PORTRAIT
33
- setOrientation(orientation)
34
  }
35
  if (queryStringPrompt?.length > 1) {
36
  console.log(`prompt = "${queryStringPrompt}"`)
 
1
  import { useEffect } from "react"
2
  import { useSearchParams } from "next/navigation"
3
+ import { ClapImageRatio } from "@aitube/clap"
4
 
5
  import { useStore } from "@/app/store"
6
 
 
13
  const { busyRef } = useIsBusy()
14
  const { handleCreateStory } = useProcessors()
15
 
16
+ const setImageRatio = useStore(s => s.setImageRatio)
17
  // this is how we support query string parameters
18
  // ?prompt=hello <- set a default prompt
19
  // ?prompt=hello&autorun=true <- automatically run the app
20
+ // ?imageRatio=landscape <- can be "landscape" or "portrait" (default)
21
  const searchParams = useSearchParams()
22
  const queryStringPrompt = (searchParams?.get('prompt') as string) || ""
23
  const queryStringAutorun = (searchParams?.get('autorun') as string) || ""
24
+ const queryStringOrientation = (searchParams?.get('imageRatio') as string) || ""
25
 
26
  useEffect(() => {
27
  if (queryStringOrientation?.length > 1) {
28
+ console.log(`imageRatio = "${queryStringOrientation}"`)
29
+ const imageRatio =
30
  queryStringOrientation.trim().toLowerCase() === "landscape"
31
+ ? ClapImageRatio.LANDSCAPE
32
+ : ClapImageRatio.PORTRAIT
33
+ setImageRatio(imageRatio)
34
  }
35
  if (queryStringPrompt?.length > 1) {
36
  console.log(`prompt = "${queryStringPrompt}"`)
src/lib/utils/{getVideoOrientation.ts → getImageRatio.ts} RENAMED
@@ -1,19 +1,19 @@
1
- import { ClapMediaOrientation } from "@aitube/clap"
2
 
3
  /**
4
- * Determine the video orientation from a video URL (data-uri or hosted)
5
  *
6
  * @param url
7
  * @returns
8
  */
9
- export async function getVideoOrientation(url: string): Promise<ClapMediaOrientation> {
10
- return new Promise<ClapMediaOrientation>(resolve => {
11
  const video = document.createElement('video')
12
  video.addEventListener( "loadedmetadata", function () {
13
  resolve(
14
- this.videoHeight < this.videoWidth ? ClapMediaOrientation.LANDSCAPE :
15
- this.videoHeight > this.videoWidth ? ClapMediaOrientation.PORTRAIT :
16
- ClapMediaOrientation.SQUARE
17
  )
18
  }, false)
19
  video.src = url
 
1
+ import { ClapImageRatio } from "@aitube/clap"
2
 
3
  /**
4
+ * Determine the video imageRatio from a video URL (data-uri or hosted)
5
  *
6
  * @param url
7
  * @returns
8
  */
9
+ export async function getImageRatio(url: string): Promise<ClapImageRatio> {
10
+ return new Promise<ClapImageRatio>(resolve => {
11
  const video = document.createElement('video')
12
  video.addEventListener( "loadedmetadata", function () {
13
  resolve(
14
+ this.videoHeight < this.videoWidth ? ClapImageRatio.LANDSCAPE :
15
+ this.videoHeight > this.videoWidth ? ClapImageRatio.PORTRAIT :
16
+ ClapImageRatio.SQUARE
17
  )
18
  }, false)
19
  video.src = url