自动生成封面
This commit is contained in:
parent
c082a30d62
commit
c2d5948301
7
bun.lock
7
bun.lock
@ -13,6 +13,7 @@
|
||||
"morgan": "^1.10.1",
|
||||
"pino": "^9.9.5",
|
||||
"pino-pretty": "^13.1.1",
|
||||
"playwright": "^1.55.0",
|
||||
"prisma": "^6.16.1",
|
||||
"zod": "^4.1.8",
|
||||
},
|
||||
@ -173,6 +174,8 @@
|
||||
|
||||
"fresh": ["fresh@2.0.0", "", {}, "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A=="],
|
||||
|
||||
"fsevents": ["fsevents@2.3.2", "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.2.tgz", { "os": "darwin" }, "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA=="],
|
||||
|
||||
"function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="],
|
||||
|
||||
"get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="],
|
||||
@ -259,6 +262,10 @@
|
||||
|
||||
"pkg-types": ["pkg-types@2.3.0", "", { "dependencies": { "confbox": "^0.2.2", "exsolve": "^1.0.7", "pathe": "^2.0.3" } }, "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig=="],
|
||||
|
||||
"playwright": ["playwright@1.55.0", "https://registry.npmmirror.com/playwright/-/playwright-1.55.0.tgz", { "dependencies": { "playwright-core": "1.55.0" }, "optionalDependencies": { "fsevents": "2.3.2" }, "bin": { "playwright": "cli.js" } }, "sha512-sdCWStblvV1YU909Xqx0DhOjPZE4/5lJsIS84IfN9dAZfcl/CIZ5O8l3o0j7hPMjDvqoTF8ZUcc+i/GL5erstA=="],
|
||||
|
||||
"playwright-core": ["playwright-core@1.55.0", "https://registry.npmmirror.com/playwright-core/-/playwright-core-1.55.0.tgz", { "bin": { "playwright-core": "cli.js" } }, "sha512-GvZs4vU3U5ro2nZpeiwyb0zuFaqb9sUiAJuyrWpcGouD8y9/HLgGbNRjIph7zU9D3hnPaisMl9zG9CgFi/biIg=="],
|
||||
|
||||
"prisma": ["prisma@6.16.1", "", { "dependencies": { "@prisma/config": "6.16.1", "@prisma/engines": "6.16.1" }, "peerDependencies": { "typescript": ">=5.1.0" }, "optionalPeers": ["typescript"], "bin": { "prisma": "build/index.js" } }, "sha512-MFkMU0eaDDKAT4R/By2IA9oQmwLTxokqv2wegAErr9Rf+oIe7W2sYpE/Uxq0H2DliIR7vnV63PkC1bEwUtl98w=="],
|
||||
|
||||
"process-warning": ["process-warning@5.0.0", "", {}, "sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA=="],
|
||||
|
||||
@ -23,6 +23,7 @@
|
||||
"morgan": "^1.10.1",
|
||||
"pino": "^9.9.5",
|
||||
"pino-pretty": "^13.1.1",
|
||||
"playwright": "^1.55.0",
|
||||
"prisma": "^6.16.1",
|
||||
"zod": "^4.1.8"
|
||||
},
|
||||
|
||||
14
src/app.ts
14
src/app.ts
@ -4,6 +4,7 @@ import helmet from 'helmet';
|
||||
import morgan from 'morgan';
|
||||
import { router as apiRouter } from './routes';
|
||||
import { errorHandler } from './middlewares/errorHandler';
|
||||
import path from 'path';
|
||||
|
||||
export function createApp() {
|
||||
const app = express();
|
||||
@ -16,6 +17,19 @@ export function createApp() {
|
||||
|
||||
app.get('/health', (_req: express.Request, res: express.Response) => res.json({ ok: true }));
|
||||
app.use('/api', apiRouter);
|
||||
|
||||
// 静态资源目录(相对于项目根目录)
|
||||
const distDir = path.resolve(process.cwd(), 'dist');
|
||||
|
||||
// 提供 dist 下的静态文件
|
||||
app.use(express.static(distDir));
|
||||
|
||||
// 对于非 /api 前缀且未命中的路由,回退返回 dist/index.html(适用于 SPA)
|
||||
app.get(/^\/(?!api)(.*)/, (_req, res, next) => {
|
||||
res.sendFile(path.join(distDir, 'index.html'), (err) => {
|
||||
if (err) next(err);
|
||||
});
|
||||
});
|
||||
app.use(errorHandler);
|
||||
return app;
|
||||
}
|
||||
|
||||
@ -3,6 +3,33 @@ import { prisma } from '../lib/prisma';
|
||||
import { basicAuth } from '../middlewares/basicAuth';
|
||||
import { CreateModelSchema, UpdateModelSchema, ListQuerySchema } from '../lib/validators';
|
||||
import { decodeBase64ToBuffer } from '../lib/base64';
|
||||
import { chromium } from 'playwright';
|
||||
import { readFile } from 'fs/promises';
|
||||
import path from 'path';
|
||||
|
||||
const dirname = new URL('.', import.meta.url).pathname;
|
||||
|
||||
async function generatePreviewImage(circuitModel: any) {
|
||||
const browser = await chromium.launch();
|
||||
const page = await browser.newPage();
|
||||
|
||||
await page.setViewportSize({ width: 1024, height: 1024 });
|
||||
// Load the lab page
|
||||
await page.goto(`http://localhost:${Number(process.env.PORT ?? 3000)}/lab?preview=true`, { waitUntil: 'load' });
|
||||
await page.waitForFunction(() => {
|
||||
// @ts-ignore
|
||||
return window.loadCircuitFromJSONText !== undefined;
|
||||
});
|
||||
const jsonText = JSON.stringify(circuitModel);
|
||||
// Inject the model data and render
|
||||
await page.evaluate((jsonText) => {
|
||||
// @ts-ignore
|
||||
window.loadCircuitFromJSONText(jsonText);
|
||||
}, jsonText);
|
||||
const image = await page.screenshot({ type: 'png' });
|
||||
await browser.close();
|
||||
return image;
|
||||
}
|
||||
|
||||
export const router = Router();
|
||||
|
||||
@ -10,14 +37,14 @@ export const router = Router();
|
||||
router.post('/', basicAuth, async (req: Request, res: Response) => {
|
||||
const parsed = CreateModelSchema.safeParse(req.body);
|
||||
if (!parsed.success) return res.status(400).json({ error: parsed.error.flatten() });
|
||||
const { title, desc, model, previewBase64, previewMime } = parsed.data;
|
||||
const { title, desc, model } = parsed.data;
|
||||
const created = await prisma.circuitModel.create({
|
||||
data: {
|
||||
title,
|
||||
desc,
|
||||
model,
|
||||
preview: decodeBase64ToBuffer(previewBase64),
|
||||
previewMime: previewBase64 ? (previewMime ?? 'image/png') : null,
|
||||
preview: await generatePreviewImage(model),
|
||||
previewMime: 'image/png',
|
||||
authorId: (req as any).user.id,
|
||||
},
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user