From bede92a5201c72179d0c6e8d02e40748e7aa42c4 Mon Sep 17 00:00:00 2001 From: Alexey Pavlov Date: Mon, 15 Jun 2026 10:20:22 +0300 Subject: [PATCH] =?UTF-8?q?feat:=20post=20image=20diversity=20=E2=80=94=20?= =?UTF-8?q?style=20rotation=20+=20random=20scene/concept=20+=20expanded=20?= =?UTF-8?q?AI=20concepts=20bank?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/services/postImages.js | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/src/services/postImages.js b/src/services/postImages.js index 2084df0..65edcfe 100644 --- a/src/services/postImages.js +++ b/src/services/postImages.js @@ -63,9 +63,11 @@ const IMAGE_PALETTES = { * Генерирует картинку к посту через GPT-5 /v1/responses + image_generation. */ async function generatePostImage({ post, channel, style = {} }) { - // Если задано несколько стилей через запятую — случайно выбираем один - const styleList = (style.image_style || 'flat-illustration') - .split(',').map(s => s.trim()).filter(s => s && s !== 'auto'); + // Если задано несколько стилей через запятую — случайно выбираем один. + // Если стиль не задан или 'auto' — ротация из трёх редакторских стилей. + const DEFAULT_ROTATION = 'realistic-photo,3d-render,flat-illustration'; + const rawStyle = style.image_style && style.image_style !== 'auto' ? style.image_style : DEFAULT_ROTATION; + const styleList = rawStyle.split(',').map(s => s.trim()).filter(Boolean); const pickedStyle = styleList[Math.floor(Math.random() * styleList.length)] || 'flat-illustration'; const imageStyle = IMAGE_STYLES[pickedStyle] || IMAGE_STYLES['flat-illustration']; const palette = style.image_custom_colors @@ -78,10 +80,7 @@ async function generatePostImage({ post, channel, style = {} }) { // Визуальная метафора — конкретный предмет/сцена на основе темы const visualConcept = getPostVisualConcept(post, channel); - // Антураж + свет — меняется по хешу поста (детерминированно, но разнообразно) - let seed = 0; - for (let i = 0; i < post.length && i < 100; i++) seed = (seed * 31 + post.charCodeAt(i)) >>> 0; - + // Антураж + свет — случайный выбор при каждой генерации (намеренно, не детерминированно) const SCENES = [ { setting: 'warm oak desktop surface, afternoon sunlight from left window', lighting: 'golden hour soft shadows', temp: 'warm amber' }, { setting: 'white marble surface, clean studio', lighting: 'flat professional studio', temp: 'cool whites' }, @@ -91,8 +90,11 @@ async function generatePostImage({ post, channel, style = {} }) { { setting: 'glass surface over city lights at night', lighting: 'city glow from below', temp: 'multicolor bokeh' }, { setting: 'antique library floor, surrounded by books, candlelight', lighting: 'warm candlelight side', temp: 'amber parchment' }, { setting: 'frosted glass, winter morning, ice crystals at edges', lighting: 'diffused winter morning', temp: 'icy blues whites' }, + { setting: 'concrete urban rooftop at golden hour, city skyline behind', lighting: 'backlit warm haze', temp: 'golden urban' }, + { setting: 'minimalist white shelf, single object lit from above', lighting: 'clean overhead spotlight', temp: 'pure whites' }, + { setting: 'old wooden table in a sunlit greenhouse, plants around', lighting: 'dappled greenhouse light', temp: 'fresh greens warm' }, ]; - const scene = SCENES[seed % SCENES.length]; + const scene = SCENES[Math.floor(Math.random() * SCENES.length)]; const prompt = `Generate a 16:9 editorial illustration for a social media post. @@ -173,10 +175,7 @@ function getPostVisualConcept(post, channel) { const niche = (channel?.niche || '').toLowerCase(); const combined = t + ' ' + niche; - // Хеш для выбора внутри категории - let seed = 0; - for (let i = 0; i < post.length && i < 80; i++) seed = (seed * 31 + post.charCodeAt(i)) >>> 0; - function pick(arr) { return arr[seed % arr.length]; } + function pick(arr) { return arr[Math.floor(Math.random() * arr.length)]; } const patterns = [ { @@ -188,6 +187,16 @@ function getPostVisualConcept(post, channel) { 'A master key held up to warm light, intricate cuts visible, golden bokeh background', 'A book opening by itself, pages turning rapidly, text rearranging mid-air in warm library', 'An optical prism splitting white light into full spectrum, mounted on dark velvet surface', + 'A chess board mid-game, one piece hovering in the air about to move, dramatic side light', + 'An hourglass frozen mid-flow, sand suspended in air, dark moody background', + 'A single neuron with glowing dendrites branching outward, macro medical illustration style', + 'A telescope pointed at a star map, constellation lines drawn in light, observatory dome open', + 'A maze viewed from above, a single glowing path found through it, aerial minimalist', + 'A blank canvas with a single brushstroke that transforms into a landscape, studio light', + 'Two puzzle pieces clicking together mid-air, warm backlight, close-up macro', + 'A vintage radio with dials, sound waves visible as light trails, dark wood surface', + 'An open toolbox with glowing tools arranged precisely, overhead industrial light', + 'A library ladder reaching impossibly high shelves disappearing into mist, warm amber', ], }, {