Skip to content

Commit 45b32bf

Browse files
shaohuzhang1liuruibin
authored andcommitted
feat: knowledge workflow
1 parent c632a09 commit 45b32bf

File tree

13 files changed

+577
-19
lines changed

13 files changed

+577
-19
lines changed

ui/src/enums/application.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export enum SearchMode {
66

77
export enum WorkflowType {
88
Base = 'base-node',
9+
KnowledgeBase = 'knowledge-base-node',
910
Start = 'start-node',
1011
AiChat = 'ai-chat-node',
1112
SearchKnowledge = 'search-knowledge-node',

ui/src/views/knowledge-workflow/index.vue

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@
140140
</div>
141141
</template>
142142
<script setup lang="ts">
143-
import { ref, onMounted, onBeforeUnmount, computed, nextTick, provide } from 'vue'
143+
import { ref, onBeforeMount, onBeforeUnmount, computed, nextTick, provide } from 'vue'
144144
import { useRouter, useRoute } from 'vue-router'
145145
import type { Action } from 'element-plus'
146146
import Workflow from '@/workflow/index.vue'
@@ -159,6 +159,7 @@ import { EditionConst, PermissionConst, RoleConst } from '@/utils/permission/dat
159159
import permissionMap from '@/permission'
160160
import { WorkflowMode } from '@/enums/application'
161161
import { loadSharedApi } from '@/utils/dynamics-api/shared-api'
162+
import { knowledgeBaseNode } from '@/workflow/common/data'
162163
provide('getResourceDetail', () => detail)
163164
provide('workflowMode', WorkflowMode.Knowledge)
164165
provide('loopWorkflowMode', WorkflowMode.KnowledgeLoop)
@@ -423,18 +424,16 @@ function getDetail() {
423424
loadSharedApi({ type: 'knowledge', systemType: apiType.value })
424425
.getKnowledgeDetail(id)
425426
.then((res: any) => {
426-
let workspace = res.data?.work_flow
427-
if (!workspace) {
428-
workspace = {}
429-
}
430-
431427
detail.value = res.data
432428
detail.value.stt_model_id = res.data.stt_model
433429
detail.value.tts_model_id = res.data.tts_model
434430
detail.value.tts_type = res.data.tts_type
435431
saveTime.value = res.data?.update_time
432+
if (!detail.value.work_flow || !('nodes' in detail.value.work_flow)) {
433+
detail.value.work_flow = { nodes: [knowledgeBaseNode] }
434+
}
436435
detail.value.work_flow?.nodes
437-
?.filter((v: any) => v.id === 'base-node')
436+
?.filter((v: any) => v.id === 'knowledge-base-node')
438437
.map((v: any) => {
439438
apiInputParams.value = v.properties.api_input_field_list
440439
? v.properties.api_input_field_list.map((v: any) => {
@@ -526,7 +525,7 @@ const closeInterval = () => {
526525
}
527526
}
528527
529-
onMounted(() => {
528+
onBeforeMount(() => {
530529
getDetail()
531530
const workflowAutoSave = localStorage.getItem('workflowAutoSave')
532531
isSave.value = workflowAutoSave === 'true' ? true : false

ui/src/workflow/common/NodeContainer.vue

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -345,9 +345,12 @@ const nodeFields = computed(() => {
345345
})
346346
347347
function showOperate(type: string) {
348-
return ![WorkflowType.Start, WorkflowType.Base, WorkflowType.LoopStartNode.toString()].includes(
349-
type,
350-
)
348+
return ![
349+
WorkflowType.Start,
350+
WorkflowType.Base,
351+
WorkflowType.KnowledgeBase,
352+
WorkflowType.LoopStartNode.toString(),
353+
].includes(type)
351354
}
352355
const openNodeMenu = (anchorValue: any) => {
353356
showAnchor.value = true

ui/src/workflow/common/app-node.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -107,10 +107,11 @@ class AppNode extends HtmlResize.view {
107107
(pre, next) => [...pre, ...next],
108108
[],
109109
)
110-
const start_node_field_list = (
111-
this.props.graphModel.getNodeModelById('start-node') ||
112-
this.props.graphModel.getNodeModelById('loop-start-node')
113-
).get_node_field_list()
110+
const start_node_field_list =
111+
(
112+
this.props.graphModel.getNodeModelById('start-node') ||
113+
this.props.graphModel.getNodeModelById('loop-start-node')
114+
)?.get_node_field_list() || []
114115
return [...start_node_field_list, ...result]
115116
}
116117

@@ -414,7 +415,7 @@ class AppNodeModel extends HtmlResize.model {
414415
const showNode = this.properties.showNode === undefined ? true : this.properties.showNode
415416
const anchors: any = []
416417

417-
if (this.type !== WorkflowType.Base) {
418+
if (![WorkflowType.Base as string, WorkflowType.KnowledgeBase as string].includes(this.type)) {
418419
if (![WorkflowType.Start, WorkflowType.LoopStartNode.toString()].includes(this.type)) {
419420
anchors.push({
420421
x: x - width / 2 + 10,

ui/src/workflow/common/data.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,28 @@ export const baseNode = {
5757
user_input_field_list: [],
5858
},
5959
}
60+
export const knowledgeBaseNode = {
61+
id: WorkflowType.KnowledgeBase,
62+
type: WorkflowType.KnowledgeBase,
63+
x: 360,
64+
y: 2761.3875,
65+
text: '',
66+
properties: {
67+
height: 728.375,
68+
stepName: t('views.applicationWorkflow.nodes.baseNode.label'),
69+
input_field_list: [],
70+
node_data: {
71+
name: '',
72+
desc: '',
73+
prologue: t('views.application.form.defaultPrologue'),
74+
tts_type: 'BROWSER',
75+
},
76+
config: {},
77+
showNode: true,
78+
user_input_config: { title: t('chat.userInput') },
79+
user_input_field_list: [],
80+
},
81+
}
6082
/**
6183
* 说明
6284
* type 与 nodes 文件对应
@@ -880,6 +902,7 @@ export const nodeDict: any = {
880902
[WorkflowType.VideoUnderstandNode]: videoUnderstandNode,
881903
[WorkflowType.ParameterExtractionNode]: parameterExtractionNode,
882904
[WorkflowType.VariableAggregationNode]: variableAggregationNode,
905+
[WorkflowType.KnowledgeBase]: knowledgeBaseNode,
883906
}
884907

885908
export function isWorkFlow(type: string | undefined) {
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<template>
2+
<el-avatar shape="square" style="background: #ff8800">
3+
<img src="@/assets/workflow/icon_hi.svg" style="width: 75%" alt="" />
4+
</el-avatar>
5+
</template>
6+
<script setup lang="ts"></script>

ui/src/workflow/index.vue

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,6 @@ const renderGraphData = (data?: any) => {
7878
strokeWidth: 1,
7979
},
8080
})
81-
lf.value.graphModel.get = 'sdasdaad'
8281
lf.value.on('graph:rendered', () => {
8382
flowId.value = lf.value.graphModel.flowId
8483
})

ui/src/workflow/nodes/base-node/index.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@ class BaseModel extends AppNodeModel {
1515
return 600
1616
}
1717
}
18+
1819
export default {
19-
type: 'base-node',
20+
type: 'knowledge-base-node',
2021
model: BaseModel,
21-
view: BaseNode
22+
view: BaseNode,
2223
}
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
<template>
2+
<el-dialog
3+
:title="
4+
isEdit
5+
? $t('common.param.editParam')
6+
: $t('common.param.addParam')
7+
"
8+
v-model="dialogVisible"
9+
:close-on-click-modal="false"
10+
:close-on-press-escape="false"
11+
:destroy-on-close="true"
12+
:before-close="close"
13+
append-to-body
14+
>
15+
<DynamicsFormConstructor
16+
v-model="currentRow"
17+
label-position="top"
18+
require-asterisk-position="right"
19+
:input_type_list="inputTypeList"
20+
ref="DynamicsFormConstructorRef"
21+
></DynamicsFormConstructor>
22+
<template #footer>
23+
<span class="dialog-footer">
24+
<el-button @click.prevent="close"> {{ $t('common.cancel') }} </el-button>
25+
<el-button type="primary" @click="submit()" :loading="loading">
26+
{{ isEdit ? $t('common.save') : $t('common.add') }}
27+
</el-button>
28+
</span>
29+
</template>
30+
</el-dialog>
31+
</template>
32+
<script setup lang="ts">
33+
import { ref, computed } from 'vue'
34+
import { cloneDeep } from 'lodash'
35+
import DynamicsFormConstructor from '@/components/dynamics-form/constructor/index.vue'
36+
import type { FormField } from '@/components/dynamics-form/type'
37+
import _ from 'lodash'
38+
import { t } from '@/locales'
39+
const emit = defineEmits(['refresh'])
40+
41+
const DynamicsFormConstructorRef = ref()
42+
const loading = ref<boolean>(false)
43+
const isEdit = ref(false)
44+
const currentItem = ref<FormField | any>()
45+
const check_field = (field_list: Array<string>, obj: any) => {
46+
return field_list.every((field) => _.get(obj, field, undefined) !== undefined)
47+
}
48+
const currentRow = computed(() => {
49+
if (currentItem.value) {
50+
const row = currentItem.value
51+
switch (row.type) {
52+
case 'input':
53+
if (check_field(['field', 'input_type', 'label', 'required', 'attrs'], currentItem.value)) {
54+
return currentItem.value
55+
}
56+
return {
57+
attrs: row.attrs || { maxlength: 200, minlength: 0 },
58+
field: row.field || row.variable,
59+
input_type: 'TextInput',
60+
label: row.label || row.name,
61+
default_value: row.default_value,
62+
required: row.required != undefined ? row.required : row.is_required
63+
}
64+
case 'select':
65+
if (
66+
check_field(
67+
['field', 'input_type', 'label', 'required', 'option_list'],
68+
currentItem.value
69+
)
70+
) {
71+
return currentItem.value
72+
}
73+
return {
74+
attrs: row.attrs || {},
75+
field: row.field || row.variable,
76+
input_type: 'SingleSelect',
77+
label: row.label || row.name,
78+
default_value: row.default_value,
79+
required: row.required != undefined ? row.required : row.is_required,
80+
option_list: row.option_list
81+
? row.option_list
82+
: row.optionList.map((o: any) => {
83+
return { key: o, value: o }
84+
})
85+
}
86+
87+
case 'date':
88+
if (
89+
check_field(
90+
[
91+
'field',
92+
'input_type',
93+
'label',
94+
'required',
95+
'attrs.format',
96+
'attrs.value-format',
97+
'attrs.type'
98+
],
99+
currentItem.value
100+
)
101+
) {
102+
return currentItem.value
103+
}
104+
return {
105+
field: row.field || row.variable,
106+
input_type: 'DatePicker',
107+
label: row.label || row.name,
108+
default_value: row.default_value,
109+
required: row.required != undefined ? row.required : row.is_required,
110+
attrs: {
111+
format: 'YYYY-MM-DD HH:mm:ss',
112+
'value-format': 'YYYY-MM-DD HH:mm:ss',
113+
type: 'datetime'
114+
}
115+
}
116+
default:
117+
return currentItem.value
118+
}
119+
} else {
120+
return { input_type: 'TextInput', required: false, attrs: { maxlength: 200, minlength: 0 }, show_default_value: true }
121+
}
122+
})
123+
const currentIndex = ref(null)
124+
const inputTypeList = ref([
125+
{ label: t('dynamicsForm.input_type_list.TextInput'), value: 'TextInputConstructor' },
126+
{ label: t('dynamicsForm.input_type_list.PasswordInput'), value: 'PasswordInputConstructor' },
127+
{ label: t('dynamicsForm.input_type_list.SingleSelect'), value: 'SingleSelectConstructor' },
128+
{ label: t('dynamicsForm.input_type_list.MultiSelect'), value: 'MultiSelectConstructor' },
129+
{ label: t('dynamicsForm.input_type_list.RadioCard'), value: 'RadioCardConstructor' },
130+
{ label: t('dynamicsForm.input_type_list.DatePicker'), value: 'DatePickerConstructor' },
131+
{ label: t('dynamicsForm.input_type_list.SwitchInput'), value: 'SwitchInputConstructor' },
132+
])
133+
134+
const dialogVisible = ref<boolean>(false)
135+
136+
const open = (row: any, index: any) => {
137+
dialogVisible.value = true
138+
139+
if (row) {
140+
isEdit.value = true
141+
currentItem.value = cloneDeep(row)
142+
currentIndex.value = index
143+
} else {
144+
currentItem.value = null
145+
}
146+
}
147+
148+
const close = () => {
149+
dialogVisible.value = false
150+
isEdit.value = false
151+
currentIndex.value = null
152+
currentItem.value = null as any
153+
}
154+
155+
const submit = async () => {
156+
const formEl = DynamicsFormConstructorRef.value
157+
if (!formEl) return
158+
await formEl.validate().then(() => {
159+
emit('refresh', formEl?.getData(), currentIndex.value)
160+
isEdit.value = false
161+
currentItem.value = null as any
162+
currentIndex.value = null
163+
})
164+
}
165+
166+
defineExpose({ open, close })
167+
</script>
168+
<style lang="scss" scoped></style>

0 commit comments

Comments
 (0)