Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
赵月辉
/
fastgpt-migrated
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Unverified
Commit
59bd2a47
authored
May 06, 2024
by
heheer
Committed by
GitHub
May 06, 2024
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: add update variable node (#1362)
* feat: add variable update node * fix * fix * change component quote
parent
d057ba29
Show whitespace changes
Inline
Side-by-side
Showing
25 changed files
with
503 additions
and
36 deletions
+503
-36
packages/global/core/workflow/constants.ts
+4
-1
packages/global/core/workflow/node/constant.ts
+2
-1
packages/global/core/workflow/runtime/constants.ts
+2
-1
packages/global/core/workflow/template/constants.ts
+8
-5
packages/global/core/workflow/template/system/variableUpdate/index.tsx
+35
-0
packages/global/core/workflow/template/system/variableUpdate/type.d.ts
+5
-0
packages/service/core/workflow/dispatch/index.ts
+6
-3
packages/service/core/workflow/dispatch/init/systemConfig.tsx
+4
-0
packages/service/core/workflow/dispatch/init/systemConfiig.tsx
+0
-10
packages/service/core/workflow/dispatch/tools/runUpdateVar.ts
+53
-0
packages/service/core/workflow/dispatch/type.d.ts
+1
-0
packages/service/core/workflow/dispatchV1/type.d.ts
+1
-0
projects/app/i18n/en/common.json
+69
-2
projects/app/i18n/zh/common.json
+3
-1
projects/app/src/components/ChatBox/index.tsx
+4
-0
projects/app/src/components/core/workflow/Flow/ChatTest.tsx
+2
-2
projects/app/src/components/core/workflow/Flow/index.tsx
+2
-1
projects/app/src/components/core/workflow/Flow/nodes/NodeVariableUpdate.tsx
+277
-0
projects/app/src/pages/api/core/chat/chatTest.ts
+6
-1
projects/app/src/pages/api/v1/chat/completions.ts
+7
-2
projects/app/src/pages/chat/index.tsx
+2
-2
projects/app/src/pages/chat/share.tsx
+2
-2
projects/app/src/pages/chat/team.tsx
+2
-2
projects/app/src/service/utils/chat/saveChat.ts
+1
-0
projects/app/src/web/common/api/fetch.ts
+5
-0
No files found.
packages/global/core/workflow/constants.ts
View file @
59bd2a47
...
...
@@ -101,7 +101,10 @@ export enum NodeInputKeyEnum {
// if else
condition
=
'condition'
,
ifElseList
=
'ifElseList'
ifElseList
=
'ifElseList'
,
// variable update
updateList
=
'updateList'
}
export
enum
NodeOutputKeyEnum
{
...
...
packages/global/core/workflow/node/constant.ts
View file @
59bd2a47
...
...
@@ -112,7 +112,8 @@ export enum FlowNodeTypeEnum {
tools
=
'tools'
,
stopTool
=
'stopTool'
,
lafModule
=
'lafModule'
,
ifElseNode
=
'ifElseNode'
ifElseNode
=
'ifElseNode'
,
variableUpdate
=
'variableUpdate'
}
export
const
EDGE_TYPE
=
'default'
;
packages/global/core/workflow/runtime/constants.ts
View file @
59bd2a47
...
...
@@ -9,7 +9,8 @@ export enum SseResponseEventEnum {
toolCall
=
'toolCall'
,
// tool start
toolParams
=
'toolParams'
,
// tool params return
toolResponse
=
'toolResponse'
,
// tool response return
flowResponses
=
'flowResponses'
// sse response request
flowResponses
=
'flowResponses'
,
// sse response request
variables
=
'variables'
}
export
enum
DispatchNodeResponseKeyEnum
{
...
...
packages/global/core/workflow/template/constants.ts
View file @
59bd2a47
...
...
@@ -18,10 +18,10 @@ import { PluginOutputModule } from './system/pluginOutput';
import
{
RunPluginModule
}
from
'./system/runPlugin'
;
import
{
AiQueryExtension
}
from
'./system/queryExtension'
;
import
type
{
FlowNodeTemplateType
,
nodeTemplateListType
}
from
'../type'
;
import
{
FlowNodeTemplateTypeEnum
}
from
'../../workflow/constants'
;
import
type
{
FlowNodeTemplateType
}
from
'../type'
;
import
{
lafModule
}
from
'./system/laf'
;
import
{
ifElseNode
}
from
'./system/ifElse/index'
;
import
{
variableUpdateNode
}
from
'./system/variableUpdate'
;
/* app flow module templates */
export
const
appSystemModuleTemplates
:
FlowNodeTemplateType
[]
=
[
...
...
@@ -39,7 +39,8 @@ export const appSystemModuleTemplates: FlowNodeTemplateType[] = [
HttpModule468
,
AiQueryExtension
,
lafModule
,
ifElseNode
ifElseNode
,
variableUpdateNode
];
/* plugin flow module templates */
export
const
pluginSystemModuleTemplates
:
FlowNodeTemplateType
[]
=
[
...
...
@@ -57,7 +58,8 @@ export const pluginSystemModuleTemplates: FlowNodeTemplateType[] = [
HttpModule468
,
AiQueryExtension
,
lafModule
,
ifElseNode
ifElseNode
,
variableUpdateNode
];
/* all module */
...
...
@@ -81,5 +83,6 @@ export const moduleTemplatesFlat: FlowNodeTemplateType[] = [
RunPluginModule
,
AiQueryExtension
,
lafModule
,
ifElseNode
ifElseNode
,
variableUpdateNode
];
packages/global/core/workflow/template/system/variableUpdate/index.tsx
0 → 100644
View file @
59bd2a47
import
{
FlowNodeInputTypeEnum
,
FlowNodeTypeEnum
}
from
'../../../node/constant'
;
import
{
FlowNodeTemplateType
}
from
'../../../type/index.d'
;
import
{
FlowNodeTemplateTypeEnum
,
NodeInputKeyEnum
,
WorkflowIOValueTypeEnum
}
from
'../../../constants'
;
import
{
getHandleConfig
}
from
'../../utils'
;
export
const
variableUpdateNode
:
FlowNodeTemplateType
=
{
id
:
FlowNodeTypeEnum
.
variableUpdate
,
templateType
:
FlowNodeTemplateTypeEnum
.
tools
,
flowNodeType
:
FlowNodeTypeEnum
.
variableUpdate
,
sourceHandle
:
getHandleConfig
(
true
,
true
,
true
,
true
),
targetHandle
:
getHandleConfig
(
true
,
true
,
true
,
true
),
avatar
:
'/imgs/workflow/variable.png'
,
name
:
'变量更新'
,
intro
:
'可以更新指定节点的输出值和全局变量'
,
showStatus
:
true
,
isTool
:
false
,
inputs
:
[
{
key
:
NodeInputKeyEnum
.
updateList
,
valueType
:
WorkflowIOValueTypeEnum
.
any
,
label
:
''
,
renderTypeList
:
[
FlowNodeInputTypeEnum
.
hidden
],
editField
:
{
key
:
true
,
valueType
:
true
},
value
:
[]
}
],
outputs
:
[]
};
packages/global/core/workflow/template/system/variableUpdate/type.d.ts
0 → 100644
View file @
59bd2a47
export
type
TUpdateListItem
=
{
variable
?:
ReferenceValueProps
;
value
?:
ReferenceValueProps
;
renderType
?:
FlowNodeInputTypeEnum
.
input
|
FlowNodeInputTypeEnum
.
reference
;
};
packages/service/core/workflow/dispatch/index.ts
View file @
59bd2a47
...
...
@@ -42,7 +42,8 @@ import { dispatchLafRequest } from './tools/runLaf';
import
{
dispatchIfElse
}
from
'./tools/runIfElse'
;
import
{
RuntimeEdgeItemType
}
from
'@fastgpt/global/core/workflow/type/edge'
;
import
{
getReferenceVariableValue
}
from
'@fastgpt/global/core/workflow/runtime/utils'
;
import
{
dispatchSystemConfig
}
from
'./init/systemConfiig'
;
import
{
dispatchSystemConfig
}
from
'./init/systemConfig'
;
import
{
dispatchUpdateVariable
}
from
'./tools/runUpdateVar'
;
const
callbackMap
:
Record
<
`
${
FlowNodeTypeEnum
}
`
,
Function
>
=
{
[
FlowNodeTypeEnum
.
workflowStart
]:
dispatchWorkflowStart
,
...
...
@@ -62,6 +63,7 @@ const callbackMap: Record<`${FlowNodeTypeEnum}`, Function> = {
[
FlowNodeTypeEnum
.
stopTool
]:
dispatchStopToolCall
,
[
FlowNodeTypeEnum
.
lafModule
]:
dispatchLafRequest
,
[
FlowNodeTypeEnum
.
ifElseNode
]:
dispatchIfElse
,
[
FlowNodeTypeEnum
.
variableUpdate
]:
dispatchUpdateVariable
,
// none
[
FlowNodeTypeEnum
.
systemConfig
]:
dispatchSystemConfig
,
...
...
@@ -355,7 +357,7 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
if
(
pluginOutputModule
&&
props
.
mode
!==
'debug'
)
{
await
nodeRunWithActive
(
pluginOutputModule
);
}
const
{
userChatInput
,
...
leftVariables
}
=
variables
;
return
{
flowResponses
:
chatResponses
,
flowUsages
:
chatNodeUsages
,
...
...
@@ -366,7 +368,8 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
},
[
DispatchNodeResponseKeyEnum
.
assistantResponses
]:
mergeAssistantResponseAnswerText
(
chatAssistantResponse
),
[
DispatchNodeResponseKeyEnum
.
toolResponses
]:
toolRunResponse
[
DispatchNodeResponseKeyEnum
.
toolResponses
]:
toolRunResponse
,
newVariables
:
leftVariables
};
}
...
...
packages/service/core/workflow/dispatch/init/systemConfig.tsx
0 → 100644
View file @
59bd2a47
export
const
dispatchSystemConfig
=
(
props
:
Record
<
string
,
any
>
)
=>
{
const
{
variables
}
=
props
;
return
variables
;
};
packages/service/core/workflow/dispatch/init/systemConfiig.tsx
deleted
100644 → 0
View file @
d057ba29
import
{
NodeInputKeyEnum
}
from
'@fastgpt/global/core/workflow/constants'
;
import
type
{
ModuleDispatchProps
}
from
'@fastgpt/global/core/workflow/type/index.d'
;
export
type
UserChatInputProps
=
ModuleDispatchProps
<
{
[
NodeInputKeyEnum
.
userChatInput
]:
string
;
}
>
;
export
const
dispatchSystemConfig
=
(
props
:
Record
<
string
,
any
>
)
=>
{
const
{
variables
}
=
props
as
UserChatInputProps
;
return
variables
;
};
packages/service/core/workflow/dispatch/tools/runUpdateVar.ts
0 → 100644
View file @
59bd2a47
import
{
NodeInputKeyEnum
,
VARIABLE_NODE_ID
}
from
'@fastgpt/global/core/workflow/constants'
;
import
{
DispatchNodeResponseKeyEnum
}
from
'@fastgpt/global/core/workflow/runtime/constants'
;
import
{
DispatchNodeResultType
}
from
'@fastgpt/global/core/workflow/runtime/type'
;
import
{
getReferenceVariableValue
}
from
'@fastgpt/global/core/workflow/runtime/utils'
;
import
{
TUpdateListItem
}
from
'@fastgpt/global/core/workflow/template/system/variableUpdate/type'
;
import
{
ModuleDispatchProps
}
from
'@fastgpt/global/core/workflow/type'
;
type
Props
=
ModuleDispatchProps
<
{
[
NodeInputKeyEnum
.
updateList
]:
TUpdateListItem
[];
}
>
;
export
const
dispatchUpdateVariable
=
async
(
props
:
Props
):
Promise
<
DispatchNodeResultType
<
any
>>
=>
{
const
{
params
,
variables
,
runtimeNodes
}
=
props
;
const
{
updateList
}
=
params
;
updateList
.
forEach
((
item
)
=>
{
const
varNodeId
=
item
.
variable
?.[
0
];
const
varKey
=
item
.
variable
?.[
1
];
if
(
!
varNodeId
||
!
varKey
)
{
return
;
}
let
value
=
''
;
if
(
!
item
.
value
?.[
0
])
{
value
=
item
.
value
?.[
1
];
}
else
{
value
=
getReferenceVariableValue
({
value
:
item
.
value
,
variables
,
nodes
:
runtimeNodes
});
}
if
(
varNodeId
===
VARIABLE_NODE_ID
)
{
variables
[
varKey
]
=
value
;
}
else
{
const
node
=
runtimeNodes
.
find
((
node
)
=>
node
.
nodeId
===
varNodeId
);
if
(
node
)
{
const
output
=
node
.
outputs
.
find
((
output
)
=>
output
.
id
===
varKey
);
if
(
output
)
{
output
.
value
=
value
;
}
}
}
});
return
{
[
DispatchNodeResponseKeyEnum
.
nodeResponse
]:
{
totalPoints
:
0
}
};
};
packages/service/core/workflow/dispatch/type.d.ts
View file @
59bd2a47
...
...
@@ -19,4 +19,5 @@ export type DispatchFlowResponse = {
};
[
DispatchNodeResponseKeyEnum
.
toolResponses
]:
ToolRunResponseItemType
;
[
DispatchNodeResponseKeyEnum
.
assistantResponses
]:
AIChatItemValueItemType
[];
newVariables
:
Record
<
string
,
string
>
;
};
packages/service/core/workflow/dispatchV1/type.d.ts
View file @
59bd2a47
...
...
@@ -12,4 +12,5 @@ export type DispatchFlowResponse = {
flowUsages
:
ChatNodeUsageType
[];
[
DispatchNodeResponseKeyEnum
.
toolResponses
]:
ToolRunResponseItemType
;
[
DispatchNodeResponseKeyEnum
.
assistantResponses
]:
AIChatItemValueItemType
[];
newVariables
:
Record
<
string
,
string
>
;
};
projects/app/i18n/en/common.json
View file @
59bd2a47
...
...
@@ -1050,8 +1050,75 @@
"Intro placeholder"
:
"If this plugin is invoked as a tool, this description will be used as the prompt."
},
"shareChat"
:
{
"Init Error"
:
"Conversation initialization failed"
,
"Init History Error"
:
"Chat history initialization failed"
"Init Error"
:
"Init Chat Error"
,
"Init History Error"
:
"Init History Error"
},
"workflow"
:
{
"Add variable"
:
"Add"
,
"Can not delete node"
:
"Can not delete the node"
,
"Change input type tip"
:
"Changing the input type will empty the entered values, please confirm!"
,
"Check Failed"
:
"Workflow verification fails. Check whether the node or connection is normal"
,
"Confirm stop debug"
:
"Do you want to terminate debugging? Debugging information is not retained."
,
"Copy node"
:
"Copy node"
,
"Current workflow"
:
"Current workflow"
,
"Custom inputs"
:
"Inputs"
,
"Custom outputs"
:
"Outputs"
,
"Custom variable"
:
"Custom variable"
,
"Dataset quote"
:
"Dataset quote"
,
"Debug"
:
"Debug"
,
"Debug Node"
:
"Workflow Debug"
,
"Failed"
:
"Running failed"
,
"Not intro"
:
"This node is not introduced"
,
"Run from here"
:
"Run from here"
,
"Run result"
:
"Run result"
,
"Running"
:
"Running"
,
"Skipped"
:
"Skipped"
,
"Stop debug"
:
"Stop"
,
"Success"
:
"Running success"
,
"Value type"
:
"Type"
,
"Variable outputs"
:
"Variables"
,
"chat"
:
{
"Quote prompt"
:
"Quote prompt"
},
"debug"
:
{
"Done"
:
"Done"
,
"Hide result"
:
"Hide result"
,
"Not result"
:
"Not result"
,
"Run result"
:
""
,
"Show result"
:
"Show result"
},
"inputType"
:
{
"JSON Editor"
:
"JSON Editor"
,
"Manual input"
:
""
,
"Manual select"
:
"Select"
,
"Reference"
:
"Reference"
,
"Required"
:
"Required"
,
"Select edit field"
:
"Editable field"
,
"Select input default value"
:
"Default value"
,
"Select input type"
:
"Configurable input types"
,
"Select input type placeholder"
:
"Please select a configurable input type"
,
"chat history"
:
"History"
,
"dynamicTargetInput"
:
"dynamic Target Input"
,
"input"
:
"Input"
,
"number input"
:
"number input"
,
"selectApp"
:
"App Selector"
,
"selectDataset"
:
"Dataset Selector"
,
"selectLLMModel"
:
"Select Chat Model"
,
"switch"
:
"Switch"
,
"target"
:
"Target Data"
,
"textarea"
:
"Textarea"
},
"publish"
:
{
"OnRevert version"
:
"Click back to that version"
,
"OnRevert version confirm"
:
"Are you sure to roll back the version?"
,
"histories"
:
"Publiish histories"
},
"tool"
:
{
"Handle"
:
"Tool handle"
,
"Select Tool"
:
"Select Tool"
},
"value"
:
"Value"
,
"variable"
:
"Variable"
}
},
"dataset"
:
{
...
...
projects/app/i18n/zh/common.json
View file @
59bd2a47
...
...
@@ -1160,7 +1160,9 @@
"tool"
:
{
"Handle"
:
"工具连接器"
,
"Select Tool"
:
"选择工具"
}
},
"value"
:
"值"
,
"variable"
:
"变量"
}
},
"dataset"
:
{
...
...
projects/app/src/components/ChatBox/index.tsx
View file @
59bd2a47
...
...
@@ -91,6 +91,7 @@ type Props = OutLinkChatAuthProps & {
onStartChat
?:
(
e
:
StartChatFnProps
)
=>
Promise
<
{
responseText
:
string
;
[
DispatchNodeResponseKeyEnum
.
nodeResponse
]:
ChatHistoryItemResType
[];
newVariables
?:
Record
<
string
,
any
>
;
isNewChat
?:
boolean
;
}
>
;
onDelMessage
?:
(
e
:
{
contentId
:
string
})
=>
void
;
...
...
@@ -462,6 +463,7 @@ const ChatBox = (
const
{
responseData
,
responseText
,
newVariables
,
isNewChat
=
false
}
=
await
onStartChat
({
chatList
:
newChatList
,
...
...
@@ -470,6 +472,7 @@ const ChatBox = (
generatingMessage
:
(
e
)
=>
generatingMessage
({
...
e
,
autoTTSResponse
}),
variables
});
setValue
(
'variables'
,
newVariables
||
[]);
isNewChatReplace
.
current
=
isNewChat
;
...
...
@@ -549,6 +552,7 @@ const ChatBox = (
resetInputVal
,
setAudioPlayingChatId
,
setChatHistories
,
setValue
,
splitText2Audio
,
startSegmentedAudio
,
t
,
...
...
projects/app/src/components/core/workflow/Flow/ChatTest.tsx
View file @
59bd2a47
...
...
@@ -68,7 +68,7 @@ const ChatTest = (
const
history
=
chatList
.
slice
(
-
historyMaxLen
-
2
,
-
2
);
// 流请求,获取数据
const
{
responseText
,
responseData
}
=
await
streamFetch
({
const
{
responseText
,
responseData
,
newVariables
}
=
await
streamFetch
({
url
:
'/api/core/chat/chatTest'
,
data
:
{
history
,
...
...
@@ -84,7 +84,7 @@ const ChatTest = (
abortCtrl
:
controller
});
return
{
responseText
,
responseData
};
return
{
responseText
,
responseData
,
newVariables
};
},
[
app
.
_id
,
app
.
name
,
edges
,
nodes
]
);
...
...
projects/app/src/components/core/workflow/Flow/index.tsx
View file @
59bd2a47
...
...
@@ -57,7 +57,8 @@ const nodeTypes: Record<`${FlowNodeTypeEnum}`, any> = {
<
NodeSimple
{
...
data
}
minW=
{
'100px'
}
maxW=
{
'300px'
}
/>
),
[
FlowNodeTypeEnum
.
lafModule
]:
dynamic
(()
=>
import
(
'./nodes/NodeLaf'
)),
[
FlowNodeTypeEnum
.
ifElseNode
]:
dynamic
(()
=>
import
(
'./nodes/NodeIfElse'
))
[
FlowNodeTypeEnum
.
ifElseNode
]:
dynamic
(()
=>
import
(
'./nodes/NodeIfElse'
)),
[
FlowNodeTypeEnum
.
variableUpdate
]:
dynamic
(()
=>
import
(
'./nodes/NodeVariableUpdate'
))
};
const
edgeTypes
=
{
[
EDGE_TYPE
]:
ButtonEdge
...
...
projects/app/src/components/core/workflow/Flow/nodes/NodeVariableUpdate.tsx
0 → 100644
View file @
59bd2a47
import
React
,
{
useCallback
,
useMemo
}
from
'react'
;
import
NodeCard
from
'./render/NodeCard'
;
import
{
NodeProps
}
from
'reactflow'
;
import
{
FlowNodeItemType
}
from
'@fastgpt/global/core/workflow/type'
;
import
{
useTranslation
}
from
'react-i18next'
;
import
{
Box
,
Button
,
Flex
,
NumberDecrementStepper
,
NumberIncrementStepper
,
NumberInput
,
NumberInputField
,
NumberInputStepper
,
Switch
,
Textarea
}
from
'@chakra-ui/react'
;
import
{
TUpdateListItem
}
from
'@fastgpt/global/core/workflow/template/system/variableUpdate/type'
;
import
{
NodeInputKeyEnum
,
WorkflowIOValueTypeEnum
}
from
'@fastgpt/global/core/workflow/constants'
;
import
{
useContextSelector
}
from
'use-context-selector'
;
import
{
WorkflowContext
}
from
'@/components/core/workflow/context'
;
import
{
FlowNodeInputMap
,
FlowNodeInputTypeEnum
}
from
'@fastgpt/global/core/workflow/node/constant'
;
import
Container
from
'../components/Container'
;
import
MyIcon
from
'@fastgpt/web/components/common/Icon'
;
import
JsonEditor
from
'@fastgpt/web/components/common/Textarea/JsonEditor'
;
import
{
SmallAddIcon
}
from
'@chakra-ui/icons'
;
import
MyTooltip
from
'@fastgpt/web/components/common/MyTooltip'
;
import
{
ReferenceValueProps
}
from
'@fastgpt/global/core/workflow/type/io'
;
import
{
ReferSelector
,
useReference
}
from
'./render/RenderInput/templates/Reference'
;
const
NodeVariableUpdate
=
({
data
,
selected
}:
NodeProps
<
FlowNodeItemType
>
)
=>
{
const
{
inputs
=
[],
nodeId
}
=
data
;
const
{
t
}
=
useTranslation
();
const
onChangeNode
=
useContextSelector
(
WorkflowContext
,
(
v
)
=>
v
.
onChangeNode
);
const
nodes
=
useContextSelector
(
WorkflowContext
,
(
v
)
=>
v
.
nodes
);
const
updateList
=
useMemo
(
()
=>
(
inputs
.
find
((
input
)
=>
input
.
key
===
NodeInputKeyEnum
.
updateList
)
?.
value
as
TUpdateListItem
[])
||
[],
[
inputs
]
);
const
onUpdateList
=
useCallback
(
(
value
:
TUpdateListItem
[])
=>
{
const
updateListInput
=
inputs
.
find
((
input
)
=>
input
.
key
===
NodeInputKeyEnum
.
updateList
);
if
(
!
updateListInput
)
return
;
onChangeNode
({
nodeId
,
type
:
'updateInput'
,
key
:
NodeInputKeyEnum
.
updateList
,
value
:
{
...
updateListInput
,
value
}
});
},
[
inputs
,
nodeId
,
onChangeNode
]
);
const
menuList
=
[
{
renderType
:
FlowNodeInputTypeEnum
.
input
,
icon
:
FlowNodeInputMap
[
FlowNodeInputTypeEnum
.
input
].
icon
,
label
:
t
(
'core.workflow.inputType.Manual input'
)
},
{
renderType
:
FlowNodeInputTypeEnum
.
reference
,
icon
:
FlowNodeInputMap
[
FlowNodeInputTypeEnum
.
reference
].
icon
,
label
:
t
(
'core.workflow.inputType.Reference'
)
}
];
return
(
<
NodeCard
selected=
{
selected
}
maxW=
{
'1000px'
}
{
...
data
}
>
<
Box
px=
{
4
}
pb=
{
4
}
>
{
updateList
.
map
((
updateItem
,
index
)
=>
{
const
type
=
(()
=>
{
const
variable
=
updateItem
.
variable
;
const
variableNodeId
=
variable
?.[
0
];
const
variableNode
=
nodes
.
find
((
node
)
=>
node
.
id
===
variableNodeId
);
if
(
!
variableNode
)
return
'any'
;
const
variableInput
=
variableNode
.
data
.
outputs
.
find
(
(
output
)
=>
output
.
id
===
variable
?.[
1
]
);
if
(
!
variableInput
)
return
'any'
;
return
variableInput
.
valueType
;
})();
const
renderTypeData
=
menuList
.
find
((
item
)
=>
item
.
renderType
===
updateItem
.
renderType
);
const
handleUpdate
=
(
newValue
:
any
)
=>
{
onUpdateList
(
updateList
.
map
((
update
,
i
)
=>
i
===
index
?
{
...
update
,
value
:
[
''
,
newValue
]
}
:
update
)
);
};
return
(
<
Flex
key=
{
index
}
>
<
Container
mt=
{
4
}
>
<
Flex
alignItems=
{
'center'
}
>
<
Flex
w=
{
'60px'
}
>
{
t
(
'core.workflow.variable'
)
}
</
Flex
>
<
Reference
nodeId=
{
nodeId
}
variable=
{
updateItem
.
variable
}
onSelect=
{
(
value
)
=>
{
onUpdateList
(
updateList
.
map
((
update
,
i
)
=>
{
if
(
i
===
index
)
{
return
{
...
update
,
variable
:
value
};
}
return
update
;
})
);
}
}
/>
<
Box
flex=
{
1
}
/>
<
MyIcon
className=
"delete"
name=
{
'delete'
}
w=
{
'14px'
}
color=
{
'myGray.600'
}
cursor=
{
'pointer'
}
ml=
{
2
}
_hover=
{
{
color
:
'red.500'
}
}
onClick=
{
()
=>
{
onUpdateList
(
updateList
.
filter
((
_
,
i
)
=>
i
!==
index
));
}
}
/>
</
Flex
>
<
Flex
mt=
{
2
}
w=
{
'full'
}
alignItems=
{
'center'
}
>
<
Flex
w=
{
'60px'
}
flex=
{
0
}
>
<
Box
>
{
t
(
'core.workflow.value'
)
}
</
Box
>
<
MyTooltip
label=
{
menuList
.
find
((
item
)
=>
item
.
renderType
===
updateItem
.
renderType
)?.
label
}
>
<
Button
size=
{
'xs'
}
bg=
{
'white'
}
borderRadius=
{
'xs'
}
mx=
{
2
}
onClick=
{
()
=>
{
onUpdateList
(
updateList
.
map
((
update
,
i
)
=>
{
if
(
i
===
index
)
{
return
{
...
update
,
value
:
[
''
,
''
],
renderType
:
updateItem
.
renderType
===
FlowNodeInputTypeEnum
.
input
?
FlowNodeInputTypeEnum
.
reference
:
FlowNodeInputTypeEnum
.
input
};
}
return
update
;
})
);
}
}
>
<
MyIcon
name=
{
renderTypeData
?.
icon
as
any
}
w=
{
'14px'
}
/>
</
Button
>
</
MyTooltip
>
</
Flex
>
{
updateItem
.
renderType
===
FlowNodeInputTypeEnum
.
reference
?
(
<
Reference
nodeId=
{
nodeId
}
variable=
{
updateItem
.
value
}
onSelect=
{
handleUpdate
}
/>
)
:
(
<>
{
type
===
'string'
&&
(
<
Textarea
bg=
"white"
value=
{
updateItem
.
value
?.[
1
]
||
''
}
w=
"300px"
onChange=
{
(
e
)
=>
handleUpdate
(
e
.
target
.
value
)
}
/>
)
}
{
type
===
'number'
&&
(
<
NumberInput
value=
{
Number
(
updateItem
.
value
?.[
1
])
||
0
}
>
<
NumberInputField
bg=
"white"
onChange=
{
(
e
)
=>
handleUpdate
(
e
.
target
.
value
)
}
/>
<
NumberInputStepper
>
<
NumberIncrementStepper
/>
<
NumberDecrementStepper
/>
</
NumberInputStepper
>
</
NumberInput
>
)
}
{
type
===
'boolean'
&&
(
<
Switch
size=
"lg"
defaultChecked=
{
updateItem
.
value
?.[
1
]
===
'true'
}
onChange=
{
(
e
)
=>
handleUpdate
(
String
(
e
.
target
.
checked
))
}
/>
)
}
{
type
!==
'string'
&&
type
!==
'number'
&&
type
!==
'boolean'
&&
(
<
JsonEditor
bg=
"white"
resize
w=
"300px"
value=
{
updateItem
.
value
?.[
1
]
||
''
}
onChange=
{
(
e
)
=>
handleUpdate
(
e
)
}
/>
)
}
</>
)
}
</
Flex
>
</
Container
>
</
Flex
>
);
})
}
<
Flex
className=
"nodrag"
cursor=
{
'default'
}
alignItems=
{
'center'
}
position=
{
'relative'
}
>
<
Button
variant=
{
'whiteBase'
}
leftIcon=
{
<
SmallAddIcon
/>
}
iconSpacing=
{
1
}
w=
{
'full'
}
size=
{
'sm'
}
onClick=
{
()
=>
{
onUpdateList
([
...
updateList
,
{
variable
:
[
''
,
''
],
value
:
[
''
,
''
],
renderType
:
FlowNodeInputTypeEnum
.
input
}
]);
}
}
>
{
t
(
'common.Add New'
)
}
</
Button
>
</
Flex
>
</
Box
>
</
NodeCard
>
);
};
export
default
React
.
memo
(
NodeVariableUpdate
);
const
Reference
=
({
nodeId
,
variable
,
onSelect
}:
{
nodeId
:
string
;
variable
?:
ReferenceValueProps
;
onSelect
:
(
e
:
ReferenceValueProps
)
=>
void
;
})
=>
{
const
{
t
}
=
useTranslation
();
const
{
referenceList
,
formatValue
}
=
useReference
({
nodeId
,
valueType
:
WorkflowIOValueTypeEnum
.
any
,
value
:
variable
});
return
(
<
ReferSelector
placeholder=
{
t
(
'选择引用变量'
)
}
list=
{
referenceList
}
value=
{
formatValue
}
onSelect=
{
onSelect
}
/>
);
};
projects/app/src/pages/api/core/chat/chatTest.ts
View file @
59bd2a47
...
...
@@ -69,7 +69,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
const
{
text
,
files
}
=
chatValue2RuntimePrompt
(
prompt
);
/* start process */
const
{
flowResponses
,
flowUsages
}
=
await
dispatchWorkFlow
({
const
{
flowResponses
,
flowUsages
,
newVariables
}
=
await
dispatchWorkFlow
({
res
,
mode
:
'test'
,
teamId
,
...
...
@@ -99,6 +99,11 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
event
:
SseResponseEventEnum
.
flowResponses
,
data
:
JSON
.
stringify
(
flowResponses
)
});
responseWrite
({
res
,
event
:
SseResponseEventEnum
.
variables
,
data
:
JSON
.
stringify
(
newVariables
)
});
res
.
end
();
pushChatUsage
({
...
...
projects/app/src/pages/api/v1/chat/completions.ts
View file @
59bd2a47
...
...
@@ -179,7 +179,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
const
responseChatItemId
:
string
|
undefined
=
messages
[
messages
.
length
-
1
].
dataId
;
/* start flow controller */
const
{
flowResponses
,
flowUsages
,
assistantResponses
}
=
await
(
async
()
=>
{
const
{
flowResponses
,
flowUsages
,
assistantResponses
,
newVariables
}
=
await
(
async
()
=>
{
if
(
app
.
version
===
'v2'
)
{
return
dispatchWorkFlow
({
res
,
...
...
@@ -247,7 +247,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
appId
:
app
.
_id
,
teamId
,
tmbId
:
tmbId
,
variables
,
variables
:
newVariables
,
isUpdateUseTime
:
isOwnerUse
&&
source
===
ChatSourceEnum
.
online
,
// owner update use time
shareId
,
outLinkUid
:
outLinkUserId
,
...
...
@@ -288,6 +288,11 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
event
:
detail
?
SseResponseEventEnum
.
answer
:
undefined
,
data
:
'[DONE]'
});
responseWrite
({
res
,
event
:
SseResponseEventEnum
.
variables
,
data
:
JSON
.
stringify
(
newVariables
)
});
if
(
responseDetail
&&
detail
)
{
responseWrite
({
...
...
projects/app/src/pages/chat/index.tsx
View file @
59bd2a47
...
...
@@ -74,7 +74,7 @@ const Chat = ({ appId, chatId }: { appId: string; chatId: string }) => {
const
prompts
=
messages
.
slice
(
-
2
);
const
completionChatId
=
chatId
?
chatId
:
nanoid
();
const
{
responseText
,
responseData
}
=
await
streamFetch
({
const
{
responseText
,
responseData
,
newVariables
}
=
await
streamFetch
({
data
:
{
messages
:
prompts
,
variables
,
...
...
@@ -123,7 +123,7 @@ const Chat = ({ appId, chatId }: { appId: string; chatId: string }) => {
history
:
ChatBoxRef
.
current
?.
getChatHistories
()
||
state
.
history
}));
return
{
responseText
,
responseData
,
isNewChat
:
forbidRefresh
.
current
};
return
{
responseText
,
responseData
,
isNewChat
:
forbidRefresh
.
current
,
newVariables
};
},
[
appId
,
chatId
,
histories
,
pushHistory
,
router
,
setChatData
,
updateHistory
]
);
...
...
projects/app/src/pages/chat/share.tsx
View file @
59bd2a47
...
...
@@ -95,7 +95,7 @@ const OutLink = ({
'*'
);
const
{
responseText
,
responseData
}
=
await
streamFetch
({
const
{
responseText
,
responseData
,
newVariables
}
=
await
streamFetch
({
data
:
{
messages
:
prompts
,
variables
:
{
...
...
@@ -169,7 +169,7 @@ const OutLink = ({
'*'
);
return
{
responseText
,
responseData
,
isNewChat
:
forbidRefresh
.
current
};
return
{
responseText
,
responseData
,
isNewChat
:
forbidRefresh
.
current
,
newVariables
};
},
[
chatId
,
...
...
projects/app/src/pages/chat/team.tsx
View file @
59bd2a47
...
...
@@ -79,7 +79,7 @@ const OutLink = () => {
const
prompts
=
messages
.
slice
(
-
2
);
const
completionChatId
=
chatId
?
chatId
:
nanoid
();
const
{
responseText
,
responseData
}
=
await
streamFetch
({
const
{
responseText
,
responseData
,
newVariables
}
=
await
streamFetch
({
data
:
{
messages
:
prompts
,
variables
:
{
...
...
@@ -135,7 +135,7 @@ const OutLink = () => {
history
:
ChatBoxRef
.
current
?.
getChatHistories
()
||
state
.
history
}));
return
{
responseText
,
responseData
,
isNewChat
:
forbidRefresh
.
current
};
return
{
responseText
,
responseData
,
isNewChat
:
forbidRefresh
.
current
,
newVariables
};
},
[
appId
,
teamToken
,
chatId
,
histories
,
pushHistory
,
router
,
setChatData
,
teamId
,
updateHistory
]
);
...
...
projects/app/src/service/utils/chat/saveChat.ts
View file @
59bd2a47
...
...
@@ -69,6 +69,7 @@ export async function saveChat({
chat
.
title
=
title
;
chat
.
updateTime
=
new
Date
();
chat
.
metadata
=
metadataUpdate
;
chat
.
variables
=
variables
||
{};
await
chat
.
save
({
session
});
}
else
{
await
MongoChat
.
create
(
...
...
projects/app/src/web/common/api/fetch.ts
View file @
59bd2a47
...
...
@@ -22,6 +22,7 @@ type StreamFetchProps = {
type
StreamResponseType
=
{
responseText
:
string
;
[
DispatchNodeResponseKeyEnum
.
nodeResponse
]:
ChatHistoryItemResType
[];
newVariables
:
Record
<
string
,
any
>
;
};
class
FatalError
extends
Error
{}
...
...
@@ -50,6 +51,7 @@ export const streamFetch = ({
)[]
=
[];
let
errMsg
:
string
|
undefined
;
let
responseData
:
ChatHistoryItemResType
[]
=
[];
let
newVariables
:
Record
<
string
,
any
>
=
{};
let
finished
=
false
;
const
finish
=
()
=>
{
...
...
@@ -57,6 +59,7 @@ export const streamFetch = ({
return
failedFinish
();
}
return
resolve
({
newVariables
,
responseText
,
responseData
});
...
...
@@ -198,6 +201,8 @@ export const streamFetch = ({
});
}
else
if
(
event
===
SseResponseEventEnum
.
flowResponses
&&
Array
.
isArray
(
parseJson
))
{
responseData
=
parseJson
;
}
else
if
(
event
===
SseResponseEventEnum
.
variables
)
{
newVariables
=
parseJson
;
}
else
if
(
event
===
SseResponseEventEnum
.
error
)
{
if
(
parseJson
.
statusText
===
TeamErrEnum
.
aiPointsNotEnough
)
{
useSystemStore
.
getState
().
setIsNotSufficientModal
(
true
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment