|
@@ -21,7 +21,7 @@
|
|
|
<!-- <transition name="el-zoom-in-top"> -->
|
|
|
<div class="dialogueList mt-4" v-show="item.open">
|
|
|
<div class="flex justify-between mb-2">
|
|
|
- <el-button v-if="item.isDelete == 0 && item.type == 0" type="primary" class="flex-1" round @click="newStart_juese(item)">新的对话</el-button>
|
|
|
+ <el-button v-if="item.isDelete == 0" type="primary" class="flex-1" round @click="newStart_juese(item)">新的对话</el-button>
|
|
|
<div v-else class="flex-1 rounded border border-gray-200 text-sm p-2 text-gray-600">
|
|
|
{{item.characterName}}已经被设定为私有或被创建者删除。
|
|
|
</div>
|
|
@@ -140,11 +140,14 @@
|
|
|
</div>
|
|
|
<div class="mt-3 text-sm max-h-48">
|
|
|
<div v-if="info.sceneList && info.sceneList.length > 0" class="grid grid-cols-2 gap-2 mb-4 cursor-pointer">
|
|
|
- <div class="flex flex-col justify-center" v-for="(item, index) in info.sceneList" :key="index" @click="sceneChange(item)">
|
|
|
- <img class=" rounded w-full h-24 object-cover" :src="baseApi + item.background" alt="">
|
|
|
- <div>{{ item.sceneName }}</div>
|
|
|
- <div class=" text-gray-400">{{ item.sceneDescription }}</div>
|
|
|
- </div>
|
|
|
+ <template v-for="(item, index) in info.sceneList" >
|
|
|
+ <div v-if="item.isDelete == 0" class="flex flex-col justify-center" :key="index" @click="sceneChange(item)">
|
|
|
+ <img class=" rounded w-full h-24 object-cover" :src="baseApi + item.background" alt="">
|
|
|
+ <div>{{ item.sceneName }}</div>
|
|
|
+ <div class=" text-gray-400">{{ item.sceneDescription }}</div>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+
|
|
|
</div>
|
|
|
<el-empty v-else description="暂无场景"></el-empty>
|
|
|
<div class="flex justify-center mt-10">
|
|
@@ -258,15 +261,15 @@
|
|
|
</div>
|
|
|
<div class="messageRight">
|
|
|
<div class="message mt-4 ml-4 p-2 rounded-r-md rounded-bl-md text-xs" >
|
|
|
- <div class="yyPlayBg mb-2 w-16 p-1 cursor-pointer" >
|
|
|
+ <div v-if="item.voiceFilePosition" class="yyPlayBg mb-2 w-16 p-1 cursor-pointer" >
|
|
|
<img v-if="audioPlayIndex == index" class="yyPlay" src="@/assets/images/播放/yyPlay1.png" alt="" >
|
|
|
- <img v-else class="yyPlay" src="@/assets/images/播放/yyPlay.png" alt="" @click="playAudio(index)">
|
|
|
+ <img v-else class="yyPlay" src="@/assets/images/播放/yyPlay.png" alt="" @click="playAudio(item.voiceFilePosition, index)">
|
|
|
<!-- <svg-icon class="icon" class-name="speech-icon" icon-class="speech" @click.stop="click" /> -->
|
|
|
</div>
|
|
|
<div v-show="!item.content" class="loadingMessage" >
|
|
|
<div v-loading="!item.content" element-loading-background="rgba(0, 0, 0, 0.0)"></div>
|
|
|
</div>
|
|
|
- <p v-show="item.content">{{ item.content }} </p>
|
|
|
+ <p style="white-space: pre-line;" v-show="item.content">{{ item.content }} </p>
|
|
|
<div class="messageOptions" v-show="returnMessage.length == 1">
|
|
|
<div class="option" v-for="(item, index) in messageOptions" :key="index" @click="messageOptionClick(item.chatGuidance)">
|
|
|
{{ item.chatGuidance }}
|
|
@@ -280,7 +283,7 @@
|
|
|
<div v-if="item.role == 'user'" class="mb-4 flex me" :key="index">
|
|
|
<div class="pt-2 photo">
|
|
|
<img
|
|
|
- src="@/assets/images/default_avatar_user.png"
|
|
|
+ :src="$store.state.user.avatar"
|
|
|
class="rounded-full w-14 h-14 object-cover"
|
|
|
/>
|
|
|
</div>
|
|
@@ -296,6 +299,7 @@
|
|
|
|
|
|
<div class="inputBox absolute left-2 right-2 bottom-4 " @click="inputBoxClick">
|
|
|
<input
|
|
|
+ v-if="canChat"
|
|
|
ref="input"
|
|
|
type="text"
|
|
|
placeholder="输入消息..."
|
|
@@ -303,7 +307,7 @@
|
|
|
v-model="content"
|
|
|
@keydown="Enterkey"
|
|
|
/>
|
|
|
- <div class="flex pt-6 justify-between">
|
|
|
+ <div class="flex pt-6 justify-between" v-if="canChat">
|
|
|
<div class="tools w-36 flex justify-between">
|
|
|
<i class="el-icon-setting text-2xl cursor-pointer" @click="showConfig = true"></i>
|
|
|
<i class="el-icon-picture-outline text-2xl cursor-pointer"></i>
|
|
@@ -313,6 +317,9 @@
|
|
|
<v-icon name="paper-plane" scale="1.5"/>
|
|
|
</button>
|
|
|
</div>
|
|
|
+ <div v-if="!canChat" class=" flex w-full text-sm text-gray-400">
|
|
|
+ 当前角色或场景已被设定为私有或被创作者删除,但你任然可以查看历史对话。
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
@@ -372,7 +379,8 @@ import {
|
|
|
getChatCharacterRecordsApi,
|
|
|
getChatRecordApi,
|
|
|
updateTitleApi,
|
|
|
- clearRecordApi
|
|
|
+ clearRecordApi,
|
|
|
+ getVoiceFileApi
|
|
|
} from "@/api/chat.js"
|
|
|
import { detailApi } from "@/api/detail.js"
|
|
|
import { Message, MessageBox, Notification, Loading } from 'element-ui'
|
|
@@ -416,17 +424,27 @@ export default {
|
|
|
value1: false,
|
|
|
value2: false,
|
|
|
},
|
|
|
-
|
|
|
+ //音频相关↓
|
|
|
//音频地址
|
|
|
audioUrl: '',
|
|
|
+ videoLoop: null,
|
|
|
+ videoLoopTime: 0,
|
|
|
//场景下拉菜单
|
|
|
dropdown3Show: false,
|
|
|
// 场景对话相关
|
|
|
sceneId: null,
|
|
|
- sceneInfo: {}
|
|
|
+ sceneInfo: {},
|
|
|
}
|
|
|
},
|
|
|
computed: {
|
|
|
+ canChat() {
|
|
|
+ // console.log(this.info.isDelete, 'this.info.isDelete');
|
|
|
+ if (!this.sceneId) {
|
|
|
+ return this.info.isDelete == 0
|
|
|
+ } else {
|
|
|
+ return this.sceneInfo.isDelete == 0
|
|
|
+ }
|
|
|
+ },
|
|
|
showNodata() {
|
|
|
return this.allRecords.length == 0 && !this.$route.query.characterId
|
|
|
}
|
|
@@ -458,6 +476,8 @@ export default {
|
|
|
},
|
|
|
methods: {
|
|
|
async init() {
|
|
|
+ // 获取模型列表
|
|
|
+ this.getModelList()
|
|
|
// 获取用户所有聊天记录
|
|
|
await this.getChatCharacterRecords()
|
|
|
// 如果用角色id获取角色详情
|
|
@@ -473,8 +493,6 @@ export default {
|
|
|
}
|
|
|
// 查找当前角色是否有对话记录
|
|
|
this.searchHistory(this.info.id)
|
|
|
- // 获取模型列表
|
|
|
- this.getModelList()
|
|
|
},
|
|
|
// 左侧面板变化
|
|
|
showInfoChange(index) {
|
|
@@ -662,7 +680,13 @@ export default {
|
|
|
this.historyRes = res.data
|
|
|
for (let i = 0; i < array.length; i++) {
|
|
|
const element = array[i];
|
|
|
- this.returnMessage = [...this.returnMessage, ...JSON.parse(element.history)]
|
|
|
+ let history = JSON.parse(element.history)
|
|
|
+ history.map(item => {
|
|
|
+ if (item.role == 'assistant') {
|
|
|
+ item.voiceFilePosition = element.voiceFilePosition
|
|
|
+ }
|
|
|
+ })
|
|
|
+ this.returnMessage = [...this.returnMessage, ...history]
|
|
|
}
|
|
|
})
|
|
|
},
|
|
@@ -910,6 +934,14 @@ export default {
|
|
|
if (!this.content) {
|
|
|
return
|
|
|
}
|
|
|
+ // 初始化定时器和audio的状态
|
|
|
+ if (this.videoLoop) {
|
|
|
+ clearInterval(this.videoLoop)
|
|
|
+ this.videoLoop = null
|
|
|
+ this.audioUrl = ''
|
|
|
+ this.$refs.audio.currentTime = 0;
|
|
|
+ this.$refs.audio.pause()
|
|
|
+ }
|
|
|
// 如果没有对话记录id,新增对话记录
|
|
|
if (!this.recordId) {
|
|
|
this.recordId = await this.addChat()
|
|
@@ -939,7 +971,8 @@ export default {
|
|
|
// 新增一条ai信息
|
|
|
this.returnMessage.push({
|
|
|
role: 'assistant',
|
|
|
- content: ''
|
|
|
+ content: '',
|
|
|
+ voiceFilePosition: '',
|
|
|
})
|
|
|
|
|
|
// 清空输入框的值
|
|
@@ -951,7 +984,7 @@ export default {
|
|
|
|
|
|
if (res.status != 200) {
|
|
|
this.$message.error(res.statusText)
|
|
|
- this.returnMessage.splice(this.returnMessage.length - 1, 1)
|
|
|
+ this.returnMessage.splice(this.returnMessage.length - 1, 2)
|
|
|
return
|
|
|
}
|
|
|
const reader = res.body.getReader()
|
|
@@ -974,9 +1007,10 @@ export default {
|
|
|
let historyRes = await getChatRecordApi(params)
|
|
|
this.historyRes = historyRes.data
|
|
|
// 如果开启自动播放,则查询并播放语音
|
|
|
- if (this.setting.value1 && !this.resError) {
|
|
|
+ this.audioUrl = ""
|
|
|
+ if (!this.resError) {
|
|
|
let index = this.historyRes.length * 2
|
|
|
- this.playAudio(index)
|
|
|
+ this.initAudio(index)
|
|
|
}
|
|
|
console.log('结束');
|
|
|
break;
|
|
@@ -1008,7 +1042,7 @@ export default {
|
|
|
}
|
|
|
if(JSON.parse(element).code == 500) {
|
|
|
console.log(JSON.parse(element), 'JSON.parse(element)');
|
|
|
- this.returnMessage.splice(this.returnMessage.length - 1, 1)
|
|
|
+ this.returnMessage.splice(this.returnMessage.length - 2, 2)
|
|
|
this.$message.error(JSON.parse(element).content || '系统错误请联系管理员')
|
|
|
this.resError = true
|
|
|
break;
|
|
@@ -1057,20 +1091,63 @@ export default {
|
|
|
this.getStreamChatWithWeb()
|
|
|
},
|
|
|
// 播放聊天语音
|
|
|
- playAudio(index) {
|
|
|
- console.log(index, 'index');
|
|
|
- console.log(this.historyRes, 'this.historyRes');
|
|
|
+ initAudio(index) {
|
|
|
+ // 从聊天记录获取id
|
|
|
let history = this.historyRes[ index / 2 - 1]
|
|
|
console.log(history, 'history');
|
|
|
+
|
|
|
+ this.loopGetVoice(history.id, index)
|
|
|
+ },
|
|
|
+ playAudio(url, index) {
|
|
|
+ this.audioUrl = url
|
|
|
this.audioPlayIndex = index
|
|
|
- this.audioUrl = history.voiceFilePosition
|
|
|
- console.log(this.audioUrl, 'this.audioUrl');
|
|
|
- console.log(this.$refs.audio, 'this.$refs.audio');
|
|
|
this.$refs.audio.volume = 1
|
|
|
setTimeout(() => {
|
|
|
- this.$refs.audio.play()
|
|
|
+ if (this.audioUrl) {
|
|
|
+ this.$refs.audio.play()
|
|
|
+ }
|
|
|
}, 1000)
|
|
|
},
|
|
|
+ async loopGetVoice(id, index) {
|
|
|
+
|
|
|
+ // 获取语音文件
|
|
|
+ let params = {
|
|
|
+ id: id
|
|
|
+ }
|
|
|
+ let fileRes = await getVoiceFileApi(params)
|
|
|
+ console.log(fileRes, 'file>>>');
|
|
|
+ if (fileRes.data) {
|
|
|
+ console.log(this.returnMessage[index], 'sssssssssss');
|
|
|
+ this.returnMessage[index].voiceFilePosition = fileRes.data.voiceFilePosition
|
|
|
+ // 有语音文件则直接播放
|
|
|
+ if (this.setting.value1) {
|
|
|
+ this.playAudio(fileRes.data.voiceFilePosition, index)
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 没有语音文件则开启定时器每两秒查询一次
|
|
|
+ this.videoLoopTime = 0
|
|
|
+ this.videoLoop = setInterval(() => {
|
|
|
+ console.log(this.videoLoopTime, '定时器');
|
|
|
+ // 如果计时器超过20秒则关闭不再获取语音文件
|
|
|
+ if (this.videoLoopTime >= 20) {
|
|
|
+ clearInterval(this.videoLoop)
|
|
|
+ this.videoLoop = null
|
|
|
+ }
|
|
|
+ this.videoLoopTime += 2
|
|
|
+ getVoiceFileApi(params).then(res => {
|
|
|
+ // 如果获取到语音文件则关闭计时器并播放语音
|
|
|
+ if (res.data) {
|
|
|
+ clearInterval(this.videoLoop)
|
|
|
+ this.videoLoop = null
|
|
|
+ this.returnMessage[index].voiceFilePosition = res.data.voiceFilePosition
|
|
|
+ if (this.setting.value1) {
|
|
|
+ this.playAudio(res.data.voiceFilePosition, index)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }, 2000)
|
|
|
+ }
|
|
|
+ },
|
|
|
audioEnd() {
|
|
|
// console.log('播放结束');
|
|
|
this.audioPlayIndex = null
|