diff --git a/client/public/imgs/module/extract.png b/client/public/imgs/module/extract.png
new file mode 100644
index 000000000..8cd0d1e02
Binary files /dev/null and b/client/public/imgs/module/extract.png differ
diff --git a/client/src/components/MyModal/index.tsx b/client/src/components/MyModal/index.tsx
index 9c9cbfe5f..357ef1cc3 100644
--- a/client/src/components/MyModal/index.tsx
+++ b/client/src/components/MyModal/index.tsx
@@ -42,7 +42,7 @@ const MyModal = ({
{...props}
>
{!!title && {title}}
-
+
{showCloseBtn && }
{children}
diff --git a/client/src/components/MyTooltip/index.tsx b/client/src/components/MyTooltip/index.tsx
index 40aaee0b1..9dc0f3946 100644
--- a/client/src/components/MyTooltip/index.tsx
+++ b/client/src/components/MyTooltip/index.tsx
@@ -20,7 +20,7 @@ const MyTooltip = ({ children, forceShow = false, ...props }: Props) => {
py={2}
borderRadius={'8px'}
whiteSpace={'pre-wrap'}
- shouldWrapChildren
+ boxShadow={'1px 1px 10px rgba(0,0,0,0.2)'}
{...props}
>
{children}
diff --git a/client/src/constants/flow/ModuleTemplate.ts b/client/src/constants/flow/ModuleTemplate.ts
index 9188121d4..b33256b74 100644
--- a/client/src/constants/flow/ModuleTemplate.ts
+++ b/client/src/constants/flow/ModuleTemplate.ts
@@ -60,7 +60,6 @@ export const UserInputModule: FlowModuleTemplateType = {
name: '用户问题(对话入口)',
intro: '用户输入的内容。该模块通常作为应用的入口,用户在发送消息后会首先执行该模块。',
flowType: FlowModuleTypeEnum.questionInput,
- url: '/app/modules/init/userChatInput',
inputs: [
{
key: SystemInputEnum.userChatInput,
@@ -83,7 +82,6 @@ export const HistoryModule: FlowModuleTemplateType = {
name: '聊天记录',
intro: '用户输入的内容。该模块通常作为应用的入口,用户在发送消息后会首先执行该模块。',
flowType: FlowModuleTypeEnum.historyNode,
- url: '/app/modules/init/history',
inputs: [
{
key: 'maxContext',
@@ -116,7 +114,6 @@ export const ChatModule: FlowModuleTemplateType = {
name: 'AI 对话',
intro: 'AI 大模型对话',
flowType: FlowModuleTypeEnum.chatNode,
- url: '/app/modules/chat/gpt',
inputs: [
{
key: 'model',
@@ -206,7 +203,6 @@ export const KBSearchModule: FlowModuleTemplateType = {
name: '知识库搜索',
intro: '去知识库中搜索对应的答案。可作为 AI 对话引用参考。',
flowType: FlowModuleTypeEnum.kbSearchNode,
- url: '/app/modules/kb/search',
inputs: [
{
key: 'kbList',
@@ -322,7 +318,6 @@ export const ClassifyQuestionModule: FlowModuleTemplateType = {
intro: '可以判断用户问题属于哪方面问题,从而执行不同的操作。',
description:
'根据用户的历史记录和当前问题判断该次提问的类型。可以添加多组问题类型,下面是一个模板例子:\n类型1: 打招呼\n类型2: 关于 laf 通用问题\n类型3: 关于 laf 代码问题\n类型4: 其他问题',
- url: '/app/modules/agent/classifyQuestion',
flowType: FlowModuleTypeEnum.classifyQuestion,
inputs: [
{
@@ -378,6 +373,65 @@ export const ClassifyQuestionModule: FlowModuleTemplateType = {
}
]
};
+export const ContextExtractModule: FlowModuleTemplateType = {
+ logo: '/imgs/module/extract.png',
+ name: '内容提取',
+ intro: '从文本中提取出指定格式的数据',
+ description: '可从文本中提取指定的数据,例如:sql语句、搜索关键词、代码等',
+ flowType: FlowModuleTypeEnum.contentExtract,
+ inputs: [
+ {
+ key: 'systemPrompt',
+ type: FlowInputItemTypeEnum.textarea,
+ valueType: FlowValueTypeEnum.string,
+ label: '提取内容描述',
+ description: '写一段提取要求,告诉 AI 需要提取哪些内容',
+ placeholder: '例如: \n1. 根据用户的\n2. Sealos 是一个集群操作系统',
+ value: ''
+ },
+ Input_Template_History,
+ Input_Template_UserChatInput,
+ {
+ key: 'agents',
+ type: FlowInputItemTypeEnum.custom,
+ label: '',
+ value: [
+ {
+ value: '打招呼',
+ key: 'fasw'
+ },
+ {
+ value: '关于 xxx 的问题',
+ key: 'fqsw'
+ },
+ {
+ value: '其他问题',
+ key: 'fesw'
+ }
+ ]
+ }
+ ],
+ outputs: [
+ {
+ key: 'fasw',
+ label: '',
+ type: FlowOutputItemTypeEnum.hidden,
+ targets: []
+ },
+ {
+ key: 'fqsw',
+ label: '',
+ type: FlowOutputItemTypeEnum.hidden,
+ targets: []
+ },
+ {
+ key: 'fesw',
+ label: '',
+ type: FlowOutputItemTypeEnum.hidden,
+ targets: []
+ }
+ ]
+};
export const EmptyModule: FlowModuleTemplateType = {
logo: '/imgs/module/cq.png',
name: '该模块已被移除',
diff --git a/client/src/constants/flow/index.ts b/client/src/constants/flow/index.ts
index cd0ead49a..1fb92be77 100644
--- a/client/src/constants/flow/index.ts
+++ b/client/src/constants/flow/index.ts
@@ -30,7 +30,8 @@ export enum FlowModuleTypeEnum {
kbSearchNode = 'kbSearchNode',
tfSwitchNode = 'tfSwitchNode',
answerNode = 'answerNode',
- classifyQuestion = 'classifyQuestion'
+ classifyQuestion = 'classifyQuestion',
+ contentExtract = 'contentExtract'
}
export enum SpecialInputKeyEnum {
diff --git a/client/src/constants/theme.ts b/client/src/constants/theme.ts
index 071683bcb..016d6a396 100644
--- a/client/src/constants/theme.ts
+++ b/client/src/constants/theme.ts
@@ -199,16 +199,6 @@ const Select = selectMultiStyle({
}
});
-const Tooltip = defineStyleConfig({
- baseStyle: {
- p: 3,
- bg: 'white',
- color: 'blackAlpha.800',
- borderRadius: '8px',
- boxShadow: '1px 1px 10px rgba(0,0,0,0.2)'
- }
-});
-
// 全局主题
export const theme = extendTheme({
styles: {
@@ -309,7 +299,6 @@ export const theme = extendTheme({
Textarea,
Switch,
Select,
- Tooltip,
NumberInput
}
});
diff --git a/client/src/pages/api/openapi/v1/chat/completions.ts b/client/src/pages/api/openapi/v1/chat/completions.ts
index 3c89a8a91..0d307b86e 100644
--- a/client/src/pages/api/openapi/v1/chat/completions.ts
+++ b/client/src/pages/api/openapi/v1/chat/completions.ts
@@ -113,6 +113,12 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
throw new Error('Question is empty');
}
+ // 创建响应流
+ res.setHeader('Content-Type', 'text/event-stream;charset=utf-8');
+ res.setHeader('Access-Control-Allow-Origin', '*');
+ res.setHeader('X-Accel-Buffering', 'no');
+ res.setHeader('Cache-Control', 'no-cache, no-transform');
+
/* start process */
const { responseData, answerText } = await dispatchModules({
res,
diff --git a/client/src/service/moduleDispatch/agent/classifyQuestion.ts b/client/src/service/moduleDispatch/agent/classifyQuestion.ts
index 303de760b..fb2cefb78 100644
--- a/client/src/service/moduleDispatch/agent/classifyQuestion.ts
+++ b/client/src/service/moduleDispatch/agent/classifyQuestion.ts
@@ -7,13 +7,14 @@ import type { ClassifyQuestionAgentItemType } from '@/types/app';
import { countModelPrice } from '@/service/events/pushBill';
import { UserModelSchema } from '@/types/mongoSchema';
import { getModel } from '@/service/utils/data';
+import { SystemInputEnum } from '@/constants/app';
export type CQProps = {
systemPrompt?: string;
history?: ChatItemType[];
- userChatInput: string;
- agents: ClassifyQuestionAgentItemType[];
+ [SystemInputEnum.userChatInput]: string;
userOpenaiAccount: UserModelSchema['openaiAccount'];
+ agents: ClassifyQuestionAgentItemType[];
};
export type CQResponse = {
[TaskResponseKeyEnum.responseData]: ChatHistoryItemResType;
@@ -22,7 +23,7 @@ export type CQResponse = {
const agentModel = 'gpt-3.5-turbo';
const agentFunName = 'agent_user_question';
-const maxTokens = 2000;
+const maxTokens = 3000;
/* request openai chat */
export const dispatchClassifyQuestion = async (props: Record): Promise => {
diff --git a/client/src/service/moduleDispatch/agent/extract.ts b/client/src/service/moduleDispatch/agent/extract.ts
index c1bfa2c83..3fa3c4c20 100644
--- a/client/src/service/moduleDispatch/agent/extract.ts
+++ b/client/src/service/moduleDispatch/agent/extract.ts
@@ -7,40 +7,41 @@ import type { ChatItemType } from '@/types/chat';
import { ChatRoleEnum } from '@/constants/chat';
import { getAIChatApi, axiosConfig } from '@/service/ai/openai';
import type { ClassifyQuestionAgentItemType } from '@/types/app';
-import { authUser } from '@/service/utils/auth';
+import { SystemInputEnum } from '@/constants/app';
export type Props = {
+ systemPrompt?: string;
history?: ChatItemType[];
- userChatInput: string;
- agents: ClassifyQuestionAgentItemType[];
+ [SystemInputEnum.userChatInput]: string;
description: string;
+ agents: ClassifyQuestionAgentItemType[];
+};
+export type Response = {
+ arguments: Record;
+ deficiency: boolean;
};
-export type Response = { history: ChatItemType[] };
-const agentModel = 'gpt-3.5-turbo-16k';
+const agentModel = 'gpt-3.5-turbo';
const agentFunName = 'agent_extract_data';
+const maxTokens = 3000;
-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) {
+export async function extract({
+ systemPrompt,
+ agents,
+ history = [],
+ userChatInput,
+ description
+}: Props): Promise {
const messages: ChatItemType[] = [
- ...history.slice(-4),
+ ...(systemPrompt
+ ? [
+ {
+ obj: ChatRoleEnum.System,
+ value: systemPrompt
+ }
+ ]
+ : []),
+ ...history,
{
obj: ChatRoleEnum.Human,
value: userChatInput
@@ -50,7 +51,7 @@ export async function extract({ agents, history = [], userChatInput, description
// @ts-ignore
model: agentModel,
prompts: messages,
- maxTokens: 3000
+ maxTokens
});
const adaptMessages = adaptChatItem_openAI({ messages: filterMessages, reserveId: false });
@@ -94,7 +95,17 @@ export async function extract({ agents, history = [], userChatInput, description
}
);
- const arg = JSON.parse(response.data.choices?.[0]?.message?.function_call?.arguments || '');
+ const arg = JSON.parse(response.data.choices?.[0]?.message?.function_call?.arguments || '{}');
+ let deficiency = false;
+ for (const key in arg) {
+ if (arg[key] === '') {
+ deficiency = true;
+ break;
+ }
+ }
- return arg;
+ return {
+ arguments: arg,
+ deficiency
+ };
}
diff --git a/client/src/types/flow.d.ts b/client/src/types/flow.d.ts
index 90edf567f..f4fb4d6e3 100644
--- a/client/src/types/flow.d.ts
+++ b/client/src/types/flow.d.ts
@@ -52,7 +52,6 @@ export type FlowModuleTemplateType = {
description?: string;
intro: string;
flowType: `${FlowModuleTypeEnum}`;
- url?: string;
inputs: FlowInputItemType[];
outputs: FlowOutputItemType[];
};