Spaces:
Running
Running
| ; | |
| /** | |
| * Management API server for the providers comparison app. | |
| * Runs on port 3001 (Vite dev server runs on 5173). | |
| * | |
| * Routes: | |
| * GET /api/status β provider status (model counts, last updated) | |
| * POST /api/fetch/:provider β run one provider's fetcher | |
| * POST /api/fetch β run all providers | |
| */ | |
| const express = require('express'); | |
| const { execFile } = require('child_process'); | |
| const path = require('path'); | |
| const fs = require('fs'); | |
| const app = express(); | |
| const PORT = process.env.PORT || 3001; | |
| const DATA_FILE = path.join(__dirname, 'data', 'providers.json'); | |
| const BENCHMARKS_FILE = path.join(__dirname, 'data', 'benchmarks.json'); | |
| const SCRIPTS_DIR = path.join(__dirname, 'scripts', 'providers'); | |
| const BENCHMARKS_SCRIPT = path.join(__dirname, 'scripts', 'fetch-benchmarks.js'); | |
| // In-memory state: which providers/benchmark sources are currently being refreshed | |
| const refreshing = new Set(); | |
| // Valid benchmark source keys (must match fetch-benchmarks.js SOURCE_FIELDS keys) | |
| const BENCHMARK_SOURCES = ['llmstats', 'hf', 'livebench', 'arena', 'aider']; | |
| // Allow cross-origin requests from the Vite dev server | |
| app.use((req, res, next) => { | |
| 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') return res.sendStatus(204); | |
| next(); | |
| }); | |
| app.use(express.json()); | |
| // Serve built static files in production | |
| const distDir = path.join(__dirname, 'dist'); | |
| if (fs.existsSync(distDir)) { | |
| app.use(express.static(distDir)); | |
| } | |
| // ------------------------------------------------------------------ | |
| // GET /api/data β serve providers.json live (for HF Space / local) | |
| // GET /api/benchmarks β serve benchmarks.json live | |
| // ------------------------------------------------------------------ | |
| app.get('/api/data', (req, res) => { | |
| try { | |
| res.json(JSON.parse(fs.readFileSync(DATA_FILE, 'utf8'))); | |
| } catch { res.status(500).json({ error: 'Failed to read providers data' }); } | |
| }); | |
| app.get('/api/benchmarks', (req, res) => { | |
| try { | |
| if (!fs.existsSync(BENCHMARKS_FILE)) return res.status(404).json([]); | |
| res.json(JSON.parse(fs.readFileSync(BENCHMARKS_FILE, 'utf8'))); | |
| } catch { res.status(500).json({ error: 'Failed to read benchmarks data' }); } | |
| }); | |
| // ------------------------------------------------------------------ | |
| // GET /api/status | |
| // Returns per-provider: model count, lastUpdated, whether a fetcher script exists | |
| // ------------------------------------------------------------------ | |
| app.get('/api/status', (req, res) => { | |
| const data = JSON.parse(fs.readFileSync(DATA_FILE, 'utf8')); | |
| const status = data.providers.map((p) => { | |
| const key = p.name.toLowerCase().replace(/\s+/g, '-').replace(/[^a-z0-9-]/g, ''); | |
| // Check if a fetcher script exists for this provider | |
| const scriptPath = path.join(SCRIPTS_DIR, `${key}.js`); | |
| // Also try common name variations (e.g. "mistral-ai" β "mistral") | |
| const altKey = key.replace(/-ai$/, '').replace(/-/g, ''); | |
| const altScript = path.join(SCRIPTS_DIR, `${altKey}.js`); | |
| const hasScript = fs.existsSync(scriptPath) || fs.existsSync(altScript); | |
| const scriptKey = fs.existsSync(scriptPath) ? key : (fs.existsSync(altScript) ? altKey : null); | |
| return { | |
| name: p.name, | |
| key: scriptKey || key, | |
| modelCount: p.models?.length ?? 0, | |
| lastUpdated: p.lastUpdated ?? null, | |
| hasScript, | |
| refreshing: refreshing.has(p.name), | |
| }; | |
| }); | |
| // Include benchmark dataset info (benchmarks.json is a plain array; use file mtime for lastUpdated) | |
| let benchmarks = null; | |
| if (fs.existsSync(BENCHMARKS_FILE)) { | |
| try { | |
| const bm = JSON.parse(fs.readFileSync(BENCHMARKS_FILE, 'utf8')); | |
| const mtime = fs.statSync(BENCHMARKS_FILE).mtime.toISOString(); | |
| benchmarks = { | |
| entryCount: Array.isArray(bm) ? bm.length : (bm.entries?.length ?? 0), | |
| lastUpdated: mtime, | |
| refreshing: refreshing.has('__benchmarks__'), | |
| sources: BENCHMARK_SOURCES.map((key) => ({ | |
| key, | |
| refreshing: refreshing.has(`__benchmarks__:${key}`), | |
| })), | |
| }; | |
| } catch { /* ignore */ } | |
| } | |
| res.json({ providers: status, benchmarks }); | |
| }); | |
| // ------------------------------------------------------------------ | |
| // POST /api/fetch/:provider (provider = script key, e.g. "scaleway") | |
| // POST /api/fetch (runs all providers that have a script) | |
| // ------------------------------------------------------------------ | |
| function runFetcher(providerName, scriptKey) { | |
| return new Promise((resolve) => { | |
| if (refreshing.has(providerName)) { | |
| return resolve({ provider: providerName, success: false, error: 'Already refreshing' }); | |
| } | |
| const scriptPath = path.join(SCRIPTS_DIR, `${scriptKey}.js`); | |
| if (!fs.existsSync(scriptPath)) { | |
| return resolve({ provider: providerName, success: false, error: 'No fetcher script' }); | |
| } | |
| refreshing.add(providerName); | |
| // Run the main orchestrator for just this provider | |
| execFile( | |
| process.execPath, | |
| [path.join(__dirname, 'scripts', 'fetch-providers.js'), scriptKey], | |
| { cwd: __dirname, timeout: 60000 }, | |
| (err, stdout, stderr) => { | |
| refreshing.delete(providerName); | |
| // Stamp lastUpdated on the provider entry in providers.json | |
| try { | |
| const d = JSON.parse(fs.readFileSync(DATA_FILE, 'utf8')); | |
| const prov = d.providers.find((p) => p.name === providerName); | |
| if (prov) { | |
| prov.lastUpdated = new Date().toISOString(); | |
| fs.writeFileSync(DATA_FILE, JSON.stringify(d, null, 2)); | |
| } | |
| } catch { /* best effort */ } | |
| if (err) { | |
| resolve({ provider: providerName, success: false, error: err.message, stderr }); | |
| } else { | |
| resolve({ provider: providerName, success: true, output: stdout }); | |
| } | |
| } | |
| ); | |
| }); | |
| } | |
| // ------------------------------------------------------------------ | |
| // POST /api/fetch/benchmarks/:source (refresh one benchmark source) | |
| // POST /api/fetch/benchmarks (refresh all benchmark sources) | |
| // ------------------------------------------------------------------ | |
| app.post('/api/fetch/benchmarks/:source', async (req, res) => { | |
| const { source } = req.params; | |
| if (!BENCHMARK_SOURCES.includes(source)) { | |
| return res.json({ success: false, error: `Unknown source: ${source}` }); | |
| } | |
| const key = `__benchmarks__:${source}`; | |
| if (refreshing.has(key)) { | |
| return res.json({ success: false, error: 'Already refreshing' }); | |
| } | |
| refreshing.add(key); | |
| execFile( | |
| process.execPath, | |
| [BENCHMARKS_SCRIPT, source], | |
| { cwd: __dirname, timeout: 300000 }, | |
| (err, stdout, stderr) => { | |
| refreshing.delete(key); | |
| if (err) res.json({ success: false, error: err.message, stderr }); | |
| else res.json({ success: true }); | |
| } | |
| ); | |
| }); | |
| app.post('/api/fetch/benchmarks', async (req, res) => { | |
| if (refreshing.has('__benchmarks__')) { | |
| return res.json({ success: false, error: 'Already refreshing' }); | |
| } | |
| refreshing.add('__benchmarks__'); | |
| execFile( | |
| process.execPath, | |
| [BENCHMARKS_SCRIPT], | |
| { cwd: __dirname, timeout: 600000 }, | |
| (err, stdout, stderr) => { | |
| refreshing.delete('__benchmarks__'); | |
| if (err) res.json({ success: false, error: err.message, stderr }); | |
| else res.json({ success: true }); | |
| } | |
| ); | |
| }); | |
| app.post('/api/fetch/:provider', async (req, res) => { | |
| const scriptKey = req.params.provider; | |
| // Find the provider name by script key | |
| const data = JSON.parse(fs.readFileSync(DATA_FILE, 'utf8')); | |
| // Try to match by lowercased name or script key | |
| const match = data.providers.find((p) => { | |
| const k = p.name.toLowerCase().replace(/\s+/g, '-').replace(/[^a-z0-9-]/g, ''); | |
| const ak = k.replace(/-ai$/, '').replace(/-/g, ''); | |
| return k === scriptKey || ak === scriptKey; | |
| }); | |
| const providerName = match?.name ?? scriptKey; | |
| const result = await runFetcher(providerName, scriptKey); | |
| res.json(result); | |
| }); | |
| app.post('/api/fetch', async (req, res) => { | |
| const data = JSON.parse(fs.readFileSync(DATA_FILE, 'utf8')); | |
| const scriptsAvailable = fs | |
| .readdirSync(SCRIPTS_DIR) | |
| .filter((f) => f.endsWith('.js')) | |
| .map((f) => f.replace('.js', '')); | |
| const tasks = data.providers | |
| .filter((p) => { | |
| const key = p.name.toLowerCase().replace(/\s+/g, '-').replace(/[^a-z0-9-]/g, ''); | |
| const altKey = key.replace(/-ai$/, '').replace(/-/g, ''); | |
| return scriptsAvailable.includes(key) || scriptsAvailable.includes(altKey); | |
| }) | |
| .map((p) => { | |
| const key = p.name.toLowerCase().replace(/\s+/g, '-').replace(/[^a-z0-9-]/g, ''); | |
| const altKey = key.replace(/-ai$/, '').replace(/-/g, ''); | |
| const scriptKey = scriptsAvailable.includes(key) ? key : altKey; | |
| return runFetcher(p.name, scriptKey); | |
| }); | |
| const results = await Promise.all(tasks); | |
| res.json({ results }); | |
| }); | |
| // SPA catch-all: serve index.html for any non-API route | |
| if (fs.existsSync(distDir)) { | |
| app.get('{/*any}', (req, res) => { | |
| res.sendFile(path.join(distDir, 'index.html')); | |
| }); | |
| } | |
| app.listen(PORT, () => { | |
| console.log(`Management API server running at http://localhost:${PORT}`); | |
| console.log(` GET /api/data`); | |
| console.log(` GET /api/benchmarks`); | |
| console.log(` GET /api/status`); | |
| console.log(` POST /api/fetch (all providers)`); | |
| console.log(` POST /api/fetch/:key (single provider)`); | |
| }); | |