130 lines
3.5 KiB
TypeScript
130 lines
3.5 KiB
TypeScript
import "server-only";
|
|
|
|
import type { AgentPsdFont } from "@/lib/agents/psd-font-config";
|
|
|
|
function normalizeFontToken(value: string) {
|
|
return String(value || "")
|
|
.trim()
|
|
.toLowerCase()
|
|
.replace(/[^a-z0-9]+/g, "");
|
|
}
|
|
|
|
function isIgnoredFontName(value: string) {
|
|
const normalized = normalizeFontToken(value);
|
|
return (
|
|
!normalized ||
|
|
normalized === "adobeinvisfont" ||
|
|
normalized.startsWith("adobeheiti") ||
|
|
normalized.startsWith("adobesong") ||
|
|
normalized.startsWith("adobeming")
|
|
);
|
|
}
|
|
|
|
export function normalizeDetectedFontNames(value: unknown) {
|
|
if (!Array.isArray(value)) return [] as string[];
|
|
|
|
return Array.from(
|
|
new Set(
|
|
value
|
|
.map((item) => String(item || "").trim())
|
|
.filter((item) => item && !isIgnoredFontName(item))
|
|
)
|
|
);
|
|
}
|
|
|
|
function getPsdFontIdentityTokens(font: Pick<AgentPsdFont, "name" | "family">) {
|
|
return Array.from(
|
|
new Set(
|
|
[font.name, font.family]
|
|
.map((item) => normalizeFontToken(String(item || "")))
|
|
.filter(Boolean)
|
|
)
|
|
);
|
|
}
|
|
|
|
export function doesPsdFontMatchDetectedNames(params: {
|
|
detectedFontNames: string[];
|
|
font: Pick<AgentPsdFont, "name" | "family">;
|
|
}) {
|
|
const detectedFontNames = normalizeDetectedFontNames(params.detectedFontNames);
|
|
if (detectedFontNames.length === 0) {
|
|
return true;
|
|
}
|
|
|
|
const fontTokens = new Set(getPsdFontIdentityTokens(params.font));
|
|
return detectedFontNames.some((detectedFontName) =>
|
|
fontTokens.has(normalizeFontToken(detectedFontName))
|
|
);
|
|
}
|
|
|
|
export function findBestMatchingPsdFont(params: {
|
|
detectedFontNames: string[];
|
|
fonts: AgentPsdFont[];
|
|
}) {
|
|
const detectedFontNames = normalizeDetectedFontNames(params.detectedFontNames);
|
|
if (detectedFontNames.length === 0 || params.fonts.length === 0) {
|
|
return null;
|
|
}
|
|
|
|
const exactMap = new Map<string, AgentPsdFont>();
|
|
const normalizedMap = new Map<string, AgentPsdFont>();
|
|
|
|
for (const font of params.fonts) {
|
|
for (const candidate of [font.name, font.family]) {
|
|
const raw = String(candidate || "").trim();
|
|
if (!raw) continue;
|
|
exactMap.set(raw.toLowerCase(), font);
|
|
normalizedMap.set(normalizeFontToken(raw), font);
|
|
}
|
|
}
|
|
|
|
for (const detectedFontName of detectedFontNames) {
|
|
const exactMatch = exactMap.get(detectedFontName.toLowerCase());
|
|
if (exactMatch) {
|
|
return {
|
|
font: exactMatch,
|
|
detectedFontName,
|
|
confidence: "high" as const,
|
|
};
|
|
}
|
|
}
|
|
|
|
for (const detectedFontName of detectedFontNames) {
|
|
const normalizedDetected = normalizeFontToken(detectedFontName);
|
|
const normalizedMatch = normalizedMap.get(normalizedDetected);
|
|
if (normalizedMatch) {
|
|
return {
|
|
font: normalizedMatch,
|
|
detectedFontName,
|
|
confidence: "high" as const,
|
|
};
|
|
}
|
|
}
|
|
|
|
for (const detectedFontName of detectedFontNames) {
|
|
const normalizedDetected = normalizeFontToken(detectedFontName);
|
|
if (!normalizedDetected) continue;
|
|
|
|
const containsMatch = params.fonts.find((font) => {
|
|
const fontName = normalizeFontToken(font.name);
|
|
const fontFamily = normalizeFontToken(font.family);
|
|
return (
|
|
fontName.includes(normalizedDetected) ||
|
|
fontFamily.includes(normalizedDetected) ||
|
|
normalizedDetected.includes(fontName) ||
|
|
normalizedDetected.includes(fontFamily)
|
|
);
|
|
});
|
|
|
|
if (containsMatch) {
|
|
return {
|
|
font: containsMatch,
|
|
detectedFontName,
|
|
confidence: "medium" as const,
|
|
};
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|