diff --git a/app/api/chat-stream/route.ts b/app/api/chat-stream/route.ts index 41f135495..060cc1fe3 100644 --- a/app/api/chat-stream/route.ts +++ b/app/api/chat-stream/route.ts @@ -1,6 +1,7 @@ import { createParser } from "eventsource-parser"; import { NextRequest } from "next/server"; import { requestOpenai } from "../common"; +import clientPromise from "../../db/mongdb"; async function createStream(req: NextRequest) { const encoder = new TextEncoder(); @@ -48,7 +49,55 @@ async function createStream(req: NextRequest) { } export async function POST(req: NextRequest) { + const accessCode = req.headers.get("access-code"); try { + // 使用 clientPromise 连接到 MongoDB 数据库 + const client = await clientPromise; + // 选择数据库和集合 + const db = client.db("chat_db"); + const usersCollection = db.collection("users"); + // 查询用户数据 + const user = await usersCollection.findOne({ key: accessCode }); + const tips = + "您的链接授权已过期,为了避免恶意盗刷,\n 关注微信公众号【coder思维】\n回复关键词:`ai` 获取授权链接 \n ![](/wx.png)"; + if (!user) { + return new Response(tips); + } + if (user["expire"] < new Date().getTime()) { + // 判断用户是否过期 + return new Response(tips); + } + + // 创建查询条件 + // 计算24小时前的时间戳 + const currentTime = new Date(); + const startTime = new Date(currentTime.getTime() - 24 * 60 * 60 * 1000); + + // 创建查询条件 + const query = { + username: user["username"], + create_time: { $gte: startTime }, + }; + + const collection = db.collection("chat_logs"); + // 根据查询条件查询记录数 + const recordCount = await collection.countDocuments(query); + if (recordCount > 1000) { + // 判断用户是否超过1000条记录 + return new Response( + "您的聊天提问已超过1000条,为了避免恶意盗刷,请过稍后再试,24小时内只能提问1000条", + ); + } + // 创建聊天记录 + const chatLog = { + username: user["username"], + create_time: new Date().getTime(), + content: req.body, + }; + collection.insertOne(chatLog).then(() => { + client.close(); + }); + const stream = await createStream(req); return new Response(stream); } catch (error) { @@ -58,7 +107,3 @@ export async function POST(req: NextRequest) { ); } } - -export const config = { - runtime: "edge", -}; diff --git a/app/db/mongdb.ts b/app/db/mongdb.ts new file mode 100644 index 000000000..5f82f5c99 --- /dev/null +++ b/app/db/mongdb.ts @@ -0,0 +1,28 @@ +// 引入 `MongoClient` 类型,以便于类型注解 +import { MongoClient, MongoClientOptions } from "mongodb"; + +// 使用 `process.env.MONGODB_URI` 的值初始化 URI 变量 +const uri: string | undefined = process.env.MONGODB_URI; +// 定义 MongoClient 选项对象 +const options: MongoClientOptions = {}; + +// 声明 client 和 clientPromise 变量,类型分别为 MongoClient 和 Promise +let client: MongoClient; +let clientPromise: Promise; + +// 判断当前环境是否为开发环境 +if (process.env.NODE_ENV === "development") { + // 在开发模式下,使用全局变量,以便在 HMR (Hot Module Replacement) 导致的模块重新加载时保留值。 + if (!global._mongoClientPromise) { + client = new MongoClient(uri!, options); // 使用非空断言运算符(!),因为我们已经检查了 uri 是否存在 + global._mongoClientPromise = client.connect(); + } + clientPromise = global._mongoClientPromise; +} else { + // 在生产模式下,最好不要使用全局变量。 + client = new MongoClient(uri!, options); // 使用非空断言运算符(!),因为我们已经检查了 uri 是否存在 + clientPromise = client.connect(); +} + +// 导出模块作用域的 MongoClient promise。通过在一个单独的模块中这样做,client 可以在函数之间共享。 +export default clientPromise; diff --git a/app/locales/cn.ts b/app/locales/cn.ts index 1bab41e42..7e44f84b8 100644 --- a/app/locales/cn.ts +++ b/app/locales/cn.ts @@ -4,7 +4,7 @@ const cn = { WIP: "该功能仍在开发中……", Error: { Unauthorized: - "现在是未授权状态,\n 关注微信公众号【coder思维】回复关键词:`ai` \n 获取授权链接", + "现在是未授权状态,为了避免恶意盗刷:,\n 关注微信公众号【coder思维】\n回复关键词:`ai` 获取授权链接 \n ![](/wx.png)", }, ChatItem: { ChatItemCount: (count: number) => `${count} 条对话`, diff --git a/public/wx.png b/public/wx.png new file mode 100644 index 000000000..96b892e58 Binary files /dev/null and b/public/wx.png differ