From f109f1cf60ecab92e02e1ad1501be5c310b0a357 Mon Sep 17 00:00:00 2001 From: archer <545436317@qq.com> Date: Sun, 30 Apr 2023 13:18:54 +0800 Subject: [PATCH] perf: save chat and del chat content;UI --- src/api/chat.ts | 4 +- src/pages/api/chat/chat.ts | 6 +-- ...ByIndex.ts => delChatRecordByContentId.ts} | 25 ++---------- src/pages/api/chat/init.ts | 16 ++++---- src/pages/api/chat/saveChat.ts | 2 + src/pages/api/openapi/chat/chat.ts | 6 +-- src/pages/api/openapi/chat/chatGpt.ts | 6 +-- src/pages/api/openapi/chat/lafGpt.ts | 6 +-- src/pages/api/openapi/chat/vectorGpt.ts | 6 +-- src/pages/chat/index.tsx | 39 ++++++++++--------- .../login/components/ForgetPasswordForm.tsx | 10 ++--- src/pages/login/components/RegisterForm.tsx | 10 ++--- src/pages/login/index.tsx | 17 +++++--- .../detail/components/SelectFileModal.tsx | 11 +++++- src/service/errorCode.ts | 2 +- src/service/models/chat.ts | 4 -- src/service/utils/auth.ts | 13 +++++-- src/service/utils/tools.ts | 6 +-- src/types/chat.d.ts | 6 ++- 19 files changed, 100 insertions(+), 95 deletions(-) rename src/pages/api/chat/{delChatRecordByIndex.ts => delChatRecordByContentId.ts} (57%) diff --git a/src/api/chat.ts b/src/api/chat.ts index 891ad71d1..c246a8536 100644 --- a/src/api/chat.ts +++ b/src/api/chat.ts @@ -31,5 +31,5 @@ export const postSaveChat = (data: { /** * 删除一句对话 */ -export const delChatRecordByIndex = (chatId: string, index: number) => - DELETE(`/chat/delChatRecordByIndex?chatId=${chatId}&index=${index}`); +export const delChatRecordByIndex = (chatId: string, contentId: string) => + DELETE(`/chat/delChatRecordByContentId?chatId=${chatId}&contentId=${contentId}`); diff --git a/src/pages/api/chat/chat.ts b/src/pages/api/chat/chat.ts index 48302dc47..9855803d8 100644 --- a/src/pages/api/chat/chat.ts +++ b/src/pages/api/chat/chat.ts @@ -2,7 +2,7 @@ import type { NextApiRequest, NextApiResponse } from 'next'; import { connectToDatabase } from '@/service/mongo'; import { getOpenAIApi, authChat } from '@/service/utils/auth'; import { axiosConfig, openaiChatFilter, systemPromptFilter } from '@/service/utils/tools'; -import { ChatItemType } from '@/types/chat'; +import { ChatItemSimpleType } from '@/types/chat'; import { jsonRes } from '@/service/response'; import { PassThrough } from 'stream'; import { modelList, ModelVectorSearchModeMap, ModelVectorSearchModeEnum } from '@/constants/model'; @@ -28,7 +28,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) try { const { chatId, prompt, modelId } = req.body as { - prompt: ChatItemType; + prompt: ChatItemSimpleType; modelId: string; chatId: '' | string; }; @@ -118,7 +118,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) const filterPrompts = openaiChatFilter({ model: model.chat.chatModel, prompts, - maxTokens: modelConstantsData.contextMaxToken - 500 + maxTokens: modelConstantsData.contextMaxToken - 300 }); // 计算温度 diff --git a/src/pages/api/chat/delChatRecordByIndex.ts b/src/pages/api/chat/delChatRecordByContentId.ts similarity index 57% rename from src/pages/api/chat/delChatRecordByIndex.ts rename to src/pages/api/chat/delChatRecordByContentId.ts index 32f9acb7c..4081b377b 100644 --- a/src/pages/api/chat/delChatRecordByIndex.ts +++ b/src/pages/api/chat/delChatRecordByContentId.ts @@ -5,13 +5,13 @@ import { authToken } from '@/service/utils/auth'; export default async function handler(req: NextApiRequest, res: NextApiResponse) { try { - const { chatId, index } = req.query as { chatId: string; index: string }; + const { chatId, contentId } = req.query as { chatId: string; contentId: string }; const { authorization } = req.headers; if (!authorization) { throw new Error('无权操作'); } - if (!chatId || !index) { + if (!chatId || !contentId) { throw new Error('缺少参数'); } @@ -26,30 +26,13 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) throw new Error('找不到对话'); } - // 重新计算 index,跳过已经被删除的内容 - let unDeleteIndex = +index; - let deletedIndex = 0; - for (deletedIndex = 0; deletedIndex < chatRecord.content.length; deletedIndex++) { - if (!chatRecord.content[deletedIndex].deleted) { - unDeleteIndex--; - if (unDeleteIndex < 0) { - break; - } - } - } - - // 删除最一条数据库记录, 也就是预发送的那一条 + // 删除一条数据库记录 await Chat.updateOne( { _id: chatId, userId }, - { - $set: { - [`content.${deletedIndex}.deleted`]: true, - updateTime: Date.now() - } - } + { $pull: { content: { _id: contentId } } } ); jsonRes(res); diff --git a/src/pages/api/chat/init.ts b/src/pages/api/chat/init.ts index 00aa42164..2acd9e6a7 100644 --- a/src/pages/api/chat/init.ts +++ b/src/pages/api/chat/init.ts @@ -36,20 +36,22 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) userId: new mongoose.Types.ObjectId(userId) } }, - { $unwind: '$content' }, - { $match: { 'content.deleted': false } }, - { $sort: { 'content._id': -1 } }, - { $limit: 50 }, { $project: { - id: '$content._id', + content: { + $slice: ['$content', -50] // 返回 content 数组的最后50个元素 + } + } + }, + { $unwind: '$content' }, + { + $project: { + _id: '$content._id', obj: '$content.obj', value: '$content.value' } } ]); - - history.reverse(); } jsonRes(res, { diff --git a/src/pages/api/chat/saveChat.ts b/src/pages/api/chat/saveChat.ts index 7a4b6bd7a..583c42bfa 100644 --- a/src/pages/api/chat/saveChat.ts +++ b/src/pages/api/chat/saveChat.ts @@ -4,6 +4,7 @@ import { ChatItemType } from '@/types/chat'; import { connectToDatabase, Chat } from '@/service/mongo'; import { authModel } from '@/service/utils/auth'; import { authToken } from '@/service/utils/auth'; +import mongoose from 'mongoose'; /* 聊天内容存存储 */ export default async function handler(req: NextApiRequest, res: NextApiResponse) { @@ -23,6 +24,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) await connectToDatabase(); const content = prompts.map((item) => ({ + _id: new mongoose.Types.ObjectId(item._id), obj: item.obj, value: item.value })); diff --git a/src/pages/api/openapi/chat/chat.ts b/src/pages/api/openapi/chat/chat.ts index d7461a65b..38c3f770f 100644 --- a/src/pages/api/openapi/chat/chat.ts +++ b/src/pages/api/openapi/chat/chat.ts @@ -2,7 +2,7 @@ import type { NextApiRequest, NextApiResponse } from 'next'; import { connectToDatabase } from '@/service/mongo'; import { getOpenAIApi, authOpenApiKey, authModel } from '@/service/utils/auth'; import { axiosConfig, openaiChatFilter, systemPromptFilter } from '@/service/utils/tools'; -import { ChatItemType } from '@/types/chat'; +import { ChatItemSimpleType } from '@/types/chat'; import { jsonRes } from '@/service/response'; import { PassThrough } from 'stream'; import { modelList, ModelVectorSearchModeMap, ModelVectorSearchModeEnum } from '@/constants/model'; @@ -32,7 +32,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) modelId, isStream = true } = req.body as { - prompts: ChatItemType[]; + prompts: ChatItemSimpleType[]; modelId: string; isStream: boolean; }; @@ -132,7 +132,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) const filterPrompts = openaiChatFilter({ model: model.chat.chatModel, prompts, - maxTokens: modelConstantsData.contextMaxToken - 500 + maxTokens: modelConstantsData.contextMaxToken - 300 }); // 计算温度 diff --git a/src/pages/api/openapi/chat/chatGpt.ts b/src/pages/api/openapi/chat/chatGpt.ts index 080fb6577..dc338957c 100644 --- a/src/pages/api/openapi/chat/chatGpt.ts +++ b/src/pages/api/openapi/chat/chatGpt.ts @@ -2,7 +2,7 @@ import type { NextApiRequest, NextApiResponse } from 'next'; import { connectToDatabase, Model } from '@/service/mongo'; import { getOpenAIApi, authOpenApiKey } from '@/service/utils/auth'; import { axiosConfig, openaiChatFilter } from '@/service/utils/tools'; -import { ChatItemType } from '@/types/chat'; +import { ChatItemSimpleType } from '@/types/chat'; import { jsonRes } from '@/service/response'; import { PassThrough } from 'stream'; import { modelList } from '@/constants/model'; @@ -31,7 +31,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) modelId, isStream = true } = req.body as { - prompts: ChatItemType[]; + prompts: ChatItemSimpleType[]; modelId: string; isStream: boolean; }; @@ -77,7 +77,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) const filterPrompts = openaiChatFilter({ model: model.chat.chatModel, prompts, - maxTokens: modelConstantsData.contextMaxToken - 500 + maxTokens: modelConstantsData.contextMaxToken - 300 }); // console.log(filterPrompts); diff --git a/src/pages/api/openapi/chat/lafGpt.ts b/src/pages/api/openapi/chat/lafGpt.ts index a48798942..00d6b1a3d 100644 --- a/src/pages/api/openapi/chat/lafGpt.ts +++ b/src/pages/api/openapi/chat/lafGpt.ts @@ -2,7 +2,7 @@ import type { NextApiRequest, NextApiResponse } from 'next'; import { connectToDatabase, Model } from '@/service/mongo'; import { getOpenAIApi, authOpenApiKey } from '@/service/utils/auth'; import { axiosConfig, openaiChatFilter, systemPromptFilter } from '@/service/utils/tools'; -import { ChatItemType } from '@/types/chat'; +import { ChatItemSimpleType } from '@/types/chat'; import { jsonRes } from '@/service/response'; import { PassThrough } from 'stream'; import { modelList, ModelVectorSearchModeMap, ChatModelEnum } from '@/constants/model'; @@ -32,7 +32,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) modelId, isStream = true } = req.body as { - prompt: ChatItemType; + prompt: ChatItemSimpleType; modelId: string; isStream: boolean; }; @@ -156,7 +156,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) const filterPrompts = openaiChatFilter({ model: model.chat.chatModel, prompts, - maxTokens: modelConstantsData.contextMaxToken - 500 + maxTokens: modelConstantsData.contextMaxToken - 300 }); // console.log(filterPrompts); diff --git a/src/pages/api/openapi/chat/vectorGpt.ts b/src/pages/api/openapi/chat/vectorGpt.ts index 9431d538b..46f3e86d1 100644 --- a/src/pages/api/openapi/chat/vectorGpt.ts +++ b/src/pages/api/openapi/chat/vectorGpt.ts @@ -2,7 +2,7 @@ import type { NextApiRequest, NextApiResponse } from 'next'; import { connectToDatabase, Model } from '@/service/mongo'; import { axiosConfig, systemPromptFilter, openaiChatFilter } from '@/service/utils/tools'; import { getOpenAIApi, authOpenApiKey } from '@/service/utils/auth'; -import { ChatItemType } from '@/types/chat'; +import { ChatItemSimpleType } from '@/types/chat'; import { jsonRes } from '@/service/response'; import { PassThrough } from 'stream'; import { modelList, ModelVectorSearchModeMap, ModelVectorSearchModeEnum } from '@/constants/model'; @@ -32,7 +32,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) modelId, isStream = true } = req.body as { - prompts: ChatItemType[]; + prompts: ChatItemSimpleType[]; modelId: string; isStream: boolean; }; @@ -127,7 +127,7 @@ ${ const filterPrompts = openaiChatFilter({ model: model.chat.chatModel, prompts, - maxTokens: modelConstantsData.contextMaxToken - 500 + maxTokens: modelConstantsData.contextMaxToken - 300 }); // console.log(filterPrompts); diff --git a/src/pages/chat/index.tsx b/src/pages/chat/index.tsx index 759ffdcd7..9d7716b29 100644 --- a/src/pages/chat/index.tsx +++ b/src/pages/chat/index.tsx @@ -29,8 +29,7 @@ import { streamFetch } from '@/api/fetch'; import Icon from '@/components/Icon'; import MyIcon from '@/components/Icon'; import { throttle } from 'lodash'; -import { customAlphabet } from 'nanoid'; -const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 5); +import mongoose from 'mongoose'; const SlideBar = dynamic(() => import('./components/SlideBar')); const Empty = dynamic(() => import('./components/Empty')); @@ -41,7 +40,6 @@ import styles from './index.module.scss'; const textareaMinH = '22px'; export type ChatSiteItemType = { - id: string; status: 'loading' | 'finish'; } & ChatItemType; @@ -136,10 +134,8 @@ const Chat = ({ modelId, chatId }: { modelId: string; chatId: string }) => { setChatData({ ...res, - history: res.history.map((item: any, i) => ({ - obj: item.obj, - value: item.value, - id: item.id || `${nanoid()}-${i}`, + history: res.history.map((item) => ({ + ...item, status: 'finish' })) }); @@ -191,15 +187,15 @@ const Chat = ({ modelId, chatId }: { modelId: string; chatId: string }) => { // gpt 对话 const gptChatPrompt = useCallback( - async (prompts: ChatSiteItemType) => { + async (prompts: ChatSiteItemType[]) => { // create abort obj const abortSignal = new AbortController(); controller.current = abortSignal; isResetPage.current = false; const prompt = { - obj: prompts.obj, - value: prompts.value + obj: prompts[0].obj, + value: prompts[0].value }; // 流请求,获取数据 @@ -238,8 +234,13 @@ const Chat = ({ modelId, chatId }: { modelId: string; chatId: string }) => { modelId, chatId, prompts: [ - prompt, { + _id: prompts[0]._id, + obj: 'Human', + value: prompt.value + }, + { + _id: prompts[1]._id, obj: 'AI', value: responseText } @@ -299,13 +300,13 @@ const Chat = ({ modelId, chatId }: { modelId: string; chatId: string }) => { const newChatList: ChatSiteItemType[] = [ ...chatData.history, { - id: nanoid(), + _id: String(new mongoose.Types.ObjectId()), obj: 'Human', value: val, status: 'finish' }, { - id: nanoid(), + _id: String(new mongoose.Types.ObjectId()), obj: 'AI', value: '', status: 'loading' @@ -325,7 +326,7 @@ const Chat = ({ modelId, chatId }: { modelId: string; chatId: string }) => { }, 100); try { - await gptChatPrompt(newChatList[newChatList.length - 2]); + await gptChatPrompt(newChatList.slice(-2)); } catch (err: any) { toast({ title: typeof err === 'string' ? err : err?.message || '聊天出错了~', @@ -345,11 +346,11 @@ const Chat = ({ modelId, chatId }: { modelId: string; chatId: string }) => { // 删除一句话 const delChatRecord = useCallback( - async (index: number) => { + async (index: number, id: string) => { setLoading(true); try { // 删除数据库最后一句 - await delChatRecordByIndex(chatId, index); + await delChatRecordByIndex(chatId, id); setChatData((state) => ({ ...state, @@ -449,7 +450,7 @@ const Chat = ({ modelId, chatId }: { modelId: string; chatId: string }) => { {chatData.history.map((item, index) => ( { onclickCopy(item.value)}>复制 - delChatRecord(index)}>删除该行 + delChatRecord(index, item._id)}>删除该行 @@ -507,7 +508,7 @@ const Chat = ({ modelId, chatId }: { modelId: string; chatId: string }) => { _hover={{ color: 'red.600' }} - onClick={() => delChatRecord(index)} + onClick={() => delChatRecord(index, item._id)} /> )} diff --git a/src/pages/login/components/ForgetPasswordForm.tsx b/src/pages/login/components/ForgetPasswordForm.tsx index 38ab71474..801022b50 100644 --- a/src/pages/login/components/ForgetPasswordForm.tsx +++ b/src/pages/login/components/ForgetPasswordForm.tsx @@ -78,7 +78,7 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => { 找回 FastGPT 账号
- + { {!!errors.username && errors.username.message} - + { {!!errors.code && errors.code.message} - + { {!!errors.password && errors.password.message} - + {