/** * 聊天历史记录管理模块 * 负责保存聊天记录、生成AI总结、读取历史总结、读取所有聊天记录 */ const stub = (name) => ({ success: false, error: `${name} 需在主进程实现` }) const electronAPI = { saveChatHistory: () => stub('saveChatHistory'), readChatHistory: () => stub('readChatHistory'), readAllChatHistory: () => stub('readAllChatHistory'), saveChatHistoryTxt: () => stub('saveChatHistoryTxt'), saveChatHistorySummary: () => stub('saveChatHistorySummary'), getChatHistorySummary: () => stub('getChatHistorySummary'), } /** * 保存聊天记录到 history 文件夹 * @param {string|Array} chatHistory - 聊天记录(可以是JSON字符串、文本格式或消息数组) * @param {string} folderPath - 工作流文件夹路径(相对路径,如 "static/processing/微信聊天自动发送工作流") * @returns {Promise<{success: boolean, error?: string, filePath?: string}>} */ async function saveChatHistory(chatHistory, folderPath) { try { if (!chatHistory) { return { success: false, error: '聊天记录为空' }; } if (!electronAPI.saveChatHistory) { return { success: false, error: '保存聊天记录 API 不可用' }; } // 解析聊天记录,转换为消息数组 let newMessages = []; if (Array.isArray(chatHistory)) { // 如果已经是数组,直接使用 newMessages = chatHistory; } else if (typeof chatHistory === 'string') { // 如果是字符串,尝试解析 // 先检查是否是 chat-history.txt 格式(包含 "data" 和 "friend"/"me" 键) if (chatHistory.includes('"data"') && (chatHistory.includes('"friend"') || chatHistory.includes('"me"'))) { // 是 chat-history.txt 格式 newMessages = parseChatHistoryTxtFormat(chatHistory); } else { // 尝试作为标准JSON字符串解析 try { const parsed = JSON.parse(chatHistory); if (Array.isArray(parsed)) { newMessages = parsed; } else { // 如果不是数组,按文本格式解析 newMessages = parseChatHistoryText(chatHistory); } } catch (e) { // JSON解析失败,按文本格式解析 newMessages = parseChatHistoryText(chatHistory); } } } if (newMessages.length === 0) { return { success: false, error: '聊天记录解析后为空' }; } // 读取历史聊天记录,进行去重 let historyMessages = []; try { if (electronAPI.readChatHistory) { const historyResult = await electronAPI.readChatHistory(folderPath); if (historyResult.success && historyResult.messages && Array.isArray(historyResult.messages)) { historyMessages = historyResult.messages; } } } catch (error) { // 读取历史聊天记录失败,将保存所有新消息 } // 对历史消息构建查找集合(用于去重) const historyMessageMap = new Map(); historyMessages.forEach((msg, index) => { const normalizedText = (msg.text || '').trim(); const key = `${msg.sender || ''}:${normalizedText}`; // 如果同一个 key 已存在,保留索引较小的(更早的消息) if (!historyMessageMap.has(key)) { historyMessageMap.set(key, { index, sender: msg.sender, text: normalizedText }); } }); // 找出真正新的消息(不在历史记录中的) const uniqueNewMessages = []; const duplicateMessages = []; for (const newMsg of newMessages) { const normalizedText = (newMsg.text || '').trim(); const key = `${newMsg.sender || ''}:${normalizedText}`; // 检查是否已存在于历史记录中 if (!historyMessageMap.has(key)) { // 这是新消息 uniqueNewMessages.push(newMsg); } else { // 消息已存在,记录为重复消息 const existingMsg = historyMessageMap.get(key); duplicateMessages.push({ sender: existingMsg.sender, text: normalizedText.substring(0, 50) + (normalizedText.length > 50 ? '...' : '') }); } } if (uniqueNewMessages.length === 0) { // console.log(`没有新消息(所有 ${newMessages.length} 条消息都与历史记录重合),跳过保存`); // if (duplicateMessages.length > 0) { // console.log(`重复消息示例: ${duplicateMessages[0].sender}: ${duplicateMessages[0].text}`); // } return { success: true, skipped: true, reason: 'no_new_messages' }; } // 合并消息:历史消息 + 新的唯一消息 const mergedMessages = [...historyMessages, ...uniqueNewMessages]; // console.log(`将保存 ${uniqueNewMessages.length} 条新消息(已剔除 ${duplicateMessages.length} 条重复消息)`); // if (duplicateMessages.length > 0 && duplicateMessages.length <= 5) { // console.log(`重复消息: ${duplicateMessages.map(m => `${m.sender}: ${m.text}`).join('; ')}`); // } else if (duplicateMessages.length > 5) { // console.log(`重复消息示例: ${duplicateMessages.slice(0, 3).map(m => `${m.sender}: ${m.text}`).join('; ')} ...`); // } // 构建保存的数据结构 const now = new Date(); const historyData = { timestamp: now.toISOString(), messageCount: mergedMessages.length, messages: mergedMessages }; // 通过 IPC 调用主进程保存聊天记录到 chat-history.txt(新格式) // 使用新的 API 保存为 chat-history.txt 格式 if (electronAPI.saveChatHistoryTxt) { const result = await electronAPI.saveChatHistoryTxt(folderPath, uniqueNewMessages); if (!result.success) { return { success: false, error: result.error }; } return { success: true, filePath: result.filePath }; } // 向后兼容:如果没有新API,使用旧API const result = await electronAPI.saveChatHistory(folderPath, historyData); if (!result.success) { return { success: false, error: result.error }; } return { success: true, filePath: result.filePath }; } catch (error) { return { success: false, error: error.message }; } } /** * 生成聊天记录的AI总结 * @param {string} chatHistory - 聊天记录文本 * @param {string} folderPath - 工作流文件夹路径 * @param {string} modelName - AI模型名称(可选,默认 'gpt-5-nano-ca') * @returns {Promise<{success: boolean, error?: string, summary?: string}>} */ async function generateHistorySummary(chatHistory, folderPath, modelName = 'gpt-5-nano-ca') { try { if (!chatHistory || !chatHistory.trim()) { return { success: false, error: '聊天记录为空' }; } // 读取历史总结(如果存在) const existingSummary = await getHistorySummary(folderPath); const summaryContext = existingSummary ? `\n\n之前的总结:\n${existingSummary}` : ''; // 构建AI提示词 const prompt = `请总结以下微信聊天记录的主要内容、话题和氛围。总结要简洁明了,控制在100字以内,帮助理解对话的上下文和情感倾向。 聊天记录: ${chatHistory}${summaryContext} 请直接返回总结内容,不要包含其他说明文字。`; // 调用AI API const response = await fetch('https://ai-anim.com/api/text2textByModel', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ prompt: prompt, modelName: modelName }) }); if (!response.ok) { return { success: false, error: `AI请求失败: ${response.statusText}` }; } const data = await response.json(); const summary = data.data?.output_text || data.text || data.content || ''; if (!summary || !summary.trim()) { return { success: false, error: 'AI返回的总结为空' }; } // 通过 IPC 调用主进程保存总结 if (!electronAPI.saveChatHistorySummary) { return { success: false, error: '保存聊天记录总结 API 不可用' }; } const saveResult = await electronAPI.saveChatHistorySummary(folderPath, summary.trim()); if (!saveResult.success) { return { success: false, error: saveResult.error }; } // console.log(`聊天记录总结已保存`); return { success: true, summary: summary.trim() }; } catch (error) { return { success: false, error: error.message }; } } /** * 读取历史聊天记录的总结 * @param {string} folderPath - 工作流文件夹路径 * @returns {Promise} 返回总结文本,如果不存在则返回空字符串 */ async function getHistorySummary(folderPath) { try { if (!electronAPI.getChatHistorySummary) { return ''; } const result = await electronAPI.getChatHistorySummary(folderPath); if (!result.success) { // 文件不存在是正常情况,返回空字符串 return ''; } return result.summary || ''; } catch (error) { return ''; } } /** * 解析 chat-history.txt 格式的 JSON 字符串为消息数组 * 格式:{"data":"时间戳","friend":"消息","me":"消息"},允许重复键 * @param {string} jsonString - JSON 字符串 * @returns {Array<{sender: string, text: string}>} */ function parseChatHistoryTxtFormat(jsonString) { const messages = []; if (!jsonString || typeof jsonString !== 'string') { return messages; } try { // 由于JSON不支持重复键,我们需要从文本解析每一行 const lines = jsonString.split('\n'); for (const line of lines) { // 匹配格式:\t"key":"value", 或 \t"key":"value" const match = line.match(/^\s*"([^"]+)":\s*"([^"]*)"\s*,?\s*$/); if (match) { const key = match[1]; const value = match[2]; // 只处理 friend 和 me 键,忽略 data 键(时间戳) if (key === 'friend' || key === 'me') { messages.push({ sender: key, text: value }); } } } } catch (e) { // 解析失败,返回空数组 return messages; } return messages; } /** * 解析聊天记录文本为结构化数据 * @param {string} chatHistoryText - 聊天记录文本(格式:好友: xxx\n我: xxx) * @returns {Array<{sender: string, text: string}>} */ function parseChatHistoryText(chatHistoryText) { const messages = []; const lines = chatHistoryText.split('\n').filter(line => line.trim()); for (const line of lines) { // 匹配格式:对方: xxx、好友: xxx 或 我: xxx const match = line.match(/^(对方|好友|我):\s*(.+)$/); if (match) { const senderLabel = match[1]; const sender = (senderLabel === '对方' || senderLabel === '好友') ? 'friend' : 'me'; const text = match[2].trim(); messages.push({ sender, text }); } } return messages; } /** * 读取所有聊天记录(合并所有历史文件) * @param {string} folderPath - 工作流文件夹路径(相对路径,如 "static/processing/微信聊天自动发送工作流") * @returns {Promise<{success: boolean, error?: string, messages?: Array}>} */ async function readAllChatHistory(folderPath) { try { // 优先使用新的 API,如果没有则使用旧的(向后兼容) const api = electronAPI.readChatHistory || electronAPI.readAllChatHistory; if (!api) { return { success: false, error: '读取聊天记录 API 不可用' }; } const result = await api(folderPath); if (!result.success) { return { success: false, error: result.error }; } // console.log(`已读取聊天记录,共 ${result.fileCount || 0} 个文件,${result.totalMessages || 0} 条消息`); return { success: true, messages: result.messages || [], fileCount: result.fileCount || 0, totalMessages: result.totalMessages || 0 }; } catch (error) { return { success: false, error: error.message || '读取聊天记录失败' }; } } module.exports = { saveChatHistory, generateHistorySummary, getHistorySummary, readAllChatHistory }