This commit is contained in:
archer
2023-07-18 11:50:16 +08:00
parent f9d83c481f
commit 505aff3dbf
26 changed files with 216 additions and 210 deletions

View File

@@ -10,7 +10,7 @@ import type { Props as UpdateHistoryProps } from '@/pages/api/chat/history/updat
/** /**
* 获取初始化聊天内容 * 获取初始化聊天内容
*/ */
export const getInitChatSiteInfo = (data: { appId: string; historyId?: string }) => export const getInitChatSiteInfo = (data: { appId: string; chatId?: string }) =>
GET<InitChatResponse>(`/chat/init`, data); GET<InitChatResponse>(`/chat/init`, data);
/** /**
@@ -27,14 +27,14 @@ export const delChatHistoryById = (id: string) => GET(`/chat/removeHistory?id=${
/** /**
* get history quotes * get history quotes
*/ */
export const getHistoryQuote = (params: { historyId: string; contentId: string }) => export const getHistoryQuote = (params: { chatId: string; contentId: string }) =>
GET<(QuoteItemType & { _id: string })[]>(`/chat/history/getHistoryQuote`, params); GET<(QuoteItemType & { _id: string })[]>(`/chat/history/getHistoryQuote`, params);
/** /**
* update history quote status * update history quote status
*/ */
export const updateHistoryQuote = (params: { export const updateHistoryQuote = (params: {
historyId: string; chatId: string;
contentId: string; contentId: string;
quoteId: string; quoteId: string;
sourceText: string; sourceText: string;
@@ -43,7 +43,7 @@ export const updateHistoryQuote = (params: {
/** /**
* 删除一句对话 * 删除一句对话
*/ */
export const delChatRecordByIndex = (data: { historyId: string; contentId: string }) => export const delChatRecordByIndex = (data: { chatId: string; contentId: string }) =>
DELETE(`/chat/delChatRecordByContentId`, data); DELETE(`/chat/delChatRecordByContentId`, data);
/** /**

View File

@@ -19,7 +19,7 @@ export const streamFetch = ({
new Promise<{ new Promise<{
responseText: string; responseText: string;
errMsg: string; errMsg: string;
newHistoryId: string | null; newChatId: string | null;
[rawSearchKey]: QuoteItemType[]; [rawSearchKey]: QuoteItemType[];
}>(async (resolve, reject) => { }>(async (resolve, reject) => {
try { try {
@@ -45,7 +45,7 @@ export const streamFetch = ({
let responseText = ''; let responseText = '';
let rawSearch: QuoteItemType[] = []; let rawSearch: QuoteItemType[] = [];
let errMsg = ''; let errMsg = '';
const newHistoryId = response.headers.get('newHistoryId'); const newChatId = response.headers.get('newChatId');
const read = async () => { const read = async () => {
try { try {
@@ -55,7 +55,7 @@ export const streamFetch = ({
return resolve({ return resolve({
responseText, responseText,
errMsg, errMsg,
newHistoryId, newChatId,
rawSearch rawSearch
}); });
} else { } else {
@@ -95,7 +95,7 @@ export const streamFetch = ({
return resolve({ return resolve({
responseText, responseText,
errMsg, errMsg,
newHistoryId, newChatId,
rawSearch rawSearch
}); });
} }

View File

@@ -13,7 +13,6 @@ export interface InitChatResponse {
intro: string; intro: string;
canUse: boolean; canUse: boolean;
}; };
customTitle?: string;
title: string; title: string;
variables: Record<string, any>; variables: Record<string, any>;
history: ChatItemType[]; history: ChatItemType[];

View File

@@ -20,12 +20,12 @@ import { getErrText } from '@/utils/tools';
import { QuoteItemType } from '@/pages/api/app/modules/kb/search'; import { QuoteItemType } from '@/pages/api/app/modules/kb/search';
const QuoteModal = ({ const QuoteModal = ({
historyId, chatId,
contentId, contentId,
rawSearch = [], rawSearch = [],
onClose onClose
}: { }: {
historyId?: string; chatId?: string;
contentId?: string; contentId?: string;
rawSearch?: QuoteItemType[]; rawSearch?: QuoteItemType[];
onClose: () => void; onClose: () => void;
@@ -45,8 +45,8 @@ const QuoteModal = ({
refetch, refetch,
isLoading isLoading
} = useQuery(['getHistoryQuote'], () => { } = useQuery(['getHistoryQuote'], () => {
if (historyId && contentId) { if (chatId && contentId) {
return getHistoryQuote({ historyId, contentId }); return getHistoryQuote({ chatId, contentId });
} }
if (rawSearch.length > 0) { if (rawSearch.length > 0) {
return rawSearch; return rawSearch;
@@ -59,12 +59,12 @@ const QuoteModal = ({
*/ */
const updateQuoteStatus = useCallback( const updateQuoteStatus = useCallback(
async (quoteId: string, sourceText: string) => { async (quoteId: string, sourceText: string) => {
if (!historyId || !contentId) return; if (!chatId || !contentId) return;
setIsLoading(true); setIsLoading(true);
try { try {
await updateHistoryQuote({ await updateHistoryQuote({
contentId, contentId,
historyId, chatId,
quoteId, quoteId,
sourceText sourceText
}); });
@@ -78,7 +78,7 @@ const QuoteModal = ({
} }
setIsLoading(false); setIsLoading(false);
}, },
[contentId, historyId, refetch, setIsLoading, toast] [contentId, chatId, refetch, setIsLoading, toast]
); );
/** /**

View File

@@ -49,7 +49,7 @@ export type StartChatFnProps = {
export type ComponentRef = { export type ComponentRef = {
getChatHistory: () => ChatSiteItemType[]; getChatHistory: () => ChatSiteItemType[];
resetVariables: (data?: Record<string, any>) => void; resetVariables: (data?: Record<string, any>) => void;
resetHistory: (history: ChatSiteItemType[]) => void; resetHistory: (chatId: ChatSiteItemType[]) => void;
scrollToBottom: (behavior?: 'smooth' | 'auto') => void; scrollToBottom: (behavior?: 'smooth' | 'auto') => void;
}; };
@@ -76,11 +76,10 @@ const Empty = () => {
return ( return (
<Box <Box
minH={'100%'} pt={[6, 0]}
w={'85%'} w={'85%'}
maxW={'600px'} maxW={'600px'}
m={'auto'} m={'auto'}
py={'5vh'}
alignItems={'center'} alignItems={'center'}
justifyContent={'center'} justifyContent={'center'}
> >
@@ -110,7 +109,7 @@ const ChatAvatar = ({
const ChatBox = ( const ChatBox = (
{ {
showEmptyIntro = false, showEmptyIntro = false,
historyId, chatId,
appAvatar, appAvatar,
variableModules, variableModules,
welcomeText, welcomeText,
@@ -119,7 +118,7 @@ const ChatBox = (
onDelMessage onDelMessage
}: { }: {
showEmptyIntro?: boolean; showEmptyIntro?: boolean;
historyId?: string; chatId?: string;
appAvatar: string; appAvatar: string;
variableModules?: VariableItemType[]; variableModules?: VariableItemType[];
welcomeText?: string; welcomeText?: string;
@@ -389,14 +388,16 @@ const ChatBox = (
}; };
const showEmpty = useMemo( const showEmpty = useMemo(
() => showEmptyIntro && chatHistory.length === 0 && !(variableModules || welcomeText), () => showEmptyIntro && chatHistory.length === 0 && !variableModules?.length && !welcomeText,
[chatHistory.length, showEmptyIntro, variableModules, welcomeText] [chatHistory.length, showEmptyIntro, variableModules, welcomeText]
); );
return ( return (
<Flex flexDirection={'column'} h={'100%'}> <Flex flexDirection={'column'} h={'100%'}>
<Box ref={ChatBoxRef} flex={'1 0 0'} h={0} overflow={'overlay'} px={[2, 5, 7]} py={[0, 5]}> <Box ref={ChatBoxRef} flex={'1 0 0'} h={0} overflow={'overlay'} px={[2, 5, 7]} pt={[0, 5]}>
<Box maxW={['100%', '1000px', '1200px']} h={'100%'} mx={'auto'}> <Box maxW={['100%', '1000px', '1200px']} h={'100%'} mx={'auto'}>
{showEmpty && <Empty />}
{!!welcomeText && ( {!!welcomeText && (
<Flex alignItems={'flex-start'} py={2}> <Flex alignItems={'flex-start'} py={2}>
{/* avatar */} {/* avatar */}
@@ -410,7 +411,7 @@ const ChatBox = (
</Flex> </Flex>
)} )}
{/* variable input */} {/* variable input */}
{variableModules && ( {!!variableModules?.length && (
<Flex alignItems={'flex-start'} py={2}> <Flex alignItems={'flex-start'} py={2}>
{/* avatar */} {/* avatar */}
<ChatAvatar src={appAvatar} order={1} mr={['6px', 2]} /> <ChatAvatar src={appAvatar} order={1} mr={['6px', 2]} />
@@ -467,7 +468,7 @@ const ChatBox = (
)} )}
{/* chat history */} {/* chat history */}
<Box id={'history'} pb={[8, 2]}> <Box id={'history'} pb={8}>
{chatHistory.map((item, index) => ( {chatHistory.map((item, index) => (
<Flex <Flex
key={item._id} key={item._id}
@@ -606,13 +607,11 @@ const ChatBox = (
</Flex> </Flex>
))} ))}
</Box> </Box>
{showEmpty && <Empty />}
</Box> </Box>
</Box> </Box>
{/* input */} {/* input */}
{variableIsFinish ? ( {variableIsFinish ? (
<Box m={['0 auto', '20px auto']} w={'100%'} maxW={['auto', 'min(750px, 100%)']} px={[0, 5]}> <Box m={['0 auto', '10px auto']} w={'100%'} maxW={['auto', 'min(750px, 100%)']} px={[0, 5]}>
<Box <Box
py={'18px'} py={'18px'}
position={'relative'} position={'relative'}
@@ -696,12 +695,11 @@ const ChatBox = (
{/* quote modal */} {/* quote modal */}
{!!quoteModalData && ( {!!quoteModalData && (
<QuoteModal <QuoteModal
historyId={historyId} chatId={chatId}
{...quoteModalData} {...quoteModalData}
onClose={() => setQuoteModalData(undefined)} onClose={() => setQuoteModalData(undefined)}
/> />
)} )}
{/* quote modal */}
</Flex> </Flex>
); );
}; };

View File

@@ -17,14 +17,14 @@ export enum NavbarTypeEnum {
const Navbar = ({ unread }: { unread: number }) => { const Navbar = ({ unread }: { unread: number }) => {
const router = useRouter(); const router = useRouter();
const { userInfo } = useUserStore(); const { userInfo } = useUserStore();
const { lastChatAppId, lastHistoryId } = useChatStore(); const { lastChatAppId, lastChatId } = useChatStore();
const navbarList = useMemo( const navbarList = useMemo(
() => [ () => [
{ {
label: '聊天', label: '聊天',
icon: 'chatLight', icon: 'chatLight',
activeIcon: 'chatFill', activeIcon: 'chatFill',
link: `/chat?appId=${lastChatAppId}&historyId=${lastHistoryId}`, link: `/chat?appId=${lastChatAppId}&chatId=${lastChatId}`,
activeLink: ['/chat'] activeLink: ['/chat']
}, },
{ {
@@ -56,7 +56,7 @@ const Navbar = ({ unread }: { unread: number }) => {
activeLink: ['/number'] activeLink: ['/number']
} }
], ],
[lastHistoryId, lastChatAppId] [lastChatId, lastChatAppId]
); );
const itemStyles: any = { const itemStyles: any = {

View File

@@ -7,13 +7,13 @@ import Badge from '../Badge';
const NavbarPhone = ({ unread }: { unread: number }) => { const NavbarPhone = ({ unread }: { unread: number }) => {
const router = useRouter(); const router = useRouter();
const { lastChatAppId, lastHistoryId } = useChatStore(); const { lastChatAppId, lastChatId } = useChatStore();
const navbarList = useMemo( const navbarList = useMemo(
() => [ () => [
{ {
label: '聊天', label: '聊天',
icon: 'chatLight', icon: 'chatLight',
link: `/chat?appId=${lastChatAppId}&historyId=${lastHistoryId}`, link: `/chat?appId=${lastChatAppId}&chatId=${lastChatId}`,
activeLink: ['/chat'], activeLink: ['/chat'],
unread: 0 unread: 0
}, },
@@ -39,7 +39,7 @@ const NavbarPhone = ({ unread }: { unread: number }) => {
unread unread
} }
], ],
[lastHistoryId, lastChatAppId, unread] [lastChatId, lastChatAppId, unread]
); );
return ( return (

View File

@@ -43,6 +43,7 @@ const Markdown = ({ source, isChatting = false }: { source: string; isChatting?:
a: Link, a: Link,
img: Image, img: Image,
pre: 'div', pre: 'div',
p: 'div',
code: Code code: Code
}} }}
> >

View File

@@ -5,10 +5,9 @@ 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 { historyId, contentId } = req.query as { historyId: string; contentId: string }; const { chatId, contentId } = req.query as { chatId: string; contentId: string };
console.log(historyId, contentId);
if (!historyId || !contentId) { if (!chatId || !contentId) {
throw new Error('缺少参数'); throw new Error('缺少参数');
} }
@@ -17,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(historyId); const chatRecord = await Chat.findById(chatId);
if (!chatRecord) { if (!chatRecord) {
throw new Error('找不到对话'); throw new Error('找不到对话');
@@ -26,7 +25,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
// 删除一条数据库记录 // 删除一条数据库记录
await Chat.updateOne( await Chat.updateOne(
{ {
_id: historyId, _id: chatId,
userId userId
}, },
{ $pull: { content: { _id: contentId } } } { $pull: { content: { _id: contentId } } }

View File

@@ -27,7 +27,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
_id: item._id, _id: item._id,
updateTime: item.updateTime, updateTime: item.updateTime,
appId: item.appId, appId: item.appId,
title: item.customTitle || item.title, customTitle: item.customTitle,
title: item.title,
top: item.top top: item.top
})) }))
}); });

View File

@@ -7,22 +7,22 @@ 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 {
const { historyId, contentId } = req.query as { const { chatId, contentId } = req.query as {
historyId: string; chatId: string;
contentId: string; contentId: string;
}; };
await connectToDatabase(); await connectToDatabase();
const { userId } = await authUser({ req, authToken: true }); const { userId } = await authUser({ req, authToken: true });
if (!historyId || !contentId) { if (!chatId || !contentId) {
throw new Error('params is error'); throw new Error('params is error');
} }
const history = await Chat.aggregate([ const history = await Chat.aggregate([
{ {
$match: { $match: {
_id: new Types.ObjectId(historyId), _id: new Types.ObjectId(chatId),
userId: new Types.ObjectId(userId) userId: new Types.ObjectId(userId)
} }
}, },

View File

@@ -4,7 +4,7 @@ import { connectToDatabase, Chat } from '@/service/mongo';
import { authUser } from '@/service/utils/auth'; import { authUser } from '@/service/utils/auth';
export type Props = { export type Props = {
historyId: string; chatId: string;
customTitle?: string; customTitle?: string;
top?: boolean; top?: boolean;
}; };
@@ -12,7 +12,7 @@ export type Props = {
/* 更新聊天标题 */ /* 更新聊天标题 */
export default async function handler(req: NextApiRequest, res: NextApiResponse) { export default async function handler(req: NextApiRequest, res: NextApiResponse) {
try { try {
const { historyId, customTitle, top } = req.body as Props; const { chatId, customTitle, top } = req.body as Props;
const { userId } = await authUser({ req, authToken: true }); const { userId } = await authUser({ req, authToken: true });
@@ -20,7 +20,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
await Chat.findOneAndUpdate( await Chat.findOneAndUpdate(
{ {
_id: historyId, _id: chatId,
userId userId
}, },
{ {

View File

@@ -7,12 +7,12 @@ import { Types } from 'mongoose';
export default async function handler(req: NextApiRequest, res: NextApiResponse) { export default async function handler(req: NextApiRequest, res: NextApiResponse) {
try { try {
let { let {
historyId, chatId,
contentId, contentId,
quoteId, quoteId,
sourceText = '' sourceText = ''
} = req.body as { } = req.body as {
historyId: string; chatId: string;
contentId: string; contentId: string;
quoteId: string; quoteId: string;
sourceText: string; sourceText: string;
@@ -21,13 +21,13 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
const { userId } = await authUser({ req, authToken: true }); const { userId } = await authUser({ req, authToken: true });
if (!contentId || !historyId || !quoteId) { if (!contentId || !chatId || !quoteId) {
throw new Error('params is error'); throw new Error('params is error');
} }
await Chat.updateOne( await Chat.updateOne(
{ {
_id: new Types.ObjectId(historyId), _id: new Types.ObjectId(chatId),
userId: new Types.ObjectId(userId), userId: new Types.ObjectId(userId),
'content._id': new Types.ObjectId(contentId) 'content._id': new Types.ObjectId(contentId)
}, },

View File

@@ -53,7 +53,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
const { chat, history = [] }: { chat?: ChatSchema; history?: ChatItemType[] } = const { chat, history = [] }: { chat?: ChatSchema; history?: ChatItemType[] } =
await (async () => { await (async () => {
if (chatId) { if (chatId) {
// auth historyId // auth chatId
const chat = await Chat.findOne({ const chat = await Chat.findOne({
_id: chatId, _id: chatId,
userId userId
@@ -104,7 +104,6 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
intro: app.intro, intro: app.intro,
canUse: app.share.isShare || isOwner canUse: app.share.isShare || isOwner
}, },
customTitle: chat?.customTitle,
title: chat?.title || '新对话', title: chat?.title || '新对话',
variables: chat?.variables || {}, variables: chat?.variables || {},
history history

View File

@@ -7,7 +7,7 @@ import { authUser } from '@/service/utils/auth';
import { Types } from 'mongoose'; import { Types } from 'mongoose';
type Props = { type Props = {
historyId?: string; chatId?: string;
appId: string; appId: string;
variables?: Record<string, any>; variables?: Record<string, any>;
prompts: [ChatItemType, ChatItemType]; prompts: [ChatItemType, ChatItemType];
@@ -16,7 +16,7 @@ type Props = {
/* 聊天内容存存储 */ /* 聊天内容存存储 */
export default async function handler(req: NextApiRequest, res: NextApiResponse) { export default async function handler(req: NextApiRequest, res: NextApiResponse) {
try { try {
const { historyId, appId, prompts } = req.body as Props; const { chatId, appId, prompts } = req.body as Props;
if (!prompts) { if (!prompts) {
throw new Error('缺少参数'); throw new Error('缺少参数');
@@ -25,7 +25,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 response = await saveChat({ const response = await saveChat({
historyId, chatId,
appId, appId,
prompts, prompts,
userId userId
@@ -43,13 +43,13 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
} }
export async function saveChat({ export async function saveChat({
newHistoryId, newChatId,
historyId, chatId,
appId, appId,
prompts, prompts,
variables, variables,
userId userId
}: Props & { newHistoryId?: Types.ObjectId; userId: string }): Promise<{ newHistoryId: string }> { }: Props & { newChatId?: Types.ObjectId; userId: string }): Promise<{ newChatId: string }> {
await connectToDatabase(); await connectToDatabase();
const { app } = await authApp({ appId, userId, authOwner: false }); const { app } = await authApp({ appId, userId, authOwner: false });
@@ -60,9 +60,9 @@ export async function saveChat({
} }
const [response] = await Promise.all([ const [response] = await Promise.all([
...(historyId ...(chatId
? [ ? [
Chat.findByIdAndUpdate(historyId, { Chat.findByIdAndUpdate(chatId, {
$push: { $push: {
content: { content: {
$each: prompts $each: prompts
@@ -72,19 +72,19 @@ export async function saveChat({
title: prompts[0].value.slice(0, 20), title: prompts[0].value.slice(0, 20),
updateTime: new Date() updateTime: new Date()
}).then(() => ({ }).then(() => ({
newHistoryId: '' newChatId: ''
})) }))
] ]
: [ : [
Chat.create({ Chat.create({
_id: newHistoryId, _id: newChatId,
userId, userId,
appId, appId,
variables, variables,
content: prompts, content: prompts,
title: prompts[0].value.slice(0, 20) title: prompts[0].value.slice(0, 20)
}).then((res) => ({ }).then((res) => ({
newHistoryId: String(res._id) newChatId: String(res._id)
})) }))
]), ]),
// update app // update app
@@ -99,6 +99,6 @@ export async function saveChat({
return { return {
// @ts-ignore // @ts-ignore
newHistoryId: response?.newHistoryId || '' newChatId: response?.newChatId || ''
}; };
} }

View File

@@ -20,7 +20,7 @@ import { BillSourceEnum } from '@/constants/user';
export type MessageItemType = ChatCompletionRequestMessage & { _id?: string }; export type MessageItemType = ChatCompletionRequestMessage & { _id?: string };
type FastGptWebChatProps = { type FastGptWebChatProps = {
historyId?: string; // undefined: nonuse history, '': new chat, 'xxxxx': use history chatId?: string; // undefined: nonuse history, '': new chat, 'xxxxx': use history
appId?: string; appId?: string;
}; };
type FastGptShareChatProps = { type FastGptShareChatProps = {
@@ -47,14 +47,7 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
res.end(); res.end();
}); });
let { let { chatId, appId, shareId, stream = false, messages = [], variables = {} } = req.body as Props;
historyId,
appId,
shareId,
stream = false,
messages = [],
variables = {}
} = req.body as Props;
let billId = ''; let billId = '';
@@ -91,7 +84,7 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
appId, appId,
userId userId
}), }),
getChatHistory({ historyId, userId }) getChatHistory({ chatId, userId })
]); ]);
const isOwner = !shareId && userId === String(app.userId); const isOwner = !shareId && userId === String(app.userId);
@@ -107,9 +100,9 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
throw new Error('Question is empty'); throw new Error('Question is empty');
} }
const newHistoryId = historyId === '' ? new Types.ObjectId() : undefined; const newChatId = chatId === '' ? new Types.ObjectId() : undefined;
if (stream && newHistoryId) { if (stream && newChatId) {
res.setHeader('newHistoryId', String(newHistoryId)); res.setHeader('newChatId', String(newChatId));
} }
billId = await createTaskBill({ billId = await createTaskBill({
@@ -133,10 +126,10 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
}); });
// save chat // save chat
if (typeof historyId === 'string') { if (typeof chatId === 'string') {
await saveChat({ await saveChat({
historyId, chatId,
newHistoryId, newChatId,
appId, appId,
variables, variables,
prompts: [ prompts: [
@@ -173,10 +166,10 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
} else { } else {
res.json({ res.json({
data: { data: {
newHistoryId, newChatId,
...responseData ...responseData
}, },
id: historyId || '', id: chatId || '',
model: '', model: '',
usage: { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 }, usage: { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 },
choices: [ choices: [

View File

@@ -7,7 +7,7 @@ import { Types } from 'mongoose';
import type { ChatItemType } from '@/types/chat'; import type { ChatItemType } from '@/types/chat';
export type Props = { export type Props = {
historyId?: string; chatId?: string;
limit?: number; limit?: number;
}; };
export type Response = { history: ChatItemType[] }; export type Response = { history: ChatItemType[] };
@@ -16,11 +16,11 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
try { try {
await connectToDatabase(); await connectToDatabase();
const { userId } = await authUser({ req }); const { userId } = await authUser({ req });
const { historyId, limit } = req.body as Props; const { chatId, limit } = req.body as Props;
jsonRes<Response>(res, { jsonRes<Response>(res, {
data: await getChatHistory({ data: await getChatHistory({
historyId, chatId,
userId, userId,
limit limit
}) })
@@ -34,16 +34,16 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
} }
export async function getChatHistory({ export async function getChatHistory({
historyId, chatId,
userId, userId,
limit = 50 limit = 50
}: Props & { userId: string }): Promise<Response> { }: Props & { userId: string }): Promise<Response> {
if (!historyId) { if (!chatId) {
return { history: [] }; return { history: [] };
} }
const history = await Chat.aggregate([ const history = await Chat.aggregate([
{ $match: { _id: new Types.ObjectId(historyId), userId: new Types.ObjectId(userId) } }, { $match: { _id: new Types.ObjectId(chatId), userId: new Types.ObjectId(userId) } },
{ {
$project: { $project: {
content: { content: {

View File

@@ -1,4 +1,4 @@
import React, { useMemo } from 'react'; import React, { useMemo, useState } from 'react';
import { import {
Box, Box,
Button, Button,
@@ -11,6 +11,7 @@ import {
IconButton IconButton
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { useGlobalStore } from '@/store/global'; import { useGlobalStore } from '@/store/global';
import { useEditInfo } from '@/hooks/useEditInfo';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import Avatar from '@/components/Avatar'; import Avatar from '@/components/Avatar';
import MyTooltip from '@/components/MyTooltip'; import MyTooltip from '@/components/MyTooltip';
@@ -19,6 +20,7 @@ import MyIcon from '@/components/Icon';
type HistoryItemType = { type HistoryItemType = {
id: string; id: string;
title: string; title: string;
customTitle?: string;
top?: boolean; top?: boolean;
}; };
@@ -27,29 +29,34 @@ const ChatHistorySlider = ({
appName, appName,
appAvatar, appAvatar,
history, history,
activeHistoryId, activeChatId,
onChangeChat, onChangeChat,
onDelHistory, onDelHistory,
onSetHistoryTop, onSetHistoryTop,
onUpdateTitle onSetCustomTitle
}: { }: {
appId?: string; appId?: string;
appName: string; appName: string;
appAvatar: string; appAvatar: string;
history: HistoryItemType[]; history: HistoryItemType[];
activeHistoryId: string; activeChatId: string;
onChangeChat: (historyId?: string) => void; onChangeChat: (chatId?: string) => void;
onDelHistory: (historyId: string) => void; onDelHistory: (chatId: string) => void;
onSetHistoryTop?: (e: { historyId: string; top: boolean }) => void; onSetHistoryTop?: (e: { chatId: string; top: boolean }) => void;
onUpdateTitle?: (e: { historyId: string; title: string }) => void; onSetCustomTitle?: (e: { chatId: string; title: string }) => void;
}) => { }) => {
const theme = useTheme(); const theme = useTheme();
const router = useRouter(); const router = useRouter();
const { isPc } = useGlobalStore(); const { isPc } = useGlobalStore();
// custom title edit
const { onOpenModal, EditModal: EditTitleModal } = useEditInfo({
title: '自定义历史记录标题',
placeholder: '如果设置为空,会自动跟随聊天记录。'
});
const concatHistory = useMemo<HistoryItemType[]>( const concatHistory = useMemo<HistoryItemType[]>(
() => (!activeHistoryId ? [{ id: activeHistoryId, title: '新对话' }].concat(history) : history), () => (!activeChatId ? [{ id: activeChatId, title: '新对话' }].concat(history) : history),
[activeHistoryId, history] [activeChatId, history]
); );
return ( return (
@@ -121,7 +128,7 @@ const ChatHistorySlider = ({
} }
}} }}
bg={item.top ? '#E6F6F6 !important' : ''} bg={item.top ? '#E6F6F6 !important' : ''}
{...(item.id === activeHistoryId {...(item.id === activeChatId
? { ? {
backgroundColor: 'myBlue.100 !important', backgroundColor: 'myBlue.100 !important',
color: 'myBlue.700' color: 'myBlue.700'
@@ -132,9 +139,9 @@ const ChatHistorySlider = ({
} }
})} })}
> >
<MyIcon name={item.id === activeHistoryId ? 'chatFill' : 'chatLight'} w={'16px'} /> <MyIcon name={item.id === activeChatId ? 'chatFill' : 'chatLight'} w={'16px'} />
<Box flex={'1 0 0'} ml={3} className="textEllipsis"> <Box flex={'1 0 0'} ml={3} className="textEllipsis">
{item.title} {item.customTitle || item.title}
</Box> </Box>
{!!item.id && ( {!!item.id && (
<Box className="more" display={['block', 'none']}> <Box className="more" display={['block', 'none']}>
@@ -154,20 +161,24 @@ const ChatHistorySlider = ({
<MenuItem <MenuItem
onClick={(e) => { onClick={(e) => {
e.stopPropagation(); e.stopPropagation();
onSetHistoryTop({ historyId: item.id, top: !item.top }); onSetHistoryTop({ chatId: item.id, top: !item.top });
}} }}
> >
<MyIcon mr={2} name={'setTop'} w={'16px'}></MyIcon> <MyIcon mr={2} name={'setTop'} w={'16px'}></MyIcon>
{item.top ? '取消置顶' : '置顶'} {item.top ? '取消置顶' : '置顶'}
</MenuItem> </MenuItem>
)} )}
{onUpdateTitle && ( {onSetCustomTitle && (
<MenuItem <MenuItem
onClick={(e) => { onClick={(e) => {
e.stopPropagation(); e.stopPropagation();
onUpdateTitle({ onOpenModal({
historyId: item.id, defaultVal: item.customTitle || item.title,
title: '是是是' onSuccess: (e) =>
onSetCustomTitle({
chatId: item.id,
title: e
})
}); });
}} }}
> >
@@ -180,7 +191,7 @@ const ChatHistorySlider = ({
onClick={(e) => { onClick={(e) => {
e.stopPropagation(); e.stopPropagation();
onDelHistory(item.id); onDelHistory(item.id);
if (item.id === activeHistoryId) { if (item.id === activeChatId) {
onChangeChat(); onChangeChat();
} }
}} }}
@@ -218,6 +229,7 @@ const ChatHistorySlider = ({
</Flex> </Flex>
)} )}
<EditTitleModal />
</Flex> </Flex>
); );
}; };

View File

@@ -26,7 +26,7 @@ import ChatHeader from './components/ChatHeader';
const Chat = () => { const Chat = () => {
const router = useRouter(); const router = useRouter();
const { appId = '', historyId = '' } = router.query as { appId: string; historyId: string }; const { appId = '', chatId = '' } = router.query as { appId: string; chatId: string };
const theme = useTheme(); const theme = useTheme();
const ChatBoxRef = useRef<ComponentRef>(null); const ChatBoxRef = useRef<ComponentRef>(null);
@@ -35,8 +35,8 @@ const Chat = () => {
const { const {
lastChatAppId, lastChatAppId,
setLastChatAppId, setLastChatAppId,
lastHistoryId, lastChatId,
setLastHistoryId, setLastChatId,
history, history,
loadHistory, loadHistory,
updateHistory, updateHistory,
@@ -52,12 +52,12 @@ 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, newHistoryId, rawSearch } = await streamFetch({ const { responseText, newChatId, rawSearch } = await streamFetch({
data: { data: {
messages: prompts, messages: prompts,
variables, variables,
appId, appId,
historyId chatId
}, },
onMessage: generatingMessage, onMessage: generatingMessage,
abortSignal: controller abortSignal: controller
@@ -66,27 +66,27 @@ const Chat = () => {
const newTitle = prompts[0].content?.slice(0, 20) || '新对话'; const newTitle = prompts[0].content?.slice(0, 20) || '新对话';
// update history // update history
if (newHistoryId) { if (newChatId) {
forbidRefresh.current = true; forbidRefresh.current = true;
router.replace({
query: {
historyId: newHistoryId,
appId
}
});
const newHistory: ChatHistoryItemType = { const newHistory: ChatHistoryItemType = {
_id: newHistoryId, _id: newChatId,
updateTime: new Date(), updateTime: new Date(),
title: newTitle, title: newTitle,
appId, appId,
top: false top: false
}; };
updateHistory(newHistory); updateHistory(newHistory);
router.replace({
query: {
chatId: newChatId,
appId
}
});
} else { } else {
const currentHistory = history.find((item) => item._id === historyId); const currentChat = history.find((item) => item._id === chatId);
currentHistory && currentChat &&
updateHistory({ updateHistory({
...currentHistory, ...currentChat,
updateTime: new Date(), updateTime: new Date(),
title: newTitle title: newTitle
}); });
@@ -100,41 +100,41 @@ const Chat = () => {
return { responseText, rawSearch }; return { responseText, rawSearch };
}, },
[appId, history, historyId, router, setChatData, updateHistory] [appId, chatId, history, router, setChatData, updateHistory]
); );
// 删除一句话 // 删除一句话
const delOneHistoryItem = useCallback( const delOneHistoryItem = useCallback(
async ({ contentId, index }: { contentId?: string; index: number }) => { async ({ contentId, index }: { contentId?: string; index: number }) => {
if (!historyId || !contentId) return; if (!chatId || !contentId) return;
try { try {
setChatData((state) => ({ setChatData((state) => ({
...state, ...state,
history: state.history.filter((_, i) => i !== index) history: state.history.filter((_, i) => i !== index)
})); }));
await delChatRecordByIndex({ historyId, contentId }); await delChatRecordByIndex({ chatId, contentId });
} catch (err) { } catch (err) {
console.log(err); console.log(err);
} }
}, },
[historyId, setChatData] [chatId, setChatData]
); );
// get chat app info // get chat app info
const loadChatInfo = useCallback( const loadChatInfo = useCallback(
async ({ async ({
appId, appId,
historyId, chatId,
loading = false loading = false
}: { }: {
appId: string; appId: string;
historyId: string; chatId: string;
loading?: boolean; loading?: boolean;
}) => { }) => {
try { try {
loading && setIsLoading(true); loading && setIsLoading(true);
const res = await getInitChatSiteInfo({ appId, historyId }); const res = await getInitChatSiteInfo({ appId, chatId });
const history = res.history.map((item) => ({ const history = res.history.map((item) => ({
...item, ...item,
status: 'finish' as any status: 'finish' as any
@@ -166,22 +166,22 @@ const Chat = () => {
} catch (e: any) { } catch (e: any) {
// reset all chat tore // reset all chat tore
setLastChatAppId(''); setLastChatAppId('');
setLastHistoryId(''); setLastChatId('');
router.replace('/chat'); router.replace('/chat');
} }
setIsLoading(false); setIsLoading(false);
return null; return null;
}, },
[setIsLoading, setChatData, router, setLastChatAppId, setLastHistoryId] [setIsLoading, setChatData, router, setLastChatAppId, setLastChatId]
); );
// 初始化聊天框 // 初始化聊天框
useQuery(['init', appId, historyId], () => { useQuery(['init', appId, chatId], () => {
// pc: redirect to latest model chat // pc: redirect to latest model chat
if (!appId && lastChatAppId) { if (!appId && lastChatAppId) {
router.replace({ router.replace({
query: { query: {
appId: lastChatAppId, appId: lastChatAppId,
historyId: lastHistoryId chatId: lastChatId
} }
}); });
return null; return null;
@@ -189,7 +189,7 @@ const Chat = () => {
// store id // store id
appId && setLastChatAppId(appId); appId && setLastChatAppId(appId);
setLastHistoryId(historyId); setLastChatId(chatId);
if (forbidRefresh.current) { if (forbidRefresh.current) {
forbidRefresh.current = false; forbidRefresh.current = false;
@@ -198,7 +198,7 @@ const Chat = () => {
return loadChatInfo({ return loadChatInfo({
appId, appId,
historyId, chatId,
loading: appId !== chatData.appId loading: appId !== chatData.appId
}); });
}); });
@@ -231,16 +231,17 @@ const Chat = () => {
appId={appId} appId={appId}
appName={chatData.app.name} appName={chatData.app.name}
appAvatar={chatData.app.avatar} appAvatar={chatData.app.avatar}
activeHistoryId={historyId} activeChatId={chatId}
history={history.map((item) => ({ history={history.map((item) => ({
id: item._id, id: item._id,
title: item.title, title: item.title,
customTitle: item.customTitle,
top: item.top top: item.top
}))} }))}
onChangeChat={(historyId) => { onChangeChat={(chatId) => {
router.push({ router.push({
query: { query: {
historyId: historyId || '', chatId: chatId || '',
appId appId
} }
}); });
@@ -252,7 +253,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.historyId); const historyItem = history.find((item) => item._id === e.chatId);
if (!historyItem) return; if (!historyItem) return;
updateHistory({ updateHistory({
...historyItem, ...historyItem,
@@ -260,17 +261,17 @@ const Chat = () => {
}); });
} catch (error) {} } catch (error) {}
}} }}
onUpdateTitle={async (e) => { onSetCustomTitle={async (e) => {
try { try {
await putChatHistory({ await putChatHistory({
historyId: e.historyId, chatId: e.chatId,
customTitle: e.title customTitle: e.title
}); });
const historyItem = history.find((item) => item._id === e.historyId); const historyItem = history.find((item) => item._id === e.chatId);
if (!historyItem) return; if (!historyItem) return;
updateHistory({ updateHistory({
...historyItem, ...historyItem,
title: e.title customTitle: e.title
}); });
} catch (error) {} } catch (error) {}
}} }}
@@ -297,7 +298,7 @@ const Chat = () => {
<ChatBox <ChatBox
ref={ChatBoxRef} ref={ChatBoxRef}
showEmptyIntro showEmptyIntro
historyId={historyId} chatId={chatId}
appAvatar={chatData.app.avatar} appAvatar={chatData.app.avatar}
variableModules={chatData.app.variableModules} variableModules={chatData.app.variableModules}
welcomeText={chatData.app.welcomeText} welcomeText={chatData.app.welcomeText}

View File

@@ -19,7 +19,7 @@ const ChatHistorySlider = dynamic(() => import('./components/ChatHistorySlider')
ssr: false ssr: false
}); });
const ShareChat = ({ shareId, historyId }: { shareId: string; historyId: string }) => { const ShareChat = ({ shareId, chatId }: { shareId: string; chatId: string }) => {
const router = useRouter(); const router = useRouter();
const { toast } = useToast(); const { toast } = useToast();
const { isOpen: isOpenSlider, onClose: onCloseSlider, onOpen: onOpenSlider } = useDisclosure(); const { isOpen: isOpenSlider, onClose: onCloseSlider, onOpen: onOpenSlider } = useDisclosure();
@@ -33,7 +33,7 @@ const ShareChat = ({ shareId, historyId }: { shareId: string; historyId: string
shareChatHistory, shareChatHistory,
saveChatResponse, saveChatResponse,
delShareChatHistoryItemById, delShareChatHistoryItemById,
delOneShareHistoryByHistoryId, delOneShareHistoryByChatId,
delManyShareChatHistoryByShareId delManyShareChatHistoryByShareId
} = useShareChatStore(); } = useShareChatStore();
@@ -60,7 +60,7 @@ const ShareChat = ({ shareId, historyId }: { shareId: string; historyId: string
/* save chat */ /* save chat */
const { newChatId } = saveChatResponse({ const { newChatId } = saveChatResponse({
historyId, chatId,
prompts: gptMessage2ChatType(prompts).map((item) => ({ prompts: gptMessage2ChatType(prompts).map((item) => ({
...item, ...item,
status: 'finish' status: 'finish'
@@ -73,7 +73,7 @@ const ShareChat = ({ shareId, historyId }: { shareId: string; historyId: string
router.replace({ router.replace({
query: { query: {
shareId, shareId,
historyId: newChatId chatId: newChatId
} }
}); });
} }
@@ -88,15 +88,15 @@ const ShareChat = ({ shareId, historyId }: { shareId: string; historyId: string
return { responseText }; return { responseText };
}, },
[historyId, router, saveChatResponse, shareChatData.maxContext, shareId] [chatId, router, saveChatResponse, shareChatData.maxContext, shareId]
); );
const loadAppInfo = useCallback( const loadAppInfo = useCallback(
async (shareId: string, historyId: string) => { async (shareId: string, chatId: string) => {
console.log(shareId, historyId); console.log(shareId, chatId);
if (!shareId) return null; if (!shareId) return null;
const history = shareChatHistory.find((item) => item._id === historyId) || defaultHistory; const history = shareChatHistory.find((item) => item._id === chatId) || defaultHistory;
ChatBoxRef.current?.resetHistory(history.chats); ChatBoxRef.current?.resetHistory(history.chats);
ChatBoxRef.current?.resetVariables(history.variables); ChatBoxRef.current?.resetVariables(history.variables);
@@ -134,8 +134,8 @@ const ShareChat = ({ shareId, historyId }: { shareId: string; historyId: string
[delManyShareChatHistoryByShareId, setShareChatData, shareChatData, shareChatHistory, toast] [delManyShareChatHistoryByShareId, setShareChatData, shareChatData, shareChatHistory, toast]
); );
useQuery(['init', shareId, historyId], () => { useQuery(['init', shareId, chatId], () => {
return loadAppInfo(shareId, historyId); return loadAppInfo(shareId, chatId);
}); });
return ( return (
@@ -156,15 +156,15 @@ const ShareChat = ({ shareId, historyId }: { shareId: string; historyId: string
<ChatHistorySlider <ChatHistorySlider
appName={shareChatData.app.name} appName={shareChatData.app.name}
appAvatar={shareChatData.app.avatar} appAvatar={shareChatData.app.avatar}
activeHistoryId={historyId} activeChatId={chatId}
history={shareChatHistory.map((item) => ({ history={shareChatHistory.map((item) => ({
id: item._id, id: item._id,
title: item.title title: item.title
}))} }))}
onChangeChat={(historyId) => { onChangeChat={(chatId) => {
router.push({ router.push({
query: { query: {
historyId: historyId || '', chatId: chatId || '',
shareId shareId
} }
}); });
@@ -172,7 +172,7 @@ const ShareChat = ({ shareId, historyId }: { shareId: string; historyId: string
onCloseSlider(); onCloseSlider();
} }
}} }}
onDelHistory={delOneShareHistoryByHistoryId} onDelHistory={delOneShareHistoryByChatId}
/> />
)} )}
@@ -208,7 +208,7 @@ const ShareChat = ({ shareId, historyId }: { shareId: string; historyId: string
})); }));
}} }}
onStartChat={startChat} onStartChat={startChat}
onDelMessage={({ index }) => delShareChatHistoryItemById({ historyId, index })} onDelMessage={({ index }) => delShareChatHistoryItemById({ chatId, index })}
/> />
</Box> </Box>
</Flex> </Flex>
@@ -219,10 +219,10 @@ const ShareChat = ({ shareId, historyId }: { shareId: string; historyId: string
export async function getServerSideProps(context: any) { export async function getServerSideProps(context: any) {
const shareId = context?.query?.shareId || ''; const shareId = context?.query?.shareId || '';
const historyId = context?.query?.historyId || ''; const chatId = context?.query?.chatId || '';
return { return {
props: { shareId, historyId } props: { shareId, chatId }
}; };
} }

View File

@@ -253,7 +253,7 @@ const DataCard = ({ kbId }: { kbId: string }) => {
</Flex> </Flex>
)} )}
{total === 0 && ( {total === 0 && (
<Flex h={'100%'} flexDirection={'column'} alignItems={'center'} pt={'10vh'}> <Flex flexDirection={'column'} alignItems={'center'} pt={'10vh'}>
<MyIcon name="empty" w={'48px'} h={'48px'} color={'transparent'} /> <MyIcon name="empty" w={'48px'} h={'48px'} color={'transparent'} />
<Box mt={2} color={'myGray.500'}> <Box mt={2} color={'myGray.500'}>

View File

@@ -18,12 +18,12 @@ const Login = () => {
const { isPc } = useGlobalStore(); const { isPc } = useGlobalStore();
const [pageType, setPageType] = useState<`${PageTypeEnum}`>(PageTypeEnum.login); const [pageType, setPageType] = useState<`${PageTypeEnum}`>(PageTypeEnum.login);
const { setUserInfo } = useUserStore(); const { setUserInfo } = useUserStore();
const { setLastHistoryId, setLastChatAppId } = useChatStore(); const { setLastChatId, setLastChatAppId } = useChatStore();
const loginSuccess = useCallback( const loginSuccess = useCallback(
(res: ResLogin) => { (res: ResLogin) => {
// init store // init store
setLastHistoryId(''); setLastChatId('');
setLastChatAppId(''); setLastChatAppId('');
setUserInfo(res.user); setUserInfo(res.user);
@@ -31,7 +31,7 @@ const Login = () => {
router.push(lastRoute ? decodeURIComponent(lastRoute) : '/app/list'); router.push(lastRoute ? decodeURIComponent(lastRoute) : '/app/list');
}, 100); }, 100);
}, },
[lastRoute, router, setLastHistoryId, setLastChatAppId, setUserInfo] [lastRoute, router, setLastChatId, setLastChatAppId, setUserInfo]
); );
function DynamicComponent({ type }: { type: `${PageTypeEnum}` }) { function DynamicComponent({ type }: { type: `${PageTypeEnum}` }) {

View File

@@ -1,17 +1,10 @@
import { ChatItemType } from '@/types/chat'; import { ChatItemType } from '@/types/chat';
import { modelToolMap } from '@/utils/plugin'; import { modelToolMap } from '@/utils/plugin';
import { ChatRoleEnum } from '@/constants/chat'; import { ChatRoleEnum, sseResponseEventEnum } from '@/constants/chat';
import { sseResponse } from '../tools';
import { OpenAiChatEnum } from '@/constants/model'; import { OpenAiChatEnum } from '@/constants/model';
import type { NextApiResponse } from 'next'; import type { NextApiResponse } from 'next';
export type ChatCompletionType = {
apiKey: string;
temperature: number;
maxToken?: number;
messages: ChatItemType[];
historyId?: string;
[key: string]: any;
};
export type ChatCompletionResponseType = { export type ChatCompletionResponseType = {
streamResponse: any; streamResponse: any;
responseMessages: ChatItemType[]; responseMessages: ChatItemType[];

View File

@@ -15,12 +15,12 @@ type State = {
setChatData: (e: InitChatResponse | ((e: InitChatResponse) => InitChatResponse)) => void; setChatData: (e: InitChatResponse | ((e: InitChatResponse) => InitChatResponse)) => void;
lastChatAppId: string; lastChatAppId: string;
setLastChatAppId: (id: string) => void; setLastChatAppId: (id: string) => void;
lastHistoryId: string; lastChatId: string;
setLastHistoryId: (id: string) => void; setLastChatId: (id: string) => void;
}; };
const defaultChatData: InitChatResponse = { const defaultChatData: InitChatResponse = {
historyId: '', chatId: '',
appId: '', appId: '',
app: { app: {
name: '', name: '',
@@ -43,10 +43,10 @@ export const useChatStore = create<State>()(
state.lastChatAppId = id; state.lastChatAppId = id;
}); });
}, },
lastHistoryId: '', lastChatId: '',
setLastHistoryId(id: string) { setLastChatId(id: string) {
set((state) => { set((state) => {
state.lastHistoryId = id; state.lastChatId = id;
}); });
}, },
history: [], history: [],
@@ -63,25 +63,36 @@ export const useChatStore = create<State>()(
}); });
return null; return null;
}, },
async delHistory(historyId) { async delHistory(chatId) {
set((state) => { set((state) => {
state.history = state.history.filter((item) => item._id !== historyId); state.history = state.history.filter((item) => item._id !== chatId);
}); });
await delChatHistoryById(historyId); await delChatHistoryById(chatId);
}, },
updateHistory(history) { updateHistory(history) {
const index = get().history.findIndex((item) => item._id === history._id); const index = get().history.findIndex((item) => item._id === history._id);
set((state) => { set((state) => {
if (index > -1) { const newHistory = (() => {
const newHistory = [ if (index > -1) {
history, return [
...get().history.slice(0, index), history,
...get().history.slice(index + 1) ...get().history.slice(0, index),
]; ...get().history.slice(index + 1)
state.history = newHistory; ];
} else { } else {
state.history = [history, ...state.history]; return [history, ...state.history];
} }
})();
// newHistory.sort(function (a, b) {
// if (a.top === true && b.top === false) {
// return -1;
// } else if (a.top === false && b.top === true) {
// return 1;
// } else {
// return 0;
// }
// });
state.history = newHistory;
}); });
}, },
chatData: defaultChatData, chatData: defaultChatData,
@@ -101,7 +112,7 @@ export const useChatStore = create<State>()(
name: 'chatStore', name: 'chatStore',
partialize: (state) => ({ partialize: (state) => ({
lastChatAppId: state.lastChatAppId, lastChatAppId: state.lastChatAppId,
lastHistoryId: state.lastHistoryId lastChatId: state.lastChatId
}) })
} }
) )

View File

@@ -12,13 +12,13 @@ type State = {
setShareChatData: (e: ShareChatType | ((e: ShareChatType) => ShareChatType)) => void; setShareChatData: (e: ShareChatType | ((e: ShareChatType) => ShareChatType)) => void;
shareChatHistory: ShareChatHistoryItemType[]; shareChatHistory: ShareChatHistoryItemType[];
saveChatResponse: (e: { saveChatResponse: (e: {
historyId: string; chatId: string;
prompts: ChatSiteItemType[]; prompts: ChatSiteItemType[];
variables: Record<string, any>; variables: Record<string, any>;
shareId: string; shareId: string;
}) => { newChatId: string }; }) => { newChatId: string };
delOneShareHistoryByHistoryId: (historyId: string) => void; delOneShareHistoryByChatId: (chatId: string) => void;
delShareChatHistoryItemById: (e: { historyId: string; index: number }) => void; delShareChatHistoryItemById: (e: { chatId: string; index: number }) => void;
delManyShareChatHistoryByShareId: (shareId?: string) => void; delManyShareChatHistoryByShareId: (shareId?: string) => void;
}; };
@@ -62,15 +62,15 @@ export const useShareChatStore = create<State>()(
}); });
}, },
shareChatHistory: [], shareChatHistory: [],
saveChatResponse({ historyId, prompts, variables, shareId }) { saveChatResponse({ chatId, prompts, variables, shareId }) {
const history = get().shareChatHistory.find((item) => item._id === historyId); const history = get().shareChatHistory.find((item) => item._id === chatId);
const newChatId = history ? '' : nanoid(); const newChatId = history ? '' : nanoid();
const historyList = (() => { const historyList = (() => {
if (history) { if (history) {
return get().shareChatHistory.map((item) => return get().shareChatHistory.map((item) =>
item._id === historyId item._id === chatId
? { ? {
...item, ...item,
title: prompts[prompts.length - 2]?.value, title: prompts[prompts.length - 2]?.value,
@@ -102,18 +102,16 @@ export const useShareChatStore = create<State>()(
newChatId newChatId
}; };
}, },
delOneShareHistoryByHistoryId(historyId: string) { delOneShareHistoryByChatId(chatId: string) {
set((state) => { set((state) => {
state.shareChatHistory = state.shareChatHistory.filter( state.shareChatHistory = state.shareChatHistory.filter((item) => item._id !== chatId);
(item) => item._id !== historyId
);
}); });
}, },
delShareChatHistoryItemById({ historyId, 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 === historyId item._id === 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)]

View File

@@ -20,6 +20,7 @@ export type ChatSiteItemType = {
export type HistoryItemType = { export type HistoryItemType = {
_id: string; _id: string;
updateTime: Date; updateTime: Date;
customTitle?: string;
title: string; title: string;
}; };
export type ChatHistoryItemType = HistoryItemType & { export type ChatHistoryItemType = HistoryItemType & {