jbilcke-hf HF staff commited on
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&apos;m experimenting at the current time.
26
- </p>
27
  <p>
28
- πŸ‘‰ Right now it uses an API that you can <a className="text-stone-600 underline" href="https://github.com/jbilcke-hf/Hotshot-XL-Gradio-API" target="_blank">fork from here</a>. This API is based on the amazing work made by <a className="text-stone-600 underline" href="https://huggingface.co/fffiloni" target="_blank">@fffiloni</a> for his super cool <a className="text-stone-600 underline" href="https://huggingface.co/spaces/fffiloni/text-to-gif" target="_blank">Hotshot-XL Space</a>.
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: "768x320", // "1024x512", // "512x512" // "320x768"
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: 'Hotshot-XL Text-to-GIF 🧞',
16
- description: 'Hotshot-XL Text-to-GIF 🧞',
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
  }) {