/** * Func 标签:ocr-chat * * 约定:src/pages/processing/func/ 目录下每个文件名就是一个"可用标签/能力"。 * 本文件用于声明该标签存在(供文档/提示词/后续动态加载使用)。 * * 运行时真实执行逻辑由 ActionParser + electronAPI.extractChatHistory + main-js/func/ocr-chat.js 实现。 */ const electronAPI = require('../../node-api.js') const tagName = 'ocr-chat' const schema = { description: '根据图片识别对话内容,区分好友和自己的对话,输出JSON字符串格式的消息记录。', inputs: { // 按用户要求:抽象为 avatar1/avatar2,不绑定 friend/me 语义 avatar1: '参与者1的头像/标识图片路径(相对于工作流目录)', avatar2: '参与者2的头像/标识图片路径(相对于工作流目录)', variable: '输出变量名(保存JSON字符串格式的消息记录)', }, outputs: { variable: 'JSON字符串格式的消息记录(数组,每个元素包含 sender 和 text 字段)', }, }; /** * 执行 ocr-chat 功能 * 这个函数会被 ActionParser 调用 * * @param {Object} params - 参数对象 * @param {string} params.device - 设备 ID/IP:Port * @param {string} params.avatar1 - 参与者1的头像路径 * @param {string} params.avatar2 - 参与者2的头像路径 * @param {string} params.folderPath - 工作流文件夹路径 * @param {Object} params.region - 识别区域(可选,包含四个顶点坐标的 corners 对象) * @param {string} params.friendRgb - 好友对话框RGB颜色(格式:"(r,g,b)") * @param {string} params.myRgb - 我的对话框RGB颜色(格式:"(r,g,b)") * @returns {Promise<{success: boolean, messagesJson?: string, messages?: Array, error?: string}>} */ async function executeOcrChat({ device, avatar1, avatar2, folderPath, region = null, friendRgb = null, myRgb = null }) { try { if (!electronAPI.extractChatHistory) { return { success: false, error: 'extractChatHistory API 不可用' }; } // 调用主进程的 extractChatHistory 函数 const result = await electronAPI.extractChatHistory( device, avatar1, avatar2, folderPath, region, // 传递区域参数 friendRgb, // 传递好友RGB myRgb // 传递我的RGB ); if (!result.success) { return { success: false, error: result.error }; } // 获取消息数组 let messages = []; if (result.messages && Array.isArray(result.messages)) { messages = result.messages; } else if (result.messagesText) { // 如果只有文本,尝试解析(向后兼容) const lines = result.messagesText.split('\n').filter(line => line.trim()); for (const line of lines) { 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 }); } } } // 将消息数组转换为 chat-history.txt 格式的字符串 // 格式:{"data":"时间戳","friend":"消息","me":"消息"} // 每个消息前都有一个时间戳(同一时间识别的消息使用相同时间戳) const formattedLines = []; formattedLines.push('{'); // 获取当前时间戳(格式:昨天 HH:MM 或 今天 HH:MM) const now = new Date(); const today = new Date(now.getFullYear(), now.getMonth(), now.getDate()); const yesterday = new Date(today); yesterday.setDate(yesterday.getDate() - 1); let timeLabel = ''; const hour = now.getHours(); const minute = now.getMinutes(); if (now >= today) { timeLabel = `今天 ${String(hour).padStart(2, '0')}:${String(minute).padStart(2, '0')}`; } else if (now >= yesterday) { timeLabel = `昨天 ${String(hour).padStart(2, '0')}:${String(minute).padStart(2, '0')}`; } else { timeLabel = `${now.getFullYear()}/${now.getMonth() + 1}/${now.getDate()} ${String(hour).padStart(2, '0')}:${String(minute).padStart(2, '0')}`; } // 添加消息(按顺序),每个消息前添加时间戳 let entryIndex = 0; for (let i = 0; i < messages.length; i++) { const msg = messages[i]; const sender = msg.sender || msg.role || ''; const text = (msg.text || msg.message || '').trim(); if (text && (sender === 'friend' || sender === 'me')) { // 每个消息前添加时间戳 formattedLines.push(`\t"data":${JSON.stringify(timeLabel)},`); formattedLines.push(`\t"${sender}":${JSON.stringify(text)}`); // 如果不是最后一条消息,添加逗号 const hasMoreMessages = messages.slice(i + 1).some(m => { const s = m.sender || m.role || ''; const t = (m.text || m.message || '').trim(); return t && (s === 'friend' || s === 'me'); }); if (hasMoreMessages) { formattedLines[formattedLines.length - 1] += ','; } } } formattedLines.push('}'); const chatHistoryFormat = formattedLines.join('\n'); return { success: true, messagesJson: chatHistoryFormat, // 返回 chat-history.txt 格式的字符串 messages: messages // 保留原始消息数组(向后兼容) }; } catch (error) { return { success: false, error: error.message || '提取聊天记录失败' }; } } module.exports = { tagName, schema, executeOcrChat }