Refactoring code

This commit is contained in:
2026-02-03 10:13:41 +01:00
parent 0c72a756c5
commit ea5eb6fa59
2 changed files with 46 additions and 17 deletions

View File

@ -1,36 +1,49 @@
"use server"; "use server";
import { prisma } from "@/lib/prisma"; import { prisma } from "@/lib/prisma";
import { VibrantSwatch } from "@/types/VibrantSwatch"; import type { VibrantSwatch } from "@/types/VibrantSwatch";
import { getImageBufferFromS3Key } from "@/utils/getImageBufferFromS3"; import { getImageBufferFromS3Key } from "@/utils/getImageBufferFromS3";
import { generateColorName, rgbToHex } from "@/utils/uploadHelper"; import { generateColorName, rgbToHex } from "@/utils/uploadHelper";
import { converter, parse } from "culori"; import { converter, parse } from "culori";
import { Vibrant } from "node-vibrant/node"; import { Vibrant } from "node-vibrant/node";
const toOklab = converter("oklab"); const toOklab = converter("oklab");
const A_MIN = -0.5, A_MAX = 0.5; const A_MIN = -0.5,
const B_MIN = -0.5, B_MAX = 0.5; A_MAX = 0.5;
const B_MIN = -0.5,
B_MAX = 0.5;
function clamp01(x: number) { return Math.max(0, Math.min(1, x)); } function clamp01(x: number) {
function norm(x: number, lo: number, hi: number) { return clamp01((x - lo) / (hi - lo)); } return Math.max(0, Math.min(1, x));
}
function norm(x: number, lo: number, hi: number) {
return clamp01((x - lo) / (hi - lo));
}
function hilbertIndex15(x01: number, y01: number): number { function hilbertIndex15(x01: number, y01: number): number {
let x = Math.floor(clamp01(x01) * 32767); let x = Math.floor(clamp01(x01) * 32767);
let y = Math.floor(clamp01(y01) * 32767); let y = Math.floor(clamp01(y01) * 32767);
let index = 0; let index = 0;
for (let s = 1 << 14; s > 0; s >>= 1) { for (let s = 1 << 14; s > 0; s >>= 1) {
const rx = (x & s) ? 1 : 0; const rx = x & s ? 1 : 0;
const ry = (y & s) ? 1 : 0; const ry = y & s ? 1 : 0;
index += s * s * ((3 * rx) ^ ry); index += s * s * ((3 * rx) ^ ry);
if (ry === 0) { if (ry === 0) {
if (rx === 1) { x = 32767 - x; y = 32767 - y; } if (rx === 1) {
const t = x; x = y; y = t; x = 32767 - x;
y = 32767 - y;
}
const t = x;
x = y;
y = t;
} }
} }
return index >>> 0; return index >>> 0;
} }
function centroidFromPaletteHexes(hexByType: Record<string, string | undefined>) { function centroidFromPaletteHexes(
hexByType: Record<string, string | undefined>,
) {
const weights: Record<string, number> = { const weights: Record<string, number> = {
Vibrant: 0.7, Vibrant: 0.7,
Muted: 0.15, Muted: 0.15,
@ -48,14 +61,20 @@ function centroidFromPaletteHexes(hexByType: Record<string, string | undefined>)
hexByType["LightVibrant"] || hexByType["LightVibrant"] ||
hexByType["LightMuted"]; hexByType["LightMuted"];
let L = 0, A = 0, B = 0, W = 0; let L = 0,
A = 0,
B = 0,
W = 0;
for (const [type, w] of Object.entries(weights)) { for (const [type, w] of Object.entries(weights)) {
const hex = hexByType[type] ?? fallbackHex; const hex = hexByType[type] ?? fallbackHex;
if (!hex || w <= 0) continue; if (!hex || w <= 0) continue;
const c = toOklab(parse(hex)); const c = toOklab(parse(hex));
if (!c) continue; if (!c) continue;
L += c.l * w; A += c.a * w; B += c.b * w; W += w; L += c.l * w;
A += c.a * w;
B += c.b * w;
W += w;
} }
if (W === 0) return { l: 0.5, a: 0, b: 0 }; if (W === 0) return { l: 0.5, a: 0, b: 0 };
@ -78,7 +97,11 @@ export async function generateArtworkColorsForArtwork(artworkId: string) {
where: { id: artworkId }, where: { id: artworkId },
select: { select: {
file: { select: { fileKey: true } }, file: { select: { fileKey: true } },
variants: { where: { type: "original" }, select: { s3Key: true }, take: 1 }, variants: {
where: { type: "original" },
select: { s3Key: true },
take: 1,
},
}, },
}); });
if (!artwork) throw new Error("Artwork not found"); if (!artwork) throw new Error("Artwork not found");
@ -117,11 +140,14 @@ export async function generateArtworkColorsForArtwork(artworkId: string) {
} }
const hexByType: Record<string, string | undefined> = Object.fromEntries( const hexByType: Record<string, string | undefined> = Object.fromEntries(
vibrantHexes.map(({ type, hex }) => [type, hex]) vibrantHexes.map(({ type, hex }) => [type, hex]),
); );
const { l, a, b } = centroidFromPaletteHexes(hexByType); const { l, a, b } = centroidFromPaletteHexes(hexByType);
const sortKey = hilbertIndex15(norm(a, A_MIN, A_MAX), norm(b, B_MIN, B_MAX)); const sortKey = hilbertIndex15(
norm(a, A_MIN, A_MAX),
norm(b, B_MIN, B_MAX),
);
await prisma.artwork.update({ await prisma.artwork.update({
where: { id: artworkId }, where: { id: artworkId },
@ -144,6 +170,9 @@ export async function generateArtworkColorsForArtwork(artworkId: string) {
colorError: e instanceof Error ? e.message : "Color generation failed", colorError: e instanceof Error ? e.message : "Color generation failed",
}, },
}); });
return { ok: false as const, error: e instanceof Error ? e.message : "Color generation failed" }; return {
ok: false as const,
error: e instanceof Error ? e.message : "Color generation failed",
};
} }
} }

View File

@ -1,6 +1,6 @@
"use server"; "use server";
import { Prisma } from "@/generated/prisma/client"; import type { Prisma } from "@/generated/prisma/client";
import { prisma } from "@/lib/prisma"; import { prisma } from "@/lib/prisma";
import { generateArtworkColorsForArtwork } from "../artworks/generateArtworkColors"; import { generateArtworkColorsForArtwork } from "../artworks/generateArtworkColors";