@@ -2745,11 +2745,11 @@ export function PsdTemplatesSettingsClient({
- {uploadFile ? `已选择:${uploadFile.name}` : "支持 80MB 以内 PSD 文件"}
+ {uploadFile ? `已选择:${uploadFile.name}` : "支持 80MB 以内 PSD / PSB 文件"}
diff --git a/app/api/admin/psd-templates/[id]/parse/route.ts b/app/api/admin/psd-templates/[id]/parse/route.ts
index 2fd7bbcac..db045ea28 100644
--- a/app/api/admin/psd-templates/[id]/parse/route.ts
+++ b/app/api/admin/psd-templates/[id]/parse/route.ts
@@ -13,8 +13,10 @@ import {
import { pickPrimaryPsdImageLayerId } from "@/lib/agents/psd-template-image-slot-selection";
import { schedulePsdTemplateAssetBackfill } from "@/lib/agents/psd-template-asset-backfill";
import {
- AGENT_PSD_TEMPLATE_UNSUPPORTED_PSB_MESSAGE,
+ AGENT_PSD_TEMPLATE_INCOMPATIBLE_PSB_MESSAGE,
+ AGENT_PSD_TEMPLATE_INVALID_FORMAT_MESSAGE,
assertSupportedAgentPsdTemplateFile,
+ type AgentPsdTemplateFileInspection,
} from "@/lib/agents/psd-template-format";
import {
createAgentPsdTemplateParseHeartbeat,
@@ -55,6 +57,22 @@ function getErrorMessage(error: unknown) {
return "PSD 解析失败";
}
+function getPsdTemplateParseErrorMessage(params: {
+ error: unknown;
+ fileInspection?: AgentPsdTemplateFileInspection;
+}) {
+ const message = getErrorMessage(params.error);
+
+ if (
+ params.fileInspection?.format === "psb" &&
+ /invalid signature/i.test(message)
+ ) {
+ return AGENT_PSD_TEMPLATE_INCOMPATIBLE_PSB_MESSAGE;
+ }
+
+ return message;
+}
+
function pickPrimaryImageLayerId(params: {
parsedLayers: Awaited>["layers"];
canvasWidth: number;
@@ -185,6 +203,7 @@ export async function POST(
}
const { id } = await context.params;
+ let fileInspection: AgentPsdTemplateFileInspection | undefined;
let latestProgress = {
progress: 0,
stage: "准备解析 PSD",
@@ -289,7 +308,7 @@ export async function POST(
}
await setParseProgress(22, "正在校验 PSD 文件格式");
- assertSupportedAgentPsdTemplateFile(fileBuffer);
+ fileInspection = assertSupportedAgentPsdTemplateFile(fileBuffer);
await setParseProgress(24, "正在解析 PSD 图层结构与预览");
const parsedTemplate = await parsePsdTemplateFile(fileBuffer, {
@@ -361,7 +380,10 @@ export async function POST(
throw error;
}
} catch (error) {
- const message = getErrorMessage(error);
+ const message = getPsdTemplateParseErrorMessage({
+ error,
+ fileInspection,
+ });
const existingTemplate = (await readAgentPsdTemplates()).find((entry) => entry.id === id);
if (existingTemplate) {
@@ -400,11 +422,12 @@ export async function POST(
fileName: existingTemplate?.fileName,
progress: latestProgress.progress,
stage: latestProgress.stage,
+ fileFormat: fileInspection?.format,
error,
});
return jsonError(
- message === AGENT_PSD_TEMPLATE_UNSUPPORTED_PSB_MESSAGE ||
- message.startsWith("模板文件格式不正确")
+ message === AGENT_PSD_TEMPLATE_INCOMPATIBLE_PSB_MESSAGE ||
+ message === AGENT_PSD_TEMPLATE_INVALID_FORMAT_MESSAGE
? 400
: 502,
message
diff --git a/app/api/admin/psd-templates/route.ts b/app/api/admin/psd-templates/route.ts
index 07bb06497..0897809c0 100644
--- a/app/api/admin/psd-templates/route.ts
+++ b/app/api/admin/psd-templates/route.ts
@@ -16,7 +16,7 @@ import {
} from "@/lib/agents/psd-template-config";
import { normalizeAgentPsdTemplateCategoryTags } from "@/lib/agents/psd-template-category-tag-config";
import {
- AGENT_PSD_TEMPLATE_UNSUPPORTED_PSB_MESSAGE,
+ AGENT_PSD_TEMPLATE_INVALID_FORMAT_MESSAGE,
assertSupportedAgentPsdTemplateFile,
} from "@/lib/agents/psd-template-format";
import { cacheAgentPsdSourceLocally } from "@/lib/agents/psd-local-cache";
@@ -26,7 +26,7 @@ import { failTimedOutAgentPsdTemplates } from "@/lib/agents/psd-template-timeout
export const runtime = "nodejs";
const MAX_TEMPLATE_FILE_SIZE = 80 * 1024 * 1024;
-const ALLOWED_TEMPLATE_EXTENSIONS = new Set(["psd"]);
+const ALLOWED_TEMPLATE_EXTENSIONS = new Set(["psd", "psb"]);
const PLACEHOLDER_PREVIEW_PNG = Buffer.from(
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO2+p4kAAAAASUVORK5CYII=",
"base64"
@@ -226,12 +226,7 @@ export async function POST(request: NextRequest) {
const extension = getFileExtension(file.name);
if (!ALLOWED_TEMPLATE_EXTENSIONS.has(extension)) {
- return jsonMutationError(
- 400,
- extension === "psb"
- ? AGENT_PSD_TEMPLATE_UNSUPPORTED_PSB_MESSAGE
- : "模板文件仅支持 Photoshop PSD(.psd)"
- );
+ return jsonMutationError(400, "模板文件仅支持 Photoshop PSD / PSB");
}
if (file.size <= 0) {
@@ -326,8 +321,7 @@ export async function POST(request: NextRequest) {
console.error("[PSD Templates][Admin] create failed:", error);
if (error instanceof Error && error.message.trim()) {
if (
- error.message === AGENT_PSD_TEMPLATE_UNSUPPORTED_PSB_MESSAGE ||
- error.message.startsWith("模板文件格式不正确")
+ error.message === AGENT_PSD_TEMPLATE_INVALID_FORMAT_MESSAGE
) {
return jsonMutationError(400, error.message);
}
diff --git a/lib/agents/psd-template-format.ts b/lib/agents/psd-template-format.ts
index 7f3c26165..22d9a4dda 100644
--- a/lib/agents/psd-template-format.ts
+++ b/lib/agents/psd-template-format.ts
@@ -13,8 +13,11 @@ export interface AgentPsdTemplateFileInspection {
colorMode: number;
}
-export const AGENT_PSD_TEMPLATE_UNSUPPORTED_PSB_MESSAGE =
- "当前生产模板解析仅支持 Photoshop PSD(.psd)。检测到 PSB / Large Document 格式,请在 Photoshop 中另存为 PSD 后再上传解析。";
+export const AGENT_PSD_TEMPLATE_INVALID_FORMAT_MESSAGE =
+ "模板文件格式不正确,请上传 Photoshop PSD / PSB 文件。";
+
+export const AGENT_PSD_TEMPLATE_INCOMPATIBLE_PSB_MESSAGE =
+ "当前 PSB 文件包含现有解析器暂不兼容的图层扩展信息,请在 Photoshop 中另存为 PSD 后再上传解析。";
export function inspectAgentPsdTemplateFile(
value: ArrayBuffer | Buffer
@@ -62,13 +65,9 @@ export function assertSupportedAgentPsdTemplateFile(
) {
const inspection = inspectAgentPsdTemplateFile(value);
- if (inspection.format === "psd") {
+ if (inspection.format === "psd" || inspection.format === "psb") {
return inspection;
}
- if (inspection.format === "psb") {
- throw new Error(AGENT_PSD_TEMPLATE_UNSUPPORTED_PSB_MESSAGE);
- }
-
- throw new Error("模板文件格式不正确,请上传 Photoshop PSD(.psd)文件。");
+ throw new Error(AGENT_PSD_TEMPLATE_INVALID_FORMAT_MESSAGE);
}