const express = require('express'); const router = express.Router(); const fs = require('fs'); const path = require('path'); const appSettings = require('../config/settings'); const { getEnv, LLAMACPP, logger } = require('@nexusai/shared'); const LLAMA_URL = getEnv('LLAMA_SERVER_URL', LLAMACPP.DEFAULT_URL); router.get('/', (req, res) => { const { modelsFolderPath } = appSettings.load(); try { // Try scanning folder for .gguf files const files = fs.readdirSync(modelsFolderPath) .filter(f => f.endsWith('.gguf')); // Try loading models.json for richer metadata (label, description) let manifest = {}; try { const manifestPath = path.join(modelsFolderPath, 'models.json'); const raw = fs.readFileSync(manifestPath, 'utf8'); // Index manifest by filename for quick lookup const list = JSON.parse(raw); for (const m of list) { manifest[m.value] = m; } } catch { // No manifest — scan only, that's fine } const models = files.map(filename => ({ value: filename, label: manifest[filename]?.label ?? filename.replace('.gguf', ''), description: manifest[filename]?.description ?? null, size: getFileSizeMB(path.join(modelsFolderPath, filename)), })); res.json(models); } catch (err) { logger.error('[models] Failed to scan folder:', err.message); res.status(500).json({ error: `Could not read models folder: ${modelsFolderPath}` }); } }); router.get('/props', async (req, res) => { try { const response = await fetch(`${LLAMA_URL}/props`); if (!response.ok) throw new Error(`llama-server error: ${response.status}`); const data = await response.json(); res.json({ contextWindow: data.default_generation_settings?.n_ctx ?? null, modelAlias: data.model_alias, }); } catch (err) { logger.error('[models/props]', err.message); res.status(503).json({ error: 'Could not reach llama-server' }); } }); function getFileSizeMB(filepath) { try { const bytes = fs.statSync(filepath).size; return (bytes / (1024 ** 3)).toFixed(1) + ' GB'; // models are big — show GB } catch { return null; } } module.exports = router;