implementing model selector
This commit is contained in:
@@ -138,7 +138,7 @@ function NumberSetting({ label, description, value, min, max, step = 1, onSave,
|
||||
function SettingsRow({ label, description, action }) {
|
||||
return (
|
||||
<div style={{
|
||||
display: 'flex', alignItems: 'center', justifyContent: 'space-between',
|
||||
display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between',
|
||||
padding: '14px 16px',
|
||||
borderBottom: '1px solid var(--border)',
|
||||
}}
|
||||
|
||||
@@ -8,6 +8,7 @@ const DEFAULTS = {
|
||||
recentEpisodeLimit: ORCHESTRATION.RECENT_EPISODE_LIMIT,
|
||||
semanticLimit: ORCHESTRATION.SEMANTIC_LIMIT,
|
||||
scoreThreshold: ORCHESTRATION.SCORE_THRESHOLD,
|
||||
modelsFolderPath: getEnv('MODELS_MANIFEST_PATH', '/mnt/nexus-models')
|
||||
};
|
||||
|
||||
function load() {
|
||||
|
||||
@@ -1,21 +1,52 @@
|
||||
// routes/models.js
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const {getEnv} = require('@nexusai/shared');
|
||||
|
||||
const MODELS_PATH = getEnv('MODELS_MANIFEST_PATH', path.join(__dirname, '../models.json'));
|
||||
const appSettings = require('../config/settings');
|
||||
|
||||
router.get('/', (req, res) => {
|
||||
const { modelsFolderPath } = appSettings.load();
|
||||
|
||||
try {
|
||||
const raw = fs.readFileSync(MODELS_PATH, 'utf8');
|
||||
const models = JSON.parse(raw);
|
||||
// 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) {
|
||||
console.error('[models] Failed to read manifest:', err.message);
|
||||
res.status(500).json({ error: 'Could not load models manifest' });
|
||||
console.error('[models] Failed to scan folder:', err.message);
|
||||
res.status(500).json({ error: `Could not read models folder: ${modelsFolderPath}` });
|
||||
}
|
||||
});
|
||||
|
||||
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;
|
||||
@@ -1,5 +1,6 @@
|
||||
const { Router } = require('express');
|
||||
const settings = require('../config/settings');
|
||||
const fs = require('fs');
|
||||
|
||||
const router = Router();
|
||||
|
||||
@@ -32,6 +33,18 @@ router.patch('/', (req, res) => {
|
||||
updates.scoreThreshold = val;
|
||||
}
|
||||
|
||||
if (req.body.modelsFolderPath !== undefined) {
|
||||
const val = req.body.modelsFolderPath.trim();
|
||||
if (!val) return res.status(400).json({ error: 'modelsFolderPath cannot be empty' });
|
||||
// Verify the path exists and is readable
|
||||
try {
|
||||
fs.readdirSync(val);
|
||||
} catch {
|
||||
return res.status(400).json({ error: `Path not accessible: ${val}` });
|
||||
}
|
||||
updates.modelsFolderPath = val;
|
||||
}
|
||||
|
||||
res.json(settings.save(updates));
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user