forked from admin/zeropost-engine
fix: post images diversity — SUBJECT+SETTING+LIGHTING prompt
Та же проблема что и у обложек статей: старый промт 'Topic essence: первые 250 символов' был слишком абстрактным → модель рисовала свой дефолт (тёмный фон + геометрия) Новый промт (3 некофликтующих параметра): VISUAL CONCEPT: конкретный предмет из getPostVisualConcept() SETTING: физический антураж (8 вариантов по seed из текста поста) LIGHTING + COLOR TEMPERATURE: конкретный свет getPostVisualConcept(): 8 тематических категорий × 4-6 концептов AI, automation, cybersec, code, marketing, money, education, health + 12 универсальных концептов Seed = hash первых 80 символов поста → детерминировано но уникально
This commit is contained in:
+145
-7
@@ -75,15 +75,36 @@ async function generatePostImage({ post, channel, style = {} }) {
|
||||
// Извлекаем суть поста для промпта (первые 250 символов)
|
||||
const postExcerpt = post.replace(/[#*_`>]/g, '').slice(0, 250);
|
||||
|
||||
const prompt = `Editorial illustration for a social media post. Topic essence: "${postExcerpt}"
|
||||
// Визуальная метафора — конкретный предмет/сцена на основе темы
|
||||
const visualConcept = getPostVisualConcept(post, channel);
|
||||
|
||||
Style: ${imageStyle.prompt}.
|
||||
${palette ? `Color palette: ${palette}.` : ''}
|
||||
Channel context: ${channel.niche || channel.name}.
|
||||
${style.image_prompt_instructions ? `\nChannel visual guidelines: ${style.image_prompt_instructions}` : ''}
|
||||
// Антураж + свет — меняется по хешу поста (детерминированно, но разнообразно)
|
||||
let seed = 0;
|
||||
for (let i = 0; i < post.length && i < 100; i++) seed = (seed * 31 + post.charCodeAt(i)) >>> 0;
|
||||
|
||||
Composition: 16:9 wide format, balanced, suitable for social media.
|
||||
Strictly: no text, no letters, no logos, no faces of real people.`;
|
||||
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' },
|
||||
{ setting: 'dark slate table, single focused overhead spotlight', lighting: 'dramatic single point', temp: 'high contrast' },
|
||||
{ setting: 'weathered wooden workbench, overcast daylight', lighting: 'soft even overcast', temp: 'muted naturals' },
|
||||
{ setting: 'black velvet surface, rim lighting from behind', lighting: 'rim lit glowing edges', temp: 'rich blacks gold' },
|
||||
{ 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' },
|
||||
];
|
||||
const scene = SCENES[seed % SCENES.length];
|
||||
|
||||
const prompt = `Generate a 16:9 editorial illustration for a social media post.
|
||||
|
||||
VISUAL CONCEPT: ${visualConcept}
|
||||
SETTING: ${scene.setting}
|
||||
LIGHTING: ${scene.lighting}
|
||||
COLOR TEMPERATURE: ${scene.temp}
|
||||
${style.image_custom_colors ? `BRAND PALETTE: ${style.image_custom_colors}` : (palette ? `PALETTE: ${palette}` : '')}
|
||||
STYLE: ${imageStyle.prompt}
|
||||
${style.image_prompt_instructions ? `CHANNEL STYLE: ${style.image_prompt_instructions}` : ''}
|
||||
|
||||
RULES: no text, no letters, no logos, no real human faces.`;
|
||||
|
||||
// Единственный провайдер: routerai /responses + gpt-5-image-mini
|
||||
// Цена: ~₽2.72/картинка. quality параметр не работает, всегда high.
|
||||
@@ -142,3 +163,120 @@ Strictly: no text, no letters, no logos, no faces of real people.`;
|
||||
}
|
||||
|
||||
module.exports = { generatePostImage, IMAGE_STYLES, IMAGE_PALETTES };
|
||||
|
||||
/**
|
||||
* Извлекает визуальный концепт из текста поста.
|
||||
* Конкретные, материальные образы — не абстрактные.
|
||||
*/
|
||||
function getPostVisualConcept(post, channel) {
|
||||
const t = post.toLowerCase();
|
||||
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]; }
|
||||
|
||||
const patterns = [
|
||||
{
|
||||
kw: ['ии', ' ai ', 'нейро', 'llm', 'gpt', 'claude', 'chatgpt', 'искусственн', 'neural'],
|
||||
concepts: [
|
||||
'A vintage typewriter with keys pressing by invisible force, paper emerging with glowing text',
|
||||
'An old brass compass spinning and settling on a new direction, surrounded by scattered maps',
|
||||
'A seed germinating in dark soil, roots and shoots emerging simultaneously, close-up macro',
|
||||
'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',
|
||||
],
|
||||
},
|
||||
{
|
||||
kw: ['автомат', 'бот', 'automat', 'workflow', 'n8n', 'zapier', 'make', 'скрипт'],
|
||||
concepts: [
|
||||
'Vintage clockwork mechanism — interlocking brass gears in motion, macro close-up, amber light',
|
||||
'A domino chain in the moment of falling, each piece a different color, motion blur',
|
||||
'Factory assembly line condensed to a tabletop, small objects moving through stages, long exposure',
|
||||
'A rube goldberg sequence frozen mid-action, multiple contraptions in motion',
|
||||
'Time-lapse of a city intersection at night, light trails forming perfect flow patterns',
|
||||
],
|
||||
},
|
||||
{
|
||||
kw: ['взлом', 'хакер', 'безопасн', 'фишинг', 'вирус', 'cyber', 'hack', 'secur'],
|
||||
concepts: [
|
||||
'A vintage combination lock under dramatic side lighting, tumblers visible, dark background',
|
||||
'A glass door with a hairline crack spreading, red emergency light leaking through fracture',
|
||||
'An old steel safe door hanging slightly open, papers spilling out, harsh spotlight',
|
||||
'A chain with one shattered link, chrome and steel, dramatic spotlight on break point',
|
||||
],
|
||||
},
|
||||
{
|
||||
kw: ['код', 'разработ', 'програм', 'code', 'develop', 'software', 'api', 'github'],
|
||||
concepts: [
|
||||
'A craftsman workbench covered in precision tools, each perfectly placed, workshop window light',
|
||||
'An architect drafting table with blueprints unrolled, compass and ruler in use, desk lamp',
|
||||
'Knitting needles mid-row on a complex pattern, wool threads crossing precisely, natural light',
|
||||
'A mason building a wall one brick at a time, each brick different texture, golden hour',
|
||||
],
|
||||
},
|
||||
{
|
||||
kw: ['маркетинг', 'реклам', 'продвиж', 'seo', 'контент', 'growth', 'аудитор'],
|
||||
concepts: [
|
||||
'A megaphone lying on a table, vintage brass, city map spread underneath it',
|
||||
'Seeds being planted in geometric rows, birds-eye view, garden tools aside, spring light',
|
||||
'A lighthouse beam sweeping over foggy harbor, ships turning toward the light',
|
||||
'A vendor market stall being set up attractively, colorful awning, morning light',
|
||||
],
|
||||
},
|
||||
{
|
||||
kw: ['деньг', 'финанс', 'инвест', 'бизнес', 'прибыл', 'доход', 'money', 'business'],
|
||||
concepts: [
|
||||
'A vintage scale perfectly balanced with different objects on each side, warm studio light',
|
||||
'Stack of different vintage coins photographed from above, macro, warm lighting',
|
||||
'A piggy bank on a wooden surface with a single coin mid-air above it, soft focus',
|
||||
'Growing seedlings in small pots arranged by height, morning light through window',
|
||||
],
|
||||
},
|
||||
{
|
||||
kw: ['обучен', 'курс', 'урок', 'учеб', 'знан', 'навык', 'learn', 'educat'],
|
||||
concepts: [
|
||||
'Open textbook with handwritten notes in margins, pencil resting on page, desk lamp',
|
||||
'Stack of colorful books with a cup of coffee, cozy reading corner, soft morning light',
|
||||
'A graduation mortarboard on stack of books, warm sunlight from side',
|
||||
'Hands writing in a notebook, pen visible, blurred background of bookshelf',
|
||||
],
|
||||
},
|
||||
{
|
||||
kw: ['здоровь', 'спорт', 'фитнес', 'еда', 'питан', 'health', 'fit', 'food'],
|
||||
concepts: [
|
||||
'Fresh vegetables arranged artfully on white surface, overhead shot, natural light',
|
||||
'Running shoes on wooden floor, morning light casting long shadows',
|
||||
'A glass of water with ice and mint, condensation visible, clean white background',
|
||||
'Yoga mat rolled out near window with morning light streaming in',
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
for (const { kw, concepts } of patterns) {
|
||||
if (kw.some(k => combined.includes(k))) {
|
||||
return pick(concepts);
|
||||
}
|
||||
}
|
||||
|
||||
// Универсальные — нейтральные но конкретные
|
||||
const generic = [
|
||||
'A single lighthouse on rocky coast at dusk, warm light in tower, dramatic sky',
|
||||
'An empty stage with single spotlight on plain wooden chair, theatre atmosphere',
|
||||
'A vintage compass on worn leather journal, mountain wilderness background',
|
||||
'A door slightly ajar with warm light escaping, curious hallway perspective',
|
||||
'A single match being struck in complete darkness, dramatic flare close-up',
|
||||
'A crossroads sign in fog, gravel road, dawn light breaking through',
|
||||
'A paper boat on still water, single ripple expanding outward, minimalist',
|
||||
'An old film projector casting beam of light, dust particles visible, cinema',
|
||||
'A telescope pointed skyward from rooftop, city lights below, stars above',
|
||||
'A bridge disappearing into morning fog, pedestrian perspective',
|
||||
'A ceramic coffee cup with steam rising, morning light through window',
|
||||
'An open notebook with a pen and fern plant, flat lay, natural light',
|
||||
];
|
||||
|
||||
return pick(generic);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user