Replace Puppeteer fallback with PDFKit for reliable PDF generation in Firebase Functions
This commit is contained in:
149
backend/package-lock.json
generated
149
backend/package-lock.json
generated
@@ -12,6 +12,7 @@
|
||||
"@google-cloud/documentai": "^9.3.0",
|
||||
"@google-cloud/storage": "^7.16.0",
|
||||
"@supabase/supabase-js": "^2.53.0",
|
||||
"@types/pdfkit": "^0.17.2",
|
||||
"axios": "^1.11.0",
|
||||
"bcryptjs": "^2.4.3",
|
||||
"cors": "^2.8.5",
|
||||
@@ -26,6 +27,7 @@
|
||||
"morgan": "^1.10.0",
|
||||
"openai": "^5.10.2",
|
||||
"pdf-parse": "^1.1.1",
|
||||
"pdfkit": "^0.17.1",
|
||||
"pg": "^8.11.3",
|
||||
"puppeteer": "^21.11.0",
|
||||
"redis": "^4.6.10",
|
||||
@@ -1097,6 +1099,15 @@
|
||||
"@supabase/storage-js": "^2.10.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/helpers": {
|
||||
"version": "0.5.17",
|
||||
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.17.tgz",
|
||||
"integrity": "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"tslib": "^2.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tootallnate/once": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz",
|
||||
@@ -1276,6 +1287,15 @@
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/pdfkit": {
|
||||
"version": "0.17.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/pdfkit/-/pdfkit-0.17.2.tgz",
|
||||
"integrity": "sha512-a7mqP/l8lsLMVNhQ3N2blU5pA1KX0YFE8FxWp0OTqZQKEZoPk7ndAlW+kdFBAWpFmLpy6fFbMRm4a6ZELWNgOQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/pg": {
|
||||
"version": "8.15.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.15.4.tgz",
|
||||
@@ -1984,6 +2004,15 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/brotli": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/brotli/-/brotli-1.3.3.tgz",
|
||||
"integrity": "sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"base64-js": "^1.1.2"
|
||||
}
|
||||
},
|
||||
"node_modules/buffer": {
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
|
||||
@@ -2159,6 +2188,15 @@
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/clone": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
|
||||
"integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/cluster-key-slot": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz",
|
||||
@@ -2356,6 +2394,12 @@
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/crypto-js": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz",
|
||||
"integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/data-uri-to-buffer": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz",
|
||||
@@ -2437,6 +2481,12 @@
|
||||
"integrity": "sha512-pM27vqEfxSxRkTMnF+XCmxSEb6duO5R+t8A9DEEJgy4Wz2RVanje2mmj99B6A3zv2r/qGfYlOvYznUhuokizmg==",
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/dfa": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/dfa/-/dfa-1.2.0.tgz",
|
||||
"integrity": "sha512-ED3jP8saaweFTjeGX8HQPjeC1YYyZs98jGNZx6IiBvxW7JG5v492kamAQB3m2wop07CvU/RQmzcKr6bgcC5D/Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/diff": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
|
||||
@@ -3026,7 +3076,6 @@
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
|
||||
"devOptional": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/fast-fifo": {
|
||||
@@ -3337,6 +3386,23 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/fontkit": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/fontkit/-/fontkit-2.0.4.tgz",
|
||||
"integrity": "sha512-syetQadaUEDNdxdugga9CpEYVaQIxOwk7GlwZWWZ19//qW4zE5bknOKeMBDYAASwnpaSHKJITRLMF9m1fp3s6g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@swc/helpers": "^0.5.12",
|
||||
"brotli": "^1.3.2",
|
||||
"clone": "^2.1.2",
|
||||
"dfa": "^1.2.0",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"restructure": "^3.0.0",
|
||||
"tiny-inflate": "^1.0.3",
|
||||
"unicode-properties": "^1.4.0",
|
||||
"unicode-trie": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/form-data": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz",
|
||||
@@ -4140,6 +4206,12 @@
|
||||
"url": "https://github.com/sponsors/panva"
|
||||
}
|
||||
},
|
||||
"node_modules/jpeg-exif": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/jpeg-exif/-/jpeg-exif-1.1.4.tgz",
|
||||
"integrity": "sha512-a+bKEcCjtuW5WTdgeXFzswSrdqi0jk4XlEtZlx5A94wCoBpFjfFTbo/Tra5SpNCl/YFZPvcV1dJc+TAYeg6ROQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
@@ -4295,6 +4367,25 @@
|
||||
"resolved": "https://registry.npmjs.org/limiter/-/limiter-1.1.5.tgz",
|
||||
"integrity": "sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA=="
|
||||
},
|
||||
"node_modules/linebreak": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/linebreak/-/linebreak-1.1.0.tgz",
|
||||
"integrity": "sha512-MHp03UImeVhB7XZtjd0E4n6+3xr5Dq/9xI/5FptGk5FrbDR3zagPa2DS6U8ks/3HjbKWG9Q1M2ufOzxV2qLYSQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"base64-js": "0.0.8",
|
||||
"unicode-trie": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/linebreak/node_modules/base64-js": {
|
||||
"version": "0.0.8",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-0.0.8.tgz",
|
||||
"integrity": "sha512-3XSA2cR/h/73EzlXXdU6YNycmYI7+kicTxks4eJg2g39biHR84slg2+des+p7iHYhbRg/udIS4TD53WabcOUkw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/lines-and-columns": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
|
||||
@@ -4877,6 +4968,12 @@
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/pako": {
|
||||
"version": "0.2.9",
|
||||
"resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz",
|
||||
"integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/parent-module": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
|
||||
@@ -4991,6 +5088,19 @@
|
||||
"ms": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/pdfkit": {
|
||||
"version": "0.17.1",
|
||||
"resolved": "https://registry.npmjs.org/pdfkit/-/pdfkit-0.17.1.tgz",
|
||||
"integrity": "sha512-Kkf1I9no14O/uo593DYph5u3QwiMfby7JsBSErN1WqeyTgCBNJE3K4pXBn3TgkdKUIVu+buSl4bYUNC+8Up4xg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"crypto-js": "^4.2.0",
|
||||
"fontkit": "^2.0.4",
|
||||
"jpeg-exif": "^1.1.4",
|
||||
"linebreak": "^1.1.0",
|
||||
"png-js": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/pend": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
|
||||
@@ -5105,6 +5215,11 @@
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/png-js": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/png-js/-/png-js-1.0.0.tgz",
|
||||
"integrity": "sha512-k+YsbhpA9e+EFfKjTCH3VW6aoKlyNYI6NYdTfDL4CIvFnvsuO84ttonmZE7rc+v23SLTH8XX+5w/Ak9v0xGY4g=="
|
||||
},
|
||||
"node_modules/postgres-array": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz",
|
||||
@@ -5476,6 +5591,12 @@
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/restructure": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/restructure/-/restructure-3.0.2.tgz",
|
||||
"integrity": "sha512-gSfoiOEA0VPE6Tukkrr7I0RBdE0s7H1eFCDBk05l1KIQT1UIKNc5JZy6jdyW6eYH3aR3g5b3PuL77rq0hvwtAw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/retry": {
|
||||
"version": "0.13.1",
|
||||
"resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz",
|
||||
@@ -6123,6 +6244,12 @@
|
||||
"integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/tiny-inflate": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz",
|
||||
"integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/to-regex-range": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||
@@ -6397,6 +6524,26 @@
|
||||
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/unicode-properties": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/unicode-properties/-/unicode-properties-1.4.1.tgz",
|
||||
"integrity": "sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"base64-js": "^1.3.0",
|
||||
"unicode-trie": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/unicode-trie": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-2.0.0.tgz",
|
||||
"integrity": "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"pako": "^0.2.5",
|
||||
"tiny-inflate": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/unpipe": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
"@google-cloud/documentai": "^9.3.0",
|
||||
"@google-cloud/storage": "^7.16.0",
|
||||
"@supabase/supabase-js": "^2.53.0",
|
||||
"@types/pdfkit": "^0.17.2",
|
||||
"axios": "^1.11.0",
|
||||
"bcryptjs": "^2.4.3",
|
||||
"cors": "^2.8.5",
|
||||
@@ -42,6 +43,7 @@
|
||||
"morgan": "^1.10.0",
|
||||
"openai": "^5.10.2",
|
||||
"pdf-parse": "^1.1.1",
|
||||
"pdfkit": "^0.17.1",
|
||||
"pg": "^8.11.3",
|
||||
"puppeteer": "^21.11.0",
|
||||
"redis": "^4.6.10",
|
||||
|
||||
@@ -17,6 +17,25 @@ try {
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
// Import PDFKit for fallback PDF generation
|
||||
let PDFDocument: any;
|
||||
try {
|
||||
PDFDocument = require('pdfkit');
|
||||
} catch (error) {
|
||||
// Mock PDFKit for test environment
|
||||
PDFDocument = class MockPDFDocument {
|
||||
constructor() {}
|
||||
pipe() { return this; }
|
||||
end() { return this; }
|
||||
font() { return this; }
|
||||
fontSize() { return this; }
|
||||
text() { return this; }
|
||||
moveDown() { return this; }
|
||||
addPage() { return this; }
|
||||
};
|
||||
}
|
||||
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { logger } from '../utils/logger';
|
||||
@@ -756,73 +775,49 @@ class PDFGenerationService {
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a simple PDF without Chrome (fallback method)
|
||||
* Generate a simple PDF using PDFKit (fallback method)
|
||||
*/
|
||||
private async generateSimplePDF(analysisData: any): Promise<Buffer> {
|
||||
try {
|
||||
// Create a simple HTML document that can be converted to PDF
|
||||
const simpleHTML = this.generateSimpleHTML(analysisData);
|
||||
|
||||
// For now, return a simple text representation
|
||||
// In a production environment, you might want to use a different PDF library
|
||||
const textContent = this.convertAnalysisToText(analysisData);
|
||||
|
||||
// Create a simple HTML document
|
||||
const html = `
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>CIM Review Report</title>
|
||||
<style>
|
||||
body { font-family: Arial, sans-serif; margin: 40px; }
|
||||
h1 { color: #333; border-bottom: 2px solid #007bff; }
|
||||
h2 { color: #555; margin-top: 30px; }
|
||||
.section { margin-bottom: 20px; }
|
||||
.field { margin-bottom: 10px; }
|
||||
.label { font-weight: bold; color: #666; }
|
||||
.value { margin-left: 10px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>BLUEPOINT Capital Partners</h1>
|
||||
<h2>CIM Review Report</h2>
|
||||
<p><strong>Generated:</strong> ${new Date().toLocaleDateString()} at ${new Date().toLocaleTimeString()}</p>
|
||||
<hr>
|
||||
${textContent}
|
||||
<hr>
|
||||
<p><em>BLUEPOINT Capital Partners | CIM Document Processor | Confidential</em></p>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
|
||||
// Try to generate PDF with Puppeteer again, but with different options
|
||||
try {
|
||||
const page = await this.getPage();
|
||||
await page.setContent(html, { waitUntil: 'networkidle0' });
|
||||
const buffer = await page.pdf({
|
||||
format: 'A4',
|
||||
margin: { top: '0.5in', right: '0.5in', bottom: '0.5in', left: '0.5in' },
|
||||
printBackground: true,
|
||||
return new Promise((resolve, reject) => {
|
||||
const doc = new PDFDocument({
|
||||
size: 'A4',
|
||||
margins: {
|
||||
top: 50,
|
||||
bottom: 50,
|
||||
left: 50,
|
||||
right: 50
|
||||
}
|
||||
});
|
||||
this.releasePage(page);
|
||||
return buffer;
|
||||
} catch (puppeteerError) {
|
||||
logger.error('Puppeteer fallback also failed, returning error response', puppeteerError);
|
||||
throw new Error('PDF generation is currently unavailable. Please try again later.');
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('Simple PDF generation failed', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert analysis data to simple text format
|
||||
*/
|
||||
private convertAnalysisToText(analysisData: any): string {
|
||||
let text = '';
|
||||
const chunks: Buffer[] = [];
|
||||
doc.on('data', (chunk: Buffer) => chunks.push(chunk));
|
||||
doc.on('end', () => {
|
||||
const result = Buffer.concat(chunks);
|
||||
resolve(result);
|
||||
});
|
||||
doc.on('error', (error: any) => {
|
||||
reject(error);
|
||||
});
|
||||
|
||||
// Add header
|
||||
doc.fontSize(24)
|
||||
.font('Helvetica-Bold')
|
||||
.text('BLUEPOINT Capital Partners', { align: 'center' });
|
||||
|
||||
doc.moveDown(0.5);
|
||||
doc.fontSize(18)
|
||||
.font('Helvetica-Bold')
|
||||
.text('CIM Review Report', { align: 'center' });
|
||||
|
||||
doc.moveDown(0.5);
|
||||
doc.fontSize(10)
|
||||
.font('Helvetica')
|
||||
.text(`Generated: ${new Date().toLocaleDateString()} at ${new Date().toLocaleTimeString()}`, { align: 'center' });
|
||||
|
||||
doc.moveDown(2);
|
||||
|
||||
// Add content sections
|
||||
const sections = [
|
||||
{ title: 'Deal Overview', data: analysisData.dealOverview },
|
||||
{ title: 'Business Description', data: analysisData.businessDescription },
|
||||
@@ -835,27 +830,47 @@ class PDFGenerationService {
|
||||
|
||||
sections.forEach(section => {
|
||||
if (section.data) {
|
||||
text += `<div class="section"><h2>${section.title}</h2>`;
|
||||
// Add section title
|
||||
doc.fontSize(14)
|
||||
.font('Helvetica-Bold')
|
||||
.text(section.title);
|
||||
|
||||
doc.moveDown(0.5);
|
||||
|
||||
// Add section content
|
||||
Object.entries(section.data).forEach(([key, value]) => {
|
||||
if (value && typeof value !== 'object') {
|
||||
text += `<div class="field"><span class="label">${this.formatFieldName(key)}:</span><span class="value">${value}</span></div>`;
|
||||
doc.fontSize(10)
|
||||
.font('Helvetica-Bold')
|
||||
.text(`${this.formatFieldName(key)}:`, { continued: true });
|
||||
|
||||
doc.fontSize(10)
|
||||
.font('Helvetica')
|
||||
.text(` ${value}`);
|
||||
|
||||
doc.moveDown(0.3);
|
||||
}
|
||||
});
|
||||
|
||||
text += '</div>';
|
||||
doc.moveDown(1);
|
||||
}
|
||||
});
|
||||
|
||||
return text;
|
||||
// Add footer
|
||||
doc.moveDown(2);
|
||||
doc.fontSize(8)
|
||||
.font('Helvetica')
|
||||
.text('BLUEPOINT Capital Partners | CIM Document Processor | Confidential', { align: 'center' });
|
||||
|
||||
doc.end();
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error('PDFKit PDF generation failed', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate simple HTML for fallback PDF generation
|
||||
*/
|
||||
private generateSimpleHTML(analysisData: any): string {
|
||||
return this.convertAnalysisToText(analysisData);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generate HTML from CIM Review analysis data
|
||||
|
||||
Reference in New Issue
Block a user