mirror of
https://github.com/labring/FastGPT.git
synced 2025-10-19 01:54:04 +00:00
perf: response store
This commit is contained in:
@@ -23,7 +23,7 @@
|
|||||||
"model": "gpt-3.5-turbo",
|
"model": "gpt-3.5-turbo",
|
||||||
"name": "FastAI-4k",
|
"name": "FastAI-4k",
|
||||||
"contextMaxToken": 4000,
|
"contextMaxToken": 4000,
|
||||||
"systemMaxToken": 2400,
|
"quoteMaxToken": 2000,
|
||||||
"maxTemperature": 1.2,
|
"maxTemperature": 1.2,
|
||||||
"price": 1.5
|
"price": 1.5
|
||||||
},
|
},
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
"model": "gpt-3.5-turbo-16k",
|
"model": "gpt-3.5-turbo-16k",
|
||||||
"name": "FastAI-16k",
|
"name": "FastAI-16k",
|
||||||
"contextMaxToken": 16000,
|
"contextMaxToken": 16000,
|
||||||
"systemMaxToken": 8000,
|
"quoteMaxToken": 8000,
|
||||||
"maxTemperature": 1.2,
|
"maxTemperature": 1.2,
|
||||||
"price": 3
|
"price": 3
|
||||||
},
|
},
|
||||||
@@ -39,7 +39,7 @@
|
|||||||
"model": "gpt-4",
|
"model": "gpt-4",
|
||||||
"name": "FastAI-Plus",
|
"name": "FastAI-Plus",
|
||||||
"contextMaxToken": 8000,
|
"contextMaxToken": 8000,
|
||||||
"systemMaxToken": 4000,
|
"quoteMaxToken": 4000,
|
||||||
"maxTemperature": 1.2,
|
"maxTemperature": 1.2,
|
||||||
"price": 45
|
"price": 45
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
import { sseResponseEventEnum } from '@/constants/chat';
|
import { sseResponseEventEnum, TaskResponseKeyEnum } from '@/constants/chat';
|
||||||
import { getErrText } from '@/utils/tools';
|
import { getErrText } from '@/utils/tools';
|
||||||
import { parseStreamChunk } from '@/utils/adapt';
|
import { parseStreamChunk } from '@/utils/adapt';
|
||||||
import { QuoteItemType } from '@/types/chat';
|
import type { ChatHistoryItemResType } from '@/types/chat';
|
||||||
|
|
||||||
interface StreamFetchProps {
|
interface StreamFetchProps {
|
||||||
url?: string;
|
url?: string;
|
||||||
@@ -17,8 +17,7 @@ export const streamFetch = ({
|
|||||||
}: StreamFetchProps) =>
|
}: StreamFetchProps) =>
|
||||||
new Promise<{
|
new Promise<{
|
||||||
responseText: string;
|
responseText: string;
|
||||||
errMsg: string;
|
[TaskResponseKeyEnum.responseData]: ChatHistoryItemResType[];
|
||||||
newChatId: string | null;
|
|
||||||
}>(async (resolve, reject) => {
|
}>(async (resolve, reject) => {
|
||||||
try {
|
try {
|
||||||
const response = await window.fetch(url, {
|
const response = await window.fetch(url, {
|
||||||
@@ -42,7 +41,7 @@ export const streamFetch = ({
|
|||||||
// response data
|
// response data
|
||||||
let responseText = '';
|
let responseText = '';
|
||||||
let errMsg = '';
|
let errMsg = '';
|
||||||
const newChatId = response.headers.get('newChatId');
|
let responseData: ChatHistoryItemResType[] = [];
|
||||||
|
|
||||||
const read = async () => {
|
const read = async () => {
|
||||||
try {
|
try {
|
||||||
@@ -51,8 +50,7 @@ export const streamFetch = ({
|
|||||||
if (response.status === 200 && !errMsg) {
|
if (response.status === 200 && !errMsg) {
|
||||||
return resolve({
|
return resolve({
|
||||||
responseText,
|
responseText,
|
||||||
errMsg,
|
responseData
|
||||||
newChatId
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
return reject({
|
return reject({
|
||||||
@@ -78,7 +76,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);
|
responseData = data;
|
||||||
} else if (item.event === sseResponseEventEnum.error) {
|
} else if (item.event === sseResponseEventEnum.error) {
|
||||||
errMsg = getErrText(data, '流响应错误');
|
errMsg = getErrText(data, '流响应错误');
|
||||||
}
|
}
|
||||||
@@ -88,8 +86,7 @@ export const streamFetch = ({
|
|||||||
if (err?.message === 'The user aborted a request.') {
|
if (err?.message === 'The user aborted a request.') {
|
||||||
return resolve({
|
return resolve({
|
||||||
responseText,
|
responseText,
|
||||||
errMsg,
|
responseData
|
||||||
newChatId
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
reject(getErrText(err, '请求异常'));
|
reject(getErrText(err, '请求异常'));
|
||||||
|
7
client/src/components/ChatBox/ResponseDetailModal.tsx
Normal file
7
client/src/components/ChatBox/ResponseDetailModal.tsx
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
const ResponseDetailModal = () => {
|
||||||
|
return <div>ResponseDetailModal</div>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ResponseDetailModal;
|
@@ -9,7 +9,12 @@ import React, {
|
|||||||
useEffect
|
useEffect
|
||||||
} from 'react';
|
} from 'react';
|
||||||
import { throttle } from 'lodash';
|
import { throttle } from 'lodash';
|
||||||
import { ChatItemType, ChatSiteItemType, ExportChatType } from '@/types/chat';
|
import {
|
||||||
|
ChatHistoryItemResType,
|
||||||
|
ChatItemType,
|
||||||
|
ChatSiteItemType,
|
||||||
|
ExportChatType
|
||||||
|
} from '@/types/chat';
|
||||||
import { useToast } from '@/hooks/useToast';
|
import { useToast } from '@/hooks/useToast';
|
||||||
import {
|
import {
|
||||||
useCopyData,
|
useCopyData,
|
||||||
@@ -35,6 +40,7 @@ import { useRouter } from 'next/router';
|
|||||||
import { useGlobalStore } from '@/store/global';
|
import { useGlobalStore } from '@/store/global';
|
||||||
import { QuoteItemType } from '@/types/chat';
|
import { QuoteItemType } from '@/types/chat';
|
||||||
import { FlowModuleTypeEnum } from '@/constants/flow';
|
import { FlowModuleTypeEnum } from '@/constants/flow';
|
||||||
|
import { TaskResponseKeyEnum } from '@/constants/chat';
|
||||||
|
|
||||||
import dynamic from 'next/dynamic';
|
import dynamic from 'next/dynamic';
|
||||||
const QuoteModal = dynamic(() => import('./QuoteModal'));
|
const QuoteModal = dynamic(() => import('./QuoteModal'));
|
||||||
@@ -131,9 +137,10 @@ const ChatBox = (
|
|||||||
variableModules?: VariableItemType[];
|
variableModules?: VariableItemType[];
|
||||||
welcomeText?: string;
|
welcomeText?: string;
|
||||||
onUpdateVariable?: (e: Record<string, any>) => void;
|
onUpdateVariable?: (e: Record<string, any>) => void;
|
||||||
onStartChat: (
|
onStartChat: (e: StartChatFnProps) => Promise<{
|
||||||
e: StartChatFnProps
|
responseText: string;
|
||||||
) => Promise<{ responseText?: string; rawSearch?: QuoteItemType[] }>;
|
[TaskResponseKeyEnum.responseData]: ChatHistoryItemResType[];
|
||||||
|
}>;
|
||||||
onDelMessage?: (e: { contentId?: string; index: number }) => void;
|
onDelMessage?: (e: { contentId?: string; index: number }) => void;
|
||||||
},
|
},
|
||||||
ref: ForwardedRef<ComponentRef>
|
ref: ForwardedRef<ComponentRef>
|
||||||
@@ -294,7 +301,7 @@ const ChatBox = (
|
|||||||
|
|
||||||
const messages = adaptChatItem_openAI({ messages: newChatList, reserveId: true });
|
const messages = adaptChatItem_openAI({ messages: newChatList, reserveId: true });
|
||||||
|
|
||||||
const { rawSearch } = await onStartChat({
|
const { responseData } = await onStartChat({
|
||||||
messages,
|
messages,
|
||||||
controller: abortSignal,
|
controller: abortSignal,
|
||||||
generatingMessage,
|
generatingMessage,
|
||||||
@@ -308,7 +315,7 @@ const ChatBox = (
|
|||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
status: 'finish',
|
status: 'finish',
|
||||||
rawSearch
|
responseData
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
@@ -51,5 +51,11 @@ export const ChatSourceMap = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export enum ChatModuleEnum {
|
||||||
|
'AIChat' = 'AI Chat',
|
||||||
|
'KBSearch' = 'KB Search',
|
||||||
|
'CQ' = 'Classify Question'
|
||||||
|
}
|
||||||
|
|
||||||
export const HUMAN_ICON = `https://fastgpt.run/icon/human.png`;
|
export const HUMAN_ICON = `https://fastgpt.run/icon/human.png`;
|
||||||
export const LOGO_ICON = `https://fastgpt.run/icon/logo.png`;
|
export const LOGO_ICON = `https://fastgpt.run/icon/logo.png`;
|
||||||
|
@@ -25,7 +25,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||||||
// 删除一条数据库记录
|
// 删除一条数据库记录
|
||||||
await Chat.updateOne(
|
await Chat.updateOne(
|
||||||
{
|
{
|
||||||
_id: chatId,
|
chatId,
|
||||||
userId
|
userId
|
||||||
},
|
},
|
||||||
{ $pull: { content: { _id: contentId } } }
|
{ $pull: { content: { _id: contentId } } }
|
||||||
|
@@ -8,6 +8,7 @@ import { authApp } from '@/service/utils/auth';
|
|||||||
import mongoose from 'mongoose';
|
import mongoose from 'mongoose';
|
||||||
import type { ChatSchema } from '@/types/mongoSchema';
|
import type { ChatSchema } from '@/types/mongoSchema';
|
||||||
import { getSpecialModule } from '@/components/ChatBox';
|
import { getSpecialModule } from '@/components/ChatBox';
|
||||||
|
import { TaskResponseKeyEnum } from '@/constants/chat';
|
||||||
|
|
||||||
/* 初始化我的聊天框,需要身份验证 */
|
/* 初始化我的聊天框,需要身份验证 */
|
||||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||||
@@ -67,7 +68,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||||||
$project: {
|
$project: {
|
||||||
_id: '$content._id',
|
_id: '$content._id',
|
||||||
obj: '$content.obj',
|
obj: '$content.obj',
|
||||||
value: '$content.value'
|
value: '$content.value',
|
||||||
|
[TaskResponseKeyEnum.responseData]: `$content.${TaskResponseKeyEnum.responseData}`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
@@ -46,7 +46,7 @@ export function gpt_chatItemTokenSlice({
|
|||||||
maxToken
|
maxToken
|
||||||
}: {
|
}: {
|
||||||
messages: ChatItemType[];
|
messages: ChatItemType[];
|
||||||
model?: ModelType;
|
model?: string;
|
||||||
maxToken: number;
|
maxToken: number;
|
||||||
}) {
|
}) {
|
||||||
let result: ChatItemType[] = [];
|
let result: ChatItemType[] = [];
|
||||||
|
@@ -68,7 +68,7 @@ export function setDefaultData() {
|
|||||||
model: 'gpt-3.5-turbo',
|
model: 'gpt-3.5-turbo',
|
||||||
name: 'FastAI-4k',
|
name: 'FastAI-4k',
|
||||||
contextMaxToken: 4000,
|
contextMaxToken: 4000,
|
||||||
systemMaxToken: 2400,
|
quoteMaxToken: 2400,
|
||||||
maxTemperature: 1.2,
|
maxTemperature: 1.2,
|
||||||
price: 1.5
|
price: 1.5
|
||||||
},
|
},
|
||||||
@@ -76,7 +76,7 @@ export function setDefaultData() {
|
|||||||
model: 'gpt-3.5-turbo-16k',
|
model: 'gpt-3.5-turbo-16k',
|
||||||
name: 'FastAI-16k',
|
name: 'FastAI-16k',
|
||||||
contextMaxToken: 16000,
|
contextMaxToken: 16000,
|
||||||
systemMaxToken: 8000,
|
quoteMaxToken: 8000,
|
||||||
maxTemperature: 1.2,
|
maxTemperature: 1.2,
|
||||||
price: 3
|
price: 3
|
||||||
},
|
},
|
||||||
@@ -84,7 +84,7 @@ export function setDefaultData() {
|
|||||||
model: 'gpt-4',
|
model: 'gpt-4',
|
||||||
name: 'FastAI-Plus',
|
name: 'FastAI-Plus',
|
||||||
contextMaxToken: 8000,
|
contextMaxToken: 8000,
|
||||||
systemMaxToken: 4000,
|
quoteMaxToken: 4000,
|
||||||
maxTemperature: 1.2,
|
maxTemperature: 1.2,
|
||||||
price: 45
|
price: 45
|
||||||
}
|
}
|
||||||
|
@@ -454,7 +454,7 @@ const ChatTest = ({ appId }: { appId: string }) => {
|
|||||||
const history = messages.slice(-historyMaxLen - 2, -2);
|
const history = messages.slice(-historyMaxLen - 2, -2);
|
||||||
|
|
||||||
// 流请求,获取数据
|
// 流请求,获取数据
|
||||||
const { responseText } = await streamFetch({
|
const { responseText, responseData } = await streamFetch({
|
||||||
url: '/api/chat/chatTest',
|
url: '/api/chat/chatTest',
|
||||||
data: {
|
data: {
|
||||||
history,
|
history,
|
||||||
@@ -468,7 +468,7 @@ const ChatTest = ({ appId }: { appId: string }) => {
|
|||||||
abortSignal: controller
|
abortSignal: controller
|
||||||
});
|
});
|
||||||
|
|
||||||
return { responseText };
|
return { responseText, responseData };
|
||||||
},
|
},
|
||||||
[modules, appId, appDetail.name]
|
[modules, appId, appDetail.name]
|
||||||
);
|
);
|
||||||
|
@@ -49,7 +49,7 @@ const ChatTest = (
|
|||||||
const history = messages.slice(-historyMaxLen - 2, -2);
|
const history = messages.slice(-historyMaxLen - 2, -2);
|
||||||
|
|
||||||
// 流请求,获取数据
|
// 流请求,获取数据
|
||||||
const { responseText } = await streamFetch({
|
const { responseText, responseData } = await streamFetch({
|
||||||
url: '/api/chat/chatTest',
|
url: '/api/chat/chatTest',
|
||||||
data: {
|
data: {
|
||||||
history,
|
history,
|
||||||
@@ -63,7 +63,7 @@ const ChatTest = (
|
|||||||
abortSignal: controller
|
abortSignal: controller
|
||||||
});
|
});
|
||||||
|
|
||||||
return { responseText };
|
return { responseText, responseData };
|
||||||
},
|
},
|
||||||
[app._id, app.name, modules]
|
[app._id, app.name, modules]
|
||||||
);
|
);
|
||||||
|
@@ -60,7 +60,7 @@ const Chat = ({ appId, chatId }: { appId: string; chatId: string }) => {
|
|||||||
const prompts = messages.slice(-2);
|
const prompts = messages.slice(-2);
|
||||||
const completionChatId = chatId ? chatId : nanoid();
|
const completionChatId = chatId ? chatId : nanoid();
|
||||||
|
|
||||||
const { responseText } = await streamFetch({
|
const { responseText, responseData } = await streamFetch({
|
||||||
data: {
|
data: {
|
||||||
messages: prompts,
|
messages: prompts,
|
||||||
variables,
|
variables,
|
||||||
@@ -106,7 +106,7 @@ const Chat = ({ appId, chatId }: { appId: string; chatId: string }) => {
|
|||||||
history: ChatBoxRef.current?.getChatHistory() || state.history
|
history: ChatBoxRef.current?.getChatHistory() || state.history
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return { responseText };
|
return { responseText, responseData };
|
||||||
},
|
},
|
||||||
[appId, chatId, history, router, setChatData, updateHistory]
|
[appId, chatId, history, router, setChatData, updateHistory]
|
||||||
);
|
);
|
||||||
|
@@ -46,7 +46,7 @@ const ShareChat = ({ shareId, chatId }: { shareId: string; chatId: string }) =>
|
|||||||
const prompts = messages.slice(-2);
|
const prompts = messages.slice(-2);
|
||||||
const completionChatId = chatId ? chatId : nanoid();
|
const completionChatId = chatId ? chatId : nanoid();
|
||||||
|
|
||||||
const { responseText } = await streamFetch({
|
const { responseText, responseData } = await streamFetch({
|
||||||
data: {
|
data: {
|
||||||
messages: prompts,
|
messages: prompts,
|
||||||
variables,
|
variables,
|
||||||
@@ -91,7 +91,7 @@ const ShareChat = ({ shareId, chatId }: { shareId: string; chatId: string }) =>
|
|||||||
'*'
|
'*'
|
||||||
);
|
);
|
||||||
|
|
||||||
return { responseText };
|
return { responseText, responseData };
|
||||||
},
|
},
|
||||||
[chatId, router, saveChatResponse, shareId]
|
[chatId, router, saveChatResponse, shareId]
|
||||||
);
|
);
|
||||||
|
@@ -68,7 +68,8 @@ const ChatSchema = new Schema({
|
|||||||
answer: String,
|
answer: String,
|
||||||
temperature: Number,
|
temperature: Number,
|
||||||
maxToken: Number,
|
maxToken: Number,
|
||||||
finishMessages: Array,
|
quoteList: Array,
|
||||||
|
completeMessages: Array,
|
||||||
similarity: Number,
|
similarity: Number,
|
||||||
limit: Number,
|
limit: Number,
|
||||||
cqList: Array,
|
cqList: Array,
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
import { adaptChatItem_openAI } from '@/utils/plugin/openai';
|
import { adaptChatItem_openAI } from '@/utils/plugin/openai';
|
||||||
import { ChatContextFilter } from '@/service/utils/chat/index';
|
import { ChatContextFilter } from '@/service/utils/chat/index';
|
||||||
import type { ChatHistoryItemResType, ChatItemType } from '@/types/chat';
|
import type { ChatHistoryItemResType, ChatItemType } from '@/types/chat';
|
||||||
import { ChatRoleEnum, TaskResponseKeyEnum } from '@/constants/chat';
|
import { ChatModuleEnum, ChatRoleEnum, TaskResponseKeyEnum } from '@/constants/chat';
|
||||||
import { getOpenAIApi, axiosConfig } from '@/service/ai/openai';
|
import { getOpenAIApi, axiosConfig } from '@/service/ai/openai';
|
||||||
import type { ClassifyQuestionAgentItemType } from '@/types/app';
|
import type { ClassifyQuestionAgentItemType } from '@/types/app';
|
||||||
import { countModelPrice } from '@/service/events/pushBill';
|
import { countModelPrice } from '@/service/events/pushBill';
|
||||||
@@ -17,7 +17,6 @@ export type CQResponse = {
|
|||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
};
|
};
|
||||||
|
|
||||||
const moduleName = 'Classify Question';
|
|
||||||
const agentModel = 'gpt-3.5-turbo';
|
const agentModel = 'gpt-3.5-turbo';
|
||||||
const agentFunName = 'agent_user_question';
|
const agentFunName = 'agent_user_question';
|
||||||
const maxTokens = 2000;
|
const maxTokens = 2000;
|
||||||
@@ -88,7 +87,7 @@ export const dispatchClassifyQuestion = async (props: Record<string, any>): Prom
|
|||||||
return {
|
return {
|
||||||
[result.key]: 1,
|
[result.key]: 1,
|
||||||
[TaskResponseKeyEnum.responseData]: {
|
[TaskResponseKeyEnum.responseData]: {
|
||||||
moduleName,
|
moduleName: ChatModuleEnum.CQ,
|
||||||
price: countModelPrice({ model: agentModel, tokens }),
|
price: countModelPrice({ model: agentModel, tokens }),
|
||||||
model: agentModel,
|
model: agentModel,
|
||||||
tokens,
|
tokens,
|
||||||
|
@@ -6,12 +6,13 @@ import { modelToolMap } from '@/utils/plugin';
|
|||||||
import { ChatContextFilter } from '@/service/utils/chat/index';
|
import { ChatContextFilter } from '@/service/utils/chat/index';
|
||||||
import type { ChatItemType, QuoteItemType } from '@/types/chat';
|
import type { ChatItemType, QuoteItemType } from '@/types/chat';
|
||||||
import type { ChatHistoryItemResType } from '@/types/chat';
|
import type { ChatHistoryItemResType } from '@/types/chat';
|
||||||
import { ChatRoleEnum, sseResponseEventEnum } from '@/constants/chat';
|
import { ChatModuleEnum, ChatRoleEnum, sseResponseEventEnum } from '@/constants/chat';
|
||||||
import { parseStreamChunk, textAdaptGptResponse } from '@/utils/adapt';
|
import { parseStreamChunk, textAdaptGptResponse } from '@/utils/adapt';
|
||||||
import { getOpenAIApi, axiosConfig } from '@/service/ai/openai';
|
import { getOpenAIApi, axiosConfig } from '@/service/ai/openai';
|
||||||
import { TaskResponseKeyEnum } from '@/constants/chat';
|
import { TaskResponseKeyEnum } from '@/constants/chat';
|
||||||
import { getChatModel } from '@/service/utils/data';
|
import { getChatModel } from '@/service/utils/data';
|
||||||
import { countModelPrice } from '@/service/events/pushBill';
|
import { countModelPrice } from '@/service/events/pushBill';
|
||||||
|
import { ChatModelItemType } from '@/types/model';
|
||||||
|
|
||||||
export type ChatProps = {
|
export type ChatProps = {
|
||||||
res: NextApiResponse;
|
res: NextApiResponse;
|
||||||
@@ -30,8 +31,6 @@ export type ChatResponse = {
|
|||||||
[TaskResponseKeyEnum.responseData]: ChatHistoryItemResType;
|
[TaskResponseKeyEnum.responseData]: ChatHistoryItemResType;
|
||||||
};
|
};
|
||||||
|
|
||||||
const moduleName = 'AI Chat';
|
|
||||||
|
|
||||||
/* request openai chat */
|
/* request openai chat */
|
||||||
export const dispatchChatCompletion = async (props: Record<string, any>): Promise<ChatResponse> => {
|
export const dispatchChatCompletion = async (props: Record<string, any>): Promise<ChatResponse> => {
|
||||||
let {
|
let {
|
||||||
@@ -54,24 +53,153 @@ export const dispatchChatCompletion = async (props: Record<string, any>): Promis
|
|||||||
return Promise.reject('The chat model is undefined, you need to select a chat model.');
|
return Promise.reject('The chat model is undefined, you need to select a chat model.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { filterQuoteQA, quotePrompt } = filterQuote({
|
||||||
|
quoteQA,
|
||||||
|
model: modelConstantsData
|
||||||
|
});
|
||||||
|
|
||||||
|
const { messages, filterMessages } = getChatMessages({
|
||||||
|
model: modelConstantsData,
|
||||||
|
history,
|
||||||
|
quotePrompt,
|
||||||
|
userChatInput,
|
||||||
|
systemPrompt,
|
||||||
|
limitPrompt
|
||||||
|
});
|
||||||
|
const { max_tokens } = getMaxTokens({
|
||||||
|
model: modelConstantsData,
|
||||||
|
maxToken,
|
||||||
|
filterMessages
|
||||||
|
});
|
||||||
|
// console.log(messages);
|
||||||
|
|
||||||
// FastGpt temperature range: 1~10
|
// FastGpt temperature range: 1~10
|
||||||
temperature = +(modelConstantsData.maxTemperature * (temperature / 10)).toFixed(2);
|
temperature = +(modelConstantsData.maxTemperature * (temperature / 10)).toFixed(2);
|
||||||
|
const chatAPI = getOpenAIApi();
|
||||||
|
|
||||||
|
const response = await chatAPI.createChatCompletion(
|
||||||
|
{
|
||||||
|
model,
|
||||||
|
temperature: Number(temperature || 0),
|
||||||
|
max_tokens,
|
||||||
|
messages,
|
||||||
|
// frequency_penalty: 0.5, // 越大,重复内容越少
|
||||||
|
// presence_penalty: -0.5, // 越大,越容易出现新内容
|
||||||
|
stream
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timeout: stream ? 60000 : 480000,
|
||||||
|
responseType: stream ? 'stream' : 'json',
|
||||||
|
...axiosConfig()
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const { answerText, totalTokens, completeMessages } = await (async () => {
|
||||||
|
if (stream) {
|
||||||
|
// sse response
|
||||||
|
const { answer } = await streamResponse({ res, response });
|
||||||
|
// count tokens
|
||||||
|
const completeMessages = filterMessages.concat({
|
||||||
|
obj: ChatRoleEnum.AI,
|
||||||
|
value: answer
|
||||||
|
});
|
||||||
|
|
||||||
|
const totalTokens = countOpenAIToken({
|
||||||
|
messages: completeMessages
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
answerText: answer,
|
||||||
|
totalTokens,
|
||||||
|
completeMessages
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
const answer = stream ? '' : response.data.choices?.[0].message?.content || '';
|
||||||
|
const totalTokens = stream ? 0 : response.data.usage?.total_tokens || 0;
|
||||||
|
|
||||||
|
const completeMessages = filterMessages.concat({
|
||||||
|
obj: ChatRoleEnum.AI,
|
||||||
|
value: answer
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
answerText: answer,
|
||||||
|
totalTokens,
|
||||||
|
completeMessages
|
||||||
|
};
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
|
return {
|
||||||
|
[TaskResponseKeyEnum.answerText]: answerText,
|
||||||
|
[TaskResponseKeyEnum.responseData]: {
|
||||||
|
moduleName: ChatModuleEnum.AIChat,
|
||||||
|
price: countModelPrice({ model, tokens: totalTokens }),
|
||||||
|
model: modelConstantsData.name,
|
||||||
|
tokens: totalTokens,
|
||||||
|
question: userChatInput,
|
||||||
|
answer: answerText,
|
||||||
|
maxToken,
|
||||||
|
quoteList: filterQuoteQA,
|
||||||
|
completeMessages
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
function filterQuote({
|
||||||
|
quoteQA = [],
|
||||||
|
model
|
||||||
|
}: {
|
||||||
|
quoteQA: ChatProps['quoteQA'];
|
||||||
|
model: ChatModelItemType;
|
||||||
|
}) {
|
||||||
|
const sliceResult = modelToolMap.tokenSlice({
|
||||||
|
model: model.model,
|
||||||
|
maxToken: model.quoteMaxToken,
|
||||||
|
messages: quoteQA.map((item, i) => ({
|
||||||
|
obj: ChatRoleEnum.System,
|
||||||
|
value: `${i + 1}. [${item.q}\n${item.a}]`
|
||||||
|
}))
|
||||||
|
});
|
||||||
|
|
||||||
|
// slice filterSearch
|
||||||
|
const filterQuoteQA = quoteQA.slice(0, sliceResult.length);
|
||||||
|
|
||||||
|
const quotePrompt =
|
||||||
|
filterQuoteQA.length > 0
|
||||||
|
? `下面是知识库内容:
|
||||||
|
${filterQuoteQA.map((item, i) => `${i + 1}. [${item.q}\n${item.a}]`).join('\n')}
|
||||||
|
`
|
||||||
|
: '';
|
||||||
|
|
||||||
|
return {
|
||||||
|
filterQuoteQA,
|
||||||
|
quotePrompt
|
||||||
|
};
|
||||||
|
}
|
||||||
|
function getChatMessages({
|
||||||
|
quotePrompt,
|
||||||
|
history = [],
|
||||||
|
systemPrompt,
|
||||||
|
limitPrompt,
|
||||||
|
userChatInput,
|
||||||
|
model
|
||||||
|
}: {
|
||||||
|
quotePrompt: string;
|
||||||
|
history: ChatProps['history'];
|
||||||
|
systemPrompt: string;
|
||||||
|
limitPrompt: string;
|
||||||
|
userChatInput: string;
|
||||||
|
model: ChatModelItemType;
|
||||||
|
}) {
|
||||||
const limitText = (() => {
|
const limitText = (() => {
|
||||||
if (limitPrompt) return limitPrompt;
|
if (limitPrompt) return limitPrompt;
|
||||||
if (quoteQA.length > 0 && !limitPrompt) {
|
if (quotePrompt && !limitPrompt) {
|
||||||
return '根据知识库内容回答问题,仅回复知识库提供的内容,不要对知识库内容做补充说明。';
|
return '根据知识库内容回答问题,仅回复知识库提供的内容,不要对知识库内容做补充说明。';
|
||||||
}
|
}
|
||||||
return '';
|
return '';
|
||||||
})();
|
})();
|
||||||
|
|
||||||
const quotePrompt =
|
|
||||||
quoteQA.length > 0
|
|
||||||
? `下面是知识库内容:
|
|
||||||
${quoteQA.map((item, i) => `${i + 1}. [${item.q}\n${item.a}]`).join('\n')}
|
|
||||||
`
|
|
||||||
: '';
|
|
||||||
|
|
||||||
const messages: ChatItemType[] = [
|
const messages: ChatItemType[] = [
|
||||||
...(quotePrompt
|
...(quotePrompt
|
||||||
? [
|
? [
|
||||||
@@ -103,92 +231,41 @@ ${quoteQA.map((item, i) => `${i + 1}. [${item.q}\n${item.a}]`).join('\n')}
|
|||||||
value: userChatInput
|
value: userChatInput
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
const modelTokenLimit = getChatModel(model)?.contextMaxToken || 4000;
|
|
||||||
|
|
||||||
const filterMessages = ChatContextFilter({
|
const filterMessages = ChatContextFilter({
|
||||||
model,
|
model: model.model,
|
||||||
prompts: messages,
|
prompts: messages,
|
||||||
maxTokens: Math.ceil(modelTokenLimit - 300) // filter token. not response maxToken
|
maxTokens: Math.ceil(model.contextMaxToken - 300) // filter token. not response maxToken
|
||||||
});
|
});
|
||||||
|
|
||||||
const adaptMessages = adaptChatItem_openAI({ messages: filterMessages, reserveId: false });
|
const adaptMessages = adaptChatItem_openAI({ messages: filterMessages, reserveId: false });
|
||||||
const chatAPI = getOpenAIApi();
|
|
||||||
console.log(adaptMessages);
|
|
||||||
|
|
||||||
/* count response max token */
|
|
||||||
const promptsToken = modelToolMap.countTokens({
|
|
||||||
model,
|
|
||||||
messages: filterMessages
|
|
||||||
});
|
|
||||||
maxToken = maxToken + promptsToken > modelTokenLimit ? modelTokenLimit - promptsToken : maxToken;
|
|
||||||
|
|
||||||
const response = await chatAPI.createChatCompletion(
|
|
||||||
{
|
|
||||||
model,
|
|
||||||
temperature: Number(temperature || 0),
|
|
||||||
max_tokens: maxToken,
|
|
||||||
messages: adaptMessages,
|
|
||||||
// frequency_penalty: 0.5, // 越大,重复内容越少
|
|
||||||
// presence_penalty: -0.5, // 越大,越容易出现新内容
|
|
||||||
stream
|
|
||||||
},
|
|
||||||
{
|
|
||||||
timeout: stream ? 60000 : 480000,
|
|
||||||
responseType: stream ? 'stream' : 'json',
|
|
||||||
...axiosConfig()
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const { answerText, totalTokens, finishMessages } = await (async () => {
|
|
||||||
if (stream) {
|
|
||||||
// sse response
|
|
||||||
const { answer } = await streamResponse({ res, response });
|
|
||||||
// count tokens
|
|
||||||
const finishMessages = filterMessages.concat({
|
|
||||||
obj: ChatRoleEnum.AI,
|
|
||||||
value: answer
|
|
||||||
});
|
|
||||||
|
|
||||||
const totalTokens = countOpenAIToken({
|
|
||||||
messages: finishMessages
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
answerText: answer,
|
|
||||||
totalTokens,
|
|
||||||
finishMessages
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
const answer = stream ? '' : response.data.choices?.[0].message?.content || '';
|
|
||||||
const totalTokens = stream ? 0 : response.data.usage?.total_tokens || 0;
|
|
||||||
|
|
||||||
const finishMessages = filterMessages.concat({
|
|
||||||
obj: ChatRoleEnum.AI,
|
|
||||||
value: answer
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
answerText: answer,
|
|
||||||
totalTokens,
|
|
||||||
finishMessages
|
|
||||||
};
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
[TaskResponseKeyEnum.answerText]: answerText,
|
messages: adaptMessages,
|
||||||
[TaskResponseKeyEnum.responseData]: {
|
filterMessages
|
||||||
moduleName,
|
|
||||||
price: countModelPrice({ model, tokens: totalTokens }),
|
|
||||||
model: modelConstantsData.name,
|
|
||||||
tokens: totalTokens,
|
|
||||||
question: userChatInput,
|
|
||||||
answer: answerText,
|
|
||||||
maxToken,
|
|
||||||
finishMessages
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
|
function getMaxTokens({
|
||||||
|
maxToken,
|
||||||
|
model,
|
||||||
|
filterMessages = []
|
||||||
|
}: {
|
||||||
|
maxToken: number;
|
||||||
|
model: ChatModelItemType;
|
||||||
|
filterMessages: ChatProps['history'];
|
||||||
|
}) {
|
||||||
|
const tokensLimit = model.contextMaxToken;
|
||||||
|
/* count response max token */
|
||||||
|
const promptsToken = modelToolMap.countTokens({
|
||||||
|
model: model.model,
|
||||||
|
messages: filterMessages
|
||||||
|
});
|
||||||
|
maxToken = maxToken + promptsToken > tokensLimit ? tokensLimit - promptsToken : maxToken;
|
||||||
|
|
||||||
|
return {
|
||||||
|
max_tokens: maxToken
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
async function streamResponse({ res, response }: { res: NextApiResponse; response: any }) {
|
async function streamResponse({ res, response }: { res: NextApiResponse; response: any }) {
|
||||||
let answer = '';
|
let answer = '';
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
import { PgClient } from '@/service/pg';
|
import { PgClient } from '@/service/pg';
|
||||||
import type { ChatHistoryItemResType, ChatItemType } from '@/types/chat';
|
import type { ChatHistoryItemResType, ChatItemType } from '@/types/chat';
|
||||||
import { TaskResponseKeyEnum } from '@/constants/chat';
|
import { ChatModuleEnum, TaskResponseKeyEnum } from '@/constants/chat';
|
||||||
import { getVector } from '@/pages/api/openapi/plugin/vector';
|
import { getVector } from '@/pages/api/openapi/plugin/vector';
|
||||||
import { countModelPrice } from '@/service/events/pushBill';
|
import { countModelPrice } from '@/service/events/pushBill';
|
||||||
import type { SelectedKbType } from '@/types/plugin';
|
import type { SelectedKbType } from '@/types/plugin';
|
||||||
@@ -20,8 +20,6 @@ export type KBSearchResponse = {
|
|||||||
quoteQA: QuoteItemType[];
|
quoteQA: QuoteItemType[];
|
||||||
};
|
};
|
||||||
|
|
||||||
const moduleName = 'KB Search';
|
|
||||||
|
|
||||||
export async function dispatchKBSearch(props: Record<string, any>): Promise<KBSearchResponse> {
|
export async function dispatchKBSearch(props: Record<string, any>): Promise<KBSearchResponse> {
|
||||||
const {
|
const {
|
||||||
kbList = [],
|
kbList = [],
|
||||||
@@ -65,7 +63,7 @@ export async function dispatchKBSearch(props: Record<string, any>): Promise<KBSe
|
|||||||
unEmpty: searchRes.length > 0 ? true : undefined,
|
unEmpty: searchRes.length > 0 ? true : undefined,
|
||||||
quoteQA: searchRes,
|
quoteQA: searchRes,
|
||||||
responseData: {
|
responseData: {
|
||||||
moduleName,
|
moduleName: ChatModuleEnum.KBSearch,
|
||||||
price: countModelPrice({ model: vectorModel.model, tokens: tokenLen }),
|
price: countModelPrice({ model: vectorModel.model, tokens: tokenLen }),
|
||||||
model: vectorModel.name,
|
model: vectorModel.name,
|
||||||
tokens: tokenLen,
|
tokens: tokenLen,
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
import { ChatItemType } from '@/types/chat';
|
import { ChatItemType } from '@/types/chat';
|
||||||
import { modelToolMap } from '@/utils/plugin';
|
import { modelToolMap } from '@/utils/plugin';
|
||||||
import { ChatRoleEnum, sseResponseEventEnum } from '@/constants/chat';
|
import { ChatRoleEnum } 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';
|
||||||
|
|
||||||
@@ -18,18 +17,6 @@ export type StreamResponseType = {
|
|||||||
model: `${OpenAiChatEnum}`;
|
model: `${OpenAiChatEnum}`;
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
};
|
};
|
||||||
export type StreamResponseReturnType = {
|
|
||||||
responseContent: string;
|
|
||||||
totalTokens: number;
|
|
||||||
finishMessages: ChatItemType[];
|
|
||||||
};
|
|
||||||
|
|
||||||
/* delete invalid symbol */
|
|
||||||
const simplifyStr = (str = '') =>
|
|
||||||
str
|
|
||||||
.replace(/\n+/g, '\n') // 连续空行
|
|
||||||
.replace(/[^\S\r\n]+/g, ' ') // 连续空白内容
|
|
||||||
.trim();
|
|
||||||
|
|
||||||
/* slice chat context by tokens */
|
/* slice chat context by tokens */
|
||||||
export const ChatContextFilter = ({
|
export const ChatContextFilter = ({
|
||||||
|
3
client/src/types/chat.d.ts
vendored
3
client/src/types/chat.d.ts
vendored
@@ -56,7 +56,8 @@ export type ChatHistoryItemResType = {
|
|||||||
question?: string;
|
question?: string;
|
||||||
temperature?: number;
|
temperature?: number;
|
||||||
maxToken?: number;
|
maxToken?: number;
|
||||||
finishMessages?: ChatItemType[];
|
quoteList?: QuoteItemType[];
|
||||||
|
completeMessages?: ChatItemType[];
|
||||||
|
|
||||||
// kb search
|
// kb search
|
||||||
similarity?: number;
|
similarity?: number;
|
||||||
|
2
client/src/types/model.d.ts
vendored
2
client/src/types/model.d.ts
vendored
@@ -2,7 +2,7 @@ export type ChatModelItemType = {
|
|||||||
model: string;
|
model: string;
|
||||||
name: string;
|
name: string;
|
||||||
contextMaxToken: number;
|
contextMaxToken: number;
|
||||||
systemMaxToken: number;
|
quoteMaxToken: number;
|
||||||
maxTemperature: number;
|
maxTemperature: number;
|
||||||
price: number;
|
price: number;
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user