forked from admin/zeropost-engine
feat: Nyxos Plus as primary image provider, aiguoguo as fallback
- app_settings: AI_IMAGE_BASE_URL → https://plus.nyxos.workers.dev/v1 - app_settings: AI_IMAGE_FALLBACK_BASE_URL/API_KEY → aiguoguo (резерв) - config/index.js: загружает imageFallbackBaseUrl + imageFallbackApiKey - covers.js: generateCoverViaImageGenerations пробует Nyxos, при 5xx/timeout автоматически переключается на aiguoguo
This commit is contained in:
+32
-46
@@ -266,56 +266,42 @@ async function generateCoverViaImagesEndpoint({ prompt }) {
|
||||
* Более стабильный чем /responses, поддерживает gpt-image-1-mini/gpt-image-2.
|
||||
*/
|
||||
async function generateCoverViaImageGenerations({ prompt }) {
|
||||
const model = config.ai.imageModel || 'gpt-image-1-mini';
|
||||
const baseUrl = config.ai.imageBaseUrl || config.ai.baseUrl;
|
||||
const started = Date.now();
|
||||
let res;
|
||||
try {
|
||||
res = await axios.post(
|
||||
`${baseUrl}/images/generations`,
|
||||
{
|
||||
model,
|
||||
prompt: prompt.slice(0, 4000),
|
||||
n: 1,
|
||||
size: '1024x1024',
|
||||
response_format: 'url', // рекомендовано провайдером: url быстрее чем b64 (~5MB)
|
||||
},
|
||||
{
|
||||
headers: { Authorization: `Bearer ${config.ai.imageApiKey}` },
|
||||
timeout: 120_000,
|
||||
const model = config.ai.imageModel || 'gpt-image-2';
|
||||
|
||||
async function tryProvider(baseUrl, apiKey) {
|
||||
const started = Date.now();
|
||||
try {
|
||||
const res = await axios.post(
|
||||
`${baseUrl}/images/generations`,
|
||||
{ model, prompt: prompt.slice(0, 4000), n: 1, size: '1024x1024', response_format: 'url' },
|
||||
{ headers: { Authorization: `Bearer ${apiKey}` }, timeout: 120_000 }
|
||||
);
|
||||
const item = res.data?.data?.[0];
|
||||
if (!item) throw new Error('No image data in response');
|
||||
aiUsage.log({ provider: aiUsage.providerFromBaseUrl(baseUrl), requestType: 'image', model, imageCount: 1, durationMs: Date.now()-started, succeeded: true }).catch(() => {});
|
||||
if (item.url) {
|
||||
const r = await axios.get(item.url, { responseType: 'arraybuffer', timeout: 60_000 });
|
||||
return { bytes: Buffer.from(r.data), format: 'png' };
|
||||
}
|
||||
);
|
||||
if (item.b64_json) return { bytes: Buffer.from(item.b64_json, 'base64'), format: 'png' };
|
||||
throw new Error('No url or b64_json in response');
|
||||
} catch (err) {
|
||||
aiUsage.log({ provider: aiUsage.providerFromBaseUrl(baseUrl), requestType: 'image', model, imageCount: 1, durationMs: Date.now()-started, succeeded: false, errorMessage: (err.response?.data?.error?.message || err.message || '').slice(0, 500) }).catch(() => {});
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
// Основной: Nyxos Plus
|
||||
try {
|
||||
return await tryProvider(config.ai.imageBaseUrl, config.ai.imageApiKey);
|
||||
} catch (err) {
|
||||
aiUsage.log({
|
||||
provider: aiUsage.providerFromBaseUrl(baseUrl),
|
||||
requestType: 'image', model, imageCount: 1,
|
||||
durationMs: Date.now() - started, succeeded: false,
|
||||
errorMessage: (err.response?.data?.error?.message || err.message || '').slice(0, 500),
|
||||
}).catch(() => {});
|
||||
const status = err.response?.status;
|
||||
if (!status || status >= 500) {
|
||||
console.warn(`[Cover] primary failed (${status||'timeout'}), trying fallback aiguoguo...`);
|
||||
return await tryProvider(config.ai.imageFallbackBaseUrl, config.ai.imageFallbackApiKey);
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
const item = res.data?.data?.[0];
|
||||
if (!item) {
|
||||
aiUsage.log({
|
||||
provider: aiUsage.providerFromBaseUrl(baseUrl),
|
||||
requestType: 'image', model, imageCount: 1,
|
||||
durationMs: Date.now() - started, succeeded: false,
|
||||
errorMessage: 'No image data in response',
|
||||
}).catch(() => {});
|
||||
throw new Error('No image data in response');
|
||||
}
|
||||
aiUsage.log({
|
||||
provider: aiUsage.providerFromBaseUrl(baseUrl),
|
||||
requestType: 'image', model, imageCount: 1,
|
||||
durationMs: Date.now() - started, succeeded: true,
|
||||
}).catch(() => {});
|
||||
// Приоритет: url (быстро) → b64_json (fallback для старых моделей)
|
||||
if (item.url) {
|
||||
const r = await axios.get(item.url, { responseType: 'arraybuffer', timeout: 60_000 });
|
||||
return { bytes: Buffer.from(r.data), format: 'png' };
|
||||
}
|
||||
if (item.b64_json) return { bytes: Buffer.from(item.b64_json, 'base64'), format: 'png' };
|
||||
throw new Error('No url or b64_json in response');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user