const express = require("express"); const http = require("http"); const path = require("path"); const fs = require("fs"); const os = require("os"); const pino = require("pino"); const { generateMusicPlan } = require("./lib/music/generator"); const { loadMeta, computeGenreProfiles } = require("./lib/training"); const logger = pino({ level: process.env.LOG_LEVEL || "info" }); const app = express(); const server = http.createServer(app); const app = express(); app.use(express.json()); app.get("/health", (req, res) => { try { const meta = loadMeta(); res.json({ ok: true, uptime: process.uptime(), training: { step: meta.step, loss: meta.loss } }); } catch (err) { log.error({ err: err.message }, "health check failed"); res.status(500).json({ ok: false, error: err.message }); } }); app.use(express.json({ limit: "1mb" })); app.use((req, res, next) => { res.setHeader("Access-Control-Allow-Origin", "*"); res.setHeader("Access-Control-Allow-Headers", "Content-Type"); if (req.method === "OPTIONS") return res.sendStatus(200); next(); }); app.get("/health", (_req, res) => { res.json({ ok: true, uptime: process.uptime() }); }); app.get("/api/profiles", (_req, res) => { try { const profiles = computeGenreProfiles(); res.json({ ok: true, profiles }); } catch (error) { logger.error({ err: error }, "failed to compute profiles"); res.status(500).json({ ok: false, error: "profile computation failed" }); } }); app.get("/api/status", (_req, res) => { try { const meta = loadMeta(); res.json({ ok: true, meta }); } catch (error) { logger.error({ err: error }, "failed to load status"); res.status(500).json({ ok: false, error: "status read failed" }); } }); app.post("/api/generate", (req, res) => { const { genre, mood, duration, tempo, key, instruments } = req.body || {}; const result = generateMusicPlan({ genre, mood, duration, tempo, key, instruments }); if (!result.ok) { return res.status(400).json(result); } logger.info({ genre: result.metadata.genre, mood: result.metadata.mood, tempo: result.metadata.tempo, duration: result.metadata.duration }, "generated composition plan"); res.json(result); }); const PUBLIC_DIR = path.join(__dirname, "public"); app.use(express.static(PUBLIC_DIR)); app.get("*", (_req, res) => { res.sendFile(path.join(PUBLIC_DIR, "index.html")); }); server.listen(PORT, () => { const address = server.address(); const port = typeof address === "object" && address ? address.port : PORT; logger.info({ port }, "narrow ai music engine online"); fs.writeFileSync(path.join(os.homedir(), ".skynet_port"), String(port)); });