process.chdir('/var/www/zeropost-engine'); require('dotenv').config(); const { query } = require('./src/config/db'); const ai = require('./src/services/ai'); const DELAY_MS = 3000; const TIMEOUT_MS = 120000; // 2 мин на статью const START_FROM_ID = parseInt(process.argv[2] || '0'); // можно передать start id const sleep = ms => new Promise(r => setTimeout(r, ms)); function withTimeout(promise, ms) { return Promise.race([ promise, new Promise((_, reject) => setTimeout(() => reject(new Error('TIMEOUT')), ms)) ]); } function parseContent(content, topic) { const lines = content.split('\n').filter(Boolean); let title = topic; const h1 = lines.find(l => l.startsWith('# ')); if (h1) title = h1.replace(/^#\s+/, '').trim(); const firstPara = lines.find(l => l.length > 80 && !l.startsWith('#')); const excerpt = firstPara ? firstPara.substring(0, 200) + (firstPara.length > 200 ? '...' : '') : ''; const wordCount = content.replace(/<[^>]+>/g, '').split(/\s+/).length; const readingTime = Math.max(1, Math.round(wordCount / 200)); return { title, excerpt, readingTime }; } async function regenArticle(article, blogChannel) { const topic = article.source_topic || article.title; try { const result = await withTimeout( ai.generateArticle(blogChannel, { topic }), TIMEOUT_MS ); if (!result?.content) return false; const { title, excerpt, readingTime } = parseContent(result.content, topic); await query( `UPDATE articles SET title=$1, content=$2, excerpt=$3, reading_time=$4, seo_title=$5, seo_descr=$6, updated_at=NOW() WHERE id=$7`, [title, result.content, excerpt, readingTime, title.substring(0,60), excerpt.substring(0,160), article.id] ); console.log(`[Regen] OK id=${article.id} "${title.slice(0,60)}"`); return true; } catch (err) { console.error(`[Regen] ERROR id=${article.id}: ${err.message}`); return false; } } async function main() { const { rows: articles } = await query( `SELECT id, title, source_topic, category FROM articles WHERE status='published' ${START_FROM_ID ? `AND id >= ${START_FROM_ID}` : ''} ORDER BY id ASC` ); const { rows: channels } = await query( `SELECT * FROM channels WHERE is_system=true AND is_active=true LIMIT 1` ); console.log(`[Regen] ${articles.length} articles to process (from id=${START_FROM_ID || 'start'})`); let ok = 0, fail = 0; for (let i = 0; i < articles.length; i++) { console.log(`[Regen] ${i+1}/${articles.length} id=${articles[i].id}`); const success = await regenArticle(articles[i], channels[0]); if (success) ok++; else fail++; if (i < articles.length - 1) await sleep(DELAY_MS); } console.log(`[Regen] DONE: ${ok} OK, ${fail} FAILED`); process.exit(0); } main().catch(e => { console.error(e); process.exit(1); });