fix: avoid repeating last 3 rubrics in cover selection (no more similar covers)
This commit is contained in:
+41
-7
@@ -466,13 +466,34 @@ async function generateCoverViaPollinations({ prompt }) {
|
|||||||
* Выбирает наиболее подходящую рубрику для обложки статьи.
|
* Выбирает наиболее подходящую рубрику для обложки статьи.
|
||||||
* Дешёвый haiku-вызов: ~50 токенов. При ошибке — случайная рубрика.
|
* Дешёвый haiku-вызов: ~50 токенов. При ошибке — случайная рубрика.
|
||||||
*/
|
*/
|
||||||
async function selectRubric({ title, tags = [], rubrics }) {
|
async function selectRubric({ title, tags = [], rubrics, channelId = null }) {
|
||||||
if (!rubrics || rubrics.length === 0) return null;
|
if (!rubrics || rubrics.length === 0) return null;
|
||||||
if (rubrics.length === 1) return rubrics[0];
|
if (rubrics.length === 1) return rubrics[0];
|
||||||
|
|
||||||
const rubricList = rubrics.map((r, i) => `${i}. ${r.id}: ${r.desc}`).join('\n');
|
// Получаем последние использованные рубрики из БД (анти-повтор)
|
||||||
const userMsg = `Article title: "${title}"\nTags: ${tags.join(', ') || 'none'}\n\nRubrics:\n${rubricList}\n\nRespond with ONLY the index number (0-${rubrics.length - 1}) of the best matching rubric.`;
|
let recentlyUsed = [];
|
||||||
|
if (channelId) {
|
||||||
|
try {
|
||||||
|
const r = await query(
|
||||||
|
'SELECT last_rubrics_used FROM channel_style WHERE channel_id = $1',
|
||||||
|
[channelId]
|
||||||
|
);
|
||||||
|
recentlyUsed = Array.isArray(r.rows[0]?.last_rubrics_used)
|
||||||
|
? r.rows[0].last_rubrics_used
|
||||||
|
: [];
|
||||||
|
} catch (_) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Доступные рубрики = все минус последние 3 использованные
|
||||||
|
// (если осталось < 2 — берём все, иначе AI выбирает только из свежих)
|
||||||
|
const recent = recentlyUsed.slice(-3);
|
||||||
|
let available = rubrics.filter(r => !recent.includes(r.id));
|
||||||
|
if (available.length < 2) available = rubrics;
|
||||||
|
|
||||||
|
const rubricList = available.map((r, i) => `${i}. ${r.id}: ${r.desc}`).join('\n');
|
||||||
|
const userMsg = `Article title: "${title}"\nTags: ${tags.join(', ') || 'none'}\n\nRubrics:\n${rubricList}\n\nRespond with ONLY the index number (0-${available.length - 1}) of the best matching rubric.`;
|
||||||
|
|
||||||
|
let selected = null;
|
||||||
try {
|
try {
|
||||||
const res = await axios.post(
|
const res = await axios.post(
|
||||||
`${config.ai.baseUrl}/chat/completions`,
|
`${config.ai.baseUrl}/chat/completions`,
|
||||||
@@ -489,12 +510,25 @@ async function selectRubric({ title, tags = [], rubrics }) {
|
|||||||
);
|
);
|
||||||
const raw = res.data?.choices?.[0]?.message?.content?.trim() || '0';
|
const raw = res.data?.choices?.[0]?.message?.content?.trim() || '0';
|
||||||
const idx = parseInt(raw.replace(/\D/g, '')) || 0;
|
const idx = parseInt(raw.replace(/\D/g, '')) || 0;
|
||||||
const safeIdx = Math.min(Math.max(idx, 0), rubrics.length - 1);
|
const safeIdx = Math.min(Math.max(idx, 0), available.length - 1);
|
||||||
return rubrics[safeIdx];
|
selected = available[safeIdx];
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.warn('[Cover] selectRubric failed, using random:', err.message.slice(0, 80));
|
console.warn('[Cover] selectRubric failed, using random:', err.message.slice(0, 80));
|
||||||
return rubrics[Math.floor(Math.random() * rubrics.length)];
|
selected = available[Math.floor(Math.random() * available.length)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Записываем в last_rubrics_used (храним последние 5)
|
||||||
|
if (channelId && selected) {
|
||||||
|
try {
|
||||||
|
const newList = [...recentlyUsed, selected.id].slice(-5);
|
||||||
|
await query(
|
||||||
|
'UPDATE channel_style SET last_rubrics_used = $1 WHERE channel_id = $2',
|
||||||
|
[JSON.stringify(newList), channelId]
|
||||||
|
);
|
||||||
|
} catch (_) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
return selected;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function generateCover({ articleId, title, tags = [], channelId = null }) {
|
async function generateCover({ articleId, title, tags = [], channelId = null }) {
|
||||||
@@ -514,7 +548,7 @@ async function generateCover({ articleId, title, tags = [], channelId = null })
|
|||||||
let styleName;
|
let styleName;
|
||||||
const rubrics = channelStyle?.image_rubrics;
|
const rubrics = channelStyle?.image_rubrics;
|
||||||
if (Array.isArray(rubrics) && rubrics.length > 0) {
|
if (Array.isArray(rubrics) && rubrics.length > 0) {
|
||||||
selectedRubric = await selectRubric({ title, tags, rubrics });
|
selectedRubric = await selectRubric({ title, tags, rubrics, channelId });
|
||||||
styleName = selectedRubric?.id || 'rubric';
|
styleName = selectedRubric?.id || 'rubric';
|
||||||
console.log(`[Cover] article=${articleId} channel=${channelId} rubric=${styleName}`);
|
console.log(`[Cover] article=${articleId} channel=${channelId} rubric=${styleName}`);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user