// const aiService = require('./aiService'); // 二期规划:AI 服务暂时禁用 const logs = require('../logProxy'); /** * 智能聊天管理模块 * 负责聊天内容生成、发送策略和效果监控 */ class ChatManager { constructor() { this.chatHistory = new Map(); // 聊天历史记录 this.chatStrategies = new Map(); // 聊天策略配置 this.effectStats = new Map(); // 聊天效果统计 this.initDefaultStrategies(); } /** * 初始化默认聊天策略 */ initDefaultStrategies() { // 初次打招呼策略 this.chatStrategies.set('greeting', { name: '初次打招呼', description: '向HR发送初次打招呼消息', template: 'greeting', timing: 'immediate', retryCount: 1, retryInterval: 300000 // 5分钟 }); // 面试邀约策略 this.chatStrategies.set('interview', { name: '面试邀约', description: '发送面试邀约消息', template: 'interview', timing: 'after_greeting', retryCount: 2, retryInterval: 600000 // 10分钟 }); // 跟进沟通策略 this.chatStrategies.set('followup', { name: '跟进沟通', description: '跟进之前的沟通', template: 'followup', timing: 'after_interview', retryCount: 1, retryInterval: 86400000 // 24小时 }); } /** * 生成聊天内容 * @param {string} sn_code - 设备SN码 * @param {object} jobInfo - 岗位信息 * @param {object} resumeInfo - 简历信息 * @param {string} chatType - 聊天类型 * @param {object} context - 聊天上下文 * @returns {Promise} 聊天内容 */ async generateChatContent(sn_code, jobInfo, resumeInfo, chatType = 'greeting', context = {}) { console.log(`[聊天管理] 开始生成设备 ${sn_code} 的聊天内容,类型: ${chatType}`); // 获取聊天策略 const strategy = this.chatStrategies.get(chatType); if (!strategy) { throw new Error(`未找到聊天类型 ${chatType} 的策略配置`); } // 二期规划:AI 生成聊天内容暂时禁用,使用默认模板 // const chatContent = await aiService.generateChatContent(jobInfo, resumeInfo, chatType); // if (!chatContent.success) { // console.error(`[聊天管理] AI生成聊天内容失败:`, chatContent.error); // throw new Error(chatContent.error); // } console.log(`[聊天管理] AI生成已禁用(二期规划),使用默认聊天模板`); const chatContent = this.generateDefaultChatContent(jobInfo, resumeInfo, chatType); const result = { sn_code: sn_code, jobInfo: jobInfo, chatType: chatType, strategy: strategy, content: chatContent.content, context: context, timestamp: Date.now() }; // 记录聊天历史 this.recordChatHistory(sn_code, result); console.log(`[聊天管理] 聊天内容生成成功:`, result); return result; } /** * 发送聊天消息 * @param {string} sn_code - 设备SN码 * @param {object} mqttClient - MQTT客户端 * @param {object} chatData - 聊天数据 * @returns {Promise} 发送结果 */ async sendChatMessage(sn_code, mqttClient, chatData) { console.log(`[聊天管理] 开始发送聊天消息到设备 ${sn_code}`); // 构建发送指令 const sendData = { platform: 'boss', action: 'send_chat_message', data: { jobId: chatData.jobInfo.jobId, companyId: chatData.jobInfo.companyId, message: chatData.content, chatType: chatData.chatType } }; // 发送MQTT指令 const response = await mqttClient.publishAndWait(sn_code, sendData); if (!response || response.code !== 200) { // 更新聊天状态 this.updateChatStatus(sn_code, chatData, 'failed', response); console.error(`[聊天管理] 聊天消息发送失败:`, response); throw new Error(response?.message || '聊天消息发送失败'); } // 更新聊天状态 this.updateChatStatus(sn_code, chatData, 'sent', response); // 记录效果统计 this.recordChatEffect(sn_code, chatData, 'sent'); console.log(`[聊天管理] 聊天消息发送成功:`, response); return response; } /** * 生成面试邀约 * @param {string} sn_code - 设备SN码 * @param {object} jobInfo - 岗位信息 * @param {object} chatHistory - 聊天历史 * @returns {Promise} 面试邀约内容 */ async generateInterviewInvitation(sn_code, jobInfo, chatHistory) { console.log(`[聊天管理] 开始生成设备 ${sn_code} 的面试邀约`); console.log(`[聊天管理] AI生成已禁用(二期规划),使用默认模板`); // 二期规划:AI 生成面试邀约暂时禁用,使用默认模板 // const invitation = await aiService.generateInterviewInvitation(jobInfo, chatHistory); // if (!invitation.success) { // console.error(`[聊天管理] AI生成面试邀约失败:`, invitation.error); // throw new Error(invitation.error); // } const invitation = this.generateDefaultInterviewInvitation(jobInfo); const result = { sn_code: sn_code, jobInfo: jobInfo, chatType: 'interview', content: invitation.content, timestamp: Date.now() }; // 记录聊天历史 this.recordChatHistory(sn_code, result); console.log(`[聊天管理] 面试邀约生成成功:`, result); return result; } /** * 记录聊天历史 * @param {string} sn_code - 设备SN码 * @param {object} chatData - 聊天数据 */ recordChatHistory(sn_code, chatData) { if (!this.chatHistory.has(sn_code)) { this.chatHistory.set(sn_code, []); } const history = this.chatHistory.get(sn_code); history.push({ ...chatData, id: Date.now() + Math.random(), status: 'generated' }); // 限制历史记录数量 if (history.length > 100) { history.splice(0, history.length - 100); } } /** * 更新聊天状态 * @param {string} sn_code - 设备SN码 * @param {object} chatData - 聊天数据 * @param {string} status - 新状态 * @param {object} response - 响应数据 */ updateChatStatus(sn_code, chatData, status, response = {}) { if (!this.chatHistory.has(sn_code)) { return; } const history = this.chatHistory.get(sn_code); const chatRecord = history.find(record => record.timestamp === chatData.timestamp && record.chatType === chatData.chatType ); if (chatRecord) { chatRecord.status = status; chatRecord.response = response; } } /** * 记录聊天效果 * @param {string} sn_code - 设备SN码 * @param {object} chatData - 聊天数据 * @param {string} action - 动作类型 */ recordChatEffect(sn_code, chatData, action) { if (!this.effectStats.has(sn_code)) { this.effectStats.set(sn_code, { totalSent: 0, totalReplied: 0, totalInterview: 0, replyRate: 0, interviewRate: 0, lastUpdate: Date.now() }); } const stats = this.effectStats.get(sn_code); if (action === 'sent') { stats.totalSent++; } else if (action === 'replied') { stats.totalReplied++; } else if (action === 'interview') { stats.totalInterview++; } // 计算比率 if (stats.totalSent > 0) { stats.replyRate = (stats.totalReplied / stats.totalSent * 100).toFixed(2); stats.interviewRate = (stats.totalInterview / stats.totalSent * 100).toFixed(2); } stats.lastUpdate = Date.now(); } /** * 获取聊天历史 * @param {string} sn_code - 设备SN码 * @param {object} filters - 过滤条件 * @returns {Array} 聊天历史 */ getChatHistory(sn_code, filters = {}) { if (!this.chatHistory.has(sn_code)) { return []; } let history = this.chatHistory.get(sn_code); // 应用过滤条件 if (filters.chatType) { history = history.filter(record => record.chatType === filters.chatType); } if (filters.status) { history = history.filter(record => record.status === filters.status); } if (filters.startTime) { history = history.filter(record => record.timestamp >= filters.startTime); } if (filters.endTime) { history = history.filter(record => record.timestamp <= filters.endTime); } // 按时间倒序排列 return history.sort((a, b) => b.timestamp - a.timestamp); } /** * 获取聊天效果统计 * @param {string} sn_code - 设备SN码 * @returns {object} 效果统计 */ getChatEffectStats(sn_code) { if (!this.effectStats.has(sn_code)) { return { totalSent: 0, totalReplied: 0, totalInterview: 0, replyRate: 0, interviewRate: 0, lastUpdate: Date.now() }; } return this.effectStats.get(sn_code); } /** * 设置聊天策略 * @param {string} chatType - 聊天类型 * @param {object} strategy - 策略配置 */ setChatStrategy(chatType, strategy) { this.chatStrategies.set(chatType, { ...this.chatStrategies.get(chatType), ...strategy }); console.log(`[聊天管理] 更新聊天策略 ${chatType}:`, strategy); } /** * 清理过期数据 */ cleanup() { const now = Date.now(); const expireTime = 30 * 24 * 3600000; // 30天 // 清理过期的聊天历史 for (const [sn_code, history] of this.chatHistory.entries()) { const filteredHistory = history.filter(record => now - record.timestamp < expireTime ); if (filteredHistory.length === 0) { this.chatHistory.delete(sn_code); } else { this.chatHistory.set(sn_code, filteredHistory); } } // 清理过期的效果统计 for (const [sn_code, stats] of this.effectStats.entries()) { if (now - stats.lastUpdate > expireTime) { this.effectStats.delete(sn_code); } } console.log(`[聊天管理] 数据清理完成`); } /** * 生成默认聊天内容(替代 AI 生成) * @param {object} jobInfo - 岗位信息 * @param {object} resumeInfo - 简历信息 * @param {string} chatType - 聊天类型 * @returns {object} 聊天内容 */ generateDefaultChatContent(jobInfo, resumeInfo, chatType) { const templates = { greeting: '您好,我对这个岗位很感兴趣,希望能进一步了解。', interview: '感谢您的回复,我很期待与您进一步沟通。', followup: '您好,想了解一下这个岗位的最新进展。' }; const content = templates[chatType] || templates.greeting; return { success: true, content: content, chatType: chatType }; } /** * 生成默认面试邀约(替代 AI 生成) * @param {object} jobInfo - 岗位信息 * @returns {object} 面试邀约内容 */ generateDefaultInterviewInvitation(jobInfo) { return { success: true, content: '感谢您的邀请,我很期待与您面谈。请问方便的时间是什么时候?', jobTitle: jobInfo.jobTitle || '该岗位', companyName: jobInfo.companyName || '贵公司' }; } /** * 获取聊天列表 * @param {string} sn_code - 设备SN码 * @param {object} mqttClient - MQTT客户端 * @param {object} params - 参数 * @returns {Promise} 聊天列表 */ async get_chat_list(sn_code, mqttClient, params = {}) { const { platform = 'boss', pageCount = 3 } = params; console.log(`[聊天管理] 开始获取设备 ${sn_code} 的聊天列表`); // 通过MQTT指令获取聊天列表 const response = await mqttClient.publishAndWait(sn_code, { platform, action: "get_chat_list", data: { pageCount } }); if (!response || response.code !== 200) { console.error(`[聊天管理] 获取聊天列表失败:`, response); throw new Error('获取聊天列表失败'); } console.log(`[聊天管理] 成功获取聊天列表`); return response.data; } } module.exports = new ChatManager();