jbilcke-hf HF staff commited on
Commit
58132fb
1 Parent(s): 846ea5b

bump to aitube/client 0.0.7

Browse files
package-lock.json CHANGED
@@ -8,8 +8,8 @@
8
  "name": "@jbilcke-hf/ai-stories-factory",
9
  "version": "0.0.0",
10
  "dependencies": {
11
- "@aitube/clap": "^0.0.6",
12
- "@aitube/client": "^0.0.4",
13
  "@radix-ui/react-accordion": "^1.1.2",
14
  "@radix-ui/react-avatar": "^1.0.4",
15
  "@radix-ui/react-checkbox": "^1.0.4",
@@ -62,9 +62,9 @@
62
  }
63
  },
64
  "node_modules/@aitube/clap": {
65
- "version": "0.0.6",
66
- "resolved": "https://registry.npmjs.org/@aitube/clap/-/clap-0.0.6.tgz",
67
- "integrity": "sha512-SPo90RBnOJCmp+DqzxllNOcp38AbHSzqkAbYEudRiubqWHDF1GGqYi25gCdG7bFIWH+8evjSiiwsjkzedpbhoA==",
68
  "dependencies": {
69
  "pure-uuid": "^1.8.1",
70
  "yaml": "^2.4.1"
@@ -74,15 +74,15 @@
74
  }
75
  },
76
  "node_modules/@aitube/client": {
77
- "version": "0.0.4",
78
- "resolved": "https://registry.npmjs.org/@aitube/client/-/client-0.0.4.tgz",
79
- "integrity": "sha512-LzOYgwSKJVslGbTEP3DEsgh5/EWupv04HNoTt3hxDQBo9/I5AF/ZwoLBDQR3QTu1i3spMJ61Sl0gVtrXxp2q3A==",
80
  "dependencies": {
81
  "uuid": "^9.0.1",
82
  "yaml": "^2.4.1"
83
  },
84
  "peerDependencies": {
85
- "@aitube/clap": "^0.0.6",
86
  "typescript": "^5.4.5"
87
  }
88
  },
@@ -190,28 +190,28 @@
190
  }
191
  },
192
  "node_modules/@floating-ui/core": {
193
- "version": "1.6.0",
194
- "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.0.tgz",
195
- "integrity": "sha512-PcF++MykgmTj3CIyOQbKA/hDzOAiqI3mhuoN44WRCopIs1sgoDoU4oty4Jtqaj/y3oDU6fnVSm4QG0a3t5i0+g==",
196
  "dependencies": {
197
- "@floating-ui/utils": "^0.2.1"
198
  }
199
  },
200
  "node_modules/@floating-ui/dom": {
201
- "version": "1.6.3",
202
- "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.3.tgz",
203
- "integrity": "sha512-RnDthu3mzPlQ31Ss/BTwQ1zjzIhr3lk1gZB1OC56h/1vEtaXkESrOqL5fQVMfXpwGtRwX+YsZBdyHtJMQnkArw==",
204
  "dependencies": {
205
  "@floating-ui/core": "^1.0.0",
206
  "@floating-ui/utils": "^0.2.0"
207
  }
208
  },
209
  "node_modules/@floating-ui/react-dom": {
210
- "version": "2.0.8",
211
- "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.8.tgz",
212
- "integrity": "sha512-HOdqOt3R3OGeTKidaLvJKcgg75S6tibQ3Tif4eyd91QnIJWr0NLvoXFpJA/j8HqkFSL68GDca9AuyWEHlhyClw==",
213
  "dependencies": {
214
- "@floating-ui/dom": "^1.6.1"
215
  },
216
  "peerDependencies": {
217
  "react": ">=16.8.0",
@@ -219,9 +219,9 @@
219
  }
220
  },
221
  "node_modules/@floating-ui/utils": {
222
- "version": "0.2.1",
223
- "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.1.tgz",
224
- "integrity": "sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q=="
225
  },
226
  "node_modules/@humanwhocodes/config-array": {
227
  "version": "0.11.14",
@@ -3127,9 +3127,9 @@
3127
  }
3128
  },
3129
  "node_modules/caniuse-lite": {
3130
- "version": "1.0.30001612",
3131
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001612.tgz",
3132
- "integrity": "sha512-lFgnZ07UhaCcsSZgWW0K5j4e69dK1u/ltrL9lTUiFOwNHs12S3UMIEYgBV0Z6C6hRDev7iRnMzzYmKabYdXF9g==",
3133
  "funding": [
3134
  {
3135
  "type": "opencollective",
@@ -5477,9 +5477,9 @@
5477
  }
5478
  },
5479
  "node_modules/lru-cache": {
5480
- "version": "10.2.1",
5481
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.1.tgz",
5482
- "integrity": "sha512-tS24spDe/zXhWbNPErCHs/AGOzbKGHT+ybSBqmdLm8WZ1xXLWvH8Qn71QPAlqVhd0qUTWjy+Kl9JmISgDdEjsA==",
5483
  "engines": {
5484
  "node": "14 || >=16.14"
5485
  }
@@ -7816,9 +7816,9 @@
7816
  "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
7817
  },
7818
  "node_modules/yaml": {
7819
- "version": "2.4.1",
7820
- "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.1.tgz",
7821
- "integrity": "sha512-pIXzoImaqmfOrL7teGUBt/T7ZDnyeGBWyXQBvOVhLkWLN37GXv8NMLK406UY6dS51JfcQHsmcW5cJ441bHg6Lg==",
7822
  "bin": {
7823
  "yaml": "bin.mjs"
7824
  },
 
8
  "name": "@jbilcke-hf/ai-stories-factory",
9
  "version": "0.0.0",
10
  "dependencies": {
11
+ "@aitube/clap": "0.0.7",
12
+ "@aitube/client": "0.0.7",
13
  "@radix-ui/react-accordion": "^1.1.2",
14
  "@radix-ui/react-avatar": "^1.0.4",
15
  "@radix-ui/react-checkbox": "^1.0.4",
 
62
  }
63
  },
64
  "node_modules/@aitube/clap": {
65
+ "version": "0.0.7",
66
+ "resolved": "https://registry.npmjs.org/@aitube/clap/-/clap-0.0.7.tgz",
67
+ "integrity": "sha512-0muPu4G1sRsNqSVZ/ICBCc4QibZ9OT33ORbahPP1+h3GYcD/7K+ZLYJjdbQwJWVEcpKDosDVaQKeNYdab0S0LA==",
68
  "dependencies": {
69
  "pure-uuid": "^1.8.1",
70
  "yaml": "^2.4.1"
 
74
  }
75
  },
76
  "node_modules/@aitube/client": {
77
+ "version": "0.0.7",
78
+ "resolved": "https://registry.npmjs.org/@aitube/client/-/client-0.0.7.tgz",
79
+ "integrity": "sha512-s6vxst7pkLt7tI96JS508gfk4EgdLJy5Itr76ej/zvtMRMgnKgAlfB6Bb8/1u7L5CToz4Wgk6h4kz8T+yEbEeg==",
80
  "dependencies": {
81
  "uuid": "^9.0.1",
82
  "yaml": "^2.4.1"
83
  },
84
  "peerDependencies": {
85
+ "@aitube/clap": "0.0.7",
86
  "typescript": "^5.4.5"
87
  }
88
  },
 
190
  }
191
  },
192
  "node_modules/@floating-ui/core": {
193
+ "version": "1.6.1",
194
+ "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.1.tgz",
195
+ "integrity": "sha512-42UH54oPZHPdRHdw6BgoBD6cg/eVTmVrFcgeRDM3jbO7uxSoipVcmcIGFcA5jmOHO5apcyvBhkSKES3fQJnu7A==",
196
  "dependencies": {
197
+ "@floating-ui/utils": "^0.2.0"
198
  }
199
  },
200
  "node_modules/@floating-ui/dom": {
201
+ "version": "1.6.4",
202
+ "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.4.tgz",
203
+ "integrity": "sha512-0G8R+zOvQsAG1pg2Q99P21jiqxqGBW1iRe/iXHsBRBxnpXKFI8QwbB4x5KmYLggNO5m34IQgOIu9SCRfR/WWiQ==",
204
  "dependencies": {
205
  "@floating-ui/core": "^1.0.0",
206
  "@floating-ui/utils": "^0.2.0"
207
  }
208
  },
209
  "node_modules/@floating-ui/react-dom": {
210
+ "version": "2.0.9",
211
+ "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.9.tgz",
212
+ "integrity": "sha512-q0umO0+LQK4+p6aGyvzASqKbKOJcAHJ7ycE9CuUvfx3s9zTHWmGJTPOIlM/hmSBfUfg/XfY5YhLBLR/LHwShQQ==",
213
  "dependencies": {
214
+ "@floating-ui/dom": "^1.0.0"
215
  },
216
  "peerDependencies": {
217
  "react": ">=16.8.0",
 
219
  }
220
  },
221
  "node_modules/@floating-ui/utils": {
222
+ "version": "0.2.2",
223
+ "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.2.tgz",
224
+ "integrity": "sha512-J4yDIIthosAsRZ5CPYP/jQvUAQtlZTTD/4suA08/FEnlxqW3sKS9iAhgsa9VYLZ6vDHn/ixJgIqRQPotoBjxIw=="
225
  },
226
  "node_modules/@humanwhocodes/config-array": {
227
  "version": "0.11.14",
 
3127
  }
3128
  },
3129
  "node_modules/caniuse-lite": {
3130
+ "version": "1.0.30001614",
3131
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001614.tgz",
3132
+ "integrity": "sha512-jmZQ1VpmlRwHgdP1/uiKzgiAuGOfLEJsYFP4+GBou/QQ4U6IOJCB4NP1c+1p9RGLpwObcT94jA5/uO+F1vBbog==",
3133
  "funding": [
3134
  {
3135
  "type": "opencollective",
 
5477
  }
5478
  },
5479
  "node_modules/lru-cache": {
5480
+ "version": "10.2.2",
5481
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz",
5482
+ "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==",
5483
  "engines": {
5484
  "node": "14 || >=16.14"
5485
  }
 
7816
  "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
7817
  },
7818
  "node_modules/yaml": {
7819
+ "version": "2.4.2",
7820
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.2.tgz",
7821
+ "integrity": "sha512-B3VqDZ+JAg1nZpaEmWtTXUlBneoGx6CPM9b0TENK6aoSu5t73dItudwdgmi6tHlIZZId4dZ9skcAQ2UbcyAeVA==",
7822
  "bin": {
7823
  "yaml": "bin.mjs"
7824
  },
package.json CHANGED
@@ -9,8 +9,8 @@
9
  "lint": "next lint"
10
  },
11
  "dependencies": {
12
- "@aitube/clap": "^0.0.6",
13
- "@aitube/client": "^0.0.4",
14
  "@radix-ui/react-accordion": "^1.1.2",
15
  "@radix-ui/react-avatar": "^1.0.4",
16
  "@radix-ui/react-checkbox": "^1.0.4",
 
9
  "lint": "next lint"
10
  },
11
  "dependencies": {
12
+ "@aitube/clap": "0.0.7",
13
+ "@aitube/client": "0.0.7",
14
  "@radix-ui/react-accordion": "^1.1.2",
15
  "@radix-ui/react-avatar": "^1.0.4",
16
  "@radix-ui/react-checkbox": "^1.0.4",
src/app/hf-logo.svg ADDED
src/app/main.tsx CHANGED
@@ -1,21 +1,25 @@
1
  "use client"
2
 
3
- import React, { useEffect, useRef, useState, useTransition } from 'react'
4
  import { ClapProject } from '@aitube/clap'
 
 
 
5
 
6
  import { Card, CardContent, CardHeader } from '@/components/ui/card'
7
  import { Button } from '@/components/ui/button'
8
  import { Toaster } from '@/components/ui/sonner'
 
9
  import { cn } from '@/lib/utils/cn'
10
 
11
- import { useStore } from './store'
12
- import { TextareaField } from '@/components/form/textarea-field'
13
- import { DeviceFrameset } from 'react-device-frameset'
14
- import 'react-device-frameset/styles/marvel-devices.min.css'
15
  import { createClap } from './server/aitube/createClap'
 
16
  import { editClapStoryboards } from './server/aitube/editClapStoryboards'
17
  import { exportClapToVideo } from './server/aitube/exportClapToVideo'
18
 
 
 
 
19
  export function Main() {
20
  const [_isPending, startTransition] = useTransition()
21
  const storyPromptDraft = useStore(s => s.storyPromptDraft)
@@ -25,6 +29,8 @@ export function Main() {
25
  const voiceGenerationStatus = useStore(s => s.voiceGenerationStatus)
26
  const imageGenerationStatus = useStore(s => s.imageGenerationStatus)
27
  const videoGenerationStatus = useStore(s => s.videoGenerationStatus)
 
 
28
  const setStoryPromptDraft = useStore(s => s.setStoryPromptDraft)
29
  const setStoryPrompt = useStore(s => s.setStoryPrompt)
30
  const setStatus = useStore(s => s.setStatus)
@@ -32,6 +38,8 @@ export function Main() {
32
  const setVoiceGenerationStatus = useStore(s => s.setVoiceGenerationStatus)
33
  const setImageGenerationStatus = useStore(s => s.setImageGenerationStatus)
34
  const setVideoGenerationStatus = useStore(s => s.setVideoGenerationStatus)
 
 
35
 
36
  const hasPendingTasks =
37
  storyGenerationStatus === "generating" ||
@@ -55,7 +63,10 @@ export function Main() {
55
  try {
56
  clap = await createClap({ prompt })
57
 
 
 
58
  console.log(`handleSubmit(): received a clap = `, clap)
 
59
  setStoryGenerationStatus("finished")
60
  } catch (err) {
61
  setStoryGenerationStatus("error")
@@ -66,11 +77,17 @@ export function Main() {
66
  return
67
  }
68
 
 
 
 
69
  try {
70
  setImageGenerationStatus("generating")
71
  clap = await editClapStoryboards({ clap })
72
 
 
 
73
  console.log(`handleSubmit(): received a clap with images = `, clap)
 
74
  setImageGenerationStatus("finished")
75
  } catch (err) {
76
  setImageGenerationStatus("error")
@@ -81,6 +98,25 @@ export function Main() {
81
  return
82
  }
83
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84
  let assetUrl = ""
85
  try {
86
  setVideoGenerationStatus("generating")
@@ -96,7 +132,8 @@ export function Main() {
96
  if (!assetUrl) {
97
  return
98
  }
99
-
 
100
  setStatus("finished")
101
  })
102
  }
@@ -105,25 +142,51 @@ export function Main() {
105
  <div className={cn(
106
  `fixed`,
107
  // `bg-zinc-800`,
108
- `bg-gradient-to-br from-amber-600 to-yellow-500`,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109
  // `bg-gradient-to-br from-sky-400 to-sky-300/30`,
110
- `w-screen h-screen overflow-y-scroll md:overflow-hidden`,
111
  )}
112
  style={{ boxShadow: "inset 0 0px 250px 0 rgb(0 0 0 / 60%)" }}>
113
- <div className="flex flex-col w-full">
114
  <div className="
115
  flex flex-col md:flex-row w-full
 
 
116
  "
117
  >
118
  <div className={cn(
119
- `flex flex-col w-full md:w-[512px]`,
120
- `transition-all duration-300 ease-in-out`,
121
- `ml-0 lg:ml-12`,
122
- `pt-4 sm:pt-8 md:pt-16 lg:pt-24`,
 
123
  )}>
124
  <Card className={cn(
125
  // `shadow-2xl z-30 rounded-3xl`,
126
  `shadow-none`,
 
 
127
  `bg-transparent dark:bg-transparent`,
128
  // `backdrop-blur-2xl dark:backdrop-blur-2xl`,
129
  // `bg-amber-500 dark:bg-amber-500`,
@@ -188,7 +251,7 @@ export function Main() {
188
  pt-2 md:pt-4
189
  "
190
  style={{ textShadow: "rgb(255 255 255 / 19%) 0px 0px 2px" }}
191
- >Generate video stories using AI ✨</p>
192
  </div>
193
  </CardHeader>
194
  <CardContent className="flex flex-col">
@@ -198,7 +261,7 @@ export function Main() {
198
  space-y-2 md:space-y-4 mt-0
199
  ">
200
  <TextareaField
201
- label="My story:"
202
  // disabled={modelState != 'ready'}
203
  onChange={(e) => {
204
  setStoryPromptDraft(e.target.value)
@@ -214,7 +277,28 @@ export function Main() {
214
  </div>
215
  <div className="flex-flex-row space-y-3 pt-4">
216
  <div className="flex flex-row justify-end items-center">
217
- <div className="flex flex-row justify-between items-center space-x-3">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
218
  <Button
219
  onClick={handleSubmit}
220
  disabled={!storyPromptDraft || isBusy}
@@ -227,14 +311,23 @@ export function Main() {
227
  storyPromptDraft ? "opacity-100" : "opacity-80"
228
  )}
229
  >
230
- <span className="mr-1">Generate</span><span className="hidden md:inline">👉</span><span className="inline md:hidden">👇</span>
231
  </Button>
232
  </div>
233
  </div>
234
- <div className="text-stone-900/90 dark:text-stone-100/90 text-xs w-full text-right">
 
 
 
235
  {isBusy
236
- ? `Generation in progress (${status})`
237
- : ""
 
 
 
 
 
 
238
  }
239
  </div>
240
  </div>
@@ -242,10 +335,11 @@ export function Main() {
242
  </Card>
243
  </div>
244
  <div className={cn(
245
- `flex flex-col items-center justify-start md:justify-center`,
246
- `flex-1`,
247
- `md:h-screen`,
248
- // `transition-all duration-300 ease-in-out`
 
249
  )}>
250
 
251
  <div className={cn(`
@@ -256,12 +350,49 @@ export function Main() {
256
  <DeviceFrameset
257
  device="Nexus 5"
258
  // color="black"
 
 
 
 
 
259
  >
260
- <div className="bg-black w-full h-full text-white">Hello world</div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
261
  </DeviceFrameset>
262
  </div>
263
  </div>
264
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
265
  </div>
266
  <Toaster />
267
  </div>
 
1
  "use client"
2
 
3
+ import React, { useTransition } from 'react'
4
  import { ClapProject } from '@aitube/clap'
5
+ import Image from "next/image"
6
+ import { DeviceFrameset } from 'react-device-frameset'
7
+ import 'react-device-frameset/styles/marvel-devices.min.css'
8
 
9
  import { Card, CardContent, CardHeader } from '@/components/ui/card'
10
  import { Button } from '@/components/ui/button'
11
  import { Toaster } from '@/components/ui/sonner'
12
+ import { TextareaField } from '@/components/form/textarea-field'
13
  import { cn } from '@/lib/utils/cn'
14
 
 
 
 
 
15
  import { createClap } from './server/aitube/createClap'
16
+ import { editClapDialogues } from './server/aitube/editClapDialogues'
17
  import { editClapStoryboards } from './server/aitube/editClapStoryboards'
18
  import { exportClapToVideo } from './server/aitube/exportClapToVideo'
19
 
20
+ import { useStore } from './store'
21
+ import HFLogo from "./hf-logo.svg"
22
+
23
  export function Main() {
24
  const [_isPending, startTransition] = useTransition()
25
  const storyPromptDraft = useStore(s => s.storyPromptDraft)
 
29
  const voiceGenerationStatus = useStore(s => s.voiceGenerationStatus)
30
  const imageGenerationStatus = useStore(s => s.imageGenerationStatus)
31
  const videoGenerationStatus = useStore(s => s.videoGenerationStatus)
32
+ const generatedClap = useStore(s => s.generatedClap)
33
+ const generatedVideo = useStore(s => s.generatedVideo)
34
  const setStoryPromptDraft = useStore(s => s.setStoryPromptDraft)
35
  const setStoryPrompt = useStore(s => s.setStoryPrompt)
36
  const setStatus = useStore(s => s.setStatus)
 
38
  const setVoiceGenerationStatus = useStore(s => s.setVoiceGenerationStatus)
39
  const setImageGenerationStatus = useStore(s => s.setImageGenerationStatus)
40
  const setVideoGenerationStatus = useStore(s => s.setVideoGenerationStatus)
41
+ const setGeneratedClap = useStore(s => s.setGeneratedClap)
42
+ const setGeneratedVideo = useStore(s => s.setGeneratedVideo)
43
 
44
  const hasPendingTasks =
45
  storyGenerationStatus === "generating" ||
 
63
  try {
64
  clap = await createClap({ prompt })
65
 
66
+ if (!clap) { throw new Error(`failed to create the clap`) }
67
+
68
  console.log(`handleSubmit(): received a clap = `, clap)
69
+ setGeneratedClap(clap)
70
  setStoryGenerationStatus("finished")
71
  } catch (err) {
72
  setStoryGenerationStatus("error")
 
77
  return
78
  }
79
 
80
+ // TODO Julian
81
+ console.log("handleSubmit(): TODO Julian: generate images in parallel of the dialogue using Promise.all()")
82
+
83
  try {
84
  setImageGenerationStatus("generating")
85
  clap = await editClapStoryboards({ clap })
86
 
87
+ if (!clap) { throw new Error(`failed to edit the storyboards`) }
88
+
89
  console.log(`handleSubmit(): received a clap with images = `, clap)
90
+ setGeneratedClap(clap)
91
  setImageGenerationStatus("finished")
92
  } catch (err) {
93
  setImageGenerationStatus("error")
 
98
  return
99
  }
100
 
101
+
102
+ try {
103
+ setVoiceGenerationStatus("generating")
104
+ clap = await editClapDialogues({ clap })
105
+
106
+ if (!clap) { throw new Error(`failed to edit the dialogues`) }
107
+
108
+ console.log(`handleSubmit(): received a clap with dialogues = `, clap)
109
+ setGeneratedClap(clap)
110
+ setVoiceGenerationStatus("finished")
111
+ } catch (err) {
112
+ setVoiceGenerationStatus("error")
113
+ setStatus("error")
114
+ return
115
+ }
116
+ if (!clap) {
117
+ return
118
+ }
119
+
120
  let assetUrl = ""
121
  try {
122
  setVideoGenerationStatus("generating")
 
132
  if (!assetUrl) {
133
  return
134
  }
135
+
136
+ setGeneratedVideo(assetUrl)
137
  setStatus("finished")
138
  })
139
  }
 
142
  <div className={cn(
143
  `fixed`,
144
  // `bg-zinc-800`,
145
+ // old style, more "amber"
146
+ // `bg-gradient-to-br from-amber-600 to-yellow-500`,
147
+
148
+ // nice style!
149
+ // `bg-gradient-to-br from-amber-700 to-yellow-300`,
150
+
151
+ // warm orange, a bit flash but not bad, not bad at all
152
+ // `bg-gradient-to-br from-orange-700 to-yellow-400`,
153
+
154
+ // nice "AiTube" vibe
155
+ `bg-gradient-to-br from-red-700 to-yellow-400`,
156
+
157
+ // pretty cool lime!
158
+ // `bg-gradient-to-br from-lime-700 to-yellow-400`,
159
+
160
+ // new style, pretty "fresh" - maybe too bright?
161
+ // use a dark logo for this one
162
+ // `bg-gradient-to-br from-yellow-200 to-yellow-500`,
163
+
164
+ // too pastel
165
+ // `bg-gradient-to-br from-yellow-200 to-red-300`,
166
+
167
  // `bg-gradient-to-br from-sky-400 to-sky-300/30`,
168
+ `w-screen h-full overflow-y-scroll md:overflow-hidden`,
169
  )}
170
  style={{ boxShadow: "inset 0 0px 250px 0 rgb(0 0 0 / 60%)" }}>
171
+ <div className="flex flex-col w-screen h-screen">
172
  <div className="
173
  flex flex-col md:flex-row w-full
174
+ items-center md:justify-center
175
+ flex-1
176
  "
177
  >
178
  <div className={cn(
179
+ `flex flex-col md:h-full md:items-center md:justify-center`,
180
+ `w-full md:w-1/2`,
181
+ `transition-all duration-200 ease-in-out`,
182
+ `ml-0`,
183
+ `pt-4 sm:pt-0`,
184
  )}>
185
  <Card className={cn(
186
  // `shadow-2xl z-30 rounded-3xl`,
187
  `shadow-none`,
188
+ `w-full md:ml-[12%] md:w-[95%]`,
189
+ `transition-all duration-200 ease-in-out`,
190
  `bg-transparent dark:bg-transparent`,
191
  // `backdrop-blur-2xl dark:backdrop-blur-2xl`,
192
  // `bg-amber-500 dark:bg-amber-500`,
 
251
  pt-2 md:pt-4
252
  "
253
  style={{ textShadow: "rgb(255 255 255 / 19%) 0px 0px 2px" }}
254
+ >Make vertical video stories using AI ✨</p>
255
  </div>
256
  </CardHeader>
257
  <CardContent className="flex flex-col">
 
261
  space-y-2 md:space-y-4 mt-0
262
  ">
263
  <TextareaField
264
+ // label="My story:"
265
  // disabled={modelState != 'ready'}
266
  onChange={(e) => {
267
  setStoryPromptDraft(e.target.value)
 
277
  </div>
278
  <div className="flex-flex-row space-y-3 pt-4">
279
  <div className="flex flex-row justify-end items-center">
280
+ <div className="
281
+ w-full
282
+ flex flex-row
283
+ justify-end items-center
284
+ space-x-3">
285
+ {/*
286
+ <Button
287
+ onClick={handleSubmit}
288
+ disabled={!storyPromptDraft || isBusy || !generatedClap}
289
+ // variant="ghost"
290
+ className={cn(
291
+ `text-sm md:text-base lg:text-lg`,
292
+ `bg-stone-800/90 text-amber-400/100 dark:bg-stone-800/90 dark:text-amber-400/100`,
293
+ `font-bold`,
294
+ `hover:bg-stone-800/100 hover:text-amber-300/100 dark:hover:bg-stone-800/100 dark:hover:text-amber-300/100`,
295
+ storyPromptDraft ? "opacity-100" : "opacity-80"
296
+ )}
297
+ >
298
+ <span className="mr-1">Save</span>
299
+ </Button>
300
+ */}
301
+
302
  <Button
303
  onClick={handleSubmit}
304
  disabled={!storyPromptDraft || isBusy}
 
311
  storyPromptDraft ? "opacity-100" : "opacity-80"
312
  )}
313
  >
314
+ <span className="mr-1.5">Create</span><span className="hidden md:inline">👉</span><span className="inline md:hidden">👇</span>
315
  </Button>
316
  </div>
317
  </div>
318
+ <div className="
319
+ text-stone-900/90 dark:text-stone-100/90
320
+ text-sm md:text-base lg:text-lg
321
+ w-full text-right">
322
  {isBusy
323
+ ? (
324
+ storyGenerationStatus === "generating" ? "Enhancing the story.."
325
+ : imageGenerationStatus === "generating" ? "Generating storyboards.."
326
+ : voiceGenerationStatus === "generating" ? "Generating voices.."
327
+ : videoGenerationStatus === "generating" ? "Assembling final video.."
328
+ : "Please wait.."
329
+ )
330
+ : <span>&nbsp;</span> // to prevent layout changes
331
  }
332
  </div>
333
  </div>
 
335
  </Card>
336
  </div>
337
  <div className={cn(
338
+ `flex flex-col items-center justify-center`,
339
+ `flex-1 h-full`,
340
+ // `transition-all duration-200 ease-in-out`
341
+
342
+ `-mt-[100px] -mb-[90px] md:-mt-0 md:-mb-0`,
343
  )}>
344
 
345
  <div className={cn(`
 
350
  <DeviceFrameset
351
  device="Nexus 5"
352
  // color="black"
353
+
354
+ // note: videos are generated in 512x1024
355
+ // so we need to keep the same ratio here
356
+ width={256}
357
+ height={512}
358
  >
359
+ <div className="
360
+ flex flex-col items-center justify-center
361
+ w-full h-full
362
+ bg-black text-white
363
+ ">
364
+ {generatedVideo && <video
365
+ src={generatedVideo}
366
+ controls
367
+ autoPlay
368
+ playsInline
369
+ muted
370
+ loop
371
+ className="object-cover"
372
+ style={{
373
+ }}
374
+ />}
375
+ </div>
376
  </DeviceFrameset>
377
  </div>
378
  </div>
379
  </div>
380
+
381
+ <div className="
382
+ flex flex-row items-center justify-end
383
+ w-full p-6
384
+ font-sans">
385
+ <span className="text-stone-950/60 text-2xs"
386
+ style={{ textShadow: "rgb(255 255 255 / 19%) 0px 0px 2px" }}>
387
+ Powered by
388
+ </span>
389
+ <span className="ml-1.5 mr-1">
390
+ <Image src={HFLogo} alt="Hugging Face" width="16" height="16" />
391
+ </span>
392
+ <span className="text-stone-950/60 text-xs font-bold"
393
+ style={{ textShadow: "rgb(255 255 255 / 19%) 0px 0px 2px" }}>Hugging Face</span>
394
+
395
+ </div>
396
  </div>
397
  <Toaster />
398
  </div>
src/app/page.tsx CHANGED
@@ -21,9 +21,9 @@ export default function Page() {
21
  <meta name="viewport" content="width=device-width, initial-scale=0.86, maximum-scale=5.0, minimum-scale=0.86" />
22
  </Head>
23
  <main className={cn(
24
- `light text-cyan-900`,
25
- // `bg-gradient-to-r from-green-500 to-yellow-400`,
26
- `bg-gradient-to-r from-cyan-500 to-blue-400`,
27
  )}>
28
  {isLoaded && <Main />}
29
  </main>
 
21
  <meta name="viewport" content="width=device-width, initial-scale=0.86, maximum-scale=5.0, minimum-scale=0.86" />
22
  </Head>
23
  <main className={cn(
24
+ ``,
25
+ `text-stone-900/90 dark:text-stone-100/90`,
26
+ `bg-stone-500`,
27
  )}>
28
  {isLoaded && <Main />}
29
  </main>
src/app/server/aitube/createClap.ts CHANGED
@@ -12,6 +12,11 @@ export async function createClap({
12
  }): Promise<ClapProject> {
13
  const clap: ClapProject = await apiCreateClap({
14
  prompt,
 
 
 
 
 
15
  token: await getToken()
16
  })
17
 
 
12
  }): Promise<ClapProject> {
13
  const clap: ClapProject = await apiCreateClap({
14
  prompt,
15
+
16
+ // the vertical video look 🤳
17
+ height: 1024,
18
+ width: 512,
19
+
20
  token: await getToken()
21
  })
22
 
src/app/server/aitube/editClapDialogues.ts ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "use server"
2
+
3
+ import { ClapProject } from "@aitube/clap"
4
+ import { editClapDialogues as apiEditClapDialogues } from "@aitube/client"
5
+
6
+ import { getToken } from "./getToken"
7
+
8
+ export async function editClapDialogues({
9
+ clap,
10
+ }: {
11
+ clap: ClapProject
12
+ }): Promise<ClapProject> {
13
+ const newClap: ClapProject = await apiEditClapDialogues({
14
+ clap,
15
+ token: await getToken()
16
+ })
17
+
18
+ return newClap
19
+ }
src/app/store.ts CHANGED
@@ -1,6 +1,7 @@
1
  "use client"
2
 
3
  import { GlobalStatus, TaskStatus } from "@/types"
 
4
  import { create } from "zustand"
5
 
6
  export const useStore = create<{
@@ -11,6 +12,8 @@ export const useStore = create<{
11
  voiceGenerationStatus: TaskStatus
12
  imageGenerationStatus: TaskStatus
13
  videoGenerationStatus: TaskStatus
 
 
14
  setStoryPromptDraft: (storyPromptDraft: string) => void
15
  setStoryPrompt: (storyPrompt: string) => void
16
  setStatus: (status: GlobalStatus) => void
@@ -18,6 +21,8 @@ export const useStore = create<{
18
  setVoiceGenerationStatus: (voiceGenerationStatus: TaskStatus) => void
19
  setImageGenerationStatus: (imageGenerationStatus: TaskStatus) => void
20
  setVideoGenerationStatus: (videoGenerationStatus: TaskStatus) => void
 
 
21
  }>((set, get) => ({
22
  storyPromptDraft: "Yesterday I was at my favorite pizza place and..",
23
  storyPrompt: "",
@@ -26,6 +31,8 @@ export const useStore = create<{
26
  voiceGenerationStatus: "idle",
27
  imageGenerationStatus: "idle",
28
  videoGenerationStatus: "idle",
 
 
29
  setStoryPromptDraft: (storyPromptDraft: string) => { set({ storyPromptDraft }) },
30
  setStoryPrompt: (storyPrompt: string) => { set({ storyPrompt }) },
31
  setStatus: (status: GlobalStatus) => { set({ status }) },
@@ -33,4 +40,6 @@ export const useStore = create<{
33
  setVoiceGenerationStatus: (voiceGenerationStatus: TaskStatus) => { set({ voiceGenerationStatus }) },
34
  setImageGenerationStatus: (imageGenerationStatus: TaskStatus) => { set({ imageGenerationStatus }) },
35
  setVideoGenerationStatus: (videoGenerationStatus: TaskStatus) => { set({ videoGenerationStatus }) },
 
 
36
  }))
 
1
  "use client"
2
 
3
  import { GlobalStatus, TaskStatus } from "@/types"
4
+ import { ClapProject } from "@aitube/clap"
5
  import { create } from "zustand"
6
 
7
  export const useStore = create<{
 
12
  voiceGenerationStatus: TaskStatus
13
  imageGenerationStatus: TaskStatus
14
  videoGenerationStatus: TaskStatus
15
+ generatedClap?: ClapProject
16
+ generatedVideo: string
17
  setStoryPromptDraft: (storyPromptDraft: string) => void
18
  setStoryPrompt: (storyPrompt: string) => void
19
  setStatus: (status: GlobalStatus) => void
 
21
  setVoiceGenerationStatus: (voiceGenerationStatus: TaskStatus) => void
22
  setImageGenerationStatus: (imageGenerationStatus: TaskStatus) => void
23
  setVideoGenerationStatus: (videoGenerationStatus: TaskStatus) => void
24
+ setGeneratedClap: (generatedClap?: ClapProject) => void
25
+ setGeneratedVideo: (generatedVideo: string) => void
26
  }>((set, get) => ({
27
  storyPromptDraft: "Yesterday I was at my favorite pizza place and..",
28
  storyPrompt: "",
 
31
  voiceGenerationStatus: "idle",
32
  imageGenerationStatus: "idle",
33
  videoGenerationStatus: "idle",
34
+ generatedClap: undefined,
35
+ generatedVideo: "",
36
  setStoryPromptDraft: (storyPromptDraft: string) => { set({ storyPromptDraft }) },
37
  setStoryPrompt: (storyPrompt: string) => { set({ storyPrompt }) },
38
  setStatus: (status: GlobalStatus) => { set({ status }) },
 
40
  setVoiceGenerationStatus: (voiceGenerationStatus: TaskStatus) => { set({ voiceGenerationStatus }) },
41
  setImageGenerationStatus: (imageGenerationStatus: TaskStatus) => { set({ imageGenerationStatus }) },
42
  setVideoGenerationStatus: (videoGenerationStatus: TaskStatus) => { set({ videoGenerationStatus }) },
43
+ setGeneratedClap: (generatedClap?: ClapProject) => { set({ generatedClap }) },
44
+ setGeneratedVideo: (generatedVideo: string) => { set({ generatedVideo }) },
45
  }))
src/components/form/textarea-field.tsx CHANGED
@@ -21,16 +21,19 @@ export function TextareaField({
21
  `flex flex-col space-y-3 items-start`,
22
  className
23
  )}>
24
- {label && <Label className={cn(`
25
- text-base md:text-lg lg:text-xl
26
- text-stone-900/90 dark:text-stone-100/90
27
- `, labelClassName)}
28
  style={{ textShadow: "rgb(255 255 255 / 19%) 0px 0px 2px" }}>{label}</Label>}
29
  <Textarea {...props} className={cn(`
30
  text-base md:text-lg lg:text-xl
31
  rounded-lg md:rounded-xl lg:rounded-2xl
32
  border-2
33
- backdrop-blur-2xl
 
 
 
34
  border-stone-800/80 dark:border-stone-800/80
35
  outline-stone-800/80 dark:outline-stone-800/80
36
  ring-stone-800/80 dark:ring-stone-800/80
 
21
  `flex flex-col space-y-3 items-start`,
22
  className
23
  )}>
24
+ {label && <Label className={cn(
25
+ `text-base md:text-lg lg:text-xl`,
26
+ `text-stone-900/90 dark:text-stone-100/90`,
27
+ labelClassName)}
28
  style={{ textShadow: "rgb(255 255 255 / 19%) 0px 0px 2px" }}>{label}</Label>}
29
  <Textarea {...props} className={cn(`
30
  text-base md:text-lg lg:text-xl
31
  rounded-lg md:rounded-xl lg:rounded-2xl
32
  border-2
33
+
34
+ bg-stone-800/90 text-amber-400/100
35
+ dark:bg-stone-800/90 dark:text-amber-400/100
36
+
37
  border-stone-800/80 dark:border-stone-800/80
38
  outline-stone-800/80 dark:outline-stone-800/80
39
  ring-stone-800/80 dark:ring-stone-800/80