Files
tyx_AI_xhs/scripts/run-wp4-04-manual-preview.mjs

113 lines
7.7 KiB
JavaScript

import { existsSync, readFileSync } from "node:fs";
import { homedir } from "node:os";
import { join, resolve } from "node:path";
import { createServer } from "vite";
const host = "127.0.0.1";
const port = Number(process.env.DADA_MANUAL_PREVIEW_PORT ?? 43122);
const projectId = "00000000-0000-4000-8000-000000000904";
const dynamicRoot = process.env.DADA_DYNAMIC_ASSET_ROOT ?? join(homedir(), "Desktop", "sticker_interactive", "单模板归档", "templates");
const stickerRoot = process.env.DADA_STATIC_STICKER_ROOT ?? join(homedir(), "Desktop", "贴纸素材");
const textRoot = process.env.DADA_TEXT_ASSET_ROOT ?? join(homedir(), "Desktop", "sticker_text");
const publicAssets = {
STK001: [join(stickerRoot, "sticker_part1", "01af6384c2a962d17f55736f9895b505.png"), "image/png"],
STK002: [join(stickerRoot, "sticker_part2", "011db0fb6ac4184e4a708374003bce66.png"), "image/png"],
"15974853bc3294ef68e7e6d58fe74fd7": [join(dynamicRoot, "DYN002", "fonts", "15974853bc3294ef68e7e6d58fe74fd7", "0202b90o6r57rxed4027b5689e0dxe7e142r0yho9d0lljuqj.ttf"), "font/ttf"],
"46f8336813e4c48d06a1aef294fdccf6": [join(dynamicRoot, "DYN016", "fonts", "46f8336813e4c48d06a1aef294fdccf6", "9fbfbb420cea1df916d7c7c7ac90b1c88b61e117-PingFang-SC-Semibold-2.ttf"), "font/ttf"],
"53ca6b704728520da50c145eabb2e635": [join(dynamicRoot, "DYN007", "fonts", "53ca6b704728520da50c145eabb2e635", "fab6c26a0b21d5e9b57fb5238843ac1fb77a2ce6-HYZhengYuan.ttf"), "font/ttf"],
"cca5efc0e02fb1bf62349bd68ef30fc1": [join(dynamicRoot, "DYN015", "fonts", "cca5efc0e02fb1bf62349bd68ef30fc1", "e11ced673fc7e63e8b0b4730166d29845d8bebae-NotoSansCJKsc-Regular.otf"), "font/otf"],
"dd25b35dcb7ba4476cbaa9a9592e39e2": [join(dynamicRoot, "DYN001", "fonts", "dd25b35dcb7ba4476cbaa9a9592e39e2", "0202b90o6r57rxed4027b5689e0dxe7e142r0ygbx80porvko.ttf"), "font/ttf"],
"e4210c9872f0c279b35273f230809821": [join(dynamicRoot, "DYN011", "fonts", "e4210c9872f0c279b35273f230809821", "06b980259e2104e1211a6819a61bc5ddeca77dcb-DJB-Get-Digital-1.ttf"), "font/ttf"],
"f4bfd4132df2d6be97ceabadf3853505": [join(dynamicRoot, "DYN008", "fonts", "f4bfd4132df2d6be97ceabadf3853505", "6ce05a147aedabbb610d9cb3e75bbe60c064c3f5-BarlowCondensed-SemiBold.ttf"), "font/ttf"],
"DYN001-image28": [join(dynamicRoot, "DYN001", "resource", "image28.png"), "image/png"],
"DYN002-image29": [join(dynamicRoot, "DYN002", "resource", "image29.png"), "image/png"],
"DYN003-image30": [join(dynamicRoot, "DYN003", "resource", "image30.png"), "image/png"],
"DYN004-image32": [join(dynamicRoot, "DYN004", "resource", "image32.png"), "image/png"],
"DYN008-backendui0": [join(dynamicRoot, "DYN008", "resource", "backendui0.png"), "image/png"],
"DYN011-backendui0": [join(dynamicRoot, "DYN011", "resource", "backendui0.png"), "image/png"],
"DYN015-imager2": [join(dynamicRoot, "DYN015", "resource", "imager2_2.png"), "image/png"],
"DYN016-image21": [join(dynamicRoot, "DYN016", "resource", "image21.png"), "image/png"],
FONT081: [join(textRoot, "字体", "面板全量采集", "font_panel_full_20260722", "resources", "font_packages", "FONT081_Lexend Deca", "font_files", "02034l0o6r57rxed4027b5689e0dxe7e142r0vi8920akeqto.ttf"), "font/ttf"],
};
if (!Object.values(publicAssets).every(([path]) => existsSync(path))) throw new Error("WP4-04 original preview assets are unavailable.");
const session = {
audience: "user", authenticated: true, credits: { available_balance: 10, reserved_balance: 0 },
csrf_token: "csrf-wp4-manual-preview-0000000000000000000000000000", expires_at: "2026-09-03T08:00:00.000Z",
user: { creator_name: "Dada Creator", role: "user", social_id: "@dada", status: "active", user_id: "00000000-0000-4000-8000-000000000901" },
};
const backgroundId = "00000000-0000-4000-8000-000000000902";
let stateVersion = 1;
let canvasState = {
background: { adjustments: { brightness: 0, contrast: 0, crop: null, filter: "none", fit: "fill", saturation: 0, sharpness: 0, temperature: 0 }, asset_id: backgroundId },
elements: [], pixel_height: 1440, pixel_width: 1080, ratio: "3:4", schema_version: 1,
};
const backgroundSvg = `<svg xmlns="http://www.w3.org/2000/svg" width="1080" height="1440"><rect width="1080" height="1440" fill="#2b3038"/><rect x="0" y="0" width="216" height="1440" fill="#04d960"/><rect x="216" y="0" width="216" height="1440" fill="#0abf58"/><rect x="432" y="0" width="216" height="1440" fill="#5fd994"/><rect x="648" y="0" width="216" height="1440" fill="#a0f2c4"/><rect x="864" y="0" width="216" height="1440" fill="#d5f2e2"/><rect x="0" y="0" width="1080" height="1440" fill="#15181d" opacity=".58"/></svg>`;
function send(response, status, body, contentType) {
response.statusCode = status;
response.setHeader("Content-Type", contentType);
response.end(body);
}
function sendJson(response, value, status = 200) {
send(response, status, JSON.stringify(value), "application/json; charset=utf-8");
}
function readJson(request) {
return new Promise((resolveBody, reject) => {
const chunks = [];
request.on("data", (chunk) => chunks.push(chunk));
request.on("end", () => {
try { resolveBody(JSON.parse(Buffer.concat(chunks).toString("utf8"))); } catch (error) { reject(error); }
});
request.on("error", reject);
});
}
const mockApi = {
name: "wp4-manual-preview-api",
configureServer(server) {
server.middlewares.use((request, response, next) => {
const url = new URL(request.url ?? "/", `http://${host}:${port}`);
if (request.method === "GET" && url.pathname === "/api/v1/auth/session") return sendJson(response, session);
if (request.method === "GET" && url.pathname === "/api/v1/assets/recent") return sendJson(response, { items: [] });
if (request.method === "GET" && url.pathname === `/api/v1/projects/${projectId}`) return sendJson(response, {
canvas_state: canvasState, created_at: "2026-08-03T08:00:00.000Z", current_image_id: backgroundId,
images: [{ created_at: "2026-08-03T08:00:00.000Z", generation_id: "00000000-0000-4000-8000-000000000903", image_id: backgroundId }],
name: "原版贴纸人工检查", pixel_height: 1440, pixel_width: 1080, project_id: projectId, ratio: "3:4", state_version: stateVersion,
});
if (request.method === "PUT" && url.pathname === `/api/v1/projects/${projectId}/state`) {
void readJson(request).then((body) => {
canvasState = body.canvas_state;
stateVersion += 1;
sendJson(response, { save_status: "saved", state_version: stateVersion });
}).catch(() => sendJson(response, { error: "invalid_state" }, 400));
return;
}
if (request.method === "GET" && url.pathname === `/api/v1/private-assets/projects/${projectId}/images/${backgroundId}`) return send(response, 200, backgroundSvg, "image/svg+xml");
if (request.method === "POST" && url.pathname === "/api/v1/location/reverse-geocode") return sendJson(response, { formatted_value: "浙江省温州市", service_mode: "mock", status: "resolved" });
const publicMatch = url.pathname.match(/^\/api\/v1\/assets\/public\/([^/]+)\/([^/]+)$/);
if (request.method === "GET" && publicMatch) {
const assetId = decodeURIComponent(publicMatch[2]);
const asset = publicAssets[assetId];
if (!asset) return sendJson(response, { error: "not_found" }, 404);
return send(response, 200, readFileSync(asset[0]), asset[1]);
}
next();
});
},
};
const vite = await createServer({
configFile: resolve("apps/web/vite.config.ts"), plugins: [mockApi], root: resolve("apps/web"),
server: { host, port, strictPort: true },
});
await vite.listen();
console.log(`WP4-04 manual preview: http://${host}:${port}/app/projects/${projectId}/editor`);
for (const signal of ["SIGINT", "SIGTERM"]) process.once(signal, () => { void vite.close().finally(() => process.exit(0)); });