diff --git a/chat_history.json b/chat_history.json
new file mode 100644
index 0000000..0637a08
--- /dev/null
+++ b/chat_history.json
@@ -0,0 +1 @@
+[]
\ No newline at end of file
diff --git a/server.js b/server.js
index 6057d2b..e6f86d8 100644
--- a/server.js
+++ b/server.js
@@ -4,15 +4,24 @@ const socketIo = require('socket.io');
const cors = require('cors');
const path = require('path');
const fs = require('fs');
+const { MessageHistory } = require('./src/message_history.js');
const app = express();
const server = http.createServer(app);
-const io = socketIo(server, {
- cors: {
- origin: "*",
- methods: ["GET", "POST"]
- }
-});
+const io = socketIo(server);
+
+// 创建消息历史管理器
+const messageHistory = new MessageHistory();
+
+// 服务器启动时初始化历史消息
+async function initializeServer() {
+ try {
+ await messageHistory.initialize();
+ console.log('消息历史初始化完成');
+ } catch (error) {
+ console.error('初始化消息历史失败:', error);
+ }
+}
// 中间件
app.use(cors());
@@ -20,22 +29,72 @@ app.use(express.json());
app.use(express.static('src'));
app.use('/videos', express.static('videos'));
+// API路由 - 获取历史消息(用于LLM上下文)
+app.get('/api/messages/for-llm', (req, res) => {
+ try {
+ const { includeSystem = true, recentCount = 5 } = req.query;
+ const messages = messageHistory.getMessagesForLLM(
+ includeSystem === 'true',
+ parseInt(recentCount)
+ );
+ res.json({ messages });
+ } catch (error) {
+ console.error('获取LLM消息失败:', error);
+ res.status(500).json({ error: '获取消息失败' });
+ }
+});
+
+// API路由 - 保存新消息
+app.post('/api/messages/save', async (req, res) => {
+ try {
+ const { userInput, assistantResponse } = req.body;
+ if (!userInput || !assistantResponse) {
+ return res.status(400).json({ error: '缺少必要参数' });
+ }
+
+ await messageHistory.addMessage(userInput, assistantResponse);
+ res.json({ success: true, message: '消息已保存' });
+ } catch (error) {
+ console.error('保存消息失败:', error);
+ res.status(500).json({ error: '保存消息失败' });
+ }
+});
+
+// API路由 - 获取完整历史(可选,用于调试或展示)
+app.get('/api/messages/history', (req, res) => {
+ try {
+ const history = messageHistory.getFullHistory();
+ res.json({ history });
+ } catch (error) {
+ console.error('获取历史消息失败:', error);
+ res.status(500).json({ error: '获取历史消息失败' });
+ }
+});
+
+// API路由 - 清空历史
+app.delete('/api/messages/clear', async (req, res) => {
+ try {
+ await messageHistory.clearHistory();
+ res.json({ success: true, message: '历史消息已清空' });
+ } catch (error) {
+ console.error('清空历史消息失败:', error);
+ res.status(500).json({ error: '清空历史消息失败' });
+ }
+});
+
// 存储连接的客户端和他们的视频流状态
const connectedClients = new Map();
// 视频映射配置
const videoMapping = {
- '你好': 'asd.mp4',
- 'hello': 'asd.mp4',
- '再见': 'zxc.mp4',
- 'goodbye': 'zxc.mp4',
- '谢谢': 'jkl.mp4',
- 'thank you': 'jkl.mp4',
- '默认': 'asd.mp4'
+ 'say-6s-m-e': '1-m.mp4',
+ 'default': '0.mp4',
+ 'say-5s-amplitude': '2.mp4',
+ 'say-5s-m-e': 'zxc.mp4'
};
// 默认视频流配置
-const DEFAULT_VIDEO = 'asd.mp4';
+const DEFAULT_VIDEO = '0.mp4';
const INTERACTION_TIMEOUT = 10000; // 10秒后回到默认视频
// 获取视频列表
@@ -217,8 +276,13 @@ io.on('connection', (socket) => {
});
});
+// 启动服务器
const PORT = process.env.PORT || 3000;
-server.listen(PORT, () => {
- console.log(`服务器运行在端口 ${PORT}`);
- console.log(`访问 http://localhost:${PORT} 开始使用`);
-});
\ No newline at end of file
+server.listen(PORT, async () => {
+ console.log(`服务器运行在端口 ${PORT}`);
+ await initializeServer();
+});
+
+// 导出消息历史管理器供其他模块使用
+module.exports = { messageHistory };
+console.log(`访问 http://localhost:${PORT} 开始使用`);
\ No newline at end of file
diff --git a/src/chat_with_audio.js b/src/chat_with_audio.js
index 6a0e6f8..4e32fdf 100644
--- a/src/chat_with_audio.js
+++ b/src/chat_with_audio.js
@@ -10,82 +10,183 @@ let isPlaying = false;
let audioQueue = [];
let isProcessingQueue = false;
-async function chatWithAudioStream(userInput) {
- // 验证配置
- if (!validateConfig()) {
- throw new Error('配置不完整,请检查config.js文件中的API密钥设置');
- }
-
- console.log('用户输入:', userInput);
-
- // 获取配置
- const llmConfig = getLLMConfig();
- const minimaxiConfig = getMinimaxiConfig();
- const audioConfig = getAudioConfig();
-
- // 清空音频队列
- audioQueue = [];
-
- // 定义段落处理函数
- const handleSegment = async (segment) => {
- console.log('\n=== 处理文本段落 ===');
- console.log('段落内容:', segment);
+// 历史消息缓存
+let historyMessage = [];
+let isInitialized = false;
+
+// 初始化历史消息
+async function initializeHistoryMessage(recentCount = 5) {
+ if (isInitialized) return historyMessage;
try {
- // 为每个段落生成音频
- const audioResult = await requestMinimaxi({
- apiKey: minimaxiConfig.apiKey,
- groupId: minimaxiConfig.groupId,
- body: {
- model: audioConfig.model,
- text: segment,
- stream: audioConfig.stream,
- language_boost: audioConfig.language_boost,
- output_format: audioConfig.output_format,
- voice_setting: audioConfig.voiceSetting,
- audio_setting: audioConfig.audioSetting,
- },
- stream: true,
- });
-
- // 将音频添加到播放队列
- if (audioResult && audioResult.data && audioResult.data.audio) {
- audioQueue.push({
- text: segment,
- audioHex: audioResult.data.audio
- });
- console.log('音频已添加到队列,队列长度:', audioQueue.length);
-
- // 开始处理队列
- processAudioQueue();
- }
+ const response = await fetch(`/api/messages/for-llm?includeSystem=true&recentCount=${recentCount}`);
+ if (!response.ok) {
+ throw new Error('获取历史消息失败');
+ }
+ const data = await response.json();
+ historyMessage = data.messages || [];
+ isInitialized = true;
+ console.log("历史消息初始化完成:", historyMessage.length, "条消息");
+ return historyMessage;
} catch (error) {
- console.error('生成音频失败:', error);
+ console.error('获取历史消息失败,使用默认格式:', error);
+ historyMessage = [
+ { role: 'system', content: 'You are a helpful assistant.' }
+ ];
+ isInitialized = true;
+ return historyMessage;
}
- };
-
- // 1. 请求大模型回答,并实时处理段落
- console.log('\n=== 请求大模型回答 ===');
- const llmResponse = await requestLLMStream({
- apiKey: llmConfig.apiKey,
- model: llmConfig.model,
- messages: [
- { role: 'system', content: 'You are a helpful assistant.' },
- { role: 'user', content: userInput },
- ],
- onSegment: handleSegment // 传入段落处理回调
- });
-
- console.log('\n=== 大模型完整回答 ===');
- console.log("llmResponse: ", llmResponse);
-
- return {
- userInput,
- llmResponse,
- audioQueue: audioQueue.map(item => ({ text: item.text, hasAudio: !!item.audioHex }))
- };
}
+// 获取当前历史消息(同步方法)
+function getCurrentHistoryMessage() {
+ if (!isInitialized) {
+ console.warn('历史消息未初始化,返回默认消息');
+ return [{ role: 'system', content: 'You are a helpful assistant.' }];
+ }
+ return [...historyMessage]; // 返回副本,避免外部修改
+}
+
+// 更新历史消息
+function updateHistoryMessage(userInput, assistantResponse) {
+ if (!isInitialized) {
+ console.warn('历史消息未初始化,无法更新');
+ return;
+ }
+
+ historyMessage.push(
+ { role: 'user', content: userInput },
+ { role: 'assistant', content: assistantResponse }
+ );
+
+ // 可选:限制历史消息数量,保持最近的对话
+ const maxMessages = 20; // 保留最近10轮对话(20条消息)
+ if (historyMessage.length > maxMessages) {
+ // 保留系统消息和最近的对话
+ const systemMessages = historyMessage.filter(msg => msg.role === 'system');
+ const recentMessages = historyMessage.slice(-maxMessages + systemMessages.length);
+ historyMessage = [...systemMessages, ...recentMessages.filter(msg => msg.role !== 'system')];
+ }
+}
+
+// 保存消息到服务端
+async function saveMessage(userInput, assistantResponse) {
+ try {
+ const response = await fetch('/api/messages/save', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify({
+ userInput,
+ assistantResponse
+ })
+ });
+
+ if (!response.ok) {
+ throw new Error('保存消息失败');
+ }
+
+ console.log('消息已保存到服务端');
+ } catch (error) {
+ console.error('保存消息失败:', error);
+ }
+}
+
+async function chatWithAudioStream(userInput) {
+ // 确保历史消息已初始化
+ if (!isInitialized) {
+ await initializeHistoryMessage();
+ }
+
+ // 验证配置
+ if (!validateConfig()) {
+ throw new Error('配置不完整,请检查config.js文件中的API密钥设置');
+ }
+
+ console.log('用户输入:', userInput);
+
+ // 获取配置
+ const llmConfig = getLLMConfig();
+ const minimaxiConfig = getMinimaxiConfig();
+ const audioConfig = getAudioConfig();
+
+ // 清空音频队列
+ audioQueue = [];
+
+ // 定义段落处理函数
+ const handleSegment = async (segment) => {
+ console.log('\n=== 处理文本段落 ===');
+ console.log('段落内容:', segment);
+
+ try {
+ // 为每个段落生成音频
+ const audioResult = await requestMinimaxi({
+ apiKey: minimaxiConfig.apiKey,
+ groupId: minimaxiConfig.groupId,
+ body: {
+ model: audioConfig.model,
+ text: segment,
+ stream: audioConfig.stream,
+ language_boost: audioConfig.language_boost,
+ output_format: audioConfig.output_format,
+ voice_setting: audioConfig.voiceSetting,
+ audio_setting: audioConfig.audioSetting,
+ },
+ stream: true,
+ });
+
+ // 将音频添加到播放队列
+ if (audioResult && audioResult.data && audioResult.data.audio) {
+ audioQueue.push({
+ text: segment,
+ audioHex: audioResult.data.audio
+ });
+ console.log('音频已添加到队列,队列长度:', audioQueue.length);
+
+ // 开始处理队列
+ processAudioQueue();
+ }
+ } catch (error) {
+ console.error('生成音频失败:', error);
+ }
+ };
+
+ // 1. 获取包含历史的消息列表
+ console.log('\n=== 获取历史消息 ===');
+ const messages = getCurrentHistoryMessage();
+ messages.push({role: 'user', content: userInput});
+ console.log('发送的消息数量:', messages);
+
+ // 2. 请求大模型回答
+ console.log('\n=== 请求大模型回答 ===');
+ const llmResponse = await requestLLMStream({
+ apiKey: llmConfig.apiKey,
+ model: llmConfig.model,
+ messages: messages,
+ onSegment: handleSegment
+ });
+
+ console.log('\n=== 大模型完整回答 ===');
+ console.log("llmResponse: ", llmResponse);
+
+ // 3. 保存对话到服务端
+ await saveMessage(userInput, llmResponse);
+
+ // 4. 更新本地历史消息
+ updateHistoryMessage(userInput, llmResponse);
+ console.log('历史消息数量:', historyMessage.length);
+
+ return {
+ userInput,
+ llmResponse,
+ audioQueue: audioQueue.map(item => ({ text: item.text, hasAudio: !!item.audioHex }))
+ };
+}
+
+// 导出初始化函数,供外部调用
+export { chatWithAudioStream, initializeHistoryMessage, getCurrentHistoryMessage };
+
// 处理音频播放队列
async function processAudioQueue() {
if (isProcessingQueue) return;
@@ -209,4 +310,4 @@ async function playAudioStreamNode(audioHex) {
-export { chatWithAudioStream, playAudioStream, playAudioStreamNode};
\ No newline at end of file
+// export { chatWithAudioStream, playAudioStream, playAudioStreamNode, initializeHistoryMessage, getCurrentHistoryMessage };
\ No newline at end of file
diff --git a/src/index.html b/src/index.html
index c729b17..86323ab 100644
--- a/src/index.html
+++ b/src/index.html
@@ -77,6 +77,6 @@
-
+