mirror of
https://github.com/1Panel-dev/MaxKB.git
synced 2025-12-26 01:33:05 +00:00
feat: Knowledge Base Workflow Execution Record (#4435)
This commit is contained in:
parent
0db2622663
commit
c4dd09ca1e
|
|
@ -15,6 +15,7 @@ from application.flow.i_step_node import KnowledgeWorkflowPostHandler
|
|||
from application.flow.knowledge_workflow_manage import KnowledgeWorkflowManage
|
||||
from application.flow.step_node import get_node
|
||||
from application.serializers.application import get_mcp_tools
|
||||
from common.db.search import page_search
|
||||
from common.exception.app_exception import AppApiException
|
||||
from common.utils.rsa_util import rsa_long_decrypt
|
||||
from common.utils.tool_code import ToolExecutor
|
||||
|
|
@ -41,16 +42,46 @@ class KnowledgeWorkflowActionRequestSerializer(serializers.Serializer):
|
|||
knowledge_base = serializers.DictField(required=True, label=_('knowledge base data'))
|
||||
|
||||
|
||||
class KnowledgeWorkflowActionListQuerySerializer(serializers.Serializer):
|
||||
user_name = serializers.CharField(required=False, label=_('Name'), allow_blank=True, allow_null=True)
|
||||
|
||||
|
||||
class KnowledgeWorkflowActionSerializer(serializers.Serializer):
|
||||
workspace_id = serializers.CharField(required=True, label=_('workspace id'))
|
||||
knowledge_id = serializers.UUIDField(required=True, label=_('knowledge id'))
|
||||
|
||||
def action(self, instance: Dict, with_valid=True):
|
||||
def get_query_set(self, instance: Dict):
|
||||
query_set = QuerySet(KnowledgeAction).filter(knowledge_id=self.data.get('knowledge_id'))
|
||||
if instance.get("user_name"):
|
||||
query_set = query_set.filter(meta__user_name__icontains=instance.get('user_name'))
|
||||
return query_set.order_by('-create_time')
|
||||
|
||||
def list(self, instance: Dict, is_valid=True):
|
||||
if is_valid:
|
||||
self.is_valid(raise_exception=True)
|
||||
KnowledgeWorkflowActionListQuerySerializer(data=instance).is_valid(raise_exception=True)
|
||||
return [{'id': a.id, 'knowledge_id': a.knowledge_id, 'state': a.state,
|
||||
'details': a.details, 'meta': a.meta, 'run_time': a.run_time} for a in self.get_query_set(instance)]
|
||||
|
||||
def page(self, current_page, page_size, instance: Dict, is_valid=True):
|
||||
if is_valid:
|
||||
self.is_valid(raise_exception=True)
|
||||
KnowledgeWorkflowActionListQuerySerializer(data=instance).is_valid(raise_exception=True)
|
||||
return page_search(current_page, page_size, self.get_query_set(instance),
|
||||
lambda a: {'id': a.id, 'knowledge_id': a.knowledge_id, 'state': a.state,
|
||||
'details': a.details, 'meta': a.meta, 'run_time': a.run_time})
|
||||
|
||||
def action(self, instance: Dict, user, with_valid=True):
|
||||
if with_valid:
|
||||
self.is_valid(raise_exception=True)
|
||||
knowledge_workflow = QuerySet(KnowledgeWorkflow).filter(knowledge_id=self.data.get("knowledge_id")).first()
|
||||
knowledge_action_id = uuid.uuid7()
|
||||
KnowledgeAction(id=knowledge_action_id, knowledge_id=self.data.get("knowledge_id"), state=State.STARTED).save()
|
||||
meta = {'user_id': str(user.id),
|
||||
'user_name': user.username}
|
||||
KnowledgeAction(id=knowledge_action_id,
|
||||
knowledge_id=self.data.get("knowledge_id"),
|
||||
state=State.STARTED,
|
||||
meta=meta).save()
|
||||
work_flow_manage = KnowledgeWorkflowManage(
|
||||
Workflow.new_instance(knowledge_workflow.work_flow, WorkflowMode.KNOWLEDGE),
|
||||
{'knowledge_id': self.data.get("knowledge_id"), 'knowledge_action_id': knowledge_action_id, 'stream': True,
|
||||
|
|
@ -59,9 +90,9 @@ class KnowledgeWorkflowActionSerializer(serializers.Serializer):
|
|||
KnowledgeWorkflowPostHandler(None, knowledge_action_id))
|
||||
work_flow_manage.run()
|
||||
return {'id': knowledge_action_id, 'knowledge_id': self.data.get("knowledge_id"), 'state': State.STARTED,
|
||||
'details': {}}
|
||||
'details': {}, 'meta': meta}
|
||||
|
||||
def upload_document(self, instance: Dict, with_valid=True):
|
||||
def upload_document(self, instance: Dict, user, with_valid=True):
|
||||
if with_valid:
|
||||
self.is_valid(raise_exception=True)
|
||||
knowledge_workflow = QuerySet(KnowledgeWorkflow).filter(knowledge_id=self.data.get("knowledge_id")).first()
|
||||
|
|
@ -71,7 +102,10 @@ class KnowledgeWorkflowActionSerializer(serializers.Serializer):
|
|||
knowledge_id=self.data.get("knowledge_id")).order_by(
|
||||
'-create_time')[0:1].first()
|
||||
knowledge_action_id = uuid.uuid7()
|
||||
KnowledgeAction(id=knowledge_action_id, knowledge_id=self.data.get("knowledge_id"), state=State.STARTED).save()
|
||||
meta = {'user_id': str(user.id),
|
||||
'user_name': user.username}
|
||||
KnowledgeAction(id=knowledge_action_id, knowledge_id=self.data.get("knowledge_id"), state=State.STARTED,
|
||||
meta=meta).save()
|
||||
work_flow_manage = KnowledgeWorkflowManage(
|
||||
Workflow.new_instance(knowledge_workflow_version.work_flow, WorkflowMode.KNOWLEDGE),
|
||||
{'knowledge_id': self.data.get("knowledge_id"), 'knowledge_action_id': knowledge_action_id, 'stream': True,
|
||||
|
|
@ -80,7 +114,7 @@ class KnowledgeWorkflowActionSerializer(serializers.Serializer):
|
|||
KnowledgeWorkflowPostHandler(None, knowledge_action_id))
|
||||
work_flow_manage.run()
|
||||
return {'id': knowledge_action_id, 'knowledge_id': self.data.get("knowledge_id"), 'state': State.STARTED,
|
||||
'details': {}}
|
||||
'details': {}, 'meta': meta}
|
||||
|
||||
class Operate(serializers.Serializer):
|
||||
workspace_id = serializers.CharField(required=True, label=_('workspace id'))
|
||||
|
|
@ -94,7 +128,8 @@ class KnowledgeWorkflowActionSerializer(serializers.Serializer):
|
|||
knowledge_action = QuerySet(KnowledgeAction).filter(id=knowledge_action_id).first()
|
||||
return {'id': knowledge_action_id, 'knowledge_id': knowledge_action.knowledge_id,
|
||||
'state': knowledge_action.state,
|
||||
'details': knowledge_action.details}
|
||||
'details': knowledge_action.details,
|
||||
'meta': knowledge_action.meta}
|
||||
|
||||
|
||||
class KnowledgeWorkflowSerializer(serializers.Serializer):
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@ urlpatterns = [
|
|||
path('workspace/<str:workspace_id>/knowledge/<str:knowledge_id>/datasource/<str:type>/<str:id>/<str:function_name>', views.KnowledgeDatasourceView.as_view()),
|
||||
path('workspace/<str:workspace_id>/knowledge/<str:knowledge_id>/publish', views.KnowledgeWorkflowView.Publish.as_view()),
|
||||
path('workspace/<str:workspace_id>/knowledge/<str:knowledge_id>/debug', views.KnowledgeWorkflowActionView.as_view()),
|
||||
path('workspace/<str:workspace_id>/knowledge/<str:knowledge_id>/action/<int:current_page>/<int:page_size>', views.KnowledgeWorkflowActionView.Page.as_view()),
|
||||
path('workspace/<str:workspace_id>/knowledge/<str:knowledge_id>/upload_document', views.KnowledgeWorkflowUploadDocumentView.as_view()),
|
||||
path('workspace/<str:workspace_id>/knowledge/<str:knowledge_id>/action/<str:knowledge_action_id>', views.KnowledgeWorkflowActionView.Operate.as_view()),
|
||||
path('workspace/<str:workspace_id>/knowledge/<str:knowledge_id>/mcp_tools', views.McpServers.as_view()),
|
||||
|
|
|
|||
|
|
@ -78,14 +78,15 @@ class KnowledgeWorkflowUploadDocumentView(APIView):
|
|||
)
|
||||
def post(self, request: Request, workspace_id: str, knowledge_id: str):
|
||||
return result.success(KnowledgeWorkflowActionSerializer(
|
||||
data={'workspace_id': workspace_id, 'knowledge_id': knowledge_id}).upload_document(request.data, True))
|
||||
data={'workspace_id': workspace_id, 'knowledge_id': knowledge_id}).upload_document(request.data,
|
||||
request.user, True))
|
||||
|
||||
|
||||
class KnowledgeWorkflowActionView(APIView):
|
||||
authentication_classes = [TokenAuth]
|
||||
|
||||
@extend_schema(
|
||||
methods=['GET'],
|
||||
methods=['POST'],
|
||||
description=_('Knowledge workflow debug'),
|
||||
summary=_('Knowledge workflow debug'),
|
||||
operation_id=_('Knowledge workflow debug'), # type: ignore
|
||||
|
|
@ -106,7 +107,35 @@ class KnowledgeWorkflowActionView(APIView):
|
|||
)
|
||||
def post(self, request: Request, workspace_id: str, knowledge_id: str):
|
||||
return result.success(KnowledgeWorkflowActionSerializer(
|
||||
data={'workspace_id': workspace_id, 'knowledge_id': knowledge_id}).action(request.data, True))
|
||||
data={'workspace_id': workspace_id, 'knowledge_id': knowledge_id}).action(request.data, request.user, True))
|
||||
|
||||
class Page(APIView):
|
||||
authentication_classes = [TokenAuth]
|
||||
|
||||
@extend_schema(
|
||||
methods=['GET'],
|
||||
description=_('Page Knowledge workflow action'),
|
||||
summary=_('Page Knowledge workflow action'),
|
||||
operation_id=_('Page Knowledge workflow action'), # type: ignore
|
||||
parameters=KnowledgeWorkflowActionApi.get_parameters(),
|
||||
request=KnowledgeWorkflowActionApi.get_request(),
|
||||
responses=KnowledgeWorkflowActionApi.get_response(),
|
||||
tags=[_('Knowledge Base')] # type: ignore
|
||||
)
|
||||
@has_permissions(
|
||||
PermissionConstants.KNOWLEDGE_DOCUMENT_CREATE.get_workspace_knowledge_permission(),
|
||||
PermissionConstants.KNOWLEDGE_DOCUMENT_CREATE.get_workspace_permission_workspace_manage_role(),
|
||||
RoleConstants.WORKSPACE_MANAGE.get_workspace_role(),
|
||||
ViewPermission(
|
||||
[RoleConstants.USER.get_workspace_role()],
|
||||
[PermissionConstants.KNOWLEDGE.get_workspace_knowledge_permission()],
|
||||
CompareConstants.AND
|
||||
),
|
||||
)
|
||||
def get(self, request: Request, workspace_id: str, knowledge_id: str, current_page: int, page_size: int):
|
||||
return result.success(
|
||||
KnowledgeWorkflowActionSerializer(data={'workspace_id': workspace_id, 'knowledge_id': knowledge_id})
|
||||
.page(current_page, page_size, request.data))
|
||||
|
||||
class Operate(APIView):
|
||||
authentication_classes = [TokenAuth]
|
||||
|
|
|
|||
|
|
@ -382,19 +382,19 @@ const publish: (knowledge_id: string, loading?: Ref<boolean>) => Promise<Result<
|
|||
|
||||
/**
|
||||
* 保存知识库工作流
|
||||
* @param knowledge_id
|
||||
* @param data
|
||||
* @param loading
|
||||
* @returns
|
||||
* @param knowledge_id
|
||||
* @param data
|
||||
* @param loading
|
||||
* @returns
|
||||
*/
|
||||
const putKnowledgeWorkflow: (
|
||||
knowledge_id: string,
|
||||
data: any,
|
||||
loading?: Ref<boolean>,
|
||||
) => Promise<Result<any>> = (knowledge_id, data, loading) => {
|
||||
return put(`${prefix.value}/${knowledge_id}/workflow`, data, undefined, loading)
|
||||
return put(`${prefix.value}/${knowledge_id}/workflow`, data, undefined, loading)
|
||||
}
|
||||
|
||||
|
||||
const listKnowledgeVersion: (
|
||||
knowledge_id: string,
|
||||
loading?: Ref<boolean>,
|
||||
|
|
@ -414,7 +414,18 @@ const updateKnowledgeVersion: (
|
|||
loading,
|
||||
)
|
||||
}
|
||||
|
||||
const pageWorkflowAction: (
|
||||
knowledge_id: string,
|
||||
page: pageRequest,
|
||||
query: any,
|
||||
loading?: Ref<boolean>,
|
||||
) => Promise<Result<any>> = (knowledge_id: string, page, query, loading) => {
|
||||
return get(
|
||||
`${prefix.value}/${knowledge_id}/action/${page.current_page}/${page.page_size}`,
|
||||
query,
|
||||
loading,
|
||||
)
|
||||
}
|
||||
const getWorkflowAction: (
|
||||
knowledge_id: string,
|
||||
knowledge_action_id: string,
|
||||
|
|
@ -468,4 +479,5 @@ export default {
|
|||
publish,
|
||||
putKnowledgeWorkflow,
|
||||
workflowUpload,
|
||||
pageWorkflowAction,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,83 @@
|
|||
<template>
|
||||
<el-drawer v-model="drawer" title="执行记录" direction="rtl" size="800px" :before-close="close">
|
||||
<el-table v-if="active == 'list'" :data="data" style="width: 100%">
|
||||
<el-table-column prop="meta" label="发起人" width="180">
|
||||
<template #default="{ row }">
|
||||
{{ row.meta.user_name }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="sate" label="状态" width="180">
|
||||
<template #default="{ row }">
|
||||
{{ row.state }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="run_time" label="运行时间">
|
||||
<template #default="{ row }">
|
||||
{{ row.run_time }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作">
|
||||
<template #default="{ row }">
|
||||
<span @click="details(row)">执行详情</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<Result
|
||||
v-if="active == 'details'"
|
||||
:id="active_action_id"
|
||||
:knowledge_id="active_knowledge_id"
|
||||
></Result>
|
||||
</el-drawer>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { loadSharedApi } from '@/utils/dynamics-api/shared-api'
|
||||
import { computed, ref, reactive } from 'vue'
|
||||
import Result from '../action/Result.vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
const drawer = ref<boolean>(false)
|
||||
const active_knowledge_id = ref<string>()
|
||||
const active_action_id = ref<string>()
|
||||
const active = ref<'list' | 'details'>('list')
|
||||
const route = useRoute()
|
||||
const details = (row: any) => {
|
||||
active_action_id.value = row.id
|
||||
active.value = 'details'
|
||||
}
|
||||
|
||||
const apiType = computed(() => {
|
||||
if (route.path.includes('shared')) {
|
||||
return 'systemShare'
|
||||
} else if (route.path.includes('resource-management')) {
|
||||
return 'systemManage'
|
||||
} else {
|
||||
return 'workspace'
|
||||
}
|
||||
})
|
||||
const paginationConfig = reactive({
|
||||
current_page: 1,
|
||||
page_size: 30,
|
||||
total: 0,
|
||||
})
|
||||
const query = ref<any>({
|
||||
user_name: '',
|
||||
})
|
||||
const data = ref<Array<any>>([])
|
||||
const page = () => {
|
||||
loadSharedApi({ type: 'knowledge', systemType: apiType.value })
|
||||
.pageWorkflowAction(active_knowledge_id.value, paginationConfig, query)
|
||||
.then((ok: any) => {
|
||||
paginationConfig.total = ok.data?.total
|
||||
data.value = ok.data.records
|
||||
})
|
||||
}
|
||||
const open = (knowledge_id: string) => {
|
||||
drawer.value = true
|
||||
active_knowledge_id.value = knowledge_id
|
||||
page()
|
||||
}
|
||||
const close = () => {
|
||||
drawer.value = false
|
||||
}
|
||||
defineExpose({ open, close })
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
||||
|
|
@ -34,8 +34,7 @@
|
|||
<AppIcon iconName="app-debug-outlined" class="mr-4"></AppIcon>
|
||||
{{ $t('common.debug') }}
|
||||
</el-button>
|
||||
<el-button v-if="permissionPrecise.workflow_edit(id)"
|
||||
@click="saveknowledge(true)">
|
||||
<el-button v-if="permissionPrecise.workflow_edit(id)" @click="saveknowledge(true)">
|
||||
<AppIcon iconName="app-save-outlined" class="mr-4"></AppIcon>
|
||||
{{ $t('common.save') }}
|
||||
</el-button>
|
||||
|
|
@ -53,7 +52,10 @@
|
|||
<AppIcon iconName="app-import-doc" class="color-secondary"></AppIcon>
|
||||
{{ $t('views.workflow.operation.toImportDoc') }}
|
||||
</el-dropdown-item>
|
||||
|
||||
<el-dropdown-item @click="openListAction">
|
||||
<AppIcon iconName="app-history-outlined" class="color-secondary"></AppIcon>
|
||||
执行记录
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item @click="openHistory">
|
||||
<AppIcon iconName="app-history-outlined" class="color-secondary"></AppIcon>
|
||||
{{ $t('views.workflow.setting.releaseHistory') }}
|
||||
|
|
@ -127,6 +129,7 @@
|
|||
</div>
|
||||
</el-collapse-transition>
|
||||
<DebugVue ref="DebugRef"></DebugVue>
|
||||
<ListAction ref="ListActionRef"></ListAction>
|
||||
<!-- 发布历史 -->
|
||||
<PublishHistory
|
||||
v-if="showHistory"
|
||||
|
|
@ -142,6 +145,7 @@ import { useRouter, useRoute } from 'vue-router'
|
|||
import type { Action } from 'element-plus'
|
||||
import Workflow from '@/workflow/index.vue'
|
||||
import DropdownMenu from '@/components/workflow-dropdown-menu/index.vue'
|
||||
import ListAction from '@/views/knowledge-workflow/component/list-action/index.vue'
|
||||
import PublishHistory from '@/views/knowledge-workflow/component/PublishHistory.vue'
|
||||
import { isAppIcon, resetUrl } from '@/utils/common'
|
||||
import { MsgSuccess, MsgError, MsgConfirm } from '@/utils/message'
|
||||
|
|
@ -190,7 +194,7 @@ const isDefaultTheme = computed(() => {
|
|||
return theme.isDefaultTheme()
|
||||
})
|
||||
const DebugRef = ref<InstanceType<typeof DebugVue>>()
|
||||
|
||||
const ListActionRef = ref<InstanceType<typeof ListAction>>()
|
||||
let interval: any
|
||||
const workflowRef = ref()
|
||||
const workflowMainRef = ref()
|
||||
|
|
@ -235,6 +239,9 @@ function back() {
|
|||
go()
|
||||
}
|
||||
}
|
||||
const openListAction = () => {
|
||||
ListActionRef.value?.open(id)
|
||||
}
|
||||
function clickoutsideHistory() {
|
||||
if (!disablePublic.value) {
|
||||
showHistory.value = false
|
||||
|
|
|
|||
Loading…
Reference in New Issue