Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion apps/application/api/application_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
from rest_framework import serializers

from application.serializers.application import ApplicationCreateSerializer, ApplicationListResponse, \
ApplicationImportRequest, ApplicationEditSerializer, TextToSpeechRequest, SpeechToTextRequest, PlayDemoTextRequest
ApplicationImportRequest, ApplicationEditSerializer, TextToSpeechRequest, SpeechToTextRequest, PlayDemoTextRequest, \
BatchCleanTimeSerializer
from common.mixins.api_mixin import APIMixin
from common.result import ResultSerializer, ResultPageSerializer, DefaultResultSerializer
from knowledge.serializers.common import BatchSerializer, BatchMoveSerializer
Expand Down Expand Up @@ -181,6 +182,10 @@ def get_request():
def get_move_request():
return BatchMoveSerializer

@staticmethod
def get_clean_time_request():
return BatchCleanTimeSerializer


class ApplicationExportAPI(APIMixin):
@staticmethod
Expand Down
33 changes: 33 additions & 0 deletions apps/application/serializers/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -1634,3 +1634,36 @@ def batch_move(self, instance: Dict, with_valid=True):

QuerySet(Application).filter(id__in=id_list, workspace_id=workspace_id).update(folder_id=folder_id)
return True

@transaction.atomic
def batch_clean_time(self, instance: Dict, with_valid=True):
if with_valid:
BatchCleanTimeSerializer(data=instance).is_valid(model=Application, raise_exception=True)
self.is_valid(raise_exception=True)
id_list = instance.get("id_list")
workspace_id = self.data.get("workspace_id")
clean_time = instance.get("clean_time")
file_clean_time = instance.get("file_clean_time")
application_count = QuerySet(Application).filter(id__in=id_list, workspace_id=workspace_id).count()
if application_count != len(id_list):
raise AppApiException(500, _("Application does not exist"))

QuerySet(Application).filter(id__in=id_list, workspace_id=workspace_id).update(
clean_time=clean_time,
file_clean_time=file_clean_time,
)
return True


class BatchCleanTimeSerializer(BatchSerializer):
clean_time = serializers.IntegerField(required=True, min_value=1, max_value=100000, label=_("Clean time"))
file_clean_time = serializers.IntegerField(
required=True, min_value=1, max_value=100000, label=_("File clean time")
)

def is_valid(self, *, model=None, raise_exception=False):
super().is_valid(model=model, raise_exception=True)
if not self.data.get("id_list"):
raise AppApiException(500, _("id list cannot be empty"))
if self.data.get("file_clean_time") > self.data.get("clean_time"):
raise AppApiException(500, _("File clean time cannot exceed clean time"))
1 change: 1 addition & 0 deletions apps/application/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
path('workspace/<str:workspace_id>/application/<int:current_page>/<int:page_size>', views.ApplicationAPI.Page.as_view(), name='application_page'),
path('workspace/<str:workspace_id>/application/batch_delete', views.ApplicationAPI.BatchDelete.as_view()),
path('workspace/<str:workspace_id>/application/batch_move', views.ApplicationAPI.BatchMove.as_view()),
path('workspace/<str:workspace_id>/application/batch_clean_time', views.ApplicationAPI.BatchCleanTime.as_view()),
path('workspace/<str:workspace_id>/application/<str:application_id>', views.ApplicationAPI.Operate.as_view()),
path('workspace/<str:workspace_id>/application/<str:application_id>/publish', views.ApplicationAPI.Publish.as_view()),
path('workspace/<str:workspace_id>/application/<str:application_id>/move/<str:folder_id>', views.ApplicationAPI.Move.as_view()),
Expand Down
43 changes: 43 additions & 0 deletions apps/application/views/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,49 @@ def inner(view,r, **kwargs):

return result.success(inner(self,request, workspace_id=workspace_id))

class BatchCleanTime(APIView):
authentication_classes = [TokenAuth]

@extend_schema(
methods=['PUT'],
description=_("Batch update application chat log clear policy"),
summary=_("Batch update application chat log clear policy"),
operation_id=_("Batch update application chat log clear policy"),
parameters=ApplicationBatchOperateAPI.get_parameters(),
request=ApplicationBatchOperateAPI.get_clean_time_request(),
responses=result.DefaultResultSerializer,
tags=[_('Application')]
)
@has_permissions(PermissionConstants.APPLICATION_READ.get_workspace_permission(),
RoleConstants.USER.get_workspace_role(),
RoleConstants.WORKSPACE_MANAGE.get_workspace_role()
)
def put(self, request: Request, workspace_id: str):
id_list = request.data.get('id_list', [])
permitted_ids = check_batch_permissions(
request, id_list, 'application_id',
(PermissionConstants.APPLICATION_CHAT_LOG_CLEAR_POLICY.get_workspace_application_permission(),
PermissionConstants.APPLICATION_CHAT_LOG_CLEAR_POLICY.get_workspace_permission_workspace_manage_role(),
ViewPermission([RoleConstants.USER.get_workspace_role()],
[PermissionConstants.APPLICATION.get_workspace_application_permission()],
CompareConstants.AND),
RoleConstants.WORKSPACE_MANAGE.get_workspace_role()),
workspace_id=workspace_id
)

@log(menu='Application', operate='Batch update application chat log clear policy',
get_operation_object=lambda r, k: get_application_operation_object_batch(permitted_ids))
def inner(view,r, **kwargs):
return ApplicationBatchOperateSerializer(
data={'workspace_id': workspace_id, 'user_id': request.user.id}
).batch_clean_time({
'id_list': permitted_ids,
'clean_time': request.data.get('clean_time'),
'file_clean_time': request.data.get('file_clean_time')
})

return result.success(inner(self,request, workspace_id=workspace_id))

class McpServers(APIView):
authentication_classes = [TokenAuth]

Expand Down
17 changes: 17 additions & 0 deletions ui/src/api/application/application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,22 @@ const putMulMoveApplication: (data: any, loading?: Ref<boolean>) => Promise<Resu
return put(`${prefix.value}/batch_move`, data, undefined, loading)
}

/**
* 批量更新智能体对话日志清除策略
* @param 参数
* {
"id_list": [String],
"clean_time": number,
"file_clean_time": number
}
*/
const putMulCleanTime: (data: any, loading?: Ref<boolean>) => Promise<Result<boolean>> = (
data,
loading,
) => {
return put(`${prefix.value}/batch_clean_time`, data, undefined, loading)
}

export default {
getAllApplication,
getApplication,
Expand Down Expand Up @@ -486,4 +502,5 @@ export default {
moveApplication,
delMulApplication,
putMulMoveApplication,
putMulCleanTime,
}
2 changes: 2 additions & 0 deletions ui/src/locales/lang/en-US/views/application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ export default {
createWorkFlowApplication: 'Create Workflow Agent',
importApplication: 'Import Agent',
copyApplication: 'Copy Agent',
batchClearStrategyTip:
'This operation will batch update the chat log clear policy for the selected agents.',
simple: 'SIMPLE',
senior: 'WORKFLOW',
simpleAgent: 'Simple Agent',
Expand Down
1 change: 1 addition & 0 deletions ui/src/locales/lang/zh-CN/views/application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export default {
createWorkFlowApplication: '创建高级智能体',
importApplication: '导入智能体',
copyApplication: '复制智能体',
batchClearStrategyTip: '该操作会对选中的智能体批量调整对话日志清除策略。',
simple: '简易',
senior: '高级',
simpleAgent: '简易智能体',
Expand Down
1 change: 1 addition & 0 deletions ui/src/locales/lang/zh-Hant/views/application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export default {
createWorkFlowApplication: '建立進階智能體',
importApplication: '匯入智能體',
copyApplication: '複製智能體',
batchClearStrategyTip: '該操作會對選中的智能體批量調整對話日誌清除策略。',
AdvancedAgent: '進階編智能體',
simpleAgent: '簡易智能體',
simple: '簡易',
Expand Down
1 change: 1 addition & 0 deletions ui/src/permission/application/system-manage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const systemManage = {
copy: () => hasPermission([RoleConst.ADMIN, PermissionConst.RESOURCE_APPLICATION_COPY], 'OR'),
batchDelete: () => false,
batchMove: () => false,
batchCleanStrategy: () => false,
folderCreate: () => false,
edit: () => hasPermission([RoleConst.ADMIN, PermissionConst.RESOURCE_APPLICATION_EDIT], 'OR'),
publish: () =>
Expand Down
10 changes: 10 additions & 0 deletions ui/src/permission/application/workspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,16 @@ const workspace = {
],
'OR',
),
batchCleanStrategy: () =>
hasPermission(
[
RoleConst.USER.getWorkspaceRole,
RoleConst.WORKSPACE_MANAGE.getWorkspaceRole,
PermissionConst.APPLICATION_CHAT_LOG_CLEAR_POLICY.getWorkspacePermission,
PermissionConst.APPLICATION_CHAT_LOG_CLEAR_POLICY.getWorkspacePermissionWorkspaceManageRole,
],
'OR',
),
copy: (source_id: string) =>
hasPermission(
[
Expand Down
109 changes: 109 additions & 0 deletions ui/src/views/application/component/BatchClearStrategyDialog.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
<template>
<el-dialog
:title="$t('views.chatLog.buttons.clearStrategy')"
v-model="dialogVisible"
width="520px"
append-to-body
:close-on-click-modal="false"
:close-on-press-escape="false"
>
<el-alert
:title="$t('views.application.batchClearStrategyTip')"
type="info"
:closable="false"
class="mb-16"
/>
<div class="clean-strategy-row mb-16">
<span>{{ $t('common.delete') }}</span>
<el-input-number
v-model="days"
controls-position="right"
:min="1"
:max="100000"
:value-on-clear="0"
step-strictly
class="clean-strategy-number"
/>
<span>{{ $t('views.chatLog.daysText') }}</span>
</div>
<div class="clean-strategy-row">
<span>{{ $t('common.delete') }}</span>
<el-input-number
v-model="fileDays"
controls-position="right"
:min="1"
:max="days"
:value-on-clear="0"
step-strictly
class="clean-strategy-number"
/>
<span>{{ $t('views.chatLog.fileDaysText') }}</span>
</div>

<template #footer>
<span class="dialog-footer">
<el-button @click="dialogVisible = false" :loading="loading">
{{ $t('common.cancel') }}
</el-button>
<el-button type="primary" @click="submitHandle" :loading="loading">
{{ $t('common.save') }}
</el-button>
</span>
</template>
</el-dialog>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import ApplicationApi from '@/api/application/application'
import { MsgSuccess } from '@/utils/message'
import { t } from '@/locales'

const emit = defineEmits(['refresh'])

const loading = ref(false)
const dialogVisible = ref(false)
const days = ref(180)
const fileDays = ref(180)
const selectedIds = ref<string[]>([])

function open(idList: string[]) {
selectedIds.value = [...idList]
days.value = 180
fileDays.value = 180
dialogVisible.value = true
}

function submitHandle() {
if (fileDays.value > days.value) {
fileDays.value = days.value
}
ApplicationApi.putMulCleanTime(
{
id_list: selectedIds.value,
clean_time: days.value,
file_clean_time: fileDays.value,
},
loading,
).then(() => {
MsgSuccess(t('common.saveSuccess'))
dialogVisible.value = false
emit('refresh')
})
}

defineExpose({ open })
</script>

<style scoped lang="scss">
.clean-strategy-row {
display: flex;
align-items: center;
gap: 8px;
line-height: 32px;
}

.clean-strategy-number {
width: 110px;
}
</style>
23 changes: 21 additions & 2 deletions ui/src/views/application/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,11 @@
</div>
<span
class="ml-8"
v-if="permissionPrecise.batchDelete() || permissionPrecise.batchMove()"
v-if="
permissionPrecise.batchDelete() ||
permissionPrecise.batchMove() ||
permissionPrecise.batchCleanStrategy()
"
>
<el-button @click="batchSelectedHandle(true)" v-if="isBatch === false">
<AppIcon iconName="app-batch-delete" class="mr-4" />
Expand Down Expand Up @@ -363,6 +367,14 @@
{{ $t('common.moveTo') }}
</el-button>

<el-button
:disabled="multipleSelection.length === 0"
@click="openBatchClearStrategyDialog"
v-if="permissionPrecise.batchCleanStrategy()"
>
{{ $t('views.chatLog.buttons.clearStrategy') }}
</el-button>

<el-button
:disabled="multipleSelection.length === 0"
@click="deleteMulApplication"
Expand All @@ -382,6 +394,7 @@
<ResourceMappingDrawer ref="resourceMappingDrawerRef" />
<CreateApplicationDialog ref="CreateApplicationDialogRef" />
<CopyApplicationDialog ref="CopyApplicationDialogRef" />
<BatchClearStrategyDialog ref="BatchClearStrategyDialogRef" @refresh="refreshApplicationList()" />
<CreateFolderDialog ref="CreateFolderDialogRef" @refresh="refreshFolder" />
<MoveToDialog
ref="MoveToDialogRef"
Expand All @@ -408,6 +421,7 @@ import type { CheckboxValueType } from 'element-plus'
import CreateApplicationDialog from '@/views/application/component/CreateApplicationDialog.vue'
import CreateFolderDialog from '@/components/folder-virtualized-tree/CreateFolderDialog.vue'
import CopyApplicationDialog from '@/views/application/component/CopyApplicationDialog.vue'
import BatchClearStrategyDialog from '@/views/application/component/BatchClearStrategyDialog.vue'
import MoveToDialog from '@/components/folder-virtualized-tree/MoveToDialog.vue'
import ResourceAuthorizationDrawer from '@/components/resource-authorization-drawer/index.vue'
import ResourceTriggerDrawer from '@/views/trigger/ResourceTriggerDrawer.vue'
Expand Down Expand Up @@ -459,6 +473,7 @@ const paginationConfig = reactive({
const folderList = ref<any[]>([])
const applicationList = ref<any[]>([])
const CopyApplicationDialogRef = ref()
const BatchClearStrategyDialogRef = ref<InstanceType<typeof BatchClearStrategyDialog>>()

// 批量操作
const isBatch = ref(false)
Expand Down Expand Up @@ -523,6 +538,10 @@ function deleteMulApplication() {
.catch(() => {})
}

function openBatchClearStrategyDialog() {
BatchClearStrategyDialogRef.value?.open([...multipleSelection.value])
}

const resourceTriggerDrawerRef = ref<InstanceType<typeof ResourceTriggerDrawer>>()
const openTriggerDrawer = (data: any) => {
resourceTriggerDrawerRef.value?.open(data)
Expand Down Expand Up @@ -558,7 +577,7 @@ function openMoveToDialog(data?: any) {
MoveToDialogRef.value?.open(obj)
}

function refreshApplicationList(row: any) {
function refreshApplicationList(row?: any) {
if (row) {
// 不是根目录才会移除
if (folder.currentFolder?.parent_id) {
Expand Down
Loading