feat: Create workflow applications that support template selection

This commit is contained in:
wangdan-fit2cloud 2025-02-24 17:29:54 +08:00 committed by GitHub
parent 6b72611b72
commit 4367b1c650
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 99 additions and 28 deletions

View File

@ -46,6 +46,10 @@ export default {
simplePlaceholder: 'Suitable for beginners to create assistant.',
workflowPlaceholder: 'Suitable for advanced users to customize the workflow of assistant'
},
appTemplate: {
blankApp: 'Blank APP',
assistantApp: 'Knowledge Assistant'
},
aiModel: {
label: 'AI Model',
placeholder: 'Please select an AI model'
@ -110,7 +114,7 @@ export default {
reasoningContent: {
label: 'Output Thinking',
tooltip:
'Please set the thinking label based on the model\'s return, and the content in the middle of the label will be recognized as the thinking process.',
"Please set the thinking label based on the model's return, and the content in the middle of the label will be recognized as the thinking process.",
start: 'Start',
end: 'End'
}
@ -211,7 +215,7 @@ export default {
slackSetting: {
title: 'Slack Configuration',
signingSecretPlaceholder: 'Please enter signing secret',
botUserTokenPlaceholder: 'Please enter bot user token',
botUserTokenPlaceholder: 'Please enter bot user token'
},
copyUrl: 'Copy the link and fill it in'
},

View File

@ -41,6 +41,10 @@ export default {
simplePlaceholder: '适合新手创建小助手',
workflowPlaceholder: '适合高级用户自定义小助手的工作流'
},
appTemplate: {
blankApp: '空白应用',
assistantApp: '知识库问答助手'
},
aiModel: {
label: 'AI 模型',
placeholder: '请选择 AI 模型'
@ -198,7 +202,7 @@ export default {
slackSetting: {
title: 'Slack 应用配置',
signingSecretPlaceholder: '请输入 Signing Secret',
botUserTokenPlaceholder: '请输入 Bot User Token',
botUserTokenPlaceholder: '请输入 Bot User Token'
},
copyUrl: '复制链接填入到'
},

View File

@ -41,6 +41,10 @@ export default {
simplePlaceholder: '適合新手建立小助手',
workflowPlaceholder: '適合高階用戶自訂小助手的工作流程'
},
appTemplate: {
blankApp: '空白應用',
assistantApp: '知識庫問答助手'
},
aiModel: {
label: 'AI 模型',
placeholder: '請選擇 AI 模型'

View File

@ -38,11 +38,7 @@
<el-radio-group v-model="applicationForm.type" class="card__radio">
<el-row :gutter="16">
<el-col :span="12">
<el-card
shadow="never"
class="mb-16"
:class="applicationForm.type === 'SIMPLE' ? 'active' : ''"
>
<el-card shadow="never" :class="applicationForm.type === 'SIMPLE' ? 'active' : ''">
<el-radio value="SIMPLE" size="large">
<p class="mb-4">{{ $t('views.application.simple') }}</p>
<el-text type="info">{{
@ -52,11 +48,7 @@
</el-card>
</el-col>
<el-col :span="12">
<el-card
shadow="never"
class="mb-16"
:class="isWorkFlow(applicationForm.type) ? 'active' : ''"
>
<el-card shadow="never" :class="isWorkFlow(applicationForm.type) ? 'active' : ''">
<el-radio value="WORK_FLOW" size="large">
<p class="mb-4">{{ $t('views.application.workflow') }}</p>
<el-text type="info">{{
@ -68,6 +60,35 @@
</el-row>
</el-radio-group>
</el-form-item>
<el-form-item
:label="$t('views.document.upload.template')"
v-if="applicationForm.type === 'WORK_FLOW'"
>
<div class="w-full">
<el-row :gutter="16">
<el-col :span="12">
<el-card
class="radio-card cursor"
shadow="never"
@click="selectedType('blank')"
:class="appTemplate === 'blank' ? 'active' : ''"
>
{{ $t('views.application.applicationForm.form.appTemplate.blankApp') }}
</el-card>
</el-col>
<el-col :span="12">
<el-card
class="radio-card cursor"
shadow="never"
:class="appTemplate === 'assistant' ? 'active' : ''"
@click="selectedType('assistant')"
>
{{ $t('views.application.applicationForm.form.appTemplate.assistantApp') }}
</el-card>
</el-col>
</el-row>
</div>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
@ -89,6 +110,7 @@ import type { FormInstance, FormRules } from 'element-plus'
import applicationApi from '@/api/application'
import { MsgSuccess, MsgAlert } from '@/utils/message'
import { isWorkFlow } from '@/utils/application'
import { baseNodes } from '@/workflow/common/data'
import { t } from '@/locales'
const router = useRouter()
const emit = defineEmits(['refresh'])
@ -106,6 +128,12 @@ const optimizationPrompt =
'<data></data>' +
t('views.application.applicationForm.dialog.defaultPrompt2')
const workflowDefault = ref<any>({
edges: [],
nodes: baseNodes
})
const appTemplate = ref('blank')
const applicationFormRef = ref()
const loading = ref(false)
@ -207,6 +235,11 @@ const submitHandle = async (formEl: FormInstance | undefined) => {
if (!formEl) return
await formEl.validate((valid) => {
if (valid) {
if (isWorkFlow(applicationForm.value.type) && appTemplate.value === 'blank') {
workflowDefault.value.nodes[0].properties.node_data.desc = applicationForm.value.desc
workflowDefault.value.nodes[0].properties.node_data.name = applicationForm.value.name
applicationForm.value['work_flow'] = workflowDefault.value
}
applicationApi.postApplication(applicationForm.value, loading).then((res) => {
MsgSuccess(t('common.createSuccess'))
if (isWorkFlow(applicationForm.value.type)) {
@ -220,6 +253,18 @@ const submitHandle = async (formEl: FormInstance | undefined) => {
})
}
function selectedType(type: string) {
appTemplate.value = type
}
defineExpose({ open })
</script>
<style lang="scss" scope></style>
<style lang="scss" scope>
.radio-card {
line-height: 22px;
&.active {
border-color: var(--el-color-primary);
color: var(--el-color-primary);
}
}
</style>

View File

@ -4,10 +4,10 @@ import { t } from '@/locales'
export const startNode = {
id: WorkflowType.Start,
type: WorkflowType.Start,
x: 180,
y: 720,
x: 480,
y: 3340,
properties: {
height: 200,
height: 364,
stepName: t('views.applicationWorkflow.nodes.startNode.label'),
config: {
fields: [
@ -20,29 +20,45 @@ export const startNode = {
{
value: 'time',
label: t('views.applicationWorkflow.nodes.startNode.currentTime')
},
{
value: 'history_context',
label: t('views.application.applicationForm.form.historyRecord.label')
},
{
value: 'chat_id',
label: t('chat.chatId')
}
]
}
},
fields: [{ label: t('views.applicationWorkflow.nodes.startNode.question'), value: 'question' }],
globalFields: [
{ label: t('views.applicationWorkflow.nodes.startNode.currentTime'), value: 'time' }
],
showNode: true
}
}
export const baseNode = {
id: WorkflowType.Base,
type: WorkflowType.Base,
x: 200,
y: 270,
x: 360,
y: 2761.3875,
text: '',
properties: {
width: 420,
height: 200,
height: 728.375,
stepName: t('views.applicationWorkflow.nodes.baseNode.label'),
input_field_list: [],
node_data: {
name: '',
desc: '',
// @ts-ignore
prologue: t('views.application.applicationForm.form.defaultPrologue')
prologue: t('views.application.applicationForm.form.defaultPrologue'),
tts_type: 'BROWSER'
},
config: {}
config: {},
showNode: true,
user_input_config: { title: t('chat.userInput') },
user_input_field_list: []
}
}
/**
@ -246,9 +262,7 @@ export const variableAssignNode = {
height: 252,
properties: {
stepName: t('views.applicationWorkflow.nodes.variableAssignNode.label'),
config: {
}
config: {}
}
}
@ -415,7 +429,7 @@ export const nodeDict: any = {
[WorkflowType.TextToSpeechNode]: textToSpeechNode,
[WorkflowType.SpeechToTextNode]: speechToTextNode,
[WorkflowType.ImageGenerateNode]: imageGenerateNode,
[WorkflowType.VariableAssignNode]: variableAssignNode,
[WorkflowType.VariableAssignNode]: variableAssignNode
}
export function isWorkFlow(type: string | undefined) {
return type === 'WORK_FLOW'