exports.generatePicturePrompt = (project = {}) => { const { title = "", lyrics: lyricsRaw, musicConfig = {}, coverStyle: coverStyleRaw = "", artistName: artistNameRaw = "", } = project || {}; const sanitizeInline = (value = "") => { if (typeof value !== "string") return ""; return value .replace(/[\r\n]+/g, " ") .replace(/[<>]/g, "") .trim(); }; const normalizeForMatching = (value = "") => { if (typeof value !== "string") return ""; return value .normalize("NFD") .replace(/[\u0300-\u036f]/g, "") .toLowerCase(); }; const titleForPrompt = sanitizeInline(title) || "Sans titre"; const artistName = sanitizeInline(artistNameRaw) || sanitizeInline(project?.userName || ""); const hasArtistName = artistName.length > 0; const { genres = [], tempo = "", voice = "", instruments = [], mood = "", } = musicConfig || {}; // Normalise les paroles en tableau de sections { type, lyrics } const lyricsSections = Array.isArray(lyricsRaw) ? lyricsRaw : [ lyricsRaw?.couplet ? { type: "couplet", lyrics: lyricsRaw.couplet } : null, lyricsRaw?.refrain ? { type: "refrain", lyrics: lyricsRaw.refrain } : null, ].filter(Boolean); // Échantillon pour l'ambiance (courtes bribes pour inspirer la direction créative) const lyricsSample = (lyricsSections || []) .map((s) => (s?.lyrics || "").split("\n").slice(0, 2).join(" ")) .filter(Boolean) .slice(0, 6) .join(" | "); // Etiquettes d'ambiance const tags = []; if (Array.isArray(genres) && genres.length) tags.push(`Genres: ${genres.join(", ")}`); if (tempo) tags.push(`Tempo: ${tempo}`); if (Array.isArray(instruments) && instruments.length) tags.push(`Instruments: ${instruments.join(", ")}`); if (voice) tags.push(`Vocal: ${voice}`); if (mood) tags.push(`Mood: ${mood}`); // Guidance palette selon tempo (simple heuristique) const paletteHint = tempo && /\b(rapid|fast|vite|agité|upbeat|energ)/i.test(String(tempo)) ? "Palette vive et contrastée (magenta, cyan, jaune, bleu électrique)" : "Palette harmonieuse et douce (bleu nuit, violet, corail, or pâle)"; const coverStyleInput = String(coverStyleRaw || "").trim(); const coverStyle = sanitizeInline(coverStyleInput); const normalizedStyle = normalizeForMatching(coverStyle); let coverStyleGuidance = coverStyle; if (normalizedStyle.includes("realist")) { coverStyleGuidance = "Style réaliste photographique hyper détaillé, textures fidèles, lumière naturelle, profondeur de champ crédible, aucun effet cartoon, fantastique ou peint"; } const hasTags = tags.length > 0; const tagsLine = hasTags ? `${tags.join( " ; ", )}. Utilise ces indications pour guider uniquement la palette, l'énergie et l'émotion, sans représenter littéralement les instruments, objets ou mots cités.` : "Ambiance sonore non précisée : crée une atmosphère abstraite sans instrument ni objet musical apparent."; const lyricsLine = lyricsSample || "Pas d'extraits fournis"; const styleLine = coverStyleGuidance ? `${coverStyleGuidance}. ${paletteHint}` : `${paletteHint}. Style libre, artistique et lumineux.`; const typographyLine = hasArtistName ? `Reproduis strictement le titre de la chanson ${titleForPrompt} sans modification, sans traduction et sans ajout ou suppression de caractères. Ajoute également le nom de l'artiste ${artistName} de manière artistique, parfaitement lisible et hiérarchisée, en harmonie avec le style abstrait et lumineux de la pochette.` : `Reproduis strictement le titre de la chanson ${titleForPrompt} sans modification, sans traduction et sans ajout ou suppression de caractères. Intègre-le de manière artistique et parfaitement lisible, en harmonie avec le style abstrait et lumineux de la pochette.`; const artistLine = hasArtistName ? ` ${artistName}\n` : ""; const prompt = ` Créer une pochette d'album en adéquation avec les paroles de la musique et qui respecte le style ${coverStyle} ${titleForPrompt} ${artistLine} ${tagsLine} ${lyricsLine} Image carrée 1024x1024 pixels, résolution haute. La composition doit être dynamique et remplir toute la surface, sans laisser de bordures ni de zones vides. ${typographyLine} Aucune faute d'orthographe n'est tolérée. Respecte la casse et l'orthographe exactes du titre fourni. Personnes, visages ou silhouettes reconnaissables. Fonds blancs ou bordures délimitant l'image. Texte illisible ou trop petit. Représenter des instruments ou objets évoqués dans STYLE_MUSICAL : ces informations servent uniquement au contexte audio. `.trim(); return prompt; };