From 5b71bdd4c02996ad7d699802de83da4607171597 Mon Sep 17 00:00:00 2001 From: Yoko Li Date: Wed, 5 Jul 2023 20:22:30 -0700 Subject: [PATCH 1/3] adding rate limit to chatgpt --- package-lock.json | 20 ++++++++++++++++++++ package.json | 1 + src/app/api/chatgpt/route.ts | 17 +++++++++++++++++ 3 files changed, 38 insertions(+) diff --git a/package-lock.json b/package-lock.json index 2f19d43..0abc3ea 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,6 +17,7 @@ "@types/node": "20.2.5", "@types/react": "18.2.8", "@types/react-dom": "18.2.4", + "@upstash/ratelimit": "^0.4.3", "@upstash/redis": "^1.21.0", "ai": "^2.1.3", "autoprefixer": "10.4.14", @@ -1000,6 +1001,25 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@upstash/core-analytics": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@upstash/core-analytics/-/core-analytics-0.0.6.tgz", + "integrity": "sha512-cpPSR0XJAJs4Ddz9nq3tINlPS5aLfWVCqhhtHnXt4p7qr5+/Znlt1Es736poB/9rnl1hAHrOsOvVj46NEXcVqA==", + "dependencies": { + "@upstash/redis": "^1.19.3" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@upstash/ratelimit": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@upstash/ratelimit/-/ratelimit-0.4.3.tgz", + "integrity": "sha512-Dsp9Mw09Flg28JRklKgFiCXqr3bqv8bbG0kgpUYoHjcgPPolFFyaYOj/I2HExvYLZiogl77NUavBoNvMOK0zUQ==", + "dependencies": { + "@upstash/core-analytics": "^0.0.6" + } + }, "node_modules/@upstash/redis": { "version": "1.21.0", "resolved": "https://registry.npmjs.org/@upstash/redis/-/redis-1.21.0.tgz", diff --git a/package.json b/package.json index eadaf46..a69d80b 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "@types/node": "20.2.5", "@types/react": "18.2.8", "@types/react-dom": "18.2.4", + "@upstash/ratelimit": "^0.4.3", "@upstash/redis": "^1.21.0", "ai": "^2.1.3", "autoprefixer": "10.4.14", diff --git a/src/app/api/chatgpt/route.ts b/src/app/api/chatgpt/route.ts index c4d48ef..b4c9c94 100644 --- a/src/app/api/chatgpt/route.ts +++ b/src/app/api/chatgpt/route.ts @@ -11,6 +11,8 @@ import { PromptTemplate } from "langchain/prompts"; import { NextResponse } from "next/server"; import { currentUser } from "@clerk/nextjs"; import MemoryManager from "@/app/utils/memory"; +import { Ratelimit } from "@upstash/ratelimit"; +import { Redis } from "@upstash/redis"; dotenv.config({ path: `.env.local` }); @@ -20,6 +22,20 @@ export async function POST(req: Request) { let clerkUserName; const { prompt, isText, userId, userName } = await req.json(); + // Rate limit through Upstash + const ratelimit = new Ratelimit({ + redis: Redis.fromEnv(), + limiter: Ratelimit.slidingWindow(10, "10 s"), + analytics: true, + prefix: "@upstash/ratelimit", + }); + const identifier = userId || "anonymous"; + const { success } = await ratelimit.limit(identifier); + if (!success) { + console.log("INFO: rate limit exceeded"); + return "Unable to process at this time"; + } + // XXX Companion name passed here. Can use as a key to get backstory, chat history etc. const name = req.headers.get("name"); const companion_file_name = name + ".txt"; @@ -35,6 +51,7 @@ export async function POST(req: Request) { } if (!clerkUserId || !!!(await clerk.users.getUser(clerkUserId))) { + console.log("user not authorized"); return new NextResponse( JSON.stringify({ Message: "User not authorized" }), { From e107f30801d19b7610cd4dcf9f22207ab32c52e3 Mon Sep 17 00:00:00 2001 From: Yoko Li Date: Sun, 9 Jul 2023 15:25:26 -0700 Subject: [PATCH 2/3] update rate limiter for all APIs --- src/app/api/chatgpt/route.ts | 24 ++++++++++++------------ src/app/api/text/route.ts | 18 ++++++++++++++++-- src/app/api/vicuna13b/route.ts | 17 +++++++++++++++++ 3 files changed, 45 insertions(+), 14 deletions(-) diff --git a/src/app/api/chatgpt/route.ts b/src/app/api/chatgpt/route.ts index b4c9c94..f533800 100644 --- a/src/app/api/chatgpt/route.ts +++ b/src/app/api/chatgpt/route.ts @@ -11,8 +11,7 @@ import { PromptTemplate } from "langchain/prompts"; import { NextResponse } from "next/server"; import { currentUser } from "@clerk/nextjs"; import MemoryManager from "@/app/utils/memory"; -import { Ratelimit } from "@upstash/ratelimit"; -import { Redis } from "@upstash/redis"; +import { rateLimit } from "@/app/utils/rateLimit"; dotenv.config({ path: `.env.local` }); @@ -22,18 +21,19 @@ export async function POST(req: Request) { let clerkUserName; const { prompt, isText, userId, userName } = await req.json(); - // Rate limit through Upstash - const ratelimit = new Ratelimit({ - redis: Redis.fromEnv(), - limiter: Ratelimit.slidingWindow(10, "10 s"), - analytics: true, - prefix: "@upstash/ratelimit", - }); - const identifier = userId || "anonymous"; - const { success } = await ratelimit.limit(identifier); + const identifier = req.url + "-" + (userId || "anonymous"); + const { success } = await rateLimit(identifier); if (!success) { console.log("INFO: rate limit exceeded"); - return "Unable to process at this time"; + return new NextResponse( + JSON.stringify({ Message: "Hi, the companions can't talk this fast." }), + { + status: 429, + headers: { + "Content-Type": "application/json", + }, + } + ); } // XXX Companion name passed here. Can use as a key to get backstory, chat history etc. diff --git a/src/app/api/text/route.ts b/src/app/api/text/route.ts index 17b8dac..3e25a5d 100644 --- a/src/app/api/text/route.ts +++ b/src/app/api/text/route.ts @@ -3,11 +3,11 @@ import twilio from "twilio"; import clerk from "@clerk/clerk-sdk-node"; import dotenv from "dotenv"; import ConfigManager from "@/app/utils/config"; +import { rateLimit } from "@/app/utils/rateLimit"; dotenv.config({ path: `.env.local` }); const twilioAuthToken = process.env.TWILIO_AUTH_TOKEN; const accountSid = process.env.TWILIO_ACCOUNT_SID; -const publishableKey = process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY; export async function POST(request: Request) { let queryMap: any = {}; @@ -21,6 +21,21 @@ export async function POST(request: Request) { const phoneNumber = queryMap["From"]; const companionPhoneNumber = queryMap["To"]; + const identifier = request.url + "-" + (phoneNumber || "anonymous"); + const { success } = await rateLimit(identifier); + if (!success) { + console.log("INFO: rate limit exceeded"); + return new NextResponse( + JSON.stringify({ Message: "Hi, the companions can't talk this fast." }), + { + status: 429, + headers: { + "Content-Type": "application/json", + }, + } + ); + } + // check if the user has verified phone # const users = await clerk.users.getUserList({ phoneNumber }); @@ -37,7 +52,6 @@ export async function POST(request: Request) { } const configManager = ConfigManager.getInstance(); - console.log(phoneNumber); const companionConfig = configManager.getConfig( "phone", companionPhoneNumber diff --git a/src/app/api/vicuna13b/route.ts b/src/app/api/vicuna13b/route.ts index ed0ea54..533da50 100644 --- a/src/app/api/vicuna13b/route.ts +++ b/src/app/api/vicuna13b/route.ts @@ -9,6 +9,7 @@ import clerk from "@clerk/clerk-sdk-node"; import MemoryManager from "@/app/utils/memory"; import { currentUser } from "@clerk/nextjs"; import { NextResponse } from "next/server"; +import { rateLimit } from "@/app/utils/rateLimit"; dotenv.config({ path: `.env.local` }); @@ -17,6 +18,22 @@ export async function POST(request: Request) { let clerkUserId; let user; let clerkUserName; + + const identifier = request.url + "-" + (userId || "anonymous"); + const { success } = await rateLimit(identifier); + if (!success) { + console.log("INFO: rate limit exceeded"); + return new NextResponse( + JSON.stringify({ Message: "Hi, the companions can't talk this fast." }), + { + status: 429, + headers: { + "Content-Type": "application/json", + }, + } + ); + } + // XXX Companion name passed here. Can use as a key to get backstory, chat history etc. const name = request.headers.get("name"); const companion_file_name = name + ".txt"; From cdf946a85ad64fbb495cda49b2df6f48b5b704f8 Mon Sep 17 00:00:00 2001 From: Yoko Li Date: Sun, 9 Jul 2023 15:26:25 -0700 Subject: [PATCH 3/3] forgot new file --- src/app/utils/rateLimit.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 src/app/utils/rateLimit.ts diff --git a/src/app/utils/rateLimit.ts b/src/app/utils/rateLimit.ts new file mode 100644 index 0000000..5cb7f2a --- /dev/null +++ b/src/app/utils/rateLimit.ts @@ -0,0 +1,13 @@ +import { Ratelimit } from "@upstash/ratelimit"; +import { Redis } from "@upstash/redis"; + +export async function rateLimit(identifier: string) { + // Rate limit through Upstash + const ratelimit = new Ratelimit({ + redis: Redis.fromEnv(), + limiter: Ratelimit.slidingWindow(10, "10 s"), + analytics: true, + prefix: "@upstash/ratelimit", + }); + return await ratelimit.limit(identifier); +}