Commit
•
58132fb
1
Parent(s):
846ea5b
bump to aitube/client 0.0.7
Browse files- package-lock.json +32 -32
- package.json +2 -2
- src/app/hf-logo.svg +37 -0
- src/app/main.tsx +156 -25
- src/app/page.tsx +3 -3
- src/app/server/aitube/createClap.ts +5 -0
- src/app/server/aitube/editClapDialogues.ts +19 -0
- src/app/store.ts +9 -0
- src/components/form/textarea-field.tsx +8 -5
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": "
|
12 |
-
"@aitube/client": "
|
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.
|
66 |
-
"resolved": "https://registry.npmjs.org/@aitube/clap/-/clap-0.0.
|
67 |
-
"integrity": "sha512-
|
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.
|
78 |
-
"resolved": "https://registry.npmjs.org/@aitube/client/-/client-0.0.
|
79 |
-
"integrity": "sha512-
|
80 |
"dependencies": {
|
81 |
"uuid": "^9.0.1",
|
82 |
"yaml": "^2.4.1"
|
83 |
},
|
84 |
"peerDependencies": {
|
85 |
-
"@aitube/clap": "
|
86 |
"typescript": "^5.4.5"
|
87 |
}
|
88 |
},
|
@@ -190,28 +190,28 @@
|
|
190 |
}
|
191 |
},
|
192 |
"node_modules/@floating-ui/core": {
|
193 |
-
"version": "1.6.
|
194 |
-
"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.
|
195 |
-
"integrity": "sha512-
|
196 |
"dependencies": {
|
197 |
-
"@floating-ui/utils": "^0.2.
|
198 |
}
|
199 |
},
|
200 |
"node_modules/@floating-ui/dom": {
|
201 |
-
"version": "1.6.
|
202 |
-
"resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.
|
203 |
-
"integrity": "sha512-
|
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.
|
211 |
-
"resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.
|
212 |
-
"integrity": "sha512-
|
213 |
"dependencies": {
|
214 |
-
"@floating-ui/dom": "^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.
|
223 |
-
"resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.
|
224 |
-
"integrity": "sha512-
|
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.
|
3131 |
-
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.
|
3132 |
-
"integrity": "sha512-
|
3133 |
"funding": [
|
3134 |
{
|
3135 |
"type": "opencollective",
|
@@ -5477,9 +5477,9 @@
|
|
5477 |
}
|
5478 |
},
|
5479 |
"node_modules/lru-cache": {
|
5480 |
-
"version": "10.2.
|
5481 |
-
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.
|
5482 |
-
"integrity": "sha512-
|
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.
|
7820 |
-
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.
|
7821 |
-
"integrity": "sha512-
|
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": "
|
13 |
-
"@aitube/client": "
|
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, {
|
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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
109 |
// `bg-gradient-to-br from-sky-400 to-sky-300/30`,
|
110 |
-
`w-screen h-
|
111 |
)}
|
112 |
style={{ boxShadow: "inset 0 0px 250px 0 rgb(0 0 0 / 60%)" }}>
|
113 |
-
<div className="flex flex-col w-
|
114 |
<div className="
|
115 |
flex flex-col md:flex-row w-full
|
|
|
|
|
116 |
"
|
117 |
>
|
118 |
<div className={cn(
|
119 |
-
`flex flex-col
|
120 |
-
`
|
121 |
-
`
|
122 |
-
`
|
|
|
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 |
-
>
|
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="
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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">
|
231 |
</Button>
|
232 |
</div>
|
233 |
</div>
|
234 |
-
<div className="
|
|
|
|
|
|
|
235 |
{isBusy
|
236 |
-
?
|
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-
|
246 |
-
`flex-1`,
|
247 |
-
`
|
248 |
-
|
|
|
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="
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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> </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 |
-
|
25 |
-
|
26 |
-
`bg-
|
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 |
-
|
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 |
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
|