Spaces:
Sleeping
Sleeping
| const express = require("express"); | |
| const cors = require("cors"); | |
| const puppeteer = require("puppeteer"); | |
| const app = express(); | |
| const PORT = process.env.PORT || 7860; // Hugging Face uses port 786 | |
| // Middleware | |
| app.use(cors()); | |
| app.use(express.json({ limit: "5mb" })); | |
| // Root endpoint - Health check | |
| app.get("/", (_req, res) => { | |
| res.json({ | |
| status: "ok", | |
| message: "HTML to PDF API is running", | |
| version: "1.0.0", | |
| endpoints: { | |
| health: "GET / or GET /health", | |
| convert: "POST /api/html-to-pdf" | |
| }, | |
| usage: { | |
| method: "POST", | |
| url: "/api/html-to-pdf", | |
| body: { | |
| html_content: "Your HTML content here", | |
| pdf_options: { | |
| format: "A4", | |
| printBackground: true, | |
| margin: { | |
| top: "10mm", | |
| right: "10mm", | |
| bottom: "10mm", | |
| left: "10mm" | |
| } | |
| } | |
| } | |
| } | |
| }); | |
| }); | |
| // Health check endpoint | |
| app.get("/health", (_req, res) => { | |
| res.json({ | |
| status: "healthy", | |
| timestamp: new Date().toISOString(), | |
| uptime: process.uptime() | |
| }); | |
| }); | |
| // Main PDF conversion endpoint | |
| app.post("/api/html-to-pdf", async (req, res) => { | |
| let browser; | |
| const startTime = Date.now(); | |
| try { | |
| const { html_code: htmlContent, pdf_options: pdfOptions } = req.body || {}; | |
| // Validate input | |
| if (!htmlContent || !htmlContent.trim()) { | |
| return res.status(400).json({ | |
| error: "html_content is required", | |
| success: false | |
| }); | |
| } | |
| console.log(`[${new Date().toISOString()}] Starting PDF generation...`); | |
| // Launch browser | |
| browser = await puppeteer.launch({ | |
| executablePath: "/usr/bin/chromium", | |
| args: [ | |
| "--no-sandbox", | |
| "--disable-setuid-sandbox", | |
| "--disable-dev-shm-usage", | |
| "--disable-gpu", | |
| "--disable-software-rasterizer", | |
| "--disable-extensions", | |
| "--disable-background-networking", | |
| "--disable-default-apps", | |
| "--disable-sync", | |
| "--metrics-recording-only", | |
| "--mute-audio", | |
| "--no-first-run" | |
| ], | |
| headless: true | |
| }); | |
| const page = await browser.newPage(); | |
| // Set content | |
| await page.setContent( | |
| `<!DOCTYPE html> | |
| <html> | |
| <head> | |
| <meta charset="utf-8" /> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | |
| </head> | |
| <body> | |
| ${htmlContent} | |
| </body> | |
| </html>`, | |
| { | |
| waitUntil: "networkidle0", | |
| timeout: 30000 | |
| } | |
| ); | |
| // Generate PDF with default options merged with user options | |
| const defaultPdfOptions = { | |
| format: "A4", | |
| printBackground: true, | |
| margin: { | |
| top: "10mm", | |
| right: "10mm", | |
| bottom: "10mm", | |
| left: "10mm" | |
| } | |
| }; | |
| const pdfBuffer = await page.pdf({ | |
| ...defaultPdfOptions, | |
| ...(pdfOptions || {}) | |
| }); | |
| await browser.close(); | |
| browser = null; | |
| const processingTime = Date.now() - startTime; | |
| console.log(`[${new Date().toISOString()}] PDF generated successfully in ${processingTime}ms`); | |
| res.json({ | |
| pdf_base64: pdfBuffer.toString("base64"), | |
| success: true, | |
| processing_time_ms: processingTime, | |
| pdf_size_bytes: pdfBuffer.length | |
| }); | |
| } catch (err) { | |
| console.error(`[${new Date().toISOString()}] PDF Generation Error:`, err); | |
| if (browser) { | |
| try { | |
| await browser.close(); | |
| } catch (closeErr) { | |
| console.error("Browser close error:", closeErr); | |
| } | |
| } | |
| res.status(500).json({ | |
| error: "Failed to generate PDF", | |
| details: err.message, | |
| success: false | |
| }); | |
| } | |
| }); | |
| // 404 handler | |
| app.use((_req, res) => { | |
| res.status(404).json({ | |
| error: "Endpoint not found", | |
| available_endpoints: [ | |
| "GET /", | |
| "GET /health", | |
| "POST /api/html-to-pdf" | |
| ] | |
| }); | |
| }); | |
| // Start server | |
| app.listen(PORT, "0.0.0.0", () => { | |
| console.log(` | |
| ββββββββββββββββββββββββββββββββββββββββββ | |
| β HTML to PDF API Server β | |
| β Status: Running β β | |
| β Port: ${PORT} β | |
| β URL: http://0.0.0.0:${PORT} β | |
| ββββββββββββββββββββββββββββββββββββββββββ | |
| `); | |
| }); | |
| // Graceful shutdown | |
| process.on('SIGTERM', () => { | |
| console.log('SIGTERM signal received: closing HTTP server'); | |
| process.exit(0); | |
| }); | |
| process.on('SIGINT', () => { | |
| console.log('SIGINT signal received: closing HTTP server'); | |
| process.exit(0); | |
| }); |