import express from 'express'; import cors from 'cors'; import dotenv from 'dotenv'; import { HfInference } from '@huggingface/inference'; import fs from 'fs'; import path from 'path'; import { createClient } from '@supabase/supabase-js'; import ws from 'ws'; import { fileURLToPath } from 'url'; import { ZipArchive } from 'archiver'; // Fix for Node.js < 22: inject ws as global WebSocket for Supabase Realtime if (!globalThis.WebSocket) { globalThis.WebSocket = ws; } // Load environment variables dotenv.config(); const app = express(); const PORT = process.env.PORT || 5000; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const publicDir = path.join(__dirname, 'public'); const productsDir = path.join(publicDir, 'products'); const coversDir = path.join(publicDir, 'covers'); const packagesDir = path.join(publicDir, 'packages'); if (!fs.existsSync(publicDir)) fs.mkdirSync(publicDir, { recursive: true }); if (!fs.existsSync(productsDir)) fs.mkdirSync(productsDir, { recursive: true }); if (!fs.existsSync(coversDir)) fs.mkdirSync(coversDir, { recursive: true }); if (!fs.existsSync(packagesDir)) fs.mkdirSync(packagesDir, { recursive: true }); // Enable CORS so the React frontend on 5173 can talk to our API on 5000 app.use(cors()); app.use(express.json()); app.use('/static', express.static(publicDir)); // ---------------------------------------------------- // DATABASE CONFIGURATION: SUPABASE WITH JSON FALLBACK // ---------------------------------------------------- let isSupabaseConnected = false; let supabase = null; // Attempt Supabase Connection if credentials are provided if (process.env.SUPABASE_URL && process.env.SUPABASE_KEY && !process.env.SUPABASE_URL.includes('your-project-id')) { console.log('🔌 Connecting to Supabase Cloud Database...'); try { supabase = createClient(process.env.SUPABASE_URL, process.env.SUPABASE_KEY, { realtime: { transport: ws } }); isSupabaseConnected = true; console.log('✅ Connected to Supabase Cloud Database!'); } catch (err) { console.error('❌ Supabase Connection Error:', err.message); console.log('âš ī¸ Falling back to Local JSON Database.'); } } else { console.log('â„šī¸ Supabase credentials not set or using template. Using Local JSON Database.'); } // JSON File Database Fallback Configuration const DB_FILE = path.join(process.cwd(), 'db.json'); const readDb = () => { try { if (!fs.existsSync(DB_FILE)) { const defaultCatalog = [ { id: '1', title: 'ADHD Daily Focus Study Planner 2026', subtitle: 'The Ultimate Aesthetic Organization Notebook for Neurodivergent College Students', type: 'planner', price: 9.99, date: new Date().toLocaleDateString() }, { id: '2', title: 'AWS Certified Solutions Architect Study Guide SAA-C03', subtitle: 'The 30-Day Cram Sheet & High-Performance Practice Exam Bank', type: 'study_guide', price: 14.99, date: new Date().toLocaleDateString() } ]; fs.writeFileSync(DB_FILE, JSON.stringify(defaultCatalog, null, 2)); return defaultCatalog; } return JSON.parse(fs.readFileSync(DB_FILE, 'utf8')); } catch (err) { return []; } }; const writeDb = (data) => { fs.writeFileSync(DB_FILE, JSON.stringify(data, null, 2)); }; // Initialize Hugging Face Inference (used ONLY for SDXL image generation) const hf = new HfInference(process.env.HF_API_KEY || ''); // ---------------------------------------------------- // GROQ LLAMA 3.3 70B — Primary Text Generation Engine // ---------------------------------------------------- const groqChat = async (prompt, maxTokens = 1200) => { if (!process.env.GROQ_API_KEY) throw new Error('GROQ_API_KEY not configured in .env'); const res = await fetch('https://api.groq.com/openai/v1/chat/completions', { method: 'POST', headers: { 'Authorization': `Bearer ${process.env.GROQ_API_KEY}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ model: 'llama-3.3-70b-versatile', messages: [{ role: 'user', content: prompt }], max_tokens: maxTokens, temperature: 0.8 }) }); const data = await res.json(); if (!res.ok) throw new Error(data.error?.message || 'Groq API error'); return data.choices[0].message.content; }; const groqJsonChat = async (prompt, maxTokens = 3800) => { if (!process.env.GROQ_API_KEY) throw new Error('GROQ_API_KEY not configured in .env'); const res = await fetch('https://api.groq.com/openai/v1/chat/completions', { method: 'POST', headers: { 'Authorization': `Bearer ${process.env.GROQ_API_KEY}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ model: 'llama-3.3-70b-versatile', messages: [ { role: 'system', content: 'You are an elite expert digital product creator and author. You must respond ONLY with a valid JSON object matching the requested schema.' }, { role: 'user', content: prompt } ], response_format: { type: 'json_object' }, max_tokens: maxTokens, temperature: 0.8 }) }); const data = await res.json(); if (!res.ok) throw new Error(data.error?.message || 'Groq API error'); return JSON.parse(data.choices[0].message.content); }; const humanizeBookContent = async (content) => { if (!content) return content; console.log(`[HUMANIZER] Initiating 100% human-like refinement pass...`); const prompt = `You are an elite expert developmental editor and premium humanizer. Your absolute goal is to make this book/guide draft read exactly as if it was written by an incredibly intelligent, expert human author. CRITICAL DIRECTIVES: 1. PRESERVE THE LAYOUT EXACTLY: Do not alter any Markdown headers (#, ##, ###), Table of Contents, code blocks, or structured chapter key point summaries (✓). Keep the exact same format. 2. 100% HUMANIZED STYLE: Rewrite the content to flow naturally, using conversational yet highly authoritative, warm, and precise easy-to-read English. Prefer short active sentences and a direct tone. 3. REMOVE ALL AI TRADEMARK FLUFF: Eliminate ALL AI-like introductory filler, generic summaries, and hallmark transition phrases (e.g. "Let's dive in", "first and foremost", "it is important to remember", "a testament to", "unlock your potential", "delve into", "in today's digital era"). 4. ZERO REPETITION: Actively prune any redundant paragraphs, circular explanations, or repetitive AI patterns. 5. MAXIMIZE PRACTICAL VALUE: Make all descriptions direct, highly practical, and pack them with clear real-world examples. Do NOT summarize, truncate, or cut the length. Ensure the resulting book remains fully detailed, comprehensive, and complete. Here is the draft book content to humanize: --- ${content} --- Respond with ONLY the polished, 100% humanized markdown content. Do not include any introductory or concluding comments outside the markdown book.`; return await groqChat(prompt, 6500); }; const parseResponseFields = (text, defaultNiche = 'Digital Guide', defaultCta = 'Get instant access') => { const fields = { title: '', subtitle: '', description: '', tags: '', cta: '', thumbnailPrompt: '', productContent: '' }; if (!text) return fields; const keys = [ { key: 'title', name: 'TITLE', next: 'SUBTITLE' }, { key: 'subtitle', name: 'SUBTITLE', next: 'DESCRIPTION' }, { key: 'description', name: 'DESCRIPTION', next: 'TAGS' }, { key: 'tags', name: 'TAGS', next: 'CTA' }, { key: 'cta', name: 'CTA', next: 'THUMBNAIL_PROMPT' }, { key: 'thumbnailPrompt', name: 'THUMBNAIL_PROMPT', next: 'PRODUCT_CONTENT' }, { key: 'productContent', name: 'PRODUCT_CONTENT', next: 'ZZEND' } ]; // 1. Try strict matching with brackets first let hasBrackets = false; for (const k of keys) { const r = new RegExp(`\\[${k.name}\\]\\n?([\\s\\S]*?)(?=\\[${k.next}\\]|$)`, 'i'); const m = text.match(r); if (m && m[1].trim()) { fields[k.key] = m[1].trim(); hasBrackets = true; } } if (hasBrackets && fields.title) { return fields; } console.log("[PARSER] Strict bracket match failed/incomplete. Running smart lexical segmenter..."); // 2. Lexical Segmenter: find sections using common labels const getSection = (startRegex, endRegex) => { const startMatch = text.match(startRegex); if (!startMatch) return ''; const startIndex = startMatch.index + startMatch[0].length; let endIndex = text.length; if (endRegex) { const endMatch = text.match(endRegex); if (endMatch && endMatch.index > startIndex) { endIndex = endMatch.index; } } return text.substring(startIndex, endIndex).trim(); }; const descLabel = /(?:^|\n)(?:description|\[description\]|\*\*description\*\*)\s*(?::|-|\n)\s*/i; const tagsLabel = /(?:^|\n)(?:tags|\[tags\]|\*\*tags\*\*)\s*(?::|-|\n)\s*/i; const thumbnailLabel = /(?:^|\n)(?:thumbnail\s*(?:prompt)?|\[thumbnail_prompt\]|\*\*thumbnail_prompt\*\*)\s*(?::|-|\n)\s*/i; const contentLabel = /(?:^|\n)(?:product\s*(?:content)?|\[product_content\]|\*\*product_content\*\*)\s*(?::|-|\n)\s*/i; const descText = getSection(descLabel, tagsLabel); const tagsText = getSection(tagsLabel, thumbnailLabel); const thumbText = getSection(thumbnailLabel, contentLabel); const contentText = getSection(contentLabel, null); fields.description = descText || fields.description; fields.tags = tagsText || fields.tags; fields.thumbnailPrompt = thumbText || fields.thumbnailPrompt; fields.productContent = contentText || fields.productContent; // Find TITLE and SUBTITLE (text before the description label) const preDesc = text.split(descLabel)[0].trim(); const preDescLines = preDesc.split('\n').map(l => l.trim()).filter(Boolean); if (preDescLines.length > 0) { fields.title = preDescLines[0].replace(/^(title:?|\[title\]|\*\*title\*\*)\s*/i, ''); if (preDescLines.length > 1) { fields.subtitle = preDescLines.slice(1).join(' ').replace(/^(subtitle:?|\[subtitle\]|\*\*subtitle\*\*)\s*/i, ''); } } // Find CTA (usually the lines between tags and thumbnailPrompt that are not tags) const preThumb = text.split(thumbnailLabel)[0].trim(); const preThumbLines = preThumb.split('\n').map(l => l.trim()).filter(Boolean); if (preThumbLines.length > 0) { for (let i = preThumbLines.length - 1; i >= 0; i--) { const line = preThumbLines[i]; if (!line.toLowerCase().startsWith('tags:') && !line.toLowerCase().startsWith('description:') && line.split(',').length < 3 && line.length > 10) { fields.cta = line.replace(/^(cta:?|\[cta\]|\*\*cta\*\*)\s*/i, ''); break; } } } // Clean up fields if they are still empty if (!fields.title) fields.title = defaultNiche; if (!fields.cta) fields.cta = defaultCta; if (fields.tags) { fields.tags = fields.tags.split('\n')[0].replace(/^(tags:?|\[tags\]|\*\*tags\*\*)\s*/i, '').trim(); } return fields; }; // Health Check Endpoint app.get('/api/health', (req, res) => { res.json({ status: 'ok', groqConfigured: !!process.env.GROQ_API_KEY, hfConfigured: !!process.env.HF_API_KEY, dbType: isSupabaseConnected ? 'supabase' : 'local_json', dbConnected: true }); }); // ---------------------------------------------------- // DATABASE CATALOG ENDPOINTS ("AI DB") // ---------------------------------------------------- app.get('/api/catalog', async (req, res) => { if (isSupabaseConnected) { try { const { data, error } = await supabase .from('catalog') .select('*') .order('id', { ascending: false }); if (error) throw error; return res.json(data || []); } catch (err) { console.error('Error fetching from Supabase:', err.message); // Fallback } } // JSON Fallback const catalog = readDb(); res.json(catalog); }); app.post('/api/catalog', async (req, res) => { const { title, subtitle, type, price, platform, thumbnail_url, tags, sales_copy, status, published_url } = req.body; if (!title) { return res.status(400).json({ error: 'Book title is required' }); } const finalPlatform = platform || 'kdp'; const finalStatus = status || 'draft'; const finalPrice = price || 9.99; if (isSupabaseConnected) { try { const { data, error } = await supabase .from('catalog') .insert([{ title, subtitle: subtitle || '', type: type || 'other', price: finalPrice, platform: finalPlatform, thumbnail_url: thumbnail_url || '', tags: tags || '', sales_copy: sales_copy || '', status: finalStatus, published_url: published_url || '' }]) .select(); if (error) throw error; if (data && data.length > 0) { return res.status(201).json(data[0]); } } catch (err) { console.error('Error saving to Supabase:', err.message); // Fallback } } // JSON Fallback const catalog = readDb(); const newBook = { id: Date.now().toString(), title, subtitle: subtitle || '', type: type || 'other', price: finalPrice, platform: finalPlatform, thumbnail_url: thumbnail_url || '', tags: tags || '', sales_copy: sales_copy || '', status: finalStatus, published_url: published_url || '', date: new Date().toLocaleDateString() }; catalog.unshift(newBook); writeDb(catalog); res.status(201).json(newBook); }); app.delete('/api/catalog/:id', async (req, res) => { const { id } = req.params; if (isSupabaseConnected) { try { const { error } = await supabase .from('catalog') .delete() .eq('id', id); if (error) throw error; return res.json({ success: true }); } catch (err) { console.error('Error deleting from Supabase:', err.message); // Fallback } } // JSON Fallback let catalog = readDb(); const originalLength = catalog.length; catalog = catalog.filter(book => book.id !== id); if (catalog.length === originalLength) { return res.status(404).json({ error: 'Book not found' }); } writeDb(catalog); res.json({ success: true }); }); // 1. TEXT GENERATION API (Uses Groq Llama 3.3 70B) app.post('/api/generate-text', async (req, res) => { const { prompt, maxTokens = 800 } = req.body; if (!process.env.GROQ_API_KEY) { return res.status(401).json({ error: 'Please set your GROQ_API_KEY in the server/.env file' }); } try { const text = await groqChat(prompt, maxTokens); res.json({ text }); } catch (error) { console.error('Groq Text Error:', error); res.status(500).json({ error: error.message }); } }); // 2. FREE COVER ART GENERATION API (Uses Stable Diffusion XL) app.post('/api/generate-cover', async (req, res) => { const { prompt, title } = req.body; if (!process.env.HF_API_KEY) { return res.status(401).json({ error: 'Please set your HF_API_KEY in the server/.env file' }); } const models = [ 'black-forest-labs/FLUX.1-schnell', 'stabilityai/stable-diffusion-xl-base-1.0', 'stabilityai/stable-diffusion-3.5-medium' ]; let responseBlob = null; let lastError = null; for (const model of models) { try { console.log(`[HF] Attempting cover generation with model: ${model}...`); responseBlob = await hf.textToImage({ model: model, inputs: prompt, parameters: model.includes('flux') ? {} : { negative_prompt: 'blurry, low quality, distorted, text, watermark' } }); console.log(`[HF] Successfully generated cover using model: ${model}`); break; } catch (err) { console.warn(`[HF] Model ${model} failed: ${err.message}`); lastError = err; } } const safeTitle = (title || 'cover').replace(/[^a-zA-Z0-9]/g, '_').toLowerCase(); const baseUrl = getBaseUrl(req); if (responseBlob) { try { const arrayBuffer = await responseBlob.arrayBuffer(); const buffer = Buffer.from(arrayBuffer); const base64Image = buffer.toString('base64'); const coverFilename = `${safeTitle}_${Date.now()}.jpg`; const coverPath = path.join(coversDir, coverFilename); fs.writeFileSync(coverPath, buffer); const coverUrl = `${baseUrl}/static/covers/${coverFilename}`; return res.json({ imageUrl: `data:image/jpeg;base64,${base64Image}`, coverUrl, coverFilename }); } catch (bufErr) { console.error('Error handling HF response buffer:', bufErr); lastError = bufErr; } } // ---------------------------------------------------- // RESILIENT FALLBACK: Generate Premium Vector SVG Cover // ---------------------------------------------------- console.log(`[HF] All models failed. Generating premium vector SVG fallback cover...`); const svgContent = ` BOOKFORGE
${(title || 'BOOKFORGE DIGITAL').toUpperCase()}
PREMIUM EDITION COMPLETE STUDY GUIDE & PLANNER
`; const svgBuffer = Buffer.from(svgContent); const base64Svg = svgBuffer.toString('base64'); const coverFilename = `${safeTitle}_${Date.now()}.svg`; const coverPath = path.join(coversDir, coverFilename); fs.writeFileSync(coverPath, svgBuffer); const coverUrl = `${baseUrl}/static/covers/${coverFilename}`; res.json({ imageUrl: `data:image/svg+xml;base64,${base64Svg}`, coverUrl, coverFilename }); }); // 3. MULTI-PLATFORM DIGITAL PRODUCT GENERATOR const PLATFORM_STRATEGIES = { gumroad: { name: 'Gumroad', emoji: '🟠', priceMin: 7, priceMax: 27, style: 'personal story + results proof', cta: 'Pay what you want or get instant access' }, etsy: { name: 'Etsy', emoji: '🟡', priceMin: 2, priceMax: 8, style: 'INSTANT DOWNLOAD urgency + printable keywords', cta: 'Instant Digital Download — Print at Home' }, kdp: { name: 'Amazon KDP', emoji: 'đŸ”ĩ', priceMin: 9, priceMax: 15, style: 'SEO keyword-first title', cta: 'Available on Amazon KDP — Kindle and Paperback' }, kofi: { name: 'Ko-fi', emoji: '☕', priceMin: 3, priceMax: 10, style: 'community + exclusivity + support', cta: 'Support the creator and get instant access' }, payhip: { name: 'Payhip', emoji: '💜', priceMin: 5, priceMax: 20, style: 'value stack + benefit headline', cta: 'Secure Checkout — Instant Delivery' }, creative: { name: 'Creative Market', emoji: '🎨', priceMin: 15, priceMax: 49, style: 'professional premium quality fonts/graphics', cta: 'Professional Grade — Commercial License Included' }, teachable:{ name: 'Teachable', emoji: '🎓', priceMin: 19, priceMax: 97, style: 'transformation promise complete guide', cta: 'Enroll Now — Lifetime Access' }, envato: { name: 'Envato', emoji: 'đŸŸĸ', priceMin: 12, priceMax: 45, style: 'premium theme/template professional', cta: 'Extended License Available' } }; // Helper to get base URL dynamically const getBaseUrl = (req) => { const host = req.headers['x-forwarded-host'] || req.headers.host || 'localhost:5000'; const protocol = req.headers['x-forwarded-proto'] || 'http'; const isHF = host.includes('hf.space'); return `${isHF ? 'https' : protocol}://${host}`; }; app.post('/api/generate-product', async (req, res) => { const { platform = 'gumroad', niche } = req.body; if (!niche) return res.status(400).json({ error: 'Niche is required' }); if (!process.env.GROQ_API_KEY) return res.status(401).json({ error: 'GROQ_API_KEY not configured' }); const strategy = PLATFORM_STRATEGIES[platform] || PLATFORM_STRATEGIES.gumroad; const optimalPrice = (Math.random() * (strategy.priceMax - strategy.priceMin) + strategy.priceMin).toFixed(2); const prompt = `Create a complete, high-converting digital book package for this niche: "${niche}", optimized for ${strategy.name} using the ${strategy.style} approach. CRITICAL ORIGINALITY & COPYRIGHT DIRECTIVES: - Content must be 100% original, creative, and written from scratch. Do NOT copy, paraphrase, or borrow from any copyrighted books, publications, or trademarked products. - Focus on high-value, highly practical content (e.g., comprehensive study guides, structured planners, templates, step-by-step how-to guides, and engaging hobby/educational materials) rather than low-quality generic text. - If this guide contains technical, factual, or educational information, ensure all facts are reviewed, verified, and include realistic, helpful examples and citations where appropriate. - COMPLIANCE & DISCLOSURE: Disclose AI assistance transparently as required by platform policies (e.g. KDP/Etsy). Add a small, elegant "Research & Editorial Note: Designed with the assistance of advanced generative tools and verified by human subject matter experts for accuracy" to the product introduction. Your response must be a single, valid JSON object matching this schema EXACTLY: { "title": "A viral, specific title optimized for self-publishing (e.g. '90-Day Indian Weight Loss Plan' instead of generic 'Weight Loss'). Max 80 characters.", "subtitle": "A benefit-driven subtitle with an emotional hook. Max 150 characters.", "description": "A 150-word high-converting product description with emotional hooks and bullet benefits.", "tags": "An array of exactly 5 comma-separated SEO tags for ${strategy.name}.", "cta": "One powerful call-to-action sentence (max 20 words).", "thumbnailPrompt": "A detailed Stable Diffusion prompt for a stunning professional product cover image. Include style, colors, composition. Keep under 80 words.", "productContent": "The actual complete high-quality digital book. Use this EXACT structure: - Detailed Table of Contents (listing all 5 chapters) - Chapter 1 - Introduction (Comprehensive introductory text in easy-to-read English, short paragraphs, real-world examples, ending with a 'Key Points' summary with checkmarks '✓') - Chapter 2 - Basics (Solid explanation of core concepts, foundational steps, ending with a 'Key Points' summary with checkmarks '✓') - Chapter 3 - Advanced Techniques (High-level professional strategies, ending with a 'Key Points' summary with checkmarks '✓') - Chapter 4 - Case Studies (Actionable case studies, templates, or checklists, ending with a 'Key Points' summary with checkmarks '✓') - Chapter 5 - Conclusion (Final takeaways, future roadmaps, ending with a 'Key Points' summary with checkmarks '✓')" } Ensure the "productContent" is extremely comprehensive, highly valuable, and direct, avoiding generic AI repetitions or empty introductory filler phrases. Let it be a complete, ready-to-sell book of at least 3000-4000 words. Provide highly detailed paragraphs, expert insights, step-by-step guidance, and real-world examples in every single chapter to maximize depth and quality.`; try { const data = await groqJsonChat(prompt, 6000); const title = data.title || niche; const subtitle = data.subtitle || ''; const description = data.description || ''; const tags = Array.isArray(data.tags) ? data.tags.join(', ') : (data.tags || ''); const cta = data.cta || strategy.cta; const thumbnailPrompt = data.thumbnailPrompt || ''; let productContent = data.productContent || 'Sample digital product guide content...'; // Humanizer Pass to make it 100% human-like try { console.log(`[HUMANIZER] Running humanization pass...`); productContent = await humanizeBookContent(productContent); console.log(`[HUMANIZER] Book successfully humanized!`); } catch (hErr) { console.error('Humanizer Pass failed, keeping original:', hErr); } // Save product content to file const safeTitle = (title || niche).replace(/[^a-zA-Z0-9]/g, '_').toLowerCase(); const productFilename = `${safeTitle}_${Date.now()}.md`; const productPath = path.join(productsDir, productFilename); fs.writeFileSync(productPath, productContent); const baseUrl = getBaseUrl(req); const productUrl = `${baseUrl}/static/products/${productFilename}`; res.json({ platform, platformName: strategy.name, platformEmoji: strategy.emoji, niche, title, subtitle, description, tags, cta, thumbnailPrompt, productContent, productFilename, productUrl, price: parseFloat(optimalPrice), priceLabel: `$${optimalPrice}`, }); } catch (err) { console.error('Generate Product Error:', err); res.status(500).json({ error: err.message }); } }); // ---------------------------------------------------- // AI AGENT AUTOPILOT ENGINE ("AUTO-PRODUCT PIPELINE") // ---------------------------------------------------- // ---------------------------------------------------- // ZIP PACKAGE BUILDER // Creates a downloadable ZIP with: book.md, cover.jpg, listing.txt // ---------------------------------------------------- const compile120PageHtml = (title, subtitle, tags, productContent, theme = 'classic') => { const text = productContent || ''; const BOOK_THEMES = { classic: { primary: '#000000', border: '#000000', bgLight: '#ffffff', dots: 'rgba(0,0,0,0.3)', gradient: '#000000' }, cherry: { primary: '#db2777', border: '#db2777', bgLight: '#fdf2f8', dots: 'rgba(219,39,119,0.35)', gradient: 'linear-gradient(135deg, #db2777, #7c3aed)' }, emerald: { primary: '#059669', border: '#059669', bgLight: '#ecfdf5', dots: 'rgba(5,150,105,0.35)', gradient: 'linear-gradient(135deg, #059669, #0891b2)' }, ocean: { primary: '#2563eb', border: '#2563eb', bgLight: '#eff6ff', dots: 'rgba(37,99,235,0.35)', gradient: 'linear-gradient(135deg, #2563eb, #0d9488)' }, sunset: { primary: '#d97706', border: '#d97706', bgLight: '#fffbeb', dots: 'rgba(217,119,6,0.35)', gradient: 'linear-gradient(135deg, #d97706, #dc2626)' } }; const themeCfg = BOOK_THEMES[theme] || BOOK_THEMES.classic; // Bulletproof Chapter Slicer bypassing the TOC const chapters = []; for (let idx = 1; idx <= 5; idx++) { const searchStr = `Chapter ${idx}`; const firstIdx = text.indexOf(searchStr); let startIndex = -1; if (firstIdx !== -1) { // Look for the second occurrence to bypass TOC startIndex = text.indexOf(searchStr, firstIdx + searchStr.length); if (startIndex === -1) { startIndex = firstIdx; // fallback to first } } if (startIndex !== -1) { let endIndex = text.length; if (idx < 5) { const nextSearchStr = `Chapter ${idx + 1}`; const nextFirstIdx = text.indexOf(nextSearchStr); let nextStartIndex = -1; if (nextFirstIdx !== -1) { nextStartIndex = text.indexOf(nextSearchStr, nextFirstIdx + nextSearchStr.length); if (nextStartIndex === -1) { nextStartIndex = nextFirstIdx; } } if (nextStartIndex !== -1) { endIndex = nextStartIndex; } } let chapterText = text.substring(startIndex, endIndex).trim(); // Remove trailing Markdown header symbols if present if (chapterText.endsWith('#')) { chapterText = chapterText.substring(0, chapterText.lastIndexOf('#')).trim(); } chapters.push(chapterText); } else { chapters.push(`Chapter ${idx}\n\nContent for chapter ${idx} is detailed here.`); } } // Dynamic 120-Page Assembler let pagesHtml = ''; // Page 1: Title Page pagesHtml += `
BOOKFORGE DIGITAL HUBS

${title}

${subtitle || ''}

COMPLETE GUIDE & PREMIUM BINDER
`; // Page 2: Copyright & Disclosures Page pagesHtml += ` `; // Page 3: Table of Contents pagesHtml += `
CONTENTS INDEX

TABLE OF CONTENTS

PREFACE & AUTHOR NOTE.......................................................................PAGE 4
CHAPTER 1 — INTRODUCTION & OVERVIEW.......................................................................PAGE 5
CHAPTER 1 GOAL WORKBOOKS & JOURNALS.......................................................................PAGE 7
CHAPTER 2 — FOUNDATIONS & CORE TECHNIQUES.......................................................................PAGE 29
CHAPTER 2 ROUTINE PLANNERS & RECORDS.......................................................................PAGE 31
CHAPTER 3 — ADVANCED DEEP-DIVE STRATEGIES.......................................................................PAGE 53
CHAPTER 3 STRATEGY WORKBOOKS.......................................................................PAGE 55
CHAPTER 4 — DETAILED CASE STUDY REVIEW.......................................................................PAGE 77
CHAPTER 4 ACTION PLAN CHECKS.......................................................................PAGE 79
CHAPTER 5 — CONCLUSION & ROADMAPS.......................................................................PAGE 101
CHAPTER 5 REFLECTION WORKBOOKS.......................................................................PAGE 103
Page 3
`; // Page 4: Preface / Intro letter pagesHtml += `
AUTHOR PREFACE

AUTHOR'S INTRODUCTORY LETTER

Welcome to this premium combined edition. Our mission is simple: to connect actionable, expert written guidance directly with physical, everyday structured exercises. By compiling this comprehensive textbook and planning journal package, you have the exact tools needed to bridge theory and active execution.

As you progress through each chapter, read the developmental insights generated to lay the conceptual groundwork. Immediately following the chapter summaries, you will find alternating worksheet templates designed to help you plan your tasks, reflect on hurdles, track habit indicators, and write details of your personal progress.

Set aside time daily, track your goals strictly, and let's forge your path to success page by page.

— The Editorial Team, BookForge Digital

Page 4
`; // Chapters Loop let globalPageNum = 5; for (let cIdx = 0; cIdx < 5; cIdx++) { const isLeft = globalPageNum % 2 !== 0; const chClass = isLeft ? 'left-page' : 'right-page'; const rawText = chapters[cIdx] || ''; // Clean and format text const cleanHeading = rawText.split('\n')[0].replace(/#+/g, '').replace(/:/g, '').trim().toUpperCase(); const bodyText = rawText.split('\n').slice(1).join('\n') .replace(/\n/g, '
') .replace(/✓ (.*?)(?=
)/g, '
  • ✓ $1
  • '); // 1. Chapter Title Page (1 page) pagesHtml += `
    CHAPTER DIVISION ${cIdx + 1}
    CHAPTER 0${cIdx + 1}

    ${cleanHeading}

    Detailed Written Guide & Workbook Interior

    Page ${globalPageNum}
    `; globalPageNum++; // 2. Chapter Written Content Page (1 page) const isLeft2 = globalPageNum % 2 !== 0; const chClass2 = isLeft2 ? 'left-page' : 'right-page'; pagesHtml += `
    ${cleanHeading}

    DEVELOPMENTAL MANUAL OUTLINE

    ${bodyText}

    Page ${globalPageNum}
    `; globalPageNum++; // 3. Alternate Workbook Sheets (22 pages for Chapters 1-4, 18 pages for Chapter 5) const numSheets = (cIdx === 4) ? 18 : 22; for (let sheetIdx = 0; sheetIdx < numSheets; sheetIdx++) { const isLeftSheet = globalPageNum % 2 !== 0; const chClassSheet = isLeftSheet ? 'left-page' : 'right-page'; let sheetContentHtml = ''; if (cIdx === 0) { if (sheetIdx % 2 === 0) { sheetContentHtml = `

    DAILY FOCUS TRACKER

    MY TOP 3 MOTIVATORS FOR TODAY
    CREATIVE SKETCH / NOTES AREA
    HIGH-PRIORITY TASKS
    `; } else { sheetContentHtml = `

    INSIGHT & NOTES

    ${'
    .
    '.repeat(80)}
    `; } } else if (cIdx === 1) { if (sheetIdx % 2 === 0) { sheetContentHtml = `

    CORE HABIT BUILDER

    HABITS TO BUILD
    âšĒâšĒâšĒâšĒâšĒâšĒâšĒ
    âšĒâšĒâšĒâšĒâšĒâšĒâšĒ
    âšĒâšĒâšĒâšĒâšĒâšĒâšĒ
    HABIT REFLECTION COMMENTS
    `; } else { sheetContentHtml = `

    CREATIVE BRAINSTORM LOG

    CENTRAL CONCEPT TOPIC
    `; } } else if (cIdx === 2) { if (sheetIdx % 2 === 0) { sheetContentHtml = `

    PRIORITY STRATEGY MATRIX

    đŸ”Ĩ 1. URGENT & IMPORTANT
    📅 2. NOT URGENT & IMPORTANT
    ⚡ 3. URGENT & NOT IMPORTANT
    💤 4. ELIMINATE / DELEGATE
    `; } else { sheetContentHtml = `

    INSIGHT & NOTES

    ${'
    .
    '.repeat(80)}
    `; } } else if (cIdx === 3) { if (sheetIdx % 2 === 0) { sheetContentHtml = `

    CASE STUDY REFLECTION LOG

    ACTION STEP REQUIREDTIMELINE
    ___ Days
    ___ Days
    ___ Days
    KEY PERFORMANCE METRIC TO DEFINE
    `; } else { sheetContentHtml = `

    CREATIVE BRAINSTORM LOG

    CENTRAL CONCEPT TOPIC
    `; } } else { if (sheetIdx % 2 === 0) { sheetContentHtml = `

    90-DAY PROGRESS SUMMARY

    MILESTONES COMPLETED & WINS
    FUTURE PERSPECTIVE ROADMAP
    `; } else { sheetContentHtml = `

    INSIGHT & NOTES

    ${'
    .
    '.repeat(80)}
    `; } } pagesHtml += `
    BOOKFORGE DIGITAL GOAL PLANNERS
    ${sheetContentHtml}
    Page ${globalPageNum}
    `; globalPageNum++; } } return ` ${title} - 120 Pages ${pagesHtml} `; }; const createProductZip = ({ title, subtitle, description, tags, cta, price, platform, productContent, coverBuffer, safeTitle, theme = 'classic' }) => { return new Promise((resolve, reject) => { const zipFilename = `${safeTitle}_${Date.now()}.zip`; const zipPath = path.join(packagesDir, zipFilename); const output = fs.createWriteStream(zipPath); const archive = new ZipArchive({ zlib: { level: 9 } }); output.on('close', () => resolve({ zipFilename, zipPath })); archive.on('error', reject); archive.pipe(output); // 1. Book content as markdown archive.append(productContent, { name: 'book_content.md' }); // 2. Cover image (if generated) if (coverBuffer) { const isSvg = coverBuffer.toString().trim().startsWith(' { const timestamp = new Date().toLocaleTimeString(); const selected = autopilotProducts[Math.floor(Math.random() * autopilotProducts.length)]; const selectedNiche = selected.niche; const selectedPlatform = selected.platform; const strategy = PLATFORM_STRATEGIES[selectedPlatform] || PLATFORM_STRATEGIES.gumroad; console.log(`🤖 Daily Generator: Creating package for '${selectedNiche}'...`); autopilotThoughts.unshift(`[${timestamp}] ${strategy.emoji} Daily Generator → Writing "${selectedNiche}"...`); if (autopilotThoughts.length > 40) autopilotThoughts.pop(); if (!process.env.GROQ_API_KEY) { autopilotThoughts.unshift(`[${timestamp}] ❌ Aborted: GROQ_API_KEY missing.`); return; } try { const prompt = `Create a complete, humanized digital product for: "${selectedNiche}" (targeting ${strategy.name} buyers). CRITICAL ORIGINALITY & COPYRIGHT DIRECTIVES: - Content must be 100% original, creative, and written from scratch. Do NOT copy, paraphrase, or borrow from any copyrighted books, publications, or trademarked products. - Focus on high-value, highly practical content (e.g., comprehensive study guides, structured planners, templates, step-by-step how-to guides, and engaging hobby/educational materials) rather than low-quality generic text. - If this guide contains technical, factual, or educational information, ensure all facts are reviewed, verified, and include realistic, helpful examples and citations where appropriate. - COMPLIANCE & DISCLOSURE: Disclose AI assistance transparently as required by platform policies (e.g. KDP/Etsy). Add a small, elegant "Research & Editorial Note: Designed with the assistance of advanced generative tools and verified by human subject matter experts for accuracy" to the product introduction. Your response must be a single, valid JSON object matching this schema EXACTLY: { "title": "A viral, specific title optimized for self-publishing (e.g. '90-Day Indian Weight Loss Plan' instead of generic 'Weight Loss'). Max 80 characters.", "subtitle": "A benefit-driven subtitle with an emotional hook. Max 150 characters.", "description": "A 150-word high-converting product description with emotional hooks and bullet benefits.", "tags": "An array of exactly 5 comma-separated SEO tags for ${strategy.name}.", "cta": "One powerful call-to-action sentence (max 20 words).", "thumbnailPrompt": "A detailed Stable Diffusion prompt for a stunning professional product cover image. Include style, colors, composition. Keep under 80 words.", "productContent": "The actual complete high-quality digital book. Use this EXACT structure: - Detailed Table of Contents (listing all 5 chapters) - Chapter 1 - Introduction (Comprehensive introductory text in easy-to-read English, short paragraphs, real-world examples, ending with a 'Key Points' summary with checkmarks '✓') - Chapter 2 - Basics (Solid explanation of core concepts, foundational steps, ending with a 'Key Points' summary with checkmarks '✓') - Chapter 3 - Advanced Techniques (High-level professional strategies, ending with a 'Key Points' summary with checkmarks '✓') - Chapter 4 - Case Studies (Actionable case studies, templates, or checklists, ending with a 'Key Points' summary with checkmarks '✓') - Chapter 5 - Conclusion (Final takeaways, future roadmaps, ending with a 'Key Points' summary with checkmarks '✓')" } Ensure the "productContent" is extremely comprehensive, highly valuable, and direct, avoiding generic AI repetitions or empty introductory filler phrases. Let it be a complete, ready-to-sell book of at least 500 words.`; const data = await groqJsonChat(prompt, 4000); const parsedTitle = data.title || selectedNiche; const parsedSubtitle = data.subtitle || ''; const parsedDescription = data.description || ''; const parsedTags = Array.isArray(data.tags) ? data.tags.join(', ') : (data.tags || ''); const parsedCta = data.cta || strategy.cta; const thumbnailPrompt = data.thumbnailPrompt || ''; let productContent = data.productContent || 'Content generation failed.'; // STEP 1.5: Humanizer Pass to make it 100% human-like if (productContent && productContent !== 'Content generation failed.') { autopilotThoughts.unshift(`[${timestamp}] âœī¸ Humanizer Pass → Refining book to 100% human-like tone...`); try { productContent = await humanizeBookContent(productContent); autopilotThoughts.unshift(`[${timestamp}] ✨ Humanizer Pass complete!`); } catch (hErr) { console.error('Autopilot Humanizer Pass failed:', hErr); autopilotThoughts.unshift(`[${timestamp}] âš ī¸ Humanizer Pass skipped: ${hErr.message}`); } } const recommendedPrice = parseFloat((Math.random() * (strategy.priceMax - strategy.priceMin) + strategy.priceMin).toFixed(2)); const safeTitle = parsedTitle.replace(/[^a-zA-Z0-9]/g, '_').toLowerCase().slice(0, 40); autopilotThoughts.unshift(`[${timestamp}] ✅ Book written! ${productContent.split(' ').length} words — "${parsedTitle.slice(0, 35)}..."`); // STEP 2: Generate cover image via Resilient HF Model Chain let coverBuffer = null; let coverUrl = ''; if (process.env.HF_API_KEY && thumbnailPrompt) { autopilotThoughts.unshift(`[${timestamp}] 🎨 HF → Initiating resilient cover art generation...`); const models = [ 'black-forest-labs/FLUX.1-schnell', 'stabilityai/stable-diffusion-xl-base-1.0', 'stabilityai/stable-diffusion-3.5-medium' ]; let responseBlob = null; for (const model of models) { try { console.log(`[HF Autopilot] Attempting cover generation with model: ${model}...`); responseBlob = await hf.textToImage({ model: model, inputs: thumbnailPrompt, parameters: model.includes('flux') ? {} : { negative_prompt: 'blurry, low quality, distorted, text, watermark' } }); console.log(`[HF Autopilot] Successfully generated cover using model: ${model}`); break; } catch (err) { console.warn(`[HF Autopilot] Model ${model} failed: ${err.message}`); } } if (responseBlob) { try { const arrayBuffer = await responseBlob.arrayBuffer(); coverBuffer = Buffer.from(arrayBuffer); const coverFilename = `${safeTitle}_${Date.now()}.jpg`; const coverPath = path.join(coversDir, coverFilename); fs.writeFileSync(coverPath, coverBuffer); const spaceUrl = process.env.SPACE_ID ? `https://${process.env.SPACE_ID.replace('/', '-')}.hf.space` : 'http://localhost:5000'; coverUrl = `${spaceUrl}/static/covers/${coverFilename}`; autopilotThoughts.unshift(`[${timestamp}] đŸ–ŧī¸ Cover generated successfully!`); } catch (bufErr) { console.error('[HF Autopilot] Error processing response buffer:', bufErr); } } else { // Fallback Vector SVG Cover console.log(`[HF Autopilot] All models failed. Generating premium vector SVG fallback cover...`); autopilotThoughts.unshift(`[${timestamp}] âš ī¸ HF models rate-limited. Generating premium vector SVG cover...`); const svgContent = ` BOOKFORGE
    ${(parsedTitle || 'BOOKFORGE DIGITAL').toUpperCase()}
    PREMIUM EDITION COMPLETE STUDY GUIDE & PLANNER
    `; coverBuffer = Buffer.from(svgContent); const coverFilename = `${safeTitle}_${Date.now()}.svg`; const coverPath = path.join(coversDir, coverFilename); fs.writeFileSync(coverPath, coverBuffer); const spaceUrl = process.env.SPACE_ID ? `https://${process.env.SPACE_ID.replace('/', '-')}.hf.space` : 'http://localhost:5000'; coverUrl = `${spaceUrl}/static/covers/${coverFilename}`; autopilotThoughts.unshift(`[${timestamp}] đŸ–ŧī¸ Premium vector SVG cover created!`); } } // STEP 3: Create ZIP package autopilotThoughts.unshift(`[${timestamp}] đŸ“Ļ Packaging into ZIP (book + cover + listing)...`); const { zipFilename } = await createProductZip({ title: parsedTitle, subtitle: parsedSubtitle, description: parsedDescription, tags: parsedTags, cta: parsedCta, price: recommendedPrice, platform: selectedPlatform, productContent, coverBuffer, safeTitle }); const spaceUrl = process.env.SPACE_ID ? `https://${process.env.SPACE_ID.replace('/', '-')}.hf.space` : 'http://localhost:5000'; const packageUrl = `${spaceUrl}/static/packages/${zipFilename}`; autopilotThoughts.unshift(`[${timestamp}] đŸ“Ļ ZIP ready! 🔗 ${packageUrl}`); // STEP 4: Save to catalog const catalogEntry = { title: parsedTitle, subtitle: parsedSubtitle, type: selected.type, price: recommendedPrice, platform: selectedPlatform, tags: parsedTags, sales_copy: parsedDescription, thumbnail_url: coverUrl, status: 'ready_to_publish', published_url: packageUrl // stores the ZIP download URL }; if (isSupabaseConnected) { try { const { error } = await supabase.from('catalog').insert([catalogEntry]); if (error) throw error; autopilotThoughts.unshift(`[${timestamp}] ✅ Saved to catalog! Download ZIP to publish manually.`); } catch (err) { const catalog = readDb(); catalog.unshift({ id: Date.now().toString(), ...catalogEntry, date: new Date().toLocaleDateString() }); writeDb(catalog); autopilotThoughts.unshift(`[${timestamp}] ✅ Saved to local catalog.`); } } else { const catalog = readDb(); catalog.unshift({ id: Date.now().toString(), ...catalogEntry, date: new Date().toLocaleDateString() }); writeDb(catalog); autopilotThoughts.unshift(`[${timestamp}] ✅ Saved to local catalog.`); } } catch (err) { console.error('Daily Generator Error:', err); autopilotThoughts.unshift(`[${timestamp}] ❌ Error: ${err.message}`); } }; app.get('/api/autopilot/status', (req, res) => { res.json({ active: !!autopilotInterval, thoughts: autopilotThoughts }); }); app.post('/api/autopilot/toggle', (req, res) => { const { active, intervalMs = 86400000 } = req.body; // Default 24 hours if (active) { if (autopilotInterval) clearInterval(autopilotInterval); runAutopilotSequence(); // Run immediately on activation autopilotInterval = setInterval(runAutopilotSequence, intervalMs); autopilotThoughts.unshift(`[${new Date().toLocaleTimeString()}] 🚀 Daily Generator ACTIVATED. Running every ${Math.round(intervalMs / 3600000)}h. Generating first package now...`); } else { if (autopilotInterval) { clearInterval(autopilotInterval); autopilotInterval = null; } autopilotThoughts.unshift(`[${new Date().toLocaleTimeString()}] 🛑 Daily Generator STOPPED.`); } res.json({ active: !!autopilotInterval }); }); // ---------------------------------------------------- // GUMROAD PUBLISHING AGENT ENGINE // ---------------------------------------------------- const publishToGumroad = async ({ title, description, price, productUrl, coverUrl, token }) => { if (!token) throw new Error('Gumroad Access Token is required'); console.log(`[GUMROAD] Creating product "${title}"...`); // 1. Create redirect product const createRes = await fetch('https://api.gumroad.com/v2/products', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ access_token: token, name: title, price: Math.round(price * 100), // in cents description: description, url: productUrl, // redirect URL redirect_to_external_url: true // Tells Gumroad to redirect buyers to the URL after purchase }) }); const createData = await createRes.json(); if (!createRes.ok || !createData.success) { throw new Error((createData && createData.message) || 'Failed to create product on Gumroad'); } const gumroadProduct = createData.product; const productId = gumroadProduct.id; console.log(`[GUMROAD] Product created. ID: ${productId}`); // 2. Attach Cover Image (if coverUrl is provided) if (coverUrl) { console.log(`[GUMROAD] Attaching cover image from: ${coverUrl}...`); const coverRes = await fetch(`https://api.gumroad.com/v2/products/${productId}/covers`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ access_token: token, url: coverUrl }) }); const coverData = await coverRes.json(); if (!coverRes.ok || !coverData.success) { console.warn(`[GUMROAD] Warning: Failed to attach cover image: ${coverData ? coverData.message : 'Unknown'}`); } else { console.log(`[GUMROAD] Cover image attached successfully.`); } } // 3. Publish/Enable the product console.log(`[GUMROAD] Enabling/publishing product...`); const enableRes = await fetch(`https://api.gumroad.com/v2/products/${productId}/enable`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ access_token: token }) }); const enableData = await enableRes.json(); if (!enableRes.ok || !enableData.success) { throw new Error((enableData && enableData.message) || 'Failed to enable product on Gumroad'); } console.log(`[GUMROAD] Product published! Short URL: ${gumroadProduct.short_url}`); return { productId, publishedUrl: gumroadProduct.short_url }; }; app.post('/api/publish/gumroad', async (req, res) => { const { id, title, description, price, productUrl, coverUrl, token } = req.body; if (!token) return res.status(400).json({ error: 'Gumroad Access Token is required' }); try { const result = await publishToGumroad({ title, description, price, productUrl, coverUrl, token }); // Update database status if ID exists if (id) { if (isSupabaseConnected) { await supabase .from('catalog') .update({ status: 'published', published_url: result.publishedUrl, thumbnail_url: coverUrl || '' }) .eq('id', id); } else { const catalog = readDb(); const item = catalog.find(x => x.id === id); if (item) { item.status = 'published'; item.published_url = result.publishedUrl; item.thumbnail_url = coverUrl || ''; writeDb(catalog); } } } res.json({ success: true, publishedUrl: result.publishedUrl }); } catch (err) { console.error('Gumroad Publishing Error:', err); res.status(500).json({ error: err.message }); } }); // Manual on-demand package generator (called from Marketplace frontend) app.post('/api/generate-package', async (req, res) => { const { title, subtitle, description, tags, cta, price, platform, productContent, thumbnailPrompt, theme } = req.body; if (!title || !productContent) return res.status(400).json({ error: 'title and productContent required' }); try { const safeTitle = title.replace(/[^a-zA-Z0-9]/g, '_').toLowerCase().slice(0, 40); let coverBuffer = null; // Generate cover if prompt provided and HF key exists if (thumbnailPrompt && process.env.HF_API_KEY) { const models = [ 'black-forest-labs/FLUX.1-schnell', 'stabilityai/stable-diffusion-xl-base-1.0', 'stabilityai/stable-diffusion-3.5-medium' ]; let responseBlob = null; for (const model of models) { try { console.log(`[HF Package] Attempting cover generation with model: ${model}...`); responseBlob = await hf.textToImage({ model: model, inputs: thumbnailPrompt, parameters: model.includes('flux') ? {} : { negative_prompt: 'blurry, low quality, distorted, text, watermark' } }); console.log(`[HF Package] Successfully generated cover using model: ${model}`); break; } catch (err) { console.warn(`[HF Package] Model ${model} failed: ${err.message}`); } } if (responseBlob) { try { coverBuffer = Buffer.from(await responseBlob.arrayBuffer()); const coverFilename = `${safeTitle}_${Date.now()}.jpg`; fs.writeFileSync(path.join(coversDir, coverFilename), coverBuffer); } catch (bufErr) { console.error('[HF Package] Error processing response buffer:', bufErr); } } else { // Fallback Vector SVG Cover console.log(`[HF Package] All models failed. Generating premium vector SVG fallback cover...`); const svgContent = ` BOOKFORGE
    ${(title || 'BOOKFORGE DIGITAL').toUpperCase()}
    PREMIUM EDITION COMPLETE STUDY GUIDE & PLANNER
    `; coverBuffer = Buffer.from(svgContent); const coverFilename = `${safeTitle}_${Date.now()}.svg`; fs.writeFileSync(path.join(coversDir, coverFilename), coverBuffer); } } const { zipFilename } = await createProductZip({ title, subtitle, description, tags, cta, price, platform, productContent, coverBuffer, safeTitle, theme }); const baseUrl = getBaseUrl(req); const packageUrl = `${baseUrl}/static/packages/${zipFilename}`; res.json({ success: true, packageUrl, zipFilename }); } catch (err) { console.error('Package generation error:', err); res.status(500).json({ error: err.message }); } }); // Start Server app.listen(PORT, () => { console.log(`🚀 KDP AI Factory Backend running at http://localhost:${PORT}`); console.log(`🤖 Groq Llama 3.3 70B: ${process.env.GROQ_API_KEY ? 'CONFIGURED ✅' : 'NOT CONFIGURED ❌ (Add GROQ_API_KEY to .env)'}`); console.log(`🎨 HuggingFace SDXL: ${process.env.HF_API_KEY ? 'CONFIGURED ✅' : 'NOT CONFIGURED ❌ (Add HF_API_KEY to .env)'}`); });