Parcourir la source

问答增加文件上传功能

htc il y a 5 jours
Parent
commit
8c0d017d12

BIN
src/assets/images/agent/file_pdf.png


BIN
src/assets/images/agent/file_word.png


+ 179 - 21
src/views/modules/agent/dialog.vue

@@ -38,7 +38,15 @@
             <div class="list">
                 <div class="l_item" v-for="(item,index) in dialogList" :key="index">
                     <div class="li_pre my adfac" v-if="item.type===1">
-                        <div class="text">{{ item.question }}</div>
+                        <div class="li_file adfac" v-if="item.askFile">
+                            <img src="@/assets/images/agent/file_pdf.png" v-if="idx===2">
+                            <img src="@/assets/images/agent/file_word.png" v-else-if="idx===3">
+                            <div class="lif_info">
+                                <p>{{ item.qfileName }}</p>
+                                <p><span>{{ item.qfileType }}</span> <span>{{ item.qfileSize }}</span></p>
+                            </div>
+                        </div>
+                        <div class="text" v-else>{{ item.question }}</div>
                         <img class="img" src="@/assets/images/agent/dialog_avatar.png">
                     </div>
                     <div class="li_pre ai" v-else-if="item.type===2">
@@ -78,10 +86,18 @@
                         <div class="text">
                             <div class="title">报告分析</div>
                             <div class="tip">智能解读报告,快速找到关键信息,提出教练重点</div>
-                            <div class="upload adfac">
-                                <img src="@/assets/images/agent/upload.png">
-                                <div class="span">上传报告</div>
-                            </div>
+                            <el-upload
+                                :action="uploadUrl"
+                                :headers="uploadHeaders"
+                                :on-success="e=>uploadFileSuccess(e,'report')"
+                                :before-upload="e=>beforeAvatarUpload(e,'report')"
+                                :file-list="fileList"
+                                :limit="1">
+                                <div class="upload adfac">
+                                    <img src="@/assets/images/agent/upload.png">
+                                    <div class="span">上传报告</div>
+                                </div>
+                            </el-upload>
                         </div>
                     </div>
                     <div class="li_pre ai adfac" v-else-if="item.type===4">
@@ -89,10 +105,18 @@
                         <div class="text">
                             <div class="title">文档问答</div>
                             <div class="tip">提供全方位多角度的PREILL团队分析</div>
-                            <div class="upload adfac">
-                                <img src="@/assets/images/agent/upload.png">
-                                <div class="span">上传文档</div>
-                            </div>
+                            <el-upload
+                                :action="uploadUrl"
+                                :headers="uploadHeaders"
+                                :on-success="e=>uploadFileSuccess(e,'file')"
+                                :before-upload="e=>beforeAvatarUpload(e,'file')"
+                                :file-list="fileList"
+                                :limit="1">
+                                <div class="upload adfac">
+                                    <img src="@/assets/images/agent/upload.png">
+                                    <div class="span">上传文档</div>
+                                </div>
+                            </el-upload> 
                         </div>
                     </div>
                 </div>
@@ -115,9 +139,18 @@
                         <span>联网搜索</span>
                     </div>
                     <!-- <div class="abl_pre adfac" :class="{'active':isScwd}" @click="isScwd=!isScwd">
-                        <img src="@/assets/images/agent/upload.png" v-if="!isScwd">
-                        <img src="@/assets/images/agent/upload2.png" v-else>
-                        <span>上传文档</span>
+                        <el-upload
+                            :action="uploadUrl"
+                            :headers="uploadHeaders"
+                            :on-success="uploadFileSuccess"
+                            :before-upload="beforeAvatarUpload"
+                            :limit="1">
+                            <div>
+                                <img src="@/assets/images/agent/upload.png" v-if="!isScwd">
+                                <img src="@/assets/images/agent/upload2.png" v-else>
+                                <span>上传文档</span>
+                            </div>
+                        </el-upload> 
                     </div> -->
                 </div>
                 <div class="ab_r">
@@ -137,6 +170,8 @@
     import { sendChatMessageStream } from '@/api/agent'
     const { toClipboard } = useClipboard();
     const { proxy } = getCurrentInstance();
+    const uploadUrl = `${window.SITE_CONFIG["apiURL"]}/sys/oss/uploadFile`
+    const uploadHeaders = {token:Cookies.get("token")};
     
     const idx = ref('')
     const placeholder = ref('有什么问题,可以向我提问!')
@@ -149,13 +184,31 @@
     const isDz = ref(false)
     const isPl = ref(false)
     const dialogList = ref([])
+    const fileList = ref([])
+    const questionFile = ref('')
     const scrollableDiv = ref(null);
+    const askParams = ref({
+        query:'',
+        identity:'教练',
+    })
+    const askFileName = ref('')
+    const askFileType = ref('')
+    const askFileSize = ref('')
 
     const currentTaskId = ref('');
 
     const handleBack = () => {
         dialogList.value = [];
         idx.value = '';
+        placeholder.value = '有什么问题,可以向我提问!';
+        questionFile.value = '';
+        askParams.value = {
+            query:'',
+            identity:'教练',
+        };
+        askFileName.value = '';
+        askFileType.value = '';
+        askFileSize.value = '';
         proxy.$router.push('/agent-dialog');
     }
 
@@ -175,8 +228,43 @@
         } 
     }
 
+    const uploadFileSuccess = (e,type) =>{
+        questionFile.value = e.data;
+        if(type==='report') askParams.value.report = e.data;
+        else if(type==='file') askParams.value.file = e.data;
+        proxy?.$modal.msgSuccess('上传成功');
+        let fnc = JSON.parse(JSON.stringify(askFileName.value));
+        let fnt = JSON.parse(JSON.stringify(askFileType.value));
+        let fns = JSON.parse(JSON.stringify(askFileSize.value));
+        dialogList.value.push({type:1,askFile:true,qfileName:fnc,qfileType:fnt,qfileSize:fns})
+        fileList.value = [];
+    }
+    const beforeAvatarUpload = (e,t) => {
+        let type = e.name.split('.')[e.name.split('.').length-1];
+        let isTxt = e.type === 'text/plain';
+        let isPdf = e.type === 'application/pdf';
+        let isHtml = e.type === 'text/html';
+        let isExcel = e.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
+        let isDocx = e.type === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
+        if((type.toLowerCase() === 'xlsx' || type.toLowerCase() === 'xls' && isExcel) 
+            || (type.toLowerCase() === 'docx' && isDocx)
+            || (type.toLowerCase() === 'txt' && isTxt)
+            || (type.toLowerCase() === 'pdf' && isPdf)
+            || (type.toLowerCase() === 'html' && isHtml)
+            && e.size <= 1024*1024*15){
+            askFileName.value = e.name;
+            askFileType.value = type.toUpperCase();
+            askFileSize.value = Math.floor(e.size/1024/1024).toFixed(1)+'MB';
+        }else{
+            proxy?.$modal.msgError('请上传txt、pdf、html、xlsx、xls或docx格式的文件!且文件大小不超过15MB!');
+            return false;
+        }
+    }
+
     const handleQuestion = () => {
         if(question.value.trim()=='') return proxy.$message.warning('请输入问题');
+        if(idx.value===2&&!questionFile.value) return proxy.$message.warning('请上传报告')
+        if(idx.value===3&&!questionFile.value) return proxy.$message.warning('请上传文档')
         let qc = JSON.parse(JSON.stringify(question.value.trim()));
         let obj1 = {
             question: question.value.trim(),
@@ -189,20 +277,55 @@
         }
         dialogList.value = [...dialogList.value,obj2]
         question.value = '';
-        startStream(qc);
+        askParams.value.query = qc;
+        startStream();
     }
 
     const startStream = async (query) => {
         try {
-            sendChatMessageStream({query}).then(res => {
-                if(res.code!==0) return proxy.$message.error(res.msg);
-                dialogList.value = [...dialogList.value].map((item, idx) => {
-                    if (idx === dialogList.value.length - 1) {
-                        return { ...item, answer: res?.data?.replace(/(\r\n|\n|\r)+/g, '<br>') };
+            const response = await fetch(`${window.SITE_CONFIG['apiURL']}/core/chat/messageByWorkflow`, {//streamingMessage messages messageByWorkflow
+                method: 'POST',
+                headers: {
+                    'token':Cookies.get('token') || '',
+                    'Content-Type': 'application/json',
+                    // 'Accept': 'text/event-stream',
+                },
+                body: JSON.stringify(askParams.value)
+            });
+
+            if (!response.ok || !response.body) {
+                throw new Error(`请求失败: ${response.status}`);
+            }
+
+            const reader = response.body.getReader();
+            const decoder = new TextDecoder('utf-8');
+            let buffer = ''; // 累积缓冲器
+
+            while (true) {
+                const { value, done } = await reader.read();
+                if (done) break;
+
+                buffer += decoder.decode(value, { stream: true });
+                const events = buffer.split('\n\n');
+                buffer = events.pop() || ''; 
+                events.forEach(event => {
+                    if (event.startsWith('data:')) {
+                        try {
+                            const jsonStr = event.slice(5).trim();
+                            const jsonData = JSON.parse(jsonStr);
+                            currentTaskId.value = jsonData?.task_id || '';
+                            dialogList.value = [...dialogList.value].map((item, idx) => {
+                                if (idx === dialogList.value.length - 1) {
+                                    return { ...item, answer: item.answer + (jsonData?.answer.replace(/(\r\n|\n|\r)+/g, '<br>') || '') };
+                                }
+                                return item;
+                            });
+                        } catch (e) {
+                            console.error('SSE解析失败', e, '原始数据:', event);
+                        }
                     }
-                    return item;
                 });
-            })
+            }
         } catch (err) {
             console.log(err,'err');
         }
@@ -239,7 +362,7 @@
         if(newVal.length>0) {
             if(scrollableDiv.value){
                 setTimeout(() => {
-                    scrollableDiv.value.scrollTop = 99999;
+                    scrollableDiv.value.scrollTop = 999999;
                 }, 50);
             } 
         }
@@ -256,6 +379,9 @@
 .icon_pop .popper__arrow::after{
     border-bottom-color:#000 !important;
 }
+.el-upload-list{
+    display: none !important;
+}
 </style>
 <style scoped lang="scss">
     ::v-deep .el-textarea textarea{
@@ -420,6 +546,38 @@
                                 }
                             }
                         }
+                        .li_file{
+                            max-width: calc(100% - 60px);
+                            padding: 14px 16px;
+                            box-sizing: border-box;
+                            background: #FFFFFF;
+                            box-shadow: 0px 2px 12px 0px rgba(0,0,0,0.04);
+                            border-radius: 8px;
+                            &>img{
+                                width: 30px;
+                                height: 30px;
+                            }
+                            .lif_info{
+                                margin-left: 16px;
+                                p{
+                                    font-family: PingFangSC, PingFang SC;
+                                    font-weight: 400;
+                                    font-size: 14px;
+                                    color: #1D2129;
+                                    line-height: 14px;
+                                    &:last-child{
+                                        margin-top: 8px;
+                                        span{
+                                            font-family: PingFangSC, PingFang SC;
+                                            font-weight: 400;
+                                            font-size: 12px;
+                                            color: #A6A6A6;
+                                            line-height: 12px;
+                                        }
+                                    }
+                                }
+                            }
+                        }
                         .icons{
                             width: 216px;
                             margin-top: 16px;