feat(autogen): ротация 4 из 8 категорий по дням
Каждый день генерируем 4 из 8 категорий по скользящему окну: День 1: cat[0..3], День 2: cat[1..4], ..., День 8: cat[7,0,1,2] Логика: dayOfYear % totalCategories = сдвиг окна. За 8 дней каждая категория выходит 4 раза, каждый день — новый набор. getAutogenStatus теперь возвращает today_active=true/false — входит ли категория в сегодняшнюю ротацию. Слоты публикации откатаны к 4 (08:11/12:11/16:11/20:11).
This commit is contained in:
+75
-7
@@ -202,21 +202,70 @@ async function runAutogen({ forceCategory = null } = {}) {
|
|||||||
params = [currentHour, currentMinute - 5, currentMinute + 5];
|
params = [currentHour, currentMinute - 5, currentMinute + 5];
|
||||||
}
|
}
|
||||||
|
|
||||||
const { rows: settings } = await query(
|
// Сначала берём ВСЕ активные категории (независимо от времени),
|
||||||
`SELECT * FROM autogen_settings ${whereClause} ORDER BY category`,
|
// затем применяем ротацию — выбираем 4 из 8 по дню года.
|
||||||
params
|
const { rows: allEnabled } = await query(
|
||||||
|
`SELECT * FROM autogen_settings WHERE enabled=true ORDER BY sort_order, category`,
|
||||||
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Ротация: скользящее окно из 4 категорий сдвигается на 1 каждый день.
|
||||||
|
// Это гарантирует что за 8 дней каждая категория выйдет минимум 4 раза,
|
||||||
|
// и каждый день читатель видит другой набор.
|
||||||
|
const DAILY_COUNT = 4;
|
||||||
|
const total = allEnabled.length;
|
||||||
|
let categoriesForToday;
|
||||||
|
if (total <= DAILY_COUNT) {
|
||||||
|
// Категорий меньше или равно 4 — берём все
|
||||||
|
categoriesForToday = allEnabled.map(s => s.category);
|
||||||
|
} else {
|
||||||
|
// День года (0..364) определяет сдвиг окна
|
||||||
|
const now = new Date();
|
||||||
|
const start = Date.UTC(now.getUTCFullYear(), 0, 0);
|
||||||
|
const dayOfYear = Math.floor((now - start) / 86400000);
|
||||||
|
const offset = dayOfYear % total;
|
||||||
|
// Берём 4 категории начиная со сдвига (с wrap-around)
|
||||||
|
categoriesForToday = Array.from({ length: DAILY_COUNT }, (_, i) =>
|
||||||
|
allEnabled[(offset + i) % total].category
|
||||||
|
);
|
||||||
|
console.log(
|
||||||
|
'[Autogen] Ротация дня ' + dayOfYear + ' (offset=' + offset + '): ' +
|
||||||
|
categoriesForToday.join(', ')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Теперь фильтруем по расписанию (если не forceCategory) — категория
|
||||||
|
// должна быть в списке дня И соответствовать текущему времени.
|
||||||
|
const { rows: allSettings } = await query(
|
||||||
|
`SELECT * FROM autogen_settings WHERE enabled=true ORDER BY run_hour, run_minute`,
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
|
let settings;
|
||||||
|
if (forceCategory) {
|
||||||
|
settings = allSettings.filter(s => s.category === forceCategory);
|
||||||
|
} else {
|
||||||
|
// Время окна ±5 мин уже применено в whereClause — переиспользуем
|
||||||
|
const { rows: timeFiltered } = await query(
|
||||||
|
`SELECT * FROM autogen_settings ${whereClause} ORDER BY run_hour, run_minute`,
|
||||||
|
params
|
||||||
|
);
|
||||||
|
// Оставляем только категории дня из сработавших по времени
|
||||||
|
const todaySet = new Set(categoriesForToday);
|
||||||
|
settings = timeFiltered.filter(s => todaySet.has(s.category));
|
||||||
|
}
|
||||||
|
|
||||||
if (!settings.length) {
|
if (!settings.length) {
|
||||||
console.log('[Autogen] Nothing to generate at this time');
|
console.log('[Autogen] Nothing to generate at this time');
|
||||||
return { processed: 0, results: [] };
|
return { processed: 0, results: [] };
|
||||||
}
|
}
|
||||||
|
|
||||||
const results = [];
|
const results = [];
|
||||||
for (const s of settings) {
|
for (let i = 0; i < settings.length; i++) {
|
||||||
|
const s = settings[i];
|
||||||
const result = await runAutogenForCategory(s.category);
|
const result = await runAutogenForCategory(s.category);
|
||||||
results.push({ category: s.category, ...result });
|
results.push({ category: s.category, ...result });
|
||||||
if (settings.indexOf(s) < settings.length - 1) {
|
if (i < settings.length - 1) {
|
||||||
await new Promise(r => setTimeout(r, 5000));
|
await new Promise(r => setTimeout(r, 5000));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -227,6 +276,20 @@ async function runAutogen({ forceCategory = null } = {}) {
|
|||||||
/**
|
/**
|
||||||
* Получить статус автогенерации.
|
* Получить статус автогенерации.
|
||||||
*/
|
*/
|
||||||
|
/**
|
||||||
|
* Возвращает категории которые активны сегодня по ротации (4 из 8).
|
||||||
|
*/
|
||||||
|
function getTodayCategories(allCategories, dailyCount = 4) {
|
||||||
|
if (allCategories.length <= dailyCount) return allCategories.map(c => c.category || c);
|
||||||
|
const now = new Date();
|
||||||
|
const start = Date.UTC(now.getUTCFullYear(), 0, 0);
|
||||||
|
const dayOfYear = Math.floor((now - start) / 86400000);
|
||||||
|
const offset = dayOfYear % allCategories.length;
|
||||||
|
return Array.from({ length: dailyCount }, (_, i) =>
|
||||||
|
(allCategories[(offset + i) % allCategories.length].category || allCategories[(offset + i) % allCategories.length])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
async function getAutogenStatus() {
|
async function getAutogenStatus() {
|
||||||
const { rows: settings } = await query(
|
const { rows: settings } = await query(
|
||||||
`SELECT s.*, c.name as cat_name, c.icon as cat_icon, c.color as cat_color,
|
`SELECT s.*, c.name as cat_name, c.icon as cat_icon, c.color as cat_color,
|
||||||
@@ -252,7 +315,12 @@ async function getAutogenStatus() {
|
|||||||
LEFT JOIN categories c ON c.slug=s.category
|
LEFT JOIN categories c ON c.slug=s.category
|
||||||
ORDER BY s.run_hour, s.category`
|
ORDER BY s.run_hour, s.category`
|
||||||
);
|
);
|
||||||
return settings;
|
// Добавим флаг today_active — входит ли категория в сегодняшнюю ротацию
|
||||||
|
const todaySet = new Set(getTodayCategories(settings));
|
||||||
|
return settings.map(s => ({
|
||||||
|
...s,
|
||||||
|
today_active: todaySet.has(s.category),
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { runAutogen, runAutogenForCategory, getAutogenStatus, TOPIC_BANK };
|
module.exports = { runAutogen, runAutogenForCategory, getAutogenStatus, getTodayCategories, TOPIC_BANK };
|
||||||
|
|||||||
Reference in New Issue
Block a user