diff --git a/publish-cauca-all-months.js b/publish-cauca-all-months.js new file mode 100644 index 0000000..c1abb9b --- /dev/null +++ b/publish-cauca-all-months.js @@ -0,0 +1,202 @@ +const fs = require('fs'); +const axios = require('axios'); +const { Client, Databases, Storage, ID, Query } = require('node-appwrite'); +require('dotenv').config({ path: '.env.local' }); + +let InputFile; +try { InputFile = require('node-appwrite/file').InputFile; } catch (e) { InputFile = null; } + +const EVOLUTION_API_URL = process.env.EVOLUTION_API_URL; +const EVOLUTION_API_KEY = process.env.EVOLUTION_API_KEY; +const EVOLUTION_INSTANCE_NAME = process.env.EVOLUTION_INSTANCE_NAME; +const CHAT_ID = '573134848203-1408546044@g.us'; + +const client = new Client() + .setEndpoint(process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT) + .setProject(process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID) + .setKey(process.env.APPWRITE_API_KEY); + +const databases = new Databases(client); +const storage = new Storage(client); +const DB_ID = process.env.APPWRITE_DATABASE_ID; +const BUCKET_ID = process.env.NEXT_PUBLIC_APPWRITE_MEDIA_BUCKET_ID; + +async function getCollectionIds() { + const list = await databases.listCollections(DB_ID); + const map = {}; + list.collections.forEach(c => { map[c.name.toLowerCase()] = c.$id; }); + return map; +} + +function extractText(msg) { + if (msg.messageType === 'conversation') return msg.message.conversation; + if (msg.messageType === 'extendedTextMessage') return msg.message.extendedTextMessage?.text; + return null; +} + +function inferPublicationType(text, typeMap) { + if (!text) return typeMap['NOTICIA']; + const t = text.toLowerCase(); + + // Check for Evento + const eventKeywords = ['invita', 'invitación', 'asiste', 'te esperamos', 'evento', 'jornada', 'foro', 'congreso', 'feria', 'festival', 'encuentro', 'conmemoramos', 'celebramos']; + if (eventKeywords.some(kw => t.includes(kw))) { + return typeMap['EVENTO'] || typeMap['NOTICIA']; + } + + // Check for Clasificado (or Convocatoria) + const classKeywords = ['oferta', 'empleo', 'vacante', 'convocatoria', 'se busca', 'clasificado', 'postúlate', 'inscríbete']; + if (classKeywords.some(kw => t.includes(kw))) { + return typeMap['CLASIFICADO'] || typeMap['NOTICIA']; + } + + return typeMap['NOTICIA']; +} + +async function run() { + console.log("Starting publishing process..."); + try { + const collections = await getCollectionIds(); + const postsCollectionId = collections['posts'] || 'posts'; + const mediaCollectionId = collections['media'] || 'media'; + const pubTypesCollectionId = collections['publication types'] || collections['publication_types'] || 'publication_types'; + + const pubTypesRes = await databases.listDocuments(DB_ID, pubTypesCollectionId); + const typeMap = {}; + pubTypesRes.documents.forEach(d => { + typeMap[d.codigo] = d.$id; + }); + + // 1. Delete old posts + 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); + } + + // 2. Fetch all messages + const allRecords = []; + let currentPage = 1; + let totalPages = 1; + + console.log("Fetching messages from Evolution API..."); + do { + const response = await axios.post( + `${EVOLUTION_API_URL}/chat/findMessages/${EVOLUTION_INSTANCE_NAME}?page=${currentPage}&limit=100`, + { where: { "key": { "remoteJid": CHAT_ID } } }, + { headers: { 'apikey': EVOLUTION_API_KEY, 'Content-Type': 'application/json' } } + ); + + const messagesObj = response.data.messages || {}; + totalPages = messagesObj.pages || 1; + allRecords.push(...(messagesObj.records || [])); + + if (currentPage > 40) break; + currentPage++; + } while (currentPage <= totalPages); + + console.log(`Total messages fetched: ${allRecords.length}`); + + // 3. Process images and find associated text + const targetMonths = [3, 4, 5, 6]; + let allImages = allRecords.filter(m => m.messageType === 'imageMessage'); + console.log(`Found ${allImages.length} images in history.`); + + let imageIndex = 0; + + for (const month of targetMonths) { + let publishedCount = 0; + console.log(`\n--- Publishing for Month ${month} ---`); + + while (publishedCount < 8 && imageIndex < allImages.length) { + const msg = allImages[imageIndex]; + imageIndex++; + + // Find associated text in the original allRecords array + let caption = msg.message?.imageMessage?.caption; + if (!caption) { + const idx = allRecords.indexOf(msg); + let bestText = null; + for (let j = Math.max(0, idx - 10); j < Math.min(allRecords.length, idx + 10); j++) { + const nearbyMsg = allRecords[j]; + if (Math.abs(nearbyMsg.messageTimestamp - msg.messageTimestamp) > 600) continue; + const text = extractText(nearbyMsg); + if (text && text.length > 20 && !text.toLowerCase().includes("comparte en tus historias")) { + bestText = text; + if (j > idx) 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} #${publishedCount + 1}`; + + if (cleanCaption.length > 20) { + const lines = cleanCaption.split('\n').map(l => l.replace(/^[\p{Emoji}\s*_*]+/gu, '').trim()).filter(l => l.length > 5); + if (lines.length > 0) { + title = lines[0]; + const genericTitles = ['flash informativo', 'boletín', 'gobernación del cauca', 'comunicado', 'atención', 'apreciados periodistas', 'medios de comunicación']; + const isGeneric = genericTitles.some(g => title.toLowerCase().includes(g)) || title.toUpperCase() === title || title.length < 25; + if (isGeneric && lines.length > 1) { + title = `${title} | ${lines[1]}`; + } + if (title.length > 100) title = title.substring(0, 100) + '...'; + } + } + + const inferredType = inferPublicationType(cleanCaption, typeMap); + + try { + const base64Res = await axios.post( + `${EVOLUTION_API_URL}/chat/getBase64FromMediaMessage/${EVOLUTION_INSTANCE_NAME}`, + { message: msg }, + { headers: { 'apikey': EVOLUTION_API_KEY, 'Content-Type': 'application/json' } } + ); + + const base64Data = base64Res.data.base64; + if (!base64Data) continue; + + const buffer = Buffer.from(base64Data, 'base64'); + const filePath = `/tmp/image-${month}-${publishedCount}.jpeg`; + fs.writeFileSync(filePath, buffer); + + let fileParam; + if (InputFile && InputFile.fromPath) fileParam = InputFile.fromPath(filePath, `image.jpeg`); + else if (InputFile && InputFile.fromBuffer) fileParam = InputFile.fromBuffer(buffer, `image.jpeg`); + else fileParam = fs.createReadStream(filePath); + + const file = await storage.createFile(BUCKET_ID, ID.unique(), fileParam); + + const mediaDoc = await databases.createDocument(DB_ID, mediaCollectionId, ID.unique(), { + file_id: file.$id, bucket_id: BUCKET_ID, + titulo: title, tipo: 'imagen' + }); + + const slug = `gobernacion-cauca-mes-${month}-pub-${publishedCount}-${Date.now()}`; + + // Artificial date corresponding to the target month + const artificialDate = new Date(2026, month - 1, 15 + publishedCount, 12, 0, 0).toISOString(); + + await databases.createDocument(DB_ID, postsCollectionId, ID.unique(), { + titulo: title, + slug: slug, + tipo_publicacion_id: inferredType, + estado: 'Publicado', + fecha_publicacion: artificialDate, + contenido: `
${cleanCaption.replace(/\n/g, '
')}