last fixes, home and videos
This commit is contained in:
+81
-20
@@ -7,7 +7,6 @@ const {
|
||||
} = require("../config/suno");
|
||||
const { SUNO_API_KEY } = require("../config/keys");
|
||||
const axios = require("axios");
|
||||
const admin = require("firebase-admin");
|
||||
const { FieldValue } = require("firebase-admin/firestore");
|
||||
const { refList } = require("../index");
|
||||
|
||||
@@ -41,7 +40,7 @@ const STRUCTURE_ALIASES = {
|
||||
"intro instrumentale longue": "long_intro",
|
||||
"pré-refrain": "pre_refrain_instrumental",
|
||||
"pre-refrain": "pre_refrain_instrumental",
|
||||
"pre_refrain": "pre_refrain_instrumental",
|
||||
pre_refrain: "pre_refrain_instrumental",
|
||||
"pre chorus": "pre_refrain_instrumental",
|
||||
"pre-chorus": "pre_refrain_instrumental",
|
||||
prechorus: "pre_refrain_instrumental",
|
||||
@@ -62,7 +61,9 @@ const STRUCTURE_ALIASES = {
|
||||
};
|
||||
|
||||
const normalizeStructureValue = (value) => {
|
||||
const raw = String(value || "").trim().toLowerCase();
|
||||
const raw = String(value || "")
|
||||
.trim()
|
||||
.toLowerCase();
|
||||
if (!raw) return "";
|
||||
if (STRUCTURE_PROMPT_LABELS[raw]) return raw;
|
||||
if (STRUCTURE_ALIASES[raw]) return STRUCTURE_ALIASES[raw];
|
||||
@@ -160,9 +161,7 @@ const moderationIndicatesBlock = (moderation = {}, fallbackText = "") => {
|
||||
const excerpts = Array.isArray(moderation.excerpts)
|
||||
? moderation.excerpts
|
||||
: [];
|
||||
const reasons = Array.isArray(moderation.reasons)
|
||||
? moderation.reasons
|
||||
: [];
|
||||
const reasons = Array.isArray(moderation.reasons) ? moderation.reasons : [];
|
||||
|
||||
const keywordDetected = (value) =>
|
||||
typeof value === "string" && TOXIC_KEYWORDS.some((rx) => rx.test(value));
|
||||
@@ -182,12 +181,7 @@ exports.generateLyrics = onCall({}, async ({ auth = {}, data = {} }) => {
|
||||
style = "",
|
||||
audience = "",
|
||||
emotion = "",
|
||||
structure: rawStructure = [
|
||||
"couplet",
|
||||
"refrain",
|
||||
"couplet",
|
||||
"refrain",
|
||||
],
|
||||
structure: rawStructure = ["couplet", "refrain", "couplet", "refrain"],
|
||||
rhymes = "",
|
||||
} = data;
|
||||
|
||||
@@ -248,14 +242,14 @@ exports.generateLyrics = onCall({}, async ({ auth = {}, data = {} }) => {
|
||||
|
||||
const system = `
|
||||
Tu es un parolier expert en chanson française moderne et populaire.
|
||||
Tu écris des chansons marquantes, accessibles, sur des thématiques d'innovation, d'esprit d'équipe et de créativité digitale.
|
||||
Ton écriture doit toucher à la fois l'humain, le collectif et la passion d'entreprendre.
|
||||
Analyse attentivement les informations placées entre balises XML-like.
|
||||
Génère un titre accrocheur et mémorable en plus des paroles, tout en respectant strictement la structure demandée.
|
||||
Retourne uniquement un JSON conforme au schéma fourni, sans ajouter d'autres textes.
|
||||
`.trim();
|
||||
|
||||
const structureTags = (Array.isArray(promptStructure) ? promptStructure : [])
|
||||
const structureTags = (
|
||||
Array.isArray(promptStructure) ? promptStructure : []
|
||||
)
|
||||
.map((part, index) => {
|
||||
const content = part || "";
|
||||
return ` <SECTION ordre="${index + 1}">${content}</SECTION>`;
|
||||
@@ -314,14 +308,12 @@ ${structureTags || fallbackStructureTags}
|
||||
lyrics: z
|
||||
.string()
|
||||
.describe(
|
||||
"Paroles de la section, chaque ligne séparée " +
|
||||
"par un retour à la ligne",
|
||||
"Paroles de la section, chaque ligne séparée par un retour à la ligne",
|
||||
),
|
||||
}),
|
||||
)
|
||||
.describe(
|
||||
"Paroles de la chanson sous forme de tableau de sections " +
|
||||
"structurées.",
|
||||
"Paroles de la chanson sous forme de tableau de sections structurées.",
|
||||
),
|
||||
lyricsDescription: z
|
||||
.string()
|
||||
@@ -339,6 +331,74 @@ ${structureTags || fallbackStructureTags}
|
||||
}
|
||||
});
|
||||
|
||||
const severityScore = (severity = "") => {
|
||||
const normalized = String(severity || "").toLowerCase();
|
||||
switch (normalized) {
|
||||
case "critical":
|
||||
return 4;
|
||||
case "high":
|
||||
return 3;
|
||||
case "medium":
|
||||
return 2;
|
||||
case "low":
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
const softenModerationDecision = (rawResult = {}) => {
|
||||
const result = { ...rawResult };
|
||||
const excerpts = Array.isArray(result.excerpts) ? result.excerpts : [];
|
||||
const reasons = Array.isArray(result.reasons) ? result.reasons : [];
|
||||
|
||||
const highestSeverity = excerpts.reduce(
|
||||
(max, excerpt) => Math.max(max, severityScore(excerpt?.severity)),
|
||||
0,
|
||||
);
|
||||
const score =
|
||||
typeof result.score === "number" && !Number.isNaN(result.score)
|
||||
? Math.min(Math.max(result.score, 0), 1)
|
||||
: 0;
|
||||
|
||||
const narrativeHint = reasons.some((reason) =>
|
||||
/narrati|story|persona|fiction|metaphor|metaphore|récit|roleplay|contexte/i.test(
|
||||
reason || "",
|
||||
),
|
||||
);
|
||||
|
||||
const adjustments = [];
|
||||
|
||||
if (result.blocked) {
|
||||
const shouldUnblockLowSeverity = highestSeverity <= 1 && score < 0.65;
|
||||
if (shouldUnblockLowSeverity) {
|
||||
result.blocked = false;
|
||||
adjustments.push("auto-unblock-low-severity");
|
||||
}
|
||||
}
|
||||
|
||||
if (!result.blocked && result.flagged) {
|
||||
const lowSignal = highestSeverity <= 1 && score < 0.4;
|
||||
const contextual = narrativeHint && highestSeverity <= 2 && score < 0.55;
|
||||
if (lowSignal) {
|
||||
result.flagged = false;
|
||||
adjustments.push("drop-flag-low-signal");
|
||||
} else if (contextual) {
|
||||
result.flagged = false;
|
||||
adjustments.push("drop-flag-contextual");
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
...result,
|
||||
moderationAdjustments: adjustments,
|
||||
moderationCalibration: {
|
||||
highestSeverity,
|
||||
score,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
// Vérifie la toxicité des paroles via Gemini et retourne un résultat structuré
|
||||
// Nom Cloud Function: lyrics-analyseLyricsToxicity
|
||||
exports.analyseLyricsToxicity = onCall({}, async ({ data = {} }) => {
|
||||
@@ -364,10 +424,11 @@ exports.analyseLyricsToxicity = onCall({}, async ({ data = {} }) => {
|
||||
});
|
||||
|
||||
const parsed = requestSchema.parse(data || {});
|
||||
const result = await analyseLyrics({
|
||||
const aiResult = await analyseLyrics({
|
||||
title: parsed.title || "",
|
||||
lyrics: parsed.lyrics,
|
||||
});
|
||||
const result = softenModerationDecision(aiResult);
|
||||
|
||||
// Prépare un message lisible pour le front
|
||||
const highCats = Object.entries(result.categories || {})
|
||||
|
||||
Reference in New Issue
Block a user