regresado a la vida el router
All checks were successful
Deploy conversation layer / deploy (push) Successful in 20s
All checks were successful
Deploy conversation layer / deploy (push) Successful in 20s
This commit is contained in:
@@ -6,7 +6,7 @@ dotenv.config();
|
|||||||
export type Handler = string | ((conv: Conversation) => Promise<string>);
|
export type Handler = string | ((conv: Conversation) => Promise<string>);
|
||||||
|
|
||||||
export const chatHandlers: Record<string, Handler> = {
|
export const chatHandlers: Record<string, Handler> = {
|
||||||
'50498554225@c.us': process.env.CONVERSATION_AGENT_URL || 'http://conversation-layer-agent:8001',
|
'50498554225@c.us': process.env.CONVERSATION_AGENT_URL || 'http://localhost:8001',
|
||||||
'120363401804322608@g.us' : 'http://planilla-agent:8012'
|
'120363401804322608@g.us' : 'http://planilla-agent:8012'
|
||||||
// Add other mappings like:
|
// Add other mappings like:
|
||||||
// '50496210031@c.us': 'http://llm-agent:8000'
|
// '50496210031@c.us': 'http://llm-agent:8000'
|
||||||
|
|||||||
@@ -1,84 +1,17 @@
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { WhatsAppMessage, Conversation, Msg, Participant } from '../types';
|
import { WhatsAppMessage, Conversation, Msg, Participant } from '../types';
|
||||||
|
|
||||||
/**
|
|
||||||
* In‑memory cache of conversations indexed by chatId.
|
|
||||||
*/
|
|
||||||
const conversations = new Map<string, Conversation>();
|
const conversations = new Map<string, Conversation>();
|
||||||
|
|
||||||
|
// ──────────────────────────── Helpers ─────────────────────────────
|
||||||
|
|
||||||
|
|
||||||
// ─────────────────────────────────────────────────────── internal helpers ────
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetches *all* messages for a chat using OpenWA and returns them as‑is.
|
|
||||||
*/
|
|
||||||
async function fetchChatMessages(chatId: string, openWaUrl: string): Promise<WhatsAppMessage[]> {
|
async function fetchChatMessages(chatId: string, openWaUrl: string): Promise<WhatsAppMessage[]> {
|
||||||
const { data } = await axios.post(`${openWaUrl}/loadAndGetAllMessagesInChat`, {
|
const { data } = await axios.post(`${openWaUrl}/loadAndGetAllMessagesInChat`, {
|
||||||
args: { chatId, includeMe: true, includeNotifications: true },
|
args: { chatId, includeMe: true, includeNotifications: true },
|
||||||
});
|
});
|
||||||
|
|
||||||
return data?.response ?? data ?? [];
|
return data?.response ?? data ?? [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds a complete {@link Conversation} object from raw WA messages.
|
|
||||||
*/
|
|
||||||
export async function buildConversation(chatId: string, openWaUrl: string): Promise<Conversation> {
|
|
||||||
const raw = await fetchChatMessages(chatId, openWaUrl);
|
|
||||||
const chatMeta = raw[0]?.chat;
|
|
||||||
|
|
||||||
const convo: Conversation = {
|
|
||||||
chatId,
|
|
||||||
title: chatMeta?.formattedTitle ?? chatMeta?.name ?? chatId,
|
|
||||||
isGroup: Boolean(chatMeta?.isGroup),
|
|
||||||
unreadCount: chatMeta?.unreadCount ?? 0,
|
|
||||||
participants: buildParticipants(raw),
|
|
||||||
messages: raw.slice(-100).map(toMsg).sort((a, b) => a.ts - b.ts),
|
|
||||||
createdAt: Date.now(),
|
|
||||||
};
|
|
||||||
|
|
||||||
conversations.set(chatId, convo);
|
|
||||||
return convo;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Collects unique participants from every message (and group metadata if any).
|
|
||||||
*/
|
|
||||||
function buildParticipants(messages: WhatsAppMessage[]): Participant[] {
|
|
||||||
const map = new Map<string, Participant>();
|
|
||||||
|
|
||||||
for (const m of messages) {
|
|
||||||
const s: any = m.sender ?? m.chat?.contact ?? null;
|
|
||||||
if (!s) continue;
|
|
||||||
|
|
||||||
if (!map.has(s.id)) {
|
|
||||||
map.set(s.id, {
|
|
||||||
id: s.id,
|
|
||||||
name: s.pushname || s.name || '',
|
|
||||||
isMe: Boolean(s.isMe),
|
|
||||||
isAdmin: Boolean(s.isAdmin || s.isSuperAdmin),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return [...map.values()];
|
|
||||||
}
|
|
||||||
|
|
||||||
function ensureParticipant(list: Participant[], sender: any): void {
|
|
||||||
if (!sender) return;
|
|
||||||
if (list.some((p) => p.id === sender.id)) return;
|
|
||||||
|
|
||||||
list.push({
|
|
||||||
id: sender.id,
|
|
||||||
name: sender.pushname || sender.name || '',
|
|
||||||
isMe: Boolean(sender.isMe),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Normalises a raw WhatsApp message to the lightweight {@link Msg} format.
|
|
||||||
*/
|
|
||||||
function toMsg(m: WhatsAppMessage): Msg {
|
function toMsg(m: WhatsAppMessage): Msg {
|
||||||
const anyMsg = m as any;
|
const anyMsg = m as any;
|
||||||
return {
|
return {
|
||||||
@@ -88,7 +21,7 @@ function toMsg(m: WhatsAppMessage): Msg {
|
|||||||
ts: anyMsg.timestamp ?? anyMsg.t ?? Date.now(),
|
ts: anyMsg.timestamp ?? anyMsg.t ?? Date.now(),
|
||||||
type: anyMsg.type ?? 'chat',
|
type: anyMsg.type ?? 'chat',
|
||||||
text: anyMsg.text ?? anyMsg.caption ?? anyMsg.body ?? '',
|
text: anyMsg.text ?? anyMsg.caption ?? anyMsg.body ?? '',
|
||||||
mediaUrl: anyMsg.cloudUrl ?? anyMsg.clientUrl ?? undefined,
|
mediaUrl: anyMsg.cloudUrl ?? anyMsg.clientUrl,
|
||||||
mentions: anyMsg.mentionedJidList ?? [],
|
mentions: anyMsg.mentionedJidList ?? [],
|
||||||
meta: {
|
meta: {
|
||||||
ack: anyMsg.ack ?? 0,
|
ack: anyMsg.ack ?? 0,
|
||||||
@@ -98,7 +31,65 @@ function toMsg(m: WhatsAppMessage): Msg {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// ─────────────────────────────────────────────────────────── public API ──────
|
function buildParticipants(messages: WhatsAppMessage[], chat?: any): Participant[] {
|
||||||
|
const map = new Map<string, Participant>();
|
||||||
|
|
||||||
|
if (chat?.contact) {
|
||||||
|
const c = chat.contact;
|
||||||
|
map.set(c.id, {
|
||||||
|
id: c.id,
|
||||||
|
name: c.pushname || c.name || '',
|
||||||
|
isMe: Boolean(c.isMe),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chat?.isGroup && chat.groupMetadata?.participants) {
|
||||||
|
for (const p of chat.groupMetadata.participants as any[]) {
|
||||||
|
const c = p.contact || {};
|
||||||
|
const id = c.id || p.id;
|
||||||
|
map.set(id, {
|
||||||
|
id,
|
||||||
|
name: c.pushname || c.name || '',
|
||||||
|
isMe: Boolean(c.isMe),
|
||||||
|
isAdmin: Boolean(p.isAdmin || p.isSuperAdmin),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const m of messages) {
|
||||||
|
const s = m.sender;
|
||||||
|
if (s && !map.has(s.id)) {
|
||||||
|
map.set(s.id, {
|
||||||
|
id: s.id,
|
||||||
|
name: s.pushname || s.name || '',
|
||||||
|
isMe: Boolean(s.isMe),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [...map.values()];
|
||||||
|
}
|
||||||
|
|
||||||
|
// ──────────────────────────── Public API ─────────────────────────────
|
||||||
|
|
||||||
|
export async function buildConversation(chatId: string, openWaUrl: string): Promise<Conversation> {
|
||||||
|
const raw = await fetchChatMessages(chatId, openWaUrl);
|
||||||
|
const chat = raw[0]?.chat;
|
||||||
|
const now = Date.now();
|
||||||
|
|
||||||
|
const conversation: Conversation = {
|
||||||
|
chatId,
|
||||||
|
title: chat?.formattedTitle ?? chat?.name ?? chatId,
|
||||||
|
isGroup: Boolean(chat?.isGroup),
|
||||||
|
unreadCount: chat?.unreadCount ?? 0,
|
||||||
|
participants: buildParticipants(raw, chat),
|
||||||
|
messages: raw.slice(-20).map(toMsg).sort((a, b) => a.ts - b.ts),
|
||||||
|
createdAt: conversations.get(chatId)?.createdAt || now,
|
||||||
|
};
|
||||||
|
|
||||||
|
conversations.set(chatId, conversation);
|
||||||
|
return conversation;
|
||||||
|
}
|
||||||
|
|
||||||
export async function getConversation(chatId: string, openWaUrl: string): Promise<Conversation> {
|
export async function getConversation(chatId: string, openWaUrl: string): Promise<Conversation> {
|
||||||
let conv = conversations.get(chatId);
|
let conv = conversations.get(chatId);
|
||||||
@@ -116,13 +107,11 @@ export function deleteConversation(chatId: string): boolean {
|
|||||||
|
|
||||||
export async function addMessageToConversation(
|
export async function addMessageToConversation(
|
||||||
chatId: string,
|
chatId: string,
|
||||||
waMsg: WhatsAppMessage,
|
msg: WhatsAppMessage,
|
||||||
openWaUrl: string,
|
openWaUrl: string
|
||||||
): Promise<Conversation> {
|
): Promise<Conversation> {
|
||||||
console.log(`[conversationStore] Adding message to ${chatId}`);
|
|
||||||
const conv = await getConversation(chatId, openWaUrl);
|
const conv = await getConversation(chatId, openWaUrl);
|
||||||
const mapped = mapMessage(msg);
|
const mapped = toMsg(msg);
|
||||||
// avoid duplicates if multiple webhook events deliver the same message
|
|
||||||
if (!conv.messages.some((m) => m.id === mapped.id)) {
|
if (!conv.messages.some((m) => m.id === mapped.id)) {
|
||||||
conv.messages.push(mapped);
|
conv.messages.push(mapped);
|
||||||
if (conv.messages.length > 20) conv.messages.shift();
|
if (conv.messages.length > 20) conv.messages.shift();
|
||||||
@@ -132,7 +121,7 @@ export async function addMessageToConversation(
|
|||||||
conv.participants.push({
|
conv.participants.push({
|
||||||
id: s.id,
|
id: s.id,
|
||||||
name: s.pushname || s.name || '',
|
name: s.pushname || s.name || '',
|
||||||
isMe: s.isMe,
|
isMe: Boolean(s.isMe),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return conv;
|
return conv;
|
||||||
|
|||||||
Reference in New Issue
Block a user