const http = require('http'); const fs = require('fs'); const path = require('path'); const PORT = process.env.PORT || 3000; function body(req) { return new Promise((resolve) => { let s = ''; req.on('data', (c) => (s += c)); req.on('end', () => { try { resolve(JSON.parse(s || '{}')); } catch (_) { resolve({}); } }); }); } http.createServer(async (req, res) => { // CORS res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS'); res.setHeader('Access-Control-Allow-Headers', 'Content-Type'); if (req.method === 'OPTIONS') { res.writeHead(200); return res.end(); } // API: AI запрос if (req.method === 'POST' && req.url === '/api/ai') { try { const data = await body(req); const aiResponse = await fetch(process.env.AI_BASE_URL + '/chat/completions', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + process.env.AI_API_KEY }, body: JSON.stringify({ model: process.env.AI_MODEL, messages: data.messages || [] }) }); if (!aiResponse.ok) { throw new Error('AI error: ' + aiResponse.status); } const result = await aiResponse.json(); res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify(result)); } catch (error) { res.writeHead(500, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: error.message })); } return; } // Статика let file = req.url === '/' ? '/index.html' : req.url.split('?')[0]; const full = path.join(__dirname, file); if (full.startsWith(__dirname) && fs.existsSync(full) && fs.statSync(full).isFile()) { const ext = path.extname(full); const type = ext === '.css' ? 'text/css' : ext === '.js' ? 'application/javascript' : 'text/html'; res.writeHead(200, { 'Content-Type': type + '; charset=utf-8' }); return res.end(fs.readFileSync(full)); } res.writeHead(404); res.end('Not found'); }).listen(PORT, () => console.log('Сервер запущен на порту ' + PORT));