feat(web): llm node add memory config
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
import React, { useState, useImperativeHandle, forwardRef, useRef } from 'react';
|
||||
import { Button, Input, Space, Typography, Tooltip, message, List } from 'antd';
|
||||
import { PlusOutlined, EditOutlined, DeleteOutlined } from '@ant-design/icons';
|
||||
import { useState, useImperativeHandle, forwardRef, useRef } from 'react';
|
||||
import { Button, Space, List } from 'antd';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import type { ChatVariable, AddChatVariableRef } from '../../types';
|
||||
import type { ChatVariableModalRef } from './types'
|
||||
|
||||
@@ -131,7 +131,7 @@ const EditableTable: React.FC<EditableTableProps> = ({
|
||||
const AddButton = ({ block = false }: { block?: boolean }) => (
|
||||
<Button
|
||||
type={block ? "dashed" : "text"}
|
||||
icon={<PlusOutlined />}
|
||||
icon={block ? undefined : <PlusOutlined />}
|
||||
onClick={() => add(createNewRow())}
|
||||
size="small"
|
||||
block={block}
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
import { type FC } from "react";
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Form, Row, Col, Divider, Switch, Slider } from 'antd'
|
||||
import type { Suggestion } from '../../Editor/plugin/AutocompletePlugin'
|
||||
import MessageEditor from '../MessageEditor'
|
||||
|
||||
const MemoryConfig: FC<{ options: Suggestion[]; parentName: string; }> = ({
|
||||
options,
|
||||
parentName
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const form = Form.useFormInstance();
|
||||
const values = Form.useWatch([], form) || {}
|
||||
|
||||
console.log('MemoryConfig', values)
|
||||
|
||||
const handleChangeEnable = (value: boolean) => {
|
||||
if (value) {
|
||||
form.setFieldsValue({
|
||||
memory: {
|
||||
...form.getFieldValue(parentName),
|
||||
enable_window: false,
|
||||
window_size: 20,
|
||||
messages: "{{sys.message}}"
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{values?.memory?.enable && <>
|
||||
<div className="rb:flex rb:items-center rb:justify-between rb:py-1.5 rb:px-2 rb:bg-[#F6F8FC] rb:rounded-md rb:mb-2">
|
||||
{t('workflow.config.llm.memory')}
|
||||
<span>{t('workflow.config.llm.inner')}</span>
|
||||
</div>
|
||||
<Form.Item layout="horizontal" name={[parentName, 'messages']}>
|
||||
<MessageEditor
|
||||
title="USER"
|
||||
isArray={false}
|
||||
parentName={[parentName, 'messages']}
|
||||
options={options}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Divider />
|
||||
</>}
|
||||
<Form.Item layout="horizontal" name={[parentName, 'enable']} label={t('workflow.config.llm.memory')}>
|
||||
<Switch onChange={handleChangeEnable} />
|
||||
</Form.Item>
|
||||
{values?.memory?.enable && <>
|
||||
<Row className="rb:mb-3">
|
||||
<Col span={10}>
|
||||
<Form.Item layout="horizontal" name={[parentName, 'enable_window']} noStyle>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
<span className="rb:ml-2">{t('workflow.config.llm.enable_window')}</span>
|
||||
</Col>
|
||||
<Col span={14}>
|
||||
<Form.Item layout="horizontal" name={[parentName, 'window_size']} noStyle>
|
||||
<Slider min={1} max={100} step={1} className="rb:my-0!" disabled={!values?.memory?.enable_window} />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
</Row>
|
||||
</>}
|
||||
</>
|
||||
);
|
||||
};
|
||||
export default MemoryConfig;
|
||||
@@ -127,7 +127,7 @@ const MessageEditor: FC<MessageEditor> = ({
|
||||
</Space>
|
||||
);
|
||||
})}
|
||||
<Form.Item>
|
||||
<Form.Item noStyle>
|
||||
<Button type="dashed" onClick={() => handleAdd(add)} block>
|
||||
+{t('workflow.addMessage')}
|
||||
</Button>
|
||||
|
||||
@@ -22,6 +22,7 @@ import ConditionList from './ConditionList'
|
||||
import CycleVarsList from './CycleVarsList'
|
||||
import AssignmentList from './AssignmentList'
|
||||
import ToolConfig from './ToolConfig'
|
||||
import MemoryConfig from './MemoryConfig'
|
||||
// import { calculateVariableList } from './utils/variableListCalculator'
|
||||
|
||||
interface PropertiesProps {
|
||||
@@ -1230,6 +1231,20 @@ const Properties: FC<PropertiesProps> = ({
|
||||
</Form.Item>
|
||||
)
|
||||
}
|
||||
if (config.type === 'memoryConfig') {
|
||||
return (
|
||||
<Form.Item
|
||||
key={key}
|
||||
name={key}
|
||||
noStyle
|
||||
>
|
||||
<MemoryConfig
|
||||
parentName={key}
|
||||
options={getFilteredVariableList('llm')}
|
||||
/>
|
||||
</Form.Item>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<Form.Item
|
||||
|
||||
@@ -135,6 +135,14 @@ export const nodeLibrary: NodeLibrary[] = [
|
||||
readonly: true
|
||||
},
|
||||
]
|
||||
},
|
||||
memory: {
|
||||
type: 'memoryConfig',
|
||||
defaultValue: {
|
||||
enable: false,
|
||||
enable_window: false,
|
||||
window_size: 20
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -750,10 +758,6 @@ export const outputVariable: { [key: string]: OutputVariable } = {
|
||||
{ name: "body", type: "string" },
|
||||
{ name: "status_code", type: "number" },
|
||||
],
|
||||
error: [
|
||||
{ name: "error_message", type: "string" },
|
||||
{ name: "error_type", type: "string" },
|
||||
]
|
||||
},
|
||||
'tool': {
|
||||
default: [
|
||||
|
||||
@@ -6,7 +6,7 @@ import { Graph, Node, MiniMap, Snapline, Clipboard, Keyboard, type Edge } from '
|
||||
import { register } from '@antv/x6-react-shape';
|
||||
|
||||
import { nodeRegisterLibrary, graphNodeLibrary, nodeLibrary, portMarkup, portAttrs } from '../constant';
|
||||
import type { WorkflowConfig, NodeProperties } from '../types';
|
||||
import type { WorkflowConfig, NodeProperties, ChatVariable } from '../types';
|
||||
import { getWorkflowConfig, saveWorkflowConfig } from '@/api/application'
|
||||
import type { PortMetadata } from '@antv/x6/lib/model/port';
|
||||
|
||||
@@ -35,6 +35,8 @@ export interface UseWorkflowGraphReturn {
|
||||
copyEvent: () => boolean | void;
|
||||
parseEvent: () => boolean | void;
|
||||
handleSave: (flag?: boolean) => Promise<unknown>;
|
||||
chatVariables: ChatVariable[];
|
||||
setChatVariables: React.Dispatch<React.SetStateAction<ChatVariable[]>>;
|
||||
}
|
||||
|
||||
export const edge_color = '#155EEF';
|
||||
@@ -54,6 +56,7 @@ export const useWorkflowGraph = ({
|
||||
const [canRedo, setCanRedo] = useState(false);
|
||||
const [isHandMode, setIsHandMode] = useState(false);
|
||||
const [config, setConfig] = useState<WorkflowConfig | null>(null);
|
||||
const [chatVariables, setChatVariables] = useState<ChatVariable[]>([])
|
||||
|
||||
useEffect(() => {
|
||||
getConfig()
|
||||
@@ -63,16 +66,15 @@ export const useWorkflowGraph = ({
|
||||
getWorkflowConfig(id)
|
||||
.then(res => {
|
||||
const { variables, ...rest } = res as WorkflowConfig
|
||||
setConfig({
|
||||
...rest,
|
||||
variables: variables.map(v => {
|
||||
const { default: _, ...cleanV } = v
|
||||
return {
|
||||
...cleanV,
|
||||
defaultValue: v.default ?? ''
|
||||
}
|
||||
})
|
||||
const initChatVariables = variables.map(v => {
|
||||
const { default: _, ...cleanV } = v
|
||||
return {
|
||||
...cleanV,
|
||||
defaultValue: v.default ?? ''
|
||||
}
|
||||
})
|
||||
setChatVariables(initChatVariables)
|
||||
setConfig({ ...rest, variables: initChatVariables })
|
||||
})
|
||||
}
|
||||
|
||||
@@ -94,7 +96,17 @@ export const useWorkflowGraph = ({
|
||||
|
||||
if (nodeLibraryConfig?.config) {
|
||||
Object.keys(nodeLibraryConfig.config).forEach(key => {
|
||||
if (key === 'knowledge_retrieval' && nodeLibraryConfig.config && nodeLibraryConfig.config[key]) {
|
||||
if (key === 'memory' && nodeLibraryConfig.config && nodeLibraryConfig.config[key]) {
|
||||
const { memory, messages } = config as any;
|
||||
if (memory?.enable && messages && messages.length > 0) {
|
||||
const lastMessage = messages[messages.length - 1]
|
||||
nodeLibraryConfig.config[key].defaultValue = {
|
||||
...memory,
|
||||
messages: lastMessage.content
|
||||
}
|
||||
nodeLibraryConfig.config.messages.defaultValue.splice(-1, 1)
|
||||
}
|
||||
} else if (key === 'knowledge_retrieval' && nodeLibraryConfig.config && nodeLibraryConfig.config[key]) {
|
||||
const { query, ...rest } = config
|
||||
nodeLibraryConfig.config[key].defaultValue = {
|
||||
...rest
|
||||
@@ -917,13 +929,13 @@ export const useWorkflowGraph = ({
|
||||
|
||||
const params = {
|
||||
...config,
|
||||
variables: config.variables.map(v => {
|
||||
const { defaultValue, ...cleanV } = v
|
||||
return {
|
||||
...cleanV,
|
||||
default: defaultValue ?? ''
|
||||
}
|
||||
}),
|
||||
variables: chatVariables.map(v => {
|
||||
const { defaultValue, ...cleanV } = v
|
||||
return {
|
||||
...cleanV,
|
||||
default: defaultValue ?? ''
|
||||
}
|
||||
}),
|
||||
nodes: nodes.map((node: Node) => {
|
||||
const data = node.getData();
|
||||
const position = node.getPosition();
|
||||
@@ -931,7 +943,15 @@ export const useWorkflowGraph = ({
|
||||
|
||||
if (data.config) {
|
||||
Object.keys(data.config).forEach(key => {
|
||||
if (data.config[key] && 'defaultValue' in data.config[key] && key === 'group_variables') {
|
||||
if (key === 'memory' && data.config[key] && 'defaultValue' in data.config[key]) {
|
||||
const { messages, ...rest } = data.config[key].defaultValue
|
||||
let memoryMessage = { role: 'USER', content: data.config[key].defaultValue.messages }
|
||||
itemConfig = {
|
||||
...itemConfig,
|
||||
messages: rest.enable ? [...itemConfig.messages, memoryMessage] : itemConfig.messages,
|
||||
memory: { ...rest },
|
||||
}
|
||||
} else if (data.config[key] && 'defaultValue' in data.config[key] && key === 'group_variables') {
|
||||
let group_variables = data.config.group.defaultValue ? {} : data.config[key].defaultValue
|
||||
if (data.config.group.defaultValue) {
|
||||
data.config[key].defaultValue.map((vo: any) => {
|
||||
@@ -1077,5 +1097,7 @@ export const useWorkflowGraph = ({
|
||||
copyEvent,
|
||||
parseEvent,
|
||||
handleSave,
|
||||
chatVariables,
|
||||
setChatVariables
|
||||
};
|
||||
};
|
||||
|
||||
@@ -8,7 +8,7 @@ import PortClickHandler from './components/PortClickHandler';
|
||||
import { useWorkflowGraph } from './hooks/useWorkflowGraph';
|
||||
import type { WorkflowRef } from '@/views/ApplicationConfig/types'
|
||||
import Chat from './components/Chat/Chat';
|
||||
import type { ChatRef, AddChatVariableRef, ChatVariable } from './types'
|
||||
import type { ChatRef, AddChatVariableRef } from './types'
|
||||
import arrowIcon from '@/assets/images/workflow/arrow.png'
|
||||
import AddChatVariable from './components/AddChatVariable';
|
||||
|
||||
@@ -21,7 +21,6 @@ const Workflow = forwardRef<WorkflowRef>((_props, ref) => {
|
||||
// 使用自定义Hook初始化工作流图
|
||||
const {
|
||||
config,
|
||||
setConfig,
|
||||
graphRef,
|
||||
selectedNode,
|
||||
setSelectedNode,
|
||||
@@ -38,6 +37,8 @@ const Workflow = forwardRef<WorkflowRef>((_props, ref) => {
|
||||
copyEvent,
|
||||
parseEvent,
|
||||
handleSave,
|
||||
chatVariables,
|
||||
setChatVariables
|
||||
} = useWorkflowGraph({ containerRef, miniMapRef });
|
||||
|
||||
const onDragOver = (event: React.DragEvent) => {
|
||||
@@ -52,15 +53,6 @@ const Workflow = forwardRef<WorkflowRef>((_props, ref) => {
|
||||
const addVariable = () => {
|
||||
addChatVariableRef.current?.handleOpen()
|
||||
}
|
||||
const handleUpdateChatVariable = (variables: ChatVariable[]) => {
|
||||
setConfig(prev => {
|
||||
if (!prev) return null
|
||||
return {
|
||||
...prev,
|
||||
variables
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
handleSave,
|
||||
@@ -125,8 +117,8 @@ const Workflow = forwardRef<WorkflowRef>((_props, ref) => {
|
||||
|
||||
<AddChatVariable
|
||||
ref={addChatVariableRef}
|
||||
variables={config?.variables}
|
||||
onChange={handleUpdateChatVariable}
|
||||
variables={chatVariables}
|
||||
onChange={setChatVariables}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user