From b56f52a7510a04788dd1c4c1a4885e6468561244 Mon Sep 17 00:00:00 2001 From: Alexey Pavlov Date: Tue, 30 Jun 2026 01:21:04 +0300 Subject: [PATCH] =?UTF-8?q?fix(covers):=20routerai=20=D0=B4=D0=BE=204=20?= =?UTF-8?q?=D0=BF=D0=BE=D0=BF=D1=8B=D1=82=D0=BE=D0=BA=20=D1=81=20backoff?= =?UTF-8?q?=20=D0=BF=D0=B5=D1=80=D0=B5=D0=B4=20SVG-=D1=84=D0=BE=D0=BB?= =?UTF-8?q?=D0=B1=D1=8D=D0=BA=D0=BE=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit routerai (image API) периодически таймаутит; раньше был всего 1 ретрай и обложка падала в local SVG-заглушку. Теперь до 4 попыток (8/16/24с backoff), SVG — только если все провалились. Провайдер один — routerai, как и решили. --- src/services/covers.js | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/src/services/covers.js b/src/services/covers.js index 4f786ce..850c1ff 100644 --- a/src/services/covers.js +++ b/src/services/covers.js @@ -559,28 +559,25 @@ async function generateCover({ articleId, title, tags = [], channelId = null }) const prompt = buildCoverPrompt({ title, tags, articleId, channelStyle, rubric: selectedRubric }); - let img; + let img = null; let usedPath = 'routerai'; - // Единственный провайдер картинок: routerai /responses + gpt-5-image-mini - // Цена: ~₽2.72/картинка (4175 image tokens, high quality, quality param не работает) - try { - img = await generateCoverViaRouterAI({ prompt }); - } catch (err) { - const status = err.response?.status; - // Ретрай при 5xx - if (!status || (status >= 500 && status < 600)) { - console.warn(`[Cover] routerai attempt 1 failed (${status||'timeout'}), retry in 10s...`); - await new Promise(r => setTimeout(r, 10_000)); - try { - img = await generateCoverViaRouterAI({ prompt }); - } catch (err2) { - console.warn(`[Cover] routerai attempt 2 failed: ${(err2.response?.data?.error?.message || err2.message).slice(0, 150)}`); - img = null; - } - } else { - console.warn(`[Cover] routerai failed (${status}): ${(err.response?.data?.error?.message || err.message).slice(0, 150)}`); - img = null; + // Единственный провайдер картинок — routerai /responses + gpt-5-image-mini + // (самый надёжный). Бывает медленным/таймаутит, поэтому до 4 попыток с + // нарастающей паузой; local SVG — только если все попытки провалились, + // чтобы обложка не осталась пустой. + const ROUTERAI_ATTEMPTS = 4; + for (let attempt = 1; attempt <= ROUTERAI_ATTEMPTS; attempt++) { + try { + img = await generateCoverViaRouterAI({ prompt }); + if (img) break; + } catch (err) { + const status = err.response?.status; + const retriable = !status || (status >= 500 && status < 600) || status === 429; + const msg = (err.response?.data?.error?.message || err.message || '').slice(0, 150); + console.warn(`[Cover] article=${articleId} routerai attempt ${attempt}/${ROUTERAI_ATTEMPTS} failed (${status || 'timeout'}): ${msg}`); + if (!retriable || attempt === ROUTERAI_ATTEMPTS) break; + await new Promise(r => setTimeout(r, attempt * 8000)); // 8s → 16s → 24s } } if (!img) {