feat(voice-recognition): add speech recognition and emotion-based video switching

Implement voice recognition functionality that displays transcript in a styled container. Add emotion analysis to switch videos based on detected positive/negative keywords in speech. Includes UI updates for transcript display and microphone interaction.
This commit is contained in:
2025-07-16 17:37:34 +08:00
parent 025cd29268
commit e917cc45a5
3 changed files with 142 additions and 20 deletions
+5
View File
@@ -38,6 +38,11 @@
</div>
</header>
<!-- 语音识别结果显示区域 -->
<div class="transcript-container">
<p id="transcript"></p>
</div>
<!-- 底部麦克风和链接 -->
<footer class="bottom-bar">
<button class="mic-button" id="mic-button" aria-label="Start Listening">
+110 -20
View File
@@ -69,33 +69,123 @@ document.addEventListener('DOMContentLoaded', function() {
activeVideo.addEventListener('ended', switchVideo, { once: true });
// --- 麦克风按钮交互和好感度条模拟 ---
// --- 语音识别核心 ---
const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
let recognition;
// 检查浏览器是否支持语音识别
if (SpeechRecognition) {
recognition = new SpeechRecognition();
recognition.continuous = true; // 持续识别
recognition.lang = 'zh-CN'; // 设置语言为中文
recognition.interimResults = true; // 获取临时结果
recognition.onresult = (event) => {
const transcriptContainer = document.getElementById('transcript');
let final_transcript = '';
let interim_transcript = '';
for (let i = event.resultIndex; i < event.results.length; ++i) {
if (event.results[i].isFinal) {
final_transcript += event.results[i][0].transcript;
} else {
interim_transcript += event.results[i][0].transcript;
}
}
// 显示最终识别结果
transcriptContainer.textContent = final_transcript || interim_transcript;
// 基于关键词的情感分析和视频切换
if (final_transcript) {
analyzeAndReact(final_transcript);
}
};
recognition.onerror = (event) => {
console.error('语音识别错误:', event.error);
};
} else {
console.log('您的浏览器不支持语音识别功能。');
// 可以在界面上给用户提示
}
// --- 麦克风按钮交互 ---
let isListening = false;
let currentFavorability = 65; // 与 CSS 中的初始宽度保持一致
micButton.addEventListener('click', function() {
isListening = !isListening;
// 切换 "监听中" 的样式 (动画)
micButton.classList.toggle('is-listening', isListening);
if (!SpeechRecognition) return; // 如果不支持,则不执行任何操作
isListening = !isListening;
micButton.classList.toggle('is-listening', isListening);
const transcriptContainer = document.querySelector('.transcript-container');
const transcriptText = document.getElementById('transcript');
// 模拟交互:每次点击麦克风,好感度增加
if (isListening) {
// 增加好感度,但最高不超过 100
currentFavorability += 5;
if (currentFavorability > 100) {
currentFavorability = 100;
}
transcriptText.textContent = '聆听中...'; // 立刻显示提示
transcriptContainer.classList.add('visible');
recognition.start();
} else {
// 如果停止监听,可以稍微降低一点好感度(可选)
currentFavorability -= 2;
if (currentFavorability < 0) {
currentFavorability = 0;
}
recognition.stop();
transcriptContainer.classList.remove('visible');
transcriptText.textContent = ''; // 清空文本
}
// 更新好感度进度条的宽度
favorabilityBar.style.width = currentFavorability + '%';
});
// --- 情感分析与反应 ---
const positiveWords = ['开心', '高兴', '喜欢', '太棒了', '你好', '漂亮'];
const negativeWords = ['难过', '生气', '讨厌', '伤心'];
const positiveVideos = [
'视频资源/jimeng-2025-07-16-1043-笑着优雅的左右摇晃,过一会儿手扶着下巴,保持微笑.mp4',
'视频资源/jimeng-2025-07-16-4437-比耶,然后微笑着优雅的左右摇晃.mp4',
'视频资源/生成加油视频.mp4',
'视频资源/生成跳舞视频.mp4'
];
const negativeVideo = '视频资源/负面/jimeng-2025-07-16-9418-双手叉腰,嘴巴一直在嘟囔,表情微微生气.mp4';
function analyzeAndReact(text) {
let reaction = 'neutral'; // 默认为中性
if (positiveWords.some(word => text.includes(word))) {
reaction = 'positive';
} else if (negativeWords.some(word => text.includes(word))) {
reaction = 'negative';
}
if (reaction !== 'neutral') {
switchVideoByEmotion(reaction);
}
}
function switchVideoByEmotion(emotion) {
let nextVideoSrc;
if (emotion === 'positive') {
const randomIndex = Math.floor(Math.random() * positiveVideos.length);
nextVideoSrc = positiveVideos[randomIndex];
} else { // negative
nextVideoSrc = negativeVideo;
}
// 避免重复播放同一个视频
const currentVideoSrc = activeVideo.querySelector('source').getAttribute('src');
if (nextVideoSrc === currentVideoSrc) return;
// --- 以下逻辑与 switchVideo 函数类似,用于切换视频 ---
inactiveVideo.querySelector('source').setAttribute('src', nextVideoSrc);
inactiveVideo.load();
inactiveVideo.addEventListener('canplaythrough', function onCanPlayThrough() {
inactiveVideo.removeEventListener('canplaythrough', onCanPlayThrough);
inactiveVideo.play().catch(error => console.error("Video play failed:", error));
activeVideo.classList.remove('active');
inactiveVideo.classList.add('active');
[activeVideo, inactiveVideo] = [inactiveVideo, activeVideo];
// 情感触发的视频播放结束后,回归随机播放
activeVideo.addEventListener('ended', switchVideo, { once: true });
}, { once: true });
}
});
+27
View File
@@ -125,6 +125,33 @@ html, body {
/* 这个区域现在是空的,可以移除或保留以备将来使用 */
}
/* --- 语音识别结果显示 --- */
.transcript-container {
position: absolute;
bottom: 180px; /* 放置在麦克风按钮上方 */
left: 50%;
transform: translateX(-50%);
width: 80%;
max-width: 600px;
padding: 15px;
background: rgba(0, 0, 0, 0.5);
border-radius: 10px;
text-align: center;
opacity: 0;
transition: opacity 0.3s ease-in-out;
pointer-events: none; /* 默认不响应鼠标事件 */
}
.transcript-container.visible {
opacity: 1;
}
#transcript {
font-size: 1.2rem;
color: #fff;
text-shadow: 1px 1px 2px rgba(0,0,0,0.7);
}
/* --- 底部内容 --- */
.bottom-bar {
width: 100%;