|
@@ -263,6 +263,13 @@ export default {
|
|
countdownTimer: null,
|
|
countdownTimer: null,
|
|
showGif: false, // 控制是否显示GIF
|
|
showGif: false, // 控制是否显示GIF
|
|
gifUrl: '', // GIF图片的URL
|
|
gifUrl: '', // GIF图片的URL
|
|
|
|
+
|
|
|
|
+ // 添加AI语音交互相关属性
|
|
|
|
+ aiVoiceUrl: '', // AI语音URL
|
|
|
|
+ aiText: '', // AI回复文本
|
|
|
|
+ transcribedText: '', // 转写文本
|
|
|
|
+ isPlayingAiVoice: false, // 是否正在播放AI语音
|
|
|
|
+ aiAudioPlayer: null, // AI语音播放器
|
|
}
|
|
}
|
|
},
|
|
},
|
|
onLoad(options) {
|
|
onLoad(options) {
|
|
@@ -305,6 +312,12 @@ export default {
|
|
beforeDestroy() {
|
|
beforeDestroy() {
|
|
// 组件销毁前停止摄像头
|
|
// 组件销毁前停止摄像头
|
|
this.stopUserCamera();
|
|
this.stopUserCamera();
|
|
|
|
+
|
|
|
|
+ // 销毁AI音频播放器
|
|
|
|
+ if (this.aiAudioPlayer) {
|
|
|
|
+ this.aiAudioPlayer.destroy();
|
|
|
|
+ this.aiAudioPlayer = null;
|
|
|
|
+ }
|
|
},
|
|
},
|
|
methods: {
|
|
methods: {
|
|
// 初始化相机
|
|
// 初始化相机
|
|
@@ -1909,7 +1922,7 @@ export default {
|
|
tenant_id: uni.getStorageSync('tenant_id') || '1'
|
|
tenant_id: uni.getStorageSync('tenant_id') || '1'
|
|
};
|
|
};
|
|
|
|
|
|
- // 发送请求到面试接口
|
|
|
|
|
|
+ // 首先提交到面试接口
|
|
uni.request({
|
|
uni.request({
|
|
url: `${apiBaseUrl}/api/job/upload_video`,
|
|
url: `${apiBaseUrl}/api/job/upload_video`,
|
|
method: 'POST',
|
|
method: 'POST',
|
|
@@ -1926,13 +1939,6 @@ export default {
|
|
// 从队列中移除当前任务
|
|
// 从队列中移除当前任务
|
|
this.uploadQueue.shift();
|
|
this.uploadQueue.shift();
|
|
|
|
|
|
- // 显示简短的成功提示
|
|
|
|
- // uni.showToast({
|
|
|
|
- // title: '视频提交成功',
|
|
|
|
- // icon: 'success',
|
|
|
|
- // duration: 1500
|
|
|
|
- // });
|
|
|
|
-
|
|
|
|
// 继续处理队列中的下一个任务
|
|
// 继续处理队列中的下一个任务
|
|
this.processUploadQueue();
|
|
this.processUploadQueue();
|
|
} else {
|
|
} else {
|
|
@@ -1949,6 +1955,9 @@ export default {
|
|
this.showRetryButton = false;
|
|
this.showRetryButton = false;
|
|
this.lastVideoToRetry = null;
|
|
this.lastVideoToRetry = null;
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ // 提交到AI语音交互接口
|
|
|
|
+ this.submitToAiVoiceInteraction(videoUrl);
|
|
} else {
|
|
} else {
|
|
// 提交失败
|
|
// 提交失败
|
|
if (task) {
|
|
if (task) {
|
|
@@ -2066,6 +2075,12 @@ export default {
|
|
proceedToNextQuestion() {
|
|
proceedToNextQuestion() {
|
|
console.log('准备跳转到下一页面');
|
|
console.log('准备跳转到下一页面');
|
|
|
|
|
|
|
|
+ // 如果正在播放AI语音,不立即跳转
|
|
|
|
+ if (this.isPlayingAiVoice) {
|
|
|
|
+ console.log('AI语音正在播放,等待播放完成后再跳转');
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
// 不再等待上传队列完成,直接跳转
|
|
// 不再等待上传队列完成,直接跳转
|
|
this.navigateToNextPage();
|
|
this.navigateToNextPage();
|
|
|
|
|
|
@@ -2073,16 +2088,6 @@ export default {
|
|
if (this.uploadQueue.length > 0) {
|
|
if (this.uploadQueue.length > 0) {
|
|
console.log('上传队列将在后台继续处理...');
|
|
console.log('上传队列将在后台继续处理...');
|
|
|
|
|
|
- // // 重置GIF状态
|
|
|
|
- // this.showGif = false;
|
|
|
|
- // this.gifUrl = '';
|
|
|
|
- // 显示简短的提示
|
|
|
|
- // uni.showToast({
|
|
|
|
- // title: '视频将在后台上传',
|
|
|
|
- // icon: 'none',
|
|
|
|
- // duration: 2000
|
|
|
|
- // });
|
|
|
|
-
|
|
|
|
// 保存上传状态到本地存储,以便在其他页面可以查看
|
|
// 保存上传状态到本地存储,以便在其他页面可以查看
|
|
this.saveUploadStatus();
|
|
this.saveUploadStatus();
|
|
}
|
|
}
|
|
@@ -2090,6 +2095,14 @@ export default {
|
|
|
|
|
|
// 修改 navigateToNextPage 方法
|
|
// 修改 navigateToNextPage 方法
|
|
navigateToNextPage() {
|
|
navigateToNextPage() {
|
|
|
|
+ console.log('准备导航到下一个页面');
|
|
|
|
+
|
|
|
|
+ // 如果正在播放AI语音,不立即跳转
|
|
|
|
+ if (this.isPlayingAiVoice) {
|
|
|
|
+ console.log('AI语音正在播放,等待播放完成后再跳转');
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
console.log('导航到下一个页面');
|
|
console.log('导航到下一个页面');
|
|
|
|
|
|
// 移除延迟,直接跳转
|
|
// 移除延迟,直接跳转
|
|
@@ -2122,10 +2135,6 @@ export default {
|
|
// 隐藏答题按钮
|
|
// 隐藏答题按钮
|
|
this.showAnswerButton = false;
|
|
this.showAnswerButton = false;
|
|
|
|
|
|
- /* // 重置GIF状态
|
|
|
|
- this.showGif = false;
|
|
|
|
- this.gifUrl = ''; */
|
|
|
|
-
|
|
|
|
// 显示简短提示
|
|
// 显示简短提示
|
|
uni.showToast({
|
|
uni.showToast({
|
|
title: '面试完成',
|
|
title: '面试完成',
|
|
@@ -2133,10 +2142,13 @@ export default {
|
|
duration: 500 // 只显示0.5秒
|
|
duration: 500 // 只显示0.5秒
|
|
});
|
|
});
|
|
|
|
|
|
- // 短暂延迟后跳转
|
|
|
|
- setTimeout(() => {
|
|
|
|
|
|
+ // 如果有最后上传的视频URL,提交到AI语音交互接口
|
|
|
|
+ if (this.lastUploadedVideoUrl) {
|
|
|
|
+ this.submitToAiVoiceInteraction(this.lastUploadedVideoUrl);
|
|
|
|
+ } else {
|
|
|
|
+ // 没有视频URL,直接跳转
|
|
this.navigateToNextPage();
|
|
this.navigateToNextPage();
|
|
- }, 500); // 0.5秒后跳转
|
|
|
|
|
|
+ }
|
|
},
|
|
},
|
|
|
|
|
|
// 处理相机错误
|
|
// 处理相机错误
|
|
@@ -2626,6 +2638,204 @@ export default {
|
|
console.error('保存上传状态失败:', e);
|
|
console.error('保存上传状态失败:', e);
|
|
}
|
|
}
|
|
},
|
|
},
|
|
|
|
+
|
|
|
|
+ // 修改 submitToAiVoiceInteraction 方法,使用 FormData 提交
|
|
|
|
+ submitToAiVoiceInteraction(videoUrl) {
|
|
|
|
+ console.log('提交视频到AI语音交互接口:', videoUrl);
|
|
|
|
+
|
|
|
|
+ // 显示加载提示
|
|
|
|
+ uni.showLoading({
|
|
|
|
+ title: 'AI正在思考...',
|
|
|
|
+ mask: true
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ // 获取用户信息和租户ID
|
|
|
|
+ const tenant_id = uni.getStorageSync('tenant_id') || '1';
|
|
|
|
+ const userInfo = uni.getStorageSync('userInfo');
|
|
|
|
+ const openid = userInfo ? (JSON.parse(userInfo).openid || '') : '';
|
|
|
|
+
|
|
|
|
+ // 检查环境
|
|
|
|
+ const systemInfo = uni.getSystemInfoSync();
|
|
|
|
+ const isMiniProgram = systemInfo.uniPlatform && systemInfo.uniPlatform.startsWith('mp-');
|
|
|
|
+
|
|
|
|
+ if (isMiniProgram) {
|
|
|
|
+ // 小程序环境使用 uni.request
|
|
|
|
+ uni.request({
|
|
|
|
+ url: `${apiBaseUrl}/api/voice_ai_interaction`,
|
|
|
|
+ method: 'POST',
|
|
|
|
+ data: {
|
|
|
|
+ url: videoUrl,
|
|
|
|
+ tenant_id: tenant_id,
|
|
|
|
+ openid: openid,
|
|
|
|
+ application_id: uni.getStorageSync('appId') || ''
|
|
|
|
+ },
|
|
|
|
+ header: {
|
|
|
|
+ 'content-type': 'application/json'
|
|
|
|
+ },
|
|
|
|
+ success: (res) => {
|
|
|
|
+ this.handleAiInteractionResponse(res.data);
|
|
|
|
+ },
|
|
|
|
+ fail: (err) => {
|
|
|
|
+ this.handleAiInteractionError(err);
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ } else {
|
|
|
|
+ // H5/App环境使用 FormData 和 XMLHttpRequest
|
|
|
|
+ const formData = new FormData();
|
|
|
|
+ formData.append('url', videoUrl);
|
|
|
|
+ formData.append('tenant_id', tenant_id);
|
|
|
|
+ formData.append('openid', openid);
|
|
|
|
+ formData.append('application_id', uni.getStorageSync('appId') || '');
|
|
|
|
+
|
|
|
|
+ const xhr = new XMLHttpRequest();
|
|
|
|
+ xhr.open('POST', `${apiBaseUrl}/api/voice_ai_interaction`, true);
|
|
|
|
+ xhr.timeout = 60000; // 60秒超时
|
|
|
|
+
|
|
|
|
+ xhr.onload = () => {
|
|
|
|
+ if (xhr.status === 200) {
|
|
|
|
+ try {
|
|
|
|
+ const response = JSON.parse(xhr.responseText);
|
|
|
|
+ this.handleAiInteractionResponse(response);
|
|
|
|
+ } catch (e) {
|
|
|
|
+ console.error('解析AI响应失败:', e);
|
|
|
|
+ this.handleAiInteractionError({ errMsg: '解析响应失败' });
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ this.handleAiInteractionError({ errMsg: 'HTTP状态: ' + xhr.status });
|
|
|
|
+ }
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ xhr.onerror = () => {
|
|
|
|
+ this.handleAiInteractionError({ errMsg: '网络错误' });
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ xhr.ontimeout = () => {
|
|
|
|
+ this.handleAiInteractionError({ errMsg: '请求超时' });
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ xhr.send(formData);
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ // 添加处理AI交互响应的方法
|
|
|
|
+ handleAiInteractionResponse(data) {
|
|
|
|
+ console.log('AI语音交互接口响应:', data);
|
|
|
|
+
|
|
|
|
+ // 隐藏加载提示
|
|
|
|
+ uni.hideLoading();
|
|
|
|
+
|
|
|
|
+ if (data && data.success) {
|
|
|
|
+ // 保存AI回复数据
|
|
|
|
+ this.aiText = data.ai_text || '';
|
|
|
|
+ this.transcribedText = data.transcribed_text ? data.transcribed_text.text : '';
|
|
|
|
+
|
|
|
|
+ // 获取AI语音URL
|
|
|
|
+ const aiVoiceUrl = data.ai_voice_url || '';
|
|
|
|
+ if (aiVoiceUrl) {
|
|
|
|
+ // 构建完整的URL
|
|
|
|
+ this.aiVoiceUrl = aiVoiceUrl.startsWith('http')
|
|
|
|
+ ? aiVoiceUrl
|
|
|
|
+ : `${apiBaseUrl}${aiVoiceUrl}`;
|
|
|
|
+
|
|
|
|
+ console.log('AI语音URL:', this.aiVoiceUrl);
|
|
|
|
+
|
|
|
|
+ // 显示AI回复文本作为字幕
|
|
|
|
+ this.currentSubtitle = this.aiText;
|
|
|
|
+
|
|
|
|
+ // 播放AI语音
|
|
|
|
+ this.playAiVoice();
|
|
|
|
+ } else {
|
|
|
|
+ console.warn('未获取到AI语音URL');
|
|
|
|
+ // 如果没有语音URL,直接跳转
|
|
|
|
+ this.navigateToNextPage();
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ console.error('AI语音交互失败:', data);
|
|
|
|
+ // AI交互失败,直接跳转
|
|
|
|
+ this.navigateToNextPage();
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ // 添加处理AI交互错误的方法
|
|
|
|
+ handleAiInteractionError(err) {
|
|
|
|
+ console.error('AI语音交互请求失败:', err);
|
|
|
|
+ uni.hideLoading();
|
|
|
|
+
|
|
|
|
+ // 显示错误提示
|
|
|
|
+ uni.showToast({
|
|
|
|
+ title: 'AI处理失败,请稍后再试',
|
|
|
|
+ icon: 'none',
|
|
|
|
+ duration: 2000
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ // 请求失败,直接跳转
|
|
|
|
+ this.navigateToNextPage();
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ // 添加新方法:播放AI语音
|
|
|
|
+ playAiVoice() {
|
|
|
|
+ console.log('开始播放AI语音:', this.aiVoiceUrl);
|
|
|
|
+
|
|
|
|
+ // 标记正在播放AI语音
|
|
|
|
+ this.isPlayingAiVoice = true;
|
|
|
|
+
|
|
|
|
+ // 创建音频播放器
|
|
|
|
+ this.aiAudioPlayer = uni.createInnerAudioContext();
|
|
|
|
+ this.aiAudioPlayer.src = this.aiVoiceUrl;
|
|
|
|
+ this.aiAudioPlayer.autoplay = true;
|
|
|
|
+
|
|
|
|
+ // 监听播放开始事件
|
|
|
|
+ this.aiAudioPlayer.onPlay(() => {
|
|
|
|
+ console.log('AI语音开始播放');
|
|
|
|
+
|
|
|
|
+ // 显示正在播放提示
|
|
|
|
+ uni.showToast({
|
|
|
|
+ title: '正在播放AI回复',
|
|
|
|
+ icon: 'none',
|
|
|
|
+ duration: 2000
|
|
|
|
+ });
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ // 监听播放结束事件
|
|
|
|
+ this.aiAudioPlayer.onEnded(() => {
|
|
|
|
+ console.log('AI语音播放结束');
|
|
|
|
+
|
|
|
|
+ // 标记播放结束
|
|
|
|
+ this.isPlayingAiVoice = false;
|
|
|
|
+
|
|
|
|
+ // 清空字幕
|
|
|
|
+ this.currentSubtitle = '';
|
|
|
|
+
|
|
|
|
+ // 销毁音频播放器
|
|
|
|
+ if (this.aiAudioPlayer) {
|
|
|
|
+ this.aiAudioPlayer.destroy();
|
|
|
|
+ this.aiAudioPlayer = null;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 播放结束后跳转到下一页
|
|
|
|
+ this.navigateToNextPage();
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ // 监听播放错误事件
|
|
|
|
+ this.aiAudioPlayer.onError((err) => {
|
|
|
|
+ console.error('AI语音播放错误:', err);
|
|
|
|
+
|
|
|
|
+ // 标记播放结束
|
|
|
|
+ this.isPlayingAiVoice = false;
|
|
|
|
+
|
|
|
|
+ // 清空字幕
|
|
|
|
+ this.currentSubtitle = '';
|
|
|
|
+
|
|
|
|
+ // 销毁音频播放器
|
|
|
|
+ if (this.aiAudioPlayer) {
|
|
|
|
+ this.aiAudioPlayer.destroy();
|
|
|
|
+ this.aiAudioPlayer = null;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 播放错误时也跳转到下一页
|
|
|
|
+ this.navigateToNextPage();
|
|
|
|
+ });
|
|
|
|
+ },
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
</script>
|