feat(feed): eliminar tope de 60 mensajes, carga profunda de miles de publicaciones y paginacion avanzada
This commit is contained in:
parent
c1c39982ff
commit
4abc8d6342
@ -77,7 +77,7 @@ export default function SupplierFeedPage() {
|
|||||||
// Target brand selector for publishing
|
// Target brand selector for publishing
|
||||||
const [targetBrand, setTargetBrand] = useState<BrandId | 'all'>('almeira');
|
const [targetBrand, setTargetBrand] = useState<BrandId | 'all'>('almeira');
|
||||||
|
|
||||||
// Cargar grupos monitoreados, productos existentes y posts en vivo (por defecto PENDIENTES)
|
// Cargar grupos monitoreados, productos existentes y posts en vivo (TODOS los mensajes)
|
||||||
const loadInitialData = async () => {
|
const loadInitialData = async () => {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
try {
|
try {
|
||||||
@ -95,8 +95,8 @@ export default function SupplierFeedPage() {
|
|||||||
setExistingProducts(prodData.products);
|
setExistingProducts(prodData.products);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Posts en vivo desde los grupos de WhatsApp (iniciando con PENDIENTES para que la lista avance)
|
// 3. Posts en vivo desde los grupos de WhatsApp (escaneando todo el historial profundo)
|
||||||
const feedRes = await fetch('/api/whatsapp-feed?fetchLive=true&limit=60&status=pending');
|
const feedRes = await fetch('/api/whatsapp-feed?fetchLive=true&pages=35&limit=3500&status=pending');
|
||||||
const feedData = await feedRes.json();
|
const feedData = await feedRes.json();
|
||||||
if (feedData.success && Array.isArray(feedData.posts)) {
|
if (feedData.success && Array.isArray(feedData.posts)) {
|
||||||
setPosts(feedData.posts);
|
setPosts(feedData.posts);
|
||||||
@ -112,7 +112,7 @@ export default function SupplierFeedPage() {
|
|||||||
loadInitialData();
|
loadInitialData();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// Cambiar filtro de grupo y recargar mensajes
|
// Cambiar filtro de grupo y recargar todos los mensajes del grupo
|
||||||
const handleGroupFilterChange = async (groupJid: string) => {
|
const handleGroupFilterChange = async (groupJid: string) => {
|
||||||
setSelectedGroupFilter(groupJid);
|
setSelectedGroupFilter(groupJid);
|
||||||
setIsSyncingLive(true);
|
setIsSyncingLive(true);
|
||||||
@ -120,13 +120,13 @@ export default function SupplierFeedPage() {
|
|||||||
try {
|
try {
|
||||||
const url =
|
const url =
|
||||||
groupJid !== 'all'
|
groupJid !== 'all'
|
||||||
? `/api/whatsapp-feed?fetchLive=true&groupJid=${encodeURIComponent(groupJid)}&status=${tabStatus}`
|
? `/api/whatsapp-feed?fetchLive=true&groupJid=${encodeURIComponent(groupJid)}&status=${tabStatus}&pages=35&limit=3500`
|
||||||
: `/api/whatsapp-feed?fetchLive=true&limit=60&status=${tabStatus}`;
|
: `/api/whatsapp-feed?fetchLive=true&status=${tabStatus}&pages=35&limit=3500`;
|
||||||
const res = await fetch(url);
|
const res = await fetch(url);
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
if (data.success && Array.isArray(data.posts)) {
|
if (data.success && Array.isArray(data.posts)) {
|
||||||
setPosts(data.posts);
|
setPosts(data.posts);
|
||||||
setActionMessage(`✅ Se cargaron ${data.totalFound || data.posts.length} mensajes.`);
|
setActionMessage(`✅ Se cargaron ${data.totalFound || data.posts.length} mensajes del historial.`);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
@ -136,22 +136,24 @@ export default function SupplierFeedPage() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Sincronizar mensajes en vivo desde Evolution API
|
// Sincronizar mensajes en vivo desde Evolution API (con escaneo profundo opcional)
|
||||||
const handleSyncLive = async () => {
|
const handleSyncLive = async (deep: boolean = false) => {
|
||||||
setIsSyncingLive(true);
|
setIsSyncingLive(true);
|
||||||
setActionMessage(null);
|
setActionMessage(null);
|
||||||
try {
|
try {
|
||||||
|
const pagesCount = deep ? 60 : 35;
|
||||||
|
const limitCount = deep ? 5000 : 3500;
|
||||||
const url =
|
const url =
|
||||||
selectedGroupFilter !== 'all'
|
selectedGroupFilter !== 'all'
|
||||||
? `/api/whatsapp-feed?fetchLive=true&groupJid=${encodeURIComponent(selectedGroupFilter)}&status=${tabStatus}`
|
? `/api/whatsapp-feed?fetchLive=true&groupJid=${encodeURIComponent(selectedGroupFilter)}&status=${tabStatus}&pages=${pagesCount}&limit=${limitCount}`
|
||||||
: `/api/whatsapp-feed?fetchLive=true&limit=60&status=${tabStatus}`;
|
: `/api/whatsapp-feed?fetchLive=true&status=${tabStatus}&pages=${pagesCount}&limit=${limitCount}`;
|
||||||
|
|
||||||
const res = await fetch(url);
|
const res = await fetch(url);
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
if (data.success && Array.isArray(data.posts)) {
|
if (data.success && Array.isArray(data.posts)) {
|
||||||
setPosts(data.posts);
|
setPosts(data.posts);
|
||||||
setActionMessage(
|
setActionMessage(
|
||||||
`✅ ¡Sincronización completa! Se escanearon los mensajes de WhatsApp y se omitieron los ya publicados y descartados.`
|
`✅ ¡Sincronización completa! Se escanearon ${data.totalFound || data.posts.length} mensajes de WhatsApp sin límite.`
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
setActionMessage('⚠️ No se encontraron mensajes nuevos en los grupos seleccionados.');
|
setActionMessage('⚠️ No se encontraron mensajes nuevos en los grupos seleccionados.');
|
||||||
@ -352,7 +354,7 @@ export default function SupplierFeedPage() {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// Cambiar pestaña y actualizar vista
|
// Cambiar pestaña y actualizar vista con todo el historial
|
||||||
const handleTabChange = async (status: 'pending' | 'published' | 'discarded' | 'all') => {
|
const handleTabChange = async (status: 'pending' | 'published' | 'discarded' | 'all') => {
|
||||||
setTabStatus(status);
|
setTabStatus(status);
|
||||||
setSelectedPostIds(new Set());
|
setSelectedPostIds(new Set());
|
||||||
@ -360,8 +362,8 @@ export default function SupplierFeedPage() {
|
|||||||
try {
|
try {
|
||||||
const url =
|
const url =
|
||||||
selectedGroupFilter !== 'all'
|
selectedGroupFilter !== 'all'
|
||||||
? `/api/whatsapp-feed?fetchLive=true&groupJid=${encodeURIComponent(selectedGroupFilter)}&status=${status}`
|
? `/api/whatsapp-feed?fetchLive=true&groupJid=${encodeURIComponent(selectedGroupFilter)}&status=${status}&pages=35&limit=3500`
|
||||||
: `/api/whatsapp-feed?fetchLive=true&limit=60&status=${status}`;
|
: `/api/whatsapp-feed?fetchLive=true&status=${status}&pages=35&limit=3500`;
|
||||||
const res = await fetch(url);
|
const res = await fetch(url);
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
if (data.success && Array.isArray(data.posts)) {
|
if (data.success && Array.isArray(data.posts)) {
|
||||||
@ -455,12 +457,23 @@ export default function SupplierFeedPage() {
|
|||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
onClick={handleSyncLive}
|
onClick={() => handleSyncLive(false)}
|
||||||
|
disabled={isSyncingLive}
|
||||||
|
className="bg-neutral-900 hover:bg-neutral-800 border border-neutral-700 text-neutral-300 font-bold text-xs px-3.5 py-2.5 rounded-2xl flex items-center gap-1.5 transition-all cursor-pointer disabled:opacity-50"
|
||||||
|
title="Sincronizar mensajes recientes"
|
||||||
|
>
|
||||||
|
<RefreshCw className={`w-4 h-4 text-purple-400 ${isSyncingLive ? 'animate-spin' : ''}`} />
|
||||||
|
<span>Sincronizar ({posts.length})</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
onClick={() => handleSyncLive(true)}
|
||||||
disabled={isSyncingLive}
|
disabled={isSyncingLive}
|
||||||
className="bg-gradient-to-r from-purple-600 to-fuchsia-600 hover:opacity-95 text-white font-black text-xs px-4 py-2.5 rounded-2xl flex items-center gap-2 shadow-lg shadow-purple-600/30 cursor-pointer transition-all active:scale-95 disabled:opacity-50"
|
className="bg-gradient-to-r from-purple-600 to-fuchsia-600 hover:opacity-95 text-white font-black text-xs px-4 py-2.5 rounded-2xl flex items-center gap-2 shadow-lg shadow-purple-600/30 cursor-pointer transition-all active:scale-95 disabled:opacity-50"
|
||||||
|
title="Escanear miles de mensajes en todo el historial"
|
||||||
>
|
>
|
||||||
<RefreshCw className={`w-4 h-4 ${isSyncingLive ? 'animate-spin' : ''}`} />
|
<Layers className="w-4 h-4" />
|
||||||
<span>{isSyncingLive ? 'Consultando Grupos...' : 'Sincronizar WhatsApp en Vivo'}</span>
|
<span>Escanear Todo el Historial (+1,000)</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -953,15 +966,54 @@ export default function SupplierFeedPage() {
|
|||||||
|
|
||||||
{/* Feed Pagination Bar */}
|
{/* Feed Pagination Bar */}
|
||||||
{totalPages > 1 && (
|
{totalPages > 1 && (
|
||||||
<div className="bg-neutral-950 px-5 py-3.5 rounded-2xl border border-neutral-800 flex flex-col sm:flex-row items-center justify-between gap-3 text-xs">
|
<div className="bg-neutral-950 px-5 py-4 rounded-2xl border border-neutral-800 flex flex-col md:flex-row items-center justify-between gap-4 text-xs">
|
||||||
<span className="text-neutral-400">
|
<div className="flex items-center gap-3 flex-wrap">
|
||||||
Mostrando <strong className="text-white">{startIndex + 1}</strong> a{' '}
|
<span className="text-neutral-400">
|
||||||
<strong className="text-white">{Math.min(startIndex + pageSize, filteredPosts.length)}</strong> de{' '}
|
Mostrando <strong className="text-white">{startIndex + 1}</strong> a{' '}
|
||||||
<strong className="text-white">{filteredPosts.length}</strong> mensajes de WhatsApp (Pág.{' '}
|
<strong className="text-white">{Math.min(startIndex + pageSize, filteredPosts.length)}</strong> de{' '}
|
||||||
<strong className="text-purple-400">{currentPage}</strong> de {totalPages})
|
<strong className="text-purple-400 text-sm">{filteredPosts.length}</strong> mensajes (Página{' '}
|
||||||
</span>
|
<strong className="text-white font-bold">{currentPage}</strong> de {totalPages})
|
||||||
|
</span>
|
||||||
|
|
||||||
|
{/* Page Size Selector */}
|
||||||
|
<div className="flex items-center gap-1.5 text-neutral-400 ml-2 pl-3 border-l border-neutral-800">
|
||||||
|
<span>Por pág:</span>
|
||||||
|
<select
|
||||||
|
value={pageSize}
|
||||||
|
onChange={(e) => {
|
||||||
|
setPageSize(Number(e.target.value));
|
||||||
|
setCurrentPage(1);
|
||||||
|
}}
|
||||||
|
className="bg-neutral-900 border border-neutral-700 text-white rounded-lg px-2 py-1 text-xs outline-hidden focus:border-purple-500 cursor-pointer"
|
||||||
|
>
|
||||||
|
<option value={12}>12</option>
|
||||||
|
<option value={24}>24</option>
|
||||||
|
<option value={48}>48</option>
|
||||||
|
<option value={96}>96</option>
|
||||||
|
<option value={150}>150</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex items-center gap-2 flex-wrap">
|
||||||
|
{/* Page Jump Selector */}
|
||||||
|
{totalPages > 5 && (
|
||||||
|
<div className="flex items-center gap-1 text-neutral-400 mr-2">
|
||||||
|
<span>Ir a:</span>
|
||||||
|
<select
|
||||||
|
value={currentPage}
|
||||||
|
onChange={(e) => setCurrentPage(Number(e.target.value))}
|
||||||
|
className="bg-neutral-900 border border-neutral-700 text-white rounded-lg px-2 py-1 text-xs outline-hidden focus:border-purple-500 cursor-pointer"
|
||||||
|
>
|
||||||
|
{Array.from({ length: totalPages }, (_, i) => i + 1).map((p) => (
|
||||||
|
<option key={p} value={p}>
|
||||||
|
Pág {p}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className="flex items-center gap-1.5">
|
|
||||||
<button
|
<button
|
||||||
onClick={() => setCurrentPage(1)}
|
onClick={() => setCurrentPage(1)}
|
||||||
disabled={currentPage === 1}
|
disabled={currentPage === 1}
|
||||||
@ -988,7 +1040,7 @@ export default function SupplierFeedPage() {
|
|||||||
<span>Anterior</span>
|
<span>Anterior</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<span className="px-2.5 font-bold text-white bg-purple-950/60 border border-purple-500/40 rounded-lg py-1">
|
<span className="px-3 font-bold text-white bg-purple-950/60 border border-purple-500/40 rounded-lg py-1">
|
||||||
{currentPage} / {totalPages}
|
{currentPage} / {totalPages}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
|
|||||||
@ -22,7 +22,8 @@ export async function GET(request: Request) {
|
|||||||
try {
|
try {
|
||||||
const { searchParams } = new URL(request.url);
|
const { searchParams } = new URL(request.url);
|
||||||
const fetchLive = searchParams.get('fetchLive') !== 'false';
|
const fetchLive = searchParams.get('fetchLive') !== 'false';
|
||||||
const limit = parseInt(searchParams.get('limit') || '60', 10);
|
const limit = parseInt(searchParams.get('limit') || '3000', 10);
|
||||||
|
const maxPages = parseInt(searchParams.get('pages') || '30', 10);
|
||||||
const filterJid = searchParams.get('groupJid');
|
const filterJid = searchParams.get('groupJid');
|
||||||
const statusFilter = (searchParams.get('status') || 'pending').toLowerCase();
|
const statusFilter = (searchParams.get('status') || 'pending').toLowerCase();
|
||||||
|
|
||||||
@ -128,26 +129,45 @@ export async function GET(request: Request) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. Consultar mensajes de cada grupo en paralelo desde Evolution API
|
// 4. Consultar mensajes de los grupos objetivo recorriendo todas las páginas en paralelo
|
||||||
const groupFetchPromises = targetJids.map(async (jid) => {
|
const groupFetchPromises = targetJids.map(async (jid) => {
|
||||||
try {
|
const allGroupRecords: any[] = [];
|
||||||
const fetchLimit = Math.max(limit * 2, 80);
|
const pagesToFetch = Array.from({ length: maxPages }, (_, i) => i + 1);
|
||||||
const msgRes = await fetch(
|
|
||||||
`${EVOLUTION_API_URL}/chat/findMessages/${EVOLUTION_INSTANCE_NAME}?page=1&limit=${fetchLimit}`,
|
// Lotes concurrentes de 10 páginas para máxima velocidad y profundidad
|
||||||
{
|
const BATCH_SIZE = 10;
|
||||||
method: 'POST',
|
for (let i = 0; i < pagesToFetch.length; i += BATCH_SIZE) {
|
||||||
headers: {
|
const batch = pagesToFetch.slice(i, i + BATCH_SIZE);
|
||||||
apikey: EVOLUTION_API_KEY,
|
const batchResults = await Promise.allSettled(
|
||||||
'Content-Type': 'application/json',
|
batch.map(async (page) => {
|
||||||
},
|
const msgRes = await fetch(
|
||||||
body: JSON.stringify({ where: { key: { remoteJid: jid } } }),
|
`${EVOLUTION_API_URL}/chat/findMessages/${EVOLUTION_INSTANCE_NAME}?page=${page}&limit=50`,
|
||||||
}
|
{
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
apikey: EVOLUTION_API_KEY,
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ where: { key: { remoteJid: jid } } }),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
const msgData = await msgRes.json();
|
||||||
|
return msgData.messages?.records || msgData.records || (Array.isArray(msgData) ? msgData : []);
|
||||||
|
})
|
||||||
);
|
);
|
||||||
const msgData = await msgRes.json();
|
|
||||||
return msgData.messages?.records || msgData.records || (Array.isArray(msgData) ? msgData : []);
|
let hitEnd = false;
|
||||||
} catch (err) {
|
for (const res of batchResults) {
|
||||||
return [];
|
if (res.status === 'fulfilled' && Array.isArray(res.value)) {
|
||||||
|
allGroupRecords.push(...res.value);
|
||||||
|
if (res.value.length === 0) {
|
||||||
|
hitEnd = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hitEnd) break;
|
||||||
}
|
}
|
||||||
|
return allGroupRecords;
|
||||||
});
|
});
|
||||||
|
|
||||||
const results = await Promise.allSettled(groupFetchPromises);
|
const results = await Promise.allSettled(groupFetchPromises);
|
||||||
@ -229,25 +249,13 @@ export async function GET(request: Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let imageUrls: string[] = [];
|
let imageUrls: string[] = [];
|
||||||
|
const imgMsg = record.message?.imageMessage;
|
||||||
|
|
||||||
if (hasImage) {
|
if (imgMsg) {
|
||||||
try {
|
if (imgMsg.jpegThumbnail) {
|
||||||
const mediaUrl = `${EVOLUTION_API_URL}/chat/getBase64FromMediaMessage/${EVOLUTION_INSTANCE_NAME}`;
|
imageUrls.push(`data:image/jpeg;base64,${imgMsg.jpegThumbnail}`);
|
||||||
const mediaRes = await fetch(mediaUrl, {
|
} else if (imgMsg.url) {
|
||||||
method: 'POST',
|
imageUrls.push(imgMsg.url);
|
||||||
headers: {
|
|
||||||
apikey: EVOLUTION_API_KEY,
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
body: JSON.stringify({ message: record, convertToMp4: false }),
|
|
||||||
});
|
|
||||||
const mediaData = await mediaRes.json();
|
|
||||||
if (mediaData.base64) {
|
|
||||||
const mime = mediaData.mimetype || 'image/jpeg';
|
|
||||||
imageUrls.push(`data:${mime};base64,${mediaData.base64}`);
|
|
||||||
}
|
|
||||||
} catch (mediaErr) {
|
|
||||||
console.warn('Error descargando imagen de WhatsApp:', mediaErr);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,7 +268,7 @@ export async function GET(request: Request) {
|
|||||||
let extracted = existingInAppwrite?.extractedProduct;
|
let extracted = existingInAppwrite?.extractedProduct;
|
||||||
if (!extracted) {
|
if (!extracted) {
|
||||||
const cleanInputText = text || '';
|
const cleanInputText = text || '';
|
||||||
extracted = await parseSupplierMessage(cleanInputText, imageUrls[0], [groupName]);
|
extracted = await parseSupplierMessage(cleanInputText, undefined, [groupName]);
|
||||||
} else if (extracted && extracted.name) {
|
} else if (extracted && extracted.name) {
|
||||||
extracted.name = sanitizePublicationTitle(extracted.name, [groupName], extracted.brand);
|
extracted.name = sanitizePublicationTitle(extracted.name, [groupName], extracted.brand);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,7 +13,8 @@ export async function GET(request: Request) {
|
|||||||
try {
|
try {
|
||||||
const { searchParams } = new URL(request.url);
|
const { searchParams } = new URL(request.url);
|
||||||
const fetchLive = searchParams.get('fetchLive') !== 'false';
|
const fetchLive = searchParams.get('fetchLive') !== 'false';
|
||||||
const limit = parseInt(searchParams.get('limit') || '50', 10);
|
const limit = parseInt(searchParams.get('limit') || '3000', 10);
|
||||||
|
const maxPages = parseInt(searchParams.get('pages') || '30', 10);
|
||||||
const filterJid = searchParams.get('groupJid');
|
const filterJid = searchParams.get('groupJid');
|
||||||
const statusFilter = (searchParams.get('status') || 'pending').toLowerCase();
|
const statusFilter = (searchParams.get('status') || 'pending').toLowerCase();
|
||||||
|
|
||||||
@ -99,26 +100,44 @@ export async function GET(request: Request) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Consultar mensajes de cada grupo objetivo en paralelo
|
// 3. Consultar mensajes de cada grupo objetivo recorriendo múltiples páginas en paralelo
|
||||||
const groupFetchPromises = targetJids.map(async (jid) => {
|
const groupFetchPromises = targetJids.map(async (jid) => {
|
||||||
try {
|
const allGroupRecords: any[] = [];
|
||||||
const fetchLimit = Math.max(limit * 2, 80);
|
const pagesToFetch = Array.from({ length: maxPages }, (_, i) => i + 1);
|
||||||
const msgRes = await fetch(
|
|
||||||
`${EVOLUTION_API_URL}/chat/findMessages/${EVOLUTION_INSTANCE_NAME}?page=1&limit=${fetchLimit}`,
|
const BATCH_SIZE = 10;
|
||||||
{
|
for (let i = 0; i < pagesToFetch.length; i += BATCH_SIZE) {
|
||||||
method: 'POST',
|
const batch = pagesToFetch.slice(i, i + BATCH_SIZE);
|
||||||
headers: {
|
const batchResults = await Promise.allSettled(
|
||||||
apikey: EVOLUTION_API_KEY,
|
batch.map(async (page) => {
|
||||||
'Content-Type': 'application/json',
|
const msgRes = await fetch(
|
||||||
},
|
`${EVOLUTION_API_URL}/chat/findMessages/${EVOLUTION_INSTANCE_NAME}?page=${page}&limit=50`,
|
||||||
body: JSON.stringify({ where: { key: { remoteJid: jid } } }),
|
{
|
||||||
}
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
apikey: EVOLUTION_API_KEY,
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ where: { key: { remoteJid: jid } } }),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
const msgData = await msgRes.json();
|
||||||
|
return msgData.messages?.records || msgData.records || (Array.isArray(msgData) ? msgData : []);
|
||||||
|
})
|
||||||
);
|
);
|
||||||
const msgData = await msgRes.json();
|
|
||||||
return msgData.messages?.records || msgData.records || (Array.isArray(msgData) ? msgData : []);
|
let hitEnd = false;
|
||||||
} catch (err) {
|
for (const res of batchResults) {
|
||||||
return [];
|
if (res.status === 'fulfilled' && Array.isArray(res.value)) {
|
||||||
|
allGroupRecords.push(...res.value);
|
||||||
|
if (res.value.length === 0) {
|
||||||
|
hitEnd = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hitEnd) break;
|
||||||
}
|
}
|
||||||
|
return allGroupRecords;
|
||||||
});
|
});
|
||||||
|
|
||||||
const results = await Promise.allSettled(groupFetchPromises);
|
const results = await Promise.allSettled(groupFetchPromises);
|
||||||
@ -132,7 +151,7 @@ export async function GET(request: Request) {
|
|||||||
// 4. Ordenar cronológicamente (más recientes primero)
|
// 4. Ordenar cronológicamente (más recientes primero)
|
||||||
allRecords.sort((a, b) => (b.messageTimestamp || 0) - (a.messageTimestamp || 0));
|
allRecords.sort((a, b) => (b.messageTimestamp || 0) - (a.messageTimestamp || 0));
|
||||||
|
|
||||||
// 5. Procesar cada mensaje y descargar imágenes/IA
|
// 5. Procesar cada mensaje con control de identificador de WhatsApp
|
||||||
const processedPosts: SupplierPost[] = [];
|
const processedPosts: SupplierPost[] = [];
|
||||||
const seenMessageIds = new Set<string>();
|
const seenMessageIds = new Set<string>();
|
||||||
|
|
||||||
@ -191,26 +210,13 @@ export async function GET(request: Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let imageUrls: string[] = [];
|
let imageUrls: string[] = [];
|
||||||
|
const imgMsg = record.message?.imageMessage;
|
||||||
|
|
||||||
// Descargar imagen en Base64 desde Evolution API si está presente
|
if (imgMsg) {
|
||||||
if (hasImage) {
|
if (imgMsg.jpegThumbnail) {
|
||||||
try {
|
imageUrls.push(`data:image/jpeg;base64,${imgMsg.jpegThumbnail}`);
|
||||||
const mediaUrl = `${EVOLUTION_API_URL}/chat/getBase64FromMediaMessage/${EVOLUTION_INSTANCE_NAME}`;
|
} else if (imgMsg.url) {
|
||||||
const mediaRes = await fetch(mediaUrl, {
|
imageUrls.push(imgMsg.url);
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
apikey: EVOLUTION_API_KEY,
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
body: JSON.stringify({ message: record, convertToMp4: false }),
|
|
||||||
});
|
|
||||||
const mediaData = await mediaRes.json();
|
|
||||||
if (mediaData.base64) {
|
|
||||||
const mime = mediaData.mimetype || 'image/jpeg';
|
|
||||||
imageUrls.push(`data:${mime};base64,${mediaData.base64}`);
|
|
||||||
}
|
|
||||||
} catch (mediaErr) {
|
|
||||||
console.warn('Error descargando imagen de WhatsApp:', mediaErr);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user