maxkb/ui/src/views/document/UploadDocument.vue
朱潮 3bbdbca861
Some checks are pending
sync2gitee / repo-sync (push) Waiting to run
Typos Check / Spell Check with Typos (push) Waiting to run
音视频前端支持分段参数
2025-12-19 10:34:05 +08:00

313 lines
9.3 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="upload-document p-12-24">
<div class="flex align-center mb-16">
<back-button to="-1" style="margin-left: -4px"></back-button>
<h3 style="display: inline-block">{{ $t('views.document.uploadDocument') }}</h3>
</div>
<el-card style="--el-card-padding: 0">
<div class="upload-document__main flex" v-loading="loading">
<div class="upload-document__component main-calc-height">
<el-scrollbar>
<template v-if="active === 0">
<div class="upload-component p-24">
<!-- 上传文档 -->
<UploadComponent ref="UploadComponentRef" />
</div>
</template>
<template v-else-if="active === 1">
<SetRules ref="SetRulesRef" />
</template>
<template v-else-if="active === 2">
<ResultSuccess :data="successInfo" />
</template>
</el-scrollbar>
</div>
</div>
</el-card>
<div class="upload-document__footer text-right border-t" v-if="active !== 2">
<el-button @click="router.go(-1)" :disabled="SetRulesRef?.loading || loading">{{
$t('common.cancel')
}}</el-button>
<el-button @click="prev" v-if="active === 1" :disabled="SetRulesRef?.loading || loading">{{
$t('views.document.buttons.prev')
}}</el-button>
<el-button
@click="next"
type="primary"
v-if="active === 0"
:disabled="SetRulesRef?.loading || loading"
>
{{
documentsType === 'txt' || documentsType === 'mineru' || documentsType === 'media'
? $t('views.document.buttons.next')
: $t('views.document.buttons.import')
}}
</el-button>
<el-button
@click="submit"
type="primary"
v-if="active === 1"
:disabled="SetRulesRef?.loading || loading"
>
{{ $t('views.document.buttons.import') }}
</el-button>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, computed, onUnmounted } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import SetRules from './upload/SetRules.vue'
import ResultSuccess from './upload/ResultSuccess.vue'
import UploadComponent from './upload/UploadComponent.vue'
import { loadSharedApi } from '@/utils/dynamics-api/shared-api'
import { MsgConfirm, MsgSuccess } from '@/utils/message'
import { t } from '@/locales'
import useStore from '@/stores'
const { knowledge } = useStore()
const documentsFiles = computed(() => knowledge.documentsFiles)
const documentsType = computed(() => knowledge.documentsType)
const router = useRouter()
const route = useRoute()
const {
params: { folderId },
query: { id }, // id为knowledgeID有id的是上传文档
} = route
const apiType = computed(() => {
if (route.path.includes('shared')) {
return 'systemShare'
} else if (route.path.includes('resource-management')) {
return 'systemManage'
} else {
return 'workspace'
}
})
const SetRulesRef = ref()
const UploadComponentRef = ref()
const loading = ref(false)
const disabled = ref(false)
const active = ref(0)
const successInfo = ref<any>(null)
async function next() {
disabled.value = true
if (await UploadComponentRef.value.validate()) {
if (documentsType.value === 'QA') {
const fd = new FormData()
documentsFiles.value.forEach((item: any) => {
if (item?.raw) {
fd.append('file', item?.raw)
}
})
if (id) {
// QA文档上传
loadSharedApi({ type: 'document', systemType: apiType.value })
.postQADocument(id as string, fd, loading)
.then(() => {
MsgSuccess(t('common.submitSuccess'))
clearStore()
router.push({
path: `/knowledge/${id}/${folderId}/document`,
})
})
}
} else if (documentsType.value === 'table') {
const fd = new FormData()
documentsFiles.value.forEach((item: any) => {
if (item?.raw) {
fd.append('file', item?.raw)
}
})
if (id) {
// table文档上传
loadSharedApi({ type: 'document', systemType: apiType.value })
.postTableDocument(id as string, fd, loading)
.then(() => {
MsgSuccess(t('common.submitSuccess'))
clearStore()
router.push({
path: `/knowledge/${id}/${folderId}/document`,
})
})
}
} else if (documentsType.value === 'mineru') {
// MinerU类型文档也需要进入分段设置页面
if (active.value++ > 2) active.value = 0
} else if (documentsType.value === 'media') {
// 音视频类型文档也需要进入分段设置页面
if (active.value++ > 2) active.value = 0
} else {
if (active.value++ > 2) active.value = 0
}
} else {
disabled.value = false
}
}
const prev = () => {
active.value = 0
}
function clearStore() {
knowledge.saveDocumentsFile([])
knowledge.saveDocumentsType('')
// 清空MinerU模型选择
knowledge.saveMinerUModels({
llmModel: null,
visionModel: null
})
// 清空音视频模型选择
knowledge.saveMediaModels({
sttModel: null,
llmModel: null
})
}
function submit() {
loading.value = true
const documents = [] as any
console.log('Submit called, documentsType:', documentsType.value)
console.log('mediaModels from store:', knowledge.mediaModels)
console.log('SetRulesRef.value:', SetRulesRef.value)
// 处理段落列表
const paragraphList = SetRulesRef.value?.paragraphList || []
console.log('paragraphList length:', paragraphList.length)
paragraphList.map((item: any) => {
if (!SetRulesRef.value?.checkedConnect) {
item.content.map((v: any) => {
delete v['problem_list']
})
}
const doc: any = {
name: item.name,
paragraphs: item.content,
source_file_id: item.source_file_id,
}
// 只有当文档类型确实是MinerU类型时才添加模型参数和分段规则
if (documentsType.value === 'mineru') {
// 确保有模型选择才添加
if (knowledge.mineruModels && knowledge.mineruModels.llmModel && knowledge.mineruModels.visionModel) {
doc.llm_model_id = knowledge.mineruModels.llmModel
doc.vision_model_id = knowledge.mineruModels.visionModel
}
// 传递分段规则
if (SetRulesRef.value?.form?.patterns) {
doc.split_patterns = SetRulesRef.value.form.patterns
}
}
// 只有当文档类型是音视频类型时才添加STT模型参数
else if (documentsType.value === 'media') {
console.log('Processing media document upload:', {
mediaModels: knowledge.mediaModels,
sttModel: knowledge.mediaModels?.sttModel,
llmModel: knowledge.mediaModels?.llmModel
})
// 确保有模型选择才添加
if (knowledge.mediaModels) {
if (knowledge.mediaModels.sttModel) {
doc.stt_model_id = knowledge.mediaModels.sttModel
}
if (knowledge.mediaModels.llmModel) {
doc.llm_model_id = knowledge.mediaModels.llmModel
}
}
// 传递分段规则(如果有)
if (SetRulesRef.value?.form) {
console.log('SetRulesRef.value.form:', SetRulesRef.value.form)
// 传递patterns
if (SetRulesRef.value.form.patterns) {
doc.split_patterns = SetRulesRef.value.form.patterns
}
// 传递limit (总是传递,即使是默认值)
doc.split_limit = SetRulesRef.value.form.limit
// 传递with_filter (总是传递,即使是默认值)
doc.split_with_filter = SetRulesRef.value.form.with_filter
console.log('Media chunking params:', {
split_patterns: doc.split_patterns,
split_limit: doc.split_limit,
split_with_filter: doc.split_with_filter
})
}
console.log('Final doc object for media:', doc)
}
documents.push(doc)
})
if (id) {
// 上传文档
console.log('Sending documents to backend:', documents)
loadSharedApi({ type: 'document', systemType: apiType.value })
.putMulDocument(id as string, documents)
.then(() => {
MsgSuccess(t('common.submitSuccess'))
clearStore()
router.push({
path: `/knowledge/${id}/${folderId}/document`,
})
})
.catch(() => {
loading.value = false
})
}
}
function back() {
if (documentsFiles.value?.length > 0) {
MsgConfirm(t('common.tip'), t('views.document.tip.saveMessage'), {
confirmButtonText: t('common.confirm'),
type: 'warning',
})
.then(() => {
router.go(-1)
clearStore()
})
.catch(() => {})
} else {
router.go(-1)
}
}
onUnmounted(() => {
clearStore()
})
</script>
<style lang="scss" scoped>
.upload-document {
&__steps {
min-width: 450px;
max-width: 800px;
width: 80%;
margin: 0 auto;
padding-right: 60px;
:deep(.el-step__line) {
left: 64% !important;
right: -33% !important;
}
}
&__component {
width: 100%;
margin: 0 auto;
overflow: hidden;
}
&__footer {
padding: 16px 24px;
position: fixed;
bottom: 0;
left: 0;
background: #ffffff;
width: 100%;
box-sizing: border-box;
}
.upload-component {
width: 70%;
margin: 0 auto;
margin-bottom: 20px;
}
}
</style>