From ffd4e194bf26f5e2af58c640770e920139751932 Mon Sep 17 00:00:00 2001
From: archer <545436317@qq.com>
Date: Thu, 3 Aug 2023 15:43:06 +0800
Subject: [PATCH] feat: http request
---
client/src/constants/flow/flowField.ts | 5 +-
.../pages/api/openapi/v1/chat/completions.ts | 8 +-
.../AdEdit/components/Nodes/NodeExtract.tsx | 2 +-
.../AdEdit/components/Nodes/NodeHttp.tsx | 1 -
.../components/modules/SetInputFieldModal.tsx | 3 +-
.../AdEdit/components/render/RenderInput.tsx | 19 ++---
.../AdEdit/components/render/RenderOutput.tsx | 80 ++++++-------------
.../AdEdit/components/render/TargetHandle.tsx | 4 +-
.../app/detail/components/AdEdit/index.tsx | 69 +++++++++-------
.../service/moduleDispatch/agent/extract.ts | 2 +-
client/src/service/moduleDispatch/index.ts | 2 +
.../src/service/moduleDispatch/tools/http.ts | 51 ++++++++++++
.../moduleDispatch/tools/httpRequest.ts | 31 -------
13 files changed, 138 insertions(+), 139 deletions(-)
create mode 100644 client/src/service/moduleDispatch/tools/http.ts
delete mode 100644 client/src/service/moduleDispatch/tools/httpRequest.ts
diff --git a/client/src/constants/flow/flowField.ts b/client/src/constants/flow/flowField.ts
index 1cd0885d5..3b3e3dcaf 100644
--- a/client/src/constants/flow/flowField.ts
+++ b/client/src/constants/flow/flowField.ts
@@ -9,7 +9,6 @@ export enum ContextExtractEnum {
export enum HttpPropsEnum {
url = 'url',
- finish = 'finish',
- body = 'body',
- response = 'response'
+ failed = 'failed',
+ finish = 'finish'
}
diff --git a/client/src/pages/api/openapi/v1/chat/completions.ts b/client/src/pages/api/openapi/v1/chat/completions.ts
index 2143cf97c..1766365bd 100644
--- a/client/src/pages/api/openapi/v1/chat/completions.ts
+++ b/client/src/pages/api/openapi/v1/chat/completions.ts
@@ -10,7 +10,9 @@ import {
dispatchChatCompletion,
dispatchKBSearch,
dispatchAnswer,
- dispatchClassifyQuestion
+ dispatchClassifyQuestion,
+ dispatchContentExtract,
+ dispatchHttpRequest
} from '@/service/moduleDispatch';
import type { CreateChatCompletionRequest } from 'openai';
import { gptMessage2ChatType, textAdaptGptResponse } from '@/utils/adapt';
@@ -25,7 +27,6 @@ import { pushTaskBill } from '@/service/events/pushBill';
import { BillSourceEnum } from '@/constants/user';
import { ChatHistoryItemResType } from '@/types/chat';
import { UserModelSchema } from '@/types/mongoSchema';
-import { dispatchContentExtract } from '@/service/moduleDispatch/agent/extract';
export type MessageItemType = ChatCompletionRequestMessage & { _id?: string };
type FastGptWebChatProps = {
@@ -339,7 +340,8 @@ export async function dispatchModules({
[FlowModuleTypeEnum.chatNode]: dispatchChatCompletion,
[FlowModuleTypeEnum.kbSearchNode]: dispatchKBSearch,
[FlowModuleTypeEnum.classifyQuestion]: dispatchClassifyQuestion,
- [FlowModuleTypeEnum.contentExtract]: dispatchContentExtract
+ [FlowModuleTypeEnum.contentExtract]: dispatchContentExtract,
+ [FlowModuleTypeEnum.httpRequest]: dispatchHttpRequest
};
if (callbackMap[module.flowType]) {
return callbackMap[module.flowType](props);
diff --git a/client/src/pages/app/detail/components/AdEdit/components/Nodes/NodeExtract.tsx b/client/src/pages/app/detail/components/AdEdit/components/Nodes/NodeExtract.tsx
index b06cc512b..998c1e090 100644
--- a/client/src/pages/app/detail/components/AdEdit/components/Nodes/NodeExtract.tsx
+++ b/client/src/pages/app/detail/components/AdEdit/components/Nodes/NodeExtract.tsx
@@ -66,7 +66,7 @@ const NodeExtract = ({
{extractKeys.map((item, index) => (
{item.key} |
-
+ |
{item.desc}
|
{item.required ? '✔' : ''} |
diff --git a/client/src/pages/app/detail/components/AdEdit/components/Nodes/NodeHttp.tsx b/client/src/pages/app/detail/components/AdEdit/components/Nodes/NodeHttp.tsx
index 656f4144a..0c443eae4 100644
--- a/client/src/pages/app/detail/components/AdEdit/components/Nodes/NodeHttp.tsx
+++ b/client/src/pages/app/detail/components/AdEdit/components/Nodes/NodeHttp.tsx
@@ -32,7 +32,6 @@ const NodeHttp = ({
key,
value: {
key,
- value: '',
valueType: FlowValueTypeEnum.string,
type: FlowInputItemTypeEnum.target,
label: 'New Param',
diff --git a/client/src/pages/app/detail/components/AdEdit/components/modules/SetInputFieldModal.tsx b/client/src/pages/app/detail/components/AdEdit/components/modules/SetInputFieldModal.tsx
index dd46ea5e4..e78fe2a3e 100644
--- a/client/src/pages/app/detail/components/AdEdit/components/modules/SetInputFieldModal.tsx
+++ b/client/src/pages/app/detail/components/AdEdit/components/modules/SetInputFieldModal.tsx
@@ -10,14 +10,13 @@ import {
Input,
FormControl
} from '@chakra-ui/react';
-import type { ContextExtractAgentItemType, HttpFieldItemType } from '@/types/app';
import { useForm } from 'react-hook-form';
import { customAlphabet } from 'nanoid';
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 6);
import MyModal from '@/components/MyModal';
import Avatar from '@/components/Avatar';
import MyTooltip from '@/components/MyTooltip';
-import { FlowInputItemTypeEnum, FlowValueTypeEnum, FlowValueTypeStyle } from '@/constants/flow';
+import { FlowInputItemTypeEnum, FlowValueTypeEnum } from '@/constants/flow';
import { useTranslation } from 'react-i18next';
import MySelect from '@/components/Select';
import { FlowInputItemType } from '@/types/flow';
diff --git a/client/src/pages/app/detail/components/AdEdit/components/render/RenderInput.tsx b/client/src/pages/app/detail/components/AdEdit/components/render/RenderInput.tsx
index 04b72a8f4..596fb82b0 100644
--- a/client/src/pages/app/detail/components/AdEdit/components/render/RenderInput.tsx
+++ b/client/src/pages/app/detail/components/AdEdit/components/render/RenderInput.tsx
@@ -35,7 +35,7 @@ export const Label = ({
const [editField, setEditField] = useState();
return (
-
+
{label}
{description && (
@@ -83,9 +83,6 @@ export const Label = ({
ml={2}
_hover={{ color: 'red.500' }}
onClick={() => {
- {
- console.log(moduleId, inputKey, valueType);
- }
onChangeNode({
moduleId,
type: 'delInput',
@@ -113,15 +110,15 @@ export const Label = ({
// diff key. del and add
onChangeNode({
moduleId,
- type: 'delInput',
- key: editField.key,
- value: ''
+ type: 'addInput',
+ key: data.key,
+ value: data
});
onChangeNode({
moduleId,
- type: 'addInput',
+ type: 'delInput',
key: editField.key,
- value: data
+ value: ''
});
}
setEditField(undefined);
@@ -132,7 +129,7 @@ export const Label = ({
);
};
-const RenderBody = ({
+const RenderInput = ({
flowInputList,
moduleId,
CustomComponent = {},
@@ -270,4 +267,4 @@ const RenderBody = ({
);
};
-export default React.memo(RenderBody);
+export default React.memo(RenderInput);
diff --git a/client/src/pages/app/detail/components/AdEdit/components/render/RenderOutput.tsx b/client/src/pages/app/detail/components/AdEdit/components/render/RenderOutput.tsx
index 0769bff81..1644f6b4b 100644
--- a/client/src/pages/app/detail/components/AdEdit/components/render/RenderOutput.tsx
+++ b/client/src/pages/app/detail/components/AdEdit/components/render/RenderOutput.tsx
@@ -1,9 +1,8 @@
-import React, { useCallback, useState } from 'react';
+import React, { useState } from 'react';
import type { FlowModuleItemType, FlowOutputItemType } from '@/types/flow';
import { Box, Flex } from '@chakra-ui/react';
import { FlowOutputItemTypeEnum } from '@/constants/flow';
import { QuestionOutlineIcon } from '@chakra-ui/icons';
-import { Handle, Position } from 'reactflow';
import MyTooltip from '@/components/MyTooltip';
import SourceHandle from './SourceHandle';
import MyIcon from '@/components/Icon';
@@ -13,24 +12,26 @@ const SetOutputFieldModal = dynamic(() => import('../modules/SetOutputFieldModal
const Label = ({
moduleId,
outputKey,
- delOutputByKey,
- updateOutput,
+ outputs,
onChangeNode,
- addUpdateOutput,
...item
}: FlowOutputItemType & {
outputKey: string;
moduleId: string;
- delOutputByKey: (key: string) => void;
- updateOutput: (key: string, val: FlowOutputItemType) => void;
- addUpdateOutput: (val: FlowOutputItemType) => void;
+ outputs: FlowOutputItemType[];
onChangeNode: FlowModuleItemType['onChangeNode'];
}) => {
const { label, description, edit } = item;
const [editField, setEditField] = useState();
return (
-
+
{edit && (
<>
delOutputByKey(outputKey)}
+ onClick={() => {
+ onChangeNode({
+ moduleId,
+ type: 'outputs',
+ key: '',
+ value: outputs.filter((output) => output.key !== outputKey)
+ });
+ }}
/>
>
)}
@@ -69,13 +77,13 @@ const Label = ({
defaultField={editField}
onClose={() => setEditField(undefined)}
onSubmit={(data) => {
- console.log(data); // same key
- if (editField.key === data.key) {
- updateOutput(data.key, data);
- } else {
- delOutputByKey(editField.key);
- addUpdateOutput(data);
- }
+ onChangeNode({
+ moduleId,
+ type: 'outputs',
+ key: '',
+ value: outputs.map((output) => (output.key === outputKey ? data : output))
+ });
+
setEditField(undefined);
}}
/>
@@ -93,40 +101,6 @@ const RenderOutput = ({
flowOutputList: FlowOutputItemType[];
onChangeNode: FlowModuleItemType['onChangeNode'];
}) => {
- const delOutputByKey = useCallback(
- (key: string) => {
- onChangeNode({
- moduleId,
- type: 'outputs',
- key: '',
- value: flowOutputList.filter((output) => output.key !== key)
- });
- },
- [moduleId, flowOutputList, onChangeNode]
- );
- const updateOutput = useCallback(
- (key: string, val: FlowOutputItemType) => {
- onChangeNode({
- moduleId,
- type: 'outputs',
- key: '',
- value: flowOutputList.map((output) => (output.key === key ? val : output))
- });
- },
- [flowOutputList, moduleId, onChangeNode]
- );
- const addUpdateOutput = useCallback(
- (val: FlowOutputItemType) => {
- onChangeNode({
- moduleId,
- type: 'outputs',
- key: '',
- value: flowOutputList.concat(val)
- });
- },
- [flowOutputList, moduleId, onChangeNode]
- );
-
return (
<>
{flowOutputList.map(
@@ -137,9 +111,7 @@ const RenderOutput = ({
moduleId={moduleId}
onChangeNode={onChangeNode}
outputKey={item.key}
- delOutputByKey={delOutputByKey}
- addUpdateOutput={addUpdateOutput}
- updateOutput={updateOutput}
+ outputs={flowOutputList}
{...item}
/>
diff --git a/client/src/pages/app/detail/components/AdEdit/components/render/TargetHandle.tsx b/client/src/pages/app/detail/components/AdEdit/components/render/TargetHandle.tsx
index 8eb0198f2..4c710a50f 100644
--- a/client/src/pages/app/detail/components/AdEdit/components/render/TargetHandle.tsx
+++ b/client/src/pages/app/detail/components/AdEdit/components/render/TargetHandle.tsx
@@ -21,6 +21,7 @@ const TargetHandle = ({ handleKey, valueType, onConnect, ...props }: Props) => {
return (
{
}}
type="target"
id={handleKey}
- datatype={valueStyle}
position={Position.Left}
/>
@@ -44,4 +44,4 @@ const TargetHandle = ({ handleKey, valueType, onConnect, ...props }: Props) => {
);
};
-export default TargetHandle;
+export default React.memo(TargetHandle);
diff --git a/client/src/pages/app/detail/components/AdEdit/index.tsx b/client/src/pages/app/detail/components/AdEdit/index.tsx
index 7fb8bdba6..608a9fe61 100644
--- a/client/src/pages/app/detail/components/AdEdit/index.tsx
+++ b/client/src/pages/app/detail/components/AdEdit/index.tsx
@@ -125,6 +125,36 @@ const AppEdit = ({ app, fullScreen, onFullScreen }: Props) => {
}, 100);
}, []);
+ const onDelNode = useCallback(
+ (nodeId: string) => {
+ setNodes((state) => state.filter((item) => item.id !== nodeId));
+ setEdges((state) => state.filter((edge) => edge.source !== nodeId && edge.target !== nodeId));
+ },
+ [setEdges, setNodes]
+ );
+ const onDelEdge = useCallback(
+ ({
+ moduleId,
+ sourceHandle,
+ targetHandle
+ }: {
+ moduleId: string;
+ sourceHandle?: string;
+ targetHandle?: string;
+ }) => {
+ if (!sourceHandle && !targetHandle) return;
+ setEdges((state) =>
+ state.filter((edge) => {
+ if (edge.source === moduleId && edge.sourceHandle === sourceHandle) return false;
+ if (edge.target === moduleId && edge.targetHandle === targetHandle) return false;
+
+ return true;
+ })
+ );
+ },
+ [setEdges]
+ );
+
const flow2AppModules = useCallback(() => {
const modules: AppModuleItemType[] = nodes.map((item) => ({
moduleId: item.data.moduleId,
@@ -203,6 +233,7 @@ const AppEdit = ({ app, fullScreen, onFullScreen }: Props) => {
};
}
if (type === 'delInput') {
+ onDelEdge({ moduleId, targetHandle: key });
return {
...node,
data: {
@@ -211,7 +242,14 @@ const AppEdit = ({ app, fullScreen, onFullScreen }: Props) => {
}
};
}
- console.log(value);
+
+ // del output connect
+ const delOutputs = node.data.outputs.filter(
+ (item) => !value.find((output: FlowOutputTargetItemType) => output.key === item.key)
+ );
+ delOutputs.forEach((output) => {
+ onDelEdge({ moduleId, sourceHandle: output.key });
+ });
return {
...node,
@@ -225,35 +263,6 @@ const AppEdit = ({ app, fullScreen, onFullScreen }: Props) => {
},
[setNodes]
);
- const onDelNode = useCallback(
- (nodeId: string) => {
- setNodes((state) => state.filter((item) => item.id !== nodeId));
- setEdges((state) => state.filter((edge) => edge.source !== nodeId && edge.target !== nodeId));
- },
- [setEdges, setNodes]
- );
- const onDelEdge = useCallback(
- ({
- moduleId,
- sourceHandle,
- targetHandle
- }: {
- moduleId: string;
- sourceHandle?: string;
- targetHandle?: string;
- }) => {
- if (!sourceHandle && !targetHandle) return;
- setEdges((state) =>
- state.filter((edge) => {
- if (edge.source === moduleId && edge.sourceHandle === sourceHandle) return false;
- if (edge.target === moduleId && edge.targetHandle === targetHandle) return false;
-
- return true;
- })
- );
- },
- [setEdges]
- );
const onAddNode = useCallback(
({ template, position }: { template: FlowModuleTemplateType; position: XYPosition }) => {
diff --git a/client/src/service/moduleDispatch/agent/extract.ts b/client/src/service/moduleDispatch/agent/extract.ts
index 7a5ea90eb..b6fcc430a 100644
--- a/client/src/service/moduleDispatch/agent/extract.ts
+++ b/client/src/service/moduleDispatch/agent/extract.ts
@@ -66,7 +66,7 @@ export async function dispatchContentExtract({
// function body
const agentFunction = {
name: agentFunName,
- description: `${description}\n如果内容不存在,返回空字符串。当前时间是2023/7/31 18:00`,
+ description: `${description}\n如果内容不存在,返回空字符串。`,
parameters: {
type: 'object',
properties,
diff --git a/client/src/service/moduleDispatch/index.ts b/client/src/service/moduleDispatch/index.ts
index a84cc7783..2d30518ae 100644
--- a/client/src/service/moduleDispatch/index.ts
+++ b/client/src/service/moduleDispatch/index.ts
@@ -3,4 +3,6 @@ export * from './init/userChatInput';
export * from './chat/oneapi';
export * from './kb/search';
export * from './tools/answer';
+export * from './tools/http';
export * from './agent/classifyQuestion';
+export * from './agent/extract';
diff --git a/client/src/service/moduleDispatch/tools/http.ts b/client/src/service/moduleDispatch/tools/http.ts
new file mode 100644
index 000000000..10c963102
--- /dev/null
+++ b/client/src/service/moduleDispatch/tools/http.ts
@@ -0,0 +1,51 @@
+import { HttpPropsEnum } from '@/constants/flow/flowField';
+import type { NextApiResponse } from 'next';
+
+export type HttpRequestProps = {
+ res: NextApiResponse;
+ stream: boolean;
+ userOpenaiAccount: any;
+ [HttpPropsEnum.url]: string;
+ [key: string]: any;
+};
+export type HttpResponse = {
+ [HttpPropsEnum.finish]: boolean;
+ [HttpPropsEnum.failed]?: boolean;
+ [key: string]: any;
+};
+
+export const dispatchHttpRequest = async (props: Record): Promise => {
+ const { res, stream, userOpenaiAccount, url, ...body } = props as HttpRequestProps;
+
+ try {
+ const response = await fetchData({ url, body });
+
+ return {
+ [HttpPropsEnum.finish]: true,
+ ...response
+ };
+ } catch (error) {
+ return {
+ [HttpPropsEnum.finish]: true,
+ [HttpPropsEnum.failed]: true
+ };
+ }
+};
+
+async function fetchData({
+ url,
+ body
+}: {
+ url: string;
+ body: Record;
+}): Promise> {
+ const response = await fetch(url, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify(body)
+ }).then((res) => res.json());
+
+ return response;
+}
diff --git a/client/src/service/moduleDispatch/tools/httpRequest.ts b/client/src/service/moduleDispatch/tools/httpRequest.ts
deleted file mode 100644
index c292b97c7..000000000
--- a/client/src/service/moduleDispatch/tools/httpRequest.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-import { sseResponseEventEnum, TaskResponseKeyEnum } from '@/constants/chat';
-import { sseResponse } from '@/service/utils/tools';
-import { textAdaptGptResponse } from '@/utils/adapt';
-import type { NextApiResponse } from 'next';
-
-export type AnswerProps = {
- res: NextApiResponse;
- text: string;
- stream: boolean;
-};
-export type AnswerResponse = {
- [TaskResponseKeyEnum.answerText]: string;
-};
-
-export const dispatchAnswer = (props: Record): AnswerResponse => {
- const { res, text = '', stream } = props as AnswerProps;
-
- if (stream) {
- sseResponse({
- res,
- event: sseResponseEventEnum.answer,
- data: textAdaptGptResponse({
- text: text.replace(/\\n/g, '\n')
- })
- });
- }
-
- return {
- [TaskResponseKeyEnum.answerText]: text
- };
-};