Update server.js
Browse files
server.js
CHANGED
|
@@ -3,69 +3,68 @@
|
|
| 3 |
import express from 'express';
|
| 4 |
import cors from 'cors';
|
| 5 |
import multer from 'multer';
|
| 6 |
-
import { commit } from '@huggingface/hub';
|
| 7 |
import path from 'path';
|
| 8 |
import { fileURLToPath } from 'url';
|
| 9 |
|
| 10 |
-
// Fix __dirname for ES Modules
|
| 11 |
const __filename = fileURLToPath(import.meta.url);
|
| 12 |
const __dirname = path.dirname(__filename);
|
| 13 |
|
| 14 |
const app = express();
|
| 15 |
-
// Hugging Face Spaces requires port 7860
|
| 16 |
const port = process.env.PORT || 3001;
|
| 17 |
|
| 18 |
-
// Middleware
|
| 19 |
app.use(cors());
|
| 20 |
-
|
|
|
|
|
|
|
| 21 |
|
| 22 |
-
// Configure Multer
|
| 23 |
-
// No limit on file count here, but we limit payload size via express/nginx usually
|
| 24 |
const storage = multer.memoryStorage();
|
| 25 |
-
const upload = multer({
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
|
| 27 |
-
// SERVER CONFIGURATION
|
| 28 |
const SERVER_CONFIG = {
|
| 29 |
TOKEN: process.env.HF_TOKEN || '',
|
| 30 |
REPO: process.env.HF_REPO || 'TwanAPI/DataTwan',
|
| 31 |
TYPE: 'dataset'
|
| 32 |
};
|
| 33 |
|
| 34 |
-
// --- API ROUTES ---
|
| 35 |
-
|
| 36 |
-
// Batch Upload Endpoint
|
| 37 |
-
// Accepts multiple files in the 'files' field
|
| 38 |
app.post('/api/upload', upload.array('files'), async (req, res) => {
|
| 39 |
try {
|
| 40 |
const files = req.files;
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
|
|
|
|
|
|
|
|
|
| 44 |
|
| 45 |
if (!files || files.length === 0) {
|
| 46 |
return res.status(400).json({ error: 'No files provided' });
|
| 47 |
}
|
| 48 |
|
| 49 |
if (files.length !== paths.length) {
|
| 50 |
-
return res.status(400).json({ error:
|
| 51 |
}
|
| 52 |
|
| 53 |
-
// Security Check
|
| 54 |
if (!SERVER_CONFIG.TOKEN) {
|
| 55 |
-
console.error('[SERVER] Upload Failed: HF_TOKEN missing');
|
| 56 |
return res.status(500).json({ error: 'Server misconfiguration: HF_TOKEN secret is missing.' });
|
| 57 |
}
|
| 58 |
|
| 59 |
console.log(`[SERVER] Processing batch of ${files.length} files...`);
|
| 60 |
|
| 61 |
-
// Prepare operations for Hugging Face 'commit'
|
| 62 |
const operations = files.map((file, index) => ({
|
| 63 |
operation: 'addOrUpdate',
|
| 64 |
path: paths[index],
|
| 65 |
content: new Blob([file.buffer])
|
| 66 |
}));
|
| 67 |
|
| 68 |
-
//
|
| 69 |
const response = await commit({
|
| 70 |
credentials: {
|
| 71 |
accessToken: SERVER_CONFIG.TOKEN,
|
|
@@ -75,16 +74,14 @@ app.post('/api/upload', upload.array('files'), async (req, res) => {
|
|
| 75 |
name: SERVER_CONFIG.REPO
|
| 76 |
},
|
| 77 |
operations: operations,
|
| 78 |
-
title: `
|
| 79 |
});
|
| 80 |
|
| 81 |
-
const commitHash = response.oid;
|
| 82 |
const urlPrefix = "https://huggingface.co/datasets";
|
| 83 |
-
|
| 84 |
-
// Generate public URLs for response
|
| 85 |
const urls = paths.map(p => `${urlPrefix}/${SERVER_CONFIG.REPO}/blob/${commitHash}/${p}`);
|
| 86 |
|
| 87 |
-
console.log(`[SERVER] Batch
|
| 88 |
|
| 89 |
res.json({
|
| 90 |
success: true,
|
|
@@ -93,7 +90,7 @@ app.post('/api/upload', upload.array('files'), async (req, res) => {
|
|
| 93 |
});
|
| 94 |
|
| 95 |
} catch (error) {
|
| 96 |
-
console.error('[SERVER]
|
| 97 |
res.status(500).json({
|
| 98 |
success: false,
|
| 99 |
error: error.message || 'Internal Server Error'
|
|
@@ -101,18 +98,12 @@ app.post('/api/upload', upload.array('files'), async (req, res) => {
|
|
| 101 |
}
|
| 102 |
});
|
| 103 |
|
| 104 |
-
// --- SERVE FRONTEND (Production) ---
|
| 105 |
-
|
| 106 |
app.use(express.static(path.join(__dirname, 'dist')));
|
| 107 |
|
| 108 |
app.get('*', (req, res) => {
|
| 109 |
res.sendFile(path.join(__dirname, 'dist', 'index.html'));
|
| 110 |
});
|
| 111 |
|
| 112 |
-
// Start Server
|
| 113 |
app.listen(port, () => {
|
| 114 |
-
console.log(
|
| 115 |
-
console.log(`✅ Server running on port ${port}`);
|
| 116 |
-
console.log(` Target Repo: ${SERVER_CONFIG.REPO}`);
|
| 117 |
-
console.log(`--------------------------------------------------`);
|
| 118 |
});
|
|
|
|
| 3 |
import express from 'express';
|
| 4 |
import cors from 'cors';
|
| 5 |
import multer from 'multer';
|
| 6 |
+
import { commit } from '@huggingface/hub';
|
| 7 |
import path from 'path';
|
| 8 |
import { fileURLToPath } from 'url';
|
| 9 |
|
|
|
|
| 10 |
const __filename = fileURLToPath(import.meta.url);
|
| 11 |
const __dirname = path.dirname(__filename);
|
| 12 |
|
| 13 |
const app = express();
|
|
|
|
| 14 |
const port = process.env.PORT || 3001;
|
| 15 |
|
|
|
|
| 16 |
app.use(cors());
|
| 17 |
+
// Increase body limit for large batch JSON/Form data
|
| 18 |
+
app.use(express.json({ limit: '500mb' }));
|
| 19 |
+
app.use(express.urlencoded({ limit: '500mb', extended: true }));
|
| 20 |
|
| 21 |
+
// Configure Multer with higher limits
|
|
|
|
| 22 |
const storage = multer.memoryStorage();
|
| 23 |
+
const upload = multer({
|
| 24 |
+
storage: storage,
|
| 25 |
+
limits: {
|
| 26 |
+
fileSize: 500 * 1024 * 1024, // 500MB per file max
|
| 27 |
+
fieldSize: 500 * 1024 * 1024, // 500MB per field
|
| 28 |
+
}
|
| 29 |
+
});
|
| 30 |
|
|
|
|
| 31 |
const SERVER_CONFIG = {
|
| 32 |
TOKEN: process.env.HF_TOKEN || '',
|
| 33 |
REPO: process.env.HF_REPO || 'TwanAPI/DataTwan',
|
| 34 |
TYPE: 'dataset'
|
| 35 |
};
|
| 36 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 37 |
app.post('/api/upload', upload.array('files'), async (req, res) => {
|
| 38 |
try {
|
| 39 |
const files = req.files;
|
| 40 |
+
let paths = req.body.paths;
|
| 41 |
+
|
| 42 |
+
// Normalize paths to array if it's a single string
|
| 43 |
+
if (!Array.isArray(paths)) {
|
| 44 |
+
paths = [paths].filter(Boolean);
|
| 45 |
+
}
|
| 46 |
|
| 47 |
if (!files || files.length === 0) {
|
| 48 |
return res.status(400).json({ error: 'No files provided' });
|
| 49 |
}
|
| 50 |
|
| 51 |
if (files.length !== paths.length) {
|
| 52 |
+
return res.status(400).json({ error: `Mismatch: ${files.length} files vs ${paths.length} paths` });
|
| 53 |
}
|
| 54 |
|
|
|
|
| 55 |
if (!SERVER_CONFIG.TOKEN) {
|
|
|
|
| 56 |
return res.status(500).json({ error: 'Server misconfiguration: HF_TOKEN secret is missing.' });
|
| 57 |
}
|
| 58 |
|
| 59 |
console.log(`[SERVER] Processing batch of ${files.length} files...`);
|
| 60 |
|
|
|
|
| 61 |
const operations = files.map((file, index) => ({
|
| 62 |
operation: 'addOrUpdate',
|
| 63 |
path: paths[index],
|
| 64 |
content: new Blob([file.buffer])
|
| 65 |
}));
|
| 66 |
|
| 67 |
+
// Using commit is atomic and faster for datasets than individual LFS uploads for small-medium files
|
| 68 |
const response = await commit({
|
| 69 |
credentials: {
|
| 70 |
accessToken: SERVER_CONFIG.TOKEN,
|
|
|
|
| 74 |
name: SERVER_CONFIG.REPO
|
| 75 |
},
|
| 76 |
operations: operations,
|
| 77 |
+
title: `Batch upload of ${files.length} files`
|
| 78 |
});
|
| 79 |
|
| 80 |
+
const commitHash = response.oid;
|
| 81 |
const urlPrefix = "https://huggingface.co/datasets";
|
|
|
|
|
|
|
| 82 |
const urls = paths.map(p => `${urlPrefix}/${SERVER_CONFIG.REPO}/blob/${commitHash}/${p}`);
|
| 83 |
|
| 84 |
+
console.log(`[SERVER] Batch Committed: ${commitHash}`);
|
| 85 |
|
| 86 |
res.json({
|
| 87 |
success: true,
|
|
|
|
| 90 |
});
|
| 91 |
|
| 92 |
} catch (error) {
|
| 93 |
+
console.error('[SERVER] Error:', error);
|
| 94 |
res.status(500).json({
|
| 95 |
success: false,
|
| 96 |
error: error.message || 'Internal Server Error'
|
|
|
|
| 98 |
}
|
| 99 |
});
|
| 100 |
|
|
|
|
|
|
|
| 101 |
app.use(express.static(path.join(__dirname, 'dist')));
|
| 102 |
|
| 103 |
app.get('*', (req, res) => {
|
| 104 |
res.sendFile(path.join(__dirname, 'dist', 'index.html'));
|
| 105 |
});
|
| 106 |
|
|
|
|
| 107 |
app.listen(port, () => {
|
| 108 |
+
console.log(`✅ Server running on port ${port} | Repo: ${SERVER_CONFIG.REPO}`);
|
|
|
|
|
|
|
|
|
|
| 109 |
});
|