fix: stabilize PSD template parsing workflow
This commit is contained in:
parent
e74586c8a0
commit
db46934025
@ -227,7 +227,10 @@ export function PsdTemplatesSettingsClient({
|
||||
backHref: string;
|
||||
backLabel: string;
|
||||
}) {
|
||||
const { data, mutate } = useSWR<AgentPsdTemplateListResponse>("/api/admin/psd-templates", fetcher);
|
||||
const { data, mutate, isLoading } = useSWR<AgentPsdTemplateListResponse>(
|
||||
"/api/admin/psd-templates",
|
||||
fetcher
|
||||
);
|
||||
const { data: siteSettingsData, mutate: mutateSiteSettings } = useSWR<{
|
||||
agentWorkflowUiConfig?: AgentWorkflowUiConfig;
|
||||
agentPsdTemplateCategoryTagConfig?: {
|
||||
@ -240,6 +243,12 @@ export function PsdTemplatesSettingsClient({
|
||||
);
|
||||
|
||||
const templates = useMemo(() => (data?.success ? data.templates : []), [data]);
|
||||
const templateListErrorMessage = useMemo(() => {
|
||||
if (!data || data.success) {
|
||||
return "";
|
||||
}
|
||||
return String(data.error || "").trim() || "PSD 模板读取失败";
|
||||
}, [data]);
|
||||
const fonts = useMemo(() => (fontsData?.success ? fontsData.fonts : []), [fontsData]);
|
||||
const brandOptions = useMemo(
|
||||
() =>
|
||||
@ -1712,7 +1721,31 @@ export function PsdTemplatesSettingsClient({
|
||||
<CardDescription>按品牌查看模板,选择一个模板继续配置槽位。</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-3">
|
||||
{templates.length === 0 ? (
|
||||
{isLoading ? (
|
||||
<div className="space-y-3">
|
||||
{Array.from({ length: 3 }).map((_, index) => (
|
||||
<div
|
||||
key={`psd-template-list-loading-${index}`}
|
||||
className="rounded-xl border border-dashed p-4 text-sm text-muted-foreground"
|
||||
>
|
||||
正在加载 PSD 模板列表...
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
) : templateListErrorMessage ? (
|
||||
<div className="rounded-xl border border-dashed border-amber-300/30 bg-amber-500/5 p-4 text-sm text-amber-100">
|
||||
<div>{templateListErrorMessage}</div>
|
||||
<Button
|
||||
className="mt-3"
|
||||
onClick={() => void mutate()}
|
||||
size="sm"
|
||||
type="button"
|
||||
variant="outline"
|
||||
>
|
||||
重新加载
|
||||
</Button>
|
||||
</div>
|
||||
) : templates.length === 0 ? (
|
||||
<div className="rounded-xl border border-dashed p-4 text-sm text-muted-foreground">
|
||||
还没有 PSD 模板,先上传一个模板开始配置。
|
||||
</div>
|
||||
|
||||
@ -16,6 +16,12 @@ import {
|
||||
preparePsdTemplateRenderAssets,
|
||||
} from "@/lib/agents/psd-template-parser";
|
||||
import { pickPrimaryPsdImageLayerId } from "@/lib/agents/psd-template-image-slot-selection";
|
||||
import {
|
||||
cacheAgentPsdSourceLocally,
|
||||
hasAgentPsdLocalCache,
|
||||
readAgentPsdSourceFromLocalCache,
|
||||
resolveAgentPsdLocalCachePath,
|
||||
} from "@/lib/agents/psd-local-cache";
|
||||
import { readAgentPsdTemplates } from "@/lib/agents/psd-template-settings";
|
||||
import { uploadFile } from "@/lib/storage/service";
|
||||
|
||||
@ -223,24 +229,64 @@ export async function POST(
|
||||
error: undefined,
|
||||
});
|
||||
|
||||
const response = await fetch(currentTemplate.fileUrl, {
|
||||
cache: "no-store",
|
||||
signal: AbortSignal.timeout(60_000),
|
||||
const localFilePath = resolveAgentPsdLocalCachePath({
|
||||
templateId: id,
|
||||
fileName: currentTemplate.fileName,
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`PSD 文件下载失败 (${response.status})`);
|
||||
let fileBuffer: ArrayBuffer;
|
||||
if (
|
||||
await hasAgentPsdLocalCache({
|
||||
templateId: id,
|
||||
fileName: currentTemplate.fileName,
|
||||
})
|
||||
) {
|
||||
await updateParseProgress({
|
||||
templateId: id,
|
||||
updatedBy: session.user.id,
|
||||
progress: 18,
|
||||
stage: "正在读取服务器本地 PSD 缓存",
|
||||
error: undefined,
|
||||
});
|
||||
const localBuffer = await readAgentPsdSourceFromLocalCache({
|
||||
templateId: id,
|
||||
fileName: currentTemplate.fileName,
|
||||
});
|
||||
fileBuffer = localBuffer.buffer.slice(
|
||||
localBuffer.byteOffset,
|
||||
localBuffer.byteOffset + localBuffer.byteLength
|
||||
) as ArrayBuffer;
|
||||
} else {
|
||||
const response = await fetch(currentTemplate.fileUrl, {
|
||||
cache: "no-store",
|
||||
signal: AbortSignal.timeout(60_000),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`PSD 文件下载失败 (${response.status})`);
|
||||
}
|
||||
|
||||
await updateParseProgress({
|
||||
templateId: id,
|
||||
updatedBy: session.user.id,
|
||||
progress: 18,
|
||||
stage: "正在下载并写入服务器本地 PSD 缓存",
|
||||
error: undefined,
|
||||
});
|
||||
|
||||
fileBuffer = await response.arrayBuffer();
|
||||
await cacheAgentPsdSourceLocally({
|
||||
templateId: id,
|
||||
fileName: currentTemplate.fileName,
|
||||
buffer: fileBuffer,
|
||||
}).catch((error) => {
|
||||
console.warn("[PSD Templates][Admin] failed to cache PSD source locally:", {
|
||||
templateId: id,
|
||||
error,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
await updateParseProgress({
|
||||
templateId: id,
|
||||
updatedBy: session.user.id,
|
||||
progress: 18,
|
||||
stage: "正在读取 PSD 文件",
|
||||
error: undefined,
|
||||
});
|
||||
|
||||
const fileBuffer = await response.arrayBuffer();
|
||||
const parsedTemplate = await parsePsdTemplateFile(fileBuffer);
|
||||
|
||||
if (parsedTemplate.layers.length === 0) {
|
||||
@ -287,6 +333,8 @@ export async function POST(
|
||||
const preparedAssets = await preparePsdTemplateRenderAssets({
|
||||
templateId: id,
|
||||
fileUrl: currentTemplate.fileUrl,
|
||||
filePath: localFilePath,
|
||||
fileBuffer,
|
||||
layers: initialLayers,
|
||||
});
|
||||
|
||||
|
||||
@ -14,6 +14,7 @@ import {
|
||||
type AgentPsdTemplateMutationResponse,
|
||||
} from "@/lib/agents/psd-template-config";
|
||||
import { normalizeAgentPsdTemplateCategoryTags } from "@/lib/agents/psd-template-category-tag-config";
|
||||
import { resolveAgentPsdLocalCachePath } from "@/lib/agents/psd-local-cache";
|
||||
import {
|
||||
preparePsdTemplateRenderAssets,
|
||||
} from "@/lib/agents/psd-template-parser";
|
||||
@ -198,6 +199,10 @@ export async function PUT(
|
||||
const preparedAssets = await preparePsdTemplateRenderAssets({
|
||||
templateId: currentTemplate.id,
|
||||
fileUrl: currentTemplate.fileUrl,
|
||||
filePath: resolveAgentPsdLocalCachePath({
|
||||
templateId: currentTemplate.id,
|
||||
fileName: currentTemplate.fileName,
|
||||
}),
|
||||
layers: nextLayers,
|
||||
});
|
||||
nextLayers = preparedAssets.layers;
|
||||
|
||||
@ -4,8 +4,8 @@ import { upsertSystemSetting } from "@/lib/db/queries";
|
||||
import { requireAgentWorkflowAdmin } from "@/lib/middleware/admin";
|
||||
import { uploadFile } from "@/lib/storage/service";
|
||||
import {
|
||||
AGENT_PSD_TEMPLATES_KEY,
|
||||
AGENT_PSD_TEMPLATE_ASSET_VERSION,
|
||||
AGENT_PSD_TEMPLATES_KEY,
|
||||
normalizeAgentPsdTemplateMode,
|
||||
normalizeAgentPsdTemplateStatus,
|
||||
upsertAgentPsdTemplate,
|
||||
@ -15,7 +15,7 @@ import {
|
||||
type AgentPsdTemplateMutationResponse,
|
||||
} from "@/lib/agents/psd-template-config";
|
||||
import { normalizeAgentPsdTemplateCategoryTags } from "@/lib/agents/psd-template-category-tag-config";
|
||||
import { repairAgentPsdTemplateAssetsIfNeeded } from "@/lib/agents/psd-template-repair";
|
||||
import { cacheAgentPsdSourceLocally } from "@/lib/agents/psd-local-cache";
|
||||
import { readAgentPsdTemplates } from "@/lib/agents/psd-template-settings";
|
||||
|
||||
export const runtime = "nodejs";
|
||||
@ -67,28 +67,9 @@ export async function GET() {
|
||||
|
||||
try {
|
||||
const templates = await readAgentPsdTemplates();
|
||||
const repairedTemplates = [] as AgentPsdTemplate[];
|
||||
let hasRepairedTemplate = false;
|
||||
|
||||
for (const template of templates) {
|
||||
const repairedTemplate = await repairAgentPsdTemplateAssetsIfNeeded(template);
|
||||
repairedTemplates.push(repairedTemplate);
|
||||
if (repairedTemplate !== template) {
|
||||
hasRepairedTemplate = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasRepairedTemplate) {
|
||||
await upsertSystemSetting({
|
||||
key: AGENT_PSD_TEMPLATES_KEY,
|
||||
value: repairedTemplates,
|
||||
updatedBy: session.user.id,
|
||||
});
|
||||
}
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
templates: hasRepairedTemplate ? repairedTemplates : templates,
|
||||
templates,
|
||||
} satisfies AgentPsdTemplateListResponse);
|
||||
} catch (error) {
|
||||
console.error("[PSD Templates][Admin] list failed:", error);
|
||||
@ -161,6 +142,17 @@ export async function POST(request: NextRequest) {
|
||||
|
||||
try {
|
||||
const fileBuffer = await file.arrayBuffer();
|
||||
const templateId = randomUUID();
|
||||
await cacheAgentPsdSourceLocally({
|
||||
templateId,
|
||||
fileName: file.name,
|
||||
buffer: fileBuffer,
|
||||
}).catch((error) => {
|
||||
console.warn("[PSD Templates][Admin] failed to cache uploaded PSD locally:", {
|
||||
templateId,
|
||||
error,
|
||||
});
|
||||
});
|
||||
const [uploadedFile, uploadedPreview] = await Promise.all([
|
||||
uploadFile(file.name, fileBuffer),
|
||||
uploadFile(
|
||||
@ -169,7 +161,6 @@ export async function POST(request: NextRequest) {
|
||||
),
|
||||
]);
|
||||
|
||||
const templateId = randomUUID();
|
||||
const now = new Date().toISOString();
|
||||
const nextTemplate: AgentPsdTemplate = {
|
||||
id: templateId,
|
||||
|
||||
99
lib/agents/psd-local-cache.ts
Normal file
99
lib/agents/psd-local-cache.ts
Normal file
@ -0,0 +1,99 @@
|
||||
import "server-only";
|
||||
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { promises as fs } from "node:fs";
|
||||
|
||||
const PSD_LOCAL_CACHE_ROOT = path.join(
|
||||
process.env.AGENT_PSD_LOCAL_CACHE_DIR || os.tmpdir(),
|
||||
"agent-psd-cache"
|
||||
);
|
||||
|
||||
function sanitizePathSegment(value: string, fallback: string) {
|
||||
const normalized = String(value || "")
|
||||
.trim()
|
||||
.replace(/[^a-zA-Z0-9_-]/g, "-")
|
||||
.replace(/-+/g, "-")
|
||||
.replace(/^-+|-+$/g, "");
|
||||
|
||||
return normalized || fallback;
|
||||
}
|
||||
|
||||
function normalizeTemplateExtension(fileName: string) {
|
||||
const normalized = String(fileName || "").trim().toLowerCase();
|
||||
if (normalized.endsWith(".psb")) {
|
||||
return "psb";
|
||||
}
|
||||
return "psd";
|
||||
}
|
||||
|
||||
function toBuffer(value: ArrayBuffer | Buffer) {
|
||||
if (Buffer.isBuffer(value)) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return Buffer.from(value);
|
||||
}
|
||||
|
||||
export function resolveAgentPsdLocalCachePath(params: {
|
||||
templateId: string;
|
||||
fileName?: string | null;
|
||||
}) {
|
||||
const templateId = sanitizePathSegment(params.templateId, "template");
|
||||
const extension = normalizeTemplateExtension(String(params.fileName || ""));
|
||||
return path.join(PSD_LOCAL_CACHE_ROOT, `${templateId}.${extension}`);
|
||||
}
|
||||
|
||||
export async function cacheAgentPsdSourceLocally(params: {
|
||||
templateId: string;
|
||||
fileName?: string | null;
|
||||
buffer: ArrayBuffer | Buffer;
|
||||
}) {
|
||||
const localFilePath = resolveAgentPsdLocalCachePath({
|
||||
templateId: params.templateId,
|
||||
fileName: params.fileName,
|
||||
});
|
||||
await fs.mkdir(path.dirname(localFilePath), { recursive: true });
|
||||
await fs.writeFile(localFilePath, toBuffer(params.buffer));
|
||||
return localFilePath;
|
||||
}
|
||||
|
||||
export async function readAgentPsdSourceFromLocalCache(params: {
|
||||
templateId: string;
|
||||
fileName?: string | null;
|
||||
}) {
|
||||
return fs.readFile(
|
||||
resolveAgentPsdLocalCachePath({
|
||||
templateId: params.templateId,
|
||||
fileName: params.fileName,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
export async function hasAgentPsdLocalCache(params: {
|
||||
templateId: string;
|
||||
fileName?: string | null;
|
||||
}) {
|
||||
try {
|
||||
await fs.access(
|
||||
resolveAgentPsdLocalCachePath({
|
||||
templateId: params.templateId,
|
||||
fileName: params.fileName,
|
||||
})
|
||||
);
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export async function deleteAgentPsdLocalCache(params: {
|
||||
templateId: string;
|
||||
fileName?: string | null;
|
||||
}) {
|
||||
const localFilePath = resolveAgentPsdLocalCachePath({
|
||||
templateId: params.templateId,
|
||||
fileName: params.fileName,
|
||||
});
|
||||
await fs.rm(localFilePath, { force: true });
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
import "server-only";
|
||||
|
||||
import { promises as fs } from "node:fs";
|
||||
import { uploadFile } from "@/lib/storage/service";
|
||||
import { normalizeDetectedFontNames } from "@/lib/agents/psd-font-matching";
|
||||
import { fetchRemoteAssetBuffer } from "@/lib/agents/psd-remote-asset";
|
||||
@ -447,6 +448,54 @@ async function fetchRemoteBuffer(url: string) {
|
||||
) as ArrayBuffer;
|
||||
}
|
||||
|
||||
function toSourceArrayBuffer(value: ArrayBuffer | Buffer) {
|
||||
if (Buffer.isBuffer(value)) {
|
||||
return value.buffer.slice(
|
||||
value.byteOffset,
|
||||
value.byteOffset + value.byteLength
|
||||
) as ArrayBuffer;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
async function readLocalPsdSourceBuffer(filePath: string) {
|
||||
const buffer = await fs.readFile(filePath);
|
||||
return buffer.buffer.slice(
|
||||
buffer.byteOffset,
|
||||
buffer.byteOffset + buffer.byteLength
|
||||
) as ArrayBuffer;
|
||||
}
|
||||
|
||||
async function resolvePsdSourceBuffer(params: {
|
||||
fileUrl?: string;
|
||||
filePath?: string;
|
||||
fileBuffer?: ArrayBuffer | Buffer;
|
||||
}) {
|
||||
if (params.fileBuffer) {
|
||||
return toSourceArrayBuffer(params.fileBuffer);
|
||||
}
|
||||
|
||||
const localFilePath = String(params.filePath || "").trim();
|
||||
if (localFilePath) {
|
||||
try {
|
||||
return await readLocalPsdSourceBuffer(localFilePath);
|
||||
} catch (error) {
|
||||
console.warn("[PSD Template] failed to read local PSD cache, falling back:", {
|
||||
filePath: localFilePath,
|
||||
error,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const fileUrl = String(params.fileUrl || "").trim();
|
||||
if (fileUrl) {
|
||||
return fetchRemoteBuffer(fileUrl);
|
||||
}
|
||||
|
||||
throw new Error("PSD 模板源文件不可用");
|
||||
}
|
||||
|
||||
export async function parsePsdTemplateFile(
|
||||
buffer: ArrayBuffer
|
||||
): Promise<ParsedPsdTemplatePayload> {
|
||||
@ -472,6 +521,15 @@ export async function parsePsdTemplateFileFromUrl(fileUrl: string) {
|
||||
return parsePsdTemplateFile(buffer);
|
||||
}
|
||||
|
||||
export async function parsePsdTemplateFileFromSource(params: {
|
||||
fileUrl?: string;
|
||||
filePath?: string;
|
||||
fileBuffer?: ArrayBuffer | Buffer;
|
||||
}) {
|
||||
const buffer = await resolvePsdSourceBuffer(params);
|
||||
return parsePsdTemplateFile(buffer);
|
||||
}
|
||||
|
||||
export async function loadPsdTemplateSourceFromUrl(fileUrl: string) {
|
||||
const buffer = await fetchRemoteBuffer(fileUrl);
|
||||
const psd = await parsePsdBuffer(buffer);
|
||||
@ -489,6 +547,27 @@ export async function loadPsdTemplateSourceFromUrl(fileUrl: string) {
|
||||
};
|
||||
}
|
||||
|
||||
export async function loadPsdTemplateSource(params: {
|
||||
fileUrl?: string;
|
||||
filePath?: string;
|
||||
fileBuffer?: ArrayBuffer | Buffer;
|
||||
}) {
|
||||
const buffer = await resolvePsdSourceBuffer(params);
|
||||
const psd = await parsePsdBuffer(buffer);
|
||||
const layerEntries = collectPsdLayerEntries(Array.isArray(psd.children) ? psd.children : []);
|
||||
|
||||
return {
|
||||
width: Math.max(1, Math.round(Number(psd.width || 0))),
|
||||
height: Math.max(1, Math.round(Number(psd.height || 0))),
|
||||
layers: layerEntries
|
||||
.filter((entry) => entry.node && typeof entry.node.composite === "function")
|
||||
.map((entry) => ({
|
||||
layer: entry.layer,
|
||||
composite: () => entry.node.composite!(),
|
||||
})) satisfies PsdTemplateSourceLayerEntry[],
|
||||
};
|
||||
}
|
||||
|
||||
async function createTransparentCanvasBuffer(width: number, height: number) {
|
||||
const sharp = await getSharp();
|
||||
const canvasWidth = Math.max(1, Math.round(Number(width || 0)));
|
||||
@ -577,11 +656,17 @@ async function fitOverlayBufferIntoCanvas(params: {
|
||||
|
||||
export async function preparePsdTemplateRenderAssets(params: {
|
||||
templateId: string;
|
||||
fileUrl: string;
|
||||
fileUrl?: string;
|
||||
filePath?: string;
|
||||
fileBuffer?: ArrayBuffer | Buffer;
|
||||
layers: AgentPsdTemplateLayerSlot[];
|
||||
forceRefreshLayerAssets?: boolean;
|
||||
}) {
|
||||
const psdBuffer = await fetchRemoteBuffer(params.fileUrl);
|
||||
const psdBuffer = await resolvePsdSourceBuffer({
|
||||
fileUrl: params.fileUrl,
|
||||
filePath: params.filePath,
|
||||
fileBuffer: params.fileBuffer,
|
||||
});
|
||||
const psd = await parsePsdBuffer(psdBuffer);
|
||||
const layerEntries = collectPsdLayerEntries(Array.isArray(psd.children) ? psd.children : []);
|
||||
const nodeMap = new Map(layerEntries.map((entry) => [entry.layer.layerId, entry]));
|
||||
|
||||
@ -17,9 +17,10 @@ import {
|
||||
pickPrimaryPsdImageLayerId,
|
||||
} from "@/lib/agents/psd-template-image-slot-selection";
|
||||
import {
|
||||
parsePsdTemplateFileFromUrl,
|
||||
parsePsdTemplateFileFromSource,
|
||||
preparePsdTemplateRenderAssets,
|
||||
} from "@/lib/agents/psd-template-parser";
|
||||
import { resolveAgentPsdLocalCachePath } from "@/lib/agents/psd-local-cache";
|
||||
import { uploadFile } from "@/lib/storage/service";
|
||||
|
||||
function hasMissingLayerAssets(template: AgentPsdTemplate) {
|
||||
@ -209,7 +210,14 @@ export async function repairAgentPsdTemplateAssetsIfNeeded(
|
||||
let nextLayers = repairEditableImageLayerSelection(template);
|
||||
if (needsFontDetection) {
|
||||
try {
|
||||
const parsedTemplate = await parsePsdTemplateFileFromUrl(template.fileUrl);
|
||||
const localFilePath = resolveAgentPsdLocalCachePath({
|
||||
templateId: template.id,
|
||||
fileName: template.fileName,
|
||||
});
|
||||
const parsedTemplate = await parsePsdTemplateFileFromSource({
|
||||
fileUrl: template.fileUrl,
|
||||
filePath: localFilePath,
|
||||
});
|
||||
const parsedTextLayerMap = new Map(
|
||||
parsedTemplate.layers
|
||||
.filter((layer) => layer.slotType === "text")
|
||||
@ -260,6 +268,10 @@ export async function repairAgentPsdTemplateAssetsIfNeeded(
|
||||
const preparedAssets = await preparePsdTemplateRenderAssets({
|
||||
templateId: template.id,
|
||||
fileUrl: template.fileUrl,
|
||||
filePath: resolveAgentPsdLocalCachePath({
|
||||
templateId: template.id,
|
||||
fileName: template.fileName,
|
||||
}),
|
||||
layers: nextLayers,
|
||||
forceRefreshLayerAssets: needsAssetVersionRefresh,
|
||||
});
|
||||
|
||||
@ -7,6 +7,7 @@ import {
|
||||
parseAgentPsdTemplates,
|
||||
type AgentPsdTemplate,
|
||||
} from "@/lib/agents/psd-template-config";
|
||||
import { deleteAgentPsdLocalCache } from "@/lib/agents/psd-local-cache";
|
||||
|
||||
export async function readAgentPsdTemplates() {
|
||||
const setting = await getSystemSetting({ key: AGENT_PSD_TEMPLATES_KEY });
|
||||
@ -14,6 +15,11 @@ export async function readAgentPsdTemplates() {
|
||||
}
|
||||
|
||||
export async function tryDeleteAgentPsdTemplateAssets(template: AgentPsdTemplate) {
|
||||
await deleteAgentPsdLocalCache({
|
||||
templateId: template.id,
|
||||
fileName: template.fileName,
|
||||
}).catch(() => undefined);
|
||||
|
||||
const filePaths = Array.from(
|
||||
new Set(
|
||||
[
|
||||
|
||||
@ -6,7 +6,8 @@ import {
|
||||
type AgentPsdTemplate,
|
||||
type AgentPsdTemplateTextLayerSlot,
|
||||
} from "@/lib/agents/psd-template-config";
|
||||
import { loadPsdTemplateSourceFromUrl } from "@/lib/agents/psd-template-parser";
|
||||
import { resolveAgentPsdLocalCachePath } from "@/lib/agents/psd-local-cache";
|
||||
import { loadPsdTemplateSource } from "@/lib/agents/psd-template-parser";
|
||||
|
||||
function getEstimatedFontSize(height: number) {
|
||||
return Math.max(16, Math.min(height, Math.round(height * 0.78)));
|
||||
@ -65,7 +66,13 @@ export async function resolveAgentPsdTemplateTextStyles(template: AgentPsdTempla
|
||||
return template;
|
||||
}
|
||||
|
||||
const source = await loadPsdTemplateSourceFromUrl(template.fileUrl);
|
||||
const source = await loadPsdTemplateSource({
|
||||
fileUrl: template.fileUrl,
|
||||
filePath: resolveAgentPsdLocalCachePath({
|
||||
templateId: template.id,
|
||||
fileName: template.fileName,
|
||||
}),
|
||||
});
|
||||
const sourceLayerMap = new Map(source.layers.map((entry) => [entry.layer.layerId, entry]));
|
||||
const pixelAnalysisCache = new Map<
|
||||
string,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user