feat(admin): тумблер вкл/выкл генерации картинок

Главный выключатель в разделе «Генерация картинок» (флаг on в конфиге,
независим от наличия токена). Выключено → /api/imggen отдаёт 503
«временно выключена». Админ-тест работает и при выключенном тумблере
(generateImage проверяет только наличие конфига). Бейдж различает
«Включена / Выключена / Не настроена».

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Maxim Dolgolyov
2026-06-12 12:00:05 +03:00
parent 88651d85ab
commit ddc260e114
3 changed files with 29 additions and 5 deletions
+6 -1
View File
@@ -1108,6 +1108,8 @@ function getImggen(_req, res) {
let stats = { count: 0, bytes: 0 };
try { stats = require('./imggenController').stats(); } catch (e) {}
const cd = Number(c.cooldownMs), dc = Number(c.dailyCap);
const configured = !!(c.provider === 'cloudflare' && c.accountId && c.token);
const on = c.on !== false;
res.json({
provider: c.provider || 'cloudflare',
accountId: c.accountId || '',
@@ -1115,7 +1117,9 @@ function getImggen(_req, res) {
hasToken: !!c.token,
cooldownMs: Number.isFinite(cd) && cd >= 0 ? cd : 4000,
dailyCap: Number.isFinite(dc) && dc >= 0 ? dc : 40,
enabled: !!(c.provider === 'cloudflare' && c.accountId && c.token),
on,
configured,
enabled: configured && on,
models: IMGGEN_MODELS,
stats,
});
@@ -1125,6 +1129,7 @@ function saveImggen(req, res) {
const b = req.body || {};
const c = _imgCfg();
c.provider = b.provider || c.provider || 'cloudflare';
if (typeof b.on === 'boolean') c.on = b.on;
if (b.accountId !== undefined) c.accountId = String(b.accountId || '').trim();
if (b.model !== undefined) c.model = String(b.model || '').trim();
if (b.clearToken) c.token = '';
+7 -3
View File
@@ -16,7 +16,9 @@ const DAILY_DEFAULT = 40;
function _cfg() {
try { const r = db.prepare("SELECT value FROM app_settings WHERE key='imggen_provider'").get(); return r ? JSON.parse(r.value) : null; } catch (e) { return null; }
}
function _enabled() { const c = _cfg(); return !!(c && c.provider === 'cloudflare' && c.accountId && c.token); }
function _configured(c) { c = (c === undefined) ? _cfg() : c; return !!(c && c.provider === 'cloudflare' && c.accountId && c.token); }
// «Включено» = настроено И не выключено тумблером (c.on !== false). Тумблер независим от наличия токена.
function _enabled() { const c = _cfg(); return _configured(c) && c.on !== false; }
function _limits() {
const c = _cfg() || {};
const cd = Number(c.cooldownMs);
@@ -95,7 +97,9 @@ function _save(uid, buf) {
/* Публичная: перевод → генерация → сохранение. Без пер-юзер лимитов
* (их применяет route generate). Возвращает { url, prompt } или бросает Error. */
async function generateImage(prompt, uid) {
if (!_enabled()) throw new Error('Генерация изображений не настроена');
// Низкоуровневая: проверяем только наличие конфига (тумблер on/off — забота вызывающего
// route /api/imggen). Так админ-тест работает даже при выключенном тумблере.
if (!_configured()) throw new Error('Генерация изображений не настроена');
const p = String(prompt || '').trim().slice(0, 500);
if (p.length < 3) throw new Error('Опиши, что нарисовать (хотя бы пару слов)');
const en = await _toEnglish(p);
@@ -115,7 +119,7 @@ function stats() {
/* POST /api/imggen { prompt } → { url } */
async function generate(req, res) {
if (!_enabled()) return res.status(503).json({ error: 'Генерация изображений не настроена' });
if (!_enabled()) return res.status(503).json({ error: _configured() ? 'Генерация картинок временно выключена' : 'Генерация изображений не настроена' });
const prompt = String((req.body && req.body.prompt) || '').trim().slice(0, 500);
if (prompt.length < 3) return res.status(400).json({ error: 'Опиши, что нарисовать (хотя бы пару слов)' });