Commit
β’
c78f7b4
1
Parent(s):
6821e3e
polishing the design π
Browse files- README.md +2 -0
- src/app/layout.tsx +3 -3
- src/app/main.tsx +68 -23
- src/app/server/aitube/generateClap.ts +1 -1
- src/app/server/config.ts +6 -1
- src/app/store.ts +1 -1
- src/components/form/select-field.tsx +3 -1
- src/components/form/slider-field.tsx +4 -1
- src/components/form/textarea-field.tsx +17 -11
README.md
CHANGED
@@ -7,7 +7,9 @@ colorTo: yellow
|
|
7 |
pinned: true
|
8 |
app_port: 3000
|
9 |
disable_embedding: false
|
|
|
10 |
header: mini
|
|
|
11 |
---
|
12 |
|
13 |
This is a work in progress Space - thanks for your patience!
|
|
|
7 |
pinned: true
|
8 |
app_port: 3000
|
9 |
disable_embedding: false
|
10 |
+
hf_oauth: true
|
11 |
header: mini
|
12 |
+
short_description: Generate video stories using AI β¨
|
13 |
---
|
14 |
|
15 |
This is a work in progress Space - thanks for your patience!
|
src/app/layout.tsx
CHANGED
@@ -4,8 +4,8 @@ import type { Metadata } from 'next'
|
|
4 |
import { inter, salsa } from './fonts'
|
5 |
|
6 |
export const metadata: Metadata = {
|
7 |
-
title: '
|
8 |
-
description: '
|
9 |
}
|
10 |
|
11 |
export default function RootLayout({
|
@@ -16,7 +16,7 @@ export default function RootLayout({
|
|
16 |
return (
|
17 |
<html lang="en">
|
18 |
<body className={cn(
|
19 |
-
`h-full w-full overflow-none`,
|
20 |
salsa.className
|
21 |
)}>
|
22 |
{children}
|
|
|
4 |
import { inter, salsa } from './fonts'
|
5 |
|
6 |
export const metadata: Metadata = {
|
7 |
+
title: 'AI Stories Factory - Generate video stories using AI β¨',
|
8 |
+
description: 'AI Stories Factory - Generate video stories using AI β¨',
|
9 |
}
|
10 |
|
11 |
export default function RootLayout({
|
|
|
16 |
return (
|
17 |
<html lang="en">
|
18 |
<body className={cn(
|
19 |
+
`h-full w-full overflow-none light`,
|
20 |
salsa.className
|
21 |
)}>
|
22 |
{children}
|
src/app/main.tsx
CHANGED
@@ -4,7 +4,6 @@ import React, { useEffect, useRef, useState, useTransition } from 'react'
|
|
4 |
|
5 |
import { Card, CardContent, CardHeader } from '@/components/ui/card'
|
6 |
import { Button } from '@/components/ui/button'
|
7 |
-
import { InputField } from '@/components/form/input-field'
|
8 |
import { Toaster } from '@/components/ui/sonner'
|
9 |
import { cn } from '@/lib/utils/cn'
|
10 |
|
@@ -65,14 +64,18 @@ export function Main() {
|
|
65 |
// `bg-zinc-800`,
|
66 |
`bg-gradient-to-br from-amber-600 to-yellow-500`,
|
67 |
// `bg-gradient-to-br from-sky-400 to-sky-300/30`,
|
68 |
-
`w-screen h-screen overflow-hidden`,
|
69 |
)}>
|
70 |
<div className="flex flex-col w-full">
|
71 |
-
<div className="
|
|
|
|
|
|
|
72 |
<div className={cn(
|
73 |
`flex flex-col w-full md:w-[512px]`,
|
74 |
`transition-all duration-300 ease-in-out`,
|
75 |
-
`ml-
|
|
|
76 |
)}>
|
77 |
<Card className={cn(
|
78 |
// `shadow-2xl z-30 rounded-3xl`,
|
@@ -93,35 +96,74 @@ export function Main() {
|
|
93 |
<div className="
|
94 |
flex flex-row
|
95 |
items-center justify-center
|
96 |
-
|
97 |
px-3
|
98 |
|
99 |
rounded-full">
|
100 |
-
<div
|
|
|
101 |
flex
|
|
|
102 |
items-center justify-center text-center
|
103 |
-
w-
|
|
|
|
|
104 |
mr-2
|
105 |
font-sans
|
106 |
-
bg-
|
107 |
-
|
108 |
-
|
109 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
110 |
</div>
|
111 |
|
112 |
-
<p
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
113 |
</div>
|
114 |
</CardHeader>
|
115 |
<CardContent className="flex flex-col">
|
116 |
-
<div className="
|
|
|
|
|
|
|
|
|
117 |
<TextareaField
|
118 |
-
label="
|
119 |
// disabled={modelState != 'ready'}
|
120 |
onChange={(e) => {
|
121 |
setStoryPromptDraft(e.target.value)
|
122 |
}}
|
123 |
placeholder="Yesterday I was at my favorite pizza place and.."
|
124 |
-
inputClassName="
|
|
|
|
|
|
|
125 |
disabled={isBusy}
|
126 |
value={storyPromptDraft}
|
127 |
/>
|
@@ -131,16 +173,17 @@ export function Main() {
|
|
131 |
<div className="flex flex-row justify-between items-center space-x-3">
|
132 |
<Button
|
133 |
onClick={handleSubmit}
|
134 |
-
disabled={isBusy}
|
135 |
// variant="ghost"
|
136 |
className={cn(
|
137 |
-
`text-xl`,
|
138 |
-
`bg-stone-
|
139 |
`font-bold`,
|
140 |
-
`hover:bg-stone-
|
|
|
141 |
)}
|
142 |
>
|
143 |
-
|
144 |
</Button>
|
145 |
</div>
|
146 |
</div>
|
@@ -155,14 +198,16 @@ export function Main() {
|
|
155 |
</Card>
|
156 |
</div>
|
157 |
<div className={cn(
|
158 |
-
`flex flex-col items-center justify-center`,
|
159 |
`flex-1`,
|
160 |
-
`h-screen`,
|
161 |
// `transition-all duration-300 ease-in-out`
|
162 |
)}>
|
163 |
|
164 |
<div className={cn(`
|
165 |
-
|
|
|
|
|
166 |
`)}>
|
167 |
<DeviceFrameset
|
168 |
device="Nexus 5"
|
|
|
4 |
|
5 |
import { Card, CardContent, CardHeader } from '@/components/ui/card'
|
6 |
import { Button } from '@/components/ui/button'
|
|
|
7 |
import { Toaster } from '@/components/ui/sonner'
|
8 |
import { cn } from '@/lib/utils/cn'
|
9 |
|
|
|
64 |
// `bg-zinc-800`,
|
65 |
`bg-gradient-to-br from-amber-600 to-yellow-500`,
|
66 |
// `bg-gradient-to-br from-sky-400 to-sky-300/30`,
|
67 |
+
`w-screen h-screen overflow-y-scroll md:overflow-hidden`,
|
68 |
)}>
|
69 |
<div className="flex flex-col w-full">
|
70 |
+
<div className="
|
71 |
+
flex flex-col md:flex-row w-full
|
72 |
+
"
|
73 |
+
style={{ boxShadow: "inset 0 0px 250px 0 rgb(0 0 0 / 60%)" }}>
|
74 |
<div className={cn(
|
75 |
`flex flex-col w-full md:w-[512px]`,
|
76 |
`transition-all duration-300 ease-in-out`,
|
77 |
+
`ml-0 lg:ml-12`,
|
78 |
+
`pt-4 sm:pt-8 md:pt-16 lg:pt-24`,
|
79 |
)}>
|
80 |
<Card className={cn(
|
81 |
// `shadow-2xl z-30 rounded-3xl`,
|
|
|
96 |
<div className="
|
97 |
flex flex-row
|
98 |
items-center justify-center
|
99 |
+
transition-all duration-200 ease-in-out
|
100 |
px-3
|
101 |
|
102 |
rounded-full">
|
103 |
+
<div
|
104 |
+
className="
|
105 |
flex
|
106 |
+
transition-all duration-200 ease-in-out
|
107 |
items-center justify-center text-center
|
108 |
+
w-10 h-10 md:w-12 md:h-12 lg:w-16 lg:h-16
|
109 |
+
text-3xl md:text-4xl lg:text-5xl
|
110 |
+
rounded-lg
|
111 |
mr-2
|
112 |
font-sans
|
113 |
+
bg-amber-400 dark:bg-amber-400
|
114 |
+
|
115 |
+
text-stone-950/80 dark:text-stone-950/80 font-bold
|
116 |
+
"
|
117 |
+
>AI</div>
|
118 |
+
<div
|
119 |
+
className="
|
120 |
+
transition-all duration-200 ease-in-out
|
121 |
+
text-amber-400 dark:text-amber-400
|
122 |
+
text-3xl md:text-4xl lg:text-5xl
|
123 |
+
"
|
124 |
+
|
125 |
+
style={{ textShadow: "#00000035 0px 0px 2px" }}
|
126 |
+
|
127 |
+
/*
|
128 |
+
className="
|
129 |
+
text-5xl
|
130 |
+
bg-gradient-to-br from-yellow-300 to-yellow-500
|
131 |
+
inline-block text-transparent bg-clip-text
|
132 |
+
py-6
|
133 |
+
"
|
134 |
+
*/
|
135 |
+
>Stories Factory</div>
|
136 |
</div>
|
137 |
|
138 |
+
<p
|
139 |
+
className="
|
140 |
+
transition-all duration-200 ease-in-out
|
141 |
+
text-stone-900/90 dark:text-stone-100/90
|
142 |
+
text-lg md:text-xl lg:text-2xl
|
143 |
+
text-center
|
144 |
+
pt-2 md:pt-4
|
145 |
+
"
|
146 |
+
style={{ textShadow: "rgb(255 255 255 / 19%) 0px 0px 2px" }}
|
147 |
+
>Generate video stories using AI β¨</p>
|
148 |
</div>
|
149 |
</CardHeader>
|
150 |
<CardContent className="flex flex-col">
|
151 |
+
<div className="
|
152 |
+
flex flex-col
|
153 |
+
transition-all duration-200 ease-in-out
|
154 |
+
space-y-2 md:space-y-4 mt-0
|
155 |
+
">
|
156 |
<TextareaField
|
157 |
+
label="My story:"
|
158 |
// disabled={modelState != 'ready'}
|
159 |
onChange={(e) => {
|
160 |
setStoryPromptDraft(e.target.value)
|
161 |
}}
|
162 |
placeholder="Yesterday I was at my favorite pizza place and.."
|
163 |
+
inputClassName="
|
164 |
+
transition-all duration-200 ease-in-out
|
165 |
+
h-32 md:h-56 lg:h-64
|
166 |
+
"
|
167 |
disabled={isBusy}
|
168 |
value={storyPromptDraft}
|
169 |
/>
|
|
|
173 |
<div className="flex flex-row justify-between items-center space-x-3">
|
174 |
<Button
|
175 |
onClick={handleSubmit}
|
176 |
+
disabled={!storyPromptDraft || isBusy}
|
177 |
// variant="ghost"
|
178 |
className={cn(
|
179 |
+
`text-lg md:text-xl lg:text-2xl`,
|
180 |
+
`bg-stone-800/90 text-amber-400/100 dark:bg-stone-800/90 dark:text-amber-400/100`,
|
181 |
`font-bold`,
|
182 |
+
`hover:bg-stone-800/100 hover:text-amber-300/100 dark:hover:bg-stone-800/100 dark:hover:text-amber-300/100`,
|
183 |
+
storyPromptDraft ? "opacity-100" : "opacity-80"
|
184 |
)}
|
185 |
>
|
186 |
+
<span className="mr-1">Generate</span><span className="hidden md:inline">π</span><span className="inline md:hidden">π</span>
|
187 |
</Button>
|
188 |
</div>
|
189 |
</div>
|
|
|
198 |
</Card>
|
199 |
</div>
|
200 |
<div className={cn(
|
201 |
+
`flex flex-col items-center justify-start md:justify-center`,
|
202 |
`flex-1`,
|
203 |
+
`md:h-screen`,
|
204 |
// `transition-all duration-300 ease-in-out`
|
205 |
)}>
|
206 |
|
207 |
<div className={cn(`
|
208 |
+
-mt-24 md:mt-0
|
209 |
+
transition-all duration-200 ease-in-out
|
210 |
+
scale-[0.7] md:scale-[0.9] lg:scale-[1.2]
|
211 |
`)}>
|
212 |
<DeviceFrameset
|
213 |
device="Nexus 5"
|
src/app/server/aitube/generateClap.ts
CHANGED
@@ -19,7 +19,7 @@ export async function generateClap({
|
|
19 |
// console.log(`calling `+ gradioApi + (gradioApi.endsWith("/") ? "" : "/") + "api/predict")
|
20 |
|
21 |
// remember: a space needs to be public for the classic fetch() to work
|
22 |
-
const res = await fetch(aitubeApiUrl
|
23 |
method: "POST",
|
24 |
headers: {
|
25 |
"Content-Type": "application/json",
|
|
|
19 |
// console.log(`calling `+ gradioApi + (gradioApi.endsWith("/") ? "" : "/") + "api/predict")
|
20 |
|
21 |
// remember: a space needs to be public for the classic fetch() to work
|
22 |
+
const res = await fetch(`${aitubeApiUrl}generate/story`, {
|
23 |
method: "POST",
|
24 |
headers: {
|
25 |
"Content-Type": "application/json",
|
src/app/server/config.ts
CHANGED
@@ -2,4 +2,9 @@
|
|
2 |
export const serverHuggingfaceApiKey = `${process.env.HF_API_TOKEN || ""}`
|
3 |
|
4 |
export const aitubeUrl = `${process.env.AI_TUBE_URL || "" }`
|
5 |
-
export const aitubeApiUrl =
|
|
|
|
|
|
|
|
|
|
|
|
2 |
export const serverHuggingfaceApiKey = `${process.env.HF_API_TOKEN || ""}`
|
3 |
|
4 |
export const aitubeUrl = `${process.env.AI_TUBE_URL || "" }`
|
5 |
+
export const aitubeApiUrl = aitubeUrl + (aitubeUrl.endsWith("/") ? "" : "/") + "api/"
|
6 |
+
|
7 |
+
console.log("debug:", {
|
8 |
+
aitubeUrl,
|
9 |
+
aitubeApiUrl,
|
10 |
+
})
|
src/app/store.ts
CHANGED
@@ -19,7 +19,7 @@ export const useStore = create<{
|
|
19 |
setImageGenerationStatus: (imageGenerationStatus: TaskStatus) => void
|
20 |
setVideoGenerationStatus: (videoGenerationStatus: TaskStatus) => void
|
21 |
}>((set, get) => ({
|
22 |
-
storyPromptDraft: "",
|
23 |
storyPrompt: "",
|
24 |
status: "idle",
|
25 |
storyGenerationStatus: "idle",
|
|
|
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: "",
|
24 |
status: "idle",
|
25 |
storyGenerationStatus: "idle",
|
src/components/form/select-field.tsx
CHANGED
@@ -21,7 +21,9 @@ export function SelectField({
|
|
21 |
`flex flex-col space-y-3 items-start`,
|
22 |
className
|
23 |
)}>
|
24 |
-
{label && <Label className={cn(
|
|
|
|
|
25 |
<Select {...props} />
|
26 |
</div>
|
27 |
)
|
|
|
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`, labelClassName)}>{label}</Label>}
|
27 |
<Select {...props} />
|
28 |
</div>
|
29 |
)
|
src/components/form/slider-field.tsx
CHANGED
@@ -21,7 +21,10 @@ export function SliderField({
|
|
21 |
`flex flex-col space-y-3 items-start`,
|
22 |
className
|
23 |
)}>
|
24 |
-
{label && <Label className={cn(
|
|
|
|
|
|
|
25 |
<Slider {...props} className={sliderClassName} />
|
26 |
</div>
|
27 |
)
|
|
|
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)}>{label}</Label>}
|
28 |
<Slider {...props} className={sliderClassName} />
|
29 |
</div>
|
30 |
)
|
src/components/form/textarea-field.tsx
CHANGED
@@ -22,19 +22,25 @@ export function TextareaField({
|
|
22 |
className
|
23 |
)}>
|
24 |
{label && <Label className={cn(`
|
25 |
-
text-
|
26 |
-
|
|
|
|
|
27 |
<Textarea {...props} className={cn(`
|
28 |
-
text-xl
|
29 |
-
rounded-2xl
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
ring-
|
|
|
35 |
placeholder:text-stone-900/50 dark:placeholder:text-stone-100/50
|
36 |
-
|
37 |
-
|
|
|
|
|
|
|
38 |
</div>
|
39 |
)
|
40 |
}
|
|
|
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
|
37 |
+
ring-offset-stone-800/0 dark:ring-offset-stone-800/0
|
38 |
placeholder:text-stone-900/50 dark:placeholder:text-stone-100/50
|
39 |
+
focus-visible:ring-amber-400/100 dark:focus-visible:ring-amber-400/100
|
40 |
+
p-2 md:p-4 lg:p-6
|
41 |
+
`, inputClassName)}
|
42 |
+
style={{ textShadow: "rgb(255 255 255 / 19%) 0px 0px 2px" }}
|
43 |
+
/>
|
44 |
</div>
|
45 |
)
|
46 |
}
|