forked from admin/zeropost-engine
feat: custom prompt for articles + HD image quality per channel
- ai.js: generateArticle принимает customPrompt (от юзера) или channel.ai_style_prompt - articles.js + routes/articles.js: проброс customPrompt через цепочку - postImages.js: channel.image_quality='hd' → gpt-5.4-image-2+medium, иначе gpt-5-image-mini+low - aiUsage.js: правильные цены routerai (RUB/token), gpt-5-image-mini и gpt-5.4-image-2 - channels.js: updateChannel сохраняет ai_style_prompt и image_quality - DB: channels.ai_style_prompt TEXT, channels.image_quality VARCHAR(16) DEFAULT standard
This commit is contained in:
@@ -86,7 +86,13 @@ Composition: 16:9 wide format, balanced, suitable for social media.
|
||||
Strictly: no text, no letters, no logos, no faces of real people.`;
|
||||
|
||||
// RouterAI /responses (primary) → Nyxos /images/generations (fallback)
|
||||
const model = config.ai.routeraiImageModel || 'openai/gpt-5-image-mini';
|
||||
// standard: gpt-5-image-mini + low quality (₽0.20/картинка)
|
||||
// hd: gpt-5.4-image-2 + medium quality (₽2.96/картинка) — для текста на картинках
|
||||
const isHD = channel.image_quality === 'hd';
|
||||
const model = isHD
|
||||
? 'openai/gpt-5.4-image-2'
|
||||
: (config.ai.routeraiImageModel || 'openai/gpt-5-image-mini');
|
||||
const imgQuality = isHD ? 'medium' : 'low';
|
||||
|
||||
async function tryRouterAI() {
|
||||
const started = Date.now();
|
||||
@@ -94,15 +100,15 @@ Strictly: no text, no letters, no logos, no faces of real people.`;
|
||||
const res = await axios.post(`${config.ai.routeraiBaseUrl}/responses`, {
|
||||
model,
|
||||
input: `Use the image_generation tool to create this illustration. Only call the tool, no text.\n\n${prompt.slice(0, 3000)}`,
|
||||
tools: [{ type: 'image_generation', quality: 'low' }],
|
||||
tools: [{ type: 'image_generation', quality: imgQuality }],
|
||||
tool_choice: { type: 'image_generation' },
|
||||
}, { headers: { Authorization: `Bearer ${config.ai.routeraiApiKey}` }, timeout: 120_000 });
|
||||
const imgCall = (res.data?.output || []).find(o => o.type === 'image_generation_call');
|
||||
if (!imgCall?.result) throw new Error('No image in RouterAI response');
|
||||
aiUsage.log({ provider: 'routerai', requestType: 'image_via_responses', model, imageCount: 1, meta: { channel_id: channel.id }, durationMs: Date.now()-started, succeeded: true }).catch(() => {});
|
||||
aiUsage.log({ provider: 'routerai', requestType: 'image_via_responses', model, quality: imgQuality, imageCount: 1, meta: { channel_id: channel.id }, durationMs: Date.now()-started, succeeded: true }).catch(() => {});
|
||||
return Buffer.from(imgCall.result, 'base64');
|
||||
} catch (err) {
|
||||
aiUsage.log({ provider: 'routerai', requestType: 'image_via_responses', model, imageCount: 1, meta: { channel_id: channel.id }, durationMs: Date.now()-started, succeeded: false, errorMessage: (err.response?.data?.error?.message || err.message || '').slice(0, 500) }).catch(() => {});
|
||||
aiUsage.log({ provider: 'routerai', requestType: 'image_via_responses', model, quality: imgQuality, imageCount: 1, meta: { channel_id: channel.id }, durationMs: Date.now()-started, succeeded: false, errorMessage: (err.response?.data?.error?.message || err.message || '').slice(0, 500) }).catch(() => {});
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user