generate two covers

This commit is contained in:
2025-10-23 10:16:36 +02:00
parent b4375d04be
commit ebe26542fe
9 changed files with 754 additions and 436 deletions
+74 -36
View File
@@ -75,49 +75,65 @@ async function performCoverGeneration(project) {
projectId: project.id,
promptPreview: String(prompt).slice(0, 160),
});
let coverUrl = "";
const timestamp = Date.now();
try {
// Utiliser une taille fixe de 1024 pixels
coverUrl = await generateImageV2(
prompt,
1024,
`users/${project.userId}/projects/${project.id}/generated-${timestamp}.png`,
);
console.log("coverUrl", coverUrl);
} catch (e) {
logger.error(" [Cover] generateImageV2 failed", {
projectId: project.id,
error: e?.message || String(e),
const baseTimestamp = Date.now();
const options = [];
for (let index = 0; index < 2; index += 1) {
const uniqueSuffix = `${baseTimestamp}-${index}`;
const storageBasePath = `users/${project.userId}/projects/${project.id}`;
const generatedPath = `${storageBasePath}/generated-${uniqueSuffix}.png`;
let generatedUrl = "";
try {
generatedUrl = await generateImageV2(prompt, 1024, generatedPath);
logger.info("🎨 [Cover] Candidate generated", {
projectId: project.id,
candidateIndex: index,
});
} catch (e) {
logger.error("❌ [Cover] generateImageV2 failed", {
projectId: project.id,
candidateIndex: index,
error: e?.message || String(e),
});
throw e;
}
if (!generatedUrl) {
throw new Error("Génération d'image échouée (URL vide)");
}
let finalCoverUrl = generatedUrl;
try {
const stampedPath = `${storageBasePath}/cover-${uniqueSuffix}-stamped.png`;
finalCoverUrl = await buildCoverWithLogo(generatedUrl, stampedPath);
} catch (e) {
logger.error("❌ [Cover] Logo overlay failed", {
projectId: project.id,
candidateIndex: index,
error: e?.message || String(e),
});
}
options.push({
id: uniqueSuffix,
generatedUrl,
finalUrl: finalCoverUrl,
});
throw e;
}
if (!coverUrl) {
throw new Error("Génération d'image échouée (URL vide)");
}
let finalCoverUrl = "";
try {
const stampedPath = `users/${project.userId}/projects/${project.id}/cover-${timestamp}-stamped.png`;
finalCoverUrl = await buildCoverWithLogo(coverUrl, stampedPath);
} catch (e) {
logger.error("❌ [Cover] Logo overlay failed", {
projectId: project.id,
error: e?.message || String(e),
});
// En cas d'échec, on retient au moins la cover générée
finalCoverUrl = coverUrl;
}
const [firstOption] = options;
// Mettre à jour le projet avec l'URL et le statut
await db
.collection("projects")
.doc(project.id)
.set(
{
cover: {
generatedBackground: coverUrl,
result: finalCoverUrl,
generatedBackground: firstOption?.generatedUrl || null,
result: firstOption?.finalUrl || null,
selectedOptionId: firstOption?.id || null,
options,
},
coverStatus: "GENERATED",
updatedAt: admin.firestore.FieldValue.serverTimestamp(),
@@ -127,11 +143,11 @@ async function performCoverGeneration(project) {
logger.info("✅ [Cover] Saved", {
projectId: project.id,
coverUrl,
finalCoverUrl,
optionsCount: options.length,
ms: Date.now() - t0,
});
return finalCoverUrl;
return firstOption?.finalUrl || null;
}
// Firestore trigger: création d'une tâche de génération de cover
@@ -185,12 +201,34 @@ exports.onTaskCreateGenerateCover = onDocumentCreated(
}
project.id = projectId;
const existingOptionsCount = Array.isArray(project?.cover?.options)
? project.cover.options.length
: 0;
logger.info("🔎 [Task] Project loaded", {
projectId,
hasGeneratedBackground: !!project?.cover?.generatedBackground,
hasUserForeground: !!project?.cover?.userForeground,
existingOptionsCount,
});
if (existingOptionsCount > 0) {
logger.warn("⛔ [Task] Cover already generated, skipping", {
projectId,
existingOptionsCount,
});
await db.collection("projects").doc(projectId).update({
coverStatus: "GENERATED",
updatedAt: admin.firestore.FieldValue.serverTimestamp(),
});
await event.data.ref.update({
status: "CANCELLED",
error: "Cover already generated",
updatedAt: admin.firestore.FieldValue.serverTimestamp(),
});
return;
}
if (type === "cover") {
logger.info("🎨 [Task] Start cover generation", { projectId });
coverUrl = await performCoverGeneration(project);