const express = require('express'); const path = require('path'); const cors = require('cors'); const app = express(); const PORT = process.env.PORT || 3000; // Simple in-memory rate limit per IP (token bucket) const buckets = new Map(); function rateLimit(req, res, next) { const ip = req.ip || req.connection.remoteAddress || 'unknown'; const now = Date.now(); const cap = 100; // tokens const refill = 50; // tokens per minute const b = buckets.get(ip) || { tokens: cap, last: now }; const elapsed = (now - b.last) / 1000 / 60; // minutes b.tokens = Math.min(cap, b.tokens + elapsed * refill); b.last = now; if (b.tokens < 1) { return res.status(429).json({ error: 'Too many requests. Please slow down.' }); } b.tokens -= 1; buckets.set(ip, b); next(); } // Middleware app.use(cors()); app.use(express.json({ limit: '2mb' })); // Health check app.get('/api/health', (req, res) => { res.json({ ok: true, time: Date.now(), service: 'VibeCode Local AI', version: '2.0.0' }); }); // Template generation endpoint app.post('/api/generate', rateLimit, async (req, res) => { try { const { prompt, template, style } = req.body || {}; if (!prompt || !template) { return res.status(400).json({ error: 'Missing required parameters: prompt, template' }); } // Template configurations const templates = { vibecode: { name: "VibeCode App", description: "Modern web app with vibecoding aesthetics", structure: { html: ` VibeApp

${prompt}

Modern vibes, clean code, smooth UX

Dashboard

Clean overview of your data

Analytics

Real-time insights

Settings

Configure your vibe

`, js: `// VibeApp JavaScript console.log('${prompt} loaded!'); document.addEventListener('DOMContentLoaded', function() { // Add smooth animations const cards = document.querySelectorAll('.glass'); cards.forEach((card, index) => { card.style.opacity = '0'; card.style.transform = 'translateY(20px)'; setTimeout(() => { card.style.transition = 'all 0.5s ease'; card.style.opacity = '1'; card.style.transform = 'translateY(0)'; }, index * 100); }); // Add hover effects const hero = document.querySelector('.neon'); if (hero) { hero.addEventListener('mouseenter', function() { this.style.textShadow = '0 0 20px currentColor, 0 0 30px currentColor'; }); hero.addEventListener('mouseleave', function() { this.style.textShadow = '0 0 10px currentColor'; }); } });` } }, website: { name: "Clean Website", description: "Professional business website", structure: { html: ` Professional Website - ${prompt}

${prompt}

We create amazing digital experiences

Fast & Efficient

Lightning-fast performance and optimized workflows

Quality Assured

Every project meets our highest standards

24/7 Support

Round-the-clock assistance when you need it

`, js: `// Professional Website JavaScript document.addEventListener('DOMContentLoaded', function() { console.log('Professional website loaded successfully'); // Smooth scrolling for anchor links document.querySelectorAll('a[href^="#"]').forEach(anchor => { anchor.addEventListener('click', function (e) { e.preventDefault(); document.querySelector(this.getAttribute('href')).scrollIntoView({ behavior: 'smooth' }); }); }); // Add intersection observer for animations const observerOptions = { threshold: 0.1, rootMargin: '0px 0px -50px 0px' }; const observer = new IntersectionObserver(function(entries) { entries.forEach(entry => { if (entry.isIntersecting) { entry.target.style.opacity = '1'; entry.target.style.transform = 'translateY(0)'; } }); }, observerOptions); // Observe elements for animation document.querySelectorAll('.text-center').forEach(el => { el.style.opacity = '0'; el.style.transform = 'translateY(20px)'; el.style.transition = 'all 0.6s ease'; observer.observe(el); }); });` } }, saas: { name: "SaaS Dashboard", description: "Analytics & admin panel", structure: { html: ` SaaS Dashboard - ${prompt}

Dashboard

${prompt}

Welcome back! Here's what's happening with your business.

Total Users

1,234

+12%

Revenue

$12,345

+8.2%

Growth

+23%

+4.1%

Active Users

856

-2.1%

Revenue Chart

User Activity

`, js: `// SaaS Dashboard JavaScript document.addEventListener('DOMContentLoaded', function() { // Initialize revenue chart const ctx1 = document.getElementById('revenueChart').getContext('2d'); new Chart(ctx1, { type: 'line', data: { labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'], datasets: [{ label: 'Revenue', data: [12000, 19000, 15000, 25000, 22000, 30000], borderColor: 'rgb(59, 130, 246)', backgroundColor: 'rgba(59, 130, 246, 0.1)', tension: 0.4, fill: true }] }, options: { responsive: true, plugins: { legend: { display: false } }, scales: { y: { beginAtZero: true, ticks: { callback: function(value) { return ' + value.toLocaleString(); } } } } } }); // Initialize activity chart const ctx2 = document.getElementById('activityChart').getContext('2d'); new Chart(ctx2, { type: 'doughnut', data: { labels: ['Desktop', 'Mobile', 'Tablet'], datasets: [{ data: [45, 35, 20], backgroundColor: [ 'rgba(59, 130, 246, 0.8)', 'rgba(16, 185, 129, 0.8)', 'rgba(245, 158, 11, 0.8)' ] }] }, options: { responsive: true, plugins: { legend: { position: 'bottom' } } } }); // Add real-time updates simulation function updateMetrics() { const metrics = document.querySelectorAll('.bg-white.p-6'); metrics.forEach(metric => { const value = metric.querySelector('.text-2xl'); if (value && Math.random() > 0.7) { // Simulate small changes const currentValue = parseFloat(value.textContent.replace(/[^0-9.]/g, '')); const change = (Math.random() - 0.5) * 0.1; const newValue = currentValue * (1 + change); value.textContent = value.textContent.replace(/\d+/, Math.round(newValue)); } }); } // Update metrics every 5 seconds setInterval(updateMetrics, 5000); });` } } }; const selectedTemplate = templates[template] || templates.vibecode; // Enhance based on style preferences let generatedHTML = selectedTemplate.structure.html; let generatedJS = selectedTemplate.structure.js; // Apply style modifications if (style) { if (style.includes('dark')) { generatedHTML = generatedHTML .replace(/bg-white/g, 'bg-gray-900') .replace(/text-gray-900/g, 'text-white') .replace(/text-gray-600/g, 'text-gray-300') .replace(/text-gray-500/g, 'text-gray-400') .replace(/bg-gray-50/g, 'bg-gray-800') .replace(/border-gray-200/g, 'border-gray-700') .replace(/shadow-sm/g, 'shadow-lg'); } if (style.includes('colorful') || style.includes('rainbow')) { generatedHTML = generatedHTML.replace( 'background: linear-gradient(135deg, #667eea 0%, #764ba2 100%)', 'background: linear-gradient(135deg, #ff6b6b, #4ecdc4, #45b7d1, #96ceb4, #feca57)' ).replace( 'from-blue-600 to-purple-600', 'from-red-500 via-yellow-500 to-green-500' ); } } const fullHTML = generatedHTML.replace('', ``); res.json({ success: true, template: selectedTemplate.name, html: generatedHTML, js: generatedJS, preview: fullHTML, description: selectedTemplate.description }); } catch (err) { console.error('Template generation error:', err); res.status(500).json({ error: 'Internal server error' }); } }); // Serve static files AFTER API routes to ensure API routes take precedence app.use(express.static(path.join(__dirname))); app.listen(PORT, () => { console.log(`VibeCode Local AI server running at http://localhost:${PORT}`); console.log('API routes registered:'); console.log(' GET /api/health'); console.log(' POST /api/generate'); });