mirror of
https://github.com/1Panel-dev/MaxKB.git
synced 2025-12-26 01:33:05 +00:00
feat: add support for uploading other file types and extend file upload settings
--story=1018411 --user=刘瑞斌 【工作流应用】文件上传可以支持其它文件类型 https://www.tapd.cn/57709429/s/1688679
This commit is contained in:
parent
54c9d4e725
commit
d32f7d36a6
|
|
@ -40,6 +40,7 @@ class BaseStartStepNode(IStarNode):
|
|||
self.context['document'] = details.get('document_list')
|
||||
self.context['image'] = details.get('image_list')
|
||||
self.context['audio'] = details.get('audio_list')
|
||||
self.context['other'] = details.get('other_list')
|
||||
self.status = details.get('status')
|
||||
self.err_message = details.get('err_message')
|
||||
for key, value in workflow_variable.items():
|
||||
|
|
@ -59,7 +60,8 @@ class BaseStartStepNode(IStarNode):
|
|||
'question': question,
|
||||
'image': self.workflow_manage.image_list,
|
||||
'document': self.workflow_manage.document_list,
|
||||
'audio': self.workflow_manage.audio_list
|
||||
'audio': self.workflow_manage.audio_list,
|
||||
'other': self.workflow_manage.other_list,
|
||||
}
|
||||
return NodeResult(node_variable, workflow_variable)
|
||||
|
||||
|
|
@ -83,5 +85,6 @@ class BaseStartStepNode(IStarNode):
|
|||
'image_list': self.context.get('image'),
|
||||
'document_list': self.context.get('document'),
|
||||
'audio_list': self.context.get('audio'),
|
||||
'other_list': self.context.get('other'),
|
||||
'global_fields': global_fields
|
||||
}
|
||||
|
|
|
|||
|
|
@ -238,6 +238,7 @@ class WorkflowManage:
|
|||
base_to_response: BaseToResponse = SystemToResponse(), form_data=None, image_list=None,
|
||||
document_list=None,
|
||||
audio_list=None,
|
||||
other_list=None,
|
||||
start_node_id=None,
|
||||
start_node_data=None, chat_record=None, child_node=None):
|
||||
if form_data is None:
|
||||
|
|
@ -248,12 +249,15 @@ class WorkflowManage:
|
|||
document_list = []
|
||||
if audio_list is None:
|
||||
audio_list = []
|
||||
if other_list is None:
|
||||
other_list = []
|
||||
self.start_node_id = start_node_id
|
||||
self.start_node = None
|
||||
self.form_data = form_data
|
||||
self.image_list = image_list
|
||||
self.document_list = document_list
|
||||
self.audio_list = audio_list
|
||||
self.other_list = other_list
|
||||
self.params = params
|
||||
self.flow = flow
|
||||
self.context = {}
|
||||
|
|
|
|||
|
|
@ -245,6 +245,7 @@ class OpenAIChatSerializer(serializers.Serializer):
|
|||
'image_list': instance.get('image_list', []),
|
||||
'document_list': instance.get('document_list', []),
|
||||
'audio_list': instance.get('audio_list', []),
|
||||
'other_list': instance.get('other_list', []),
|
||||
}
|
||||
).chat(base_to_response=OpenaiToResponse())
|
||||
|
||||
|
|
@ -274,6 +275,7 @@ class ChatMessageSerializer(serializers.Serializer):
|
|||
image_list = serializers.ListField(required=False, error_messages=ErrMessage.list(_("picture")))
|
||||
document_list = serializers.ListField(required=False, error_messages=ErrMessage.list(_("document")))
|
||||
audio_list = serializers.ListField(required=False, error_messages=ErrMessage.list(_("Audio")))
|
||||
other_list = serializers.ListField(required=False, error_messages=ErrMessage.list(_("Other")))
|
||||
child_node = serializers.DictField(required=False, allow_null=True,
|
||||
error_messages=ErrMessage.dict(_("Child Nodes")))
|
||||
|
||||
|
|
@ -372,6 +374,7 @@ class ChatMessageSerializer(serializers.Serializer):
|
|||
image_list = self.data.get('image_list')
|
||||
document_list = self.data.get('document_list')
|
||||
audio_list = self.data.get('audio_list')
|
||||
other_list = self.data.get('other_list')
|
||||
user_id = chat_info.application.user_id
|
||||
chat_record_id = self.data.get('chat_record_id')
|
||||
chat_record = None
|
||||
|
|
@ -388,7 +391,7 @@ class ChatMessageSerializer(serializers.Serializer):
|
|||
'client_id': client_id,
|
||||
'client_type': client_type,
|
||||
'user_id': user_id}, WorkFlowPostHandler(chat_info, client_id, client_type),
|
||||
base_to_response, form_data, image_list, document_list, audio_list,
|
||||
base_to_response, form_data, image_list, document_list, audio_list, other_list,
|
||||
self.data.get('runtime_node_id'),
|
||||
self.data.get('node_data'), chat_record, self.data.get('child_node'))
|
||||
r = work_flow_manage.run()
|
||||
|
|
|
|||
|
|
@ -144,6 +144,8 @@ class ChatView(APIView):
|
|||
'document_list') if 'document_list' in request.data else [],
|
||||
'audio_list': request.data.get(
|
||||
'audio_list') if 'audio_list' in request.data else [],
|
||||
'other_list': request.data.get(
|
||||
'other_list') if 'other_list' in request.data else [],
|
||||
'client_type': request.auth.client_type,
|
||||
'node_id': request.data.get('node_id', None),
|
||||
'runtime_node_id': request.data.get('runtime_node_id', None),
|
||||
|
|
|
|||
|
|
@ -10,7 +10,8 @@
|
|||
uploadDocumentList.length ||
|
||||
uploadImageList.length ||
|
||||
uploadAudioList.length ||
|
||||
uploadVideoList.length
|
||||
uploadVideoList.length ||
|
||||
uploadOtherList.length
|
||||
"
|
||||
>
|
||||
<el-row :gutter="10">
|
||||
|
|
@ -50,6 +51,42 @@
|
|||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col
|
||||
v-for="(item, index) in uploadOtherList"
|
||||
:key="index"
|
||||
:xs="24"
|
||||
:sm="props.type === 'debug-ai-chat' ? 24 : 12"
|
||||
:md="props.type === 'debug-ai-chat' ? 24 : 12"
|
||||
:lg="props.type === 'debug-ai-chat' ? 24 : 12"
|
||||
:xl="props.type === 'debug-ai-chat' ? 24 : 12"
|
||||
class="mb-8"
|
||||
>
|
||||
<el-card
|
||||
shadow="never"
|
||||
style="--el-card-padding: 8px; max-width: 100%"
|
||||
class="file cursor"
|
||||
>
|
||||
<div
|
||||
class="flex align-center"
|
||||
@mouseenter.stop="mouseenter(item)"
|
||||
@mouseleave.stop="mouseleave()"
|
||||
>
|
||||
<div
|
||||
@click="deleteFile(index, 'document')"
|
||||
class="delete-icon color-secondary"
|
||||
v-if="showDelete === item.url"
|
||||
>
|
||||
<el-icon>
|
||||
<CircleCloseFilled />
|
||||
</el-icon>
|
||||
</div>
|
||||
<img :src="getImgUrl(item && item?.name)" alt="" width="24" />
|
||||
<div class="ml-4 ellipsis-1" :title="item && item?.name">
|
||||
{{ item && item?.name }}
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
|
||||
<el-col
|
||||
:xs="24"
|
||||
|
|
@ -310,9 +347,10 @@ const imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'bmp']
|
|||
const documentExtensions = ['pdf', 'docx', 'txt', 'xls', 'xlsx', 'md', 'html', 'csv']
|
||||
const videoExtensions = ['mp4', 'avi', 'mov', 'mkv', 'flv']
|
||||
const audioExtensions = ['mp3', 'wav', 'ogg', 'aac', 'm4a']
|
||||
let otherExtensions = ['ppt', 'doc']
|
||||
|
||||
const getAcceptList = () => {
|
||||
const { image, document, audio, video } = props.applicationDetails.file_upload_setting
|
||||
const { image, document, audio, video, other } = props.applicationDetails.file_upload_setting
|
||||
let accepts: any = []
|
||||
if (image) {
|
||||
accepts = [...imageExtensions]
|
||||
|
|
@ -326,6 +364,11 @@ const getAcceptList = () => {
|
|||
if (video) {
|
||||
accepts = [...accepts, ...videoExtensions]
|
||||
}
|
||||
if (other) {
|
||||
// 其他文件类型
|
||||
otherExtensions = props.applicationDetails.file_upload_setting.otherExtensions
|
||||
accepts = [...accepts, ...otherExtensions]
|
||||
}
|
||||
|
||||
if (accepts.length === 0) {
|
||||
return `.${t('chat.uploadFile.tipMessage')}`
|
||||
|
|
@ -339,7 +382,8 @@ const checkMaxFilesLimit = () => {
|
|||
uploadImageList.value.length +
|
||||
uploadDocumentList.value.length +
|
||||
uploadAudioList.value.length +
|
||||
uploadVideoList.value.length
|
||||
uploadVideoList.value.length +
|
||||
uploadOtherList.value.length
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -350,7 +394,8 @@ const uploadFile = async (file: any, fileList: any) => {
|
|||
uploadImageList.value.length +
|
||||
uploadDocumentList.value.length +
|
||||
uploadAudioList.value.length +
|
||||
uploadVideoList.value.length
|
||||
uploadVideoList.value.length +
|
||||
uploadOtherList.value.length
|
||||
if (file_limit_once >= maxFiles) {
|
||||
MsgWarning(t('chat.uploadFile.limitMessage1') + maxFiles + t('chat.uploadFile.limitMessage2'))
|
||||
fileList.splice(0, fileList.length)
|
||||
|
|
@ -376,6 +421,8 @@ const uploadFile = async (file: any, fileList: any) => {
|
|||
uploadVideoList.value.push(file)
|
||||
} else if (audioExtensions.includes(extension)) {
|
||||
uploadAudioList.value.push(file)
|
||||
} else if (otherExtensions.includes(extension)) {
|
||||
uploadOtherList.value.push(file)
|
||||
}
|
||||
|
||||
if (!chatId_context.value) {
|
||||
|
|
@ -434,6 +481,15 @@ const uploadFile = async (file: any, fileList: any) => {
|
|||
file.file_id = f[0].file_id
|
||||
}
|
||||
})
|
||||
uploadOtherList.value.forEach((file: any) => {
|
||||
const f = response.data.filter(
|
||||
(f: any) => f.name.replaceAll(' ', '') === file.name.replaceAll(' ', '')
|
||||
)
|
||||
if (f.length > 0) {
|
||||
file.url = f[0].url
|
||||
file.file_id = f[0].file_id
|
||||
}
|
||||
})
|
||||
if (!inputValue.value && uploadImageList.value.length > 0) {
|
||||
inputValue.value = t('chat.uploadFile.imageMessage')
|
||||
}
|
||||
|
|
@ -499,6 +555,7 @@ const uploadImageList = ref<Array<any>>([])
|
|||
const uploadDocumentList = ref<Array<any>>([])
|
||||
const uploadVideoList = ref<Array<any>>([])
|
||||
const uploadAudioList = ref<Array<any>>([])
|
||||
const uploadOtherList = ref<Array<any>>([])
|
||||
|
||||
const showDelete = ref('')
|
||||
|
||||
|
|
@ -709,13 +766,15 @@ function autoSendMessage() {
|
|||
image_list: uploadImageList.value,
|
||||
document_list: uploadDocumentList.value,
|
||||
audio_list: uploadAudioList.value,
|
||||
video_list: uploadVideoList.value
|
||||
video_list: uploadVideoList.value,
|
||||
other_list: uploadOtherList.value,
|
||||
})
|
||||
inputValue.value = ''
|
||||
uploadImageList.value = []
|
||||
uploadDocumentList.value = []
|
||||
uploadAudioList.value = []
|
||||
uploadVideoList.value = []
|
||||
uploadOtherList.value = []
|
||||
if (quickInputRef.value) {
|
||||
quickInputRef.value.textareaStyle.height = '45px'
|
||||
}
|
||||
|
|
@ -771,6 +830,8 @@ function deleteFile(index: number, val: string) {
|
|||
uploadVideoList.value.splice(index, 1)
|
||||
} else if (val === 'audio') {
|
||||
uploadAudioList.value.splice(index, 1)
|
||||
} else if (val === 'other') {
|
||||
uploadOtherList.value.splice(index, 1)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -45,7 +45,9 @@ export default {
|
|||
document: 'Documents',
|
||||
image: 'Image',
|
||||
audio: 'Audio',
|
||||
video: 'Video'
|
||||
video: 'Video',
|
||||
other: 'Other file',
|
||||
addExtensions: 'Add file extensions',
|
||||
},
|
||||
status: {
|
||||
label: 'Status',
|
||||
|
|
@ -55,7 +57,7 @@ export default {
|
|||
param: {
|
||||
outputParam: 'Output Parameters',
|
||||
inputParam: 'Input Parameters',
|
||||
initParam: 'Startup Parameters',
|
||||
initParam: 'Startup Parameters'
|
||||
},
|
||||
|
||||
inputPlaceholder: 'Please input',
|
||||
|
|
|
|||
|
|
@ -45,7 +45,9 @@ export default {
|
|||
document: '文档',
|
||||
image: '图片',
|
||||
audio: '音频',
|
||||
video: '视频'
|
||||
video: '视频',
|
||||
other: '其他文件',
|
||||
addExtensions: '添加文件扩展名',
|
||||
},
|
||||
status: {
|
||||
label: '状态',
|
||||
|
|
|
|||
|
|
@ -45,7 +45,9 @@ export default {
|
|||
document: '文檔',
|
||||
image: '圖片',
|
||||
audio: '音頻',
|
||||
video: '視頻'
|
||||
video: '視頻',
|
||||
other: '其他文件',
|
||||
addExtensions: '添加文件擴展名'
|
||||
},
|
||||
status: {
|
||||
label: '狀態',
|
||||
|
|
|
|||
|
|
@ -57,10 +57,11 @@
|
|||
{{ $t('common.fileUpload.document') }}(TXT、MD、DOCX、HTML、CSV、XLSX、XLS、PDF)
|
||||
</p>
|
||||
<el-text class="color-secondary">{{
|
||||
$t(
|
||||
'views.applicationWorkflow.nodes.baseNode.FileUploadSetting.fileUploadType.documentText'
|
||||
)
|
||||
}}</el-text>
|
||||
$t(
|
||||
'views.applicationWorkflow.nodes.baseNode.FileUploadSetting.fileUploadType.documentText'
|
||||
)
|
||||
}}
|
||||
</el-text>
|
||||
</div>
|
||||
</div>
|
||||
<el-checkbox
|
||||
|
|
@ -84,10 +85,11 @@
|
|||
{{ $t('common.fileUpload.image') }}(JPG、JPEG、PNG、GIF)
|
||||
</p>
|
||||
<el-text class="color-secondary">{{
|
||||
$t(
|
||||
'views.applicationWorkflow.nodes.baseNode.FileUploadSetting.fileUploadType.imageText'
|
||||
)
|
||||
}}</el-text>
|
||||
$t(
|
||||
'views.applicationWorkflow.nodes.baseNode.FileUploadSetting.fileUploadType.imageText'
|
||||
)
|
||||
}}
|
||||
</el-text>
|
||||
</div>
|
||||
</div>
|
||||
<el-checkbox v-model="form_data.image" @change="form_data.image = !form_data.image" />
|
||||
|
|
@ -109,15 +111,58 @@
|
|||
{{ $t('common.fileUpload.audio') }}(MP3、WAV、OGG、ACC、M4A)
|
||||
</p>
|
||||
<el-text class="color-secondary">{{
|
||||
$t(
|
||||
'views.applicationWorkflow.nodes.baseNode.FileUploadSetting.fileUploadType.audioText'
|
||||
)
|
||||
}}</el-text>
|
||||
$t(
|
||||
'views.applicationWorkflow.nodes.baseNode.FileUploadSetting.fileUploadType.audioText'
|
||||
)
|
||||
}}
|
||||
</el-text>
|
||||
</div>
|
||||
</div>
|
||||
<el-checkbox v-model="form_data.audio" @change="form_data.audio = !form_data.audio" />
|
||||
</div>
|
||||
</el-card>
|
||||
<el-card
|
||||
shadow="hover"
|
||||
class="card-checkbox cursor w-full mb-8"
|
||||
:class="form_data.other ? 'active' : ''"
|
||||
style="--el-card-padding: 8px 16px"
|
||||
@click.stop="form_data.other = !form_data.other"
|
||||
>
|
||||
<div class="flex-between">
|
||||
<div class="flex align-center">
|
||||
<img class="mr-12" src="@/assets/icon_file-doc.svg" alt="" />
|
||||
<div>
|
||||
<p class="line-height-22 mt-4">
|
||||
{{ $t('common.fileUpload.other') }}
|
||||
</p>
|
||||
<div class="flex">
|
||||
<el-tag
|
||||
v-for="tag in form_data.otherExtensions"
|
||||
:key="tag"
|
||||
closable
|
||||
:disable-transitions="false"
|
||||
@close="handleClose(tag)"
|
||||
>
|
||||
{{ tag }}
|
||||
</el-tag>
|
||||
<el-input
|
||||
v-if="inputVisible"
|
||||
ref="InputRef"
|
||||
v-model="inputValue"
|
||||
class="w-20"
|
||||
size="small"
|
||||
@keyup.enter="handleInputConfirm"
|
||||
@blur="handleInputConfirm"
|
||||
/>
|
||||
<el-button v-else class="button-new-tag" size="small" @click.stop="showInput">
|
||||
+ {{ $t('common.fileUpload.addExtensions') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-checkbox v-model="form_data.other" @change="form_data.other = !form_data.other" />
|
||||
</div>
|
||||
</el-card>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
|
|
@ -133,20 +178,28 @@
|
|||
|
||||
<script setup lang="ts">
|
||||
import { nextTick, ref } from 'vue'
|
||||
import type { InputInstance } from 'element-plus'
|
||||
import { cloneDeep } from 'lodash'
|
||||
|
||||
const emit = defineEmits(['refresh'])
|
||||
const props = defineProps<{ nodeModel: any }>()
|
||||
|
||||
const dialogVisible = ref(false)
|
||||
const inputVisible = ref(false)
|
||||
const inputValue = ref('')
|
||||
const loading = ref(false)
|
||||
const fieldFormRef = ref()
|
||||
const InputRef = ref<InputInstance>()
|
||||
|
||||
const form_data = ref({
|
||||
maxFiles: 3,
|
||||
fileLimit: 50,
|
||||
document: true,
|
||||
image: false,
|
||||
audio: false,
|
||||
video: false
|
||||
video: false,
|
||||
other: false,
|
||||
otherExtensions: ['ppt', 'doc']
|
||||
})
|
||||
|
||||
function open(data: any) {
|
||||
|
|
@ -160,11 +213,31 @@ function close() {
|
|||
dialogVisible.value = false
|
||||
}
|
||||
|
||||
const handleClose = (tag: string) => {
|
||||
form_data.value.otherExtensions = form_data.value.otherExtensions.filter(item => item !== tag)
|
||||
}
|
||||
|
||||
const showInput = () => {
|
||||
inputVisible.value = true
|
||||
nextTick(() => {
|
||||
InputRef.value!.input!.focus()
|
||||
})
|
||||
}
|
||||
const handleInputConfirm = () => {
|
||||
if (inputValue.value) {
|
||||
form_data.value.otherExtensions.push(inputValue.value)
|
||||
}
|
||||
inputVisible.value = false
|
||||
inputValue.value = ''
|
||||
}
|
||||
|
||||
async function submit() {
|
||||
const formEl = fieldFormRef.value
|
||||
if (!formEl) return
|
||||
await formEl.validate().then(() => {
|
||||
emit('refresh', form_data.value)
|
||||
const formattedData = cloneDeep(form_data.value)
|
||||
emit('refresh', formattedData)
|
||||
// emit('refresh', form_data.value)
|
||||
props.nodeModel.graphModel.eventCenter.emit('refreshFileUploadConfig')
|
||||
dialogVisible.value = false
|
||||
})
|
||||
|
|
|
|||
|
|
@ -314,7 +314,9 @@ const switchFileUpload = () => {
|
|||
document: true,
|
||||
image: false,
|
||||
audio: false,
|
||||
video: false
|
||||
video: false,
|
||||
other: false,
|
||||
otherExtensions: ['ppt', 'doc']
|
||||
}
|
||||
|
||||
if (form_data.value.file_upload_enable) {
|
||||
|
|
|
|||
|
|
@ -78,7 +78,8 @@ const refreshFileUploadConfig = () => {
|
|||
item.value !== 'image' &&
|
||||
item.value !== 'document' &&
|
||||
item.value !== 'audio' &&
|
||||
item.value !== 'video'
|
||||
item.value !== 'video' &&
|
||||
item.value !== 'other'
|
||||
)
|
||||
|
||||
if (form_data.length === 0) {
|
||||
|
|
@ -98,6 +99,9 @@ const refreshFileUploadConfig = () => {
|
|||
if (form_data[0].video) {
|
||||
fileUploadFields.push({ label: t('common.fileUpload.video'), value: 'video' })
|
||||
}
|
||||
if (form_data[0].other) {
|
||||
fileUploadFields.push({ label: t('common.fileUpload.other'), value: 'other' })
|
||||
}
|
||||
|
||||
set(props.nodeModel.properties.config, 'fields', [...fields, ...fileUploadFields])
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue