fix: Rewrite script to intelligently match WhatsApp image texts
This commit is contained in:
parent
f77523519e
commit
75feab0ab1
194
publish-cauca.js
194
publish-cauca.js
@ -1,15 +1,10 @@
|
|||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const axios = require('axios');
|
const axios = require('axios');
|
||||||
const { Client, Databases, Storage, ID } = require('node-appwrite');
|
const { Client, Databases, Storage, ID, Query } = require('node-appwrite');
|
||||||
require('dotenv').config({ path: '.env.local' });
|
require('dotenv').config({ path: '.env.local' });
|
||||||
|
|
||||||
// Let's try to get InputFile if it exists in node-appwrite/file (for older SDKs)
|
|
||||||
let InputFile;
|
let InputFile;
|
||||||
try {
|
try { InputFile = require('node-appwrite/file').InputFile; } catch (e) { InputFile = null; }
|
||||||
InputFile = require('node-appwrite/file').InputFile;
|
|
||||||
} catch (e) {
|
|
||||||
InputFile = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const EVOLUTION_API_URL = process.env.EVOLUTION_API_URL;
|
const EVOLUTION_API_URL = process.env.EVOLUTION_API_URL;
|
||||||
const EVOLUTION_API_KEY = process.env.EVOLUTION_API_KEY;
|
const EVOLUTION_API_KEY = process.env.EVOLUTION_API_KEY;
|
||||||
@ -23,7 +18,6 @@ const client = new Client()
|
|||||||
|
|
||||||
const databases = new Databases(client);
|
const databases = new Databases(client);
|
||||||
const storage = new Storage(client);
|
const storage = new Storage(client);
|
||||||
|
|
||||||
const DB_ID = process.env.APPWRITE_DATABASE_ID;
|
const DB_ID = process.env.APPWRITE_DATABASE_ID;
|
||||||
const BUCKET_ID = process.env.NEXT_PUBLIC_APPWRITE_MEDIA_BUCKET_ID;
|
const BUCKET_ID = process.env.NEXT_PUBLIC_APPWRITE_MEDIA_BUCKET_ID;
|
||||||
|
|
||||||
@ -34,6 +28,12 @@ async function getCollectionIds() {
|
|||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function extractText(msg) {
|
||||||
|
if (msg.messageType === 'conversation') return msg.message.conversation;
|
||||||
|
if (msg.messageType === 'extendedTextMessage') return msg.message.extendedTextMessage?.text;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
async function run() {
|
async function run() {
|
||||||
console.log("Starting publishing process...");
|
console.log("Starting publishing process...");
|
||||||
try {
|
try {
|
||||||
@ -44,12 +44,17 @@ async function run() {
|
|||||||
|
|
||||||
const pubTypes = await databases.listDocuments(DB_ID, pubTypesCollectionId);
|
const pubTypes = await databases.listDocuments(DB_ID, pubTypesCollectionId);
|
||||||
const defaultPubTypeId = pubTypes.documents.length > 0 ? pubTypes.documents[0].$id : null;
|
const defaultPubTypeId = pubTypes.documents.length > 0 ? pubTypes.documents[0].$id : null;
|
||||||
if (!defaultPubTypeId) {
|
|
||||||
console.error("No publication types found. Can't create posts.");
|
// 1. Delete old posts
|
||||||
return;
|
console.log("Deleting old script posts...");
|
||||||
|
const resOld = await databases.listDocuments(DB_ID, postsCollectionId, [Query.limit(500)]);
|
||||||
|
const scriptPosts = resOld.documents.filter(p => p.slug && p.slug.startsWith('gobernacion-cauca-mes-'));
|
||||||
|
for (const p of scriptPosts) {
|
||||||
|
await databases.deleteDocument(DB_ID, postsCollectionId, p.$id);
|
||||||
}
|
}
|
||||||
|
|
||||||
const allImages = [];
|
// 2. Fetch all messages
|
||||||
|
const allRecords = [];
|
||||||
let currentPage = 1;
|
let currentPage = 1;
|
||||||
let totalPages = 1;
|
let totalPages = 1;
|
||||||
|
|
||||||
@ -63,34 +68,63 @@ async function run() {
|
|||||||
|
|
||||||
const messagesObj = response.data.messages || {};
|
const messagesObj = response.data.messages || {};
|
||||||
totalPages = messagesObj.pages || 1;
|
totalPages = messagesObj.pages || 1;
|
||||||
const records = messagesObj.records || [];
|
allRecords.push(...(messagesObj.records || []));
|
||||||
|
|
||||||
for (const msg of records) {
|
|
||||||
if (msg.messageType === 'imageMessage') {
|
|
||||||
allImages.push(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentPage > 40) break;
|
if (currentPage > 40) break;
|
||||||
currentPage++;
|
currentPage++;
|
||||||
} while (currentPage <= totalPages);
|
} while (currentPage <= totalPages);
|
||||||
|
|
||||||
console.log(`Total images found in chat history: ${allImages.length}`);
|
console.log(`Total messages fetched: ${allRecords.length}`);
|
||||||
|
|
||||||
// We need 32 images (8 for March, 8 for April, 8 for May, 8 for June)
|
// 3. Process images and find associated text
|
||||||
// If we don't have enough images, we'll just use as many as we have.
|
const targetMonths = [3, 4, 5, 6];
|
||||||
// We'll distribute them artificially over the months if the actual timestamps are all from June.
|
const monthCounts = { 3:0, 4:0, 5:0, 6:0 };
|
||||||
|
|
||||||
let targetMonths = [3, 4, 5, 6];
|
for (let i = 0; i < allRecords.length; i++) {
|
||||||
let imageIndex = 0;
|
const msg = allRecords[i];
|
||||||
|
if (msg.messageType !== 'imageMessage') continue;
|
||||||
|
|
||||||
for (const month of targetMonths) {
|
const ts = msg.messageTimestamp;
|
||||||
console.log(`\n--- Publishing for Month ${month} ---`);
|
const date = new Date(ts * 1000);
|
||||||
let publishedCount = 0;
|
const month = date.getMonth() + 1;
|
||||||
|
|
||||||
while (publishedCount < 8 && imageIndex < allImages.length) {
|
if (!targetMonths.includes(month)) continue;
|
||||||
const msg = allImages[imageIndex];
|
if (monthCounts[month] >= 8) continue; // max 8 per month
|
||||||
imageIndex++;
|
|
||||||
|
// Find associated text
|
||||||
|
let caption = msg.message?.imageMessage?.caption;
|
||||||
|
|
||||||
|
if (!caption) {
|
||||||
|
// Look backwards and forwards within 10 minutes (600 seconds)
|
||||||
|
let bestText = null;
|
||||||
|
for (let j = Math.max(0, i - 10); j < Math.min(allRecords.length, i + 10); j++) {
|
||||||
|
const nearbyMsg = allRecords[j];
|
||||||
|
if (Math.abs(nearbyMsg.messageTimestamp - ts) > 600) continue;
|
||||||
|
|
||||||
|
const text = extractText(nearbyMsg);
|
||||||
|
if (text && text.length > 20 && !text.toLowerCase().includes("comparte en tus historias")) {
|
||||||
|
bestText = text;
|
||||||
|
// if this text is very close (older), break
|
||||||
|
if (j > i) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (bestText) caption = bestText;
|
||||||
|
}
|
||||||
|
|
||||||
|
let cleanCaption = caption || `Publicación gráfica de la Gobernación del Cauca para el mes de ${month}.`;
|
||||||
|
let title = `Boletín Gobernación - Mes ${month} #${monthCounts[month] + 1}`;
|
||||||
|
|
||||||
|
if (cleanCaption.length > 20) {
|
||||||
|
const lines = cleanCaption.split('\n').map(l => l.trim()).filter(l => l.length > 5);
|
||||||
|
if (lines.length > 0) {
|
||||||
|
title = lines[0];
|
||||||
|
if ((title.toUpperCase() === title || title.includes("GOBERNACIÓN") || title.includes("Boletín")) && lines.length > 1) {
|
||||||
|
title = lines[1];
|
||||||
|
}
|
||||||
|
title = title.replace(/^[\p{Emoji}\s*_*]+/gu, ''); // Remove emojis, stars, underscores
|
||||||
|
if (title.length > 100) title = title.substring(0, 100) + '...';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Get base64
|
// Get base64
|
||||||
@ -104,101 +138,39 @@ async function run() {
|
|||||||
if (!base64Data) continue;
|
if (!base64Data) continue;
|
||||||
|
|
||||||
const buffer = Buffer.from(base64Data, 'base64');
|
const buffer = Buffer.from(base64Data, 'base64');
|
||||||
const filePath = `/tmp/image-${month}-${publishedCount}.jpeg`;
|
const filePath = `/tmp/image-${month}-${monthCounts[month]}.jpeg`;
|
||||||
const filename = `image-${month}-${publishedCount}.jpeg`;
|
|
||||||
fs.writeFileSync(filePath, buffer);
|
fs.writeFileSync(filePath, buffer);
|
||||||
|
|
||||||
// Appwrite File Upload Compatibility
|
|
||||||
let fileParam;
|
let fileParam;
|
||||||
if (InputFile && InputFile.fromPath) {
|
if (InputFile && InputFile.fromPath) fileParam = InputFile.fromPath(filePath, `image.jpeg`);
|
||||||
fileParam = InputFile.fromPath(filePath, filename);
|
else if (InputFile && InputFile.fromBuffer) fileParam = InputFile.fromBuffer(buffer, `image.jpeg`);
|
||||||
} else if (InputFile && InputFile.fromBuffer) {
|
else fileParam = fs.createReadStream(filePath);
|
||||||
fileParam = InputFile.fromBuffer(buffer, filename);
|
|
||||||
} else {
|
|
||||||
// Fallback to node fs read stream (works in some SDKs) or directly passing string path if supported
|
|
||||||
// Appwrite 1.x Node SDK usually accepts a ReadStream
|
|
||||||
fileParam = fs.createReadStream(filePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
const file = await storage.createFile(
|
const file = await storage.createFile(BUCKET_ID, ID.unique(), fileParam);
|
||||||
BUCKET_ID,
|
|
||||||
ID.unique(),
|
|
||||||
fileParam
|
|
||||||
);
|
|
||||||
|
|
||||||
let mediaDoc;
|
const mediaDoc = await databases.createDocument(DB_ID, mediaCollectionId, ID.unique(), {
|
||||||
try {
|
file_id: file.$id, bucket_id: BUCKET_ID,
|
||||||
mediaDoc = await databases.createDocument(
|
titulo: title, tipo: 'imagen'
|
||||||
DB_ID,
|
});
|
||||||
mediaCollectionId,
|
|
||||||
ID.unique(),
|
|
||||||
{
|
|
||||||
file_id: file.$id,
|
|
||||||
bucket_id: BUCKET_ID,
|
|
||||||
titulo: `Pieza Gráfica Gobernación del Cauca - Mes ${month}`,
|
|
||||||
tipo: 'imagen'
|
|
||||||
}
|
|
||||||
);
|
|
||||||
} catch (e) {
|
|
||||||
console.error("Media error:", e.message);
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
|
|
||||||
let caption = msg.message?.imageMessage?.caption || `Pieza gráfica de la Gobernación del Cauca correspondiente al mes ${month}.`;
|
const slug = `gobernacion-cauca-mes-${month}-pub-${monthCounts[month]}-${Date.now()}`;
|
||||||
|
await databases.createDocument(DB_ID, postsCollectionId, ID.unique(), {
|
||||||
let title = `Boletín Gobernación - Mes ${month} #${publishedCount + 1}`;
|
|
||||||
if (caption && caption.length >= 5) {
|
|
||||||
const lines = caption.split('\n').map(l => l.trim()).filter(l => l.length > 5);
|
|
||||||
if (lines.length > 0) {
|
|
||||||
title = lines[0];
|
|
||||||
if ((title.toUpperCase() === title || title.includes("GOBERNACIÓN")) && lines.length > 1) {
|
|
||||||
title = lines[1];
|
|
||||||
}
|
|
||||||
title = title.replace(/^[\p{Emoji}\s]+/gu, '');
|
|
||||||
if (title.length > 100) title = title.substring(0, 100) + '...';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const slug = `gobernacion-cauca-mes-${month}-pub-${publishedCount}-${Date.now()}`;
|
|
||||||
|
|
||||||
const realDate = new Date(msg.messageTimestamp * 1000).toISOString();
|
|
||||||
const cleanCaption = caption || `Publicación gráfica de la Gobernación del Cauca para el mes de ${month}.`;
|
|
||||||
|
|
||||||
try {
|
|
||||||
await databases.createDocument(
|
|
||||||
DB_ID,
|
|
||||||
postsCollectionId,
|
|
||||||
ID.unique(),
|
|
||||||
{
|
|
||||||
titulo: title,
|
titulo: title,
|
||||||
slug: slug,
|
slug: slug,
|
||||||
tipo_publicacion_id: defaultPubTypeId,
|
tipo_publicacion_id: defaultPubTypeId,
|
||||||
estado: 'borrador', // Cambiado a borrador para revisión
|
estado: 'borrador',
|
||||||
fecha_publicacion: realDate, // Fecha real del mensaje
|
fecha_publicacion: date.toISOString(),
|
||||||
contenido: `<p>${cleanCaption.replace(/\n/g, '<br/>')}</p>`, // Formato HTML básico
|
contenido: `<p>${cleanCaption.replace(/\n/g, '<br/>')}</p>`,
|
||||||
imagen_destacada_id: mediaDoc.$id
|
imagen_destacada_id: mediaDoc.$id
|
||||||
}
|
});
|
||||||
);
|
|
||||||
} catch(e) {
|
|
||||||
console.error("Post error:", e.message);
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(`[Success] Published post ${publishedCount + 1}/8 for Month ${month}`);
|
console.log(`[Success] Published post ${monthCounts[month] + 1}/8 for Month ${month}: ${title}`);
|
||||||
publishedCount++;
|
monthCounts[month]++;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(`Failed to publish image for month ${month}:`, err.message);
|
console.error(`Failed to publish image for month ${month}:`, err.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (publishedCount < 8) {
|
|
||||||
console.log(`Could only publish ${publishedCount} images for Month ${month} (ran out of images).`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log("All done!");
|
console.log("All done!");
|
||||||
} catch (e) {
|
} catch (e) { console.error("Error:", e.message); }
|
||||||
console.error("Error:", e.message);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
run();
|
run();
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user