mirror of
https://github.com/labring/FastGPT.git
synced 2025-08-05 14:47:38 +00:00
name
This commit is contained in:
133
client/src/pages/api/app/modules/agent/classifyQuestion.ts
Normal file
133
client/src/pages/api/app/modules/agent/classifyQuestion.ts
Normal file
@@ -0,0 +1,133 @@
|
||||
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { jsonRes } from '@/service/response';
|
||||
import { adaptChatItem_openAI } from '@/utils/plugin/openai';
|
||||
import { ChatContextFilter } from '@/service/utils/chat/index';
|
||||
import type { ChatItemType } from '@/types/chat';
|
||||
import { ChatRoleEnum } from '@/constants/chat';
|
||||
import { getOpenAIApi, axiosConfig } from '@/service/ai/openai';
|
||||
import type { ClassifyQuestionAgentItemType } from '@/types/app';
|
||||
import { countModelPrice, pushTaskBillListItem } from '@/service/events/pushBill';
|
||||
import { getModel } from '@/service/utils/data';
|
||||
import { authUser } from '@/service/utils/auth';
|
||||
|
||||
export type Props = {
|
||||
systemPrompt?: string;
|
||||
history?: ChatItemType[];
|
||||
userChatInput: string;
|
||||
agents: ClassifyQuestionAgentItemType[];
|
||||
billId?: string;
|
||||
};
|
||||
export type Response = { history: ChatItemType[] };
|
||||
|
||||
const agentModel = 'gpt-3.5-turbo-16k';
|
||||
const agentFunName = 'agent_user_question';
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
try {
|
||||
await authUser({ req, authRoot: true });
|
||||
let { userChatInput } = req.body as Props;
|
||||
|
||||
if (!userChatInput) {
|
||||
throw new Error('userChatInput is empty');
|
||||
}
|
||||
|
||||
const response = await classifyQuestion(req.body);
|
||||
|
||||
jsonRes(res, {
|
||||
data: response
|
||||
});
|
||||
} catch (err) {
|
||||
jsonRes(res, {
|
||||
code: 500,
|
||||
error: err
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/* request openai chat */
|
||||
export async function classifyQuestion({
|
||||
agents,
|
||||
systemPrompt,
|
||||
history = [],
|
||||
userChatInput,
|
||||
billId
|
||||
}: Props) {
|
||||
const messages: ChatItemType[] = [
|
||||
...(systemPrompt
|
||||
? [
|
||||
{
|
||||
obj: ChatRoleEnum.System,
|
||||
value: systemPrompt
|
||||
}
|
||||
]
|
||||
: []),
|
||||
{
|
||||
obj: ChatRoleEnum.Human,
|
||||
value: userChatInput
|
||||
}
|
||||
];
|
||||
const filterMessages = ChatContextFilter({
|
||||
// @ts-ignore
|
||||
model: agentModel,
|
||||
prompts: messages,
|
||||
maxTokens: 1500
|
||||
});
|
||||
const adaptMessages = adaptChatItem_openAI({ messages: filterMessages, reserveId: false });
|
||||
|
||||
// function body
|
||||
const agentFunction = {
|
||||
name: agentFunName,
|
||||
description: '判断用户问题的类型,并返回不同的值',
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
type: {
|
||||
type: 'string',
|
||||
description: agents.map((item) => `${item.value},返回: '${item.key}'`).join('\n'),
|
||||
enum: agents.map((item) => item.key)
|
||||
}
|
||||
},
|
||||
required: ['type']
|
||||
}
|
||||
};
|
||||
const chatAPI = getOpenAIApi();
|
||||
|
||||
const response = await chatAPI.createChatCompletion(
|
||||
{
|
||||
model: agentModel,
|
||||
temperature: 0,
|
||||
messages: [...adaptMessages],
|
||||
function_call: { name: agentFunName },
|
||||
functions: [agentFunction]
|
||||
},
|
||||
{
|
||||
...axiosConfig()
|
||||
}
|
||||
);
|
||||
|
||||
const arg = JSON.parse(response.data.choices?.[0]?.message?.function_call?.arguments || '');
|
||||
|
||||
if (!arg.type) {
|
||||
throw new Error('');
|
||||
}
|
||||
|
||||
const totalTokens = response.data.usage?.total_tokens || 0;
|
||||
|
||||
await pushTaskBillListItem({
|
||||
billId,
|
||||
moduleName: 'Classify Question',
|
||||
amount: countModelPrice({ model: agentModel, tokens: totalTokens }),
|
||||
model: getModel(agentModel)?.name,
|
||||
tokenLen: totalTokens
|
||||
});
|
||||
|
||||
console.log(
|
||||
'CQ',
|
||||
agents.findIndex((item) => item.key === arg.type)
|
||||
);
|
||||
|
||||
return {
|
||||
[arg.type]: 1
|
||||
};
|
||||
}
|
100
client/src/pages/api/app/modules/agent/extract.ts
Normal file
100
client/src/pages/api/app/modules/agent/extract.ts
Normal file
@@ -0,0 +1,100 @@
|
||||
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { jsonRes } from '@/service/response';
|
||||
import { adaptChatItem_openAI } from '@/utils/plugin/openai';
|
||||
import { ChatContextFilter } from '@/service/utils/chat/index';
|
||||
import type { ChatItemType } from '@/types/chat';
|
||||
import { ChatRoleEnum } from '@/constants/chat';
|
||||
import { getOpenAIApi, axiosConfig } from '@/service/ai/openai';
|
||||
import type { ClassifyQuestionAgentItemType } from '@/types/app';
|
||||
import { authUser } from '@/service/utils/auth';
|
||||
|
||||
export type Props = {
|
||||
history?: ChatItemType[];
|
||||
userChatInput: string;
|
||||
agents: ClassifyQuestionAgentItemType[];
|
||||
description: string;
|
||||
};
|
||||
export type Response = { history: ChatItemType[] };
|
||||
|
||||
const agentModel = 'gpt-3.5-turbo-16k';
|
||||
const agentFunName = 'agent_extract_data';
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
try {
|
||||
await authUser({ req, authRoot: true });
|
||||
|
||||
const response = await extract(req.body);
|
||||
|
||||
jsonRes(res, {
|
||||
data: response
|
||||
});
|
||||
} catch (err) {
|
||||
jsonRes(res, {
|
||||
code: 500,
|
||||
error: err
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/* request openai chat */
|
||||
export async function extract({ agents, history = [], userChatInput, description }: Props) {
|
||||
const messages: ChatItemType[] = [
|
||||
...history.slice(-4),
|
||||
{
|
||||
obj: ChatRoleEnum.Human,
|
||||
value: userChatInput
|
||||
}
|
||||
];
|
||||
const filterMessages = ChatContextFilter({
|
||||
// @ts-ignore
|
||||
model: agentModel,
|
||||
prompts: messages,
|
||||
maxTokens: 3000
|
||||
});
|
||||
const adaptMessages = adaptChatItem_openAI({ messages: filterMessages, reserveId: false });
|
||||
|
||||
const properties: Record<
|
||||
string,
|
||||
{
|
||||
type: string;
|
||||
description: string;
|
||||
}
|
||||
> = {};
|
||||
agents.forEach((item) => {
|
||||
properties[item.key] = {
|
||||
type: 'string',
|
||||
description: item.value
|
||||
};
|
||||
});
|
||||
|
||||
// function body
|
||||
const agentFunction = {
|
||||
name: agentFunName,
|
||||
description,
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties,
|
||||
required: agents.map((item) => item.key)
|
||||
}
|
||||
};
|
||||
|
||||
const chatAPI = getOpenAIApi();
|
||||
|
||||
const response = await chatAPI.createChatCompletion(
|
||||
{
|
||||
model: agentModel,
|
||||
temperature: 0,
|
||||
messages: [...adaptMessages],
|
||||
function_call: { name: agentFunName },
|
||||
functions: [agentFunction]
|
||||
},
|
||||
{
|
||||
...axiosConfig()
|
||||
}
|
||||
);
|
||||
|
||||
const arg = JSON.parse(response.data.choices?.[0]?.message?.function_call?.arguments || '');
|
||||
|
||||
return arg;
|
||||
}
|
265
client/src/pages/api/app/modules/chat/gpt.ts
Normal file
265
client/src/pages/api/app/modules/chat/gpt.ts
Normal file
@@ -0,0 +1,265 @@
|
||||
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { jsonRes, sseErrRes } from '@/service/response';
|
||||
import { sseResponse } from '@/service/utils/tools';
|
||||
import { OpenAiChatEnum } from '@/constants/model';
|
||||
import { adaptChatItem_openAI, countOpenAIToken } from '@/utils/plugin/openai';
|
||||
import { modelToolMap } from '@/utils/plugin';
|
||||
import { ChatContextFilter } from '@/service/utils/chat/index';
|
||||
import type { ChatItemType } from '@/types/chat';
|
||||
import { ChatRoleEnum, sseResponseEventEnum } from '@/constants/chat';
|
||||
import { parseStreamChunk, textAdaptGptResponse } from '@/utils/adapt';
|
||||
import { getOpenAIApi, axiosConfig } from '@/service/ai/openai';
|
||||
import { SpecificInputEnum } from '@/constants/app';
|
||||
import { getChatModel } from '@/service/utils/data';
|
||||
import { countModelPrice, pushTaskBillListItem } from '@/service/events/pushBill';
|
||||
import { authUser } from '@/service/utils/auth';
|
||||
|
||||
export type Props = {
|
||||
model: `${OpenAiChatEnum}`;
|
||||
temperature?: number;
|
||||
maxToken?: number;
|
||||
history?: ChatItemType[];
|
||||
userChatInput: string;
|
||||
stream?: boolean;
|
||||
quotePrompt?: string;
|
||||
systemPrompt?: string;
|
||||
limitPrompt?: string;
|
||||
billId?: string;
|
||||
};
|
||||
export type Response = { [SpecificInputEnum.answerText]: string; totalTokens: number };
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
let { model, temperature = 0, stream } = req.body as Props;
|
||||
try {
|
||||
await authUser({ req, authRoot: true });
|
||||
|
||||
const response = await chatCompletion({
|
||||
...req.body,
|
||||
res,
|
||||
model
|
||||
});
|
||||
|
||||
if (stream) {
|
||||
sseResponse({
|
||||
res,
|
||||
event: sseResponseEventEnum.moduleFetchResponse,
|
||||
data: JSON.stringify(response)
|
||||
});
|
||||
res.end();
|
||||
} else {
|
||||
jsonRes(res, {
|
||||
data: response
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
if (stream) {
|
||||
res.status(500);
|
||||
sseErrRes(res, err);
|
||||
res.end();
|
||||
} else {
|
||||
jsonRes(res, {
|
||||
code: 500,
|
||||
error: err
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* request openai chat */
|
||||
export async function chatCompletion({
|
||||
res,
|
||||
model,
|
||||
temperature = 0,
|
||||
maxToken = 4000,
|
||||
stream = false,
|
||||
history = [],
|
||||
quotePrompt = '',
|
||||
userChatInput,
|
||||
systemPrompt = '',
|
||||
limitPrompt = '',
|
||||
billId
|
||||
}: Props & { res: NextApiResponse }): Promise<Response> {
|
||||
// temperature adapt
|
||||
const modelConstantsData = getChatModel(model);
|
||||
|
||||
if (!modelConstantsData) {
|
||||
return Promise.reject('The chat model is undefined');
|
||||
}
|
||||
|
||||
// FastGpt temperature range: 1~10
|
||||
temperature = +(modelConstantsData.maxTemperature * (temperature / 10)).toFixed(2);
|
||||
|
||||
const messages: ChatItemType[] = [
|
||||
...(quotePrompt
|
||||
? [
|
||||
{
|
||||
obj: ChatRoleEnum.System,
|
||||
value: quotePrompt
|
||||
}
|
||||
]
|
||||
: []),
|
||||
...(systemPrompt
|
||||
? [
|
||||
{
|
||||
obj: ChatRoleEnum.System,
|
||||
value: systemPrompt
|
||||
}
|
||||
]
|
||||
: []),
|
||||
...history,
|
||||
...(limitPrompt
|
||||
? [
|
||||
{
|
||||
obj: ChatRoleEnum.Human,
|
||||
value: limitPrompt
|
||||
}
|
||||
]
|
||||
: []),
|
||||
{
|
||||
obj: ChatRoleEnum.Human,
|
||||
value: userChatInput
|
||||
}
|
||||
];
|
||||
const modelTokenLimit = getChatModel(model)?.contextMaxToken || 4000;
|
||||
|
||||
const filterMessages = ChatContextFilter({
|
||||
model,
|
||||
prompts: messages,
|
||||
maxTokens: Math.ceil(modelTokenLimit - 300) // filter token. not response maxToken
|
||||
});
|
||||
|
||||
const adaptMessages = adaptChatItem_openAI({ messages: filterMessages, reserveId: false });
|
||||
const chatAPI = getOpenAIApi();
|
||||
|
||||
/* 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 { answer, totalTokens } = 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,
|
||||
model: 'gpt-3.5-turbo-16k'
|
||||
});
|
||||
|
||||
return {
|
||||
answer,
|
||||
totalTokens
|
||||
};
|
||||
} else {
|
||||
const answer = stream ? '' : response.data.choices?.[0].message?.content || '';
|
||||
const totalTokens = stream ? 0 : response.data.usage?.total_tokens || 0;
|
||||
|
||||
return {
|
||||
answer,
|
||||
totalTokens
|
||||
};
|
||||
}
|
||||
})();
|
||||
|
||||
await pushTaskBillListItem({
|
||||
billId,
|
||||
moduleName: 'AI Chat',
|
||||
amount: countModelPrice({ model, tokens: totalTokens }),
|
||||
model: modelConstantsData.name,
|
||||
tokenLen: totalTokens
|
||||
});
|
||||
|
||||
return {
|
||||
answerText: answer,
|
||||
totalTokens
|
||||
};
|
||||
}
|
||||
|
||||
async function streamResponse({ res, response }: { res: NextApiResponse; response: any }) {
|
||||
let answer = '';
|
||||
let error: any = null;
|
||||
|
||||
const clientRes = async (data: string) => {
|
||||
const { content = '' } = (() => {
|
||||
try {
|
||||
const json = JSON.parse(data);
|
||||
const content: string = json?.choices?.[0].delta.content || '';
|
||||
error = json.error;
|
||||
answer += content;
|
||||
return { content };
|
||||
} catch (error) {
|
||||
return {};
|
||||
}
|
||||
})();
|
||||
|
||||
if (res.closed || error) return;
|
||||
|
||||
if (data === '[DONE]') {
|
||||
sseResponse({
|
||||
res,
|
||||
event: sseResponseEventEnum.answer,
|
||||
data: textAdaptGptResponse({
|
||||
text: null,
|
||||
finish_reason: 'stop'
|
||||
})
|
||||
});
|
||||
sseResponse({
|
||||
res,
|
||||
event: sseResponseEventEnum.answer,
|
||||
data: '[DONE]'
|
||||
});
|
||||
} else {
|
||||
sseResponse({
|
||||
res,
|
||||
event: sseResponseEventEnum.answer,
|
||||
data: textAdaptGptResponse({
|
||||
text: content
|
||||
})
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
for await (const chunk of response.data as any) {
|
||||
if (res.closed) break;
|
||||
const parse = parseStreamChunk(chunk);
|
||||
parse.forEach((item) => clientRes(item.data));
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('pipe error', error);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
console.log(error);
|
||||
return Promise.reject(error);
|
||||
}
|
||||
|
||||
return {
|
||||
answer
|
||||
};
|
||||
}
|
20
client/src/pages/api/app/modules/init/history.tsx
Normal file
20
client/src/pages/api/app/modules/init/history.tsx
Normal file
@@ -0,0 +1,20 @@
|
||||
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { jsonRes } from '@/service/response';
|
||||
import { SystemInputEnum } from '@/constants/app';
|
||||
import { ChatItemType } from '@/types/chat';
|
||||
|
||||
export type Props = {
|
||||
maxContext: number;
|
||||
[SystemInputEnum.history]: ChatItemType[];
|
||||
};
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
const { maxContext = 5, history } = req.body as Props;
|
||||
|
||||
jsonRes(res, {
|
||||
data: {
|
||||
history: history.slice(-maxContext)
|
||||
}
|
||||
});
|
||||
}
|
17
client/src/pages/api/app/modules/init/userChatInput.tsx
Normal file
17
client/src/pages/api/app/modules/init/userChatInput.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { jsonRes } from '@/service/response';
|
||||
import { SystemInputEnum } from '@/constants/app';
|
||||
|
||||
export type Props = {
|
||||
[SystemInputEnum.userChatInput]: string;
|
||||
};
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
const { userChatInput } = req.body as Props;
|
||||
jsonRes(res, {
|
||||
data: {
|
||||
userChatInput
|
||||
}
|
||||
});
|
||||
}
|
132
client/src/pages/api/app/modules/kb/search.ts
Normal file
132
client/src/pages/api/app/modules/kb/search.ts
Normal file
@@ -0,0 +1,132 @@
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { jsonRes } from '@/service/response';
|
||||
import { PgClient } from '@/service/pg';
|
||||
import { withNextCors } from '@/service/utils/tools';
|
||||
import type { ChatItemType } from '@/types/chat';
|
||||
import { ChatRoleEnum, rawSearchKey } from '@/constants/chat';
|
||||
import { modelToolMap } from '@/utils/plugin';
|
||||
import { getVector } from '@/pages/api/openapi/plugin/vector';
|
||||
import { countModelPrice, pushTaskBillListItem } from '@/service/events/pushBill';
|
||||
import { getModel } from '@/service/utils/data';
|
||||
import { authUser } from '@/service/utils/auth';
|
||||
|
||||
export type QuoteItemType = {
|
||||
kb_id: string;
|
||||
id: string;
|
||||
q: string;
|
||||
a: string;
|
||||
source?: string;
|
||||
};
|
||||
type Props = {
|
||||
kb_ids: string[];
|
||||
history: ChatItemType[];
|
||||
similarity: number;
|
||||
limit: number;
|
||||
maxToken: number;
|
||||
userChatInput: string;
|
||||
stream?: boolean;
|
||||
billId?: string;
|
||||
};
|
||||
type Response = {
|
||||
[rawSearchKey]: QuoteItemType[];
|
||||
isEmpty?: boolean;
|
||||
quotePrompt?: string;
|
||||
};
|
||||
|
||||
export default withNextCors(async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||
try {
|
||||
await authUser({ req, authRoot: true });
|
||||
|
||||
const { kb_ids = [], userChatInput } = req.body as Props;
|
||||
|
||||
if (!userChatInput || !Array.isArray(kb_ids)) {
|
||||
throw new Error('params is error');
|
||||
}
|
||||
|
||||
const result = await kbSearch({
|
||||
...req.body,
|
||||
kb_ids,
|
||||
userChatInput
|
||||
});
|
||||
|
||||
jsonRes<Response>(res, {
|
||||
data: result
|
||||
});
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
jsonRes(res, {
|
||||
code: 500,
|
||||
error: err
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
export async function kbSearch({
|
||||
kb_ids = [],
|
||||
history = [],
|
||||
similarity = 0.8,
|
||||
limit = 5,
|
||||
maxToken = 2500,
|
||||
userChatInput,
|
||||
billId
|
||||
}: Props): Promise<Response> {
|
||||
if (kb_ids.length === 0)
|
||||
return {
|
||||
isEmpty: true,
|
||||
rawSearch: [],
|
||||
quotePrompt: undefined
|
||||
};
|
||||
|
||||
// get vector
|
||||
const vectorModel = global.vectorModels[0].model;
|
||||
const { vectors, tokenLen } = await getVector({
|
||||
model: vectorModel,
|
||||
input: [userChatInput]
|
||||
});
|
||||
|
||||
// search kb
|
||||
const [res]: any = await Promise.all([
|
||||
PgClient.query(
|
||||
`BEGIN;
|
||||
SET LOCAL ivfflat.probes = ${global.systemEnv.pgIvfflatProbe || 10};
|
||||
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]
|
||||
}]' limit ${limit};
|
||||
COMMIT;`
|
||||
),
|
||||
pushTaskBillListItem({
|
||||
billId,
|
||||
moduleName: 'Vector Generate',
|
||||
amount: countModelPrice({ model: vectorModel, tokens: tokenLen }),
|
||||
model: getModel(vectorModel)?.name,
|
||||
tokenLen
|
||||
})
|
||||
]);
|
||||
|
||||
const searchRes: QuoteItemType[] = res?.[2]?.rows || [];
|
||||
|
||||
// filter part quote by maxToken
|
||||
const sliceResult = modelToolMap
|
||||
.tokenSlice({
|
||||
model: 'gpt-3.5-turbo',
|
||||
maxToken,
|
||||
messages: searchRes.map((item, i) => ({
|
||||
obj: ChatRoleEnum.System,
|
||||
value: `${i + 1}: [${item.q}\n${item.a}]`
|
||||
}))
|
||||
})
|
||||
.map((item) => item.value)
|
||||
.join('\n')
|
||||
.trim();
|
||||
|
||||
// slice filterSearch
|
||||
const rawSearch = searchRes.slice(0, sliceResult.length);
|
||||
|
||||
return {
|
||||
isEmpty: rawSearch.length === 0 ? true : undefined,
|
||||
rawSearch,
|
||||
quotePrompt: sliceResult ? `知识库:\n${sliceResult}` : undefined
|
||||
};
|
||||
}
|
Reference in New Issue
Block a user