mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-23 21:13:50 +00:00
perf: save chat and del chat content;UI
This commit is contained in:
@@ -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}`);
|
||||
|
@@ -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
|
||||
});
|
||||
|
||||
// 计算温度
|
||||
|
@@ -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);
|
@@ -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<InitChatResponse>(res, {
|
||||
|
@@ -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
|
||||
}));
|
||||
|
@@ -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
|
||||
});
|
||||
|
||||
// 计算温度
|
||||
|
@@ -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);
|
||||
|
@@ -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);
|
||||
|
@@ -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);
|
||||
|
@@ -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 }) => {
|
||||
<Box ref={ChatBox} pb={[4, 0]} flex={'1 0 0'} h={0} w={'100%'} overflowY={'auto'}>
|
||||
{chatData.history.map((item, index) => (
|
||||
<Box
|
||||
key={item.id}
|
||||
key={item._id}
|
||||
py={media(9, 6)}
|
||||
px={media(4, 2)}
|
||||
backgroundColor={
|
||||
@@ -475,7 +476,7 @@ const Chat = ({ modelId, chatId }: { modelId: string; chatId: string }) => {
|
||||
</MenuButton>
|
||||
<MenuList fontSize={'sm'}>
|
||||
<MenuItem onClick={() => onclickCopy(item.value)}>复制</MenuItem>
|
||||
<MenuItem onClick={() => delChatRecord(index)}>删除该行</MenuItem>
|
||||
<MenuItem onClick={() => delChatRecord(index, item._id)}>删除该行</MenuItem>
|
||||
</MenuList>
|
||||
</Menu>
|
||||
<Box flex={'1 0 0'} w={0} overflow={'hidden'} id={`chat${index}`}>
|
||||
@@ -507,7 +508,7 @@ const Chat = ({ modelId, chatId }: { modelId: string; chatId: string }) => {
|
||||
_hover={{
|
||||
color: 'red.600'
|
||||
}}
|
||||
onClick={() => delChatRecord(index)}
|
||||
onClick={() => delChatRecord(index, item._id)}
|
||||
/>
|
||||
</Flex>
|
||||
)}
|
||||
|
@@ -78,7 +78,7 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
|
||||
找回 FastGPT 账号
|
||||
</Box>
|
||||
<form onSubmit={handleSubmit(onclickFindPassword)}>
|
||||
<FormControl mt={8} isInvalid={!!errors.username}>
|
||||
<FormControl mt={5} isInvalid={!!errors.username}>
|
||||
<Input
|
||||
placeholder="邮箱/手机号"
|
||||
size={mediaLgMd}
|
||||
@@ -95,7 +95,7 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
|
||||
{!!errors.username && errors.username.message}
|
||||
</FormErrorMessage>
|
||||
</FormControl>
|
||||
<FormControl mt={8} isInvalid={!!errors.username}>
|
||||
<FormControl mt={5} isInvalid={!!errors.username}>
|
||||
<Flex>
|
||||
<Input
|
||||
flex={1}
|
||||
@@ -121,7 +121,7 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
|
||||
{!!errors.code && errors.code.message}
|
||||
</FormErrorMessage>
|
||||
</FormControl>
|
||||
<FormControl mt={8} isInvalid={!!errors.password}>
|
||||
<FormControl mt={5} isInvalid={!!errors.password}>
|
||||
<Input
|
||||
type={'password'}
|
||||
placeholder="新密码"
|
||||
@@ -142,7 +142,7 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
|
||||
{!!errors.password && errors.password.message}
|
||||
</FormErrorMessage>
|
||||
</FormControl>
|
||||
<FormControl mt={8} isInvalid={!!errors.password2}>
|
||||
<FormControl mt={5} isInvalid={!!errors.password2}>
|
||||
<Input
|
||||
type={'password'}
|
||||
placeholder="确认密码"
|
||||
@@ -168,7 +168,7 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
|
||||
</Box>
|
||||
<Button
|
||||
type="submit"
|
||||
mt={8}
|
||||
mt={5}
|
||||
w={'100%'}
|
||||
size={mediaLgMd}
|
||||
colorScheme="blue"
|
||||
|
@@ -86,7 +86,7 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
|
||||
注册 FastGPT 账号
|
||||
</Box>
|
||||
<form onSubmit={handleSubmit(onclickRegister)}>
|
||||
<FormControl mt={8} isInvalid={!!errors.username}>
|
||||
<FormControl mt={5} isInvalid={!!errors.username}>
|
||||
<Input
|
||||
placeholder="邮箱/手机号"
|
||||
size={mediaLgMd}
|
||||
@@ -103,7 +103,7 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
|
||||
{!!errors.username && errors.username.message}
|
||||
</FormErrorMessage>
|
||||
</FormControl>
|
||||
<FormControl mt={8} isInvalid={!!errors.username}>
|
||||
<FormControl mt={5} isInvalid={!!errors.username}>
|
||||
<Flex>
|
||||
<Input
|
||||
flex={1}
|
||||
@@ -129,7 +129,7 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
|
||||
{!!errors.code && errors.code.message}
|
||||
</FormErrorMessage>
|
||||
</FormControl>
|
||||
<FormControl mt={8} isInvalid={!!errors.password}>
|
||||
<FormControl mt={5} isInvalid={!!errors.password}>
|
||||
<Input
|
||||
type={'password'}
|
||||
placeholder="密码"
|
||||
@@ -150,7 +150,7 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
|
||||
{!!errors.password && errors.password.message}
|
||||
</FormErrorMessage>
|
||||
</FormControl>
|
||||
<FormControl mt={8} isInvalid={!!errors.password2}>
|
||||
<FormControl mt={5} isInvalid={!!errors.password2}>
|
||||
<Input
|
||||
type={'password'}
|
||||
placeholder="确认密码"
|
||||
@@ -176,7 +176,7 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
|
||||
</Box>
|
||||
<Button
|
||||
type="submit"
|
||||
mt={8}
|
||||
mt={5}
|
||||
w={'100%'}
|
||||
size={mediaLgMd}
|
||||
colorScheme="blue"
|
||||
|
@@ -45,12 +45,19 @@ const Login = () => {
|
||||
}, [router]);
|
||||
|
||||
return (
|
||||
<Box className={styles.loginPage} h={'100%'} p={isPc ? '10vh 10vw' : 0}>
|
||||
<Flex
|
||||
alignItems={'center'}
|
||||
justifyContent={'center'}
|
||||
className={styles.loginPage}
|
||||
h={'100%'}
|
||||
px={[0, '10vw']}
|
||||
>
|
||||
<Flex
|
||||
maxW={'1240px'}
|
||||
m={'auto'}
|
||||
backgroundColor={'#fff'}
|
||||
height="100%"
|
||||
w={'100%'}
|
||||
maxW={'1240px'}
|
||||
maxH={['auto', '660px']}
|
||||
backgroundColor={'#fff'}
|
||||
alignItems={'center'}
|
||||
justifyContent={'center'}
|
||||
p={10}
|
||||
@@ -83,7 +90,7 @@ const Login = () => {
|
||||
<DynamicComponent type={pageType} />
|
||||
</Box>
|
||||
</Flex>
|
||||
</Box>
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
|
@@ -162,15 +162,22 @@ const SelectFileModal = ({
|
||||
return (
|
||||
<Modal isOpen={true} onClose={onClose} isCentered>
|
||||
<ModalOverlay />
|
||||
<ModalContent maxW={'min(1000px, 90vw)'} m={0} position={'relative'} h={'90vh'}>
|
||||
<ModalContent
|
||||
display={'flex'}
|
||||
maxW={'min(1000px, 90vw)'}
|
||||
m={0}
|
||||
position={'relative'}
|
||||
h={'90vh'}
|
||||
>
|
||||
<ModalHeader>文件导入</ModalHeader>
|
||||
<ModalCloseButton />
|
||||
|
||||
<ModalBody
|
||||
flex={1}
|
||||
h={0}
|
||||
display={'flex'}
|
||||
flexDirection={'column'}
|
||||
p={0}
|
||||
h={'100%'}
|
||||
alignItems={'center'}
|
||||
justifyContent={'center'}
|
||||
fontSize={'sm'}
|
||||
|
@@ -23,7 +23,7 @@ export const openaiError: Record<string, string> = {
|
||||
context_length_exceeded: '内容超长了,请重置对话',
|
||||
Unauthorized: 'API-KEY 不合法',
|
||||
rate_limit_reached: 'API被限制,请稍后再试',
|
||||
'Bad Request': 'Bad Request~ openai 异常',
|
||||
'Bad Request': 'Bad Request~ 可能内容太多了',
|
||||
'Bad Gateway': '网关异常,请重试'
|
||||
};
|
||||
export const openaiError2: Record<string, string> = {
|
||||
|
@@ -41,10 +41,6 @@ const ChatSchema = new Schema({
|
||||
value: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
deleted: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
}
|
||||
],
|
||||
|
@@ -4,7 +4,7 @@ import jwt from 'jsonwebtoken';
|
||||
import { Chat, Model, OpenApi, User } from '../mongo';
|
||||
import type { ModelSchema } from '@/types/mongoSchema';
|
||||
import { getOpenApiKey } from './openai';
|
||||
import type { ChatItemType } from '@/types/chat';
|
||||
import type { ChatItemSimpleType } from '@/types/chat';
|
||||
import mongoose from 'mongoose';
|
||||
import { defaultModel } from '@/constants/model';
|
||||
import { formatPrice } from '@/utils/user';
|
||||
@@ -94,14 +94,20 @@ export const authChat = async ({
|
||||
const { model } = await authModel({ modelId, userId, authOwner: false, reserveDetail: true });
|
||||
|
||||
// 聊天内容
|
||||
let content: ChatItemType[] = [];
|
||||
let content: ChatItemSimpleType[] = [];
|
||||
|
||||
if (chatId) {
|
||||
// 获取 chat 数据
|
||||
content = await Chat.aggregate([
|
||||
{ $match: { _id: new mongoose.Types.ObjectId(chatId) } },
|
||||
{
|
||||
$project: {
|
||||
content: {
|
||||
$slice: ['$content', -50] // 返回 content 数组的最后50个元素
|
||||
}
|
||||
}
|
||||
},
|
||||
{ $unwind: '$content' },
|
||||
{ $match: { 'content.deleted': false } },
|
||||
{
|
||||
$project: {
|
||||
obj: '$content.obj',
|
||||
@@ -110,7 +116,6 @@ export const authChat = async ({
|
||||
}
|
||||
]);
|
||||
}
|
||||
|
||||
// 获取 user 的 apiKey
|
||||
const { userApiKey, systemKey } = await getOpenApiKey(userId);
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import crypto from 'crypto';
|
||||
import jwt from 'jsonwebtoken';
|
||||
import { ChatItemType } from '@/types/chat';
|
||||
import { ChatItemSimpleType } from '@/types/chat';
|
||||
import { countChatTokens } from '@/utils/tools';
|
||||
import { ChatCompletionRequestMessageRoleEnum, ChatCompletionRequestMessage } from 'openai';
|
||||
import { ChatModelEnum } from '@/constants/model';
|
||||
@@ -45,7 +45,7 @@ export const openaiChatFilter = ({
|
||||
maxTokens
|
||||
}: {
|
||||
model: `${ChatModelEnum}`;
|
||||
prompts: ChatItemType[];
|
||||
prompts: ChatItemSimpleType[];
|
||||
maxTokens: number;
|
||||
}) => {
|
||||
// role map
|
||||
@@ -94,7 +94,7 @@ export const openaiChatFilter = ({
|
||||
|
||||
/* 整体 tokens 超出范围 */
|
||||
if (tokens >= maxTokens) {
|
||||
break;
|
||||
return systemPrompt ? [systemPrompt, ...chats.slice(1)] : chats.slice(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
6
src/types/chat.d.ts
vendored
6
src/types/chat.d.ts
vendored
@@ -1,5 +1,7 @@
|
||||
export type ChatItemType = {
|
||||
export type ChatItemSimpleType = {
|
||||
obj: 'Human' | 'AI' | 'SYSTEM';
|
||||
value: string;
|
||||
deleted?: boolean;
|
||||
};
|
||||
export type ChatItemType = {
|
||||
_id: string;
|
||||
} & ChatItemSimpleType;
|
||||
|
Reference in New Issue
Block a user