224 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			224 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 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} 开始使用`);
 | |
| }); 
 | 
