CognxSafeTrack
feat: Genspark-Standard upgrade, MLOps audit fixes, and XAMLÉ branding
eac938a
import puppeteer from 'puppeteer';
import { OnePagerData } from '../ai/types';
import { DocumentRenderer } from './types';
export class PdfOnePagerRenderer implements DocumentRenderer<OnePagerData> {
async render(data: OnePagerData): Promise<Buffer> {
// Design System Colors: Primary #1C7C54, Secondary #1B3A57, Accent #F4A261
const htmlContent = `
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
@import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@700&family=Inter:wght@400;600&display=swap');
body {
font-family: 'Inter', sans-serif;
color: #333;
line-height: 1.6;
margin: 0;
padding: 40px;
background-color: #fff;
}
header {
text-align: center;
margin-bottom: 30px;
padding-bottom: 20px;
border-bottom: 3px solid #F4A261;
}
.main-image {
width: 100%;
height: 250px;
object-fit: cover;
border-radius: 8px;
margin-bottom: 20px;
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
}
h1 {
font-family: 'Montserrat', sans-serif;
color: #1B3A57;
font-size: 28px;
margin: 0 0 10px 0;
text-transform: uppercase;
letter-spacing: 1px;
}
.tagline {
color: #1C7C54;
font-size: 16px;
font-weight: 600;
margin: 0;
}
.section {
margin-bottom: 30px;
}
h2 {
font-family: 'Montserrat', sans-serif;
color: #1B3A57;
font-size: 20px;
border-left: 4px solid #1C7C54;
padding-left: 10px;
margin-bottom: 15px;
}
p {
font-size: 14px;
margin: 0 0 10px 0;
color: #4a5568;
}
.cta {
margin-top: 50px;
text-align: center;
background-color: #1B3A57;
color: white;
padding: 20px;
border-radius: 8px;
}
.cta p {
color: white;
font-size: 16px;
font-weight: 600;
margin: 0;
}
</style>
</head>
<body>
<header>
${data.mainImage ? `<img src="${data.mainImage}" class="main-image" alt="Brand Visual">` : ''}
<h1>${data.title || '[Nom du Projet]'}</h1>
<p class="tagline">${data.tagline || '[Votre Slogan Stratégique]'}</p>
</header>
<div class="section">
<h2>Analyse du Problème</h2>
<p>${data.problem || '[Donnée à compléter]'}</p>
</div>
<div class="section">
<h2>Notre Solution Stratégique</h2>
<p>${data.solution || '[Donnée à compléter]'}</p>
</div>
<div class="section">
<h2>Cible et Opportunité</h2>
<p>${data.targetAudience || '[Donnée à compléter]'}</p>
</div>
<div class="section">
<h2>Modèle Économique & Croissance</h2>
<p>${data.businessModel || '[Donnée à compléter]'}</p>
</div>
${data.marketSources ? `
<div class="section" style="margin-top: 40px; border-top: 1px solid #e2e8f0; padding-top: 20px;">
<p style="font-size: 12px; color: #718096; text-align: center;"><strong>Sources & Données Réelles :</strong> ${data.marketSources}</p>
</div>` : ''}
<div class="cta">
<p>${data.callToAction || '[Action Suivante]'}</p>
</div>
</body>
</html>
`;
const browser = await puppeteer.launch({
executablePath: process.env.PUPPETEER_EXECUTABLE_PATH || undefined,
headless: true,
args: ['--no-sandbox', '--disable-setuid-sandbox'], // Required for running as root in Docker/HF
});
const page = await browser.newPage();
await page.setContent(htmlContent, { waitUntil: 'networkidle0' });
const pdfBuffer = await page.pdf({
format: 'A4',
printBackground: true,
margin: { top: '20px', right: '20px', bottom: '20px', left: '20px' }
});
await browser.close();
return pdfBuffer as Buffer;
}
}