This commit is contained in:
parent
8ab770305c
commit
d50341711e
|
@ -0,0 +1,57 @@
|
||||||
|
<template>
|
||||||
|
<div style="position: relative;">
|
||||||
|
<div class="div" />
|
||||||
|
<p class="text">
|
||||||
|
AI播放中
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.text{
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
font-size: 1.5em;
|
||||||
|
text-align: center;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
bottom: -6em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.div {
|
||||||
|
display: flex;
|
||||||
|
width: 3.5em;
|
||||||
|
height: 3.5em;
|
||||||
|
border: 3px solid transparent;
|
||||||
|
border-top-color: #3cefff;
|
||||||
|
border-bottom-color: #3cefff;
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: spin 1.5s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
div:before {
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
margin: auto;
|
||||||
|
width: 0.75em;
|
||||||
|
height: 0.75em;
|
||||||
|
border: 3px solid #3cefff;
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: pulse 1s alternate ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
to {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pulse {
|
||||||
|
from {
|
||||||
|
transform: scale(0.5);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,6 +1,7 @@
|
||||||
<script setup lang='ts'>
|
<script setup lang='ts'>
|
||||||
import { computed, reactive, ref, watch, toRef, nextTick } from 'vue'
|
import { computed, reactive, ref, watch } from 'vue'
|
||||||
import { NDropdown, useMessage } from 'naive-ui'
|
import { NDropdown, useMessage } from 'naive-ui'
|
||||||
|
import axios from 'axios'
|
||||||
import AvatarComponent from './Avatar.vue'
|
import AvatarComponent from './Avatar.vue'
|
||||||
import TextComponent from './Text.vue'
|
import TextComponent from './Text.vue'
|
||||||
import { SvgIcon } from '@/components/common'
|
import { SvgIcon } from '@/components/common'
|
||||||
|
@ -12,7 +13,7 @@ import { copyToClip } from '@/utils/copy'
|
||||||
interface Props {
|
interface Props {
|
||||||
dateTime?: string
|
dateTime?: string
|
||||||
text?: string
|
text?: string
|
||||||
tts?: string
|
tts?: string
|
||||||
inversion?: boolean
|
inversion?: boolean
|
||||||
error?: boolean
|
error?: boolean
|
||||||
loading?: boolean
|
loading?: boolean
|
||||||
|
@ -93,47 +94,70 @@ async function handleCopy() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
import axios from "axios"
|
const http = (text: any) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
const http = (text: any)=>{
|
axios.post('https://chat.lihaink.cn/index/tts', { data: text })
|
||||||
return new Promise((resolve, reject)=>{
|
.then((response) => {
|
||||||
axios.post('https://chat.lihaink.cn/index/tts',{data: text})
|
|
||||||
.then(response => {
|
|
||||||
// 请求成功处理逻辑
|
// 请求成功处理逻辑
|
||||||
// console.log('请求成功',response.data);
|
// console.log('请求成功',response.data);
|
||||||
resolve(response.data)
|
resolve(response.data)
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch((error) => {
|
||||||
// 请求失败处理逻辑
|
// 请求失败处理逻辑
|
||||||
console.error('请求失败',error);
|
console.error('请求失败', error)
|
||||||
reject(error)
|
reject(error)
|
||||||
});
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
let ttsList = [];
|
|
||||||
async function loadTTS(){
|
// 创建音频对象的数组
|
||||||
let tts = props.tts?JSON.parse(props.tts):[]
|
const audioElements = reactive([])
|
||||||
if(tts.length>ttsList.length){
|
|
||||||
for(let i=ttsList.length;i<tts.length;i++){
|
let ttslength = 0
|
||||||
let res = await http(tts[i])
|
let ttsLoadFlag = 0
|
||||||
const a = new Audio(res.data.mp3)
|
let lengthFlag = 0
|
||||||
a.addEventListener('ended', () => {
|
let tts = props.tts ? JSON.parse(props.tts) : []
|
||||||
onAudioEnd()
|
async function loadTTS() {
|
||||||
})
|
lengthFlag = tts.length
|
||||||
audioElements.push(a)
|
if (tts.length > ttslength && audioElements.length == ttslength && ttsLoadFlag == 0) {
|
||||||
if (ttsList.length == 0)
|
for (let i = ttslength; i < lengthFlag; i++) {
|
||||||
playAudio()
|
console.log(`加载了${i}次`, tts[i])
|
||||||
}
|
ttsLoadFlag = 1
|
||||||
ttsList = JSON.parse(JSON.stringify(tts));
|
if (tts[i] == '')
|
||||||
}
|
break
|
||||||
|
try {
|
||||||
|
const res = await http(tts[i])
|
||||||
|
const a = new Audio(res.data.mp3)
|
||||||
|
a.addEventListener('ended', () => {
|
||||||
|
onAudioEnd()
|
||||||
|
})
|
||||||
|
audioElements.push(a)
|
||||||
|
if (ttslength == 0)
|
||||||
|
playAudio()
|
||||||
|
if (i == tts.length - 1) {
|
||||||
|
ttslength = tts.length
|
||||||
|
ttsLoadFlag = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.log(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 监听到文本数据改变
|
// 监听到文本数据改变
|
||||||
watch(()=>props.tts, async (n:any, o:any)=>{
|
watch(() => props.tts, async (n: any, o: any) => {
|
||||||
loadTTS();
|
if (props.tts == '') {
|
||||||
},{immediate:true,deep:true})
|
for (let i = 0; i < audioElements.length; i++)
|
||||||
|
audioElements[i].pause()
|
||||||
|
audioElements.length = 0
|
||||||
|
}
|
||||||
|
tts = props.tts ? JSON.parse(props.tts) : []
|
||||||
|
loadTTS()
|
||||||
|
}, { immediate: true, deep: true })
|
||||||
|
|
||||||
console.log( '组件渲染 ', props.text, props.tts);
|
console.log('组件渲染 ', props.text, props.tts)
|
||||||
|
|
||||||
const playStatus = ref('end')
|
const playStatus = ref('end')
|
||||||
let playing = 0
|
let playing = 0
|
||||||
|
@ -141,7 +165,7 @@ let sok = false
|
||||||
async function radioPlay() {
|
async function radioPlay() {
|
||||||
return console.log('播放', props.tts[0])
|
return console.log('播放', props.tts[0])
|
||||||
audioElements.length = 0
|
audioElements.length = 0
|
||||||
emit('changeNowStatus', 'loding')
|
emit('changeNowStatus', 'loding')
|
||||||
const socket = new WebSocket('wss://chat.lihaink.cn/zhanti/tts')
|
const socket = new WebSocket('wss://chat.lihaink.cn/zhanti/tts')
|
||||||
sok = true
|
sok = true
|
||||||
|
|
||||||
|
@ -158,12 +182,11 @@ async function radioPlay() {
|
||||||
|
|
||||||
await promise()
|
await promise()
|
||||||
|
|
||||||
|
|
||||||
// 监听WebSocket关闭事件
|
// 监听WebSocket关闭事件
|
||||||
socket.onclose = (event: any) => {
|
socket.onclose = (event: any) => {
|
||||||
sok = false
|
sok = false
|
||||||
console.log('连接已关闭: ', event, sok)
|
console.log('连接已关闭: ', event, sok)
|
||||||
console.log('sok状态', sok);
|
console.log('sok状态', sok)
|
||||||
}
|
}
|
||||||
|
|
||||||
// socket.send(JSON.stringify({
|
// socket.send(JSON.stringify({
|
||||||
|
@ -178,9 +201,9 @@ async function radioPlay() {
|
||||||
socket.onmessage = (event: any) => {
|
socket.onmessage = (event: any) => {
|
||||||
const msg = JSON.parse(event.data)
|
const msg = JSON.parse(event.data)
|
||||||
console.log(i, msg.mp3)
|
console.log(i, msg.mp3)
|
||||||
if(msg.key=='false'){
|
if (msg.key == 'false')
|
||||||
return socket.close();
|
return socket.close()
|
||||||
}
|
|
||||||
const a = new Audio(msg.mp3)
|
const a = new Audio(msg.mp3)
|
||||||
a.addEventListener('ended', () => {
|
a.addEventListener('ended', () => {
|
||||||
onAudioEnd()
|
onAudioEnd()
|
||||||
|
@ -210,20 +233,18 @@ const onAudioEnd = (index: any) => {
|
||||||
if (playing < audioElements.length) {
|
if (playing < audioElements.length) {
|
||||||
playFlag = true
|
playFlag = true
|
||||||
audioElements[playing].play()
|
audioElements[playing].play()
|
||||||
emit('changeNowStatus', 'playing')
|
emit('changeNowStatus', 'playing')
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
playStatus.value = 'end';
|
playStatus.value = 'end'
|
||||||
emit('changeNowStatus', 'input')
|
emit('changeNowStatus', 'input')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 创建音频对象的数组
|
|
||||||
const audioElements = reactive([])
|
|
||||||
// 播放音频
|
// 播放音频
|
||||||
const playAudio = (playIndex: any) => {
|
const playAudio = (playIndex: any) => {
|
||||||
// for (let i = 0; i < audioElements.length; i++)
|
// for (let i = 0; i < audioElements.length; i++)
|
||||||
audioElements[0].play()
|
audioElements[0].play()
|
||||||
emit('changeNowStatus', 'playing')
|
emit('changeNowStatus', 'playing')
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(() => audioElements.length, (newVal, oldVal) => {
|
watch(() => audioElements.length, (newVal, oldVal) => {
|
||||||
|
@ -240,13 +261,13 @@ let pauseIndex = -1
|
||||||
const pauseAudio = () => {
|
const pauseAudio = () => {
|
||||||
pauseIndex = playing + 0
|
pauseIndex = playing + 0
|
||||||
playStatus.value = 'pause'
|
playStatus.value = 'pause'
|
||||||
emit('changeNowStatus', 'input')
|
emit('changeNowStatus', 'input')
|
||||||
for (let i = 0; i < audioElements.length; i++)
|
for (let i = 0; i < audioElements.length; i++)
|
||||||
audioElements[i].pause()
|
audioElements[i].pause()
|
||||||
}
|
}
|
||||||
const noPauseAudio = () => {
|
const noPauseAudio = () => {
|
||||||
playStatus.value = 'playing'
|
playStatus.value = 'playing'
|
||||||
emit('changeNowStatus', 'playing')
|
emit('changeNowStatus', 'playing')
|
||||||
audioElements[pauseIndex].play()
|
audioElements[pauseIndex].play()
|
||||||
pauseIndex = -1
|
pauseIndex = -1
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ import indexBG from '@/components/animation/indexBG.vue'
|
||||||
import recording from '@/components/animation/recording.vue'
|
import recording from '@/components/animation/recording.vue'
|
||||||
import inputing from '@/components/animation/inputing.vue'
|
import inputing from '@/components/animation/inputing.vue'
|
||||||
import lodingSpin from '@/components/animation/lodingSpin.vue'
|
import lodingSpin from '@/components/animation/lodingSpin.vue'
|
||||||
|
import playing from '@/components/animation/playing.vue'
|
||||||
|
|
||||||
// import IatRecorder from '@/utils/larRcorder.js'
|
// import IatRecorder from '@/utils/larRcorder.js'
|
||||||
|
|
||||||
|
@ -108,7 +109,7 @@ const conversationList = computed(() =>
|
||||||
const prompt = ref<string>('')
|
const prompt = ref<string>('')
|
||||||
const loading = ref<boolean>(false)
|
const loading = ref<boolean>(false)
|
||||||
const inputRef = ref<Ref | null>(null)
|
const inputRef = ref<Ref | null>(null)
|
||||||
const nowStatus = ref('input') // 当前系统状态, input等待, loding加载, record录音,
|
const nowStatus = ref('playing') // 当前系统状态, input等待, loding加载, record录音,playing播放
|
||||||
const nowStart = ref(true) // 当前是否有消息, 有才显示聊天记录
|
const nowStart = ref(true) // 当前是否有消息, 有才显示聊天记录
|
||||||
|
|
||||||
// 添加PromptStore
|
// 添加PromptStore
|
||||||
|
@ -166,7 +167,7 @@ async function onConversation() {
|
||||||
addChat(+uuid, {
|
addChat(+uuid, {
|
||||||
dateTime: new Date().toLocaleString(),
|
dateTime: new Date().toLocaleString(),
|
||||||
text: message,
|
text: message,
|
||||||
tts: '',
|
tts: '',
|
||||||
inversion: true,
|
inversion: true,
|
||||||
error: false,
|
error: false,
|
||||||
conversationOptions: null,
|
conversationOptions: null,
|
||||||
|
@ -188,7 +189,7 @@ async function onConversation() {
|
||||||
addChat(+uuid, {
|
addChat(+uuid, {
|
||||||
dateTime: new Date().toLocaleString(),
|
dateTime: new Date().toLocaleString(),
|
||||||
text: '思考中',
|
text: '思考中',
|
||||||
tts: '',
|
tts: '',
|
||||||
loading: true,
|
loading: true,
|
||||||
inversion: false,
|
inversion: false,
|
||||||
error: false,
|
error: false,
|
||||||
|
@ -197,27 +198,26 @@ async function onConversation() {
|
||||||
})
|
})
|
||||||
scrollToBottom()
|
scrollToBottom()
|
||||||
|
|
||||||
let infoList = JSON.parse(JSON.stringify(dataSources.value));
|
let infoList = JSON.parse(JSON.stringify(dataSources.value))
|
||||||
infoList = infoList.map((item:any, index:any)=>{
|
infoList = infoList.map((item: any, index: any) => {
|
||||||
return {
|
return {
|
||||||
role: index%2==0?'user':'assistant',
|
role: index % 2 == 0 ? 'user' : 'assistant',
|
||||||
content: item.text
|
content: item.text,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
console.log(dataSources.value);
|
|
||||||
|
|
||||||
|
console.log(dataSources.value)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let lastText = ''
|
let lastText = ''
|
||||||
const tts:any = [];
|
const tts: any = []
|
||||||
console.log('发送消息', message)
|
console.log('发送消息', message)
|
||||||
|
|
||||||
const fetchChatAPIOnce = async () => {
|
const fetchChatAPIOnce = async () => {
|
||||||
socket.send(JSON.stringify({
|
socket.send(JSON.stringify({
|
||||||
tts: 1,
|
tts: 1,
|
||||||
data: [
|
data: [
|
||||||
...infoList,
|
...infoList,
|
||||||
{
|
{
|
||||||
role: 'user',
|
role: 'user',
|
||||||
content: message,
|
content: message,
|
||||||
|
@ -234,8 +234,8 @@ async function onConversation() {
|
||||||
// console.log(`收到消息: `, msg.payload.choices.text[0].content);
|
// console.log(`收到消息: `, msg.payload.choices.text[0].content);
|
||||||
// console.log(`当前消息: `, dataSources.value[dataSources.value.length - 1].text);
|
// console.log(`当前消息: `, dataSources.value[dataSources.value.length - 1].text);
|
||||||
lastText += msg.payload.choices.text[0].content
|
lastText += msg.payload.choices.text[0].content
|
||||||
console.log('返回的tts:', msg.payload.choices.tts_text);
|
console.log('返回的tts:', msg.payload.choices.tts_text)
|
||||||
msg.payload.choices.tts_text != '' ? tts.push(msg.payload.choices.tts_text): null;
|
msg.payload.choices.tts_text != '' ? tts.push(msg.payload.choices.tts_text) : null
|
||||||
const loading = false
|
const loading = false
|
||||||
nowStart.value = false
|
nowStart.value = false
|
||||||
updateChat(
|
updateChat(
|
||||||
|
@ -245,14 +245,14 @@ async function onConversation() {
|
||||||
dateTime: new Date().toLocaleString(),
|
dateTime: new Date().toLocaleString(),
|
||||||
text: lastText,
|
text: lastText,
|
||||||
inversion: false,
|
inversion: false,
|
||||||
tts: JSON.stringify(tts),
|
tts: JSON.stringify(tts),
|
||||||
error: false,
|
error: false,
|
||||||
loading,
|
loading,
|
||||||
conversationOptions: { conversationId: msg.header.sid, parentMessageId: msg.header.sid },
|
conversationOptions: { conversationId: msg.header.sid, parentMessageId: msg.header.sid },
|
||||||
requestOptions: { prompt: message, options: { ...options } },
|
requestOptions: { prompt: message, options: { ...options } },
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
scrollToBottomIfAtBottom()
|
scrollToBottomIfAtBottom()
|
||||||
// 关闭连接
|
// 关闭连接
|
||||||
if (msg.header.code != 0 || (event.data && msg.header.status == 2)) {
|
if (msg.header.code != 0 || (event.data && msg.header.status == 2)) {
|
||||||
nowStatus.value = 'input'
|
nowStatus.value = 'input'
|
||||||
|
@ -613,7 +613,7 @@ const changeNowStatus = (e: any) => {
|
||||||
console.log('收到数据', e)
|
console.log('收到数据', e)
|
||||||
if (e != nowStatus.value) {
|
if (e != nowStatus.value) {
|
||||||
switch (e) {
|
switch (e) {
|
||||||
case 'playing': nowStatus.value = 'record'; break
|
case 'playing': nowStatus.value = 'playing'; break
|
||||||
case 'loding': nowStatus.value = 'loding'; break
|
case 'loding': nowStatus.value = 'loding'; break
|
||||||
default: nowStatus.value = 'input'; break
|
default: nowStatus.value = 'input'; break
|
||||||
}
|
}
|
||||||
|
@ -651,6 +651,7 @@ setTimeout(() => {
|
||||||
<recording v-else-if="nowStatus == 'record'" key="record" />
|
<recording v-else-if="nowStatus == 'record'" key="record" />
|
||||||
<!-- <loding v-else-if="nowStatus=='loding'" key="loding"></loding> -->
|
<!-- <loding v-else-if="nowStatus=='loding'" key="loding"></loding> -->
|
||||||
<lodingSpin v-else-if="nowStatus == 'loding'" key="loding" />
|
<lodingSpin v-else-if="nowStatus == 'loding'" key="loding" />
|
||||||
|
<playing v-else-if="nowStatus == 'playing'" key="playing" />
|
||||||
<!-- <lodingCir v-else-if="nowStatus=='loding'" key="loding"></lodingCir> -->
|
<!-- <lodingCir v-else-if="nowStatus=='loding'" key="loding"></lodingCir> -->
|
||||||
</transition>
|
</transition>
|
||||||
</indexBG>
|
</indexBG>
|
||||||
|
@ -698,7 +699,7 @@ setTimeout(() => {
|
||||||
:key="index"
|
:key="index"
|
||||||
:date-time="item.dateTime"
|
:date-time="item.dateTime"
|
||||||
:text="item.text"
|
:text="item.text"
|
||||||
:tts="item.tts"
|
:tts="item.tts"
|
||||||
:inversion="item.inversion"
|
:inversion="item.inversion"
|
||||||
:error="item.error"
|
:error="item.error"
|
||||||
:loading="item.loading"
|
:loading="item.loading"
|
||||||
|
|
Loading…
Reference in New Issue