const http = require('http'); const fs = require('fs'); const BACKEND_PORT = process.env.PORT || 7861; const CSS = `@media print { @page { size: A4; margin: 15mm 10mm; } body { -webkit-print-color-adjust: exact; } } body { font-family: -apple-system, sans-serif; font-size: 14px; line-height: 1.6; max-width: 746px; margin: 0 auto; padding: 20px; } h1,h2,h3 { font-weight: 600; margin: 16px 0 8px; } pre { background: #f6f8fa; padding: 16px; border-radius: 6px; overflow-x: auto; border: 1px solid #e1e4e8; } code { font-family: monospace; font-size: 13px; } p { margin: 8px 0; } table { border-collapse: collapse; width: 100%; margin: 12px 0; } th,td { border: 1px solid #dfe2e5; padding: 8px 12px; } th { background: #f1f3f4; } .chat-container { display: flex; flex-direction: column; gap: 16px; } .message-row { display: flex; gap: 10px; } .message-bubble { max-width: 85%; padding: 12px 16px; border-radius: 12px; } .ai-bubble { background: #fff; border: 1px solid #eee; } .user-bubble { background: #e8f0fe; } .avatar { width: 32px; height: 32px; border-radius: 50%; display: flex; align-items: center; justify-content: center; }`; function E(s) { return s.replace(/&/g,'&').replace(//g,'>'); } function shikiWrap(token, color) { return `${E(token)}`; } function generateShikiCode(lines) { return lines.map(line => { const parts = []; const tokens = line.split(/(\s+|[^a-zA-Z0-9_\s]+)/g); for (const tok of tokens) { if (!tok) continue; if (/^\s+$/.test(tok)) { parts.push(tok); continue; } let color = '#c9d1d9'; if (/^(const|let|var|function|return|if|else|for|async|await|import|from|export|class|extends|new|try|catch|throw|typeof|this|switch|case|break|continue|while|do|of|in|static|get|set|super|interface|type|void|null|undefined|true|false)$/.test(tok)) color = '#ff7b72'; else if (/^(console|log|error|fetch|Promise|Math|Date|JSON|Map|Set|Array|Object|String|Number|Error|setTimeout|clearTimeout|AbortController|AbortSignal|require|module|exports|process)$/.test(tok)) color = '#d2a8ff'; else if (/^\d+$/.test(tok)) color = '#79c0ff'; else if (/^[{}()\[\];,\.:=+\-*/<>!&|?%@~^'"`]+$/.test(tok)) color = '#c9d1d9'; else if (/^[A-Z]/.test(tok) && tok.length > 1) color = '#ffa657'; parts.push(shikiWrap(tok, color)); } return parts.join(''); }).join('\n'); } const CODE_LINES = [ 'async function fetchData(url, options = {}) {', ' const controller = new AbortController();', ' const timeout = setTimeout(() => controller.abort(), 30000);', ' try {', ' const response = await fetch(url, {', ' ...options,', ' signal: controller.signal,', " headers: { 'Content-Type': 'application/json' },", ' });', ' if (!response.ok) {', ' throw new Error(`HTTP ${response.status}: ${response.statusText}`);', ' }', ' const data = await response.json();', " console.log('Data received:', data);", ' return data;', ' } catch (error) {', " console.error('Fetch failed:', error.message);", ' throw error;', ' } finally {', ' clearTimeout(timeout);', ' }', '}', ]; const TEXT = '
This is a typical AI response explaining a concept with some details and examples that users commonly see in chat conversations.
'; function buildHtml(targetSizeMB) { const shikiCode = generateShikiCode(CODE_LINES); const codeBlock = `${shikiCode}`;
const codeBlockSize = Buffer.byteLength(codeBlock, 'utf8');
const textBlockSize = Buffer.byteLength(TEXT, 'utf8');
const overhead = 2048;
const targetBytes = targetSizeMB * 1024 * 1024 - overhead;
let html = `