diff --git a/client/src/api/chat.ts b/client/src/api/chat.ts index 221a55bb8..ef981280e 100644 --- a/client/src/api/chat.ts +++ b/client/src/api/chat.ts @@ -4,8 +4,7 @@ import type { InitChatResponse, InitShareChatResponse } from './response/chat'; import { RequestPaging } from '../types/index'; import type { ShareChatSchema } from '@/types/mongoSchema'; import type { ShareChatEditType } from '@/types/app'; -import { Obj2Query } from '@/utils/tools'; -import type { QuoteItemType } from '@/pages/api/openapi/kb/appKbSearch'; +import type { QuoteItemType } from '@/pages/api/openapi/modules/kb/search'; import type { Props as UpdateHistoryProps } from '@/pages/api/chat/history/updateChatHistory'; /** @@ -39,7 +38,7 @@ export const updateHistoryQuote = (params: { contentId: string; quoteId: string; sourceText: string; -}) => GET(`/chat/history/updateHistoryQuote`, params); +}) => PUT(`/chat/history/updateHistoryQuote`, params); /** * 删除一句对话 diff --git a/client/src/api/fetch.ts b/client/src/api/fetch.ts index 28b625831..b3a8d2aa6 100644 --- a/client/src/api/fetch.ts +++ b/client/src/api/fetch.ts @@ -1,6 +1,8 @@ import { sseResponseEventEnum } from '@/constants/chat'; import { getErrText } from '@/utils/tools'; import { parseStreamChunk } from '@/utils/adapt'; +import { QuoteItemType } from '@/pages/api/openapi/modules/kb/search'; +import { rawSearchKey } from '@/constants/chat'; interface StreamFetchProps { url?: string; @@ -14,88 +16,94 @@ export const streamFetch = ({ onMessage, abortSignal }: StreamFetchProps) => - new Promise<{ responseText: string; errMsg: string; newHistoryId: string | null }>( - async (resolve, reject) => { - try { - const response = await window.fetch(url, { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - signal: abortSignal.signal, - body: JSON.stringify({ - ...data, - stream: true - }) - }); + new Promise<{ + responseText: string; + errMsg: string; + newHistoryId: string | null; + [rawSearchKey]: QuoteItemType[]; + }>(async (resolve, reject) => { + try { + const response = await window.fetch(url, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + signal: abortSignal.signal, + body: JSON.stringify({ + ...data, + stream: true + }) + }); - if (response.status !== 200) { - const err = await response.json(); - return reject(err); - } + if (!response?.body) { + throw new Error('Request Error'); + } - if (!response?.body) { - throw new Error('Request Error'); - } + const reader = response.body?.getReader(); - const reader = response.body?.getReader(); + // response data + let responseText = ''; + let rawSearch: QuoteItemType[] = []; + let errMsg = ''; + const newHistoryId = response.headers.get('newHistoryId'); - // response data - let responseText = ''; - let errMsg = ''; - const newHistoryId = response.headers.get('newHistoryId'); - - const read = async () => { - try { - const { done, value } = await reader.read(); - if (done) { - if (response.status === 200) { - return resolve({ - responseText, - errMsg, - newHistoryId - }); - } else { - return reject('响应过程出现异常~'); - } - } - const chunkResponse = parseStreamChunk(value); - - chunkResponse.forEach((item) => { - // parse json data - const data = (() => { - try { - return JSON.parse(item.data); - } catch (error) { - return item.data; - } - })(); - - if (item.event === sseResponseEventEnum.answer && data !== '[DONE]') { - const answer: string = data?.choices?.[0].delta.content || ''; - onMessage(answer); - responseText += answer; - } else if (item.event === sseResponseEventEnum.error) { - errMsg = getErrText(data, '流响应错误'); - } - }); - read(); - } catch (err: any) { - if (err?.message === 'The user aborted a request.') { + const read = async () => { + try { + const { done, value } = await reader.read(); + if (done) { + if (response.status === 200 && !errMsg) { return resolve({ responseText, errMsg, - newHistoryId + newHistoryId, + rawSearch + }); + } else { + return reject({ + message: errMsg || '响应过程出现异常~', + responseText }); } - reject(getErrText(err, '请求异常')); } - }; - read(); - } catch (err: any) { - console.log(err); + const chunkResponse = parseStreamChunk(value); - reject(getErrText(err, '请求异常')); - } + chunkResponse.forEach((item) => { + // parse json data + const data = (() => { + try { + return JSON.parse(item.data); + } catch (error) { + return item.data; + } + })(); + + if (item.event === sseResponseEventEnum.answer && data !== '[DONE]') { + const answer: string = data?.choices?.[0].delta.content || ''; + onMessage(answer); + responseText += answer; + } else if (item.event === sseResponseEventEnum.appStreamResponse) { + rawSearch = data?.[rawSearchKey] ? data[rawSearchKey] : rawSearch; + } else if (item.event === sseResponseEventEnum.error) { + errMsg = getErrText(data, '流响应错误'); + } + }); + read(); + } catch (err: any) { + if (err?.message === 'The user aborted a request.') { + return resolve({ + responseText, + errMsg, + newHistoryId, + rawSearch + }); + } + reject(getErrText(err, '请求异常')); + } + }; + read(); + } catch (err: any) { + console.log(err); + + reject(getErrText(err, '请求异常')); } - ); + }); diff --git a/client/src/pages/chat/components/QuoteModal.tsx b/client/src/components/ChatBox/QuoteModal.tsx similarity index 90% rename from client/src/pages/chat/components/QuoteModal.tsx rename to client/src/components/ChatBox/QuoteModal.tsx index 1d22f522a..60492c746 100644 --- a/client/src/pages/chat/components/QuoteModal.tsx +++ b/client/src/components/ChatBox/QuoteModal.tsx @@ -17,20 +17,24 @@ import { useQuery } from '@tanstack/react-query'; import { getHistoryQuote, updateHistoryQuote } from '@/api/chat'; import { useToast } from '@/hooks/useToast'; import { getErrText } from '@/utils/tools'; +import { QuoteItemType } from '@/pages/api/openapi/modules/kb/search'; const QuoteModal = ({ historyId, contentId, + rawSearch = [], onClose }: { - historyId: string; - contentId: string; + historyId?: string; + contentId?: string; + rawSearch?: QuoteItemType[]; onClose: () => void; }) => { const theme = useTheme(); const { toast } = useToast(); const { setIsLoading, Loading } = useLoading(); const [editDataItem, setEditDataItem] = useState<{ + kbId: string; dataId: string; a: string; q: string; @@ -40,13 +44,22 @@ const QuoteModal = ({ data: quote = [], refetch, isLoading - } = useQuery(['getHistoryQuote'], () => getHistoryQuote({ historyId, contentId })); + } = useQuery(['getHistoryQuote'], () => { + if (historyId && contentId) { + return getHistoryQuote({ historyId, contentId }); + } + if (rawSearch.length > 0) { + return rawSearch; + } + return []; + }); /** * update kbData, update mongo status and reload quotes */ const updateQuoteStatus = useCallback( async (quoteId: string, sourceText: string) => { + if (!historyId || !contentId) return; setIsLoading(true); try { await updateHistoryQuote({ @@ -83,6 +96,7 @@ const QuoteModal = ({ } setEditDataItem({ + kbId: data.kb_id, dataId: data.id, q: data.q, a: data.a @@ -166,7 +180,7 @@ const QuoteModal = ({ onClose={() => setEditDataItem(undefined)} onSuccess={() => updateQuoteStatus(editDataItem.dataId, '手动修改')} onDelete={() => updateQuoteStatus(editDataItem.dataId, '已删除')} - kbId="" + kbId={editDataItem.kbId} defaultValues={editDataItem} /> )} diff --git a/client/src/components/ChatBox/index.tsx b/client/src/components/ChatBox/index.tsx index 03c45eb8a..5f8892190 100644 --- a/client/src/components/ChatBox/index.tsx +++ b/client/src/components/ChatBox/index.tsx @@ -15,7 +15,7 @@ import { Box, Card, Flex, Input, Textarea, Button, useTheme } from '@chakra-ui/r import { useUserStore } from '@/store/user'; import { Types } from 'mongoose'; -import { HUMAN_ICON } from '@/constants/chat'; +import { HUMAN_ICON, quoteLenKey, rawSearchKey } from '@/constants/chat'; import Markdown from '@/components/Markdown'; import MyIcon from '@/components/Icon'; import Avatar from '@/components/Avatar'; @@ -26,10 +26,15 @@ import { VariableInputEnum } from '@/constants/app'; import { useForm } from 'react-hook-form'; import MySelect from '@/components/Select'; import { MessageItemType } from '@/pages/api/openapi/v1/chat/completions'; -import styles from './index.module.scss'; import MyTooltip from '../MyTooltip'; import { fileDownload } from '@/utils/file'; import { htmlTemplate } from '@/constants/common'; +import dynamic from 'next/dynamic'; + +const QuoteModal = dynamic(() => import('./QuoteModal')); + +import styles from './index.module.scss'; +import { QuoteItemType } from '@/pages/api/openapi/modules/kb/search'; const textareaMinH = '22px'; export type StartChatFnProps = { @@ -65,6 +70,7 @@ const VariableLabel = ({ const ChatBox = ( { + historyId, appAvatar, variableModules, welcomeText, @@ -72,11 +78,14 @@ const ChatBox = ( onStartChat, onDelMessage }: { + historyId?: string; appAvatar: string; variableModules?: VariableItemType[]; welcomeText?: string; onUpdateVariable?: (e: Record) => void; - onStartChat: (e: StartChatFnProps) => Promise<{ responseText: string }>; + onStartChat: ( + e: StartChatFnProps + ) => Promise<{ responseText?: string; rawSearch?: QuoteItemType[] }>; onDelMessage?: (e: { contentId?: string; index: number }) => void; }, ref: ForwardedRef @@ -92,6 +101,10 @@ const ChatBox = ( const [refresh, setRefresh] = useState(false); const [variables, setVariables] = useState>({}); const [chatHistory, setChatHistory] = useState([]); + const [quoteModalData, setQuoteModalData] = useState<{ + contentId?: string; + rawSearch?: QuoteItemType[]; + }>(); const isChatting = useMemo( () => chatHistory[chatHistory.length - 1]?.status === 'loading', @@ -235,13 +248,25 @@ const ChatBox = ( const messages = adaptChatItem_openAI({ messages: newChatList, reserveId: true }); - await onStartChat({ + const { rawSearch } = await onStartChat({ messages, controller: abortSignal, generatingMessage, variables: data }); + // set finish status + setChatHistory((state) => + state.map((item, index) => { + if (index !== state.length - 1) return item; + return { + ...item, + status: 'finish', + rawSearch + }; + }) + ); + setTimeout(() => { generatingScroll(); TextareaDom.current?.focus(); @@ -258,18 +283,18 @@ const ChatBox = ( resetInputVal(value); setChatHistory(newChatList.slice(0, newChatList.length - 2)); } - } - // set finish status - setChatHistory((state) => - state.map((item, index) => { - if (index !== state.length - 1) return item; - return { - ...item, - status: 'finish' - }; - }) - ); + // set finish status + setChatHistory((state) => + state.map((item, index) => { + if (index !== state.length - 1) return item; + return { + ...item, + status: 'finish' + }; + }) + ); + } }, [ isChatting, @@ -439,7 +464,24 @@ const ChatBox = ( source={item.value} isChatting={index === chatHistory.length - 1 && isChatting} /> + {(item[quoteLenKey] || item[rawSearchKey]?.length) && ( + + )} + ) : null} + {/* quote modal */} + {!!quoteModalData && ( + setQuoteModalData(undefined)} + /> + )} + {/* quote modal */} ); }; diff --git a/client/src/constants/app.ts b/client/src/constants/app.ts index 4dfd24249..044c440e1 100644 --- a/client/src/constants/app.ts +++ b/client/src/constants/app.ts @@ -1,4 +1,5 @@ import type { AppItemType } from '@/types/app'; +import { rawSearchKey } from './chat'; /* app */ export enum AppModuleItemTypeEnum { @@ -530,7 +531,7 @@ export const appTemplates: (AppItemType & { avatar: string; intro: string })[] = ], outputs: [ { - key: 'rawSearch', + key: rawSearchKey, label: '源搜索数据', type: 'hidden', response: true, @@ -1165,7 +1166,7 @@ export const appTemplates: (AppItemType & { avatar: string; intro: string })[] = ], outputs: [ { - key: 'rawSearch', + key: rawSearchKey, label: '源搜索数据', type: 'hidden', response: true, diff --git a/client/src/constants/chat.ts b/client/src/constants/chat.ts index f1bc61234..08eb057e0 100644 --- a/client/src/constants/chat.ts +++ b/client/src/constants/chat.ts @@ -24,5 +24,8 @@ export const ChatRoleMap = { } }; +export const rawSearchKey = 'rawSearch'; +export const quoteLenKey = 'quoteLen'; + export const HUMAN_ICON = `https://fastgpt.run/icon/human.png`; export const LOGO_ICON = `https://fastgpt.run/icon/logo.png`; diff --git a/client/src/constants/flow/ModuleTemplate.ts b/client/src/constants/flow/ModuleTemplate.ts index 02897bb98..010e91cd6 100644 --- a/client/src/constants/flow/ModuleTemplate.ts +++ b/client/src/constants/flow/ModuleTemplate.ts @@ -7,6 +7,7 @@ import { Input_Template_TFSwitch, Input_Template_UserChatInput } from './inputTemplate'; +import { rawSearchKey } from '../chat'; export const VariableInputModule: AppModuleTemplateItemType = { logo: '/imgs/module/userGuide.png', @@ -215,7 +216,7 @@ export const KBSearchModule: AppModuleTemplateItemType = { ], outputs: [ { - key: 'rawSearch', + key: rawSearchKey, label: '源搜索数据', type: FlowOutputItemTypeEnum.hidden, response: true, diff --git a/client/src/pages/api/chat/history/getHistoryQuote.ts b/client/src/pages/api/chat/history/getHistoryQuote.ts index 1c7258a49..34b37f26e 100644 --- a/client/src/pages/api/chat/history/getHistoryQuote.ts +++ b/client/src/pages/api/chat/history/getHistoryQuote.ts @@ -3,6 +3,7 @@ import { jsonRes } from '@/service/response'; import { connectToDatabase, Chat } from '@/service/mongo'; import { authUser } from '@/service/utils/auth'; import { Types } from 'mongoose'; +import { rawSearchKey } from '@/constants/chat'; export default async function handler(req: NextApiRequest, res: NextApiResponse) { try { @@ -35,13 +36,13 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) }, { $project: { - quote: '$content.quote' + [rawSearchKey]: `$content.${rawSearchKey}` } } ]); jsonRes(res, { - data: history[0]?.quote || [] + data: history[0]?.[rawSearchKey] || [] }); } catch (err) { jsonRes(res, { diff --git a/client/src/pages/api/chat/history/updateHistoryQuote.ts b/client/src/pages/api/chat/history/updateHistoryQuote.ts index 431d8e765..a8580e91d 100644 --- a/client/src/pages/api/chat/history/updateHistoryQuote.ts +++ b/client/src/pages/api/chat/history/updateHistoryQuote.ts @@ -11,7 +11,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) contentId, quoteId, sourceText = '' - } = req.query as { + } = req.body as { historyId: string; contentId: string; quoteId: string; @@ -33,7 +33,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) }, { $set: { - 'content.$.quote.$[quoteElem].source': sourceText + 'content.$.rawSearch.$[quoteElem].source': sourceText } }, { diff --git a/client/src/pages/api/chat/init.ts b/client/src/pages/api/chat/init.ts index 031cb398e..35014775f 100644 --- a/client/src/pages/api/chat/init.ts +++ b/client/src/pages/api/chat/init.ts @@ -9,6 +9,7 @@ import mongoose from 'mongoose'; import type { AppSchema, ChatSchema } from '@/types/mongoSchema'; import { FlowModuleTypeEnum } from '@/constants/flow'; import { SystemInputEnum } from '@/constants/app'; +import { quoteLenKey, rawSearchKey } from '@/constants/chat'; /* 初始化我的聊天框,需要身份验证 */ export default async function handler(req: NextApiRequest, res: NextApiResponse) { @@ -82,8 +83,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) _id: '$content._id', obj: '$content.obj', value: '$content.value', - systemPrompt: '$content.systemPrompt', - quoteLen: { $size: { $ifNull: ['$content.quote', []] } } + [quoteLenKey]: { $size: { $ifNull: [`$content.${rawSearchKey}`, []] } } } } ]); diff --git a/client/src/pages/api/openapi/modules/chat/gpt.ts b/client/src/pages/api/openapi/modules/chat/gpt.ts index 7bdc49a8d..bb7ca2e39 100644 --- a/client/src/pages/api/openapi/modules/chat/gpt.ts +++ b/client/src/pages/api/openapi/modules/chat/gpt.ts @@ -128,7 +128,6 @@ export async function chatCompletion({ const adaptMessages = adaptChatItem_openAI({ messages: filterMessages, reserveId: false }); const chatAPI = getOpenAIApi(); - console.log(adaptMessages); /* count response max token */ const promptsToken = modelToolMap.countTokens({ diff --git a/client/src/pages/api/openapi/modules/kb/search.ts b/client/src/pages/api/openapi/modules/kb/search.ts index 64a5809f0..fd561af84 100644 --- a/client/src/pages/api/openapi/modules/kb/search.ts +++ b/client/src/pages/api/openapi/modules/kb/search.ts @@ -3,13 +3,14 @@ import { jsonRes } from '@/service/response'; import { PgClient } from '@/service/pg'; import { withNextCors } from '@/service/utils/tools'; import type { ChatItemType } from '@/types/chat'; -import { ChatRoleEnum } from '@/constants/chat'; +import { ChatRoleEnum, rawSearchKey } from '@/constants/chat'; import { modelToolMap } from '@/utils/plugin'; import { getVector } from '../../plugin/vector'; import { countModelPrice, pushTaskBillListItem } from '@/service/events/pushBill'; import { getModel } from '@/service/utils/data'; export type QuoteItemType = { + kb_id: string; id: string; q: string; a: string; @@ -26,7 +27,7 @@ type Props = { billId?: string; }; type Response = { - rawSearch: QuoteItemType[]; + [rawSearchKey]: QuoteItemType[]; isEmpty?: boolean; quotePrompt?: string; }; @@ -85,7 +86,7 @@ export async function kbSearch({ PgClient.query( `BEGIN; SET LOCAL ivfflat.probes = ${global.systemEnv.pgIvfflatProbe || 10}; - select id,q,a,source from modelData where kb_id IN (${kb_ids + select kb_id,id,q,a,source from modelData where kb_id IN (${kb_ids .map((item) => `'${item}'`) .join(',')}) AND vector <#> '[${vectors[0]}]' < -${similarity} order by vector <#> '[${ vectors[0] diff --git a/client/src/pages/api/openapi/text/gptMessagesSlice.ts b/client/src/pages/api/openapi/text/gptMessagesSlice.ts index 221fba7f8..7498d4bc6 100644 --- a/client/src/pages/api/openapi/text/gptMessagesSlice.ts +++ b/client/src/pages/api/openapi/text/gptMessagesSlice.ts @@ -42,11 +42,11 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) export function gpt_chatItemTokenSlice({ messages, - model, + model = 'gpt-3.5-turbo', maxToken }: { messages: ChatItemType[]; - model: ModelType; + model?: ModelType; maxToken: number; }) { let result: ChatItemType[] = []; diff --git a/client/src/pages/api/openapi/v1/chat/completions.ts b/client/src/pages/api/openapi/v1/chat/completions.ts index f3b22f10c..daec3aa84 100644 --- a/client/src/pages/api/openapi/v1/chat/completions.ts +++ b/client/src/pages/api/openapi/v1/chat/completions.ts @@ -94,6 +94,8 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex getChatHistory({ historyId, userId }) ]); + const isOwner = !shareId && userId === String(app.userId); + const prompts = history.concat(gptMessage2ChatType(messages)); if (prompts[prompts.length - 1].obj === 'AI') { prompts.pop(); @@ -143,24 +145,30 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex _id: messages[messages.length - 1]._id, obj: ChatRoleEnum.AI, value: answerText, - responseData + ...responseData } ], userId }); } + console.log(`finish time: ${(Date.now() - startTime) / 100}s`); + if (stream) { sseResponse({ res, event: sseResponseEventEnum.answer, data: '[DONE]' }); - sseResponse({ - res, - event: sseResponseEventEnum.appStreamResponse, - data: JSON.stringify(responseData) - }); + + if (isOwner) { + sseResponse({ + res, + event: sseResponseEventEnum.appStreamResponse, + data: JSON.stringify(responseData) + }); + } + res.end(); } else { res.json({ @@ -189,7 +197,6 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex delTaskBill(billId); if (stream) { - res.status(500); sseErrRes(res, err); res.end(); } else { diff --git a/client/src/pages/api/plugins/kb/data/getDataById.ts b/client/src/pages/api/plugins/kb/data/getDataById.ts index a38c026a9..f7ee9db9e 100644 --- a/client/src/pages/api/plugins/kb/data/getDataById.ts +++ b/client/src/pages/api/plugins/kb/data/getDataById.ts @@ -29,7 +29,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse< const where: any = [['user_id', userId], 'AND', ['id', dataId]]; const searchRes = await PgClient.select('modelData', { - fields: ['id', 'q', 'a', 'source'], + fields: ['kb_id', 'id', 'q', 'a', 'source'], where, limit: 1 }); diff --git a/client/src/pages/app/detail/components/edit/components/ChatTest.tsx b/client/src/pages/app/detail/components/edit/components/ChatTest.tsx index 656729213..d491e068b 100644 --- a/client/src/pages/app/detail/components/edit/components/ChatTest.tsx +++ b/client/src/pages/app/detail/components/edit/components/ChatTest.tsx @@ -63,7 +63,7 @@ const ChatTest = ( const history = messages.slice(-historyMaxLen - 2, -2); // 流请求,获取数据 - const { responseText, errMsg } = await streamFetch({ + const { responseText, rawSearch } = await streamFetch({ url: '/api/chat/chatTest', data: { history, @@ -77,14 +77,7 @@ const ChatTest = ( abortSignal: controller }); - if (errMsg) { - return Promise.reject({ - message: errMsg, - responseText - }); - } - - return { responseText }; + return { responseText, rawSearch }; }, [app._id, app.name, modules] ); diff --git a/client/src/pages/chat/index.tsx b/client/src/pages/chat/index.tsx index d26dd3403..3a3dbd112 100644 --- a/client/src/pages/chat/index.tsx +++ b/client/src/pages/chat/index.tsx @@ -1,28 +1,18 @@ -import React, { useCallback, useState, useRef } from 'react'; +import React, { useCallback, useRef } from 'react'; import { useRouter } from 'next/router'; import { getInitChatSiteInfo, delChatRecordByIndex, putChatHistory } from '@/api/chat'; import { Box, Flex, - useColorModeValue, - Modal, - ModalOverlay, - ModalContent, - ModalBody, - ModalCloseButton, - ModalHeader, useDisclosure, Drawer, DrawerOverlay, DrawerContent, useTheme } from '@chakra-ui/react'; -import { useToast } from '@/hooks/useToast'; import { useGlobalStore } from '@/store/global'; import { useQuery } from '@tanstack/react-query'; -import dynamic from 'next/dynamic'; import { streamFetch } from '@/api/fetch'; -import MyIcon from '@/components/Icon'; import { useChatStore } from '@/store/chat'; import { useLoading } from '@/hooks/useLoading'; @@ -32,8 +22,6 @@ import PageContainer from '@/components/PageContainer'; import SideBar from '@/components/SideBar'; import ChatHistorySlider from './components/ChatHistorySlider'; import SliderApps from './components/SliderApps'; -import Tag from '@/components/Tag'; -import ToolMenu from './components/ToolMenu'; import ChatHeader from './components/ChatHeader'; const Chat = () => { @@ -44,9 +32,6 @@ const Chat = () => { const ChatBoxRef = useRef(null); const forbidRefresh = useRef(false); - const [showHistoryQuote, setShowHistoryQuote] = useState(); - const [showSystemPrompt, setShowSystemPrompt] = useState(''); - const { lastChatAppId, setLastChatAppId, @@ -67,7 +52,7 @@ const Chat = () => { const startChat = useCallback( async ({ messages, controller, generatingMessage, variables }: StartChatFnProps) => { const prompts = messages.slice(-2); - const { responseText, newHistoryId } = await streamFetch({ + const { responseText, newHistoryId, rawSearch } = await streamFetch({ data: { messages: prompts, variables, @@ -113,7 +98,7 @@ const Chat = () => { history: ChatBoxRef.current?.getChatHistory() || state.history })); - return { responseText }; + return { responseText, rawSearch }; }, [appId, history, historyId, router, setChatData, updateHistory] ); @@ -297,6 +282,7 @@ const Chat = () => { { - - {/* quote modal*/} - {/* {showHistoryQuote && historyId && ( - setShowHistoryQuote(undefined)} - /> - )} */} - {/* system prompt show modal */} - { - setShowSystemPrompt('')}> - - - - 提示词 - - {showSystemPrompt} - - - - } ); }; diff --git a/client/src/pages/chat/share.tsx b/client/src/pages/chat/share.tsx index ab1452f76..14ccb5cf4 100644 --- a/client/src/pages/chat/share.tsx +++ b/client/src/pages/chat/share.tsx @@ -184,7 +184,7 @@ const ShareChat = ({ shareId, historyId }: { shareId: string; historyId: string {/* header */} diff --git a/client/src/service/models/chat.ts b/client/src/service/models/chat.ts index 43dc42b61..60377c89a 100644 --- a/client/src/service/models/chat.ts +++ b/client/src/service/models/chat.ts @@ -44,20 +44,17 @@ const ChatSchema = new Schema({ type: String, default: '' }, - quote: { + rawSearch: { type: [ { id: String, q: String, a: String, + kb_id: String, source: String } ], default: [] - }, - systemPrompt: { - type: String, - default: '' } } ], diff --git a/client/src/types/chat.d.ts b/client/src/types/chat.d.ts index 4902a0968..b6c270c2f 100644 --- a/client/src/types/chat.d.ts +++ b/client/src/types/chat.d.ts @@ -1,4 +1,4 @@ -import { ChatRoleEnum } from '@/constants/chat'; +import { ChatRoleEnum, rawSearchKey } from '@/constants/chat'; import type { InitChatResponse, InitShareChatResponse } from '@/api/response/chat'; import { QuoteItemType } from '@/pages/api/openapi/kb/appKbSearch'; @@ -8,6 +8,8 @@ export type ChatItemType = { _id?: string; obj: `${ChatRoleEnum}`; value: string; + [rawSearchKey]?: QuoteItemType[]; + quoteLen?: number; [key: string]: any; };