From 67b54d4ad940b836b82210867e586f0b51d6ea44 Mon Sep 17 00:00:00 2001 From: josedario87 Date: Thu, 4 Dec 2025 14:51:09 -0600 Subject: [PATCH] Feat: Sincronizar contactos y grupos, mejorar nombres en MCP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Agregar listeners contacts.upsert y contacts.update - Agregar listeners groups.upsert y groups.update - Guardar contactos del historial en messaging-history.set - Modificar MCP para hacer JOIN con contacts y group_metadata - Ahora los chats muestran nombres reales en lugar de nĂºmeros/IDs --- server/services/baileys/manager.ts | 135 +++++++++++++++++++++++++++++ server/utils/mcp.ts | 71 ++++++++++----- 2 files changed, 185 insertions(+), 21 deletions(-) diff --git a/server/services/baileys/manager.ts b/server/services/baileys/manager.ts index cb26776..ce3404f 100644 --- a/server/services/baileys/manager.ts +++ b/server/services/baileys/manager.ts @@ -407,6 +407,121 @@ class BaileysManager extends EventEmitter { } }) + // Contacts upsert - save/update contacts + socket.ev.on('contacts.upsert', async (contacts) => { + console.log(`[BaileysManager] contacts.upsert: ${contacts.length} contacts`) + for (const contact of contacts) { + try { + await query( + `INSERT INTO contacts (instance_id, jid, name, push_name) + VALUES ($1, $2, $3, $4) + ON CONFLICT (instance_id, jid) DO UPDATE SET + name = COALESCE(NULLIF(EXCLUDED.name, ''), contacts.name), + push_name = COALESCE(NULLIF(EXCLUDED.push_name, ''), contacts.push_name), + updated_at = NOW()`, + [instanceId, contact.id, contact.name || null, contact.notify || null] + ) + } catch (err) { + console.error(`[BaileysManager] Error saving contact:`, err) + } + } + }) + + // Contacts update - partial updates + socket.ev.on('contacts.update', async (updates) => { + console.log(`[BaileysManager] contacts.update: ${updates.length} updates`) + for (const update of updates) { + try { + const fields: string[] = [] + const values: any[] = [instanceId, update.id] + let paramIndex = 3 + + if (update.name !== undefined) { + fields.push(`name = $${paramIndex}`) + values.push(update.name) + paramIndex++ + } + if (update.notify !== undefined) { + fields.push(`push_name = $${paramIndex}`) + values.push(update.notify) + paramIndex++ + } + + if (fields.length > 0) { + fields.push('updated_at = NOW()') + await query( + `UPDATE contacts SET ${fields.join(', ')} WHERE instance_id = $1 AND jid = $2`, + values + ) + } + } catch (err) { + console.error(`[BaileysManager] Error updating contact:`, err) + } + } + }) + + // Groups upsert - save/update group metadata + socket.ev.on('groups.upsert', async (groups) => { + console.log(`[BaileysManager] groups.upsert: ${groups.length} groups`) + for (const group of groups) { + try { + await query( + `INSERT INTO group_metadata (instance_id, jid, subject, description, owner_jid, participants) + VALUES ($1, $2, $3, $4, $5, $6) + ON CONFLICT (instance_id, jid) DO UPDATE SET + subject = COALESCE(NULLIF(EXCLUDED.subject, ''), group_metadata.subject), + description = COALESCE(EXCLUDED.description, group_metadata.description), + owner_jid = COALESCE(EXCLUDED.owner_jid, group_metadata.owner_jid), + participants = COALESCE(EXCLUDED.participants, group_metadata.participants), + updated_at = NOW()`, + [ + instanceId, + group.id, + group.subject || null, + group.desc || null, + group.owner || null, + JSON.stringify(group.participants || []) + ] + ) + } catch (err) { + console.error(`[BaileysManager] Error saving group:`, err) + } + } + }) + + // Groups update - partial updates + socket.ev.on('groups.update', async (updates) => { + console.log(`[BaileysManager] groups.update: ${updates.length} updates`) + for (const update of updates) { + try { + const fields: string[] = [] + const values: any[] = [instanceId, update.id] + let paramIndex = 3 + + if (update.subject !== undefined) { + fields.push(`subject = $${paramIndex}`) + values.push(update.subject) + paramIndex++ + } + if (update.desc !== undefined) { + fields.push(`description = $${paramIndex}`) + values.push(update.desc) + paramIndex++ + } + + if (fields.length > 0) { + fields.push('updated_at = NOW()') + await query( + `UPDATE group_metadata SET ${fields.join(', ')} WHERE instance_id = $1 AND jid = $2`, + values + ) + } + } catch (err) { + console.error(`[BaileysManager] Error updating group:`, err) + } + } + }) + // Message reactions socket.ev.on('messages.reaction', async (reactions) => { for (const reaction of reactions) { @@ -467,6 +582,26 @@ class BaileysManager extends EventEmitter { } } + // Save contacts from history + if (contacts?.length) { + console.log(`[BaileysManager] Saving ${contacts.length} contacts from history`) + for (const contact of contacts) { + try { + await query( + `INSERT INTO contacts (instance_id, jid, name, push_name) + VALUES ($1, $2, $3, $4) + ON CONFLICT (instance_id, jid) DO UPDATE SET + name = COALESCE(NULLIF(EXCLUDED.name, ''), contacts.name), + push_name = COALESCE(NULLIF(EXCLUDED.push_name, ''), contacts.push_name), + updated_at = NOW()`, + [instanceId, contact.id, contact.name || null, contact.notify || null] + ) + } catch (err) { + console.error(`[BaileysManager] Error saving contact from history:`, err) + } + } + } + // Save messages if (messages?.length) { for (const msg of messages) { diff --git a/server/utils/mcp.ts b/server/utils/mcp.ts index ac7bfb4..f0d6a39 100644 --- a/server/utils/mcp.ts +++ b/server/utils/mcp.ts @@ -687,10 +687,17 @@ export async function handleToolCall(toolName: string, args: Record } const result = await query( - `SELECT id, jid, name, is_group, unread_count, last_message_at, last_message_type - FROM chats - WHERE instance_id = $1 - ORDER BY last_message_at DESC NULLS LAST + `SELECT + c.id, c.jid, c.is_group, c.unread_count, c.last_message_at, c.last_message_type, + CASE + WHEN c.is_group THEN COALESCE(gm.subject, c.name, c.jid) + ELSE COALESCE(ct.name, ct.push_name, c.name, SPLIT_PART(c.jid, '@', 1)) + END as name + FROM chats c + LEFT JOIN contacts ct ON c.instance_id = ct.instance_id AND c.jid = ct.jid + LEFT JOIN group_metadata gm ON c.instance_id = gm.instance_id AND c.jid = gm.jid + WHERE c.instance_id = $1 + ORDER BY c.last_message_at DESC NULLS LAST LIMIT $2`, [instanceId, Math.min(limit, 100)] ) @@ -717,9 +724,17 @@ export async function handleToolCall(toolName: string, args: Record } const result = await query( - `SELECT id, jid, name, is_group, unread_count, last_message_at, last_message_type - FROM chats - WHERE id = $1 AND instance_id = $2`, + `SELECT + c.id, c.jid, c.is_group, c.unread_count, c.last_message_at, c.last_message_type, + CASE + WHEN c.is_group THEN COALESCE(gm.subject, c.name, c.jid) + ELSE COALESCE(ct.name, ct.push_name, c.name, SPLIT_PART(c.jid, '@', 1)) + END as name, + gm.participants as group_participants + FROM chats c + LEFT JOIN contacts ct ON c.instance_id = ct.instance_id AND c.jid = ct.jid + LEFT JOIN group_metadata gm ON c.instance_id = gm.instance_id AND c.jid = gm.jid + WHERE c.id = $1 AND c.instance_id = $2`, [chatId, instanceId] ) @@ -728,17 +743,24 @@ export async function handleToolCall(toolName: string, args: Record } const chat = result.rows[0] + const response: any = { + id: chat.id, + jid: chat.jid, + name: chat.name, + isGroup: chat.is_group, + unreadCount: chat.unread_count || 0, + lastMessageAt: chat.last_message_at, + lastMessageType: chat.last_message_type + } + + // Include participants for groups + if (chat.is_group && chat.group_participants) { + response.participants = chat.group_participants + } + return mcpSuccess({ ok: true, - chat: { - id: chat.id, - jid: chat.jid, - name: chat.name, - isGroup: chat.is_group, - unreadCount: chat.unread_count || 0, - lastMessageAt: chat.last_message_at, - lastMessageType: chat.last_message_type - } + chat: response }) } @@ -750,11 +772,18 @@ export async function handleToolCall(toolName: string, args: Record } const result = await query( - `SELECT id, jid, name, is_group, unread_count, last_message_at - FROM chats - WHERE instance_id = $1 - AND (name ILIKE $2 OR jid ILIKE $2) - ORDER BY last_message_at DESC NULLS LAST + `SELECT + c.id, c.jid, c.is_group, c.unread_count, c.last_message_at, + CASE + WHEN c.is_group THEN COALESCE(gm.subject, c.name, c.jid) + ELSE COALESCE(ct.name, ct.push_name, c.name, SPLIT_PART(c.jid, '@', 1)) + END as name + FROM chats c + LEFT JOIN contacts ct ON c.instance_id = ct.instance_id AND c.jid = ct.jid + LEFT JOIN group_metadata gm ON c.instance_id = gm.instance_id AND c.jid = gm.jid + WHERE c.instance_id = $1 + AND (c.name ILIKE $2 OR c.jid ILIKE $2 OR ct.name ILIKE $2 OR ct.push_name ILIKE $2 OR gm.subject ILIKE $2) + ORDER BY c.last_message_at DESC NULLS LAST LIMIT $3`, [instanceId, `%${searchQuery}%`, Math.min(limit, 50)] )