new song structure
This commit is contained in:
+80
-7
@@ -10,6 +10,67 @@ const axios = require("axios");
|
||||
const admin = require("firebase-admin");
|
||||
const { refList } = require("../index");
|
||||
|
||||
const STRUCTURE_PROMPT_LABELS = {
|
||||
couplet: "couplet",
|
||||
refrain: "refrain",
|
||||
short_intro: "introduction instrumentale courte",
|
||||
long_intro: "introduction instrumentale longue",
|
||||
pre_chorus: "pré-refrain",
|
||||
};
|
||||
|
||||
const STRUCTURE_ALIASES = {
|
||||
"short intro": "short_intro",
|
||||
"introduction instrumentale courte": "short_intro",
|
||||
"intro instrumentale courte": "short_intro",
|
||||
"long intro": "long_intro",
|
||||
"introduction instrumentale longue": "long_intro",
|
||||
"intro instrumentale longue": "long_intro",
|
||||
"pré-refrain": "pre_chorus",
|
||||
"pre-refrain": "pre_chorus",
|
||||
"pre chorus": "pre_chorus",
|
||||
"pre-chorus": "pre_chorus",
|
||||
prechorus: "pre_chorus",
|
||||
};
|
||||
|
||||
const normalizeStructureValue = (value) => {
|
||||
const raw = String(value || "").trim().toLowerCase();
|
||||
if (!raw) return "";
|
||||
if (STRUCTURE_PROMPT_LABELS[raw]) return raw;
|
||||
if (STRUCTURE_ALIASES[raw]) return STRUCTURE_ALIASES[raw];
|
||||
const sanitized = raw.replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
|
||||
if (STRUCTURE_PROMPT_LABELS[sanitized]) return sanitized;
|
||||
if (STRUCTURE_ALIASES[sanitized]) return STRUCTURE_ALIASES[sanitized];
|
||||
return sanitized;
|
||||
};
|
||||
|
||||
const sanitizeStructureEntries = (structure = []) => {
|
||||
if (!Array.isArray(structure)) return [];
|
||||
const output = [];
|
||||
structure.forEach((entry) => {
|
||||
const normalized = normalizeStructureValue(entry);
|
||||
if (!normalized) return;
|
||||
if (normalized === "short_intro" || normalized === "long_intro") {
|
||||
const existingIndex = output.findIndex(
|
||||
(item) => item === "short_intro" || item === "long_intro",
|
||||
);
|
||||
if (existingIndex !== -1) output.splice(existingIndex, 1);
|
||||
output.push(normalized);
|
||||
return;
|
||||
}
|
||||
if (normalized === "pre_chorus") {
|
||||
if (!output.includes("pre_chorus")) output.push("pre_chorus");
|
||||
return;
|
||||
}
|
||||
output.push(normalized);
|
||||
});
|
||||
return output;
|
||||
};
|
||||
|
||||
const mapStructureToPrompt = (structure = []) =>
|
||||
sanitizeStructureEntries(structure).map(
|
||||
(entry) => STRUCTURE_PROMPT_LABELS[entry] || entry,
|
||||
);
|
||||
|
||||
const TOXIC_KEYWORDS = [
|
||||
/\bnazis?\b/i,
|
||||
/\bnazisme\b/i,
|
||||
@@ -39,8 +100,9 @@ const buildModerationBrief = ({
|
||||
`<RIMES>${Array.isArray(rhymes) ? rhymes.join(", ") : rhymes || ""}</RIMES>`,
|
||||
];
|
||||
|
||||
if (Array.isArray(structure) && structure.length) {
|
||||
sections.push(`<STRUCTURE>${structure.join(" | ")}</STRUCTURE>`);
|
||||
const promptStructure = mapStructureToPrompt(structure);
|
||||
if (promptStructure.length) {
|
||||
sections.push(`<STRUCTURE>${promptStructure.join(" | ")}</STRUCTURE>`);
|
||||
}
|
||||
|
||||
return `<BRIEF_UTILISATEUR>\n${sections.join("\n")}\n</BRIEF_UTILISATEUR>`;
|
||||
@@ -76,17 +138,29 @@ exports.generateLyrics = onCall({}, async ({ auth = {}, data = {} }) => {
|
||||
style = "",
|
||||
audience = "",
|
||||
emotion = "",
|
||||
structure = ["couplet", "refrain", "couplet", "refrain"],
|
||||
structure: rawStructure = [
|
||||
"couplet",
|
||||
"refrain",
|
||||
"couplet",
|
||||
"refrain",
|
||||
],
|
||||
rhymes = "",
|
||||
} = data;
|
||||
|
||||
const sanitizedStructure = sanitizeStructureEntries(rawStructure);
|
||||
const promptStructure = sanitizedStructure.length
|
||||
? sanitizedStructure.map(
|
||||
(entry) => STRUCTURE_PROMPT_LABELS[entry] || entry,
|
||||
)
|
||||
: [];
|
||||
|
||||
const moderationPayload = {
|
||||
objective,
|
||||
context,
|
||||
style,
|
||||
audience,
|
||||
emotion,
|
||||
structure,
|
||||
structure: promptStructure,
|
||||
rhymes,
|
||||
};
|
||||
|
||||
@@ -137,7 +211,7 @@ Génère un titre accrocheur et mémorable en plus des paroles, tout en respecta
|
||||
Retourne uniquement un JSON conforme au schéma fourni, sans ajouter d'autres textes.
|
||||
`.trim();
|
||||
|
||||
const structureTags = (Array.isArray(structure) ? structure : [])
|
||||
const structureTags = (Array.isArray(promptStructure) ? promptStructure : [])
|
||||
.map((part, index) => {
|
||||
const content = part || "";
|
||||
return ` <SECTION ordre="${index + 1}">${content}</SECTION>`;
|
||||
@@ -191,8 +265,7 @@ ${structureTags || fallbackStructureTags}
|
||||
type: z
|
||||
.string()
|
||||
.describe(
|
||||
'Type de section : "couplet" ou "refrain" ' +
|
||||
"selon la structure",
|
||||
"Type de section : respecter exactement le nom de la section demandé dans la structure",
|
||||
),
|
||||
lyrics: z
|
||||
.string()
|
||||
|
||||
Reference in New Issue
Block a user