fix(shorts): живые обновления страницы и лимит на вызовы ИИ
- shorts.js подписан на SSE shorts_changed с дебаунсом и реконнектом
- dispatchEvent больше не отдаёт любой неизвестный тип как
entries_changed: entries_changed/lessons_changed/shorts_changed
теперь маршрутизируются по имени (иначе правка короткого
сообщения будила журнал с ложным тостом о новой записи)
- добавлен aiLimiter (30/мин на cache.rateLimitStore('ai')) и
навешен на оба вызова модели: /api/ai/correct и
/api/shorts/ai-correct
This commit is contained in:
@@ -159,6 +159,10 @@ function dispatchEvent(payload) {
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (payload && (payload.type === 'entries_changed' || payload.type === 'lessons_changed' || payload.type === 'shorts_changed')) {
|
||||
writeFrame(payload.type, { ts: Date.now() });
|
||||
return;
|
||||
}
|
||||
if (payload && payload.type === 'ai_status') {
|
||||
writeFrame('ai_status', {
|
||||
id: payload.id,
|
||||
@@ -1991,6 +1995,15 @@ const chatLimiter = rateLimit({
|
||||
message: { error: 'Слишком много сообщений. Подождите минуту.' },
|
||||
});
|
||||
|
||||
const aiLimiter = rateLimit({
|
||||
windowMs: 60 * 1000,
|
||||
max: 30,
|
||||
standardHeaders: true,
|
||||
legacyHeaders: false,
|
||||
store: cache.rateLimitStore('ai', 60 * 1000),
|
||||
message: { error: 'Слишком много запросов к ИИ. Подождите минуту.' },
|
||||
});
|
||||
|
||||
async function chatThreadFor(user, threadId) {
|
||||
const id = parseInt(threadId, 10);
|
||||
if (!Number.isInteger(id) || id < 1) return { error: 400, message: 'Invalid thread' };
|
||||
@@ -2747,7 +2760,7 @@ app.delete('/api/shorts/:id/permanent', requireAuth, requireAdmin, async (req, r
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/api/shorts/ai-correct', requireAuth, async (req, res) => {
|
||||
app.post('/api/shorts/ai-correct', requireAuth, aiLimiter, async (req, res) => {
|
||||
try {
|
||||
const text = reqStr(req.body?.text, 5000);
|
||||
if (!text) return res.status(400).json({ error: 'Текст не указан' });
|
||||
@@ -7486,7 +7499,7 @@ app.put('/api/entries/:id/unschedule', requireAuth, async (req, res) => {
|
||||
res.json({ ok: true });
|
||||
});
|
||||
|
||||
app.post('/api/ai/correct', requireAuth, async (req, res) => {
|
||||
app.post('/api/ai/correct', requireAuth, aiLimiter, async (req, res) => {
|
||||
const text = reqStr(req.body?.text, 5000);
|
||||
if (!text) return res.status(400).json({ error: 'Текст не указан' });
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user