mirror of
https://github.com/labring/FastGPT.git
synced 2025-10-21 19:42:07 +00:00
perf: completion chatId
This commit is contained in:
@@ -22,7 +22,7 @@ export const getChatHistory = (data: RequestPaging & { appId?: string }) =>
|
|||||||
/**
|
/**
|
||||||
* 删除一条历史记录
|
* 删除一条历史记录
|
||||||
*/
|
*/
|
||||||
export const delChatHistoryById = (id: string) => GET(`/chat/removeHistory?id=${id}`);
|
export const delChatHistoryById = (chatId: string) => DELETE(`/chat/removeHistory`, { chatId });
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get history quotes
|
* get history quotes
|
||||||
|
@@ -78,6 +78,7 @@ export const streamFetch = ({
|
|||||||
onMessage(answer);
|
onMessage(answer);
|
||||||
responseText += answer;
|
responseText += answer;
|
||||||
} else if (item.event === sseResponseEventEnum.appStreamResponse) {
|
} else if (item.event === sseResponseEventEnum.appStreamResponse) {
|
||||||
|
console.log(data);
|
||||||
} else if (item.event === sseResponseEventEnum.error) {
|
} else if (item.event === sseResponseEventEnum.error) {
|
||||||
errMsg = getErrText(data, '流响应错误');
|
errMsg = getErrText(data, '流响应错误');
|
||||||
}
|
}
|
||||||
|
1
client/src/api/response/chat.d.ts
vendored
1
client/src/api/response/chat.d.ts
vendored
@@ -20,7 +20,6 @@ export interface InitChatResponse {
|
|||||||
|
|
||||||
export interface InitShareChatResponse {
|
export interface InitShareChatResponse {
|
||||||
userAvatar: string;
|
userAvatar: string;
|
||||||
maxContext: number;
|
|
||||||
app: {
|
app: {
|
||||||
variableModules?: VariableItemType[];
|
variableModules?: VariableItemType[];
|
||||||
welcomeText?: string;
|
welcomeText?: string;
|
||||||
|
@@ -19,7 +19,6 @@ import {
|
|||||||
getErrText
|
getErrText
|
||||||
} from '@/utils/tools';
|
} from '@/utils/tools';
|
||||||
import { Box, Card, Flex, Input, Textarea, Button, useTheme } from '@chakra-ui/react';
|
import { Box, Card, Flex, Input, Textarea, Button, useTheme } from '@chakra-ui/react';
|
||||||
import { useUserStore } from '@/store/user';
|
|
||||||
import { feConfigs } from '@/store/static';
|
import { feConfigs } from '@/store/static';
|
||||||
import { Types } from 'mongoose';
|
import { Types } from 'mongoose';
|
||||||
import { EventNameEnum } from '../Markdown/constant';
|
import { EventNameEnum } from '../Markdown/constant';
|
||||||
@@ -118,6 +117,7 @@ const ChatBox = (
|
|||||||
showEmptyIntro = false,
|
showEmptyIntro = false,
|
||||||
chatId,
|
chatId,
|
||||||
appAvatar,
|
appAvatar,
|
||||||
|
userAvatar,
|
||||||
variableModules,
|
variableModules,
|
||||||
welcomeText,
|
welcomeText,
|
||||||
onUpdateVariable,
|
onUpdateVariable,
|
||||||
@@ -126,7 +126,8 @@ const ChatBox = (
|
|||||||
}: {
|
}: {
|
||||||
showEmptyIntro?: boolean;
|
showEmptyIntro?: boolean;
|
||||||
chatId?: string;
|
chatId?: string;
|
||||||
appAvatar: string;
|
appAvatar?: string;
|
||||||
|
userAvatar?: string;
|
||||||
variableModules?: VariableItemType[];
|
variableModules?: VariableItemType[];
|
||||||
welcomeText?: string;
|
welcomeText?: string;
|
||||||
onUpdateVariable?: (e: Record<string, any>) => void;
|
onUpdateVariable?: (e: Record<string, any>) => void;
|
||||||
@@ -142,7 +143,6 @@ const ChatBox = (
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { copyData } = useCopyData();
|
const { copyData } = useCopyData();
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
const { userInfo } = useUserStore();
|
|
||||||
const { isPc } = useGlobalStore();
|
const { isPc } = useGlobalStore();
|
||||||
const TextareaDom = useRef<HTMLTextAreaElement>(null);
|
const TextareaDom = useRef<HTMLTextAreaElement>(null);
|
||||||
const controller = useRef(new AbortController());
|
const controller = useRef(new AbortController());
|
||||||
@@ -585,7 +585,7 @@ const ChatBox = (
|
|||||||
)}
|
)}
|
||||||
</Flex>
|
</Flex>
|
||||||
</Box>
|
</Box>
|
||||||
<ChatAvatar src={userInfo?.avatar} ml={['6px', 2]} />
|
<ChatAvatar src={userAvatar} ml={['6px', 2]} />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{item.obj === 'AI' && (
|
{item.obj === 'AI' && (
|
||||||
|
61
client/src/pages/api/admin/initChat.ts
Normal file
61
client/src/pages/api/admin/initChat.ts
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
|
||||||
|
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||||
|
import { jsonRes } from '@/service/response';
|
||||||
|
import { authUser } from '@/service/utils/auth';
|
||||||
|
import { connectToDatabase, TrainingData, User, promotionRecord, Chat } from '@/service/mongo';
|
||||||
|
import { PRICE_SCALE } from '@/constants/common';
|
||||||
|
|
||||||
|
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||||
|
try {
|
||||||
|
await authUser({ req, authRoot: true });
|
||||||
|
await connectToDatabase();
|
||||||
|
|
||||||
|
const { limit = 1000 } = req.body as { limit: number };
|
||||||
|
let skip = 0;
|
||||||
|
const total = await Chat.countDocuments({
|
||||||
|
chatId: { $exists: false }
|
||||||
|
});
|
||||||
|
let promise = Promise.resolve();
|
||||||
|
console.log(total);
|
||||||
|
|
||||||
|
for (let i = 0; i < total; i += limit) {
|
||||||
|
const skipVal = skip;
|
||||||
|
skip += limit;
|
||||||
|
promise = promise
|
||||||
|
.then(() => init(limit, skipVal))
|
||||||
|
.then(() => {
|
||||||
|
console.log(skipVal);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await promise;
|
||||||
|
|
||||||
|
jsonRes(res, {});
|
||||||
|
} catch (error) {
|
||||||
|
jsonRes(res, {
|
||||||
|
code: 500,
|
||||||
|
error
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function init(limit: number, skip: number) {
|
||||||
|
// 遍历 app
|
||||||
|
const chats = await Chat.find(
|
||||||
|
{
|
||||||
|
chatId: { $exists: false }
|
||||||
|
},
|
||||||
|
'_id'
|
||||||
|
)
|
||||||
|
.limit(limit)
|
||||||
|
.skip(skip);
|
||||||
|
|
||||||
|
await Promise.all(
|
||||||
|
chats.map((chat) =>
|
||||||
|
Chat.findByIdAndUpdate(chat._id, {
|
||||||
|
chatId: String(chat._id),
|
||||||
|
source: 'online'
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
@@ -1,47 +0,0 @@
|
|||||||
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
|
|
||||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
|
||||||
import { jsonRes } from '@/service/response';
|
|
||||||
import { authUser } from '@/service/utils/auth';
|
|
||||||
import { connectToDatabase, TrainingData, User, promotionRecord } from '@/service/mongo';
|
|
||||||
import { PRICE_SCALE } from '@/constants/common';
|
|
||||||
|
|
||||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
|
||||||
try {
|
|
||||||
await authUser({ req, authRoot: true });
|
|
||||||
await connectToDatabase();
|
|
||||||
|
|
||||||
// 计算剩余金额
|
|
||||||
const countResidue: { userId: string; totalAmount: number }[] = await promotionRecord.aggregate(
|
|
||||||
[
|
|
||||||
{
|
|
||||||
$group: {
|
|
||||||
_id: '$userId', // Group by userId
|
|
||||||
totalAmount: { $sum: '$amount' } // Calculate the sum of amount field
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
$project: {
|
|
||||||
_id: false, // Exclude _id field
|
|
||||||
userId: '$_id', // Include userId field
|
|
||||||
totalAmount: true // Include totalAmount field
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
await Promise.all(
|
|
||||||
countResidue.map((item) =>
|
|
||||||
User.findByIdAndUpdate(item.userId, {
|
|
||||||
$inc: { balance: item.totalAmount * PRICE_SCALE }
|
|
||||||
})
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
jsonRes(res, { data: countResidue });
|
|
||||||
} catch (error) {
|
|
||||||
jsonRes(res, {
|
|
||||||
code: 500,
|
|
||||||
error
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@@ -16,7 +16,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||||||
// 凭证校验
|
// 凭证校验
|
||||||
const { userId } = await authUser({ req, authToken: true });
|
const { userId } = await authUser({ req, authToken: true });
|
||||||
|
|
||||||
const chatRecord = await Chat.findById(chatId);
|
const chatRecord = await Chat.findOne({ chatId });
|
||||||
|
|
||||||
if (!chatRecord) {
|
if (!chatRecord) {
|
||||||
throw new Error('找不到对话');
|
throw new Error('找不到对话');
|
||||||
|
@@ -17,14 +17,14 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||||||
userId,
|
userId,
|
||||||
...(appId && { appId })
|
...(appId && { appId })
|
||||||
},
|
},
|
||||||
'_id title top customTitle appId updateTime'
|
'chatId title top customTitle appId updateTime'
|
||||||
)
|
)
|
||||||
.sort({ top: -1, updateTime: -1 })
|
.sort({ top: -1, updateTime: -1 })
|
||||||
.limit(20);
|
.limit(20);
|
||||||
|
|
||||||
jsonRes<ChatHistoryItemType[]>(res, {
|
jsonRes<ChatHistoryItemType[]>(res, {
|
||||||
data: data.map((item) => ({
|
data: data.map((item) => ({
|
||||||
_id: item._id,
|
chatId: item.chatId,
|
||||||
updateTime: item.updateTime,
|
updateTime: item.updateTime,
|
||||||
appId: item.appId,
|
appId: item.appId,
|
||||||
customTitle: item.customTitle,
|
customTitle: item.customTitle,
|
||||||
|
@@ -3,7 +3,6 @@ import { jsonRes } from '@/service/response';
|
|||||||
import { connectToDatabase, Chat } from '@/service/mongo';
|
import { connectToDatabase, Chat } from '@/service/mongo';
|
||||||
import { authUser } from '@/service/utils/auth';
|
import { authUser } from '@/service/utils/auth';
|
||||||
import { Types } from 'mongoose';
|
import { Types } from 'mongoose';
|
||||||
import { rawSearchKey } from '@/constants/chat';
|
|
||||||
|
|
||||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||||
try {
|
try {
|
||||||
@@ -36,13 +35,13 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
$project: {
|
$project: {
|
||||||
[rawSearchKey]: `$content.${rawSearchKey}`
|
// [rawSearchKey]: `$content.${rawSearchKey}`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
|
|
||||||
jsonRes(res, {
|
jsonRes(res, {
|
||||||
data: history[0]?.[rawSearchKey] || []
|
// data: history[0]?.[rawSearchKey] || []
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
jsonRes(res, {
|
jsonRes(res, {
|
||||||
|
@@ -20,7 +20,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||||||
|
|
||||||
await Chat.findOneAndUpdate(
|
await Chat.findOneAndUpdate(
|
||||||
{
|
{
|
||||||
_id: chatId,
|
chatId,
|
||||||
userId
|
userId
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@@ -27,7 +27,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||||||
|
|
||||||
await Chat.updateOne(
|
await Chat.updateOne(
|
||||||
{
|
{
|
||||||
_id: new Types.ObjectId(chatId),
|
chatId,
|
||||||
userId: new Types.ObjectId(userId),
|
userId: new Types.ObjectId(userId),
|
||||||
'content._id': new Types.ObjectId(contentId)
|
'content._id': new Types.ObjectId(contentId)
|
||||||
},
|
},
|
||||||
|
@@ -6,8 +6,7 @@ import { authUser } from '@/service/utils/auth';
|
|||||||
import { ChatItemType } from '@/types/chat';
|
import { ChatItemType } from '@/types/chat';
|
||||||
import { authApp } from '@/service/utils/auth';
|
import { authApp } from '@/service/utils/auth';
|
||||||
import mongoose from 'mongoose';
|
import mongoose from 'mongoose';
|
||||||
import type { AppSchema, ChatSchema } from '@/types/mongoSchema';
|
import type { ChatSchema } from '@/types/mongoSchema';
|
||||||
import { quoteLenKey, rawSearchKey } from '@/constants/chat';
|
|
||||||
import { getSpecialModule } from '@/components/ChatBox';
|
import { getSpecialModule } from '@/components/ChatBox';
|
||||||
|
|
||||||
/* 初始化我的聊天框,需要身份验证 */
|
/* 初始化我的聊天框,需要身份验证 */
|
||||||
@@ -20,72 +19,62 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||||||
chatId: '' | string;
|
chatId: '' | string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (!appId) {
|
||||||
|
return jsonRes(res, {
|
||||||
|
code: 501,
|
||||||
|
message: "You don't have an app yet"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
await connectToDatabase();
|
await connectToDatabase();
|
||||||
|
|
||||||
// 没有 appId 时,直接获取用户的第一个id
|
// 校验使用权限
|
||||||
const app = await (async () => {
|
const app = (
|
||||||
if (!appId) {
|
await authApp({
|
||||||
const myModel = await App.findOne({ userId });
|
appId,
|
||||||
if (!myModel) {
|
userId,
|
||||||
const { _id } = await App.create({
|
authUser: false,
|
||||||
name: '应用1',
|
authOwner: false
|
||||||
userId
|
})
|
||||||
});
|
).app;
|
||||||
return (await App.findById(_id)) as AppSchema;
|
|
||||||
} else {
|
|
||||||
return myModel;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 校验使用权限
|
|
||||||
const authRes = await authApp({
|
|
||||||
appId,
|
|
||||||
userId,
|
|
||||||
authUser: false,
|
|
||||||
authOwner: false
|
|
||||||
});
|
|
||||||
return authRes.app;
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
|
|
||||||
appId = appId || app._id;
|
|
||||||
|
|
||||||
// 历史记录
|
// 历史记录
|
||||||
const { chat, history = [] }: { chat?: ChatSchema; history?: ChatItemType[] } =
|
const { chat, history = [] }: { chat?: ChatSchema; history?: ChatItemType[] } =
|
||||||
await (async () => {
|
await (async () => {
|
||||||
if (chatId) {
|
if (chatId) {
|
||||||
// auth chatId
|
// auth chatId
|
||||||
const chat = await Chat.findOne({
|
const [chat, history] = await Promise.all([
|
||||||
_id: chatId,
|
Chat.findOne({
|
||||||
userId
|
chatId,
|
||||||
});
|
userId
|
||||||
|
}),
|
||||||
|
Chat.aggregate([
|
||||||
|
{
|
||||||
|
$match: {
|
||||||
|
chatId,
|
||||||
|
userId: new mongoose.Types.ObjectId(userId)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
$project: {
|
||||||
|
content: {
|
||||||
|
$slice: ['$content', -50] // 返回 content 数组的最后50个元素
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ $unwind: '$content' },
|
||||||
|
{
|
||||||
|
$project: {
|
||||||
|
_id: '$content._id',
|
||||||
|
obj: '$content.obj',
|
||||||
|
value: '$content.value'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
])
|
||||||
|
]);
|
||||||
if (!chat) {
|
if (!chat) {
|
||||||
throw new Error('聊天框不存在');
|
throw new Error('聊天框不存在');
|
||||||
}
|
}
|
||||||
// 获取 chat.content 数据
|
|
||||||
const history = await Chat.aggregate([
|
|
||||||
{
|
|
||||||
$match: {
|
|
||||||
_id: new mongoose.Types.ObjectId(chatId),
|
|
||||||
userId: new mongoose.Types.ObjectId(userId)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
$project: {
|
|
||||||
content: {
|
|
||||||
$slice: ['$content', -50] // 返回 content 数组的最后50个元素
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{ $unwind: '$content' },
|
|
||||||
{
|
|
||||||
$project: {
|
|
||||||
_id: '$content._id',
|
|
||||||
obj: '$content.obj',
|
|
||||||
value: '$content.value',
|
|
||||||
[quoteLenKey]: { $size: { $ifNull: [`$content.${rawSearchKey}`, []] } }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
return { history, chat };
|
return { history, chat };
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
|
@@ -6,13 +6,13 @@ import { authUser } from '@/service/utils/auth';
|
|||||||
/* 获取历史记录 */
|
/* 获取历史记录 */
|
||||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||||
try {
|
try {
|
||||||
const { id } = req.query;
|
const { chatId } = req.query;
|
||||||
const { userId } = await authUser({ req, authToken: true });
|
const { userId } = await authUser({ req, authToken: true });
|
||||||
|
|
||||||
await connectToDatabase();
|
await connectToDatabase();
|
||||||
|
|
||||||
await Chat.findOneAndRemove({
|
await Chat.findOneAndRemove({
|
||||||
_id: id,
|
chatId,
|
||||||
userId
|
userId
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -1,104 +0,0 @@
|
|||||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
|
||||||
import { jsonRes } from '@/service/response';
|
|
||||||
import { ChatItemType } from '@/types/chat';
|
|
||||||
import { connectToDatabase, Chat, App } from '@/service/mongo';
|
|
||||||
import { authApp } from '@/service/utils/auth';
|
|
||||||
import { authUser } from '@/service/utils/auth';
|
|
||||||
import { Types } from 'mongoose';
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
chatId?: string;
|
|
||||||
appId: string;
|
|
||||||
variables?: Record<string, any>;
|
|
||||||
prompts: [ChatItemType, ChatItemType];
|
|
||||||
};
|
|
||||||
|
|
||||||
/* 聊天内容存存储 */
|
|
||||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
|
||||||
try {
|
|
||||||
const { chatId, appId, prompts } = req.body as Props;
|
|
||||||
|
|
||||||
if (!prompts) {
|
|
||||||
throw new Error('缺少参数');
|
|
||||||
}
|
|
||||||
|
|
||||||
const { userId } = await authUser({ req, authToken: true });
|
|
||||||
|
|
||||||
const response = await saveChat({
|
|
||||||
chatId,
|
|
||||||
appId,
|
|
||||||
prompts,
|
|
||||||
userId
|
|
||||||
});
|
|
||||||
|
|
||||||
jsonRes(res, {
|
|
||||||
data: response
|
|
||||||
});
|
|
||||||
} catch (err) {
|
|
||||||
jsonRes(res, {
|
|
||||||
code: 500,
|
|
||||||
error: err
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function saveChat({
|
|
||||||
newChatId,
|
|
||||||
chatId,
|
|
||||||
appId,
|
|
||||||
prompts,
|
|
||||||
variables,
|
|
||||||
userId
|
|
||||||
}: Props & { newChatId?: Types.ObjectId; userId: string }): Promise<{ newChatId: string }> {
|
|
||||||
await connectToDatabase();
|
|
||||||
const { app } = await authApp({ appId, userId, authOwner: false });
|
|
||||||
|
|
||||||
if (String(app.userId) === userId) {
|
|
||||||
await App.findByIdAndUpdate(appId, {
|
|
||||||
updateTime: new Date()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const [response] = await Promise.all([
|
|
||||||
...(chatId
|
|
||||||
? [
|
|
||||||
Chat.findByIdAndUpdate(chatId, {
|
|
||||||
$push: {
|
|
||||||
content: {
|
|
||||||
$each: prompts
|
|
||||||
}
|
|
||||||
},
|
|
||||||
variables,
|
|
||||||
title: prompts[0].value.slice(0, 20),
|
|
||||||
updateTime: new Date()
|
|
||||||
}).then(() => ({
|
|
||||||
newChatId: ''
|
|
||||||
}))
|
|
||||||
]
|
|
||||||
: [
|
|
||||||
Chat.create({
|
|
||||||
_id: newChatId,
|
|
||||||
userId,
|
|
||||||
appId,
|
|
||||||
variables,
|
|
||||||
content: prompts,
|
|
||||||
title: prompts[0].value.slice(0, 20)
|
|
||||||
}).then((res) => ({
|
|
||||||
newChatId: String(res._id)
|
|
||||||
}))
|
|
||||||
]),
|
|
||||||
// update app
|
|
||||||
...(String(app.userId) === userId
|
|
||||||
? [
|
|
||||||
App.findByIdAndUpdate(appId, {
|
|
||||||
updateTime: new Date()
|
|
||||||
})
|
|
||||||
]
|
|
||||||
: [])
|
|
||||||
]);
|
|
||||||
|
|
||||||
return {
|
|
||||||
// @ts-ignore
|
|
||||||
newChatId: response?.newChatId || ''
|
|
||||||
};
|
|
||||||
}
|
|
@@ -9,7 +9,7 @@ const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 24);
|
|||||||
/* create a shareChat */
|
/* create a shareChat */
|
||||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||||
try {
|
try {
|
||||||
const { appId, name, maxContext } = req.body as ShareChatEditType & {
|
const { appId, name } = req.body as ShareChatEditType & {
|
||||||
appId: string;
|
appId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -27,8 +27,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||||||
shareId,
|
shareId,
|
||||||
userId,
|
userId,
|
||||||
appId,
|
appId,
|
||||||
name,
|
name
|
||||||
maxContext
|
|
||||||
});
|
});
|
||||||
|
|
||||||
jsonRes(res, {
|
jsonRes(res, {
|
||||||
|
@@ -3,10 +3,7 @@ import { jsonRes } from '@/service/response';
|
|||||||
import { connectToDatabase, ShareChat, User } from '@/service/mongo';
|
import { connectToDatabase, ShareChat, User } from '@/service/mongo';
|
||||||
import type { InitShareChatResponse } from '@/api/response/chat';
|
import type { InitShareChatResponse } from '@/api/response/chat';
|
||||||
import { authApp } from '@/service/utils/auth';
|
import { authApp } from '@/service/utils/auth';
|
||||||
import { hashPassword } from '@/service/utils/tools';
|
|
||||||
import { HUMAN_ICON } from '@/constants/chat';
|
import { HUMAN_ICON } from '@/constants/chat';
|
||||||
import { FlowModuleTypeEnum } from '@/constants/flow';
|
|
||||||
import { SystemInputEnum } from '@/constants/app';
|
|
||||||
import { getSpecialModule } from '@/components/ChatBox';
|
import { getSpecialModule } from '@/components/ChatBox';
|
||||||
|
|
||||||
/* 初始化我的聊天框,需要身份验证 */
|
/* 初始化我的聊天框,需要身份验证 */
|
||||||
@@ -33,21 +30,18 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 校验使用权限
|
// 校验使用权限
|
||||||
const { app } = await authApp({
|
const [{ app }, user] = await Promise.all([
|
||||||
appId: shareChat.appId,
|
authApp({
|
||||||
userId: String(shareChat.userId),
|
appId: shareChat.appId,
|
||||||
authOwner: false
|
userId: String(shareChat.userId),
|
||||||
});
|
authOwner: false
|
||||||
|
}),
|
||||||
const user = await User.findById(shareChat.userId, 'avatar');
|
User.findById(shareChat.userId, 'avatar')
|
||||||
|
]);
|
||||||
|
|
||||||
jsonRes<InitShareChatResponse>(res, {
|
jsonRes<InitShareChatResponse>(res, {
|
||||||
data: {
|
data: {
|
||||||
userAvatar: user?.avatar || HUMAN_ICON,
|
userAvatar: user?.avatar || HUMAN_ICON,
|
||||||
maxContext:
|
|
||||||
app.modules
|
|
||||||
?.find((item) => item.flowType === FlowModuleTypeEnum.historyNode)
|
|
||||||
?.inputs?.find((item) => item.key === 'maxContext')?.value || 0,
|
|
||||||
app: {
|
app: {
|
||||||
...getSpecialModule(app.modules),
|
...getSpecialModule(app.modules),
|
||||||
name: app.name,
|
name: app.name,
|
||||||
|
@@ -28,7 +28,6 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||||||
shareId: item.shareId,
|
shareId: item.shareId,
|
||||||
name: item.name,
|
name: item.name,
|
||||||
total: item.total,
|
total: item.total,
|
||||||
maxContext: item.maxContext,
|
|
||||||
lastTime: item.lastTime
|
lastTime: item.lastTime
|
||||||
}))
|
}))
|
||||||
});
|
});
|
||||||
|
@@ -3,7 +3,7 @@ import { connectToDatabase } from '@/service/mongo';
|
|||||||
import { authUser, authApp, authShareChat } from '@/service/utils/auth';
|
import { authUser, authApp, authShareChat } from '@/service/utils/auth';
|
||||||
import { sseErrRes, jsonRes } from '@/service/response';
|
import { sseErrRes, jsonRes } from '@/service/response';
|
||||||
import { withNextCors } from '@/service/utils/tools';
|
import { withNextCors } from '@/service/utils/tools';
|
||||||
import { ChatRoleEnum, sseResponseEventEnum } from '@/constants/chat';
|
import { ChatRoleEnum, ChatSourceEnum, sseResponseEventEnum } from '@/constants/chat';
|
||||||
import {
|
import {
|
||||||
dispatchHistory,
|
dispatchHistory,
|
||||||
dispatchChatInput,
|
dispatchChatInput,
|
||||||
@@ -15,12 +15,11 @@ import {
|
|||||||
import type { CreateChatCompletionRequest } from 'openai';
|
import type { CreateChatCompletionRequest } from 'openai';
|
||||||
import { gptMessage2ChatType } from '@/utils/adapt';
|
import { gptMessage2ChatType } from '@/utils/adapt';
|
||||||
import { getChatHistory } from './getHistory';
|
import { getChatHistory } from './getHistory';
|
||||||
import { saveChat } from '@/pages/api/chat/saveChat';
|
import { saveChat } from '@/service/utils/chat/saveChat';
|
||||||
import { sseResponse } from '@/service/utils/tools';
|
import { sseResponse } from '@/service/utils/tools';
|
||||||
import { type ChatCompletionRequestMessage } from 'openai';
|
import { type ChatCompletionRequestMessage } from 'openai';
|
||||||
import { TaskResponseKeyEnum } from '@/constants/chat';
|
import { TaskResponseKeyEnum } from '@/constants/chat';
|
||||||
import { FlowModuleTypeEnum, initModuleType } from '@/constants/flow';
|
import { FlowModuleTypeEnum, initModuleType } from '@/constants/flow';
|
||||||
import { Types } from 'mongoose';
|
|
||||||
import { AppModuleItemType, RunningModuleItemType } from '@/types/app';
|
import { AppModuleItemType, RunningModuleItemType } from '@/types/app';
|
||||||
import { pushTaskBill } from '@/service/events/pushBill';
|
import { pushTaskBill } from '@/service/events/pushBill';
|
||||||
import { BillSourceEnum } from '@/constants/user';
|
import { BillSourceEnum } from '@/constants/user';
|
||||||
@@ -101,16 +100,10 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
|
|||||||
}
|
}
|
||||||
// user question
|
// user question
|
||||||
const prompt = prompts.pop();
|
const prompt = prompts.pop();
|
||||||
|
|
||||||
if (!prompt) {
|
if (!prompt) {
|
||||||
throw new Error('Question is empty');
|
throw new Error('Question is empty');
|
||||||
}
|
}
|
||||||
|
|
||||||
const newChatId = chatId === '' ? new Types.ObjectId() : undefined;
|
|
||||||
if (stream && newChatId) {
|
|
||||||
res.setHeader('newChatId', String(newChatId));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* start process */
|
/* start process */
|
||||||
const { responseData, answerText } = await dispatchModules({
|
const { responseData, answerText } = await dispatchModules({
|
||||||
res,
|
res,
|
||||||
@@ -122,29 +115,39 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
|
|||||||
},
|
},
|
||||||
stream
|
stream
|
||||||
});
|
});
|
||||||
console.log(responseData, '===', answerText);
|
// console.log(responseData, '===', answerText);
|
||||||
|
|
||||||
if (!answerText) {
|
// if (!answerText) {
|
||||||
throw new Error('回复内容为空,可能模块编排出现问题');
|
// throw new Error('回复内容为空,可能模块编排出现问题');
|
||||||
}
|
// }
|
||||||
|
|
||||||
// save chat
|
// save chat
|
||||||
if (typeof chatId === 'string') {
|
if (typeof chatId === 'string') {
|
||||||
await saveChat({
|
await saveChat({
|
||||||
chatId,
|
chatId,
|
||||||
newChatId,
|
|
||||||
appId,
|
appId,
|
||||||
|
userId,
|
||||||
variables,
|
variables,
|
||||||
prompts: [
|
isOwner,
|
||||||
|
shareId,
|
||||||
|
source: (() => {
|
||||||
|
if (shareId) {
|
||||||
|
return ChatSourceEnum.share;
|
||||||
|
}
|
||||||
|
if (authType === 'apikey') {
|
||||||
|
return ChatSourceEnum.api;
|
||||||
|
}
|
||||||
|
return ChatSourceEnum.online;
|
||||||
|
})(),
|
||||||
|
content: [
|
||||||
prompt,
|
prompt,
|
||||||
{
|
{
|
||||||
_id: messages[messages.length - 1]._id,
|
_id: messages[messages.length - 1]._id,
|
||||||
obj: ChatRoleEnum.AI,
|
obj: ChatRoleEnum.AI,
|
||||||
value: answerText,
|
value: answerText,
|
||||||
...responseData
|
responseData
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
userId
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -43,7 +43,7 @@ export async function getChatHistory({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const history = await Chat.aggregate([
|
const history = await Chat.aggregate([
|
||||||
{ $match: { _id: new Types.ObjectId(chatId), userId: new Types.ObjectId(userId) } },
|
{ $match: { chatId, userId: new Types.ObjectId(userId) } },
|
||||||
{
|
{
|
||||||
$project: {
|
$project: {
|
||||||
content: {
|
content: {
|
||||||
@@ -54,10 +54,8 @@ export async function getChatHistory({
|
|||||||
{ $unwind: '$content' },
|
{ $unwind: '$content' },
|
||||||
{
|
{
|
||||||
$project: {
|
$project: {
|
||||||
_id: '$content._id',
|
|
||||||
obj: '$content.obj',
|
obj: '$content.obj',
|
||||||
value: '$content.value',
|
value: '$content.value'
|
||||||
quote: '$content.quote'
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
|
@@ -42,6 +42,66 @@ export async function getInitConfig() {
|
|||||||
global.qaModels = res.QAModels;
|
global.qaModels = res.QAModels;
|
||||||
global.vectorModels = res.VectorModels;
|
global.vectorModels = res.VectorModels;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
setDefaultData();
|
||||||
return Promise.reject('get init config error');
|
return Promise.reject('get init config error');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function setDefaultData() {
|
||||||
|
global.systemEnv = {
|
||||||
|
vectorMaxProcess: 15,
|
||||||
|
qaMaxProcess: 15,
|
||||||
|
pgIvfflatProbe: 20,
|
||||||
|
sensitiveCheck: false
|
||||||
|
};
|
||||||
|
global.feConfigs = {
|
||||||
|
show_emptyChat: true,
|
||||||
|
show_register: true,
|
||||||
|
show_appStore: true,
|
||||||
|
show_userDetail: true,
|
||||||
|
show_git: true,
|
||||||
|
systemTitle: 'FastAI',
|
||||||
|
authorText: 'Made by FastAI Team.'
|
||||||
|
};
|
||||||
|
global.chatModels = [
|
||||||
|
{
|
||||||
|
model: 'gpt-3.5-turbo',
|
||||||
|
name: 'FastAI-4k',
|
||||||
|
contextMaxToken: 4000,
|
||||||
|
systemMaxToken: 2400,
|
||||||
|
maxTemperature: 1.2,
|
||||||
|
price: 1.5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model: 'gpt-3.5-turbo-16k',
|
||||||
|
name: 'FastAI-16k',
|
||||||
|
contextMaxToken: 16000,
|
||||||
|
systemMaxToken: 8000,
|
||||||
|
maxTemperature: 1.2,
|
||||||
|
price: 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model: 'gpt-4',
|
||||||
|
name: 'FastAI-Plus',
|
||||||
|
contextMaxToken: 8000,
|
||||||
|
systemMaxToken: 4000,
|
||||||
|
maxTemperature: 1.2,
|
||||||
|
price: 45
|
||||||
|
}
|
||||||
|
];
|
||||||
|
global.qaModels = [
|
||||||
|
{
|
||||||
|
model: 'gpt-3.5-turbo-16k',
|
||||||
|
name: 'FastAI-16k',
|
||||||
|
maxToken: 16000,
|
||||||
|
price: 3
|
||||||
|
}
|
||||||
|
];
|
||||||
|
global.vectorModels = [
|
||||||
|
{
|
||||||
|
model: 'text-embedding-ada-002',
|
||||||
|
name: 'Embedding-2',
|
||||||
|
price: 0.2
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
@@ -441,7 +441,7 @@ const Settings = ({ appId }: { appId: string }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const ChatTest = ({ appId }: { appId: string }) => {
|
const ChatTest = ({ appId }: { appId: string }) => {
|
||||||
const { appDetail } = useUserStore();
|
const { appDetail, userInfo } = useUserStore();
|
||||||
const ChatBoxRef = useRef<ComponentRef>(null);
|
const ChatBoxRef = useRef<ComponentRef>(null);
|
||||||
const [modules, setModules] = useState<AppModuleItemType[]>([]);
|
const [modules, setModules] = useState<AppModuleItemType[]>([]);
|
||||||
|
|
||||||
@@ -509,6 +509,7 @@ const ChatTest = ({ appId }: { appId: string }) => {
|
|||||||
<ChatBox
|
<ChatBox
|
||||||
ref={ChatBoxRef}
|
ref={ChatBoxRef}
|
||||||
appAvatar={appDetail.avatar}
|
appAvatar={appDetail.avatar}
|
||||||
|
userAvatar={userInfo?.avatar}
|
||||||
{...getSpecialModule(modules)}
|
{...getSpecialModule(modules)}
|
||||||
onStartChat={startChat}
|
onStartChat={startChat}
|
||||||
onDelMessage={() => {}}
|
onDelMessage={() => {}}
|
||||||
|
@@ -13,6 +13,7 @@ import MyIcon from '@/components/Icon';
|
|||||||
import { FlowModuleTypeEnum } from '@/constants/flow';
|
import { FlowModuleTypeEnum } from '@/constants/flow';
|
||||||
import { streamFetch } from '@/api/fetch';
|
import { streamFetch } from '@/api/fetch';
|
||||||
import MyTooltip from '@/components/MyTooltip';
|
import MyTooltip from '@/components/MyTooltip';
|
||||||
|
import { useUserStore } from '@/store/user';
|
||||||
import ChatBox, {
|
import ChatBox, {
|
||||||
getSpecialModule,
|
getSpecialModule,
|
||||||
type ComponentRef,
|
type ComponentRef,
|
||||||
@@ -36,6 +37,7 @@ const ChatTest = (
|
|||||||
ref: ForwardedRef<ChatTestComponentRef>
|
ref: ForwardedRef<ChatTestComponentRef>
|
||||||
) => {
|
) => {
|
||||||
const ChatBoxRef = useRef<ComponentRef>(null);
|
const ChatBoxRef = useRef<ComponentRef>(null);
|
||||||
|
const { userInfo } = useUserStore();
|
||||||
const isOpen = useMemo(() => modules && modules.length > 0, [modules]);
|
const isOpen = useMemo(() => modules && modules.length > 0, [modules]);
|
||||||
|
|
||||||
const startChat = useCallback(
|
const startChat = useCallback(
|
||||||
@@ -47,7 +49,7 @@ const ChatTest = (
|
|||||||
const history = messages.slice(-historyMaxLen - 2, -2);
|
const history = messages.slice(-historyMaxLen - 2, -2);
|
||||||
|
|
||||||
// 流请求,获取数据
|
// 流请求,获取数据
|
||||||
const { responseText, rawSearch } = await streamFetch({
|
const { responseText } = await streamFetch({
|
||||||
url: '/api/chat/chatTest',
|
url: '/api/chat/chatTest',
|
||||||
data: {
|
data: {
|
||||||
history,
|
history,
|
||||||
@@ -61,7 +63,7 @@ const ChatTest = (
|
|||||||
abortSignal: controller
|
abortSignal: controller
|
||||||
});
|
});
|
||||||
|
|
||||||
return { responseText, rawSearch };
|
return { responseText };
|
||||||
},
|
},
|
||||||
[app._id, app.name, modules]
|
[app._id, app.name, modules]
|
||||||
);
|
);
|
||||||
@@ -113,6 +115,7 @@ const ChatTest = (
|
|||||||
<ChatBox
|
<ChatBox
|
||||||
ref={ChatBoxRef}
|
ref={ChatBoxRef}
|
||||||
appAvatar={app.avatar}
|
appAvatar={app.avatar}
|
||||||
|
userAvatar={userInfo?.avatar}
|
||||||
{...getSpecialModule(modules)}
|
{...getSpecialModule(modules)}
|
||||||
onStartChat={startChat}
|
onStartChat={startChat}
|
||||||
onDelMessage={() => {}}
|
onDelMessage={() => {}}
|
||||||
|
@@ -15,19 +15,24 @@ import { useQuery } from '@tanstack/react-query';
|
|||||||
import { streamFetch } from '@/api/fetch';
|
import { streamFetch } from '@/api/fetch';
|
||||||
import { useChatStore } from '@/store/chat';
|
import { useChatStore } from '@/store/chat';
|
||||||
import { useLoading } from '@/hooks/useLoading';
|
import { useLoading } from '@/hooks/useLoading';
|
||||||
|
import { useToast } from '@/hooks/useToast';
|
||||||
|
import { customAlphabet } from 'nanoid';
|
||||||
|
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 12);
|
||||||
|
import type { ChatHistoryItemType } from '@/types/chat';
|
||||||
|
|
||||||
import ChatBox, { type ComponentRef, type StartChatFnProps } from '@/components/ChatBox';
|
import ChatBox, { type ComponentRef, type StartChatFnProps } from '@/components/ChatBox';
|
||||||
import { ChatHistoryItemType } from '@/types/chat';
|
|
||||||
import PageContainer from '@/components/PageContainer';
|
import PageContainer from '@/components/PageContainer';
|
||||||
import SideBar from '@/components/SideBar';
|
import SideBar from '@/components/SideBar';
|
||||||
import ChatHistorySlider from './components/ChatHistorySlider';
|
import ChatHistorySlider from './components/ChatHistorySlider';
|
||||||
import SliderApps from './components/SliderApps';
|
import SliderApps from './components/SliderApps';
|
||||||
import ChatHeader from './components/ChatHeader';
|
import ChatHeader from './components/ChatHeader';
|
||||||
|
import { getErrText } from '@/utils/tools';
|
||||||
|
import { useUserStore } from '@/store/user';
|
||||||
|
|
||||||
const Chat = () => {
|
const Chat = ({ appId, chatId }: { appId: string; chatId: string }) => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { appId = '', chatId = '' } = router.query as { appId: string; chatId: string };
|
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
const { toast } = useToast();
|
||||||
|
|
||||||
const ChatBoxRef = useRef<ComponentRef>(null);
|
const ChatBoxRef = useRef<ComponentRef>(null);
|
||||||
const forbidRefresh = useRef(false);
|
const forbidRefresh = useRef(false);
|
||||||
@@ -44,6 +49,7 @@ const Chat = () => {
|
|||||||
chatData,
|
chatData,
|
||||||
setChatData
|
setChatData
|
||||||
} = useChatStore();
|
} = useChatStore();
|
||||||
|
const { myApps, userInfo } = useUserStore();
|
||||||
|
|
||||||
const { isPc } = useGlobalStore();
|
const { isPc } = useGlobalStore();
|
||||||
const { Loading, setIsLoading } = useLoading();
|
const { Loading, setIsLoading } = useLoading();
|
||||||
@@ -52,12 +58,14 @@ const Chat = () => {
|
|||||||
const startChat = useCallback(
|
const startChat = useCallback(
|
||||||
async ({ messages, controller, generatingMessage, variables }: StartChatFnProps) => {
|
async ({ messages, controller, generatingMessage, variables }: StartChatFnProps) => {
|
||||||
const prompts = messages.slice(-2);
|
const prompts = messages.slice(-2);
|
||||||
const { responseText, newChatId, rawSearch } = await streamFetch({
|
const completionChatId = chatId ? chatId : nanoid();
|
||||||
|
|
||||||
|
const { responseText } = await streamFetch({
|
||||||
data: {
|
data: {
|
||||||
messages: prompts,
|
messages: prompts,
|
||||||
variables,
|
variables,
|
||||||
appId,
|
appId,
|
||||||
chatId
|
chatId: completionChatId
|
||||||
},
|
},
|
||||||
onMessage: generatingMessage,
|
onMessage: generatingMessage,
|
||||||
abortSignal: controller
|
abortSignal: controller
|
||||||
@@ -66,10 +74,10 @@ const Chat = () => {
|
|||||||
const newTitle = prompts[0].content?.slice(0, 20) || '新对话';
|
const newTitle = prompts[0].content?.slice(0, 20) || '新对话';
|
||||||
|
|
||||||
// update history
|
// update history
|
||||||
if (newChatId && !controller.signal.aborted) {
|
if (completionChatId !== chatId && !controller.signal.aborted) {
|
||||||
forbidRefresh.current = true;
|
forbidRefresh.current = true;
|
||||||
const newHistory: ChatHistoryItemType = {
|
const newHistory: ChatHistoryItemType = {
|
||||||
_id: newChatId,
|
chatId: completionChatId,
|
||||||
updateTime: new Date(),
|
updateTime: new Date(),
|
||||||
title: newTitle,
|
title: newTitle,
|
||||||
appId,
|
appId,
|
||||||
@@ -78,12 +86,12 @@ const Chat = () => {
|
|||||||
updateHistory(newHistory);
|
updateHistory(newHistory);
|
||||||
router.replace({
|
router.replace({
|
||||||
query: {
|
query: {
|
||||||
chatId: newChatId,
|
chatId: completionChatId,
|
||||||
appId
|
appId
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
const currentChat = history.find((item) => item._id === chatId);
|
const currentChat = history.find((item) => item.chatId === chatId);
|
||||||
currentChat &&
|
currentChat &&
|
||||||
updateHistory({
|
updateHistory({
|
||||||
...currentChat,
|
...currentChat,
|
||||||
@@ -98,7 +106,7 @@ const Chat = () => {
|
|||||||
history: ChatBoxRef.current?.getChatHistory() || state.history
|
history: ChatBoxRef.current?.getChatHistory() || state.history
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return { responseText, rawSearch };
|
return { responseText };
|
||||||
},
|
},
|
||||||
[appId, chatId, history, router, setChatData, updateHistory]
|
[appId, chatId, history, router, setChatData, updateHistory]
|
||||||
);
|
);
|
||||||
@@ -153,38 +161,43 @@ const Chat = () => {
|
|||||||
ChatBoxRef.current?.scrollToBottom('auto');
|
ChatBoxRef.current?.scrollToBottom('auto');
|
||||||
}, 200);
|
}, 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
// empty appId request, return first app
|
|
||||||
if (res.appId !== appId) {
|
|
||||||
forbidRefresh.current = true;
|
|
||||||
router.replace({
|
|
||||||
query: {
|
|
||||||
appId: res.appId
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
// reset all chat tore
|
// reset all chat tore
|
||||||
setLastChatAppId('');
|
setLastChatAppId('');
|
||||||
setLastChatId('');
|
setLastChatId('');
|
||||||
router.replace('/chat');
|
toast({
|
||||||
|
title: getErrText(e, '初始化聊天失败'),
|
||||||
|
status: 'error'
|
||||||
|
});
|
||||||
|
if (e?.code === 501) {
|
||||||
|
router.replace('/app/list');
|
||||||
|
} else {
|
||||||
|
router.replace('/chat');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
[setIsLoading, setChatData, router, setLastChatAppId, setLastChatId]
|
[setIsLoading, setChatData, router, setLastChatAppId, setLastChatId, toast]
|
||||||
);
|
);
|
||||||
// 初始化聊天框
|
// 初始化聊天框
|
||||||
useQuery(['init', appId, chatId], () => {
|
useQuery(['init', appId, chatId], () => {
|
||||||
// pc: redirect to latest model chat
|
// pc: redirect to latest model chat
|
||||||
if (!appId && lastChatAppId) {
|
if (!appId && lastChatAppId) {
|
||||||
router.replace({
|
return router.replace({
|
||||||
query: {
|
query: {
|
||||||
appId: lastChatAppId,
|
appId: lastChatAppId,
|
||||||
chatId: lastChatId
|
chatId: lastChatId
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return null;
|
}
|
||||||
|
if (!appId && myApps[0]) {
|
||||||
|
return router.replace({
|
||||||
|
query: {
|
||||||
|
appId: myApps[0]._id,
|
||||||
|
chatId: lastChatId
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// store id
|
// store id
|
||||||
@@ -196,11 +209,15 @@ const Chat = () => {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return loadChatInfo({
|
if (appId) {
|
||||||
appId,
|
return loadChatInfo({
|
||||||
chatId,
|
appId,
|
||||||
loading: appId !== chatData.appId
|
chatId,
|
||||||
});
|
loading: appId !== chatData.appId
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
useQuery(['loadHistory', appId], () => (appId ? loadHistory({ appId }) : null));
|
useQuery(['loadHistory', appId], () => (appId ? loadHistory({ appId }) : null));
|
||||||
@@ -233,7 +250,7 @@ const Chat = () => {
|
|||||||
appAvatar={chatData.app.avatar}
|
appAvatar={chatData.app.avatar}
|
||||||
activeChatId={chatId}
|
activeChatId={chatId}
|
||||||
history={history.map((item) => ({
|
history={history.map((item) => ({
|
||||||
id: item._id,
|
id: item.chatId,
|
||||||
title: item.title,
|
title: item.title,
|
||||||
customTitle: item.customTitle,
|
customTitle: item.customTitle,
|
||||||
top: item.top
|
top: item.top
|
||||||
@@ -253,7 +270,7 @@ const Chat = () => {
|
|||||||
onSetHistoryTop={async (e) => {
|
onSetHistoryTop={async (e) => {
|
||||||
try {
|
try {
|
||||||
await putChatHistory(e);
|
await putChatHistory(e);
|
||||||
const historyItem = history.find((item) => item._id === e.chatId);
|
const historyItem = history.find((item) => item.chatId === e.chatId);
|
||||||
if (!historyItem) return;
|
if (!historyItem) return;
|
||||||
updateHistory({
|
updateHistory({
|
||||||
...historyItem,
|
...historyItem,
|
||||||
@@ -267,7 +284,7 @@ const Chat = () => {
|
|||||||
chatId: e.chatId,
|
chatId: e.chatId,
|
||||||
customTitle: e.title
|
customTitle: e.title
|
||||||
});
|
});
|
||||||
const historyItem = history.find((item) => item._id === e.chatId);
|
const historyItem = history.find((item) => item.chatId === e.chatId);
|
||||||
if (!historyItem) return;
|
if (!historyItem) return;
|
||||||
updateHistory({
|
updateHistory({
|
||||||
...historyItem,
|
...historyItem,
|
||||||
@@ -300,6 +317,7 @@ const Chat = () => {
|
|||||||
showEmptyIntro
|
showEmptyIntro
|
||||||
chatId={chatId}
|
chatId={chatId}
|
||||||
appAvatar={chatData.app.avatar}
|
appAvatar={chatData.app.avatar}
|
||||||
|
userAvatar={userInfo?.avatar}
|
||||||
variableModules={chatData.app.variableModules}
|
variableModules={chatData.app.variableModules}
|
||||||
welcomeText={chatData.app.welcomeText}
|
welcomeText={chatData.app.welcomeText}
|
||||||
onUpdateVariable={(e) => {}}
|
onUpdateVariable={(e) => {}}
|
||||||
@@ -315,4 +333,13 @@ const Chat = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export async function getServerSideProps(context: any) {
|
||||||
|
return {
|
||||||
|
props: {
|
||||||
|
appId: context?.query?.appId || '',
|
||||||
|
chatId: context?.query?.chatId || ''
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export default Chat;
|
export default Chat;
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import React, { useCallback, useEffect, useRef } from 'react';
|
import React, { useCallback, useMemo, useRef } from 'react';
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
import { initShareChatInfo } from '@/api/chat';
|
import { initShareChatInfo } from '@/api/chat';
|
||||||
import { Box, Flex, useDisclosure, Drawer, DrawerOverlay, DrawerContent } from '@chakra-ui/react';
|
import { Box, Flex, useDisclosure, Drawer, DrawerOverlay, DrawerContent } from '@chakra-ui/react';
|
||||||
@@ -10,14 +10,14 @@ import { useShareChatStore, defaultHistory } from '@/store/shareChat';
|
|||||||
import SideBar from '@/components/SideBar';
|
import SideBar from '@/components/SideBar';
|
||||||
import { gptMessage2ChatType } from '@/utils/adapt';
|
import { gptMessage2ChatType } from '@/utils/adapt';
|
||||||
import { getErrText } from '@/utils/tools';
|
import { getErrText } from '@/utils/tools';
|
||||||
import dynamic from 'next/dynamic';
|
import { ChatSiteItemType } from '@/types/chat';
|
||||||
|
import { customAlphabet } from 'nanoid';
|
||||||
|
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 12);
|
||||||
|
|
||||||
import ChatBox, { type ComponentRef, type StartChatFnProps } from '@/components/ChatBox';
|
import ChatBox, { type ComponentRef, type StartChatFnProps } from '@/components/ChatBox';
|
||||||
import PageContainer from '@/components/PageContainer';
|
import PageContainer from '@/components/PageContainer';
|
||||||
import ChatHeader from './components/ChatHeader';
|
import ChatHeader from './components/ChatHeader';
|
||||||
|
import ChatHistorySlider from './components/ChatHistorySlider';
|
||||||
const ChatHistorySlider = dynamic(() => import('./components/ChatHistorySlider'), {
|
|
||||||
ssr: false
|
|
||||||
});
|
|
||||||
|
|
||||||
const ShareChat = ({ shareId, chatId }: { shareId: string; chatId: string }) => {
|
const ShareChat = ({ shareId, chatId }: { shareId: string; chatId: string }) => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@@ -36,44 +36,46 @@ const ShareChat = ({ shareId, chatId }: { shareId: string; chatId: string }) =>
|
|||||||
delOneShareHistoryByChatId,
|
delOneShareHistoryByChatId,
|
||||||
delManyShareChatHistoryByShareId
|
delManyShareChatHistoryByShareId
|
||||||
} = useShareChatStore();
|
} = useShareChatStore();
|
||||||
|
const history = useMemo(
|
||||||
|
() => shareChatHistory.filter((item) => item.shareId === shareId),
|
||||||
|
[shareChatHistory, shareId]
|
||||||
|
);
|
||||||
|
|
||||||
const startChat = useCallback(
|
const startChat = useCallback(
|
||||||
async ({ messages, controller, generatingMessage, variables }: StartChatFnProps) => {
|
async ({ messages, controller, generatingMessage, variables }: StartChatFnProps) => {
|
||||||
const prompts = messages.slice(-shareChatData.maxContext - 2);
|
const prompts = messages.slice(-2);
|
||||||
|
const completionChatId = chatId ? chatId : nanoid();
|
||||||
|
|
||||||
const { responseText } = await streamFetch({
|
const { responseText } = await streamFetch({
|
||||||
data: {
|
data: {
|
||||||
history,
|
|
||||||
messages: prompts,
|
messages: prompts,
|
||||||
variables,
|
variables,
|
||||||
shareId
|
shareId,
|
||||||
|
chatId: completionChatId
|
||||||
},
|
},
|
||||||
onMessage: generatingMessage,
|
onMessage: generatingMessage,
|
||||||
abortSignal: controller
|
abortSignal: controller
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = {
|
const result: ChatSiteItemType[] = gptMessage2ChatType(prompts).map((item) => ({
|
||||||
question: messages[messages.length - 2].content || '',
|
...item,
|
||||||
answer: responseText
|
status: 'finish'
|
||||||
};
|
}));
|
||||||
|
result[1].value = responseText;
|
||||||
prompts[prompts.length - 1].content = responseText;
|
|
||||||
|
|
||||||
/* save chat */
|
/* save chat */
|
||||||
const { newChatId } = saveChatResponse({
|
saveChatResponse({
|
||||||
chatId,
|
chatId: completionChatId,
|
||||||
prompts: gptMessage2ChatType(prompts).map((item) => ({
|
prompts: result,
|
||||||
...item,
|
|
||||||
status: 'finish'
|
|
||||||
})),
|
|
||||||
variables,
|
variables,
|
||||||
shareId
|
shareId
|
||||||
});
|
});
|
||||||
|
|
||||||
if (newChatId && !controller.signal.aborted) {
|
if (completionChatId !== chatId && !controller.signal.aborted) {
|
||||||
router.replace({
|
router.replace({
|
||||||
query: {
|
query: {
|
||||||
shareId,
|
shareId,
|
||||||
chatId: newChatId
|
chatId: completionChatId
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -81,14 +83,17 @@ const ShareChat = ({ shareId, chatId }: { shareId: string; chatId: string }) =>
|
|||||||
window.top?.postMessage(
|
window.top?.postMessage(
|
||||||
{
|
{
|
||||||
type: 'shareChatFinish',
|
type: 'shareChatFinish',
|
||||||
data: result
|
data: {
|
||||||
|
question: result[0]?.value,
|
||||||
|
answer: result[1]?.value
|
||||||
|
}
|
||||||
},
|
},
|
||||||
'*'
|
'*'
|
||||||
);
|
);
|
||||||
|
|
||||||
return { responseText };
|
return { responseText };
|
||||||
},
|
},
|
||||||
[chatId, router, saveChatResponse, shareChatData.maxContext, shareId]
|
[chatId, router, saveChatResponse, shareId]
|
||||||
);
|
);
|
||||||
|
|
||||||
const loadAppInfo = useCallback(
|
const loadAppInfo = useCallback(
|
||||||
@@ -96,7 +101,7 @@ const ShareChat = ({ shareId, chatId }: { shareId: string; chatId: string }) =>
|
|||||||
console.log(shareId, chatId);
|
console.log(shareId, chatId);
|
||||||
|
|
||||||
if (!shareId) return null;
|
if (!shareId) return null;
|
||||||
const history = shareChatHistory.find((item) => item._id === chatId) || defaultHistory;
|
const history = shareChatHistory.find((item) => item.chatId === chatId) || defaultHistory;
|
||||||
|
|
||||||
ChatBoxRef.current?.resetHistory(history.chats);
|
ChatBoxRef.current?.resetHistory(history.chats);
|
||||||
ChatBoxRef.current?.resetVariables(history.variables);
|
ChatBoxRef.current?.resetVariables(history.variables);
|
||||||
@@ -157,11 +162,13 @@ const ShareChat = ({ shareId, chatId }: { shareId: string; chatId: string }) =>
|
|||||||
appName={shareChatData.app.name}
|
appName={shareChatData.app.name}
|
||||||
appAvatar={shareChatData.app.avatar}
|
appAvatar={shareChatData.app.avatar}
|
||||||
activeChatId={chatId}
|
activeChatId={chatId}
|
||||||
history={shareChatHistory.map((item) => ({
|
history={history.map((item) => ({
|
||||||
id: item._id,
|
id: item.chatId,
|
||||||
title: item.title
|
title: item.title
|
||||||
}))}
|
}))}
|
||||||
onChangeChat={(chatId) => {
|
onChangeChat={(chatId) => {
|
||||||
|
console.log(chatId);
|
||||||
|
|
||||||
router.push({
|
router.push({
|
||||||
query: {
|
query: {
|
||||||
chatId: chatId || '',
|
chatId: chatId || '',
|
||||||
@@ -196,6 +203,7 @@ const ShareChat = ({ shareId, chatId }: { shareId: string; chatId: string }) =>
|
|||||||
<ChatBox
|
<ChatBox
|
||||||
ref={ChatBoxRef}
|
ref={ChatBoxRef}
|
||||||
appAvatar={shareChatData.app.avatar}
|
appAvatar={shareChatData.app.avatar}
|
||||||
|
userAvatar={shareChatData.userAvatar}
|
||||||
variableModules={shareChatData.app.variableModules}
|
variableModules={shareChatData.app.variableModules}
|
||||||
welcomeText={shareChatData.app.welcomeText}
|
welcomeText={shareChatData.app.welcomeText}
|
||||||
onUpdateVariable={(e) => {
|
onUpdateVariable={(e) => {
|
||||||
|
@@ -4,13 +4,12 @@ import { useGlobalStore } from '@/store/global';
|
|||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
import dynamic from 'next/dynamic';
|
import dynamic from 'next/dynamic';
|
||||||
import { clearCookie } from '@/utils/user';
|
import { clearCookie } from '@/utils/user';
|
||||||
|
import { useUserStore } from '@/store/user';
|
||||||
|
import { useConfirm } from '@/hooks/useConfirm';
|
||||||
import PageContainer from '@/components/PageContainer';
|
import PageContainer from '@/components/PageContainer';
|
||||||
import SideTabs from '@/components/SideTabs';
|
import SideTabs from '@/components/SideTabs';
|
||||||
|
|
||||||
import Tabs from '@/components/Tabs';
|
import Tabs from '@/components/Tabs';
|
||||||
import UserInfo from './components/Info';
|
import UserInfo from './components/Info';
|
||||||
import { useUserStore } from '@/store/user';
|
|
||||||
|
|
||||||
const BillTable = dynamic(() => import('./components/BillTable'), {
|
const BillTable = dynamic(() => import('./components/BillTable'), {
|
||||||
ssr: false
|
ssr: false
|
||||||
@@ -39,6 +38,10 @@ const NumberSetting = ({ currentTab }: { currentTab: `${TabEnum}` }) => {
|
|||||||
{ icon: 'loginoutLight', label: '登出', id: TabEnum.loginout, Component: () => <></> }
|
{ icon: 'loginoutLight', label: '登出', id: TabEnum.loginout, Component: () => <></> }
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
const { openConfirm, ConfirmChild } = useConfirm({
|
||||||
|
content: '确认退出登录?'
|
||||||
|
});
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const { isPc } = useGlobalStore();
|
const { isPc } = useGlobalStore();
|
||||||
@@ -47,9 +50,11 @@ const NumberSetting = ({ currentTab }: { currentTab: `${TabEnum}` }) => {
|
|||||||
const setCurrentTab = useCallback(
|
const setCurrentTab = useCallback(
|
||||||
(tab: string) => {
|
(tab: string) => {
|
||||||
if (tab === TabEnum.loginout) {
|
if (tab === TabEnum.loginout) {
|
||||||
clearCookie();
|
openConfirm(() => {
|
||||||
setUserInfo(null);
|
clearCookie();
|
||||||
router.replace('/login');
|
setUserInfo(null);
|
||||||
|
router.replace('/login');
|
||||||
|
})();
|
||||||
} else {
|
} else {
|
||||||
router.replace({
|
router.replace({
|
||||||
query: {
|
query: {
|
||||||
@@ -58,7 +63,7 @@ const NumberSetting = ({ currentTab }: { currentTab: `${TabEnum}` }) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[router, setUserInfo]
|
[openConfirm, router, setUserInfo]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -105,6 +110,7 @@ const NumberSetting = ({ currentTab }: { currentTab: `${TabEnum}` }) => {
|
|||||||
{currentTab === TabEnum.inform && <InformTable />}
|
{currentTab === TabEnum.inform && <InformTable />}
|
||||||
</Box>
|
</Box>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
<ConfirmChild />
|
||||||
</PageContainer>
|
</PageContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@@ -1,9 +1,13 @@
|
|||||||
import { Schema, model, models, Model } from 'mongoose';
|
import { Schema, model, models, Model } from 'mongoose';
|
||||||
import { ChatSchema as ChatType } from '@/types/mongoSchema';
|
import { ChatSchema as ChatType } from '@/types/mongoSchema';
|
||||||
import { ChatRoleMap } from '@/constants/chat';
|
import { ChatRoleMap, TaskResponseKeyEnum } from '@/constants/chat';
|
||||||
import { ChatSourceEnum, ChatSourceMap } from '@/constants/chat';
|
import { ChatSourceEnum, ChatSourceMap } from '@/constants/chat';
|
||||||
|
|
||||||
const ChatSchema = new Schema({
|
const ChatSchema = new Schema({
|
||||||
|
chatId: {
|
||||||
|
type: String,
|
||||||
|
require: true
|
||||||
|
},
|
||||||
userId: {
|
userId: {
|
||||||
type: Schema.Types.ObjectId,
|
type: Schema.Types.ObjectId,
|
||||||
ref: 'user',
|
ref: 'user',
|
||||||
@@ -33,14 +37,14 @@ const ChatSchema = new Schema({
|
|||||||
type: Object,
|
type: Object,
|
||||||
default: {}
|
default: {}
|
||||||
},
|
},
|
||||||
// source: {
|
source: {
|
||||||
// type: String,
|
type: String,
|
||||||
// enum: Object.keys(ChatSourceMap),
|
enum: Object.keys(ChatSourceMap),
|
||||||
// required: true
|
required: true
|
||||||
// },
|
},
|
||||||
// shareId: {
|
shareId: {
|
||||||
// type: String
|
type: String
|
||||||
// },
|
},
|
||||||
content: {
|
content: {
|
||||||
type: [
|
type: [
|
||||||
{
|
{
|
||||||
@@ -53,14 +57,22 @@ const ChatSchema = new Schema({
|
|||||||
type: String,
|
type: String,
|
||||||
default: ''
|
default: ''
|
||||||
},
|
},
|
||||||
rawSearch: {
|
[TaskResponseKeyEnum.responseData]: {
|
||||||
type: [
|
type: [
|
||||||
{
|
{
|
||||||
id: String,
|
moduleName: String,
|
||||||
q: String,
|
price: String,
|
||||||
a: String,
|
model: String,
|
||||||
kb_id: String,
|
tokens: Number,
|
||||||
source: String
|
question: String,
|
||||||
|
answer: String,
|
||||||
|
temperature: Number,
|
||||||
|
maxToken: Number,
|
||||||
|
finishMessages: Array,
|
||||||
|
similarity: Number,
|
||||||
|
limit: Number,
|
||||||
|
cqList: Array,
|
||||||
|
cqResult: String
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
default: []
|
default: []
|
||||||
|
@@ -24,10 +24,6 @@ const ShareChatSchema = new Schema({
|
|||||||
type: Number,
|
type: Number,
|
||||||
default: 0
|
default: 0
|
||||||
},
|
},
|
||||||
maxContext: {
|
|
||||||
type: Number,
|
|
||||||
default: 20
|
|
||||||
},
|
|
||||||
lastTime: {
|
lastTime: {
|
||||||
type: Date
|
type: Date
|
||||||
}
|
}
|
||||||
|
@@ -113,7 +113,7 @@ ${quoteQA.map((item, i) => `${i + 1}. [${item.q}\n${item.a}]`).join('\n')}
|
|||||||
|
|
||||||
const adaptMessages = adaptChatItem_openAI({ messages: filterMessages, reserveId: false });
|
const adaptMessages = adaptChatItem_openAI({ messages: filterMessages, reserveId: false });
|
||||||
const chatAPI = getOpenAIApi();
|
const chatAPI = getOpenAIApi();
|
||||||
// console.log(adaptMessages);
|
console.log(adaptMessages);
|
||||||
|
|
||||||
/* count response max token */
|
/* count response max token */
|
||||||
const promptsToken = modelToolMap.countTokens({
|
const promptsToken = modelToolMap.countTokens({
|
||||||
@@ -128,8 +128,8 @@ ${quoteQA.map((item, i) => `${i + 1}. [${item.q}\n${item.a}]`).join('\n')}
|
|||||||
temperature: Number(temperature || 0),
|
temperature: Number(temperature || 0),
|
||||||
max_tokens: maxToken,
|
max_tokens: maxToken,
|
||||||
messages: adaptMessages,
|
messages: adaptMessages,
|
||||||
frequency_penalty: 0.5, // 越大,重复内容越少
|
// frequency_penalty: 0.5, // 越大,重复内容越少
|
||||||
presence_penalty: -0.5, // 越大,越容易出现新内容
|
// presence_penalty: -0.5, // 越大,越容易出现新内容
|
||||||
stream
|
stream
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
65
client/src/service/utils/chat/saveChat.ts
Normal file
65
client/src/service/utils/chat/saveChat.ts
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
import { ChatItemType } from '@/types/chat';
|
||||||
|
import { Chat, App } from '@/service/mongo';
|
||||||
|
import { ChatSourceEnum } from '@/constants/chat';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
chatId: string;
|
||||||
|
appId: string;
|
||||||
|
userId: string;
|
||||||
|
variables?: Record<string, any>;
|
||||||
|
isOwner: boolean;
|
||||||
|
source: `${ChatSourceEnum}`;
|
||||||
|
shareId?: string;
|
||||||
|
content: [ChatItemType, ChatItemType];
|
||||||
|
};
|
||||||
|
|
||||||
|
export async function saveChat({
|
||||||
|
chatId,
|
||||||
|
appId,
|
||||||
|
userId,
|
||||||
|
variables,
|
||||||
|
isOwner,
|
||||||
|
source,
|
||||||
|
shareId,
|
||||||
|
content
|
||||||
|
}: Props) {
|
||||||
|
const chatHistory = await Chat.findOne(
|
||||||
|
{
|
||||||
|
chatId,
|
||||||
|
userId
|
||||||
|
},
|
||||||
|
'_id'
|
||||||
|
);
|
||||||
|
|
||||||
|
if (chatHistory) {
|
||||||
|
await Chat.findOneAndUpdate(
|
||||||
|
{ chatId },
|
||||||
|
{
|
||||||
|
$push: {
|
||||||
|
content: {
|
||||||
|
$each: content
|
||||||
|
}
|
||||||
|
},
|
||||||
|
title: content[0].value.slice(0, 20),
|
||||||
|
updateTime: new Date()
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
await Chat.create({
|
||||||
|
chatId,
|
||||||
|
userId,
|
||||||
|
appId,
|
||||||
|
variables,
|
||||||
|
title: content[0].value.slice(0, 20),
|
||||||
|
source,
|
||||||
|
shareId,
|
||||||
|
content: content
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isOwner && source === ChatSourceEnum.online) {
|
||||||
|
App.findByIdAndUpdate(appId, {
|
||||||
|
updateTime: new Date()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@@ -65,12 +65,12 @@ export const useChatStore = create<State>()(
|
|||||||
},
|
},
|
||||||
async delHistory(chatId) {
|
async delHistory(chatId) {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
state.history = state.history.filter((item) => item._id !== chatId);
|
state.history = state.history.filter((item) => item.chatId !== chatId);
|
||||||
});
|
});
|
||||||
await delChatHistoryById(chatId);
|
await delChatHistoryById(chatId);
|
||||||
},
|
},
|
||||||
updateHistory(history) {
|
updateHistory(history) {
|
||||||
const index = get().history.findIndex((item) => item._id === history._id);
|
const index = get().history.findIndex((item) => item.chatId === history.chatId);
|
||||||
set((state) => {
|
set((state) => {
|
||||||
const newHistory = (() => {
|
const newHistory = (() => {
|
||||||
if (index > -1) {
|
if (index > -1) {
|
||||||
|
@@ -4,8 +4,6 @@ import { immer } from 'zustand/middleware/immer';
|
|||||||
|
|
||||||
import type { ChatSiteItemType, ShareChatHistoryItemType, ShareChatType } from '@/types/chat';
|
import type { ChatSiteItemType, ShareChatHistoryItemType, ShareChatType } from '@/types/chat';
|
||||||
import { HUMAN_ICON } from '@/constants/chat';
|
import { HUMAN_ICON } from '@/constants/chat';
|
||||||
import { customAlphabet } from 'nanoid';
|
|
||||||
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 12);
|
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
shareChatData: ShareChatType;
|
shareChatData: ShareChatType;
|
||||||
@@ -16,21 +14,20 @@ type State = {
|
|||||||
prompts: ChatSiteItemType[];
|
prompts: ChatSiteItemType[];
|
||||||
variables: Record<string, any>;
|
variables: Record<string, any>;
|
||||||
shareId: string;
|
shareId: string;
|
||||||
}) => { newChatId: string };
|
}) => void;
|
||||||
delOneShareHistoryByChatId: (chatId: string) => void;
|
delOneShareHistoryByChatId: (chatId: string) => void;
|
||||||
delShareChatHistoryItemById: (e: { chatId: string; index: number }) => void;
|
delShareChatHistoryItemById: (e: { chatId: string; index: number }) => void;
|
||||||
delManyShareChatHistoryByShareId: (shareId?: string) => void;
|
delManyShareChatHistoryByShareId: (shareId?: string) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const defaultHistory: ShareChatHistoryItemType = {
|
export const defaultHistory: ShareChatHistoryItemType = {
|
||||||
_id: `${Date.now()}`,
|
chatId: `${Date.now()}`,
|
||||||
updateTime: new Date(),
|
updateTime: new Date(),
|
||||||
title: '新对话',
|
title: '新对话',
|
||||||
shareId: '',
|
shareId: '',
|
||||||
chats: []
|
chats: []
|
||||||
};
|
};
|
||||||
const defaultShareChatData: ShareChatType = {
|
const defaultShareChatData: ShareChatType = {
|
||||||
maxContext: 5,
|
|
||||||
userAvatar: HUMAN_ICON,
|
userAvatar: HUMAN_ICON,
|
||||||
app: {
|
app: {
|
||||||
name: '',
|
name: '',
|
||||||
@@ -57,32 +54,30 @@ export const useShareChatStore = create<State>()(
|
|||||||
state.shareChatData = val;
|
state.shareChatData = val;
|
||||||
// update history
|
// update history
|
||||||
state.shareChatHistory = state.shareChatHistory.map((item) =>
|
state.shareChatHistory = state.shareChatHistory.map((item) =>
|
||||||
item._id === val.history._id ? val.history : item
|
item.chatId === val.history.chatId ? val.history : item
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
shareChatHistory: [],
|
shareChatHistory: [],
|
||||||
saveChatResponse({ chatId, prompts, variables, shareId }) {
|
saveChatResponse({ chatId, prompts, variables, shareId }) {
|
||||||
const history = get().shareChatHistory.find((item) => item._id === chatId);
|
const chatHistory = get().shareChatHistory.find((item) => item.chatId === chatId);
|
||||||
|
|
||||||
const newChatId = history ? '' : nanoid();
|
|
||||||
|
|
||||||
const historyList = (() => {
|
const historyList = (() => {
|
||||||
if (history) {
|
if (chatHistory) {
|
||||||
return get().shareChatHistory.map((item) =>
|
return get().shareChatHistory.map((item) =>
|
||||||
item._id === chatId
|
item.chatId === chatId
|
||||||
? {
|
? {
|
||||||
...item,
|
...item,
|
||||||
title: prompts[prompts.length - 2]?.value,
|
title: prompts[prompts.length - 2]?.value,
|
||||||
updateTime: new Date(),
|
updateTime: new Date(),
|
||||||
chats: prompts,
|
chats: chatHistory.chats.concat(prompts).slice(-50),
|
||||||
variables
|
variables
|
||||||
}
|
}
|
||||||
: item
|
: item
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return get().shareChatHistory.concat({
|
return get().shareChatHistory.concat({
|
||||||
_id: newChatId,
|
chatId,
|
||||||
shareId,
|
shareId,
|
||||||
title: prompts[prompts.length - 2]?.value,
|
title: prompts[prompts.length - 2]?.value,
|
||||||
updateTime: new Date(),
|
updateTime: new Date(),
|
||||||
@@ -97,21 +92,19 @@ export const useShareChatStore = create<State>()(
|
|||||||
set((state) => {
|
set((state) => {
|
||||||
state.shareChatHistory = historyList.slice(0, 100);
|
state.shareChatHistory = historyList.slice(0, 100);
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
|
||||||
newChatId
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
delOneShareHistoryByChatId(chatId: string) {
|
delOneShareHistoryByChatId(chatId: string) {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
state.shareChatHistory = state.shareChatHistory.filter((item) => item._id !== chatId);
|
state.shareChatHistory = state.shareChatHistory.filter(
|
||||||
|
(item) => item.chatId !== chatId
|
||||||
|
);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
delShareChatHistoryItemById({ chatId, index }) {
|
delShareChatHistoryItemById({ chatId, index }) {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
// update history store
|
// update history store
|
||||||
const newHistoryList = state.shareChatHistory.map((item) =>
|
const newHistoryList = state.shareChatHistory.map((item) =>
|
||||||
item._id === chatId
|
item.chatId === chatId
|
||||||
? {
|
? {
|
||||||
...item,
|
...item,
|
||||||
chats: [...item.chats.slice(0, index), ...item.chats.slice(index + 1)]
|
chats: [...item.chats.slice(0, index), ...item.chats.slice(index + 1)]
|
||||||
|
1
client/src/types/app.d.ts
vendored
1
client/src/types/app.d.ts
vendored
@@ -37,7 +37,6 @@ export interface ShareAppItem {
|
|||||||
|
|
||||||
export type ShareChatEditType = {
|
export type ShareChatEditType = {
|
||||||
name: string;
|
name: string;
|
||||||
maxContext: number;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* agent */
|
/* agent */
|
||||||
|
8
client/src/types/chat.d.ts
vendored
8
client/src/types/chat.d.ts
vendored
@@ -1,4 +1,4 @@
|
|||||||
import { ChatRoleEnum, rawSearchKey } from '@/constants/chat';
|
import { ChatRoleEnum } from '@/constants/chat';
|
||||||
import type { InitChatResponse, InitShareChatResponse } from '@/api/response/chat';
|
import type { InitChatResponse, InitShareChatResponse } from '@/api/response/chat';
|
||||||
import { TaskResponseKeyEnum } from '@/constants/chat';
|
import { TaskResponseKeyEnum } from '@/constants/chat';
|
||||||
import { ClassifyQuestionAgentItemType } from './app';
|
import { ClassifyQuestionAgentItemType } from './app';
|
||||||
@@ -9,9 +9,7 @@ export type ChatItemType = {
|
|||||||
_id?: string;
|
_id?: string;
|
||||||
obj: `${ChatRoleEnum}`;
|
obj: `${ChatRoleEnum}`;
|
||||||
value: string;
|
value: string;
|
||||||
[rawSearchKey]?: QuoteItemType[];
|
[TaskResponseKeyEnum.responseData]?: ChatHistoryItemResType[];
|
||||||
quoteLen?: number;
|
|
||||||
[key: string]: any;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ChatSiteItemType = {
|
export type ChatSiteItemType = {
|
||||||
@@ -19,7 +17,7 @@ export type ChatSiteItemType = {
|
|||||||
} & ChatItemType;
|
} & ChatItemType;
|
||||||
|
|
||||||
export type HistoryItemType = {
|
export type HistoryItemType = {
|
||||||
_id: string;
|
chatId: string;
|
||||||
updateTime: Date;
|
updateTime: Date;
|
||||||
customTitle?: string;
|
customTitle?: string;
|
||||||
title: string;
|
title: string;
|
||||||
|
2
client/src/types/index.d.ts
vendored
2
client/src/types/index.d.ts
vendored
@@ -18,7 +18,7 @@ export type FeConfigsType = {
|
|||||||
show_register?: boolean;
|
show_register?: boolean;
|
||||||
show_appStore?: boolean;
|
show_appStore?: boolean;
|
||||||
show_userDetail?: boolean;
|
show_userDetail?: boolean;
|
||||||
show_git?: false;
|
show_git?: boolean;
|
||||||
systemTitle?: string;
|
systemTitle?: string;
|
||||||
authorText?: string;
|
authorText?: string;
|
||||||
};
|
};
|
||||||
|
5
client/src/types/mongoSchema.d.ts
vendored
5
client/src/types/mongoSchema.d.ts
vendored
@@ -4,6 +4,7 @@ import type { DataType } from './data';
|
|||||||
import { BillSourceEnum, InformTypeEnum } from '@/constants/user';
|
import { BillSourceEnum, InformTypeEnum } from '@/constants/user';
|
||||||
import { TrainingModeEnum } from '@/constants/plugin';
|
import { TrainingModeEnum } from '@/constants/plugin';
|
||||||
import type { AppModuleItemType } from './app';
|
import type { AppModuleItemType } from './app';
|
||||||
|
import { ChatSourceEnum } from '@/constants/chat';
|
||||||
|
|
||||||
export interface UserModelSchema {
|
export interface UserModelSchema {
|
||||||
_id: string;
|
_id: string;
|
||||||
@@ -78,6 +79,7 @@ export interface TrainingDataSchema {
|
|||||||
|
|
||||||
export interface ChatSchema {
|
export interface ChatSchema {
|
||||||
_id: string;
|
_id: string;
|
||||||
|
chatId: string;
|
||||||
userId: string;
|
userId: string;
|
||||||
appId: string;
|
appId: string;
|
||||||
updateTime: Date;
|
updateTime: Date;
|
||||||
@@ -85,6 +87,8 @@ export interface ChatSchema {
|
|||||||
customTitle: string;
|
customTitle: string;
|
||||||
top: boolean;
|
top: boolean;
|
||||||
variables: Record<string, any>;
|
variables: Record<string, any>;
|
||||||
|
source: `${ChatSourceEnum}`;
|
||||||
|
shareId?: string;
|
||||||
content: ChatItemType[];
|
content: ChatItemType[];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,7 +142,6 @@ export interface ShareChatSchema {
|
|||||||
appId: string;
|
appId: string;
|
||||||
name: string;
|
name: string;
|
||||||
total: number;
|
total: number;
|
||||||
maxContext: number;
|
|
||||||
lastTime: Date;
|
lastTime: Date;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user