feat: Data source web node

This commit is contained in:
zhangzhanwei 2025-11-12 14:56:21 +08:00 committed by zhanweizhang7
parent 8df567fb79
commit 17c0056be1
13 changed files with 131 additions and 28 deletions

View File

@ -10,6 +10,7 @@ from .ai_chat_step_node import *
from .application_node import BaseApplicationNode
from .condition_node import *
from .data_source_local_node.impl.base_data_source_local_node import BaseDataSourceLocalNode
from .data_source_web_node.impl.base_data_source_web_node import BaseDataSourceWebNode
from .direct_reply_node import *
from .document_extract_node import *
from .form_node import *
@ -48,7 +49,7 @@ node_list = [BaseStartStepNode, BaseChatNode, BaseSearchKnowledgeNode, BaseSearc
BaseIntentNode, BaseLoopNode, BaseLoopStartStepNode,
BaseLoopContinueNode,
BaseLoopBreakNode, BaseVariableSplittingNode, BaseParameterExtractionNode, BaseVariableAggregationNode,
BaseDataSourceLocalNode]
BaseDataSourceLocalNode,BaseDataSourceWebNode]
def get_node(node_type):

View File

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

View File

@ -0,0 +1,30 @@
# coding=utf-8
"""
@project: MaxKB
@Authorniu
@file i_data_source_web_node.py
@date2025/11/12 13:47
@desc:
"""
from abc import abstractmethod
from application.flow.i_step_node import INode, NodeResult
class IDataSourceWebNode(INode):
type = 'data-source-web-node'
@staticmethod
@abstractmethod
def get_form_class():
pass
def _run(self):
return self.execute(**self.node_params_serializer.data, **self.flow_params_serializer.data)
def execute(self, **kwargs) -> NodeResult:
pass

View File

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

View File

@ -0,0 +1,29 @@
# coding=utf-8
"""
@project: MaxKB
@Authorniu
@file base_data_source_web_node.py
@date2025/11/12 13:47
@desc:
"""
from application.flow.i_step_node import NodeResult
from application.flow.step_node.data_source_web_node.i_data_source_web_node import IDataSourceWebNode
from common import forms
from common.forms import BaseForm
class BaseDataSourceWebNodeForm(BaseForm):
source_url = forms.TextInputField('source url', required=True)
selector = forms.TextInputField('knowledge selector', required=True)
class BaseDataSourceWebNode(IDataSourceWebNode):
def save_context(self, details, workflow_manage):
pass
@staticmethod
def get_form_class():
return BaseDataSourceWebNodeForm
def execute(self, **kwargs) -> NodeResult:
pass

View File

@ -39,6 +39,7 @@ export enum WorkflowType {
VideoUnderstandNode = 'video-understand-node',
ParameterExtractionNode = 'parameter-extraction-node',
DataSourceLocalNode = 'data-source-local-node',
DataSourceWebNode = 'data-source-web-node',
}
export enum WorkflowKind {
DataSource = 'data-source',

View File

@ -79,6 +79,12 @@ export default {
loopNodeBreakNodeRequired: 'Wireless loop must have a Break node',
},
nodes: {
dataSourceWebNode: {
label: 'Web Site',
text: 'Web Site',
display: 'No data available',
field_label: 'Document list',
},
classify: {
aiCapability: 'AI capability',
businessLogic: 'Business logic',

View File

@ -81,6 +81,12 @@ export default {
loopNodeBreakNodeRequired: '无限循环 必须存在 Break 节点',
},
nodes: {
dataSourceWebNode: {
label: 'Web站点',
text: 'Web站点',
display: '暂无数据',
field_label: '文档列表',
},
classify: {
aiCapability: 'AI能力',
businessLogic: '业务逻辑',

View File

@ -80,6 +80,12 @@ export default {
loopNodeBreakNodeRequired: '無限循環必須存在Break節點',
},
nodes: {
dataSourceWebNode: {
label: 'Web網站',
text: 'Web網站',
display: '暫無資料',
field_label: '文件列表',
},
classify: {
aiCapability: 'AI能力',
businessLogic: '業務邏輯',

View File

@ -69,7 +69,7 @@ const {
} = route as any
const sourceChange = (node_id: string) => {
const n = source_node_list.value.find((n: any) => n.id == node_id)
node_id = n ? ([WorkflowType.DataSourceLocalNode].includes(n.type) ? n.type : node_id) : node_id
node_id = n ? ([WorkflowType.DataSourceLocalNode,WorkflowType.DataSourceWebNode].includes(n.type) ? n.type : node_id) : node_id
loadSharedApi({ type: 'knowledge', systemType: apiType.value })
.getKnowledgeWorkflowFormList(id, 'local', node_id)
.then((ok) => {

View File

@ -98,6 +98,31 @@ export const dataSourceLocalNode = {
user_input_field_list: [],
},
}
export const dataSourceWebNode = {
id: WorkflowType.DataSourceWebNode,
type: WorkflowType.DataSourceWebNode,
x: 360,
y: 2761.3875,
text: t('views.applicationWorkflow.nodes.dataSourceWebNode.text', 'Web站点'),
label: t('views.applicationWorkflow.nodes.dataSourceWebNode.label', 'Web站点'),
properties: {
kind: WorkflowKind.DataSource,
height: 180,
stepName: t('views.applicationWorkflow.nodes.dataSourceWebNode.label', 'Web站点'),
config: {
fields: [
{
label: t('views.applicationWorkflow.nodes.dataSourceWebNode.field_label'),
value: 'document_list',
},
],
},
},
}
/**
*
* type nodes
@ -662,7 +687,7 @@ export const loopBreakNode = {
export const knowledgeMenuNodes = [
{
label: t('views.applicationWorkflow.nodes.classify.dataSource', '数据源'),
list: [dataSourceLocalNode],
list: [dataSourceLocalNode, dataSourceWebNode],
},
{
label: t('views.applicationWorkflow.nodes.classify.aiCapability'),
@ -926,6 +951,7 @@ export const nodeDict: any = {
[WorkflowType.VariableAggregationNode]: variableAggregationNode,
[WorkflowType.KnowledgeBase]: knowledgeBaseNode,
[WorkflowType.DataSourceLocalNode]: dataSourceLocalNode,
[WorkflowType.DataSourceWebNode]: dataSourceWebNode,
}
export function isWorkFlow(type: string | undefined) {

View File

@ -0,0 +1,6 @@
<template>
<el-avatar shape="square" style="background: #7F3BF5">
<img src="@/assets/knowledge/icon_web.svg" style="width: 65%" alt="" />
</el-avatar>
</template>
<script setup lang="ts"></script>

View File

@ -2,31 +2,7 @@
<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"
>
<el-form-item
:label="$t('views.problem.relateParagraph.selectDocument')"
:rules="{
type: 'array',
required: true,
message: $t('views.chatLog.documentPlaceholder'),
trigger: 'change',
}"
>
<NodeCascader
ref="nodeCascaderRef"
:nodeModel="nodeModel"
class="w-full"
:placeholder="$t('views.chatLog.documentPlaceholder')"
v-model="form_data.document_list"
/>
</el-form-item>
</el-form>
<h4>{{ $t('views.applicationWorkflow.nodes.dataSourceWebNode.display') }}</h4>
</el-card>
</NodeContainer>
</template>