1
This commit is contained in:
@@ -7,13 +7,24 @@ const ai_service = require('../../../services/ai_service');
|
||||
class ChatManager {
|
||||
/**
|
||||
* 解析沟通列表返回值,统一为 { friendList, foldText, ... }
|
||||
* 设备端可能返回 code:0 + zpData 或 code:200 + data
|
||||
* 只支持新的结构:
|
||||
* response.data = { success, apiData: [ { response: { code, zpData:{...} } } ] }
|
||||
* @private
|
||||
*/
|
||||
_parse_chat_list_response(response) {
|
||||
if (!response) return null;
|
||||
const raw = response.zpData != null ? response.zpData : response.data;
|
||||
if (!raw) return { friendList: [], foldText: '', filterEncryptIdList: [], filterBossIdList: [] };
|
||||
const outerData = response && response.data;
|
||||
if (!outerData || !Array.isArray(outerData.apiData) || outerData.apiData.length === 0) {
|
||||
return { friendList: [], foldText: '', filterEncryptIdList: [], filterBossIdList: [] };
|
||||
}
|
||||
|
||||
const firstApi = outerData.apiData[0] || {};
|
||||
const innerResp = firstApi.response || firstApi.data || null;
|
||||
const raw = innerResp && (innerResp.zpData != null ? innerResp.zpData : innerResp.data);
|
||||
|
||||
if (!raw) {
|
||||
return { friendList: [], foldText: '', filterEncryptIdList: [], filterBossIdList: [] };
|
||||
}
|
||||
|
||||
return {
|
||||
friendList: Array.isArray(raw.friendList) ? raw.friendList : [],
|
||||
foldText: raw.foldText || '',
|
||||
@@ -41,14 +52,19 @@ class ChatManager {
|
||||
data: { pageCount }
|
||||
});
|
||||
|
||||
// 沟通列表接口成功为 code: 0 或 code: 200
|
||||
const ok = response && (response.code === 0 || response.code === 200);
|
||||
// 只认新结构:data.success === true
|
||||
const ok = !!response && response.data && response.data.success === true;
|
||||
if (!ok) {
|
||||
console.error(`[聊天管理] 获取聊天列表失败:`, response);
|
||||
throw new Error(response?.message || '获取聊天列表失败');
|
||||
}
|
||||
|
||||
const parsed = this._parse_chat_list_response(response);
|
||||
|
||||
|
||||
// 存储数据库
|
||||
|
||||
|
||||
console.log(`[聊天管理] 成功获取聊天列表,共 ${parsed.friendList.length} 个联系人`);
|
||||
return parsed;
|
||||
}
|
||||
@@ -162,37 +178,20 @@ class ChatManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用 AI 自动决定是否回复,并发送回复
|
||||
* 流程:
|
||||
* 1. 根据参数获取沟通详情(消息列表)
|
||||
* 2. 如果最后一句是 HR 说的,则调用阿里云 Qwen 生成回复文案
|
||||
* 3. 通过 send_chat_message 把回复发出去
|
||||
* 根据沟通详情(get_chat_detail 的解析结果)判断是否需回复,并用 AI 生成回复文案
|
||||
* 供任务层在「获取详情」指令执行后调用,不包含发送消息(由任务层再下发 send_chat_message 指令)
|
||||
*
|
||||
* @param {string} sn_code - 设备SN码
|
||||
* @param {object} mqttClient - MQTT客户端
|
||||
* @param {object} params - 包含 friendId + 获取详情所需参数(如 encryptBossId/encryptJobId 等)
|
||||
* @returns {Promise<object>} { replied, reply_content?, hr_message_text?, reason? }
|
||||
* @param {object} detail - 沟通详情,含 variant、messages、job 等
|
||||
* @returns {Promise<object>} { replied: true, reply_content, hr_message_text } | { replied: false, reason }
|
||||
*/
|
||||
async auto_reply_with_ai(sn_code, mqttClient, params = {}) {
|
||||
const { friendId, platform = 'boss', ...detailParams } = params;
|
||||
|
||||
if (!friendId) {
|
||||
throw new Error('friendId 不能为空');
|
||||
}
|
||||
|
||||
// 1. 获取沟通详情(期望拿到消息列表)
|
||||
const detail = await this.get_chat_detail(sn_code, mqttClient, {
|
||||
platform,
|
||||
...detailParams
|
||||
});
|
||||
|
||||
async getReplyContentFromDetail(detail) {
|
||||
if (!detail || detail.variant !== 'messages' || !Array.isArray(detail.messages) || detail.messages.length === 0) {
|
||||
return { replied: false, reason: '无可用消息' };
|
||||
}
|
||||
|
||||
const messages = detail.messages;
|
||||
|
||||
// 2. 推断 HR 与 求职者 uid
|
||||
// 推断 HR 与 求职者 uid
|
||||
let hr_uid = null;
|
||||
let geek_uid = null;
|
||||
|
||||
@@ -249,14 +248,6 @@ class ChatManager {
|
||||
return { replied: false, reason: 'AI 未生成有效回复' };
|
||||
}
|
||||
|
||||
// 4. 通过统一的 send_chat_message 下发回复
|
||||
await this.send_chat_message(sn_code, mqttClient, {
|
||||
friendId,
|
||||
messages: [{ type: 'text', content: reply_content }],
|
||||
chatType: 'reply',
|
||||
platform
|
||||
});
|
||||
|
||||
return {
|
||||
replied: true,
|
||||
reply_content,
|
||||
@@ -265,78 +256,32 @@ class ChatManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动获取沟通列表 + 按会话自动 AI 回复
|
||||
* 1. 调用 get_chat_list 获取会话列表
|
||||
* 2. 对每个会话按 friendId 调用 auto_reply_with_ai(内部会先获取详情,再决定是否回复)
|
||||
* 使用 AI 自动决定是否回复,并发送回复(内部会先获取详情,再调用 getReplyContentFromDetail,再发送)
|
||||
* 单条指令场景用;任务 auto_chat 已改为下发 get_chat_list / get_chat_detail / send_chat_message 多条指令。
|
||||
*
|
||||
* @param {string} sn_code - 设备SN码
|
||||
* @param {object} mqttClient - MQTT客户端
|
||||
* @param {object} params - { platform?, pageCount? }
|
||||
* @returns {Promise<object>} { success, total_contacts, replied_count, details: [...] }
|
||||
* @param {object} params - 包含 friendId + 获取详情所需参数
|
||||
* @returns {Promise<object>} { replied, reply_content?, hr_message_text?, reason? }
|
||||
*/
|
||||
async auto_chat_ai(sn_code, mqttClient, params = {}) {
|
||||
const { platform = 'boss', pageCount = 3 } = params;
|
||||
async auto_reply_with_ai(sn_code, mqttClient, params = {}) {
|
||||
const { friendId, platform = 'boss', ...detailParams } = params;
|
||||
if (!friendId) throw new Error('friendId 不能为空');
|
||||
|
||||
// 1. 获取沟通列表
|
||||
const listResult = await this.get_chat_list(sn_code, mqttClient, {
|
||||
platform,
|
||||
pageCount
|
||||
const detail = await this.get_chat_detail(sn_code, mqttClient, { platform, ...detailParams });
|
||||
const decision = await this.getReplyContentFromDetail(detail);
|
||||
if (!decision.replied) return decision;
|
||||
|
||||
await this.send_chat_message(sn_code, mqttClient, {
|
||||
friendId,
|
||||
messages: [{ type: 'text', content: decision.reply_content }],
|
||||
chatType: 'reply',
|
||||
platform
|
||||
});
|
||||
|
||||
const friendList = Array.isArray(listResult.friendList) ? listResult.friendList : [];
|
||||
|
||||
if (friendList.length === 0) {
|
||||
return {
|
||||
success: true,
|
||||
total_contacts: 0,
|
||||
replied_count: 0,
|
||||
details: [],
|
||||
message: '没有可沟通的会话'
|
||||
};
|
||||
}
|
||||
|
||||
let replied_count = 0;
|
||||
const details = [];
|
||||
|
||||
// 2. 逐个会话顺序处理,避免并发下发指令
|
||||
for (const friend of friendList) {
|
||||
const friendId = friend.friendId;
|
||||
if (!friendId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
const r = await this.auto_reply_with_ai(sn_code, mqttClient, {
|
||||
platform,
|
||||
friendId
|
||||
});
|
||||
|
||||
if (r.replied) {
|
||||
replied_count++;
|
||||
}
|
||||
|
||||
details.push({
|
||||
friendId,
|
||||
replied: !!r.replied,
|
||||
reason: r.reason || null,
|
||||
reply_content: r.reply_content || null
|
||||
});
|
||||
} catch (error) {
|
||||
details.push({
|
||||
friendId,
|
||||
replied: false,
|
||||
reason: error.message || '自动回复失败',
|
||||
reply_content: null
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
total_contacts: friendList.length,
|
||||
replied_count,
|
||||
details,
|
||||
message: '自动获取列表并尝试AI回复完成'
|
||||
replied: true,
|
||||
reply_content: decision.reply_content,
|
||||
hr_message_text: decision.hr_message_text
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -600,16 +600,16 @@ class JobManager {
|
||||
|
||||
|
||||
// 等待 1秒
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
// await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
|
||||
const location = await locationService.getLocationByAddress(addressToParse).catch(error => {
|
||||
console.error(`[工作管理] 获取位置失败:`, error);
|
||||
});
|
||||
// const location = await locationService.getLocationByAddress(addressToParse).catch(error => {
|
||||
// console.error(`[工作管理] 获取位置失败:`, error);
|
||||
// });
|
||||
|
||||
if (location) {
|
||||
jobInfo.latitude = String(location.lat);
|
||||
jobInfo.longitude = String(location.lng);
|
||||
}
|
||||
// if (location) {
|
||||
// jobInfo.latitude = String(location.lat);
|
||||
// jobInfo.longitude = String(location.lng);
|
||||
// }
|
||||
}
|
||||
|
||||
// 检查是否已存在(根据 jobId 和 sn_code)
|
||||
|
||||
Reference in New Issue
Block a user