|
@@ -45,7 +45,7 @@
|
|
|
</div>
|
|
|
<!-- 仅这一部分滚动 -->
|
|
|
<div class="window-content-wrap hidden-scrollbar">
|
|
|
- <div class="content-item" v-for="item in historyList" :key="item.AiChatId">
|
|
|
+ <div class="content-item" v-for="item in historyList" :key="item.AiChatId" >
|
|
|
<!-- user 提问 -->
|
|
|
<Message-Item :messageInfo="formatMsg(item,'user')"
|
|
|
@startTyping="handleStartTyping"
|
|
@@ -57,9 +57,22 @@
|
|
|
@finishedTyping="handleFinishedTyping"
|
|
|
/>
|
|
|
</div>
|
|
|
- <New-Window-Hint v-if="activeWindowId===0"/>
|
|
|
+ <New-Window-Hint v-if="activeWindowId===0" />
|
|
|
</div>
|
|
|
- <div class="input-box">
|
|
|
+ <div class="input-box" id="input-box">
|
|
|
+ <div class="upload-row">
|
|
|
+ <el-upload
|
|
|
+ style="display: inline-block; margin-right: 8px"
|
|
|
+ accept=".pptx,.pdf"
|
|
|
+ action=""
|
|
|
+ :http-request="handleUpload"
|
|
|
+ :before-upload="handleBeforeUpload"
|
|
|
+ :show-file-list="false"
|
|
|
+ :disabled="startUploadAudio">
|
|
|
+ <img src="~@/assets/img/icons/ai-upload.png" />
|
|
|
+ </el-upload>
|
|
|
+ <span>支持格式:PDF、PPTX;大小不超过10MB;要求纯文本,不含图片</span>
|
|
|
+ </div>
|
|
|
<textarea rows="6" v-model="inputText" placeholder="请输入提问,Shift+Enter换行" @keydown.enter="handleSendMsg"></textarea>
|
|
|
<div class="send-btn" @click="handleSendMsg"><img src="~@/assets/img/ai_m/send.png" />发送</div>
|
|
|
</div>
|
|
@@ -116,6 +129,9 @@ export default {
|
|
|
windowContentLoading:null,
|
|
|
answerLoading:false,//回答中
|
|
|
companyName:'',
|
|
|
+ aiFileIds:[],
|
|
|
+ // 上传窗口的队列
|
|
|
+ windowSet:new Set()
|
|
|
};
|
|
|
},
|
|
|
watch:{
|
|
@@ -162,16 +178,23 @@ export default {
|
|
|
if(res.Ret!==200) return
|
|
|
const {List} = res.Data
|
|
|
this.historyList = List||[]
|
|
|
+
|
|
|
+ this.aiFileIds=this.historyList.map(item => item.OpenaiFileId).filter(Boolean)
|
|
|
+
|
|
|
this.windowContentLoading&&this.windowContentLoading.close()
|
|
|
//使用模型
|
|
|
this.model = this.historyList.length?this.historyList[this.historyList.length-1].Model:'GPT-4 Turbo'
|
|
|
//如果有历史记录,则滚动到底部
|
|
|
- this.$nextTick(()=>{
|
|
|
- const windowContentWrap = document.querySelector('.window-content-wrap')
|
|
|
- windowContentWrap.scrollTo({
|
|
|
- top:windowContentWrap.scrollHeight,
|
|
|
- behavior:'smooth'
|
|
|
- })
|
|
|
+ this.windowContentToBottom()
|
|
|
+ })
|
|
|
+ },
|
|
|
+ // 滚动到聊天窗口底部
|
|
|
+ windowContentToBottom(){
|
|
|
+ this.$nextTick(()=>{
|
|
|
+ const windowContentWrap = document.querySelector('.window-content-wrap')
|
|
|
+ windowContentWrap.scrollTo({
|
|
|
+ top:windowContentWrap.scrollHeight,
|
|
|
+ behavior:'smooth'
|
|
|
})
|
|
|
})
|
|
|
},
|
|
@@ -184,11 +207,12 @@ export default {
|
|
|
messageType:'',
|
|
|
modelName:''
|
|
|
}
|
|
|
- const {Ask,Answer,CreateTime,ModifyTime,isPlay,Model} = msg
|
|
|
+ const {Ask,Answer,CreateTime,ModifyTime,isPlay,Model,OpenaiFilePath} = msg
|
|
|
if(type==='user'){
|
|
|
msgObj.messageText = Ask||''
|
|
|
msgObj.messageType = 'question'
|
|
|
msgObj.messageTime = CreateTime||''
|
|
|
+ msgObj.askFileUrl = OpenaiFilePath || ''
|
|
|
}
|
|
|
else{
|
|
|
msgObj.messageText = Answer||''
|
|
@@ -196,6 +220,7 @@ export default {
|
|
|
msgObj.messageTime = ModifyTime||''
|
|
|
msgObj.modelName = Model||''
|
|
|
msgObj.isPlay = Boolean(isPlay)
|
|
|
+ msgObj.askFileUrl = OpenaiFilePath || ''
|
|
|
}
|
|
|
return msgObj
|
|
|
},
|
|
@@ -211,6 +236,7 @@ export default {
|
|
|
this.activeWindow=null
|
|
|
this.historyList=[]
|
|
|
this.model='GPT-4 Turbo'
|
|
|
+ this.aiFileIds=[]
|
|
|
//this.inputText=''
|
|
|
this.isTyping = false
|
|
|
},
|
|
@@ -319,7 +345,7 @@ export default {
|
|
|
//mock 加入到historyList中
|
|
|
const msgObj = {
|
|
|
AiChatId:-1,
|
|
|
- AiChatTopicId:0,
|
|
|
+ AiChatTopicId:this.activeWindowId || 0,
|
|
|
Ask:this.inputText,
|
|
|
Answer:'回答生成中...',
|
|
|
CreateTime:'',
|
|
@@ -329,20 +355,23 @@ export default {
|
|
|
this.historyList.push(msgObj)
|
|
|
|
|
|
//滚动到底部
|
|
|
- this.$nextTick(()=>{
|
|
|
- const windowContentWrap = document.querySelector('.window-content-wrap')
|
|
|
- windowContentWrap.scrollTo({
|
|
|
- top:windowContentWrap.scrollHeight,
|
|
|
- behavior:'smooth'
|
|
|
- })
|
|
|
- })
|
|
|
+ this.windowContentToBottom()
|
|
|
+
|
|
|
const inputText = this.inputText
|
|
|
this.inputText = ''
|
|
|
- aiQAInterence.sendChatMsg({
|
|
|
+ let apiName = "sendChatMsg"
|
|
|
+ let params={
|
|
|
AiChatTopicId:this.activeWindowId<=0?0:this.activeWindowId,
|
|
|
Ask:inputText,
|
|
|
// Model:this.model
|
|
|
- }).then(res=>{
|
|
|
+ }
|
|
|
+ if(this.aiFileIds && this.aiFileIds.length>0){
|
|
|
+ // 文件检索功能
|
|
|
+ apiName="fileRetrieve"
|
|
|
+ params.OpenaiFileId=this.aiFileIds
|
|
|
+ }
|
|
|
+ // console.log(params,"params");
|
|
|
+ aiQAInterence[apiName](params).then(res=>{
|
|
|
this.answerLoading=false
|
|
|
//在回答未获取前切换了新窗口
|
|
|
if(this.historyList.length===0){
|
|
@@ -387,7 +416,10 @@ export default {
|
|
|
})
|
|
|
},
|
|
|
//获取窗口列表
|
|
|
- getWindowList(){
|
|
|
+ /**
|
|
|
+ * @param {*} topicId AiChatTopicId 定位到具体窗口
|
|
|
+ */
|
|
|
+ getWindowList(topicId){
|
|
|
this.listWrapLoading = this.$loading({
|
|
|
target:document.querySelector('.list-wrap'),
|
|
|
background: 'rgba(244, 245, 249, 1)'
|
|
@@ -395,6 +427,9 @@ export default {
|
|
|
aiQAInterence.getTopicList().then(res=>{
|
|
|
if(res.Ret!==200) return
|
|
|
this.windowList = res.Data.List||[]
|
|
|
+ if(topicId){
|
|
|
+ this.changeActiveWindow({AiChatTopicId:topicId})
|
|
|
+ }
|
|
|
this.listWrapLoading&&this.listWrapLoading.close()
|
|
|
})
|
|
|
},
|
|
@@ -405,11 +440,112 @@ export default {
|
|
|
this.companyName=res.Data.CompanyName||''
|
|
|
}
|
|
|
})
|
|
|
+ },
|
|
|
+ inputBoxDragover(event){
|
|
|
+ event.preventDefault(); //阻止默认行为,允许放置
|
|
|
+ },
|
|
|
+ inputBoxDrop(event){
|
|
|
+ event.preventDefault(); //阻止浏览器默认行为
|
|
|
+ // 获取文件的数据
|
|
|
+ const DataTransferItemList = event.dataTransfer.files
|
|
|
+ if(DataTransferItemList && DataTransferItemList.length){
|
|
|
+ if(DataTransferItemList.length>1){
|
|
|
+ return this.$message.error("单次只能上传一个文件,请重试");
|
|
|
+ }else{
|
|
|
+ let file = DataTransferItemList[0]
|
|
|
+ if(file.type && (file.name.endsWith('.pdf')||file.name.endsWith('.pptx'))){
|
|
|
+ if(file.size/1024/1024 > 10.1){
|
|
|
+ this.$message.error("上传文件大小不超过10MB");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ this.handleUpload({file})
|
|
|
+ }else{
|
|
|
+ return this.$message.error("上传文件格式只支持PDF、PPTX");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }else{
|
|
|
+ // 没有文件数据
|
|
|
+ let txt = event.dataTransfer.getData("text/plain")
|
|
|
+ this.inputText=txt
|
|
|
+ }
|
|
|
+ },
|
|
|
+ handleBeforeUpload(e) {
|
|
|
+ if(!(e.name.endsWith('.pdf') || e.name.endsWith('.pptx'))){
|
|
|
+ this.$message.error("上传文件格式只支持PDF、PPTX");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if(!(e.size/1024/1024 < 10.1)){
|
|
|
+ this.$message.error("上传文件大小不超过10MB");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ handleUpload(e){
|
|
|
+ // console.log(this.windowSet,this.activeWindowId);
|
|
|
+ if(this.windowSet.has(this.activeWindowId)){
|
|
|
+ return this.$message.warning("请等待文件上传完成")
|
|
|
+ }
|
|
|
+
|
|
|
+ let {file} = e
|
|
|
+ let downloadHint = this.$message({
|
|
|
+ type:"info",
|
|
|
+ message:'上传中,请稍后······',
|
|
|
+ duration:0,
|
|
|
+ iconClass:'el-icon-loading'
|
|
|
+ })
|
|
|
+ let formData = new FormData()
|
|
|
+ formData.append('File',file)
|
|
|
+ formData.append('AiChatTopicId',this.activeWindowId)
|
|
|
+ this.windowSet.add(this.activeWindowId)
|
|
|
+ aiQAInterence.fileUpload(formData).then(res=>{
|
|
|
+ downloadHint.close()
|
|
|
+ if(res.Ret == 200){
|
|
|
+ let Data = res.Data || {}
|
|
|
+ this.$message.success(`${Data.ResourceName}上传成功`)
|
|
|
+ if(this.windowList.find(item => item.AiChatTopicId == Data.AiChatTopicId)){
|
|
|
+ // 窗口存在
|
|
|
+ this.windowSet.delete(Data.AiChatTopicId)
|
|
|
+
|
|
|
+ if(Data.AiChatTopicId == this.activeWindowId){
|
|
|
+ this.aiFileIds.push(Data.OpenaiFileId)
|
|
|
+ const msgObj = {
|
|
|
+ AiChatId:Data.AiChatId || -1,
|
|
|
+ AiChatTopicId:Data.AiChatTopicId,
|
|
|
+ Ask:Data.ResourceName,
|
|
|
+ OpenaiFilePath:Data.ResourceUrl,
|
|
|
+ Answer:Data.Answer || '',
|
|
|
+ CreateTime:Data.CreateTime||'',
|
|
|
+ ModifyTime:Data.ModifyTime || '',
|
|
|
+ Model:this.model
|
|
|
+ }
|
|
|
+ this.historyList.push(msgObj)
|
|
|
+ this.windowContentToBottom()
|
|
|
+ }
|
|
|
+ }else{
|
|
|
+ //窗口不存在
|
|
|
+ this.windowSet.delete(0)
|
|
|
+ this.getWindowList(this.activeWindowId==0 ? Data.AiChatTopicId:0)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }).catch(()=>{
|
|
|
+ downloadHint.close()
|
|
|
+ // 失败,清空
|
|
|
+ this.windowSet.clear()
|
|
|
+ })
|
|
|
}
|
|
|
},
|
|
|
mounted(){
|
|
|
this.getWindowList()
|
|
|
this.getBaseConfig()
|
|
|
+ const dropDom = document.getElementById('input-box')
|
|
|
+ dropDom.addEventListener('dragover',this.inputBoxDragover);
|
|
|
+
|
|
|
+ dropDom.addEventListener('drop',this.inputBoxDrop);
|
|
|
+ },
|
|
|
+ beforeDestroy(){
|
|
|
+ const dropDom = document.getElementById('input-box')
|
|
|
+ dropDom.removeEventListener('dragover',this.inputBoxDragover);
|
|
|
+
|
|
|
+ dropDom.removeEventListener('drop',this.inputBoxDrop);
|
|
|
}
|
|
|
};
|
|
|
</script>
|
|
@@ -556,13 +692,30 @@ $border-color:#3D52A1;
|
|
|
}
|
|
|
}
|
|
|
.input-box{
|
|
|
- padding:30px;
|
|
|
+ padding:12px 30px 30px;
|
|
|
position: relative;
|
|
|
+ .upload-row{
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ padding: 0 20px;
|
|
|
+ margin-bottom: 12px;
|
|
|
+ img{
|
|
|
+ height: 20px;
|
|
|
+ width: 20px;
|
|
|
+ vertical-align: bottom;
|
|
|
+ box-shadow: 3px 3px 8px 0px #182c421f;
|
|
|
+ }
|
|
|
+ span{
|
|
|
+ color: #A5A5A5;
|
|
|
+ font-size: 15px;
|
|
|
+ font-weight: 400;
|
|
|
+ }
|
|
|
+ }
|
|
|
textarea{
|
|
|
width:100%;
|
|
|
border-radius: 16px;
|
|
|
box-sizing: border-box;
|
|
|
- padding:20px 85px 20px 20px;
|
|
|
+ padding:20px 95px 20px 20px;
|
|
|
font-size: 16px;
|
|
|
resize: none;
|
|
|
border-color: #E3E3E3;
|