|
@@ -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;
|