This commit is contained in:
parent
ea465ad586
commit
df98105213
13
server.js
13
server.js
@ -137,7 +137,8 @@ const scenes = [
|
|||||||
tag: 'chat',
|
tag: 'chat',
|
||||||
apiKey: 'bot-20250916100919-w8vxr', // 起床场景的API key
|
apiKey: 'bot-20250916100919-w8vxr', // 起床场景的API key
|
||||||
openingLines: [
|
openingLines: [
|
||||||
" 爷爷/奶奶,我来啦!今天您过得怎么样呀?有没有什么好玩的事儿跟我说说呀?",
|
"我来啦!今天您过得怎么样呀?有没有什么好玩的事儿跟我说说呀?",
|
||||||
|
"天冷了,您可得多穿点啊!"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
@ -487,7 +488,7 @@ io.on('connection', (socket) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 断开连接
|
// 断开连接
|
||||||
socket.on('disconnect', () => {
|
socket.on('disconnect', async () => {
|
||||||
console.log('用户断开连接:', socket.id);
|
console.log('用户断开连接:', socket.id);
|
||||||
const client = connectedClients.get(socket.id);
|
const client = connectedClients.get(socket.id);
|
||||||
if (client) {
|
if (client) {
|
||||||
@ -499,6 +500,14 @@ io.on('connection', (socket) => {
|
|||||||
}
|
}
|
||||||
connectedClients.delete(socket.id);
|
connectedClients.delete(socket.id);
|
||||||
|
|
||||||
|
// 清空聊天记录
|
||||||
|
try {
|
||||||
|
await messageHistory.clearHistory();
|
||||||
|
console.log('断开连接后已清空 chat_history.json');
|
||||||
|
} catch (err) {
|
||||||
|
console.error('清空聊天记录失败:', err);
|
||||||
|
}
|
||||||
|
|
||||||
// 清除活跃用户
|
// 清除活跃用户
|
||||||
if (activeUser === socket.id) {
|
if (activeUser === socket.id) {
|
||||||
activeUser = null;
|
activeUser = null;
|
||||||
|
|||||||
@ -197,7 +197,7 @@ async function chatWithAudioStream(userInput) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 导出初始化函数,供外部调用
|
// 导出初始化函数,供外部调用
|
||||||
export { chatWithAudioStream, initializeHistoryMessage, getCurrentHistoryMessage, saveMessage, updateHistoryMessage };
|
export { chatWithAudioStream, initializeHistoryMessage, getCurrentHistoryMessage, saveMessage, updateHistoryMessage, prependIntroRole };
|
||||||
|
|
||||||
// 处理音频播放队列
|
// 处理音频播放队列
|
||||||
async function processAudioQueue() {
|
async function processAudioQueue() {
|
||||||
@ -323,3 +323,18 @@ async function playAudioStreamNode(audioHex) {
|
|||||||
|
|
||||||
|
|
||||||
// export { chatWithAudioStream, playAudioStream, playAudioStreamNode, initializeHistoryMessage, getCurrentHistoryMessage };
|
// export { chatWithAudioStream, playAudioStream, playAudioStreamNode, initializeHistoryMessage, getCurrentHistoryMessage };
|
||||||
|
|
||||||
|
// 在历史消息顶部插入“我是你的roleName / 好的,roleName。”开场提示
|
||||||
|
function prependIntroRole(roleName) {
|
||||||
|
if (!roleName) return;
|
||||||
|
const introUser = { role: 'user', content: `我是你的${roleName}` };
|
||||||
|
const introAssistant = { role: 'assistant', content: `好的,${roleName}。` };
|
||||||
|
const hasIntro = historyMessage.slice(0, 2).some(m =>
|
||||||
|
m.content === introUser.content || m.content === introAssistant.content
|
||||||
|
);
|
||||||
|
if (!hasIntro) {
|
||||||
|
// 先插助手,再插用户,确保用户消息在最顶部
|
||||||
|
historyMessage.unshift(introAssistant);
|
||||||
|
historyMessage.unshift(introUser);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -56,7 +56,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-col md:flex-row items-center justify-center gap-8 md:gap-16 w-full" data-aos="fade-up">
|
<div class="flex flex-col md:flex-row items-center justify-center gap-8 md:gap-16 w-full" data-aos="fade-up">
|
||||||
<a href="/index.html" class="group block cursor-pointer focus:outline-none">
|
<a href="/old.html" class="group block cursor-pointer focus:outline-none">
|
||||||
<div class="avatar-hover bg-gray-800 bg-opacity-60 backdrop-blur-md rounded-full p-4 border-2 border-green-500 transition-all duration-300 group-hover:border-purple-500 md:group-hover:border-purple-500 group-active:border-purple-500">
|
<div class="avatar-hover bg-gray-800 bg-opacity-60 backdrop-blur-md rounded-full p-4 border-2 border-green-500 transition-all duration-300 group-hover:border-purple-500 md:group-hover:border-purple-500 group-active:border-purple-500">
|
||||||
<div class="w-32 h-32 md:w-40 md:h-40 rounded-full overflow-hidden border-4 border-green-400 group-hover:border-purple-400 md:group-hover:border-purple-400 group-active:border-purple-400 transition-all duration-300">
|
<div class="w-32 h-32 md:w-40 md:h-40 rounded-full overflow-hidden border-4 border-green-400 group-hover:border-purple-400 md:group-hover:border-purple-400 group-active:border-purple-400 transition-all duration-300">
|
||||||
<img src="tx.png" alt="Dashboard" class="w-full h-full object-cover">
|
<img src="tx.png" alt="Dashboard" class="w-full h-full object-cover">
|
||||||
|
|||||||
20
src/index.js
20
src/index.js
@ -1,7 +1,7 @@
|
|||||||
console.log('视频文件:');
|
console.log('视频文件:');
|
||||||
// WebRTC 音视频通话应用
|
// WebRTC 音视频通话应用
|
||||||
// import { chatWithAudioStream } from './chat_with_audio.js';
|
// import { chatWithAudioStream } from './chat_with_audio.js';
|
||||||
import { chatWithAudioStream, initializeHistoryMessage, updateHistoryMessage } from './chat_with_audio.js';
|
import { chatWithAudioStream, initializeHistoryMessage, updateHistoryMessage, prependIntroRole } from './chat_with_audio.js';
|
||||||
|
|
||||||
import { AudioProcessor } from './audio_processor.js';
|
import { AudioProcessor } from './audio_processor.js';
|
||||||
|
|
||||||
@ -256,7 +256,11 @@ class WebRTCChat {
|
|||||||
async initializeHistory() {
|
async initializeHistory() {
|
||||||
try {
|
try {
|
||||||
await initializeHistoryMessage(100);
|
await initializeHistoryMessage(100);
|
||||||
|
const params = new URLSearchParams(window.location.search);
|
||||||
|
const roleName = params.get('roleName');
|
||||||
|
if (roleName) {
|
||||||
|
prependIntroRole(roleName);
|
||||||
|
}
|
||||||
console.log('历史消息初始化完成');
|
console.log('历史消息初始化完成');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('历史消息初始化失败:', error);
|
console.error('历史消息初始化失败:', error);
|
||||||
@ -268,16 +272,22 @@ class WebRTCChat {
|
|||||||
try {
|
try {
|
||||||
console.log('开始初始化开场白音频...');
|
console.log('开始初始化开场白音频...');
|
||||||
|
|
||||||
|
// 获取URL参数中的roleName
|
||||||
|
const params = new URLSearchParams(window.location.search);
|
||||||
|
const roleName = params.get('roleName') || '';
|
||||||
|
|
||||||
// 获取当前场景的开场白
|
// 获取当前场景的开场白
|
||||||
const response = await fetch('/api/current-scene/opening-line');
|
const response = await fetch('/api/current-scene/opening-line');
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
|
|
||||||
if (data.success && data.openingLine) {
|
if (data.success && data.openingLine) {
|
||||||
console.log(`获取到开场白: ${data.openingLine}`);
|
// 如果有roleName,则在开场白前加上角色名称
|
||||||
|
const finalOpeningLine = roleName ? `${roleName},${data.openingLine}` : data.openingLine;
|
||||||
|
console.log(`获取到开场白: ${finalOpeningLine}`);
|
||||||
|
|
||||||
// 生成开场白音频
|
// 生成开场白音频
|
||||||
await this.generateOpeningAudio(data.openingLine);
|
await this.generateOpeningAudio(finalOpeningLine);
|
||||||
this.logMessage(`开场白音频已准备就绪: ${data.openingLine}`, 'success');
|
this.logMessage(`开场白音频已准备就绪: ${finalOpeningLine}`, 'success');
|
||||||
} else {
|
} else {
|
||||||
console.warn('未获取到开场白:', data.message);
|
console.warn('未获取到开场白:', data.message);
|
||||||
}
|
}
|
||||||
|
|||||||
188
src/old.html
Normal file
188
src/old.html
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Yantootech</title>
|
||||||
|
<script src="https://cdn.tailwindcss.com"></script>
|
||||||
|
<script src="https://unpkg.com/feather-icons"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/vanta@latest/dist/vanta.net.min.js"></script>
|
||||||
|
<style>
|
||||||
|
@keyframes float {
|
||||||
|
0%, 100% { transform: translateY(0); }
|
||||||
|
50% { transform: translateY(-10px); }
|
||||||
|
}
|
||||||
|
.card-hover:hover {
|
||||||
|
transform: translateY(-5px);
|
||||||
|
box-shadow: 0 15px 30px rgba(252, 118, 7, 0.2);
|
||||||
|
}
|
||||||
|
.selected-card {
|
||||||
|
animation: pulse 2s infinite;
|
||||||
|
box-shadow: 0 0 0 4px rgba(252, 118, 7, 0.3);
|
||||||
|
}
|
||||||
|
@keyframes pulse {
|
||||||
|
0% { box-shadow: 0 0 0 0 rgba(252, 118, 7, 0.4); }
|
||||||
|
70% { box-shadow: 0 0 0 15px rgba(252, 118, 7, 0); }
|
||||||
|
100% { box-shadow: 0 0 0 0 rgba(252, 118, 7, 0); }
|
||||||
|
}
|
||||||
|
.button-glow {
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
.button-glow:hover {
|
||||||
|
box-shadow: 0 0 20px rgba(252, 118, 7, 0.6);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body class="bg-[#EEECBC] min-h-screen font-sans">
|
||||||
|
<div id="vanta-bg" class="fixed inset-0 z-0"></div>
|
||||||
|
|
||||||
|
<div class="relative z-10 container mx-auto px-4 py-12">
|
||||||
|
<div class="text-center mb-16">
|
||||||
|
<h1 class="text-4xl md:text-5xl font-bold text-[#D83514] mb-4">选择你的身份</h1>
|
||||||
|
<p class="text-lg text-[#AC8975] max-w-2xl mx-auto">在数字世界找到属于你的温暖连接</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8 max-w-4xl mx-auto">
|
||||||
|
<!-- Uncle Card -->
|
||||||
|
<div class="card bg-[#EFCE7D] rounded-xl p-6 text-center cursor-pointer transition-all duration-300 border-2 border-[#AC8975] card-hover" onclick="selectRole('uncle')">
|
||||||
|
<div class="bg-white rounded-full w-24 h-24 mx-auto mb-4 flex items-center justify-center text-4xl">
|
||||||
|
👨💼
|
||||||
|
</div>
|
||||||
|
<h3 class="text-2xl font-semibold text-[#D83514] mb-2">叔叔</h3>
|
||||||
|
<!-- <p class="text-[#AC8975]">智慧与经验的分享者</p> -->
|
||||||
|
<div class="selected-indicator hidden mt-4 text-[#FC7607]">
|
||||||
|
<i data-feather="check-circle" class="w-8 h-8 mx-auto"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Aunt Card -->
|
||||||
|
<div class="card bg-[#EFCE7D] rounded-xl p-6 text-center cursor-pointer transition-all duration-300 border-2 border-[#AC8975] card-hover" onclick="selectRole('aunt')">
|
||||||
|
<div class="bg-white rounded-full w-24 h-24 mx-auto mb-4 flex items-center justify-center text-4xl">
|
||||||
|
👩💼
|
||||||
|
</div>
|
||||||
|
<h3 class="text-2xl font-semibold text-[#D83514] mb-2">阿姨</h3>
|
||||||
|
<!-- <p class="text-[#AC8975]">温柔与关怀的传递者</p> -->
|
||||||
|
<div class="selected-indicator hidden mt-4 text-[#FC7607]">
|
||||||
|
<i data-feather="check-circle" class="w-8 h-8 mx-auto"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Grandpa Card -->
|
||||||
|
<div class="card bg-[#EFCE7D] rounded-xl p-6 text-center cursor-pointer transition-all duration-300 border-2 border-[#AC8975] card-hover" onclick="selectRole('grandpa')">
|
||||||
|
<div class="bg-white rounded-full w-24 h-24 mx-auto mb-4 flex items-center justify-center text-4xl">
|
||||||
|
👴🌳
|
||||||
|
</div>
|
||||||
|
<h3 class="text-2xl font-semibold text-[#D83514] mb-2">爷爷</h3>
|
||||||
|
<!-- <p class="text-[#AC8975]">故事与智慧的宝库</p> -->
|
||||||
|
<div class="selected-indicator hidden mt-4 text-[#FC7607]">
|
||||||
|
<i data-feather="check-circle" class="w-8 h-8 mx-auto"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Grandma Card -->
|
||||||
|
<div class="card bg-[#EFCE7D] rounded-xl p-6 text-center cursor-pointer transition-all duration-300 border-2 border-[#AC8975] card-hover" onclick="selectRole('grandma')">
|
||||||
|
<div class="bg-white rounded-full w-24 h-24 mx-auto mb-4 flex items-center justify-center text-4xl">
|
||||||
|
👵🧶
|
||||||
|
</div>
|
||||||
|
<h3 class="text-2xl font-semibold text-[#D83514] mb-2">奶奶</h3>
|
||||||
|
<!-- <p class="text-[#AC8975]">爱与传统的守护者</p> -->
|
||||||
|
<div class="selected-indicator hidden mt-4 text-[#FC7607]">
|
||||||
|
<i data-feather="check-circle" class="w-8 h-8 mx-auto"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="text-center mt-16">
|
||||||
|
<button id="confirmBtn" class="bg-[#AC8975] bg-opacity-60 text-gray-500 px-8 py-4 rounded-full text-xl font-medium transition-all duration-300 cursor-not-allowed">
|
||||||
|
确认选择
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
if (window.THREE && window.VANTA && document.querySelector('#vanta-bg')) {
|
||||||
|
VANTA.NET({
|
||||||
|
el: "#vanta-bg",
|
||||||
|
THREE: window.THREE, // 显式传入 THREE,避免读取不到全局
|
||||||
|
mouseControls: true,
|
||||||
|
touchControls: true,
|
||||||
|
gyroControls: false,
|
||||||
|
minHeight: 200.00,
|
||||||
|
minWidth: 200.00,
|
||||||
|
scale: 1.00,
|
||||||
|
scaleMobile: 1.00,
|
||||||
|
color: 0xfc7607,
|
||||||
|
backgroundColor: 0xeeecbc,
|
||||||
|
points: 8.00,
|
||||||
|
maxDistance: 20.00,
|
||||||
|
spacing: 15.00
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.error('VANTA 初始化失败:THREE 或 VANTA 未加载');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化 feather icons
|
||||||
|
feather.replace();
|
||||||
|
|
||||||
|
let selectedRole = null;
|
||||||
|
const roleNames = {
|
||||||
|
'uncle': '叔叔',
|
||||||
|
'aunt': '阿姨',
|
||||||
|
'grandpa': '爷爷',
|
||||||
|
'grandma': '奶奶'
|
||||||
|
};
|
||||||
|
|
||||||
|
function selectRole(role) {
|
||||||
|
// Remove selection from all cards
|
||||||
|
document.querySelectorAll('.card').forEach(card => {
|
||||||
|
card.classList.remove('selected-card', 'border-[#FC7607]');
|
||||||
|
card.querySelector('.selected-indicator').classList.add('hidden');
|
||||||
|
card.style.transform = '';
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add selection to clicked card
|
||||||
|
const selectedCard = event.currentTarget;
|
||||||
|
selectedCard.classList.add('selected-card', 'border-[#FC7607]');
|
||||||
|
selectedCard.querySelector('.selected-indicator').classList.remove('hidden');
|
||||||
|
selectedCard.style.transform = 'scale(1.05)';
|
||||||
|
|
||||||
|
selectedRole = role;
|
||||||
|
|
||||||
|
// Enable confirm button
|
||||||
|
const confirmBtn = document.getElementById('confirmBtn');
|
||||||
|
confirmBtn.classList.remove('bg-[#AC8975]', 'bg-opacity-60', 'text-gray-500', 'cursor-not-allowed');
|
||||||
|
confirmBtn.classList.add('bg-gradient-to-r', 'from-[#FC7607]', 'to-[#D83514]', 'text-white', 'button-glow', 'cursor-pointer');
|
||||||
|
confirmBtn.textContent = `小乐与 ${roleNames[role]} 开始对话`;
|
||||||
|
|
||||||
|
// Add animation to the button
|
||||||
|
confirmBtn.style.animation = 'none';
|
||||||
|
setTimeout(() => {
|
||||||
|
confirmBtn.style.animation = 'pulse 1.5s infinite';
|
||||||
|
}, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add hover effect to cards
|
||||||
|
document.querySelectorAll('.card').forEach(card => {
|
||||||
|
card.addEventListener('mouseenter', () => {
|
||||||
|
if (!card.classList.contains('selected-card')) {
|
||||||
|
card.classList.add('border-[#FC7607]');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
card.addEventListener('mouseleave', () => {
|
||||||
|
if (!card.classList.contains('selected-card')) {
|
||||||
|
card.classList.remove('border-[#FC7607]');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Confirm button action
|
||||||
|
document.getElementById('confirmBtn').addEventListener('click', function() {
|
||||||
|
if (selectedRole) {
|
||||||
|
const roleName = roleNames[selectedRole];
|
||||||
|
window.location.href = `index.html?roleName=${encodeURIComponent(roleName)}`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Loading…
x
Reference in New Issue
Block a user