manage errors
This commit is contained in:
+71
-13
@@ -1,4 +1,4 @@
|
||||
const { onCall, onRequest } = require("firebase-functions/v2/https");
|
||||
const { onCall, onRequest, HttpsError } = require("firebase-functions/v2/https");
|
||||
const axios = require("axios");
|
||||
const admin = require("firebase-admin");
|
||||
const { logger } = require("firebase-functions/logger");
|
||||
@@ -14,6 +14,46 @@ const {
|
||||
// Initialiser Firestorey
|
||||
const db = admin.firestore();
|
||||
|
||||
/**
|
||||
* Marque un projet comme échoué suite à une erreur Suno
|
||||
* @param {string} projectId - Identifiant du projet
|
||||
* @param {Object} error - Erreur capturée (axios)
|
||||
*/
|
||||
async function markProjectMusicFailure(projectId, error) {
|
||||
if (!projectId) return;
|
||||
try {
|
||||
const docRef = db.collection("projects").doc(projectId);
|
||||
const status = error?.response?.status || error?.status || null;
|
||||
const sunoMessage =
|
||||
error?.response?.data?.msg ||
|
||||
error?.response?.data?.message ||
|
||||
error?.message ||
|
||||
"Erreur lors de la génération de musique";
|
||||
const errorPayload = {
|
||||
source: "SUNO_API",
|
||||
message: sunoMessage,
|
||||
};
|
||||
if (status) errorPayload.status = status;
|
||||
if (error?.code) errorPayload.code = error.code;
|
||||
|
||||
await docRef.set(
|
||||
{
|
||||
musicStatus: "FAILED",
|
||||
sunoTaskId: admin.firestore.FieldValue.delete(),
|
||||
generationStartAt: admin.firestore.FieldValue.delete(),
|
||||
musicError: errorPayload,
|
||||
updatedAt: admin.firestore.FieldValue.serverTimestamp(),
|
||||
},
|
||||
{ merge: true }
|
||||
);
|
||||
} catch (err) {
|
||||
console.error(
|
||||
"❌ [generateMusic] Impossible de marquer le projet en erreur:",
|
||||
err
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Limite la longueur d'une chaîne
|
||||
* @param {string} str - La chaîne à limiter
|
||||
@@ -40,7 +80,7 @@ function extractVoiceStrings(voice) {
|
||||
}
|
||||
if (typeof voice === "object") {
|
||||
return Object.values(voice).filter(
|
||||
(v) => typeof v === "string" && v.trim(),
|
||||
(v) => typeof v === "string" && v.trim()
|
||||
);
|
||||
}
|
||||
return [];
|
||||
@@ -94,7 +134,7 @@ function detectVocalGender(voiceInput = "") {
|
||||
if (Array.isArray(voiceInput)) {
|
||||
const baseItem = voiceInput.find(
|
||||
(v) =>
|
||||
v && (v.category === "base" || v?.category?.toLowerCase() === "base"),
|
||||
v && (v.category === "base" || v?.category?.toLowerCase() === "base")
|
||||
);
|
||||
const text = baseItem ? baseItem.value || baseItem.text || baseItem : null;
|
||||
if (text) return detectVocalGender(text);
|
||||
@@ -306,7 +346,7 @@ exports.generateMusic = onCall(async ({ data = {} }) => {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${SUNO_API_KEY}`,
|
||||
},
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const parsed = response.data;
|
||||
@@ -325,9 +365,26 @@ exports.generateMusic = onCall(async ({ data = {} }) => {
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("❌ Erreur lors de la génération de musique:", error);
|
||||
throw new Error(
|
||||
`Erreur lors de la génération de musique: ${error.message}`,
|
||||
);
|
||||
try {
|
||||
await markProjectMusicFailure(data?.projectId, error);
|
||||
} catch (markErr) {
|
||||
console.error(
|
||||
"❌ Erreur lors de la mise à jour du statut de projet:",
|
||||
markErr
|
||||
);
|
||||
}
|
||||
|
||||
const status = error?.response?.status || "INTERNAL_ERROR";
|
||||
const message =
|
||||
error?.response?.data?.msg ||
|
||||
error?.response?.data?.message ||
|
||||
error?.message ||
|
||||
"Erreur lors de la génération de musique avec Suno";
|
||||
|
||||
throw new HttpsError("internal", message, {
|
||||
status,
|
||||
source: "SUNO_API",
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -355,7 +412,7 @@ exports.getSunoStatus = onCall(async ({ data = {} }) => {
|
||||
Authorization: `Bearer ${SUNO_API_KEY}`,
|
||||
},
|
||||
timeout: 30000, // 30 secondes de timeout
|
||||
},
|
||||
}
|
||||
);
|
||||
parsed = response.data;
|
||||
|
||||
@@ -510,7 +567,7 @@ exports.sunoCallback = onRequest({ methods: ["POST"] }, async (req, res) => {
|
||||
const audioUrls = tracks
|
||||
.map(
|
||||
(t) =>
|
||||
t.audio_url || t.audioUrl || t.stream_audio_url || t.streamAudioUrl,
|
||||
t.audio_url || t.audioUrl || t.stream_audio_url || t.streamAudioUrl
|
||||
)
|
||||
.filter(Boolean)
|
||||
.slice(0, 2);
|
||||
@@ -525,7 +582,7 @@ exports.sunoCallback = onRequest({ methods: ["POST"] }, async (req, res) => {
|
||||
has_audio_url: !!t.audio_url,
|
||||
has_stream_audio_url: !!t.stream_audio_url,
|
||||
})),
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -550,14 +607,14 @@ exports.sunoCallback = onRequest({ methods: ["POST"] }, async (req, res) => {
|
||||
},
|
||||
});
|
||||
const downloadUrl = `https://firebasestorage.googleapis.com/v0/b/${bucket.name}/o/${encodeURIComponent(
|
||||
path,
|
||||
path
|
||||
)}?alt=media&token=${token}`;
|
||||
console.log("✅ [SunoCallback] Sauvegardé:", path, "URL:", downloadUrl);
|
||||
return { path, url: downloadUrl };
|
||||
} catch (e) {
|
||||
console.error(
|
||||
`❌ [SunoCallback] Échec save piste ${index + 1}:`,
|
||||
e.message,
|
||||
e.message
|
||||
);
|
||||
return null;
|
||||
}
|
||||
@@ -575,9 +632,10 @@ exports.sunoCallback = onRequest({ methods: ["POST"] }, async (req, res) => {
|
||||
{
|
||||
musicStatus: "GENERATED",
|
||||
musicUrls,
|
||||
musicError: admin.firestore.FieldValue.delete(),
|
||||
updatedAt: admin.firestore.FieldValue.serverTimestamp(),
|
||||
},
|
||||
{ merge: true },
|
||||
{ merge: true }
|
||||
);
|
||||
console.log("🏷️ [SunoCallback] Projet marqué GENERATED", {
|
||||
projectId,
|
||||
|
||||
Reference in New Issue
Block a user