perf: init chat content.use mongo aggregate
This commit is contained in:
parent
1f112f7715
commit
e60c36b423
@ -1,5 +1,5 @@
|
|||||||
import { GET, POST, DELETE } from './request';
|
import { GET, POST, DELETE } from './request';
|
||||||
import type { ChatItemType, ChatSiteItemType } from '@/types/chat';
|
import type { ChatItemType } from '@/types/chat';
|
||||||
import type { InitChatResponse } from './response/chat';
|
import type { InitChatResponse } from './response/chat';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -8,24 +8,6 @@ import type { InitChatResponse } from './response/chat';
|
|||||||
export const getInitChatSiteInfo = (modelId: string, chatId: '' | string) =>
|
export const getInitChatSiteInfo = (modelId: string, chatId: '' | string) =>
|
||||||
GET<InitChatResponse>(`/chat/init?modelId=${modelId}&chatId=${chatId}`);
|
GET<InitChatResponse>(`/chat/init?modelId=${modelId}&chatId=${chatId}`);
|
||||||
|
|
||||||
/**
|
|
||||||
* 发送 GPT3 prompt
|
|
||||||
*/
|
|
||||||
export const postGPT3SendPrompt = ({
|
|
||||||
chatId,
|
|
||||||
prompt
|
|
||||||
}: {
|
|
||||||
prompt: ChatSiteItemType[];
|
|
||||||
chatId: string;
|
|
||||||
}) =>
|
|
||||||
POST<string>(`/chat/gpt3`, {
|
|
||||||
chatId,
|
|
||||||
prompt: prompt.map((item) => ({
|
|
||||||
obj: item.obj,
|
|
||||||
value: item.value
|
|
||||||
}))
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取历史记录
|
* 获取历史记录
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import React, { memo, useMemo } from 'react';
|
import React, { memo } from 'react';
|
||||||
import ReactMarkdown from 'react-markdown';
|
import ReactMarkdown from 'react-markdown';
|
||||||
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
|
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
|
||||||
import { Box, Flex, useColorModeValue } from '@chakra-ui/react';
|
import { Box, Flex, useColorModeValue } from '@chakra-ui/react';
|
||||||
@ -14,7 +14,6 @@ import { codeLight } from './codeLight';
|
|||||||
|
|
||||||
const Markdown = ({ source, isChatting = false }: { source: string; isChatting?: boolean }) => {
|
const Markdown = ({ source, isChatting = false }: { source: string; isChatting?: boolean }) => {
|
||||||
const { copyData } = useCopyData();
|
const { copyData } = useCopyData();
|
||||||
const formatSource = useMemo(() => source, [source]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ReactMarkdown
|
<ReactMarkdown
|
||||||
@ -63,7 +62,7 @@ const Markdown = ({ source, isChatting = false }: { source: string; isChatting?:
|
|||||||
}}
|
}}
|
||||||
linkTarget="_blank"
|
linkTarget="_blank"
|
||||||
>
|
>
|
||||||
{formatSource}
|
{source}
|
||||||
</ReactMarkdown>
|
</ReactMarkdown>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,10 +1,11 @@
|
|||||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||||
import { jsonRes } from '@/service/response';
|
import { jsonRes } from '@/service/response';
|
||||||
import { connectToDatabase, Chat, Model } from '@/service/mongo';
|
import { connectToDatabase, Chat } from '@/service/mongo';
|
||||||
import type { InitChatResponse } from '@/api/response/chat';
|
import type { InitChatResponse } from '@/api/response/chat';
|
||||||
import { authToken } from '@/service/utils/tools';
|
import { authToken } from '@/service/utils/tools';
|
||||||
import { ChatItemType } from '@/types/chat';
|
import { ChatItemType } from '@/types/chat';
|
||||||
import { authModel } from '@/service/utils/auth';
|
import { authModel } from '@/service/utils/auth';
|
||||||
|
import mongoose from 'mongoose';
|
||||||
|
|
||||||
/* 初始化我的聊天框,需要身份验证 */
|
/* 初始化我的聊天框,需要身份验证 */
|
||||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||||
@ -27,19 +28,23 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||||||
let history: ChatItemType[] = [];
|
let history: ChatItemType[] = [];
|
||||||
|
|
||||||
if (chatId) {
|
if (chatId) {
|
||||||
// 获取 chat 数据
|
// 获取 chat.content 数据
|
||||||
const chat = await Chat.findOne({
|
history = await Chat.aggregate([
|
||||||
_id: chatId,
|
{ $match: { _id: new mongoose.Types.ObjectId(chatId) } },
|
||||||
userId,
|
{ $unwind: '$content' },
|
||||||
modelId
|
{ $match: { 'content.deleted': false } },
|
||||||
});
|
{ $sort: { 'content._id': -1 } },
|
||||||
|
{ $limit: 50 },
|
||||||
|
{
|
||||||
|
$project: {
|
||||||
|
id: '$content._id',
|
||||||
|
obj: '$content.obj',
|
||||||
|
value: '$content.value'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
if (!chat) {
|
history.reverse();
|
||||||
throw new Error('聊天框不存在');
|
|
||||||
}
|
|
||||||
|
|
||||||
// filter 被 deleted 的内容
|
|
||||||
history = chat.content.filter((item) => item.deleted !== true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
jsonRes<InitChatResponse>(res, {
|
jsonRes<InitChatResponse>(res, {
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import { useRouter } from 'next/router';
|
|||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
import { getInitChatSiteInfo, delChatRecordByIndex, postSaveChat } from '@/api/chat';
|
import { getInitChatSiteInfo, delChatRecordByIndex, postSaveChat } from '@/api/chat';
|
||||||
import type { InitChatResponse } from '@/api/response/chat';
|
import type { InitChatResponse } from '@/api/response/chat';
|
||||||
import { ChatSiteItemType } from '@/types/chat';
|
import type { ChatItemType } from '@/types/chat';
|
||||||
import {
|
import {
|
||||||
Textarea,
|
Textarea,
|
||||||
Box,
|
Box,
|
||||||
@ -29,6 +29,8 @@ import { streamFetch } from '@/api/fetch';
|
|||||||
import Icon from '@/components/Icon';
|
import Icon from '@/components/Icon';
|
||||||
import MyIcon from '@/components/Icon';
|
import MyIcon from '@/components/Icon';
|
||||||
import { throttle } from 'lodash';
|
import { throttle } from 'lodash';
|
||||||
|
import { customAlphabet } from 'nanoid';
|
||||||
|
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 5);
|
||||||
|
|
||||||
const SlideBar = dynamic(() => import('./components/SlideBar'));
|
const SlideBar = dynamic(() => import('./components/SlideBar'));
|
||||||
const Empty = dynamic(() => import('./components/Empty'));
|
const Empty = dynamic(() => import('./components/Empty'));
|
||||||
@ -36,6 +38,11 @@ const Markdown = dynamic(() => import('@/components/Markdown'));
|
|||||||
|
|
||||||
const textareaMinH = '22px';
|
const textareaMinH = '22px';
|
||||||
|
|
||||||
|
export type ChatSiteItemType = {
|
||||||
|
id: string;
|
||||||
|
status: 'loading' | 'finish';
|
||||||
|
} & ChatItemType;
|
||||||
|
|
||||||
interface ChatType extends InitChatResponse {
|
interface ChatType extends InitChatResponse {
|
||||||
history: ChatSiteItemType[];
|
history: ChatSiteItemType[];
|
||||||
}
|
}
|
||||||
@ -123,10 +130,13 @@ const Chat = ({ modelId, chatId }: { modelId: string; chatId: string }) => {
|
|||||||
isLoading && setLoading(true);
|
isLoading && setLoading(true);
|
||||||
try {
|
try {
|
||||||
const res = await getInitChatSiteInfo(modelId, chatId);
|
const res = await getInitChatSiteInfo(modelId, chatId);
|
||||||
|
|
||||||
setChatData({
|
setChatData({
|
||||||
...res,
|
...res,
|
||||||
history: res.history.map((item) => ({
|
history: res.history.map((item: any, i) => ({
|
||||||
...item,
|
obj: item.obj,
|
||||||
|
value: item.value,
|
||||||
|
id: item.id || `${nanoid()}-${i}`,
|
||||||
status: 'finish'
|
status: 'finish'
|
||||||
}))
|
}))
|
||||||
});
|
});
|
||||||
@ -284,11 +294,13 @@ const Chat = ({ modelId, chatId }: { modelId: string; chatId: string }) => {
|
|||||||
const newChatList: ChatSiteItemType[] = [
|
const newChatList: ChatSiteItemType[] = [
|
||||||
...chatData.history,
|
...chatData.history,
|
||||||
{
|
{
|
||||||
|
id: nanoid(),
|
||||||
obj: 'Human',
|
obj: 'Human',
|
||||||
value: val,
|
value: val,
|
||||||
status: 'finish'
|
status: 'finish'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
id: nanoid(),
|
||||||
obj: 'AI',
|
obj: 'AI',
|
||||||
value: '',
|
value: '',
|
||||||
status: 'loading'
|
status: 'loading'
|
||||||
@ -432,7 +444,7 @@ const Chat = ({ modelId, chatId }: { modelId: string; chatId: string }) => {
|
|||||||
<Box ref={ChatBox} pb={[4, 0]} flex={'1 0 0'} h={0} w={'100%'} overflowY={'auto'}>
|
<Box ref={ChatBox} pb={[4, 0]} flex={'1 0 0'} h={0} w={'100%'} overflowY={'auto'}>
|
||||||
{chatData.history.map((item, index) => (
|
{chatData.history.map((item, index) => (
|
||||||
<Box
|
<Box
|
||||||
key={index}
|
key={item.id}
|
||||||
py={media(9, 6)}
|
py={media(9, 6)}
|
||||||
px={media(4, 2)}
|
px={media(4, 2)}
|
||||||
backgroundColor={
|
backgroundColor={
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import type { ModelSchema } from '@/types/mongoSchema';
|
|||||||
import { authToken } from './tools';
|
import { authToken } from './tools';
|
||||||
import { getOpenApiKey } from './openai';
|
import { getOpenApiKey } from './openai';
|
||||||
import type { ChatItemType } from '@/types/chat';
|
import type { ChatItemType } from '@/types/chat';
|
||||||
|
import mongoose from 'mongoose';
|
||||||
|
|
||||||
export const getOpenAIApi = (apiKey: string) => {
|
export const getOpenAIApi = (apiKey: string) => {
|
||||||
const configuration = new Configuration({
|
const configuration = new Configuration({
|
||||||
@ -47,14 +48,17 @@ export const authChat = async ({
|
|||||||
|
|
||||||
if (chatId) {
|
if (chatId) {
|
||||||
// 获取 chat 数据
|
// 获取 chat 数据
|
||||||
const chat = await Chat.findById(chatId);
|
content = await Chat.aggregate([
|
||||||
|
{ $match: { _id: new mongoose.Types.ObjectId(chatId) } },
|
||||||
if (!chat) {
|
{ $unwind: '$content' },
|
||||||
return Promise.reject('对话不存在');
|
{ $match: { 'content.deleted': false } },
|
||||||
}
|
{
|
||||||
|
$project: {
|
||||||
// filter 掉被 deleted 的内容
|
obj: '$content.obj',
|
||||||
content = chat.content.filter((item) => item.deleted !== true);
|
value: '$content.value'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取 user 的 apiKey
|
// 获取 user 的 apiKey
|
||||||
|
|||||||
10
src/types/chat.d.ts
vendored
10
src/types/chat.d.ts
vendored
@ -3,13 +3,3 @@ export type ChatItemType = {
|
|||||||
value: string;
|
value: string;
|
||||||
deleted?: boolean;
|
deleted?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ChatSiteItemType = {
|
|
||||||
status: 'loading' | 'finish';
|
|
||||||
} & ChatItemType;
|
|
||||||
|
|
||||||
export type HistoryItem = {
|
|
||||||
chatId: string;
|
|
||||||
title: string;
|
|
||||||
history?: ChatSiteItemType[];
|
|
||||||
};
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user