fix: cover image variety — concrete metaphors + articleId cycling

getVisualMetaphor():
- articleId % array.length как чистый индекс цикличности
- Метафоры конкретные/материальные (ключи, телескопы, часы, книги)
  вместо абстрактных neural nodes которые все выглядят одинаково
- AI категория: 14 метафор (повтор через 14 статей = ~5 дней)
- 11 тематических категорий + 15 универсальных
This commit is contained in:
Ник (Claude)
2026-06-13 09:26:36 +03:00
parent 05fa7644cc
commit 170c7b7b16
+113 -59
View File
@@ -167,7 +167,7 @@ function buildCoverPrompt({ title, tags = [], articleId = 0, channelStyle = null
paletteDesc = PALETTES[channelStyle.image_palette] || null;
}
const visualMetaphor = getVisualMetaphor(title, tags);
const visualMetaphor = getVisualMetaphor(title, tags, articleId);
return `Create a wide 16:9 editorial cover illustration.
@@ -183,112 +183,166 @@ ${channelStyle?.image_prompt_instructions ? `\nCHANNEL STYLE: ${channelStyle.ima
RULE: absolutely no text, no letters, no words, no logos, no real human faces.`;
}
function getVisualMetaphor(title, tags = []) {
/**
* Возвращает уникальную визуальную метафору для обложки.
* articleId гарантирует уникальность даже при одинаковой теме.
* Метафоры — конкретные, материальные, не абстрактные.
*/
function getVisualMetaphor(title, tags = [], articleId = 0) {
const t = (title + ' ' + tags.join(' ')).toLowerCase();
// Чистый index по articleId — каждая новая статья = следующая метафора в цикле
// Гарантирует повторение только через N статей (N = кол-во метафор в категории)
function pick(arr) { return arr[articleId % arr.length]; }
// Тематические паттерны → конкретные визуальные метафоры
const patterns = [
{ kw: ['взлом', 'хакер', 'атак', 'уязвим', 'безопасн', 'hack', 'secur', 'cyber', 'exploit', 'inject', 'фишинг'],
{ kw: ['взлом', 'хакер', 'атак', 'уязвим', 'безопасн', 'hack', 'secur', 'cyber', 'exploit', 'inject', 'фишинг', 'ransomware'],
metaphors: [
'A digital lock being opened by invisible force, streams of binary code dissolving into particles',
'Abstract shield shattering into geometric fragments, neon cracks spreading through dark digital surface',
'A labyrinth of glowing circuits with a single thread breaking through a barrier',
'Mirror reflecting a distorted version of itself, duality and deception made abstract',
'A vintage combination lock under ultraviolet light, tumblers glowing, one tumbler broken open — dark industrial background',
'A glass door with a hairline crack spreading across its surface, red light leaking through the fracture',
'An old steel safe with its door hanging open, interior papers spilling out, emergency light casting harsh shadows',
'A chain with one shattered link, chrome and steel, dramatic spotlight on the break point',
'An antique key duplicating itself in a hall of mirrors, each copy slightly distorted',
'A fingerprint dissolving into scattered pixels under a magnifying glass, neon forensic lab aesthetic',
'A locked filing cabinet surrounded by floating question marks and warning symbols, cinematic lighting',
]
},
{ kw: ['ии', ' ai ', 'нейро', 'llm', 'gpt', 'claude', 'модел', 'neural', 'machine learn', 'deep learn', 'искусственн'],
{ kw: ['ии', ' ai ', 'нейро', 'llm', 'gpt', 'claude', 'модел', 'neural', 'machine learn', 'deep learn', 'искусственн', 'chatgpt'],
metaphors: [
'Abstract neural network nodes pulsing with light, interconnected pathways branching into infinity',
'A geometric brain lattice dissolving at the edges into streams of luminous particles',
'Floating data cubes assembling themselves into emergent patterns, representing machine cognition',
'Concentric rings of light expanding outward from a central pulsing node',
'A vintage typewriter whose keys are being pressed by invisible force, paper emerging with text forming itself',
'An hourglass where sand flows upward, each grain transforming into a tiny glowing letter',
'A book opening by itself in a dark library, pages turning rapidly, text rearranging mid-air',
'An old brass telescope pointed at a sky full of equations instead of stars',
'A clay sculpture being shaped by invisible hands, smooth surfaces revealing complex geometry underneath',
'A single candle flame in darkness, its shadow casting a complex branching pattern on the wall behind',
'A compass spinning wildly then settling on a new direction, surrounded by scattered maps and charts',
'A chess queen piece casting a shadow of an entire army, dramatic chiaroscuro lighting',
'An optical prism splitting white light into spectrum, mounted on dark velvet, macro photography',
'A moth drawn to a glowing lamp, dozens of moths circling, long exposure photography blur',
'A seed germinating in time-lapse, roots and shoots emerging simultaneously, dark soil background',
'A master key on a ring of different keys, held up to light, warm metal tones',
'A musician tuning an instrument by ear, close-up on hands on strings, warm studio light',
'A cartographer sketching an unmapped territory, hand drawing a coastline into blank space',
]
},
{ kw: ['автомат', 'бот', 'automat', 'workflow', 'pipeline', 'скрипт', 'robot', 'n8n', 'make ', 'zapier'],
{ kw: ['автомат', 'бот', 'automat', 'workflow', 'pipeline', 'скрипт', 'robot', 'n8n', 'make ', 'zapier', 'automation'],
metaphors: [
'Elegant gears of light meshing perfectly, each tooth sparking as they turn in unison',
'Abstract conveyor belt transforming raw geometric shapes into refined crystalline forms',
'Overlapping circular flow arrows suggesting perpetual automation, each loop more refined',
'Vintage clockwork mechanism — interlocking brass gears in motion, warm amber light, macro detail',
'A factory assembly line condensed to a tabletop, tiny objects moving through stages, long exposure light trails',
'A domino chain in the moment of falling, each domino a different color, motion blur',
'A switchboard operator desk with hundreds of cables connecting ports, warm retro office lighting',
'Pipes of different materials connecting and merging into one clean output pipe, industrial workshop',
'A rube goldberg sequence frozen in time, multiple contraptions mid-action',
'Time-lapse of a city intersection at night, light trails forming perfect flow patterns',
]
},
{ kw: ['данн', 'аналит', 'data', 'analyt', 'метрик', 'статист', 'chart', 'график'],
{ kw: ['данн', 'аналит', 'data', 'analyt', 'метрик', 'статист', 'chart', 'график', 'seo'],
metaphors: [
'Rivers of light converging from edges to a bright focal point, order emerging from streams',
'Translucent scatter plot in 3D space, clusters of meaning floating in abstract dimension',
'Cascading data streams transforming from chaotic noise into clean organized patterns',
'A vintage stock ticker machine printing endless paper tape, trading floor atmosphere',
'A weather station with multiple instruments all pointing to extremes, storm approaching',
'Cartographer desk with overlapping transparent maps, pins and measurements, candlelight',
'A microscope slide with a complex pattern of cells, lab setting, precise clinical lighting',
'Library card catalog system with infinite drawers, one drawer pulled open revealing complex index',
'A piano with sheet music where the notes form bar chart patterns, concert hall lighting',
'A surveyor theodolite in a field, precision instruments against a dramatic sky',
]
},
{ kw: ['дипфейк', 'голос', 'deepfake', 'voice', 'fraud', 'fake', 'мошенн'],
metaphors: [
'A face dissolving at the edges into a mosaic of pixels, the real becoming uncertain',
'Abstract mask layered over another mask, shadow figures suggesting layered identity',
'Two mirrors facing each other creating infinite regress, reality and reflection indistinguishable',
'A wax museum figure melting slightly at the edges, museum spotlights, uncanny valley',
'Two theatrical masks — comedy and tragedy — but identical, hanging in spotlight',
'A reflection in water that is slightly different from what stands above it, twilight mood',
'Vintage photobooth with curtain closed, multiple shadow silhouettes visible through fabric',
'A hand puppet casting a human-shaped shadow on a wall, single dramatic light source',
'A mirror cracked down the middle, each half showing a different scene',
]
},
{ kw: ['код', 'разработ', 'програм', 'code', 'develop', 'software', 'api', 'github', 'cursor', 'copilot'],
metaphors: [
'Layers of abstract code symbols transforming into crystalline architectural structures',
'A branching tree of glowing paths, each fork representing choices in logic flow',
'Floating geometric modules snapping together like elegant puzzle pieces in zero gravity',
'A craftsman workbench covered in tools, each precisely placed, wood shavings on floor, workshop window light',
'An architect drafting table with blueprints unrolled, compass and ruler in use, desk lamp',
'A vintage telephone exchange switchboard, operator perspective, warm bulb lights',
'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 a different texture, golden hour',
'An open laptop in a dark room, only the screen light illuminating the workspace, code reflection on glasses',
]
},
{ kw: ['seo', 'маркетинг', 'контент', 'реклам', 'marketing', 'content', 'growth', 'продвиж'],
{ kw: ['маркетинг', 'контент', 'реклам', 'marketing', 'content', 'growth', 'продвиж', 'аудитор'],
metaphors: [
'Abstract particles rising in an upward spiral, accelerating as they approach the light',
'Geometric shapes spontaneously organizing from scattered chaos into perfect aligned grid',
'A single beam cutting through layered fog, illuminating a clear path forward',
'A megaphone lying on a table, vintage brass, city map spread underneath it',
'A fishing rod cast into a sea of business cards, one card caught on the hook',
'A vendor market stall being set up, colorful awning, products arranged attractively, morning light',
'Seeds being planted in geometric rows, birds-eye view, garden tools aside, spring light',
'A lighthouse beam sweeping over a foggy harbor, ships turning toward the light',
'A street performer drawing a large crowd, performer perspective from stage, golden sunset',
]
},
{ kw: ['email', 'рассылк', 'письм', 'newsletter', 'inbox'],
metaphors: [
'Paper planes of light streaming outward from a central pulsing source in all directions',
'Abstract envelopes unfolding into origami shapes that take flight as geometric birds',
'Digital waves radiating concentrically outward, each ring more refined and intentional',
'A vintage mailbox overflowing with envelopes, country road, afternoon light',
'A writing desk with fountain pen mid-sentence on paper, wax seal nearby, window light',
'Hundreds of paper airplanes suspended in air radiating from a single point, white room',
'A postal sorting office with letters on conveyor, warm institutional lighting',
'A message in a bottle washing ashore, ocean at golden hour, single perfect wave',
]
},
{ kw: ['vector', 'embed', 'pinecone', 'база знаний', 'rag ', 'retriev', 'weaviate', 'pgvector'],
{ kw: ['prompt', 'промпт', 'инжиниринг', 'instruct', 'few-shot', 'chain', 'копирайт'],
metaphors: [
'Multi-dimensional space: glowing constellation points clustering by invisible forces of meaning',
'Abstract geometric lattice stretching to infinity, nodes connected by silk-thin lines',
'A library of light — glowing geometric books organized in vast abstract infinite space',
'A sculptor chiseling marble, chips flying, emerging form just visible, dramatic studio lighting',
'A translator desk with multiple open dictionaries and handwritten notes between them',
'A cook adjusting seasoning over a pot, herbs and spices scattered artfully on counter',
'A jeweler using loupe to set a tiny gem, precision tools, warm workshop light',
'A conductor baton frozen mid-gesture, orchestra music sheets visible below',
]
},
{ kw: ['prompt', 'промпт', 'инжиниринг', 'instruct', 'few-shot', 'chain'],
{ kw: ['vector', 'embed', 'база знаний', 'rag ', 'pinecone', 'weaviate', 'langchain', 'llamaindex'],
metaphors: [
'Abstract command flowing as light through a series of transforming geometric gates',
'A sculptor chisel made of light, shaping formless material into precise form',
'Words becoming shapes becoming outcomes — a visual sequence of transformation',
'A vast library card catalog extending to infinite depth, one card pulled mid-search',
'A specimen collection in glass cases, each specimen precisely labeled, natural history museum',
'A wine cellar with bottles organized in a complex system, sommelier consulting notes',
'A large cork pinboard covered in photos and strings connecting them, detective war room',
'A seed bank vault with thousands of labeled drawers, clinical cold light',
]
},
{ kw: ['продуктив', 'задач', 'workflow', 'менеджмент', 'таск', 'task', 'agile', 'sprint'],
metaphors: [
'A physical inbox/outbox tray system stacked high on wooden desk, morning office light',
'A large whiteboard covered in sticky notes being organized by unseen hands',
'A craftsman apron with every tool in its pocket, each in perfect order',
'Calendar pages turning on a desk, one date circled in red, pen nearby',
]
},
];
for (const { kw, metaphors } of patterns) {
if (kw.some(k => t.includes(k))) {
// Детерминированный но разнообразный выбор по хешу заголовка
let seed = 0;
for (let i = 0; i < title.length; i++) seed = (seed * 31 + title.charCodeAt(i)) >>> 0;
return metaphors[seed % metaphors.length];
return pick(metaphors);
}
}
// Универсальные метафоры — конкретные и разнообразные
const generic = [
'Abstract architectural forms assembling from scattered fragments into a coherent whole',
'Geometric light rays converging from multiple directions into a single illuminated focal point',
'Flowing liquid-like shapes morphing and transforming, suggesting evolution and emergence',
'A horizon where two contrasting worlds meet — ordered and organic — in perfect visual tension',
'Cascading layers of translucent geometric planes revealing depth and hidden complexity',
'Crystalline growth pattern emerging organically from a single seed point into elaborate structure',
'Diagonal force lines cutting through deep negative space with directional energy and purpose',
'Nested geometric forms expanding outward from center like a visual echo in still water',
'Abstract topography of peaks and valleys formed by data, landscape of pure information',
'A vortex of geometric elements spiraling inward toward a luminous center of clarity',
'A single lighthouse on a rocky coast at dusk, warm light in the tower, storm approaching from sea',
'A vintage globe being spun by unseen hands, old map colors, library atmosphere',
'A hand planting a seed in rich dark soil, morning mist in background, close-up',
'An empty stage with a single spotlight on a plain wooden chair, theatre atmosphere',
'A vintage compass on a worn leather journal, mountain wilderness in background',
'A mason jar filled with fireflies, summer night, porch railing, blurred trees behind',
'An old film projector casting beam of light, dust particles visible, cinema darkness',
'A door slightly ajar, warm light escaping, curious perspective from hallway',
'A ladder leaning against a wall reaching above the clouds, surreal realistic style',
'A single match being struck in complete darkness, dramatic flare, close-up',
'A crossroads sign pointing in four different directions, fog, gravel road, dawn',
'A paper boat on still water, single ripple expanding outward, minimalist',
'An old radio being tuned, backlit frequency dial, warm evening light',
'A telescope pointed skyward from a rooftop, city lights below, stars above',
'A bridge in fog, one end visible, other end disappearing into mist, pedestrian perspective',
];
let seed = 0;
for (let i = 0; i < title.length; i++) seed = (seed * 31 + title.charCodeAt(i)) >>> 0;
return generic[seed % generic.length];
return pick(generic);
}
async function generateCoverViaRouterAI({ prompt }) {
const base = config.ai.routeraiBaseUrl;
const key = config.ai.routeraiApiKey;