Commit
β’
80175c8
1
Parent(s):
18e5e63
add countdown
Browse files
TODO.md
CHANGED
@@ -1,4 +1,3 @@
|
|
1 |
-
Find a name (hotshot factory? gipher? gif factory? fun factory?)
|
2 |
|
3 |
Allow browsing some loras
|
4 |
|
|
|
|
|
1 |
|
2 |
Allow browsing some loras
|
3 |
|
src/app/interface/about/index.tsx
CHANGED
@@ -21,15 +21,9 @@ export function About() {
|
|
21 |
</DialogDescription>
|
22 |
</DialogHeader>
|
23 |
<div className="grid gap-4 py-4 text-stone-800">
|
24 |
-
<p className="">
|
25 |
-
The model used by the AI Clip Factory depends on what I'm experimenting at the current time.
|
26 |
-
</p>
|
27 |
<p>
|
28 |
-
π
|
29 |
</p>
|
30 |
-
<p>
|
31 |
-
π The model is <a className="text-stone-600 underline" href="https://huggingface.co/hotshotco/Hotshot-XL" target="_blank">Hotshot-XL</a> made by the awesome <a className="text-stone-600 underline" href="https://hotshot.co" target="_blank">hotshot.co team</a>.
|
32 |
-
</p>
|
33 |
</div>
|
34 |
<DialogFooter>
|
35 |
<Button type="submit" onClick={() => setOpen(false)}>Got it</Button>
|
|
|
21 |
</DialogDescription>
|
22 |
</DialogHeader>
|
23 |
<div className="grid gap-4 py-4 text-stone-800">
|
|
|
|
|
|
|
24 |
<p>
|
25 |
+
π This space generates clips using <a className="text-stone-600 underline" href="https://github.com/jbilcke-hf/Hotshot-XL-Gradio-API" target="_blank">Hotshot-XL-Gradio-API</a>, a fork of <a className="text-stone-600 underline" href="https://huggingface.co/spaces/fffiloni/text-to-gif" target="_blank">fffiloni/text-to-gif</a>.
|
26 |
</p>
|
|
|
|
|
|
|
27 |
</div>
|
28 |
<DialogFooter>
|
29 |
<Button type="submit" onClick={() => setOpen(false)}>Got it</Button>
|
src/app/interface/countdown/index.tsx
ADDED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { cn } from "@/lib/utils"
|
2 |
+
|
3 |
+
export function Countdown({
|
4 |
+
remainingTimeInSec,
|
5 |
+
progressPercent
|
6 |
+
}: {
|
7 |
+
remainingTimeInSec: number,
|
8 |
+
progressPercent: number
|
9 |
+
}) {
|
10 |
+
return (
|
11 |
+
<div
|
12 |
+
className={cn(
|
13 |
+
`z-20`,
|
14 |
+
`fixed top-8 right-8`,
|
15 |
+
`radial-progress text-primary-content border-4`,
|
16 |
+
`transition-all duration-1000`,
|
17 |
+
`bg-sky-600/30`,
|
18 |
+
`border-sky-800/30`,
|
19 |
+
`text-blue-100`
|
20 |
+
|
21 |
+
)}
|
22 |
+
style={{
|
23 |
+
"--value": progressPercent
|
24 |
+
} as any}
|
25 |
+
>{
|
26 |
+
remainingTimeInSec
|
27 |
+
}s
|
28 |
+
</div>
|
29 |
+
)
|
30 |
+
}
|
src/app/interface/generate/index.tsx
CHANGED
@@ -8,6 +8,8 @@ import { headingFont } from "@/app/interface/fonts"
|
|
8 |
import { useCharacterLimit } from "@/lib/useCharacterLimit"
|
9 |
import { generateAnimation } from "@/app/server/actions/animation"
|
10 |
import { postToCommunity } from "@/app/server/actions/community"
|
|
|
|
|
11 |
|
12 |
export function Generate() {
|
13 |
const [_isPending, startTransition] = useTransition()
|
@@ -17,6 +19,13 @@ export function Generate() {
|
|
17 |
const [assetUrl, setAssetUrl] = useState("")
|
18 |
const [isOverSubmitButton, setOverSubmitButton] = useState(false)
|
19 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
20 |
const { shouldWarn, colorClass, nbCharsUsed, nbCharsLimits } = useCharacterLimit({
|
21 |
value: promptDraft,
|
22 |
nbCharsLimits: 70,
|
@@ -41,6 +50,7 @@ export function Generate() {
|
|
41 |
console.log("handleSubmit:", { isLocked, promptDraft })
|
42 |
if (isLocked) { return }
|
43 |
if (!promptDraft) { return }
|
|
|
44 |
setLocked(true)
|
45 |
startTransition(async () => {
|
46 |
const huggingFaceLora = "KappaNeuro/studio-ghibli-style"
|
@@ -73,7 +83,7 @@ export function Generate() {
|
|
73 |
// foundation
|
74 |
// replicateLora: "https://pbxt.replicate.delivery/VHU109Irgh6EPJrZ7aVScvadYDqXhlL3izfEAjfhs8Cvz0hRA/trained_model.tar",
|
75 |
|
76 |
-
size: "
|
77 |
|
78 |
nbFrames: 8, // if duration is 1000ms then it means 8 FPS
|
79 |
duration: 1000, // in ms
|
@@ -105,6 +115,10 @@ export function Generate() {
|
|
105 |
`transition-all duration-300 ease-in-out`,
|
106 |
// panel === "play" ? "opacity-1 translate-x-0" : "opacity-0 translate-x-[-1000px] pointer-events-none"
|
107 |
)}>
|
|
|
|
|
|
|
|
|
108 |
<div className={cn(
|
109 |
`flex flex-col md:flex-row`,
|
110 |
`w-full md:max-w-4xl lg:max-w-5xl xl:max-w-6xl max-h-[80vh]`,
|
|
|
8 |
import { useCharacterLimit } from "@/lib/useCharacterLimit"
|
9 |
import { generateAnimation } from "@/app/server/actions/animation"
|
10 |
import { postToCommunity } from "@/app/server/actions/community"
|
11 |
+
import { useCountdown } from "@/lib/useCountdown"
|
12 |
+
import { Countdown } from "../countdown"
|
13 |
|
14 |
export function Generate() {
|
15 |
const [_isPending, startTransition] = useTransition()
|
|
|
19 |
const [assetUrl, setAssetUrl] = useState("")
|
20 |
const [isOverSubmitButton, setOverSubmitButton] = useState(false)
|
21 |
|
22 |
+
const [runs, setRuns] = useState(0)
|
23 |
+
const { progressPercent, remainingTimeInSec } = useCountdown({
|
24 |
+
timerId: runs, // everytime we change this, the timer will reset
|
25 |
+
durationInSec: 40,
|
26 |
+
onEnd: () => {}
|
27 |
+
})
|
28 |
+
|
29 |
const { shouldWarn, colorClass, nbCharsUsed, nbCharsLimits } = useCharacterLimit({
|
30 |
value: promptDraft,
|
31 |
nbCharsLimits: 70,
|
|
|
50 |
console.log("handleSubmit:", { isLocked, promptDraft })
|
51 |
if (isLocked) { return }
|
52 |
if (!promptDraft) { return }
|
53 |
+
setRuns(runs + 1)
|
54 |
setLocked(true)
|
55 |
startTransition(async () => {
|
56 |
const huggingFaceLora = "KappaNeuro/studio-ghibli-style"
|
|
|
83 |
// foundation
|
84 |
// replicateLora: "https://pbxt.replicate.delivery/VHU109Irgh6EPJrZ7aVScvadYDqXhlL3izfEAjfhs8Cvz0hRA/trained_model.tar",
|
85 |
|
86 |
+
size: "672x384", // "1024x512", // "512x512" // "320x768"
|
87 |
|
88 |
nbFrames: 8, // if duration is 1000ms then it means 8 FPS
|
89 |
duration: 1000, // in ms
|
|
|
115 |
`transition-all duration-300 ease-in-out`,
|
116 |
// panel === "play" ? "opacity-1 translate-x-0" : "opacity-0 translate-x-[-1000px] pointer-events-none"
|
117 |
)}>
|
118 |
+
{isLocked ? <Countdown
|
119 |
+
progressPercent={progressPercent}
|
120 |
+
remainingTimeInSec={remainingTimeInSec}
|
121 |
+
/> : null}
|
122 |
<div className={cn(
|
123 |
`flex flex-col md:flex-row`,
|
124 |
`w-full md:max-w-4xl lg:max-w-5xl xl:max-w-6xl max-h-[80vh]`,
|
src/app/layout.tsx
CHANGED
@@ -12,8 +12,8 @@ export const metadata: Metadata = {
|
|
12 |
// GIF Factory
|
13 |
// GIF Magic
|
14 |
// AI GIF Genie
|
15 |
-
title: '
|
16 |
-
description: '
|
17 |
}
|
18 |
|
19 |
export default function RootLayout({
|
|
|
12 |
// GIF Factory
|
13 |
// GIF Magic
|
14 |
// AI GIF Genie
|
15 |
+
title: 'AI Clip Factory π§',
|
16 |
+
description: 'AI Clip Factory π§',
|
17 |
}
|
18 |
|
19 |
export default function RootLayout({
|
src/app/server/actions/generateWithGradioApi.ts
CHANGED
@@ -15,7 +15,7 @@ export async function generateVideoWithGradioAPI({
|
|
15 |
steps = 30,
|
16 |
}: VideoOptions): Promise<string> {
|
17 |
console.log(`SEND TO ${gradioApi + (gradioApi.endsWith("/") ? "" : "/") + "api/predict"}:`, [
|
18 |
-
accessToken,
|
19 |
positivePrompt,
|
20 |
negativePrompt,
|
21 |
huggingFaceLora,
|
|
|
15 |
steps = 30,
|
16 |
}: VideoOptions): Promise<string> {
|
17 |
console.log(`SEND TO ${gradioApi + (gradioApi.endsWith("/") ? "" : "/") + "api/predict"}:`, [
|
18 |
+
// accessToken,
|
19 |
positivePrompt,
|
20 |
negativePrompt,
|
21 |
huggingFaceLora,
|
src/lib/useCountdown.ts
CHANGED
@@ -7,7 +7,7 @@ export function useCountdown({
|
|
7 |
durationInSec,
|
8 |
onEnd = () => {},
|
9 |
}: {
|
10 |
-
timerId: string
|
11 |
durationInSec: number
|
12 |
onEnd: () => void
|
13 |
}) {
|
|
|
7 |
durationInSec,
|
8 |
onEnd = () => {},
|
9 |
}: {
|
10 |
+
timerId: string | number
|
11 |
durationInSec: number
|
12 |
onEnd: () => void
|
13 |
}) {
|