Files

81 lines
2.8 KiB
JavaScript

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); });