自动生成封面
This commit is contained in:
+14
@@ -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;
|
||||
}
|
||||
|
||||
+30
-3
@@ -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,
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user