const express = require('express'); const http = require('http'); const socketIo = require('socket.io'); const cors = require('cors'); const path = require('path'); const fs = require('fs'); const app = express(); const server = http.createServer(app); const io = socketIo(server, { cors: { origin: "*", methods: ["GET", "POST"] } }); // 中间件 app.use(cors()); app.use(express.json()); app.use(express.static('src')); app.use('/videos', express.static('videos')); // 存储连接的客户端和他们的视频流状态 const connectedClients = new Map(); // 视频映射配置 const videoMapping = { '你好': 'asd.mp4', 'hello': 'asd.mp4', '再见': 'zxc.mp4', 'goodbye': 'zxc.mp4', '谢谢': 'jkl.mp4', 'thank you': 'jkl.mp4', '默认': 'asd.mp4' }; // 默认视频流配置 const DEFAULT_VIDEO = 'asd.mp4'; const INTERACTION_TIMEOUT = 10000; // 10秒后回到默认视频 // 获取视频列表 app.get('/api/videos', (req, res) => { const videosDir = path.join(__dirname, 'videos'); fs.readdir(videosDir, (err, files) => { if (err) { return res.status(500).json({ error: '无法读取视频目录' }); } const videoFiles = files.filter(file => file.endsWith('.mp4') || file.endsWith('.webm') || file.endsWith('.avi') ); res.json({ videos: videoFiles }); }); }); // 获取视频映射 app.get('/api/video-mapping', (req, res) => { res.json({ mapping: videoMapping }); }); // 获取默认视频 app.get('/api/default-video', (req, res) => { res.json({ defaultVideo: DEFAULT_VIDEO, autoLoop: true }); }); // Socket.IO 连接处理 io.on('connection', (socket) => { console.log('用户连接:', socket.id); connectedClients.set(socket.id, { socket: socket, currentVideo: DEFAULT_VIDEO, isInInteraction: false }); // 处理WebRTC信令 - 用于传输视频流 socket.on('offer', (data) => { console.log('收到offer:', socket.id); socket.broadcast.emit('offer', { ...data, from: socket.id }); }); socket.on('answer', (data) => { console.log('收到answer:', socket.id); socket.broadcast.emit('answer', { ...data, from: socket.id }); }); socket.on('ice-candidate', (data) => { console.log('收到ice-candidate:', socket.id); socket.broadcast.emit('ice-candidate', { ...data, from: socket.id }); }); // 处理视频流切换请求 socket.on('switch-video-stream', (data) => { const { videoFile, type, text } = data; console.log(`用户 ${socket.id} 请求切换视频流: ${videoFile} (${type})`); // 更新客户端状态 const client = connectedClients.get(socket.id); if (client) { client.currentVideo = videoFile; client.isInInteraction = true; } // 广播视频流切换指令给所有用户 io.emit('video-stream-switched', { videoFile, type, text, from: socket.id }); // 如果是交互类型,设置定时器回到默认视频 if (type === 'text' || type === 'voice') { setTimeout(() => { console.log(`交互超时,用户 ${socket.id} 回到默认视频`); if (client) { client.currentVideo = DEFAULT_VIDEO; client.isInInteraction = false; } // 广播回到默认视频的指令 io.emit('video-stream-switched', { videoFile: DEFAULT_VIDEO, type: 'default', from: socket.id }); }, INTERACTION_TIMEOUT); } }); // 处理通话开始 socket.on('call-started', () => { console.log('通话开始,用户:', socket.id); const client = connectedClients.get(socket.id); if (client) { client.currentVideo = DEFAULT_VIDEO; client.isInInteraction = false; } io.emit('call-started', { from: socket.id }); }); // 处理文本输入 socket.on('text-input', (data) => { const { text } = data; console.log('收到文本输入:', text, '来自用户:', socket.id); // 根据文本查找对应视频 let videoFile = videoMapping['默认']; for (const [key, value] of Object.entries(videoMapping)) { if (text.toLowerCase().includes(key.toLowerCase())) { videoFile = value; break; } } console.log(`用户 ${socket.id} 文本输入 "${text}" 对应视频: ${videoFile}`); // 发送视频流切换请求 socket.emit('switch-video-stream', { videoFile, type: 'text', text }); }); // 处理语音输入 socket.on('voice-input', (data) => { const { audioData, text } = data; console.log('收到语音输入:', text, '来自用户:', socket.id); // 根据语音识别的文本查找对应视频 let videoFile = videoMapping['默认']; for (const [key, value] of Object.entries(videoMapping)) { if (text.toLowerCase().includes(key.toLowerCase())) { videoFile = value; break; } } console.log(`用户 ${socket.id} 语音输入 "${text}" 对应视频: ${videoFile}`); // 发送视频流切换请求 socket.emit('switch-video-stream', { videoFile, type: 'voice', text }); }); // 处理回到默认视频请求 socket.on('return-to-default', () => { console.log('用户请求回到默认视频:', socket.id); const client = connectedClients.get(socket.id); if (client) { client.currentVideo = DEFAULT_VIDEO; client.isInInteraction = false; } socket.emit('switch-video-stream', { videoFile: DEFAULT_VIDEO, type: 'default' }); }); // 断开连接 socket.on('disconnect', () => { console.log('用户断开连接:', socket.id); connectedClients.delete(socket.id); }); }); const PORT = process.env.PORT || 3000; server.listen(PORT, () => { console.log(`服务器运行在端口 ${PORT}`); console.log(`访问 http://localhost:${PORT} 开始使用`); });