feat: Knowledge write node

This commit is contained in:
zhangzhanwei 2025-11-17 10:24:39 +08:00 committed by zhanweizhang7
parent 399f33604c
commit 39fd3657dd
19 changed files with 232 additions and 4 deletions

View File

@ -18,6 +18,7 @@ from .image_generate_step_node import *
from .image_to_video_step_node import BaseImageToVideoNode
from .image_understand_step_node import *
from .intent_node import *
from .knowledge_write_node.impl.base_knowledge_write_node import BaseKnowledgeWriteNode
from .loop_break_node import BaseLoopBreakNode
from .loop_continue_node import BaseLoopContinueNode
from .loop_node import *
@ -49,7 +50,7 @@ node_list = [BaseStartStepNode, BaseChatNode, BaseSearchKnowledgeNode, BaseSearc
BaseIntentNode, BaseLoopNode, BaseLoopStartStepNode,
BaseLoopContinueNode,
BaseLoopBreakNode, BaseVariableSplittingNode, BaseParameterExtractionNode, BaseVariableAggregationNode,
BaseDataSourceLocalNode,BaseDataSourceWebNode]
BaseDataSourceLocalNode,BaseDataSourceWebNode,BaseKnowledgeWriteNode]
def get_node(node_type):

View File

@ -0,0 +1,8 @@
# coding=utf-8
"""
@project: MaxKB
@Authorniu
@file __init__.py.py
@date2025/11/13 11:17
@desc:
"""

View File

@ -0,0 +1,38 @@
# coding=utf-8
"""
@project: MaxKB
@Authorniu
@file i_knowledge_write_node.py
@date2025/11/13 11:19
@desc:
"""
from typing import Type
from django.utils.translation import gettext_lazy as _
from rest_framework import serializers
from application.flow.i_step_node import INode, NodeResult
class KnowledgeWriteNodeParamSerializer(serializers.Serializer):
paragraph_list = serializers.ListField(required=True, label=_("Paragraph list"))
chunk_length = serializers.CharField(required=True, label=_("Child chunk length"))
class IKnowledgeWriteNode(INode):
def get_node_params_serializer_class(self) -> Type[serializers.Serializer]:
return KnowledgeWriteNodeParamSerializer
def _run(self):
return self.execute(**self.node_params_serializer.data, **self.flow_params_serializer.data)
def execute(self, paragraph_list, chunk_length, **kwargs) -> NodeResult:
pass
type = 'knowledge-write-node'

View File

@ -0,0 +1,8 @@
# coding=utf-8
"""
@project: MaxKB
@Authorniu
@file __init__.py.py
@date2025/11/13 11:18
@desc:
"""

View File

@ -0,0 +1,19 @@
# coding=utf-8
"""
@project: MaxKB
@Authorniu
@file base_knowledge_write_node.py
@date2025/11/13 11:19
@desc:
"""
from application.flow.i_step_node import NodeResult
from application.flow.step_node.knowledge_write_node.i_knowledge_write_node import IKnowledgeWriteNode
class BaseKnowledgeWriteNode(IKnowledgeWriteNode):
def save_context(self, details, workflow_manage):
pass
def execute(self, paragraph_list, chunk_length, **kwargs) -> NodeResult:
pass

View File

@ -0,0 +1,6 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 10C0 5.28595 0 2.92893 1.46447 1.46447C2.92893 0 5.28595 0 10 0C14.714 0 17.0711 0 18.5355 1.46447C20 2.92893 20 5.28595 20 10C20 14.714 20 17.0711 18.5355 18.5355C17.0711 20 14.714 20 10 20C5.28595 20 2.92893 20 1.46447 18.5355C0 17.0711 0 14.714 0 10Z" fill="#3370FF"/>
<path d="M6.91961 15.7292H5.31258C5.17445 15.7292 5.04197 15.6743 4.9443 15.5767C4.84662 15.479 4.79175 15.3465 4.79175 15.2084V4.79171C4.79175 4.65357 4.84662 4.5211 4.9443 4.42342C5.04197 4.32575 5.17445 4.27087 5.31258 4.27087H13.6459C13.784 4.27087 13.9165 4.32575 14.0142 4.42342C14.1119 4.5211 14.1667 4.65357 14.1667 4.79171V8.48155C14.1668 8.61964 14.112 8.75208 14.0144 8.84978L7.2881 15.5766C7.23972 15.625 7.18227 15.6634 7.11904 15.6896C7.05582 15.7158 6.98805 15.7292 6.91961 15.7292ZM7.21177 9.92377C7.26061 9.9726 7.32685 10 7.39591 10H10.0001C10.0691 10 10.1354 9.9726 10.1842 9.92377C10.2331 9.87493 10.2605 9.80869 10.2605 9.73962V9.21879C10.2605 9.14972 10.2331 9.08349 10.1842 9.03465C10.1354 8.98581 10.0691 8.95837 10.0001 8.95837H7.39591C7.32685 8.95837 7.26061 8.98581 7.21177 9.03465C7.16293 9.08349 7.1355 9.14972 7.1355 9.21879V9.73962C7.1355 9.80869 7.16293 9.87493 7.21177 9.92377ZM7.21177 7.3196C7.26061 7.36844 7.32685 7.39587 7.39591 7.39587H11.823C11.8572 7.39587 11.8911 7.38914 11.9227 7.37605C11.9542 7.36296 11.983 7.34378 12.0071 7.3196C12.0313 7.29542 12.0505 7.26671 12.0636 7.23511C12.0767 7.20352 12.0834 7.16966 12.0834 7.13546V6.61462C12.0834 6.58043 12.0767 6.54656 12.0636 6.51497C12.0505 6.48337 12.0313 6.45466 12.0071 6.43048C11.983 6.4063 11.9542 6.38712 11.9227 6.37403C11.8911 6.36094 11.8572 6.35421 11.823 6.35421H7.39591C7.32685 6.35421 7.26061 6.38164 7.21177 6.43048C7.16293 6.47932 7.1355 6.54556 7.1355 6.61462V7.13546C7.1355 7.20452 7.16293 7.27076 7.21177 7.3196Z" fill="white"/>
<path d="M14.3477 12.7485L12.8787 11.2798L9.65087 14.5282L9.47925 15.9201C9.47925 15.9892 9.50668 16.0554 9.55552 16.1042C9.60436 16.1531 9.6706 16.1805 9.73966 16.1805L11.1334 15.9587L14.3477 12.7485Z" fill="white"/>
<path d="M14.7255 10.1635C14.5224 9.96007 14.2086 9.94445 14.0242 10.1283L13.2456 10.9096L14.7164 12.3803L15.4958 11.6022L15.5205 11.5756C15.6789 11.3892 15.656 11.0939 15.462 10.8996L14.7255 10.1635Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -40,6 +40,7 @@ export enum WorkflowType {
ParameterExtractionNode = 'parameter-extraction-node',
DataSourceLocalNode = 'data-source-local-node',
DataSourceWebNode = 'data-source-web-node',
KnowledgeWriteNode = 'knowledge-write-node',
}
export enum WorkflowKind {
DataSource = 'data-source',

View File

@ -76,6 +76,7 @@ export default {
},
aggregationStrategy: 'Aggregation Strategy',
inputPlaceholder: 'Please input',
inputContent: 'Input content',
selectPlaceholder: 'Please select',
title: 'Title',
content: 'Content',

View File

@ -79,6 +79,11 @@ export default {
loopNodeBreakNodeRequired: 'Wireless loop must have a Break node',
},
nodes: {
knowledgeWriteNode: {
chunk_length: 'Chunk length',
text: 'Knowledge write',
label: 'Knowledge write',
},
dataSourceWebNode: {
label: 'Web Site',
text: 'Web Site',

View File

@ -80,6 +80,7 @@ export default {
},
aggregationStrategy: '聚合策略',
inputPlaceholder: '请输入',
inputContent: '输入内容',
selectPlaceholder: '请选择',
title: '标题',
content: '内容',

View File

@ -81,6 +81,11 @@ export default {
loopNodeBreakNodeRequired: '无限循环 必须存在 Break 节点',
},
nodes: {
knowledgeWriteNode: {
chunk_length: '子分块长度',
text: '知识库写入',
label: '知识库写入',
},
dataSourceWebNode: {
label: 'Web站点',
text: 'Web站点',

View File

@ -76,6 +76,7 @@ export default {
},
aggregationStrategy: '聚合策略',
inputPlaceholder: '請輸入',
inputContent: '輸入內容',
selectPlaceholder: '請選擇',
title: '標題',
content: '内容',

View File

@ -80,6 +80,11 @@ export default {
loopNodeBreakNodeRequired: '無限循環必須存在Break節點',
},
nodes: {
knowledgeWriteNode: {
chunk_length: '子分塊長度',
text: '知識庫寫入',
label: '知識庫寫入',
},
dataSourceWebNode: {
label: 'Web網站',
text: 'Web網站',

View File

@ -185,7 +185,7 @@ const systemManage = {
PermissionConst.RESOURCE_KNOWLEDGE_TAG_DELETE
],'OR'
),
bug: () =>
debug: () =>
hasPermission([
RoleConst.ADMIN,
PermissionConst.RESOURCE_KNOWLEDGE_WORKFLOW_READ

View File

@ -30,7 +30,7 @@
<AppIcon iconName="app-add-outlined" class="mr-4" />
{{ $t('views.knowledgeWorkflow.setting.addComponent') }}
</el-button>
<el-button @click="clickShowDebug" :disabled="showDebug">
<el-button @click="clickShowDebug" :disabled="showDebug" v-if="permissionPrecise.debug(id)">
<AppIcon iconName="app-debug-outlined" class="mr-4"></AppIcon>
{{ $t('views.knowledgeWorkflow.setting.debug') }}
</el-button>

View File

@ -119,7 +119,19 @@ export const dataSourceWebNode = {
],
},
},
}
export const knowledgeWriteNode = {
type: WorkflowType.KnowledgeWriteNode,
text: t('views.applicationWorkflow.nodes.knowledgeWriteNode.text'),
label: t('views.applicationWorkflow.nodes.knowledgeWriteNode.label'),
properties: {
height: 252,
stepName: t('views.applicationWorkflow.nodes.knowledgeWriteNode.label'),
config: {
fields:[]
},
},
}
@ -706,7 +718,7 @@ export const knowledgeMenuNodes = [
},
{
label: t('views.knowledge.title'),
list: [documentExtractNode],
list: [documentExtractNode, knowledgeWriteNode],
},
{
label: t('views.applicationWorkflow.nodes.classify.businessLogic'),
@ -952,6 +964,7 @@ export const nodeDict: any = {
[WorkflowType.KnowledgeBase]: knowledgeBaseNode,
[WorkflowType.DataSourceLocalNode]: dataSourceLocalNode,
[WorkflowType.DataSourceWebNode]: dataSourceWebNode,
[WorkflowType.KnowledgeWriteNode]: knowledgeWriteNode,
}
export function isWorkFlow(type: string | undefined) {

View File

@ -0,0 +1,6 @@
<template>
<el-avatar shape="square">
<img src="@/assets/workflow/icon_knowledge_write.svg" style="width: 75%" alt="" />
</el-avatar>
</template>
<script setup lang="ts"></script>

View File

@ -0,0 +1,15 @@
import KnowledgeWriteVue from './index.vue'
import { AppNode, AppNodeModel } from '@/workflow/common/app-node'
class KnowledgeWriteNode extends AppNode {
constructor(props: any) {
super(props, KnowledgeWriteVue)
}
}
export default {
type: 'knowledge-write-node',
model: AppNodeModel,
view: KnowledgeWriteNode,
}

View File

@ -0,0 +1,95 @@
<template>
<NodeContainer :nodeModel="nodeModel">
<h5 class="title-decoration-1 mb-8">{{ $t('views.applicationWorkflow.nodeSetting') }}</h5>
<el-card shadow="never" class="card-never">
<el-form
@submit.prevent
:model="form_data"
label-position="top"
require-asterisk-position="right"
label-width="auto"
ref="IntentClassifyNodeFormRef"
hide-required-asterisk
>
<el-form-item
prop="paragraph_list"
:label="$t('common.inputContent')"
:rules="{
message: $t('views.applicationWorkflow.nodes.textToSpeechNode.content.label'),
trigger: 'change',
required: true,
}"
>
<template #label>
<div class="flex-between">
<div>
<span
>{{ $t('common.inputContent')
}}<span class="color-danger">*</span></span
>
</div>
</div>
</template>
<NodeCascader
ref="nodeCascaderRef"
:nodeModel="nodeModel"
class="w-full"
:placeholder="$t('views.applicationWorkflow.nodes.textToSpeechNode.content.label')"
v-model="form_data.paragraph_list"
/>
</el-form-item>
<el-form-item
prop="chunk_length"
:label="$t('views.applicationWorkflow.nodes.knowledgeWriteNode.chunk_length')"
:rules="{
message: $t('views.applicationWorkflow.nodes.knowledgeWriteNode.chunk_length'),
trigger: 'change',
required: true,
}"
>
<template #label>
<div class="flex-between">
<div>
<span
>{{ $t('views.applicationWorkflow.nodes.knowledgeWriteNode.chunk_length')
}}<span class="color-danger">*</span></span
>
</div>
</div>
</template>
<el-slider v-model="form_data.chunk_length" show-input :max="8192"></el-slider>
</el-form-item>
</el-form>
</el-card>
</NodeContainer>
</template>
<script setup lang="ts">
import NodeContainer from '@/workflow/common/NodeContainer.vue'
import { computed } from 'vue'
import { set } from 'lodash'
import NodeCascader from '@/workflow/common/NodeCascader.vue'
const props = defineProps<{ nodeModel: any }>()
const form = {
paragraph_list: [],
chunk_length: 4096
}
const form_data = computed({
get: () => {
if (props.nodeModel.properties.node_data) {
return props.nodeModel.properties.node_data
} else {
set(props.nodeModel.properties, 'node_data', form)
}
return props.nodeModel.properties.node_data
},
set: (value) => {
set(props.nodeModel.properties, 'node_data', value)
},
})
</script>
<style lang="scss" scoped></style>