Commit
β’
6eef442
1
Parent(s):
5a7544b
analytics + more flexible rate limit
Browse files- src/app/interface/generate/index.tsx +2 -2
- src/app/page.tsx +14 -2
- src/app/server/actions/animation.ts +19 -4
src/app/interface/generate/index.tsx
CHANGED
@@ -172,7 +172,7 @@ export function Generate() {
|
|
172 |
} else {
|
173 |
toast({
|
174 |
title: "We couldn't generate your video π",
|
175 |
-
description: "We
|
176 |
})
|
177 |
}
|
178 |
|
@@ -187,7 +187,7 @@ export function Generate() {
|
|
187 |
console.error("error, too many requests")
|
188 |
toast({
|
189 |
title: "Error: the free server is over capacity π",
|
190 |
-
description: "You can generate
|
191 |
})
|
192 |
setLocked(false)
|
193 |
return
|
|
|
172 |
} else {
|
173 |
toast({
|
174 |
title: "We couldn't generate your video π",
|
175 |
+
description: "We are probably over capacity, but you can try again π€",
|
176 |
})
|
177 |
}
|
178 |
|
|
|
187 |
console.error("error, too many requests")
|
188 |
toast({
|
189 |
title: "Error: the free server is over capacity π",
|
190 |
+
description: "You can generate 2 videos per minute π€ Please try again in a moment!",
|
191 |
})
|
192 |
setLocked(false)
|
193 |
return
|
src/app/page.tsx
CHANGED
@@ -1,10 +1,12 @@
|
|
1 |
"use client"
|
2 |
|
|
|
3 |
import Head from "next/head"
|
|
|
4 |
|
5 |
-
import { Main } from "./main"
|
6 |
import { cn } from "@/lib/utils"
|
7 |
-
|
|
|
8 |
|
9 |
// https://nextjs.org/docs/pages/building-your-application/optimizing/fonts
|
10 |
|
@@ -24,6 +26,16 @@ export default function Page() {
|
|
24 |
`bg-gradient-to-r from-cyan-500 to-blue-400`,
|
25 |
)}>
|
26 |
{isLoaded && <Main />}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
27 |
</main>
|
28 |
</>
|
29 |
)
|
|
|
1 |
"use client"
|
2 |
|
3 |
+
import { useEffect, useState } from "react"
|
4 |
import Head from "next/head"
|
5 |
+
import Script from "next/script"
|
6 |
|
|
|
7 |
import { cn } from "@/lib/utils"
|
8 |
+
|
9 |
+
import { Main } from "./main"
|
10 |
|
11 |
// https://nextjs.org/docs/pages/building-your-application/optimizing/fonts
|
12 |
|
|
|
26 |
`bg-gradient-to-r from-cyan-500 to-blue-400`,
|
27 |
)}>
|
28 |
{isLoaded && <Main />}
|
29 |
+
<Script src="https://www.googletagmanager.com/gtag/js?id=GTM-NJ2ZZFBX" />
|
30 |
+
<Script id="google-analytics">
|
31 |
+
{`
|
32 |
+
window.dataLayer = window.dataLayer || [];
|
33 |
+
function gtag(){dataLayer.push(arguments);}
|
34 |
+
gtag('js', new Date());
|
35 |
+
|
36 |
+
gtag('config', 'GTM-NJ2ZZFBX');
|
37 |
+
`}
|
38 |
+
</Script>
|
39 |
</main>
|
40 |
</>
|
41 |
)
|
src/app/server/actions/animation.ts
CHANGED
@@ -19,10 +19,23 @@ const redis = new Redis({
|
|
19 |
token: `${process.env.UPSTASH_REDIS_REST_TOKEN || ""}`,
|
20 |
})
|
21 |
|
22 |
-
// Create a
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
23 |
const rateLimitAnons = new Ratelimit({
|
24 |
redis,
|
25 |
-
limiter: Ratelimit.slidingWindow(
|
26 |
analytics: true,
|
27 |
timeout: 1000,
|
28 |
prefix: "production:anon"
|
@@ -48,16 +61,18 @@ export async function generateAnimation({
|
|
48 |
|
49 |
console.log(`user ${key.slice(0, 10)} requested "${cropped}${cropped !== positivePrompt ? "..." : ""}"`)
|
50 |
|
|
|
|
|
51 |
// this waits for 3 seconds before failing the request
|
52 |
// we don't wait more because it is frustrating for someone to wait a failure
|
53 |
-
const
|
54 |
// const rateLimitResult = await rateLimitAnons.blockUntilReady(key, 3_000)
|
55 |
|
56 |
// admin / developers will have this key:
|
57 |
// eff8e7ca506627fe15dda5e0e512fcaad70b6d520f37cc76597fdb4f2d83a1a3
|
58 |
|
59 |
// result.limit
|
60 |
-
if (!
|
61 |
console.log(`blocking user ${key.slice(0, 10)} who requested "${cropped}${cropped !== positivePrompt ? "..." : ""}"`)
|
62 |
throw new Error(`Rate Limit Reached`)
|
63 |
} else {
|
|
|
19 |
token: `${process.env.UPSTASH_REDIS_REST_TOKEN || ""}`,
|
20 |
})
|
21 |
|
22 |
+
// Create a global ratelimiter for all users, that allows 14 requests per 60 seconds
|
23 |
+
// 14 is roughly the number of requests that can be handled by the server
|
24 |
+
/*
|
25 |
+
const rateLimitGlobal = new Ratelimit({
|
26 |
+
redis,
|
27 |
+
limiter: Ratelimit.slidingWindow(14, "60 s"),
|
28 |
+
analytics: true,
|
29 |
+
timeout: 1000,
|
30 |
+
prefix: "production"
|
31 |
+
})
|
32 |
+
*/
|
33 |
+
|
34 |
+
|
35 |
+
// Create a new ratelimiter for anonymous users, that allows 2 requests per minute
|
36 |
const rateLimitAnons = new Ratelimit({
|
37 |
redis,
|
38 |
+
limiter: Ratelimit.slidingWindow(2, "60 s"),
|
39 |
analytics: true,
|
40 |
timeout: 1000,
|
41 |
prefix: "production:anon"
|
|
|
61 |
|
62 |
console.log(`user ${key.slice(0, 10)} requested "${cropped}${cropped !== positivePrompt ? "..." : ""}"`)
|
63 |
|
64 |
+
// const globalRateLimitResult = rateLimitGlobal.limit("global")
|
65 |
+
|
66 |
// this waits for 3 seconds before failing the request
|
67 |
// we don't wait more because it is frustrating for someone to wait a failure
|
68 |
+
const userRateLimitResult = await rateLimitAnons.limit(key || "anon")
|
69 |
// const rateLimitResult = await rateLimitAnons.blockUntilReady(key, 3_000)
|
70 |
|
71 |
// admin / developers will have this key:
|
72 |
// eff8e7ca506627fe15dda5e0e512fcaad70b6d520f37cc76597fdb4f2d83a1a3
|
73 |
|
74 |
// result.limit
|
75 |
+
if (!userRateLimitResult.success) {
|
76 |
console.log(`blocking user ${key.slice(0, 10)} who requested "${cropped}${cropped !== positivePrompt ? "..." : ""}"`)
|
77 |
throw new Error(`Rate Limit Reached`)
|
78 |
} else {
|