Files
bella/script.js
你的名字 8a89c2a7fa feat(core): activate LLM model and enhance think method with personality prompts
refactor(script): improve UI feedback with styled thinking and response elements

docs: add project planning and feature list documents

style(script): add visual styling for better user feedback

chore: update PRD and README to reflect current project status
2025-07-21 20:35:25 +08:00

190 lines
7.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import BellaAI from './core.js';
document.addEventListener('DOMContentLoaded', async function() {
// --- Get all necessary DOM elements first ---
const transcriptDiv = document.getElementById('transcript');
const loadingScreen = document.getElementById('loading-screen');
const video1 = document.getElementById('video1');
const video2 = document.getElementById('video2');
const micButton = document.getElementById('mic-button');
// --- AI Core Initialization ---
let bellaAI;
micButton.disabled = true;
transcriptDiv.textContent = '正在唤醒贝拉的核心...';
try {
bellaAI = await BellaAI.getInstance();
micButton.disabled = false;
transcriptDiv.textContent = '贝拉已准备好,请点击麦克风开始对话。';
} catch (error) {
console.error('Failed to initialize Bella AI:', error);
transcriptDiv.textContent = '唤醒贝拉时遇到问题,请检查控制台信息。';
// Keep the app running with visual features even if AI fails
}
// --- Loading screen handling ---
setTimeout(() => {
loadingScreen.style.opacity = '0';
// Hide it after the animation to prevent it from blocking interactions
setTimeout(() => {
loadingScreen.style.display = 'none';
}, 500); // This time should match the transition time in CSS
}, 1500); // Start fading out after 1.5 seconds
let activeVideo = video1;
let inactiveVideo = video2;
// 视频列表
const videoList = [
'视频资源/3D 建模图片制作.mp4',
'视频资源/jimeng-2025-07-16-1043-笑着优雅的左右摇晃,过一会儿手扶着下巴,保持微笑.mp4',
'视频资源/jimeng-2025-07-16-4437-比耶,然后微笑着优雅的左右摇晃.mp4',
'视频资源/生成加油视频.mp4',
'视频资源/生成跳舞视频.mp4',
'视频资源/负面/jimeng-2025-07-16-9418-双手叉腰,嘴巴一直在嘟囔,表情微微生气.mp4'
];
// --- 视频交叉淡入淡出播放功能 ---
function switchVideo() {
// 1. 选择下一个视频
const currentVideoSrc = activeVideo.querySelector('source').getAttribute('src');
let nextVideoSrc = currentVideoSrc;
while (nextVideoSrc === currentVideoSrc) {
const randomIndex = Math.floor(Math.random() * videoList.length);
nextVideoSrc = videoList[randomIndex];
}
// 2. 设置不活动的 video 元素的 source
inactiveVideo.querySelector('source').setAttribute('src', nextVideoSrc);
inactiveVideo.load();
// 3. 当不活动的视频可以播放时,执行切换
inactiveVideo.addEventListener('canplaythrough', function onCanPlayThrough() {
// 确保事件只触发一次
inactiveVideo.removeEventListener('canplaythrough', onCanPlayThrough);
// 4. 播放新视频
inactiveVideo.play().catch(error => {
console.error("Video play failed:", error);
});
// 5. 切换 active class 来触发 CSS 过渡
activeVideo.classList.remove('active');
inactiveVideo.classList.add('active');
// 6. 更新角色
[activeVideo, inactiveVideo] = [inactiveVideo, activeVideo];
// 为新的 activeVideo 绑定 ended 事件
activeVideo.addEventListener('ended', switchVideo, { once: true });
}, { once: true }); // 使用 { once: true } 确保事件只被处理一次
}
// 初始启动
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 = async (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;
}
}
// Update interim results
transcriptContainer.textContent = `你: ${final_transcript || interim_transcript}`;
// Once we have a final result, process it with the AI
if (final_transcript && bellaAI) {
const userText = final_transcript.trim();
transcriptContainer.textContent = `你: ${userText}`;
try {
// Let Bella think
const thinkingText = document.createElement('p');
thinkingText.textContent = '贝拉正在思考...';
thinkingText.style.color = '#888';
thinkingText.style.fontStyle = 'italic';
transcriptContainer.appendChild(thinkingText);
const response = await bellaAI.think(userText);
transcriptContainer.removeChild(thinkingText);
const bellaText = document.createElement('p');
bellaText.textContent = `贝拉: ${response}`;
bellaText.style.color = '#ff6b9d';
bellaText.style.fontWeight = 'bold';
bellaText.style.marginTop = '10px';
transcriptContainer.appendChild(bellaText);
// TTS功能暂时禁用将在下一阶段激活
// TODO: 激活语音合成功能
// const audioData = await bellaAI.speak(response);
// const blob = new Blob([audioData], { type: 'audio/wav' });
// const audioUrl = URL.createObjectURL(blob);
// const audio = new Audio(audioUrl);
// audio.play();
} catch (error) {
console.error('Bella AI processing error:', error);
const errorText = document.createElement('p');
errorText.textContent = '贝拉处理时遇到问题,但她还在努力学习中...';
errorText.style.color = '#ff9999';
transcriptContainer.appendChild(errorText);
}
}
};
recognition.onerror = (event) => {
console.error('语音识别错误:', event.error);
};
} else {
console.log('您的浏览器不支持语音识别功能。');
// 可以在界面上给用户提示
}
// --- 麦克风按钮交互 ---
let isListening = false;
micButton.addEventListener('click', function() {
if (!SpeechRecognition) return; // 如果不支持,则不执行任何操作
isListening = !isListening;
micButton.classList.toggle('is-listening', isListening);
const transcriptContainer = document.querySelector('.transcript-container');
const transcriptText = document.getElementById('transcript');
if (isListening) {
transcriptText.textContent = '聆听中...'; // 立刻显示提示
transcriptContainer.classList.add('visible');
recognition.start();
} else {
recognition.stop();
transcriptContainer.classList.remove('visible');
transcriptText.textContent = ''; // 清空文本
}
});
});