Julian Bilcke
commited on
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 {
|