Skip to content

Commit 91d8def

Browse files
committed
Merge branch 'master' of github.com:profullstack/generate-pdf-api
2 parents 98e17d0 + b499ff0 commit 91d8def

File tree

11 files changed

+235
-151
lines changed

11 files changed

+235
-151
lines changed

README.md

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,3 @@ node scripts/test-pdf-generation.js
401401
```
402402

403403
This script will generate a test PDF and output the detected Chrome path.
404-
405-
test2
406-

package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
"@supabase/supabase-js": "^2.49.4",
3131
"chalk": "^5.3.0",
3232
"commander": "^12.0.0",
33+
"docx": "^9.5.0",
3334
"dotenv": "^16.5.0",
3435
"dotenv-flow": "^4.1.0",
3536
"form-data": "^4.0.2",
@@ -38,11 +39,9 @@
3839
"jsdom": "^26.1.0",
3940
"mailgun.js": "^12.0.1",
4041
"marked": "^15.0.8",
41-
"pptxgenjs": "^3.12.0",
4242
"puppeteer": "^22.5.0",
4343
"qrcode": "^1.5.4",
4444
"stripe": "^14.22.0",
45-
"turndown": "^7.2.0",
4645
"uuid": "^11.1.0",
4746
"ws": "^8.18.1",
4847
"xlsx": "^0.18.5"

pnpm-lock.yaml

Lines changed: 54 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

public/js/api-client.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,8 @@ export class ApiClient {
8181
* @param {boolean} store - Whether to store the document in Supabase
8282
* @returns {Promise<Blob>} - Word document blob
8383
*/
84-
static async htmlToDoc(html, filename = 'document.doc', store = false) {
84+
static async htmlToDoc(html, filename = 'document.docx', store = false) {
85+
console.log('Sending HTML to DOC conversion request with filename:', filename);
8586
return this.fetchBinaryResponse(`${this.baseUrl}/html-to-doc`, {
8687
html,
8788
filename,

public/js/views/dashboard.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ function updateFilenameExtension(documentType) {
126126
// Add new extension based on document type
127127
const extensions = {
128128
pdf: '.pdf',
129-
doc: '.doc',
129+
doc: '.docx', // Updated from .doc to .docx
130130
excel: '.xlsx',
131131
ppt: '.pptx',
132132
epub: '.epub',
@@ -182,7 +182,9 @@ async function convertDocument() {
182182
break;
183183

184184
case 'doc':
185+
console.log('Converting to DOCX');
185186
result = await ApiClient.htmlToDoc(html, filename, storeDocument);
187+
console.log('DOCX conversion successful');
186188
break;
187189

188190
case 'excel':

src/routes/html-to-doc.js

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,20 @@ import { errorUtils } from '../utils/error-utils.js';
1010
*/
1111
export async function htmlToDocHandler(c) {
1212
try {
13-
const { html, filename = 'document.doc', store = false } = c.get('body');
13+
const { html, filename = 'document.docx', store = false } = c.get('body');
1414

15-
// Generate Word document from HTML
16-
const docBuffer = docService.generateDoc(html);
15+
// Ensure filename has the correct extension
16+
const finalFilename = filename.endsWith('.docx') ? filename : filename.replace(/\.doc$|$/, '.docx');
17+
18+
// Generate Word document from HTML - now returns a Promise
19+
const docBuffer = await docService.generateDoc(html);
1720

1821
// Store the document in Supabase if requested
1922
if (store) {
2023
try {
2124
// Extract metadata from the request
2225
const metadata = {
23-
contentType: 'application/msword',
26+
contentType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
2427
userAgent: c.req.header('user-agent'),
2528
timestamp: new Date().toISOString()
2629
};
@@ -29,7 +32,7 @@ export async function htmlToDocHandler(c) {
2932
const userEmail = c.get('userEmail');
3033

3134
// Store the document with user association and original HTML content
32-
const result = await storageService.storeDoc(docBuffer, filename, metadata, userEmail, html);
35+
const result = await storageService.storeDoc(docBuffer, finalFilename, metadata, userEmail, html);
3336

3437
// Add storage information to the response headers
3538
c.header('X-Storage-Path', result.path);
@@ -39,13 +42,14 @@ export async function htmlToDocHandler(c) {
3942
}
4043
}
4144

42-
// Set response headers
43-
c.header('Content-Type', 'application/msword');
44-
c.header('Content-Disposition', `attachment; filename="${filename}"`);
45+
// Set response headers for .docx format
46+
c.header('Content-Type', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document');
47+
c.header('Content-Disposition', `attachment; filename="${finalFilename}"`);
4548

4649
// Return the document buffer
4750
return c.body(docBuffer);
4851
} catch (error) {
52+
console.error('Error in HTML to DOC conversion:', error);
4953
return errorUtils.handleError(error, c);
5054
}
5155
}

src/routes/html-to-excel.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export async function htmlToExcelHandler(c) {
1313
const { html, filename = 'document.xlsx', sheetName = 'Sheet1', store = false } = c.get('body');
1414

1515
// Generate Excel spreadsheet from HTML tables
16-
const excelBuffer = excelService.generateExcel(html, sheetName);
16+
const excelBuffer = await excelService.generateExcel(html, sheetName);
1717

1818
// Store the Excel file in Supabase if requested
1919
if (store) {

src/services/doc-service.js

Lines changed: 51 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,60 @@
1+
import { exec } from 'child_process';
2+
import fs from 'fs';
3+
import path from 'path';
4+
import { promisify } from 'util';
5+
import { v4 as uuidv4 } from 'uuid';
6+
import os from 'os';
7+
8+
const execPromise = promisify(exec);
9+
110
/**
211
* Service for generating Word documents from HTML content
312
*/
413
export const docService = {
514
/**
6-
* Generate a Word document from HTML content
15+
* Generate a Word document from HTML content using pandoc
716
* @param {string} html - The HTML content to convert to Word format
8-
* @returns {Buffer} - A buffer containing the Word document data
17+
* @returns {Promise<Buffer>} - A buffer containing the Word document data
918
*/
10-
generateDoc(html) {
11-
// Create Word document from HTML
12-
const header = `
13-
<html xmlns:o='urn:schemas-microsoft-com:office:office'
14-
xmlns:w='urn:schemas-microsoft-com:office:word'
15-
xmlns='http://www.w3.org/TR/REC-html40'>
16-
<head><meta charset='utf-8'></head><body>`;
17-
const footer = `</body></html>`;
18-
const sourceHTML = header + html + footer;
19-
20-
// Add BOM (Byte Order Mark) for proper encoding in Word
21-
const bomPrefix = Buffer.from([0xEF, 0xBB, 0xBF]);
22-
const htmlBuffer = Buffer.from(sourceHTML);
23-
const docBuffer = Buffer.concat([bomPrefix, htmlBuffer]);
24-
25-
return docBuffer;
19+
async generateDoc(html) {
20+
try {
21+
// Create temporary files for input and output
22+
const tempDir = os.tmpdir();
23+
const inputId = uuidv4();
24+
const outputId = uuidv4();
25+
const inputPath = path.join(tempDir, `${inputId}.html`);
26+
const outputPath = path.join(tempDir, `${outputId}.docx`);
27+
28+
// Write HTML to temporary file
29+
await fs.promises.writeFile(inputPath, html, 'utf8');
30+
31+
// Use pandoc to convert HTML to DOCX
32+
const command = `pandoc -f html -t docx "${inputPath}" -o "${outputPath}"`;
33+
console.log(`Executing pandoc command: ${command}`);
34+
35+
await execPromise(command);
36+
37+
// Read the generated DOCX file
38+
const docBuffer = await fs.promises.readFile(outputPath);
39+
40+
// Clean up temporary files
41+
try {
42+
await fs.promises.unlink(inputPath);
43+
await fs.promises.unlink(outputPath);
44+
} catch (cleanupError) {
45+
console.warn('Error cleaning up temporary files:', cleanupError);
46+
}
47+
48+
return docBuffer;
49+
} catch (error) {
50+
console.error('Error generating Word document with pandoc:', error);
51+
52+
// If pandoc fails, provide a detailed error message
53+
if (error.stderr) {
54+
console.error('Pandoc error output:', error.stderr);
55+
}
56+
57+
throw new Error(`Failed to generate Word document: ${error.message}`);
58+
}
2659
}
2760
};

src/services/excel-service.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ export const excelService = {
99
* Generate an Excel spreadsheet from HTML content containing tables
1010
* @param {string} html - The HTML content containing tables
1111
* @param {string} sheetName - The name for the worksheet (default: 'Sheet1')
12-
* @returns {Buffer} - A buffer containing the Excel file data
12+
* @returns {Promise<Buffer>} - A buffer containing the Excel file data
1313
* @throws {Error} - If no tables are found in the HTML content
1414
*/
15-
generateExcel(html, sheetName = 'Sheet1') {
15+
async generateExcel(html, sheetName = 'Sheet1') {
1616
// Create a DOM from the HTML
1717
const dom = new JSDOM(html);
1818
const document = dom.window.document;

0 commit comments

Comments
 (0)