mix rhymes

This commit is contained in:
2026-02-23 14:41:25 +01:00
parent 125ac0f40f
commit 8648793d64
2 changed files with 33 additions and 15 deletions
-12
View File
@@ -541,7 +541,6 @@
"resolved": "https://registry.npmjs.org/@google-cloud/firestore/-/firestore-7.11.6.tgz",
"integrity": "sha512-EW/O8ktzwLfyWBOsNuhRoMi8lrC3clHM5LVFhGvO1HCsLozCOOXRAlHrYBoE6HL42Sc8yYMuCb2XqcnJ4OOEpw==",
"license": "Apache-2.0",
"peer": true,
"dependencies": {
"@opentelemetry/api": "^1.3.0",
"fast-deep-equal": "^3.1.1",
@@ -1655,7 +1654,6 @@
"resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz",
"integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==",
"license": "Apache-2.0",
"peer": true,
"engines": {
"node": ">=8.0.0"
}
@@ -1751,7 +1749,6 @@
"resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.25.1.tgz",
"integrity": "sha512-GeT/l6rBYWVQ4XArluLVB6WWQ8flHbdb6r2FCHC3smtdOAbrJBIv35tpV/yp9bmYUJf+xmZpu9DRTIeJVhFbEQ==",
"license": "Apache-2.0",
"peer": true,
"dependencies": {
"@opentelemetry/semantic-conventions": "1.25.1"
},
@@ -2939,7 +2936,6 @@
"resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.25.1.tgz",
"integrity": "sha512-pkZT+iFYIZsVn6+GzM0kSX+u3MSLCY9md+lIJOoKl/P+gJFfxJte/60Usdp8Ce4rOs8GduUpSPNe1ddGyDT1sQ==",
"license": "Apache-2.0",
"peer": true,
"dependencies": {
"@opentelemetry/core": "1.25.1",
"@opentelemetry/semantic-conventions": "1.25.1"
@@ -2982,7 +2978,6 @@
"resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.25.1.tgz",
"integrity": "sha512-9Mb7q5ioFL4E4dDrc4wC/A3NTHDat44v4I3p2pLPSxRvqUbDIQyMVr9uK+EU69+HWhlET1VaSrRzwdckWqY15Q==",
"license": "Apache-2.0",
"peer": true,
"dependencies": {
"@opentelemetry/core": "1.25.1",
"@opentelemetry/resources": "1.25.1",
@@ -3036,7 +3031,6 @@
"resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.25.1.tgz",
"integrity": "sha512-C8k4hnEbc5FamuZQ92nTOp8X/diCY56XUTnMiv9UTuJitCzaNNHAVsdm5+HLCdI8SLQsLWIrG38tddMxLVoftw==",
"license": "Apache-2.0",
"peer": true,
"dependencies": {
"@opentelemetry/core": "1.25.1",
"@opentelemetry/resources": "1.25.1",
@@ -3557,7 +3551,6 @@
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"license": "MIT",
"peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -4384,7 +4377,6 @@
"deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1",
@@ -4879,7 +4871,6 @@
"resolved": "https://registry.npmjs.org/firebase-admin/-/firebase-admin-12.7.0.tgz",
"integrity": "sha512-raFIrOyTqREbyXsNkSHyciQLfv8AUZazehPaQS1lZBSCDYW74FYXU0nQZa3qHI4K+hawohlDbywZ4+qce9YNxA==",
"license": "Apache-2.0",
"peer": true,
"dependencies": {
"@fastify/busboy": "^3.0.0",
"@firebase/database-compat": "1.0.8",
@@ -5184,7 +5175,6 @@
"resolved": "https://registry.npmjs.org/genkit/-/genkit-1.27.0.tgz",
"integrity": "sha512-54OAzw9+dlOs2H4bWnktMwKVA1wwY9XmudKBAz2uBdWhep5r0xHy1qNE6tUVnSgn+LGGaR/0xfYRSs8uqNPFVw==",
"license": "Apache-2.0",
"peer": true,
"dependencies": {
"@genkit-ai/ai": "1.27.0",
"@genkit-ai/core": "1.27.0",
@@ -7838,7 +7828,6 @@
"integrity": "sha512-LZNJgPzfKR+/J3cHkxcpHKpKKvGfDZVPS4hfJCc4cCG0CgYzvlD6yE/S3CIL/Yt91ak327YCpiF/0MyeZHEHKA==",
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@colors/colors": "^1.6.0",
"@dabh/diagnostics": "^2.0.8",
@@ -8025,7 +8014,6 @@
"resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz",
"integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==",
"license": "MIT",
"peer": true,
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}
+33 -3
View File
@@ -82,6 +82,35 @@ const sanitizeStructureEntries = (structure = []) => {
const mapStructureToPrompt = (structure = []) =>
sanitizeStructureEntries(structure).map((entry) => STRUCTURE_PROMPT_LABELS[entry] || entry)
const RHYMES_PRESETS = [
{
matchers: ['avec rimes', 'avec des rimes', 'rimes'],
prompt: 'Rimes riches et variées (rimes finales + internes). Évite les rimes faciles.',
},
{
matchers: ['sans rimes', 'sans rime', 'pas de rimes', 'pas de rime'],
prompt:
"Vers libres sans rimes finales ni schéma de rimes. Évite les rimes intentionnelles, privilégie le rythme et l'imagerie.",
},
{
matchers: ['mélange des deux', 'melange des deux', 'mixte'],
prompt:
'Mélange: alterne sections rimées et sections non rimées. Au moins la moitié des lignes sans rime finale. Quand tu rimes, rimes riches et variées.',
},
]
const resolveRhymesInstruction = (value) => {
if (typeof value === 'string') {
const trimmed = value.trim()
if (!trimmed) return ''
const key = trimmed.toLowerCase()
const preset = RHYMES_PRESETS.find((option) => option.matchers.includes(key))
return preset ? preset.prompt : trimmed
}
if (Array.isArray(value)) return value.join(', ')
return ''
}
// --- MODERATION ---
const buildModerationBrief = ({
@@ -119,6 +148,7 @@ exports.generateLyrics = onCall({}, async ({ auth = {}, data = {} }) => {
structure: rawStructure = ['couplet', 'refrain', 'couplet', 'refrain'],
rhymes = '',
} = data
const rhymesInstruction = resolveRhymesInstruction(rhymes)
// 1. Préparation Structure
const sanitizedStructure = sanitizeStructureEntries(rawStructure)
@@ -135,7 +165,7 @@ exports.generateLyrics = onCall({}, async ({ auth = {}, data = {} }) => {
audience,
emotion,
structure: promptStructure,
rhymes,
rhymes: rhymesInstruction,
}
const moderationInput = buildModerationBrief(moderationPayload)
@@ -172,7 +202,7 @@ Ta spécialité est la **Prosodie** (le rythme naturel des mots) et l'impact ém
TES RÈGLES D'OR :
1. **MÉTRIQUE & RYTHME** : Tes vers doivent être "chantables". Compte les syllabes pour qu'elles collent au style musical demandé. Évite les phrases trop longues ou imprononçables rapidement.
2. **RIMES RICHES** : Évite les rimes faciles (amour/toujours). Cherche des assonances et des rimes internes.
2. **RIMES** : Suis strictement <TYPE_DE_RIMES> du brief. Si "Sans rimes" ou "Mélange des deux" est demandé, respecte l'absence/alternance de rimes. Si rien n'est indiqué, fais des rimes riches et évite les rimes faciles (amour/toujours).
3. **SHOW, DON'T TELL** : N'écris pas "Je suis triste", écris "La pluie brouille mes carreaux". Utilise des détails sensoriels.
4. **STRUCTURE STRICTE** : Respecte exactement l'ordre des sections demandées.
- **Couplet** : Raconte l'histoire, pose le décor.
@@ -199,7 +229,7 @@ Retourne UNIQUEMENT un JSON valide.
<EMOTION_DOMINANTE>${emotion || 'Intense'}</EMOTION_DOMINANTE>
<STYLE_MUSICAL>${style || 'Pop Moderne'}</STYLE_MUSICAL>
<CIBLE>${audience || 'Tout public'}</CIBLE>
<TYPE_DE_RIMES>${rhymes || 'Rimes croisées et riches'}</TYPE_DE_RIMES>
<TYPE_DE_RIMES>${rhymesInstruction || 'Rimes croisées et riches'}</TYPE_DE_RIMES>
</BRIEF_CREATIF>
<STRUCTURE_IMPOSEE>