/**
* Generate PDFs for All Public Documents
* Creates downloadable PDFs for documents that will be visible on /docs.html
* Uses Puppeteer (headless Chrome) for PDF generation
*/
const { MongoClient } = require('mongodb');
const puppeteer = require('puppeteer');
const fs = require('fs').promises;
const path = require('path');
// Correct slugs for public documents (verified from database)
const PUBLIC_DOCS = [
// Getting Started (6)
'introduction',
'core-concepts',
'executive-summary-tractatus-inflection-point',
'implementation-guide-v1.1',
'implementation-guide',
'implementation-guide-python-examples',
// Research & Theory (7)
'tractatus-framework-research', // Working Paper v0.1
'pluralistic-values-research-foundations',
'the-27027-incident-a-case-study-in-pattern-recognition-bias',
'real-world-ai-governance-a-case-study-in-framework-failure-and-recovery',
'llm-integration-feasibility-research-scope',
'research-topic-concurrent-session-architecture',
'research-topic-rule-proliferation-transactional-overhead',
// Technical Reference (5)
'technical-architecture',
'api-reference-complete',
'api-javascript-examples',
'api-python-examples',
'openapi-specification',
// Advanced Topics (3)
'value-pluralism-faq',
'tractatus-ai-safety-framework-core-values-and-principles',
'organizational-theory-foundations',
// Business Leadership (1)
'business-case-tractatus-framework'
];
function generatePdfHtml(doc) {
let contentHtml = '';
if (doc.sections && doc.sections.length > 0) {
// Build from sections
doc.sections.forEach(section => {
contentHtml += `
${section.title}
\n`;
if (section.content_html) {
contentHtml += section.content_html + '\n';
}
});
} else if (doc.content_html) {
contentHtml = doc.content_html;
}
return `
${doc.title}
${contentHtml}
`;
}
async function generatePDF(doc, browser) {
try {
const outputPdf = path.join(__dirname, `../public/downloads/${doc.slug}.pdf`);
// Generate HTML
const html = generatePdfHtml(doc);
// Create new page
const page = await browser.newPage();
// Set content
await page.setContent(html, {
waitUntil: 'networkidle0'
});
// Generate PDF
await page.pdf({
path: outputPdf,
format: 'A4',
printBackground: true,
margin: {
top: '2cm',
right: '2cm',
bottom: '2cm',
left: '2cm'
}
});
await page.close();
console.log(` ✓ Generated: ${doc.slug}.pdf`);
return { success: true, slug: doc.slug };
} catch (error) {
console.error(` ✗ Failed: ${doc.slug} - ${error.message}`);
return { success: false, slug: doc.slug, error: error.message };
}
}
async function run() {
const client = new MongoClient('mongodb://localhost:27017');
let browser;
try {
await client.connect();
const db = client.db('tractatus_dev');
const collection = db.collection('documents');
console.log('═══════════════════════════════════════════════════════════');
console.log(' GENERATING PDFs FOR PUBLIC DOCUMENTS');
console.log('═══════════════════════════════════════════════════════════\n');
console.log(`Total documents: ${PUBLIC_DOCS.length}\n`);
// Ensure downloads directory exists
const downloadsDir = path.join(__dirname, '../public/downloads');
await fs.mkdir(downloadsDir, { recursive: true });
// Launch browser
console.log('Launching browser...\n');
browser = await puppeteer.launch({
headless: 'new',
args: ['--no-sandbox', '--disable-setuid-sandbox']
});
const results = {
success: [],
failed: [],
notFound: []
};
for (const slug of PUBLIC_DOCS) {
const doc = await collection.findOne({ slug });
if (!doc) {
console.log(` ⚠️ Not found: ${slug}`);
results.notFound.push(slug);
continue;
}
const result = await generatePDF(doc, browser);
if (result.success) {
results.success.push(slug);
// Update database with PDF path
await collection.updateOne(
{ slug },
{
$set: {
'download_formats.pdf': `/downloads/${slug}.pdf`,
updated_at: new Date()
}
}
);
} else {
results.failed.push({ slug, error: result.error });
}
}
console.log('\n═══════════════════════════════════════════════════════════');
console.log(' SUMMARY');
console.log('═══════════════════════════════════════════════════════════\n');
console.log(`✅ Successfully generated: ${results.success.length}`);
console.log(`✗ Failed: ${results.failed.length}`);
console.log(`⚠️ Not found: ${results.notFound.length}\n`);
if (results.failed.length > 0) {
console.log('Failed PDFs:');
results.failed.forEach(f => console.log(` - ${f.slug}: ${f.error}`));
}
if (browser) await browser.close();
await client.close();
process.exit(0);
} catch (error) {
console.error('Error:', error);
if (browser) await browser.close();
await client.close();
process.exit(1);
}
}
run();