feat: i18n

This commit is contained in:
王丹 2025-01-18 17:15:31 +08:00
parent 5c4d61c45c
commit ff3f51179b
18 changed files with 333 additions and 130 deletions

View File

@ -1,7 +1,7 @@
<template> <template>
<el-dialog <el-dialog
class="execution-details-dialog" class="execution-details-dialog"
title="执行详情" :title="$t('components.chat.executionDetails.title')"
v-model="dialogVisible" v-model="dialogVisible"
destroy-on-close destroy-on-close
append-to-body append-to-body
@ -56,7 +56,9 @@
" "
> >
<div class="card-never border-r-4"> <div class="card-never border-r-4">
<h5 class="p-8-12">参数输入</h5> <h5 class="p-8-12">
{{ $t('components.chat.executionDetails.paramInput') }}
</h5>
<div class="p-8-12 border-t-dashed lighter"> <div class="p-8-12 border-t-dashed lighter">
<div class="mb-8"> <div class="mb-8">
<span class="color-secondary">用户问题:</span> <span class="color-secondary">用户问题:</span>

View File

@ -65,6 +65,7 @@ import ChatInputOperate from '@/components/ai-chat/component/chat-input-operate/
import PrologueContent from '@/components/ai-chat/component/prologue-content/index.vue' import PrologueContent from '@/components/ai-chat/component/prologue-content/index.vue'
import UserForm from '@/components/ai-chat/component/user-form/index.vue' import UserForm from '@/components/ai-chat/component/user-form/index.vue'
import Control from '@/components/ai-chat/component/control/index.vue' import Control from '@/components/ai-chat/component/control/index.vue'
import { t } from '@/locales'
defineOptions({ name: 'AiChat' }) defineOptions({ name: 'AiChat' })
const route = useRoute() const route = useRoute()
const { const {
@ -270,7 +271,7 @@ const getWrite = (chat: any, reader: any, stream: boolean) => {
const errorWrite = (chat: any, message?: string) => { const errorWrite = (chat: any, message?: string) => {
ChatManagement.addChatRecord(chat, 50, loading) ChatManagement.addChatRecord(chat, 50, loading)
ChatManagement.write(chat.id) ChatManagement.write(chat.id)
ChatManagement.append(chat.id, message || '抱歉,当前正在维护,无法提供服务,请稍后再试!') ChatManagement.append(chat.id, message || t('components.chat.tip.error500Message'))
ChatManagement.updateStatus(chat.id, 500) ChatManagement.updateStatus(chat.id, 500)
ChatManagement.close(chat.id) ChatManagement.close(chat.id)
} }
@ -343,9 +344,9 @@ function chatMessage(chat?: any, problem?: string, re_chat?: boolean, other_para
errorWrite(chat) errorWrite(chat)
}) })
} else if (response.status === 460) { } else if (response.status === 460) {
return Promise.reject('无法识别用户身份') return Promise.reject(t('components.chat.tip.errorIdentifyMessage'))
} else if (response.status === 461) { } else if (response.status === 461) {
return Promise.reject('抱歉,您的提问已达到最大限制,请明天再来吧!') return Promise.reject('components.chat.tip.errorLimitMessage')
} else { } else {
nextTick(() => { nextTick(() => {
// //

View File

@ -39,6 +39,7 @@ export default {
debug: 'Debug', debug: 'Debug',
required: 'Required', required: 'Required',
noData: 'No data', noData: 'No data',
result: 'Result',
status: { status: {
label: 'Status', label: 'Status',
enableSuccess: 'Enable Successful', enableSuccess: 'Enable Successful',

View File

@ -67,7 +67,6 @@ export default {
paramInfo1: 'Displayed when using the function', paramInfo1: 'Displayed when using the function',
paramInfo2: 'Not displayed when using the function', paramInfo2: 'Not displayed when using the function',
code: 'Code', code: 'Code',
result: 'Result'
}, },
debug: { debug: {
run: 'Run', run: 'Run',

View File

@ -39,6 +39,7 @@ export default {
debug: '调试', debug: '调试',
required: '必填', required: '必填',
noData: '暂无数据', noData: '暂无数据',
result: '结果',
status: { status: {
label: '状态', label: '状态',
enableSuccess: '启用成功', enableSuccess: '启用成功',

View File

@ -11,6 +11,13 @@ export default {
errorMessage2: '密码错误' errorMessage2: '密码错误'
}, },
executionDetails: { executionDetails: {
title: '执行详情',
paramInput: '参数输入',
paramOutput: '参数输出', paramOutput: '参数输出',
},
tip: {
error500Message: '抱歉,当前正在维护,无法提供服务,请稍后再试!',
errorIdentifyMessage: '无法识别用户身份',
errorLimitMessage:'抱歉,您的提问已达到最大限制,请明天再来吧!'
} }
} }

View File

@ -1,6 +1,8 @@
import type { result } from 'lodash'
export default { export default {
node: '节点', node: '节点',
baseNodes: '基础组件', baseComponent: '基础组件',
searchBar: { searchBar: {
placeholder: '按名称搜索' placeholder: '按名称搜索'
}, },
@ -27,10 +29,21 @@ export default {
onlylest: '只允许连接左边的锚点', onlylest: '只允许连接左边的锚点',
applicationNodeError: '该应用不可用', applicationNodeError: '该应用不可用',
functionNodeError: '该函数不可用', functionNodeError: '该函数不可用',
repeatedNodeError: '节点名称已存在!' repeatedNodeError: '节点名称已存在!',
cannotCopy: '不能被复制',
copyError: '已复制节点'
}, },
delete: { delete: {
confirmTitle: '确定删除该节点?' confirmTitle: '确定删除该节点?',
deleteMessage: '节点不允许删除'
},
control: {
zoomOut: '缩小',
zoomIn: '放大',
fitView: '适应',
retract: '收起全部节点',
extend: '展开全部节点',
beautify: '一键美化'
}, },
variable: { variable: {
global: '全局变量', global: '全局变量',
@ -45,5 +58,116 @@ export default {
AND: '所有', AND: '所有',
OR: '任一', OR: '任一',
text: '连线节点执行完,执行当前节点' text: '连线节点执行完,执行当前节点'
},
validate: {
startNodeRequired: '开始节点必填',
startNodeOnly: '开始节点只能有一个',
baseNodeRequired: '基本信息节点必填',
baseNodeOnly: '基本信息节点只能有一个',
notInWorkFlowNode: '未在流程中的节点',
noNextNode: '不存在的下一个节点',
nodeUnavailable: '节点不可用',
needConnect1: '节点的',
needConnect2: '分支需要连接',
cannotEndNode: '节点不能当做结束节点'
},
nodes: {
startNode: {
label: '开始',
question: '用户问题',
currentTime: '当前时间'
},
baseNode: {
label: '基本信息'
},
aiChatNode: {
label: 'AI 对话',
text: '与 AI 大模型进行对话',
answer: 'AI 回答内容'
},
searchDatasetNode: {
label: '知识库检索',
text: '关联知识库,查找与问题相关的分段',
paragraph_list: '检索结果的分段列表',
is_hit_handling_method_list: '满足直接回答的分段列表',
result: '检索结果',
directly_return: '满足直接回答的分段内容'
},
questionNode: {
label: '问题优化',
text: '根据历史聊天记录优化完善当前问题,更利于匹配知识库分段',
result: '问题优化结果'
},
conditionNode: {
label: '判断器',
text: '根据不同条件执行不同的节点',
branch_name: '分支名称'
},
replyNode: {
label: '指定回复',
text: '指定回复内容,引用变量会转换为字符串进行输出',
content: '内容'
},
rerankerNode: {
label: '多路召回',
text: '使用重排模型对多个知识库的检索结果进行二次召回',
result_list: '重排结果列表',
result: '重排结果'
},
formNode: {
label: '表单收集',
text: '在问答过程中用于收集用户信息,可以根据收集到表单数据执行后续流程',
form_content_format: `你好,请先填写下面表单内容:
{{form}}
`,
form_data: '表单全部内容'
},
documentExtractNode: {
label: '文档内容提取',
text: '提取文档中的内容',
content: '文档内容'
},
imageUnderstandNode: {
label: '图片理解',
text: '识别出图片中的对象、场景等信息回答用户问题',
answer: 'AI 回答内容'
},
imageGenerateNode: {
label: '图片生成',
text: '根据提供的文本内容生成图片',
answer: 'AI 回答内容',
image: '图片'
},
speechToTextNode: {
label: '语音转文本',
text: '将音频通过语音识别模型转换为文本'
},
textToSpeechNode: {
label: '文本转语音',
text: '将文本通过语音合成模型转换为音频'
},
functionNode: {
label: '自定义函数',
text: '通过执行自定义脚本,实现数据处理'
},
applicationNode: {
label: '应用节点'
}
},
compare: {
is_null: '为空',
is_not_null: '不为空',
contain: '包含',
not_contain: '不包含',
eq: '等于',
ge: '大于等于',
gt: '大于',
le: '小于等于',
lt: '小于',
len_eq: '长度等于',
len_ge: '长度大于等于',
len_gt: '长度大于',
len_le: '长度小于等于',
len_lt: '长度小于'
} }
} }

View File

@ -65,7 +65,6 @@ export default {
paramInfo1: '使用函数时显示', paramInfo1: '使用函数时显示',
paramInfo2: '使用函数时不显示', paramInfo2: '使用函数时不显示',
code: '代码', code: '代码',
result: '结果'
}, },
debug: { debug: {
run: '运行', run: '运行',

View File

@ -39,6 +39,7 @@ export default {
debug: '調試', debug: '調試',
required: '必填', required: '必填',
noData: '暂无数据', noData: '暂无数据',
result: '結果',
status: { status: {
label: '狀態', label: '狀態',
enableSuccess: '啟用成功', enableSuccess: '啟用成功',

View File

@ -65,7 +65,6 @@ export default {
paramInfo1: '使用函數時顯示', paramInfo1: '使用函數時顯示',
paramInfo2: '使用函數時不顯示', paramInfo2: '使用函數時不顯示',
code: '代碼', code: '代碼',
result: '結果'
}, },
debug: { debug: {
run: '運行', run: '運行',

View File

@ -13,7 +13,7 @@
</el-input> </el-input>
</div> </div>
<el-tab-pane :label="$t('views.applicationWorkflow.baseNodes')" name="base"> <el-tab-pane :label="$t('views.applicationWorkflow.baseComponent')" name="base">
<el-scrollbar height="400"> <el-scrollbar height="400">
<div v-if="filter_menu_nodes.length > 0"> <div v-if="filter_menu_nodes.length > 0">
<template v-for="(item, index) in filter_menu_nodes" :key="index"> <template v-for="(item, index) in filter_menu_nodes" :key="index">

View File

@ -147,7 +147,7 @@
</el-text> </el-text>
</h4> </h4>
<div class="flex-between border-r-4 p-8-12 mb-8 layout-bg lighter"> <div class="flex-between border-r-4 p-8-12 mb-8 layout-bg lighter">
<span>{{ $t('views.functionLib.functionForm.form.param.result') }} {result}</span> <span>{{ $t('common.result') }} {result}</span>
</div> </div>
</div> </div>

View File

@ -1,34 +1,83 @@
<template> <template>
<el-card shadow="always" style="--el-card-padding: 8px 12px; --el-card-border-radius: 8px"> <el-card shadow="always" style="--el-card-padding: 8px 12px; --el-card-border-radius: 8px">
<el-button link @click="zoomOut"> <el-button link @click="zoomOut">
<el-tooltip class="box-item" effect="dark" content="缩小" placement="top"> <el-tooltip
<el-icon :size="16" title="缩小"><ZoomOut /></el-icon> class="box-item"
effect="dark"
:content="$t('views.applicationWorkflow.control.zoomOut')"
placement="top"
>
<el-icon :size="16" :title="$t('views.applicationWorkflow.control.zoomOut')"
><ZoomOut
/></el-icon>
</el-tooltip> </el-tooltip>
</el-button> </el-button>
<el-button link @click="zoomIn"> <el-button link @click="zoomIn">
<el-tooltip class="box-item" effect="dark" content="放大" placement="top"> <el-tooltip
<el-icon :size="16" title="放大"><ZoomIn /></el-icon> class="box-item"
effect="dark"
:content="$t('views.applicationWorkflow.control.zoomIn')"
placement="top"
>
<el-icon :size="16" :title="$t('views.applicationWorkflow.control.zoomIn')"
><ZoomIn
/></el-icon>
</el-tooltip> </el-tooltip>
</el-button> </el-button>
<el-button link @click="fitView"> <el-button link @click="fitView">
<el-tooltip class="box-item" effect="dark" content="适应" placement="top"> <el-tooltip
<AppIcon iconName="app-fitview" title="适应"></AppIcon> class="box-item"
effect="dark"
:content="$t('views.applicationWorkflow.control.fitView')"
placement="top"
>
<AppIcon
iconName="app-fitview"
:title="$t('views.applicationWorkflow.control.fitView')"
></AppIcon>
</el-tooltip> </el-tooltip>
</el-button> </el-button>
<el-divider direction="vertical" /> <el-divider direction="vertical" />
<el-button link @click="retract"> <el-button link @click="retract">
<el-tooltip class="box-item" effect="dark" content="收起全部节点" placement="top"> <el-tooltip
<AppIcon style="font-size: 16px" iconName="app-retract" title="收起全部节点"></AppIcon> class="box-item"
effect="dark"
:content="$t('views.applicationWorkflow.control.retract')"
placement="top"
>
<AppIcon
style="font-size: 16px"
iconName="app-retract"
:title="$t('views.applicationWorkflow.control.retract')"
></AppIcon>
</el-tooltip> </el-tooltip>
</el-button> </el-button>
<el-button link @click="extend"> <el-button link @click="extend">
<el-tooltip class="box-item" effect="dark" content="展开全部节点" placement="top"> <el-tooltip
<AppIcon style="font-size: 16px" iconName="app-extend" title="展开全部节点"></AppIcon> class="box-item"
effect="dark"
:content="$t('views.applicationWorkflow.control.extend')"
placement="top"
>
<AppIcon
style="font-size: 16px"
iconName="app-extend"
:title="$t('views.applicationWorkflow.control.extend')"
></AppIcon>
</el-tooltip> </el-tooltip>
</el-button> </el-button>
<el-button link @click="layout"> <el-button link @click="layout">
<el-tooltip class="box-item" effect="dark" content="一键美化" placement="top"> <el-tooltip
<AppIcon style="font-size: 16px" iconName="app-beautify" title="一键美化"></AppIcon> class="box-item"
effect="dark"
:content="$t('views.applicationWorkflow.control.beautify')"
placement="top"
>
<AppIcon
style="font-size: 16px"
iconName="app-beautify"
:title="$t('views.applicationWorkflow.control.beautify')"
></AppIcon>
</el-tooltip> </el-tooltip>
</el-button> </el-button>
</el-card> </el-card>

View File

@ -8,18 +8,18 @@ export const startNode = {
y: 720, y: 720,
properties: { properties: {
height: 200, height: 200,
stepName: '开始', stepName: t('views.applicationWorkflow.nodes.startNode.label'),
config: { config: {
fields: [ fields: [
{ {
label: '用户问题', label: t('views.applicationWorkflow.nodes.startNode.question'),
value: 'question' value: 'question'
} }
], ],
globalFields: [ globalFields: [
{ {
value: 'time', value: 'time',
label: '当前时间' label: t('views.applicationWorkflow.nodes.startNode.currentTime')
} }
] ]
} }
@ -34,7 +34,7 @@ export const baseNode = {
properties: { properties: {
width: 420, width: 420,
height: 200, height: 200,
stepName: '基本信息', stepName: t('views.applicationWorkflow.nodes.baseNode.label'),
input_field_list: [], input_field_list: [],
node_data: { node_data: {
name: '', name: '',
@ -55,15 +55,15 @@ export const baseNodes = [baseNode, startNode]
*/ */
export const aiChatNode = { export const aiChatNode = {
type: WorkflowType.AiChat, type: WorkflowType.AiChat,
text: '与 AI 大模型进行对话', text: t('views.applicationWorkflow.nodes.aiChatNode.text'),
label: 'AI 对话', label: t('views.applicationWorkflow.nodes.aiChatNode.label'),
height: 340, height: 340,
properties: { properties: {
stepName: 'AI 对话', stepName: t('views.applicationWorkflow.nodes.aiChatNode.label'),
config: { config: {
fields: [ fields: [
{ {
label: 'AI 回答内容', label: t('views.applicationWorkflow.nodes.aiChatNode.answer'),
value: 'answer' value: 'answer'
} }
] ]
@ -75,21 +75,27 @@ export const aiChatNode = {
*/ */
export const searchDatasetNode = { export const searchDatasetNode = {
type: WorkflowType.SearchDataset, type: WorkflowType.SearchDataset,
text: '关联知识库,查找与问题相关的分段', text: t('views.applicationWorkflow.nodes.searchDatasetNode.text'),
label: '知识库检索', label: t('views.applicationWorkflow.nodes.searchDatasetNode.label'),
height: 355, height: 355,
properties: { properties: {
stepName: '知识库检索', stepName: t('views.applicationWorkflow.nodes.searchDatasetNode.label'),
config: { config: {
fields: [ fields: [
{ label: '检索结果的分段列表', value: 'paragraph_list' },
{ label: '满足直接回答的分段列表', value: 'is_hit_handling_method_list' },
{ {
label: '检索结果', label: t('views.applicationWorkflow.nodes.searchDatasetNode.paragraph_list'),
value: 'paragraph_list'
},
{
label: t('views.applicationWorkflow.nodes.searchDatasetNode.is_hit_handling_method_list'),
value: 'is_hit_handling_method_list'
},
{
label: t('views.applicationWorkflow.nodes.searchDatasetNode.result'),
value: 'data' value: 'data'
}, },
{ {
label: '满足直接回答的分段内容', label: t('views.applicationWorkflow.nodes.searchDatasetNode.directly_return'),
value: 'directly_return' value: 'directly_return'
} }
] ]
@ -98,15 +104,15 @@ export const searchDatasetNode = {
} }
export const questionNode = { export const questionNode = {
type: WorkflowType.Question, type: WorkflowType.Question,
text: '根据历史聊天记录优化完善当前问题,更利于匹配知识库分段', text: t('views.applicationWorkflow.nodes.searchDatasetNode.text'),
label: '问题优化', label: t('views.applicationWorkflow.nodes.searchDatasetNode.label'),
height: 345, height: 345,
properties: { properties: {
stepName: '问题优化', stepName: t('views.applicationWorkflow.nodes.searchDatasetNode.label'),
config: { config: {
fields: [ fields: [
{ {
label: '问题优化结果', label: t('views.applicationWorkflow.nodes.searchDatasetNode.result'),
value: 'answer' value: 'answer'
} }
] ]
@ -115,16 +121,16 @@ export const questionNode = {
} }
export const conditionNode = { export const conditionNode = {
type: WorkflowType.Condition, type: WorkflowType.Condition,
text: '根据不同条件执行不同的节点', text: t('views.applicationWorkflow.nodes.conditionNode.text'),
label: '判断器', label: t('views.applicationWorkflow.nodes.conditionNode.label'),
height: 175, height: 175,
properties: { properties: {
width: 600, width: 600,
stepName: '判断器', stepName: t('views.applicationWorkflow.nodes.conditionNode.label'),
config: { config: {
fields: [ fields: [
{ {
label: '分支名称', label: t('views.applicationWorkflow.nodes.conditionNode.branch_name'),
value: 'branch_name' value: 'branch_name'
} }
] ]
@ -133,15 +139,15 @@ export const conditionNode = {
} }
export const replyNode = { export const replyNode = {
type: WorkflowType.Reply, type: WorkflowType.Reply,
text: '指定回复内容,引用变量会转换为字符串进行输出', text: t('views.applicationWorkflow.nodes.replyNode.text'),
label: '指定回复', label: t('views.applicationWorkflow.nodes.replyNode.label'),
height: 210, height: 210,
properties: { properties: {
stepName: '指定回复', stepName: t('views.applicationWorkflow.nodes.replyNode.label'),
config: { config: {
fields: [ fields: [
{ {
label: '内容', label: t('views.applicationWorkflow.nodes.replyNode.content'),
value: 'answer' value: 'answer'
} }
] ]
@ -150,19 +156,19 @@ export const replyNode = {
} }
export const rerankerNode = { export const rerankerNode = {
type: WorkflowType.RrerankerNode, type: WorkflowType.RrerankerNode,
text: '使用重排模型对多个知识库的检索结果进行二次召回', text: t('views.applicationWorkflow.nodes.rerankerNode.text'),
label: '多路召回', label: t('views.applicationWorkflow.nodes.rerankerNode.label'),
height: 252, height: 252,
properties: { properties: {
stepName: '多路召回', stepName: t('views.applicationWorkflow.nodes.rerankerNode.label'),
config: { config: {
fields: [ fields: [
{ {
label: '重排结果列表', label: t('views.applicationWorkflow.nodes.rerankerNode.result_list'),
value: 'result_list' value: 'result_list'
}, },
{ {
label: '重排结果', label: t('views.applicationWorkflow.nodes.rerankerNode.result'),
value: 'result' value: 'result'
} }
] ]
@ -171,23 +177,21 @@ export const rerankerNode = {
} }
export const formNode = { export const formNode = {
type: WorkflowType.FormNode, type: WorkflowType.FormNode,
text: '在问答过程中用于收集用户信息,可以根据收集到表单数据执行后续流程', text: t('views.applicationWorkflow.nodes.formNode.text'),
label: '表单收集', label: t('views.applicationWorkflow.nodes.formNode.label'),
height: 252, height: 252,
properties: { properties: {
width: 600, width: 600,
stepName: '表单收集', stepName: t('views.applicationWorkflow.nodes.formNode.label'),
node_data: { node_data: {
is_result: true, is_result: true,
form_field_list: [], form_field_list: [],
form_content_format: `你好,请先填写下面表单内容: form_content_format: t('views.applicationWorkflow.nodes.formNode.form_content_format')
{{form}}
`
}, },
config: { config: {
fields: [ fields: [
{ {
label: '表单全部内容', label: t('views.applicationWorkflow.nodes.formNode.form_data'),
value: 'form_data' value: 'form_data'
} }
] ]
@ -196,15 +200,15 @@ export const formNode = {
} }
export const documentExtractNode = { export const documentExtractNode = {
type: WorkflowType.DocumentExtractNode, type: WorkflowType.DocumentExtractNode,
text: '提取文档中的内容', text: t('views.applicationWorkflow.nodes.documentExtractNode.text'),
label: '文档内容提取', label: t('views.applicationWorkflow.nodes.documentExtractNode.label'),
height: 252, height: 252,
properties: { properties: {
stepName: '文档内容提取', stepName: t('views.applicationWorkflow.nodes.documentExtractNode.label'),
config: { config: {
fields: [ fields: [
{ {
label: '文档内容', label: t('views.applicationWorkflow.nodes.documentExtractNode.content'),
value: 'content' value: 'content'
} }
] ]
@ -213,15 +217,15 @@ export const documentExtractNode = {
} }
export const imageUnderstandNode = { export const imageUnderstandNode = {
type: WorkflowType.ImageUnderstandNode, type: WorkflowType.ImageUnderstandNode,
text: '识别出图片中的对象、场景等信息回答用户问题', text: t('views.applicationWorkflow.nodes.imageUnderstandNode.text'),
label: '图片理解', label: t('views.applicationWorkflow.nodes.imageUnderstandNode.label'),
height: 252, height: 252,
properties: { properties: {
stepName: '图片理解', stepName: t('views.applicationWorkflow.nodes.imageUnderstandNode.label'),
config: { config: {
fields: [ fields: [
{ {
label: 'AI 回答内容', label: t('views.applicationWorkflow.nodes.imageUnderstandNode.answer'),
value: 'answer' value: 'answer'
} }
] ]
@ -231,19 +235,19 @@ export const imageUnderstandNode = {
export const imageGenerateNode = { export const imageGenerateNode = {
type: WorkflowType.ImageGenerateNode, type: WorkflowType.ImageGenerateNode,
text: '根据提供的文本内容生成图片', text: t('views.applicationWorkflow.nodes.imageGenerateNode.text'),
label: '图片生成', label: t('views.applicationWorkflow.nodes.imageGenerateNode.label'),
height: 252, height: 252,
properties: { properties: {
stepName: '图片生成', stepName: t('views.applicationWorkflow.nodes.imageGenerateNode.label'),
config: { config: {
fields: [ fields: [
{ {
label: 'AI 回答内容', label: t('views.applicationWorkflow.nodes.imageGenerateNode.answer'),
value: 'answer' value: 'answer'
}, },
{ {
label: '图片', label: t('views.applicationWorkflow.nodes.imageGenerateNode.image'),
value: 'image' value: 'image'
} }
] ]
@ -253,15 +257,15 @@ export const imageGenerateNode = {
export const speechToTextNode = { export const speechToTextNode = {
type: WorkflowType.SpeechToTextNode, type: WorkflowType.SpeechToTextNode,
text: '将音频通过语音识别模型转换为文本', text: t('views.applicationWorkflow.nodes.speechToTextNode.text'),
label: '语音转文本', label: t('views.applicationWorkflow.nodes.speechToTextNode.label'),
height: 252, height: 252,
properties: { properties: {
stepName: '语音转文本', stepName: t('views.applicationWorkflow.nodes.speechToTextNode.label'),
config: { config: {
fields: [ fields: [
{ {
label: '结果', label: t('common.result'),
value: 'result' value: 'result'
} }
] ]
@ -270,15 +274,15 @@ export const speechToTextNode = {
} }
export const textToSpeechNode = { export const textToSpeechNode = {
type: WorkflowType.TextToSpeechNode, type: WorkflowType.TextToSpeechNode,
text: '将文本通过语音合成模型转换为音频', text: t('views.applicationWorkflow.nodes.textToSpeechNode.text'),
label: '文本转语音', label: t('views.applicationWorkflow.nodes.textToSpeechNode.label'),
height: 252, height: 252,
properties: { properties: {
stepName: '文本转语音', stepName: t('views.applicationWorkflow.nodes.textToSpeechNode.label'),
config: { config: {
fields: [ fields: [
{ {
label: '结果', label: t('common.result'),
value: 'result' value: 'result'
} }
] ]
@ -305,15 +309,15 @@ export const menuNodes = [
*/ */
export const functionNode = { export const functionNode = {
type: WorkflowType.FunctionLibCustom, type: WorkflowType.FunctionLibCustom,
text: '通过执行自定义脚本,实现数据处理', text: t('views.applicationWorkflow.nodes.functionNode.text'),
label: '自定义函数', label: t('views.applicationWorkflow.nodes.functionNode.label'),
height: 260, height: 260,
properties: { properties: {
stepName: '自定义函数', stepName: t('views.applicationWorkflow.nodes.functionNode.label'),
config: { config: {
fields: [ fields: [
{ {
label: '结果', label: t('common.result'),
value: 'result' value: 'result'
} }
] ]
@ -322,15 +326,15 @@ export const functionNode = {
} }
export const functionLibNode = { export const functionLibNode = {
type: WorkflowType.FunctionLib, type: WorkflowType.FunctionLib,
text: '通过执行自定义脚本,实现数据处理', text: t('views.applicationWorkflow.nodes.functionNode.text'),
label: '自定义函数', label: t('views.applicationWorkflow.nodes.functionNode.label'),
height: 170, height: 170,
properties: { properties: {
stepName: '自定义函数', stepName: t('views.applicationWorkflow.nodes.functionNode.label'),
config: { config: {
fields: [ fields: [
{ {
label: '结果', label: t('common.result'),
value: 'result' value: 'result'
} }
] ]
@ -340,15 +344,15 @@ export const functionLibNode = {
export const applicationNode = { export const applicationNode = {
type: WorkflowType.Application, type: WorkflowType.Application,
text: '应用节点', text: t('views.applicationWorkflow.nodes.applicationNode.label'),
label: '应用节点', label: t('views.applicationWorkflow.nodes.applicationNode.label'),
height: 260, height: 260,
properties: { properties: {
stepName: '应用节点', stepName: t('views.applicationWorkflow.nodes.applicationNode.label'),
config: { config: {
fields: [ fields: [
{ {
label: '结果', label: t('common.result'),
value: 'result' value: 'result'
} }
] ]
@ -357,20 +361,20 @@ export const applicationNode = {
} }
export const compareList = [ export const compareList = [
{ value: 'is_null', label: '为空' }, { value: 'is_null', label: t('views.applicationWorkflow.compare.is_null') },
{ value: 'is_not_null', label: '不为空' }, { value: 'is_not_null', label: t('views.applicationWorkflow.compare.is_not_null') },
{ value: 'contain', label: '包含' }, { value: 'contain', label: t('views.applicationWorkflow.compare.contain') },
{ value: 'not_contain', label: '不包含' }, { value: 'not_contain', label: t('views.applicationWorkflow.compare.not_contain') },
{ value: 'eq', label: '等于' }, { value: 'eq', label: t('views.applicationWorkflow.compare.eq') },
{ value: 'ge', label: '大于等于' }, { value: 'ge', label: t('views.applicationWorkflow.compare.ge') },
{ value: 'gt', label: '大于' }, { value: 'gt', label:t('views.applicationWorkflow.compare.gt') },
{ value: 'le', label: '小于等于' }, { value: 'le', label: t('views.applicationWorkflow.compare.le') },
{ value: 'lt', label: '小于' }, { value: 'lt', label: t('views.applicationWorkflow.compare.lt') },
{ value: 'len_eq', label: '长度等于' }, { value: 'len_eq', label: t('views.applicationWorkflow.compare.len_eq')},
{ value: 'len_ge', label: '长度大于等于' }, { value: 'len_ge', label: t('views.applicationWorkflow.compare.len_ge') },
{ value: 'len_gt', label: '长度大于' }, { value: 'len_gt', label:t('views.applicationWorkflow.compare.len_gt') },
{ value: 'len_le', label: '长度小于等于' }, { value: 'len_le', label: t('views.applicationWorkflow.compare.len_le') },
{ value: 'len_lt', label: '长度小于' } { value: 'len_lt', label: t('views.applicationWorkflow.compare.len_lt') }
] ]
export const nodeDict: any = { export const nodeDict: any = {

View File

@ -60,13 +60,13 @@ export function initDefaultShortcut(lf: LogicFlow, graph: GraphModel) {
(node: any) => node.type === WorkflowType.Start || node.type === WorkflowType.Base (node: any) => node.type === WorkflowType.Start || node.type === WorkflowType.Base
) )
if (base_nodes.length > 0) { if (base_nodes.length > 0) {
MsgError(base_nodes[0]?.properties?.stepName + '不能被复制') MsgError(base_nodes[0]?.properties?.stepName + t('views.applicationWorkflow.tip.cannotCopy'))
return return
} }
selected = elements selected = elements
selected.nodes.forEach((node: any) => translationNodeData(node, TRANSLATION_DISTANCE)) selected.nodes.forEach((node: any) => translationNodeData(node, TRANSLATION_DISTANCE))
selected.edges.forEach((edge: any) => translationEdgeData(edge, TRANSLATION_DISTANCE)) selected.edges.forEach((edge: any) => translationEdgeData(edge, TRANSLATION_DISTANCE))
MsgSuccess('已复制节点') MsgSuccess(t('views.applicationWorkflow.tip.copyError'))
return false return false
} }
const paste_node = () => { const paste_node = () => {
@ -96,7 +96,7 @@ export function initDefaultShortcut(lf: LogicFlow, graph: GraphModel) {
} }
const nodes = elements.nodes.filter((node) => ['start-node', 'base-node'].includes(node.type)) const nodes = elements.nodes.filter((node) => ['start-node', 'base-node'].includes(node.type))
if (nodes.length > 0) { if (nodes.length > 0) {
MsgError(`${nodes[0].properties?.stepName}节点不允许删除`) MsgError(`${nodes[0].properties?.stepName}${t('views.applicationWorkflow.delete.deleteMessage')}`)
return return
} }
MsgConfirm(t('common.tip'), t('views.applicationWorkflow.delete.confirmTitle'), { MsgConfirm(t('common.tip'), t('views.applicationWorkflow.delete.confirmTitle'), {

View File

@ -1,4 +1,5 @@
import { WorkflowType } from '@/enums/workflow' import { WorkflowType } from '@/enums/workflow'
import { t } from '@/locales'
const end_nodes: Array<string> = [ const end_nodes: Array<string> = [
WorkflowType.AiChat, WorkflowType.AiChat,
@ -26,9 +27,9 @@ export class WorkFlowInstance {
private is_valid_start_node() { private is_valid_start_node() {
const start_node_list = this.nodes.filter((item) => item.id === WorkflowType.Start) const start_node_list = this.nodes.filter((item) => item.id === WorkflowType.Start)
if (start_node_list.length == 0) { if (start_node_list.length == 0) {
throw '开始节点必填' throw t('views.applicationWorkflow.validate.startNodeRequired')
} else if (start_node_list.length > 1) { } else if (start_node_list.length > 1) {
throw '开始节点只能有一个' throw t('views.applicationWorkflow.validate.startNodeOnly')
} }
} }
/** /**
@ -37,9 +38,9 @@ export class WorkFlowInstance {
private is_valid_base_node() { private is_valid_base_node() {
const start_node_list = this.nodes.filter((item) => item.id === WorkflowType.Base) const start_node_list = this.nodes.filter((item) => item.id === WorkflowType.Base)
if (start_node_list.length == 0) { if (start_node_list.length == 0) {
throw '基本信息节点必填' throw t('views.applicationWorkflow.validate.baseNodeRequired')
} else if (start_node_list.length > 1) { } else if (start_node_list.length > 1) {
throw '基本信息节点只能有一个' throw t('views.applicationWorkflow.validate.baseNodeOnly')
} }
} }
/** /**
@ -91,7 +92,7 @@ export class WorkFlowInstance {
.filter((node: any) => node.id !== WorkflowType.Start && node.id !== WorkflowType.Base) .filter((node: any) => node.id !== WorkflowType.Start && node.id !== WorkflowType.Base)
.filter((node) => !this.workFlowNodes.includes(node)) .filter((node) => !this.workFlowNodes.includes(node))
if (notInWorkFlowNodes.length > 0) { if (notInWorkFlowNodes.length > 0) {
throw `未在流程中的节点:${notInWorkFlowNodes.map((node) => node.properties.stepName).join('')}` throw `${t('views.applicationWorkflow.validate.notInWorkFlowNode')}:${notInWorkFlowNodes.map((node) => node.properties.stepName).join('')}`
} }
this.workFlowNodes = [] this.workFlowNodes = []
} }
@ -106,7 +107,7 @@ export class WorkFlowInstance {
.map((edge) => this.nodes.filter((node) => node.id == edge.targetNodeId)) .map((edge) => this.nodes.filter((node) => node.id == edge.targetNodeId))
.reduce((x, y) => [...x, ...y], []) .reduce((x, y) => [...x, ...y], [])
if (node_list.length == 0 && !end_nodes.includes(node.type)) { if (node_list.length == 0 && !end_nodes.includes(node.type)) {
throw '不存在的下一个节点' throw t('views.applicationWorkflow.validate.noNextNode')
} }
return node_list return node_list
} }
@ -114,7 +115,7 @@ export class WorkFlowInstance {
for (const node of this.nodes) { for (const node of this.nodes) {
if (node.type !== WorkflowType.Base && node.type !== WorkflowType.Start) { if (node.type !== WorkflowType.Base && node.type !== WorkflowType.Start) {
if (!this.edges.some((edge) => edge.targetNodeId === node.id)) { if (!this.edges.some((edge) => edge.targetNodeId === node.id)) {
throw `未在流程中的节点:${node.properties.stepName}` throw `${t('views.applicationWorkflow.validate.notInWorkFlowNode')}:${node.properties.stepName}`
} }
} }
} }
@ -125,7 +126,7 @@ export class WorkFlowInstance {
*/ */
private is_valid_node(node: any) { private is_valid_node(node: any) {
if (node.properties.status && node.properties.status === 500) { if (node.properties.status && node.properties.status === 500) {
throw `${node.properties.stepName} 节点不可用` throw `${node.properties.stepName} ${t('views.applicationWorkflow.validate.nodeUnavailable')}`
} }
if (node.type === WorkflowType.Condition) { if (node.type === WorkflowType.Condition) {
const branch_list = node.properties.node_data.branch const branch_list = node.properties.node_data.branch
@ -133,17 +134,17 @@ export class WorkFlowInstance {
const source_anchor_id = `${node.id}_${branch.id}_right` const source_anchor_id = `${node.id}_${branch.id}_right`
const edge_list = this.edges.filter((edge) => edge.sourceAnchorId == source_anchor_id) const edge_list = this.edges.filter((edge) => edge.sourceAnchorId == source_anchor_id)
if (edge_list.length == 0) { if (edge_list.length == 0) {
throw `${node.properties.stepName} 节点的${branch.type}分支需要连接` throw `${node.properties.stepName} ${t('views.applicationWorkflow.validate.needConnect1')}${branch.type}${t('views.applicationWorkflow.validate.needConnect2')}`
} }
} }
} else { } else {
const edge_list = this.edges.filter((edge) => edge.sourceNodeId == node.id) const edge_list = this.edges.filter((edge) => edge.sourceNodeId == node.id)
if (edge_list.length == 0 && !end_nodes.includes(node.type)) { if (edge_list.length == 0 && !end_nodes.includes(node.type)) {
throw `${node.properties.stepName} 节点不能当做结束节点` throw `${node.properties.stepName} ${t('views.applicationWorkflow.validate.cannotEndNode')}`
} }
} }
if (node.properties.status && node.properties.status !== 200) { if (node.properties.status && node.properties.status !== 200) {
throw `${node.properties.stepName} 节点不可用` throw `${node.properties.stepName} ${t('views.applicationWorkflow.validate.nodeUnavailable')}`
} }
} }
} }

View File

@ -93,7 +93,7 @@
<div class="flex-between"> <div class="flex-between">
<div>历史聊天记录</div> <div>历史聊天记录</div>
<el-select v-model="chat_data.dialogue_type" type="small" style="width: 100px"> <el-select v-model="chat_data.dialogue_type" type="small" style="width: 100px">
<el-option label="节点" value="NODE" /> <el-option :label="$t('views.applicationWorkflow.node')" value="NODE" />
<el-option label="工作流" value="WORKFLOW" /> <el-option label="工作流" value="WORKFLOW" />
</el-select> </el-select>
</div> </div>

View File

@ -1,6 +1,6 @@
<template> <template>
<NodeContainer :nodeModel="nodeModel"> <NodeContainer :nodeModel="nodeModel">
<h5 class="title-decoration-1 mb-8">全局变量</h5> <h5 class="title-decoration-1 mb-8">{{ $t('views.applicationWorkflow.variable.global') }}</h5>
<div <div
v-for="(item, index) in nodeModel.properties.config.globalFields" v-for="(item, index) in nodeModel.properties.config.globalFields"
:key="index" :key="index"
@ -9,10 +9,19 @@
@mouseleave="showicon = false" @mouseleave="showicon = false"
> >
<span>{{ item.label }} {{ '{' + item.value + '}' }}</span> <span>{{ item.label }} {{ '{' + item.value + '}' }}</span>
<el-tooltip effect="dark" :content="$t('views.applicationWorkflow.setting.copyParam')" placement="top" v-if="showicon === true"> <el-tooltip
effect="dark"
content="$t('views.applicationWorkflow.setting.copyParam')"
placement="top"
v-if="showicon === true"
>
<el-button <el-button
link link
@click="copyClick('{{' + '全局变量.' + item.value + '}}')" @click="
copyClick(
`{{${$t('views.applicationWorkflow.variable.global')}.${item.value}}}`
)
"
style="padding: 0" style="padding: 0"
> >
<AppIcon iconName="app-copy"></AppIcon> <AppIcon iconName="app-copy"></AppIcon>
@ -69,7 +78,13 @@ const refreshFileUploadConfig = () => {
.map((v: any) => cloneDeep(v.properties.node_data.file_upload_setting)) .map((v: any) => cloneDeep(v.properties.node_data.file_upload_setting))
.filter((v: any) => v) .filter((v: any) => v)
fields = fields.filter((item: any) => item.value !== 'image' && item.value !== 'document' && item.value !== 'audio' && item.value !== 'video') fields = fields.filter(
(item: any) =>
item.value !== 'image' &&
item.value !== 'document' &&
item.value !== 'audio' &&
item.value !== 'video'
)
if (form_data.length === 0) { if (form_data.length === 0) {
set(props.nodeModel.properties.config, 'fields', fields) set(props.nodeModel.properties.config, 'fields', fields)