diff --git a/src/services/articles.js b/src/services/articles.js index 033baf9..2eb8ead 100644 --- a/src/services/articles.js +++ b/src/services/articles.js @@ -143,8 +143,8 @@ async function generateAndSaveArticle({ topic, keywords = [], tags = [], autoPub )); const { rows: artRows } = await query( - `INSERT INTO articles (slug, title, excerpt, content, tags, category, reading_time, status, job_id, seo_title, seo_descr) - VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11) RETURNING *`, + `INSERT INTO articles (slug, title, excerpt, content, tags, category, reading_time, status, job_id, seo_title, seo_descr, source_topic) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12) RETURNING *`, [ slug, title, excerpt, content, JSON.stringify(cleanTags), @@ -154,6 +154,7 @@ async function generateAndSaveArticle({ topic, keywords = [], tags = [], autoPub jobId, title.substring(0, 60), excerpt.substring(0, 160), + topic || null, ] ); diff --git a/src/services/autogen.js b/src/services/autogen.js index 5885427..6696a00 100644 --- a/src/services/autogen.js +++ b/src/services/autogen.js @@ -69,14 +69,31 @@ async function getNextTopic(category) { if (rows.length) { return { id: rows[0].id, topic: rows[0].topic, tags: rows[0].tags || [], keywords: rows[0].keywords || [] }; } - // Из банка — случайная тема которой ещё не было + // Из банка — темы которые ещё не использовались const bank = TOPIC_BANK[category] || TOPIC_BANK['ai-tools']; - const { rows: used } = await query( - `SELECT a.title FROM articles a WHERE a.category=$1 AND a.status='published'`, + + // Получаем уже использованные темы по source_topic (точное совпадение) + const { rows: usedTopics } = await query( + `SELECT source_topic FROM articles WHERE category=$1 AND source_topic IS NOT NULL`, [category] ); - const usedTitles = used.map(r => r.title.toLowerCase()); - const unused = bank.filter(t => !usedTitles.some(u => u.includes(t.slice(0, 20).toLowerCase()))); + const usedSet = new Set(usedTopics.map(r => r.source_topic.toLowerCase().trim())); + + // Также проверяем по заголовкам (fallback для старых статей без source_topic) + const { rows: usedTitles } = await query( + `SELECT title FROM articles WHERE category=$1 AND source_topic IS NULL AND status='published'`, + [category] + ); + const titlesLower = usedTitles.map(r => r.title.toLowerCase()); + + const unused = bank.filter(t => { + const tLow = t.toLowerCase().trim(); + if (usedSet.has(tLow)) return false; + // Fallback: проверяем по первым 30 символам заголовка + if (titlesLower.some(title => title.includes(tLow.slice(0, 30)))) return false; + return true; + }); + const pool = unused.length > 0 ? unused : bank; const topic = pool[Math.floor(Math.random() * pool.length)]; return { id: null, topic, tags: [], keywords: [] };