Agregar campo username a User entity y DTO
- Columna username (unique, nullable) en auth.users - Campo username en CreateUserDto y UpdateUserDto Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
175
scripts/fetch-images-wikimedia.js
Executable file
175
scripts/fetch-images-wikimedia.js
Executable file
@@ -0,0 +1,175 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Script para obtener imágenes de Wikimedia Commons para monumentos
|
||||
* Usa la API de Wikimedia Commons (gratuita, sin API key)
|
||||
*/
|
||||
|
||||
const { Client } = require('pg');
|
||||
const https = require('https');
|
||||
|
||||
// Configuración
|
||||
const config = {
|
||||
db: {
|
||||
host: 'localhost',
|
||||
port: 5432,
|
||||
user: 'karibeo',
|
||||
password: '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',
|
||||
database: 'karibeo_db',
|
||||
},
|
||||
};
|
||||
|
||||
// Buscar imágenes en Wikimedia Commons
|
||||
async function searchWikimediaImages(query, limit = 3) {
|
||||
return new Promise((resolve, reject) => {
|
||||
// Primero buscar en Wikipedia para obtener la página del lugar
|
||||
const searchUrl = `https://commons.wikimedia.org/w/api.php?action=query&list=search&srsearch=${encodeURIComponent(query)}&srnamespace=6&srlimit=${limit}&format=json`;
|
||||
|
||||
https.get(searchUrl, { headers: { 'User-Agent': 'KaribeoAI/1.0 (contact@karibeo.ai)' } }, (res) => {
|
||||
let data = '';
|
||||
res.on('data', chunk => data += chunk);
|
||||
res.on('end', () => {
|
||||
try {
|
||||
const json = JSON.parse(data);
|
||||
if (json.query && json.query.search && json.query.search.length > 0) {
|
||||
// Obtener URLs de las imágenes
|
||||
const titles = json.query.search.map(s => s.title).join('|');
|
||||
getImageUrls(titles).then(resolve).catch(reject);
|
||||
} else {
|
||||
resolve([]);
|
||||
}
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
});
|
||||
}).on('error', reject);
|
||||
});
|
||||
}
|
||||
|
||||
// Obtener URLs directas de las imágenes
|
||||
async function getImageUrls(titles) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const url = `https://commons.wikimedia.org/w/api.php?action=query&titles=${encodeURIComponent(titles)}&prop=imageinfo&iiprop=url|size&format=json`;
|
||||
|
||||
https.get(url, { headers: { 'User-Agent': 'KaribeoAI/1.0 (contact@karibeo.ai)' } }, (res) => {
|
||||
let data = '';
|
||||
res.on('data', chunk => data += chunk);
|
||||
res.on('end', () => {
|
||||
try {
|
||||
const json = JSON.parse(data);
|
||||
const urls = [];
|
||||
if (json.query && json.query.pages) {
|
||||
for (const pageId in json.query.pages) {
|
||||
const page = json.query.pages[pageId];
|
||||
if (page.imageinfo && page.imageinfo[0]) {
|
||||
const info = page.imageinfo[0];
|
||||
// Solo incluir imágenes de tamaño razonable (> 100KB y < 10MB)
|
||||
if (info.size > 100000 && info.size < 10000000) {
|
||||
urls.push(info.url);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
resolve(urls);
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
});
|
||||
}).on('error', reject);
|
||||
});
|
||||
}
|
||||
|
||||
// Buscar con términos alternativos
|
||||
async function searchWithAlternatives(name, country) {
|
||||
const countryName = country === 'DO' ? 'Dominican Republic' : 'Puerto Rico';
|
||||
const countryNameEs = country === 'DO' ? 'República Dominicana' : 'Puerto Rico';
|
||||
|
||||
// Lista de búsquedas a intentar
|
||||
const searches = [
|
||||
`${name} ${countryNameEs}`,
|
||||
`${name} ${countryName}`,
|
||||
name,
|
||||
`${name} Caribbean`,
|
||||
];
|
||||
|
||||
for (const query of searches) {
|
||||
console.log(` Buscando: "${query}"`);
|
||||
const images = await searchWikimediaImages(query, 5);
|
||||
if (images.length > 0) {
|
||||
return images.slice(0, 3); // Máximo 3 imágenes
|
||||
}
|
||||
await delay(500); // Rate limit
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
function delay(ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
async function main() {
|
||||
console.log('🖼️ Buscador de Imágenes - Wikimedia Commons');
|
||||
console.log('============================================\n');
|
||||
|
||||
// Conectar a la DB
|
||||
const client = new Client(config.db);
|
||||
await client.connect();
|
||||
console.log('✅ Conectado a la base de datos\n');
|
||||
|
||||
// Obtener monumentos sin imágenes válidas
|
||||
const query = `
|
||||
SELECT id, name, country, slug, images
|
||||
FROM tourism.places_of_interest
|
||||
WHERE active = true
|
||||
AND (images IS NULL OR images::text = '[]' OR images::text LIKE '%example.com%')
|
||||
ORDER BY name
|
||||
`;
|
||||
|
||||
const result = await client.query(query);
|
||||
const places = result.rows;
|
||||
console.log(`📍 Encontrados ${places.length} lugares sin imágenes válidas\n`);
|
||||
|
||||
let found = 0;
|
||||
let notFound = 0;
|
||||
|
||||
for (let i = 0; i < places.length; i++) {
|
||||
const place = places[i];
|
||||
console.log(`[${i + 1}/${places.length}] ${place.name} (${place.country})`);
|
||||
|
||||
try {
|
||||
const images = await searchWithAlternatives(place.name, place.country);
|
||||
|
||||
if (images.length > 0) {
|
||||
// Guardar en la DB
|
||||
await client.query(
|
||||
`UPDATE tourism.places_of_interest SET images = $1 WHERE id = $2`,
|
||||
[JSON.stringify(images), place.id]
|
||||
);
|
||||
console.log(` ✅ ${images.length} imágenes encontradas`);
|
||||
found++;
|
||||
} else {
|
||||
console.log(` ⚠️ No se encontraron imágenes`);
|
||||
notFound++;
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(` ❌ Error: ${error.message}`);
|
||||
notFound++;
|
||||
}
|
||||
|
||||
// Rate limit para la API de Wikimedia
|
||||
await delay(1000);
|
||||
}
|
||||
|
||||
await client.end();
|
||||
|
||||
console.log('\n============================================');
|
||||
console.log('📊 RESUMEN');
|
||||
console.log(` ✅ Con imágenes: ${found}`);
|
||||
console.log(` ⚠️ Sin imágenes: ${notFound}`);
|
||||
console.log('============================================\n');
|
||||
}
|
||||
|
||||
main().catch(err => {
|
||||
console.error('Error fatal:', err);
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in New Issue
Block a user