project-nomad/admin/start/routes.ts
Chris Sherwood 755807f95e feat: Add system benchmark feature with NOMAD Score
Add comprehensive benchmarking capability to measure server performance:

Backend:
- BenchmarkService with CPU, memory, disk, and AI benchmarks using sysbench
- Database migrations for benchmark_results and benchmark_settings tables
- REST API endpoints for running benchmarks and retrieving results
- CLI commands: benchmark:run, benchmark:results, benchmark:submit
- BullMQ job for async benchmark execution with SSE progress updates
- Synchronous mode option (?sync=true) for simpler local dev setup

Frontend:
- Benchmark settings page with circular gauges for scores
- NOMAD Score display with weighted composite calculation
- System Performance section (CPU, Memory, Disk Read/Write)
- AI Performance section (tokens/sec, time to first token)
- Hardware Information display
- Expandable Benchmark Details section
- Progress simulation during sync benchmark execution

Easy Setup Integration:
- Added System Benchmark to Additional Tools section
- Built-in capability pattern for non-Docker features
- Click-to-navigate behavior for built-in tools

Fixes:
- Docker log multiplexing issue (Tty: true) for proper output parsing
- Consolidated disk benchmarks into single container execution

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-22 21:48:12 -08:00

143 lines
5.7 KiB
TypeScript

/*
|--------------------------------------------------------------------------
| Routes file
|--------------------------------------------------------------------------
|
| The routes file is used for defining the HTTP routes.
|
*/
import BenchmarkController from '#controllers/benchmark_controller'
import DocsController from '#controllers/docs_controller'
import DownloadsController from '#controllers/downloads_controller'
import EasySetupController from '#controllers/easy_setup_controller'
import HomeController from '#controllers/home_controller'
import MapsController from '#controllers/maps_controller'
import OpenWebUIController from '#controllers/openwebui_controller'
import SettingsController from '#controllers/settings_controller'
import SystemController from '#controllers/system_controller'
import ZimController from '#controllers/zim_controller'
import router from '@adonisjs/core/services/router'
import transmit from '@adonisjs/transmit/services/main'
transmit.registerRoutes()
router.get('/', [HomeController, 'index'])
router.get('/home', [HomeController, 'home'])
router.on('/about').renderInertia('about')
router.get('/easy-setup', [EasySetupController, 'index'])
router.get('/easy-setup/complete', [EasySetupController, 'complete'])
router.get('/api/easy-setup/curated-categories', [EasySetupController, 'listCuratedCategories'])
router
.group(() => {
router.get('/system', [SettingsController, 'system'])
router.get('/apps', [SettingsController, 'apps'])
router.get('/legal', [SettingsController, 'legal'])
router.get('/maps', [SettingsController, 'maps'])
router.get('/models', [SettingsController, 'models'])
router.get('/update', [SettingsController, 'update'])
router.get('/zim', [SettingsController, 'zim'])
router.get('/zim/remote-explorer', [SettingsController, 'zimRemote'])
router.get('/benchmark', [SettingsController, 'benchmark'])
})
.prefix('/settings')
router
.group(() => {
router.get('/:slug', [DocsController, 'show'])
router.get('/', ({ inertia }) => {
return inertia.render('Docs/Index', {
title: 'Documentation',
content: 'Welcome to the documentation!',
})
})
})
.prefix('/docs')
router.get('/maps', [MapsController, 'index'])
router
.group(() => {
router.get('/regions', [MapsController, 'listRegions'])
router.get('/styles', [MapsController, 'styles'])
router.get('/preflight', [MapsController, 'checkBaseAssets'])
router.get('/curated-collections', [MapsController, 'listCuratedCollections'])
router.post('/fetch-latest-collections', [MapsController, 'fetchLatestCollections'])
router.post('/download-base-assets', [MapsController, 'downloadBaseAssets'])
router.post('/download-remote', [MapsController, 'downloadRemote'])
router.post('/download-remote-preflight', [MapsController, 'downloadRemotePreflight'])
router.post('/download-collection', [MapsController, 'downloadCollection'])
router.delete('/:filename', [MapsController, 'delete'])
})
.prefix('/api/maps')
router
.group(() => {
router.get('/list', [DocsController, 'list'])
})
.prefix('/api/docs')
router
.group(() => {
router.get('/jobs', [DownloadsController, 'index'])
router.get('/jobs/:filetype', [DownloadsController, 'filetype'])
})
.prefix('/api/downloads')
router.get('/api/health', () => {
return { status: 'ok' }
})
router
.group(() => {
router.get('/models', [OpenWebUIController, 'models'])
router.get('/installed-models', [OpenWebUIController, 'installedModels'])
router.post('/download-model', [OpenWebUIController, 'dispatchModelDownload'])
router.post('/delete-model', [OpenWebUIController, 'deleteModel'])
})
.prefix('/api/openwebui')
router
.group(() => {
router.get('/info', [SystemController, 'getSystemInfo'])
router.get('/internet-status', [SystemController, 'getInternetStatus'])
router.get('/services', [SystemController, 'getServices'])
router.post('/services/affect', [SystemController, 'affectService'])
router.post('/services/install', [SystemController, 'installService'])
router.post('/services/force-reinstall', [SystemController, 'forceReinstallService'])
router.get('/latest-version', [SystemController, 'checkLatestVersion'])
router.post('/update', [SystemController, 'requestSystemUpdate'])
router.get('/update/status', [SystemController, 'getSystemUpdateStatus'])
router.get('/update/logs', [SystemController, 'getSystemUpdateLogs'])
})
.prefix('/api/system')
router
.group(() => {
router.get('/list', [ZimController, 'list'])
router.get('/list-remote', [ZimController, 'listRemote'])
router.get('/curated-collections', [ZimController, 'listCuratedCollections'])
router.post('/fetch-latest-collections', [ZimController, 'fetchLatestCollections'])
router.post('/download-remote', [ZimController, 'downloadRemote'])
router.post('/download-collection', [ZimController, 'downloadCollection'])
router.delete('/:filename', [ZimController, 'delete'])
})
.prefix('/api/zim')
router
.group(() => {
router.post('/run', [BenchmarkController, 'run'])
router.post('/run/system', [BenchmarkController, 'runSystem'])
router.post('/run/ai', [BenchmarkController, 'runAI'])
router.get('/results', [BenchmarkController, 'results'])
router.get('/results/latest', [BenchmarkController, 'latest'])
router.get('/results/:id', [BenchmarkController, 'show'])
router.post('/submit', [BenchmarkController, 'submit'])
router.get('/comparison', [BenchmarkController, 'comparison'])
router.get('/status', [BenchmarkController, 'status'])
router.get('/settings', [BenchmarkController, 'settings'])
router.post('/settings', [BenchmarkController, 'updateSettings'])
})
.prefix('/api/benchmark')