|
@@ -119,136 +119,225 @@ const handleStopRecord = (message) => {
|
|
sessionId.value = generateSessionId();
|
|
sessionId.value = generateSessionId();
|
|
chatGpt(message);
|
|
chatGpt(message);
|
|
};
|
|
};
|
|
-let audioQueue = []; // 音频队列,保存按请求顺序的音频数据
|
|
|
|
-let playingQueue = []; // 用来记录当前正在播放的音频序号
|
|
|
|
-let isPlaying = false; // 当前是否正在播放
|
|
|
|
-let orderId = 0; // 请求顺序号
|
|
|
|
|
|
+// let audioQueue = []; // 音频队列,保存按请求顺序的音频数据
|
|
|
|
+// let playingQueue = []; // 用来记录当前正在播放的音频序号
|
|
|
|
+// let isPlaying = false; // 当前是否正在播放
|
|
|
|
+// let orderId = 0; // 请求顺序号
|
|
|
|
|
|
// 用来控制正在播放音频的锁定机制
|
|
// 用来控制正在播放音频的锁定机制
|
|
let playingLock = false; // 标识是否正在播放
|
|
let playingLock = false; // 标识是否正在播放
|
|
|
|
|
|
-// 1. 发起 TTS 请求
|
|
|
|
-// const playTTS = async (ttsMessage) => {
|
|
|
|
-// const currentOrderId = orderId++; // 获取当前请求的顺序号
|
|
|
|
-
|
|
|
|
-// try {
|
|
|
|
-// // 发起请求
|
|
|
|
-// const res = await axios.get(
|
|
|
|
-// `/openapi-prd/ai/ttt/synthesize?text=${ttsMessage}&sessionId=${sessionId.value}`,
|
|
|
|
-// { responseType: "arraybuffer" }
|
|
|
|
-// );
|
|
|
|
|
|
|
|
-// // 将音频数据和顺序号一起存入 audioQueue
|
|
|
|
-// audioQueue.push({ orderId: currentOrderId, audioData: res.data });
|
|
|
|
|
|
+let audioQueue = []; // 音频队列,保存按请求顺序的音频数据
|
|
|
|
+let playingQueue = []; // 记录已播放的音频序号
|
|
|
|
+let isPlaying = false; // 当前是否正在播放
|
|
|
|
+let orderId = 0; // 请求顺序号
|
|
|
|
|
|
-// // 如果当前没有音频在播放,开始播放
|
|
|
|
-// if (!isPlaying && !playingLock) {
|
|
|
|
-// await playNextAudio(); // 开始播放
|
|
|
|
-// }
|
|
|
|
-// } catch (error) {
|
|
|
|
-// console.error("调用 TTS API 时出错:", error);
|
|
|
|
-// }
|
|
|
|
-// };
|
|
|
|
|
|
+// 1. 发起 TTS 请求(修改后)
|
|
const playTTS = async (ttsMessage) => {
|
|
const playTTS = async (ttsMessage) => {
|
|
queue.add(async () => {
|
|
queue.add(async () => {
|
|
- const currentOrderId = orderId++;
|
|
|
|
|
|
+ const currentOrderId = orderId++; // 先获取顺序号再发送请求
|
|
|
|
|
|
try {
|
|
try {
|
|
const res = await axios.get(
|
|
const res = await axios.get(
|
|
`/openapi-prd/ai/ttt/synthesize?text=${ttsMessage}&sessionId=${sessionId.value}`,
|
|
`/openapi-prd/ai/ttt/synthesize?text=${ttsMessage}&sessionId=${sessionId.value}`,
|
|
{ responseType: "arraybuffer" }
|
|
{ responseType: "arraybuffer" }
|
|
);
|
|
);
|
|
- if (!res.data || res.data.byteLength === 0) {
|
|
|
|
- console.error("音频数据无效,无法播放.");
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
- // 按顺序存入音频队列
|
|
|
|
- audioQueue.push({ orderId: currentOrderId, audioData: res.data });
|
|
|
|
-
|
|
|
|
- // 仅在没有播放时启动播放
|
|
|
|
- if (!isPlaying) {
|
|
|
|
- await playNextAudio();
|
|
|
|
- }
|
|
|
|
|
|
+
|
|
|
|
+ // 即使请求失败也要保持队列连续性(新增部分)
|
|
|
|
+ const audioItem = {
|
|
|
|
+ orderId: currentOrderId,
|
|
|
|
+ audioData: res.data || null,
|
|
|
|
+ status: res.data ? 'valid' : 'invalid'
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ audioQueue.push(audioItem);
|
|
|
|
+ audioQueue.sort((a, b) => a.orderId - b.orderId); // 保持队列有序
|
|
|
|
+
|
|
|
|
+ if (!isPlaying) await playNextAudio();
|
|
} catch (error) {
|
|
} catch (error) {
|
|
console.error("调用 TTS API 时出错:", error);
|
|
console.error("调用 TTS API 时出错:", error);
|
|
|
|
+ // 请求失败时插入占位符保持顺序(关键修复)
|
|
|
|
+ audioQueue.push({
|
|
|
|
+ orderId: currentOrderId,
|
|
|
|
+ audioData: null,
|
|
|
|
+ status: 'invalid'
|
|
|
|
+ });
|
|
|
|
+ audioQueue.sort((a, b) => a.orderId - b.orderId);
|
|
|
|
+ if (!isPlaying) await playNextAudio();
|
|
}
|
|
}
|
|
});
|
|
});
|
|
};
|
|
};
|
|
-// 2. 播放下一个音频
|
|
|
|
|
|
+
|
|
|
|
+// 2. 播放下一个音频(修改后)
|
|
const playNextAudio = async () => {
|
|
const playNextAudio = async () => {
|
|
- // 如果播放队列为空,停止播放
|
|
|
|
if (audioQueue.length === 0) {
|
|
if (audioQueue.length === 0) {
|
|
- isPlaying = false; // 播放完所有音频
|
|
|
|
- // audioQueue = []; // 确保列表为空
|
|
|
|
|
|
+ isPlaying = false;
|
|
console.log("所有音频播放完毕.");
|
|
console.log("所有音频播放完毕.");
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
- // 找到队列中最小序号的音频,确保顺序播放
|
|
|
|
const nextAudio = getNextAudioToPlay();
|
|
const nextAudio = getNextAudioToPlay();
|
|
- console.log(nextAudio,"没有找到下一个应该播放的音频,队列尚未按顺序准备好.");
|
|
|
|
-
|
|
|
|
- // 如果找不到下一个应该播放的音频,表示队列还没有按顺序准备好
|
|
|
|
if (!nextAudio) {
|
|
if (!nextAudio) {
|
|
- console.log("没有找到下一个应该播放的音频,队列尚未按顺序准备好.");
|
|
|
|
- console.log("当前音频队列:", audioQueue); // 打印当前音频队列
|
|
|
|
- console.log("当前已播放的序列:", playingQueue); // 打印已经播放的音频序列
|
|
|
|
|
|
+ console.log("等待后续音频数据...");
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
- // 打印正在播放的音频序号
|
|
|
|
- console.log(`正在播放音频,序号:${nextAudio.orderId}`);
|
|
|
|
-
|
|
|
|
try {
|
|
try {
|
|
- isPlaying = true; // 标记当前正在播放
|
|
|
|
- playingLock = true; // 锁定播放,避免新的音频插入
|
|
|
|
|
|
+ isPlaying = true;
|
|
|
|
+ console.log(`正在播放音频,序号:${nextAudio.orderId}`);
|
|
|
|
|
|
- // 播放当前音频
|
|
|
|
- await playAudio(nextAudio.audioData);
|
|
|
|
|
|
+ if (nextAudio.status === 'valid') {
|
|
|
|
+ await playAudio(nextAudio.audioData);
|
|
|
|
+ } else {
|
|
|
|
+ console.warn(`跳过无效音频,序号:${nextAudio.orderId}`);
|
|
|
|
+ }
|
|
|
|
|
|
- // 播放完成后,移除已播放的音频
|
|
|
|
|
|
+ // 更新播放状态(优化处理)
|
|
|
|
+ playingQueue = [...new Set([...playingQueue, nextAudio.orderId])].sort((a, b) => a - b);
|
|
audioQueue = audioQueue.filter(audio => audio.orderId !== nextAudio.orderId);
|
|
audioQueue = audioQueue.filter(audio => audio.orderId !== nextAudio.orderId);
|
|
- playingQueue.push(nextAudio.orderId); // 将已播放的序号添加到播放记录
|
|
|
|
-
|
|
|
|
- // 输出音频播放完成的日志
|
|
|
|
- console.log(`音频序号 ${nextAudio.orderId} 播放完成,等待播放下一个包...`);
|
|
|
|
-
|
|
|
|
- // 解除锁定,等待下一个音频播放
|
|
|
|
- playingLock = false;
|
|
|
|
|
|
|
|
- // 使用定时器周期性检查是否可以播放下一个音频
|
|
|
|
- const checkNextAudioTimer = setInterval(async () => {
|
|
|
|
- if (!playingLock) {
|
|
|
|
- await playNextAudio();
|
|
|
|
- clearInterval(checkNextAudioTimer); // 清除定时器
|
|
|
|
- }
|
|
|
|
- }, 300); // 每秒检查一次
|
|
|
|
|
|
+ // 立即尝试播放下一个(优化播放流程)
|
|
|
|
+ isPlaying = false;
|
|
|
|
+ await playNextAudio();
|
|
} catch (error) {
|
|
} catch (error) {
|
|
- console.error(`播放音频序号 ${nextAudio.orderId} 时出错:`, error);
|
|
|
|
- // 如果某个音频播放失败,跳过这个音频,继续播放下一个
|
|
|
|
- audioQueue = audioQueue.filter(audio => audio.orderId !== nextAudio.orderId); // 移除报错的音频
|
|
|
|
- playingQueue.push(nextAudio.orderId); // 将已播放的序号添加到播放记录
|
|
|
|
- playingLock = false; // 解除锁定
|
|
|
|
- // 继续播放下一个音频
|
|
|
|
|
|
+ console.error(`播放失败,序号:${nextAudio.orderId}`, error);
|
|
|
|
+ audioQueue = audioQueue.filter(audio => audio.orderId !== nextAudio.orderId);
|
|
|
|
+ isPlaying = false;
|
|
await playNextAudio();
|
|
await playNextAudio();
|
|
}
|
|
}
|
|
};
|
|
};
|
|
|
|
|
|
-// 获取下一个应该播放的音频(保证顺序)
|
|
|
|
|
|
+// 获取下一个应该播放的音频(修改后)
|
|
const getNextAudioToPlay = () => {
|
|
const getNextAudioToPlay = () => {
|
|
- // 检查音频队列中是否有下一个应该播放的音频
|
|
|
|
- console.log("检查下一个播放的音频...");
|
|
|
|
- for (let i = 0; i < audioQueue.length; i++) {
|
|
|
|
- const audio = audioQueue[i];
|
|
|
|
- // 找到最小的序号,即请求的顺序号
|
|
|
|
- if (audio.orderId === playingQueue.length) {
|
|
|
|
- console.log(`找到了下一个应该播放的音频,序号:${audio.orderId}`);
|
|
|
|
- return audio;
|
|
|
|
|
|
+ // 获取当前应该播放的最小序号
|
|
|
|
+ const expectedOrderId = playingQueue.length > 0
|
|
|
|
+ ? Math.max(...playingQueue) + 1
|
|
|
|
+ : 0;
|
|
|
|
+
|
|
|
|
+ // 查找第一个匹配的有效音频(新增有效性检查)
|
|
|
|
+ const nextAudio = audioQueue.find(audio =>
|
|
|
|
+ audio.orderId === expectedOrderId &&
|
|
|
|
+ audio.status === 'valid'
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+ // 如果找不到有效音频但有序号匹配的无效项,跳过该序号
|
|
|
|
+ if (!nextAudio) {
|
|
|
|
+ const invalidAudio = audioQueue.find(audio =>
|
|
|
|
+ audio.orderId === expectedOrderId
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+ if (invalidAudio) {
|
|
|
|
+ console.warn(`检测到无效音频,自动跳过序号:${expectedOrderId}`);
|
|
|
|
+ playingQueue.push(expectedOrderId);
|
|
|
|
+ return getNextAudioToPlay(); // 递归处理
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- console.log("没有找到下一个应该播放的音频,返回 null");
|
|
|
|
- return null; // 如果没有找到匹配的音频,返回 null
|
|
|
|
|
|
+
|
|
|
|
+ return nextAudio || null;
|
|
};
|
|
};
|
|
|
|
+// 1. 发起 TTS 请求
|
|
|
|
+
|
|
|
|
+// const playTTS = async (ttsMessage) => {
|
|
|
|
+// queue.add(async () => {
|
|
|
|
+// const currentOrderId = orderId++;
|
|
|
|
+
|
|
|
|
+// try {
|
|
|
|
+// const res = await axios.get(
|
|
|
|
+// `/openapi-prd/ai/ttt/synthesize?text=${ttsMessage}&sessionId=${sessionId.value}`,
|
|
|
|
+// { responseType: "arraybuffer" }
|
|
|
|
+// );
|
|
|
|
+// if (!res.data || res.data.byteLength === 0) {
|
|
|
|
+// console.error("音频数据无效,无法播放.");
|
|
|
|
+// return;
|
|
|
|
+// }
|
|
|
|
+// // 按顺序存入音频队列
|
|
|
|
+// audioQueue.push({ orderId: currentOrderId, audioData: res.data });
|
|
|
|
+
|
|
|
|
+// // 仅在没有播放时启动播放
|
|
|
|
+// if (!isPlaying) {
|
|
|
|
+// await playNextAudio();
|
|
|
|
+// }
|
|
|
|
+// } catch (error) {
|
|
|
|
+// console.error("调用 TTS API 时出错:", error);
|
|
|
|
+// }
|
|
|
|
+// });
|
|
|
|
+// };
|
|
|
|
+// 2. 播放下一个音频
|
|
|
|
+// const playNextAudio = async () => {
|
|
|
|
+// // 如果播放队列为空,停止播放
|
|
|
|
+// if (audioQueue.length === 0) {
|
|
|
|
+// isPlaying = false; // 播放完所有音频
|
|
|
|
+// // audioQueue = []; // 确保列表为空
|
|
|
|
+// console.log("所有音频播放完毕.");
|
|
|
|
+// return;
|
|
|
|
+// }
|
|
|
|
+
|
|
|
|
+// // 找到队列中最小序号的音频,确保顺序播放
|
|
|
|
+// const nextAudio = getNextAudioToPlay();
|
|
|
|
+// console.log(nextAudio,"没有找到下一个应该播放的音频,队列尚未按顺序准备好.");
|
|
|
|
+
|
|
|
|
+// // 如果找不到下一个应该播放的音频,表示队列还没有按顺序准备好
|
|
|
|
+// if (!nextAudio) {
|
|
|
|
+// console.log("没有找到下一个应该播放的音频,队列尚未按顺序准备好.");
|
|
|
|
+// console.log("当前音频队列:", audioQueue); // 打印当前音频队列
|
|
|
|
+// console.log("当前已播放的序列:", playingQueue); // 打印已经播放的音频序列
|
|
|
|
+// return;
|
|
|
|
+// }
|
|
|
|
+
|
|
|
|
+// // 打印正在播放的音频序号
|
|
|
|
+// console.log(`正在播放音频,序号:${nextAudio.orderId}`);
|
|
|
|
+
|
|
|
|
+// try {
|
|
|
|
+// isPlaying = true; // 标记当前正在播放
|
|
|
|
+// playingLock = true; // 锁定播放,避免新的音频插入
|
|
|
|
+
|
|
|
|
+// // 播放当前音频
|
|
|
|
+// await playAudio(nextAudio.audioData);
|
|
|
|
+
|
|
|
|
+// // 播放完成后,移除已播放的音频
|
|
|
|
+// audioQueue = audioQueue.filter(audio => audio.orderId !== nextAudio.orderId);
|
|
|
|
+// playingQueue.push(nextAudio.orderId); // 将已播放的序号添加到播放记录
|
|
|
|
+
|
|
|
|
+// // 输出音频播放完成的日志
|
|
|
|
+// console.log(`音频序号 ${nextAudio.orderId} 播放完成,等待播放下一个包...`);
|
|
|
|
+
|
|
|
|
+// // 解除锁定,等待下一个音频播放
|
|
|
|
+// playingLock = false;
|
|
|
|
+
|
|
|
|
+// // 使用定时器周期性检查是否可以播放下一个音频
|
|
|
|
+// const checkNextAudioTimer = setInterval(async () => {
|
|
|
|
+// if (!playingLock) {
|
|
|
|
+// await playNextAudio();
|
|
|
|
+// clearInterval(checkNextAudioTimer); // 清除定时器
|
|
|
|
+// }
|
|
|
|
+// }, 300); // 每秒检查一次
|
|
|
|
+// } catch (error) {
|
|
|
|
+// console.error(`播放音频序号 ${nextAudio.orderId} 时出错:`, error);
|
|
|
|
+// // 如果某个音频播放失败,跳过这个音频,继续播放下一个
|
|
|
|
+// audioQueue = audioQueue.filter(audio => audio.orderId !== nextAudio.orderId); // 移除报错的音频
|
|
|
|
+// playingQueue.push(nextAudio.orderId); // 将已播放的序号添加到播放记录
|
|
|
|
+// playingLock = false; // 解除锁定
|
|
|
|
+// // 继续播放下一个音频
|
|
|
|
+// await playNextAudio();
|
|
|
|
+// }
|
|
|
|
+// };
|
|
|
|
+
|
|
|
|
+// 获取下一个应该播放的音频(保证顺序)
|
|
|
|
+// const getNextAudioToPlay = () => {
|
|
|
|
+// // 检查音频队列中是否有下一个应该播放的音频
|
|
|
|
+// console.log("检查下一个播放的音频...");
|
|
|
|
+// for (let i = 0; i < audioQueue.length; i++) {
|
|
|
|
+// const audio = audioQueue[i];
|
|
|
|
+// // 找到最小的序号,即请求的顺序号
|
|
|
|
+// if (audio.orderId === playingQueue.length) {
|
|
|
|
+// console.log(`找到了下一个应该播放的音频,序号:${audio.orderId}`);
|
|
|
|
+// return audio;
|
|
|
|
+// }
|
|
|
|
+// }
|
|
|
|
+// console.log("没有找到下一个应该播放的音频,返回 null");
|
|
|
|
+// return null; // 如果没有找到匹配的音频,返回 null
|
|
|
|
+// };
|
|
|
|
|
|
// 播放音频的方法
|
|
// 播放音频的方法
|
|
const playAudio = (audioData) => {
|
|
const playAudio = (audioData) => {
|