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];
|
||||
}
|
||||
|
||||
const { rows: settings } = await query(
|
||||
`SELECT * FROM autogen_settings ${whereClause} ORDER BY category`,
|
||||
params
|
||||
// Сначала берём ВСЕ активные категории (независимо от времени),
|
||||
// затем применяем ротацию — выбираем 4 из 8 по дню года.
|
||||
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) {
|
||||
console.log('[Autogen] Nothing to generate at this time');
|
||||
return { processed: 0, 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);
|
||||
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));
|
||||
}
|
||||
}
|
||||
@@ -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() {
|
||||
const { rows: settings } = await query(
|
||||
`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
|
||||
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