Skip to content

Commit 234a1c5

Browse files
authored
fix: AI Node Multi Modal Add Visual Switch (#6166)
1 parent cb361fa commit 234a1c5

6 files changed

Lines changed: 85 additions & 55 deletions

File tree

apps/application/flow/step_node/ai_chat_step_node/i_chat_node.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ class ChatNodeSerializer(serializers.Serializer):
5353

5454
image_list = serializers.ListField(required=False, label=_("picture"))
5555

56+
vision = serializers.BooleanField(required=False, default=False, label=_("vision"))
57+
5658

5759
class IChatNode(INode):
5860
type = 'ai-chat-node'

apps/application/flow/step_node/ai_chat_step_node/impl/base_chat_node.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -391,15 +391,21 @@ def get_history_message(history_chat_record, dialogue_number, dialogue_type, run
391391
def generate_prompt_question(self, prompt, model):
392392
image = self.get_image()
393393
video = self.get_video()
394+
vision = self.is_vision()
394395
videos = []
395396
images = []
396-
if image:
397+
if image and vision:
397398
images = self._process_images(image)
398-
if video:
399+
if video and vision:
399400
videos = self._process_videos(video, model)
400401
return HumanMessage(
401402
content=[*videos, *images, {'type': 'text', 'text': self.workflow_manage.generate_prompt(prompt)}])
402403

404+
def is_vision(self):
405+
if 'vision' in self.node_params_serializer.data:
406+
return self.node_params_serializer.data.get('vision')
407+
return False
408+
403409
def get_image(self):
404410
if 'image_list' in self.node_params_serializer.data:
405411
image = self.workflow_manage.get_reference_field(self.node_params_serializer.data.get('image_list')[0],

ui/src/locales/lang/en-US/workflow.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,9 @@ export default {
156156
label: 'AI Chat',
157157
text: 'Chat with an AI model',
158158
answer: 'AI Content',
159+
vision: {
160+
label: 'vision',
161+
},
159162
returnContent: {
160163
label: 'Return Content',
161164
tooltip: `If turned off, the content of this node will not be output to the user.

ui/src/locales/lang/zh-CN/workflow.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,9 @@ export default {
157157
label: 'AI 对话',
158158
text: '与 AI 大模型进行对话',
159159
answer: 'AI 回答内容',
160+
vision: {
161+
label: '视觉',
162+
},
160163
returnContent: {
161164
label: '返回内容',
162165
tooltip: `关闭后该节点的内容则不输出给用户。

ui/src/locales/lang/zh-Hant/workflow.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,9 @@ export default {
156156
label: 'AI 對話',
157157
text: '與 AI 大模型進行對話',
158158
answer: 'AI 回答內容',
159+
vision: {
160+
label: '視覺',
161+
},
159162
returnContent: {
160163
label: '返回內容',
161164
tooltip: `關閉後該節點的內容則不輸出給用戶。

ui/src/workflow/nodes/ai-chat-node/index.vue

Lines changed: 66 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -170,60 +170,66 @@
170170
:step-strictly="true"
171171
/>
172172
</el-form-item>
173-
<el-form-item
174-
:rules="{
175-
type: 'array',
176-
required: true,
177-
message: $t('workflow.nodes.imageUnderstandNode.image.requiredMessage'),
178-
trigger: 'change',
179-
}"
180-
>
181-
<div class="flex align-center">
182-
<div>
183-
<span>{{ $t('workflow.nodes.imageUnderstandNode.image.label') }} </span>
173+
<div class="flex" style="justify-content: space-between">
174+
{{ t('workflow.nodes.aiChatNode.vision.label') }}
175+
<el-switch size="small" v-model="vision" />
176+
</div>
177+
<template v-if="vision">
178+
<el-form-item
179+
:rules="{
180+
type: 'array',
181+
required: true,
182+
message: $t('workflow.nodes.imageUnderstandNode.image.requiredMessage'),
183+
trigger: 'change',
184+
}"
185+
>
186+
<div class="flex align-center">
187+
<div>
188+
<span>{{ $t('workflow.nodes.imageUnderstandNode.image.label') }} </span>
189+
</div>
190+
<el-tooltip effect="dark" placement="right">
191+
<template #content>
192+
<div style="white-space: pre-wrap; font-family: monospace">{{ fileTooltip }}</div>
193+
</template>
194+
<AppIcon iconName="app-warning" class="app-warning-icon"></AppIcon>
195+
</el-tooltip>
184196
</div>
185-
<el-tooltip effect="dark" placement="right">
186-
<template #content>
187-
<div style="white-space: pre-wrap; font-family: monospace">{{ fileTooltip }}</div>
188-
</template>
189-
<AppIcon iconName="app-warning" class="app-warning-icon"></AppIcon>
190-
</el-tooltip>
191-
</div>
192-
<NodeCascader
193-
ref="nodeCascaderRef"
194-
:nodeModel="nodeModel"
195-
class="w-full"
196-
:placeholder="$t('workflow.nodes.imageUnderstandNode.image.requiredMessage')"
197-
v-model="chat_data.image_list"
198-
/>
199-
</el-form-item>
200-
<el-form-item
201-
:rules="{
202-
type: 'array',
203-
required: false,
204-
message: $t('workflow.nodes.videoUnderstandNode.video.requiredMessage'),
205-
trigger: 'change',
206-
}"
207-
>
208-
<div class="flex align-center">
209-
<div>
210-
<span>{{ $t('workflow.nodes.videoUnderstandNode.video.label') }} </span>
197+
<NodeCascader
198+
ref="nodeCascaderRef"
199+
:nodeModel="nodeModel"
200+
class="w-full"
201+
:placeholder="$t('workflow.nodes.imageUnderstandNode.image.requiredMessage')"
202+
v-model="chat_data.image_list"
203+
/>
204+
</el-form-item>
205+
<el-form-item
206+
:rules="{
207+
type: 'array',
208+
required: false,
209+
message: $t('workflow.nodes.videoUnderstandNode.video.requiredMessage'),
210+
trigger: 'change',
211+
}"
212+
>
213+
<div class="flex align-center">
214+
<div>
215+
<span>{{ $t('workflow.nodes.videoUnderstandNode.video.label') }} </span>
216+
</div>
217+
<el-tooltip effect="dark" placement="right">
218+
<template #content>
219+
<div style="white-space: pre-wrap; font-family: monospace">{{ fileTooltip }}</div>
220+
</template>
221+
<AppIcon iconName="app-warning" class="app-warning-icon"></AppIcon>
222+
</el-tooltip>
211223
</div>
212-
<el-tooltip effect="dark" placement="right">
213-
<template #content>
214-
<div style="white-space: pre-wrap; font-family: monospace">{{ fileTooltip }}</div>
215-
</template>
216-
<AppIcon iconName="app-warning" class="app-warning-icon"></AppIcon>
217-
</el-tooltip>
218-
</div>
219-
<NodeCascader
220-
ref="nodeCascaderRef"
221-
:nodeModel="nodeModel"
222-
class="w-full"
223-
:placeholder="$t('workflow.nodes.videoUnderstandNode.video.requiredMessage')"
224-
v-model="chat_data.video_list"
225-
/>
226-
</el-form-item>
224+
<NodeCascader
225+
ref="nodeCascaderRef"
226+
:nodeModel="nodeModel"
227+
class="w-full"
228+
:placeholder="$t('workflow.nodes.videoUnderstandNode.video.requiredMessage')"
229+
v-model="chat_data.video_list"
230+
/> </el-form-item
231+
></template>
232+
227233
<div class="mb-8 mt-12 flex-between">
228234
<span class="mr-4 lighter">
229235
{{ $t('views.tool.skill.title') }}
@@ -616,7 +622,14 @@ const route = useRoute()
616622
const {
617623
params: { id },
618624
} = route as any
619-
625+
const vision = computed({
626+
get: () => {
627+
return props.nodeModel.properties.node_data.vision
628+
},
629+
set: (vision: boolean) => {
630+
set(props.nodeModel.properties.node_data, 'vision', vision)
631+
},
632+
})
620633
const apiType = computed(() => {
621634
if (route.path.includes('resource-management')) {
622635
return 'systemManage'

0 commit comments

Comments
 (0)