116 lines
4.7 KiB
JavaScript
116 lines
4.7 KiB
JavaScript
exports.generatePicturePrompt = (project = {}) => {
|
|
const {
|
|
title = '',
|
|
lyrics: lyricsRaw,
|
|
musicConfig = {},
|
|
coverStyle: coverStyleRaw = '',
|
|
artistName: artistNameRaw = '',
|
|
} = project || {}
|
|
|
|
// --- 1. Nettoyage et Normalisation ---
|
|
const sanitizeInline = (value = '') => {
|
|
if (typeof value !== 'string') return ''
|
|
return value
|
|
.replace(/[\r\n]+/g, ' ')
|
|
.replace(/[<>]/g, '')
|
|
.trim()
|
|
}
|
|
|
|
const titleForPrompt = sanitizeInline(title) || 'Sans titre'
|
|
const artistName = sanitizeInline(artistNameRaw) || sanitizeInline(project?.userName || '')
|
|
const hasArtistName = artistName.length > 0
|
|
|
|
const { genres = [], tempo = '', mood = '', instruments = [] } = musicConfig || {}
|
|
const userStyle = sanitizeInline(coverStyleRaw)
|
|
|
|
// --- 2. Intelligence Visuelle (Mapping) ---
|
|
|
|
// Détermination de l'énergie visuelle
|
|
const isEnergetic =
|
|
tempo && /\b(rapid|fast|vite|agité|upbeat|energ|dance|rock|metal)\b/i.test(String(tempo))
|
|
const isDark =
|
|
mood && /\b(sombre|triste|dark|sad|mélancoli|nuit|night|eerie)\b/i.test(String(mood))
|
|
|
|
// Construction de la Palette & Lumière
|
|
let visualAtmosphere = ''
|
|
if (isDark) {
|
|
visualAtmosphere =
|
|
'Atmosphere: Cinematic atmosphere, moody shadows, deep contrast. Palette: Midnight blue, obsidian, deep purple, metallic accents.'
|
|
} else if (isEnergetic) {
|
|
visualAtmosphere =
|
|
'Atmosphere: Dynamic atmosphere, high energy, vibrant saturation. Palette: Neon colors, electric blue, magenta, bright yellow, high contrast.'
|
|
} else {
|
|
visualAtmosphere =
|
|
'Atmosphere: Soft atmosphere, harmonious and ethereal. Palette: Pastel tones, warm gold, soft coral, balanced and elegant colors.'
|
|
}
|
|
|
|
// Définition du Style de Rendu (Si l'utilisateur est vague, on renforce)
|
|
let renderingStyle = userStyle ? `Art Style: ${userStyle}` : 'Art Style: Digital Art, Mixed Media'
|
|
|
|
if (userStyle.toLowerCase().includes('realist') || userStyle.toLowerCase().includes('photo')) {
|
|
renderingStyle +=
|
|
', 8k resolution, highly detailed texture, photorealistic, cinematic depth of field, raytracing.'
|
|
} else if (
|
|
userStyle.toLowerCase().includes('illu') ||
|
|
userStyle.toLowerCase().includes('dessin')
|
|
) {
|
|
renderingStyle +=
|
|
', vector art, clean lines, professional illustration, flat design or detailed painting.'
|
|
} else {
|
|
// Style par défaut "Album Cover" qui marche bien
|
|
renderingStyle += ', abstract surrealism, conceptual album art, high fidelity, masterpiece.'
|
|
}
|
|
|
|
// --- 3. Extraction de l'Inspiration (Lyrics) ---
|
|
|
|
// On cherche le REFRAIN en priorité pour l'image, car c'est le cœur visuel
|
|
const sections = Array.isArray(lyricsRaw) ? lyricsRaw : []
|
|
const chorus = sections.find((s) => s.type === 'refrain' || s.type === 'chorus')
|
|
const verse = sections.find((s) => s.type === 'couplet' || s.type === 'verse')
|
|
|
|
// On prend 2 lignes max du refrain, ou du premier couplet
|
|
const visualHook = (chorus?.lyrics || verse?.lyrics || '')
|
|
.split('\n')
|
|
.filter((l) => l.length > 10) // On évite les lignes trop courtes
|
|
.slice(0, 2)
|
|
.join('. ')
|
|
|
|
const imageryPrompt = visualHook
|
|
? `Visual Inspiration: An interpretation of these lyrics: "${visualHook}".`
|
|
: "Visual Inspiration: Abstract visual representation of the song's mood."
|
|
|
|
// --- 4. Construction du Prompt Final (Structure Optimisée Imagen 3) ---
|
|
|
|
const promptParts = [
|
|
// Rôle
|
|
'Design a professional, high-quality music album cover.',
|
|
|
|
// 1. Le Texte (Crucial pour Imagen 3 - Doit être au début ou très clair)
|
|
`**Typography & Text:**`,
|
|
`The song title "${titleForPrompt}" must be the CENTERPIECE. Write it in a distinct font that matches the mood.`,
|
|
hasArtistName
|
|
? `The artist name "${artistName}" must appear smaller, elegant, and legible near the bottom or top.`
|
|
: '',
|
|
'Ensure perfect spelling. The text should be integrated into the artwork (e.g., metallic texture, neon glow, or bold cut-out), not just pasted on top.',
|
|
|
|
// 2. Le Visuel
|
|
`**Visuals:**`,
|
|
renderingStyle,
|
|
imageryPrompt,
|
|
`Subject: A central visual element that represents the song. ${isEnergetic ? 'Dynamic composition.' : 'Balanced, centered composition.'}`,
|
|
|
|
// 3. L'Atmosphère (Context from music config)
|
|
`**Mood & Color:**`,
|
|
visualAtmosphere,
|
|
genres.length > 0 ? `Musical Vibe Reference: ${genres.join(', ')}.` : '',
|
|
|
|
// 4. Contraintes Négatives (Phrasées positivement pour l'IA)
|
|
'**Constraints:**',
|
|
'Use a square 1:1 aspect ratio.',
|
|
'Do NOT depict literal musical instruments (like guitars or microphones) unless they are part of a surreal abstract composition.',
|
|
'No blurry text. No messy borders. No watermarks.',
|
|
]
|
|
|
|
return promptParts.filter(Boolean).join('\n\n')
|
|
}
|