Spaces:
Sleeping
Sleeping
| const express = require('express'); | |
| const { randomUUID } = require('node:crypto'); | |
| const fs = require('node:fs/promises'); | |
| const path = require('node:path'); | |
| const app = express(); | |
| const PORT = Number(process.env.PORT || 4000); | |
| const BUILD_DIR = path.join(__dirname, '..', 'build'); | |
| const LOCAL_DATA_DIR = path.join(__dirname, '..', 'data'); | |
| const LOCAL_DATA_FILE = process.env.RUNS_FILE || path.join(LOCAL_DATA_DIR, 'runs.json'); | |
| const HUB_DATASET_REPO = process.env.HF_DATASET_REPO || ''; | |
| const HUB_TOKEN = process.env.HF_TOKEN || ''; | |
| const HUB_DATASET_FILE = process.env.HF_DATASET_FILE || 'runs.json'; | |
| app.use(express.json({ limit: '1mb' })); | |
| function sortRunsByDateDesc(runs) { | |
| return [...runs].sort((a, b) => { | |
| const byDate = (b?.date || '').localeCompare(a?.date || ''); | |
| if (byDate !== 0) return byDate; | |
| return (b?.id || '').localeCompare(a?.id || ''); | |
| }); | |
| } | |
| function usingHubDataset() { | |
| return Boolean(HUB_DATASET_REPO && HUB_TOKEN); | |
| } | |
| async function ensureLocalDataFile() { | |
| await fs.mkdir(path.dirname(LOCAL_DATA_FILE), { recursive: true }); | |
| try { | |
| await fs.access(LOCAL_DATA_FILE); | |
| } catch { | |
| await fs.writeFile(LOCAL_DATA_FILE, '[]\n', 'utf8'); | |
| } | |
| } | |
| async function importHub() { | |
| return import('@huggingface/hub'); | |
| } | |
| async function ensureDatasetRepo() { | |
| const hub = await importHub(); | |
| try { | |
| await hub.createRepo({ | |
| repo: { type: 'dataset', name: HUB_DATASET_REPO }, | |
| accessToken: HUB_TOKEN, | |
| private: true, | |
| }); | |
| } catch (error) { | |
| const status = error && typeof error === 'object' && 'statusCode' in error ? error.statusCode : null; | |
| if (status !== 409 && status !== 403) { | |
| throw error; | |
| } | |
| } | |
| } | |
| async function readLocalRuns() { | |
| await ensureLocalDataFile(); | |
| const raw = await fs.readFile(LOCAL_DATA_FILE, 'utf8'); | |
| const parsed = JSON.parse(raw); | |
| return Array.isArray(parsed) ? parsed : []; | |
| } | |
| async function writeLocalRuns(runs) { | |
| await ensureLocalDataFile(); | |
| await fs.writeFile(LOCAL_DATA_FILE, `${JSON.stringify(runs, null, 2)}\n`, 'utf8'); | |
| } | |
| async function readDatasetRuns() { | |
| await ensureDatasetRepo(); | |
| const hub = await importHub(); | |
| try { | |
| const response = await hub.downloadFile({ | |
| repo: { type: 'dataset', name: HUB_DATASET_REPO }, | |
| path: HUB_DATASET_FILE, | |
| accessToken: HUB_TOKEN, | |
| }); | |
| if (!response) return []; | |
| const raw = await response.text(); | |
| const parsed = JSON.parse(raw); | |
| return Array.isArray(parsed) ? parsed : []; | |
| } catch (error) { | |
| if (error && typeof error === 'object' && 'statusCode' in error && error.statusCode === 404) { | |
| return []; | |
| } | |
| throw error; | |
| } | |
| } | |
| async function writeDatasetRuns(runs) { | |
| await ensureDatasetRepo(); | |
| const hub = await importHub(); | |
| const payload = `${JSON.stringify(runs, null, 2)}\n`; | |
| await hub.uploadFiles({ | |
| repo: { type: 'dataset', name: HUB_DATASET_REPO }, | |
| accessToken: HUB_TOKEN, | |
| files: [ | |
| { | |
| path: HUB_DATASET_FILE, | |
| content: new Blob([payload], { type: 'application/json' }), | |
| }, | |
| ], | |
| commitTitle: 'Update running dashboard runs', | |
| }); | |
| } | |
| async function readRuns() { | |
| if (usingHubDataset()) return readDatasetRuns(); | |
| return readLocalRuns(); | |
| } | |
| async function writeRuns(runs) { | |
| if (usingHubDataset()) return writeDatasetRuns(runs); | |
| return writeLocalRuns(runs); | |
| } | |
| app.get('/api/health', (_req, res) => { | |
| res.json({ | |
| ok: true, | |
| storage: usingHubDataset() ? 'huggingface-dataset' : 'local-file', | |
| datasetRepo: HUB_DATASET_REPO || null, | |
| }); | |
| }); | |
| app.get('/api/runs', async (_req, res, next) => { | |
| try { | |
| const runs = await readRuns(); | |
| res.json(sortRunsByDateDesc(runs)); | |
| } catch (error) { | |
| next(error); | |
| } | |
| }); | |
| app.post('/api/runs', async (req, res, next) => { | |
| try { | |
| const incoming = req.body; | |
| if (!incoming || typeof incoming !== 'object') { | |
| return res.status(400).json({ error: 'Invalid run payload.' }); | |
| } | |
| const runs = await readRuns(); | |
| const run = { | |
| ...incoming, | |
| id: incoming.id || randomUUID(), | |
| }; | |
| const withoutSameId = runs.filter((entry) => entry.id !== run.id); | |
| const updated = sortRunsByDateDesc([run, ...withoutSameId]); | |
| await writeRuns(updated); | |
| return res.status(201).json(run); | |
| } catch (error) { | |
| next(error); | |
| } | |
| }); | |
| app.put('/api/runs/:id', async (req, res, next) => { | |
| try { | |
| const { id } = req.params; | |
| const changes = req.body; | |
| if (!changes || typeof changes !== 'object') { | |
| return res.status(400).json({ error: 'Invalid update payload.' }); | |
| } | |
| const runs = await readRuns(); | |
| const index = runs.findIndex((entry) => entry.id === id); | |
| if (index === -1) { | |
| return res.status(404).json({ error: 'Run not found.' }); | |
| } | |
| const updatedRun = { ...runs[index], ...changes, id }; | |
| const nextRuns = [...runs]; | |
| nextRuns[index] = updatedRun; | |
| await writeRuns(sortRunsByDateDesc(nextRuns)); | |
| return res.json(updatedRun); | |
| } catch (error) { | |
| next(error); | |
| } | |
| }); | |
| app.delete('/api/runs/:id', async (req, res, next) => { | |
| try { | |
| const { id } = req.params; | |
| const runs = await readRuns(); | |
| const nextRuns = runs.filter((entry) => entry.id !== id); | |
| if (nextRuns.length === runs.length) { | |
| return res.status(404).json({ error: 'Run not found.' }); | |
| } | |
| await writeRuns(nextRuns); | |
| return res.status(204).send(); | |
| } catch (error) { | |
| next(error); | |
| } | |
| }); | |
| if (process.env.NODE_ENV === 'production') { | |
| app.use(express.static(BUILD_DIR)); | |
| app.get('{*path}', (_req, res) => { | |
| res.sendFile(path.join(BUILD_DIR, 'index.html')); | |
| }); | |
| } | |
| app.use((error, _req, res, _next) => { | |
| // eslint-disable-next-line no-console | |
| console.error(error); | |
| res.status(500).json({ error: 'Internal server error' }); | |
| }); | |
| app.listen(PORT, () => { | |
| // eslint-disable-next-line no-console | |
| console.log(`Run API listening on http://localhost:${PORT}`); | |
| // eslint-disable-next-line no-console | |
| console.log(`Storage backend: ${usingHubDataset() ? `dataset:${HUB_DATASET_REPO}/${HUB_DATASET_FILE}` : `local:${LOCAL_DATA_FILE}`}`); | |
| }); | |