-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathserver.ts
More file actions
111 lines (92 loc) · 3.29 KB
/
server.ts
File metadata and controls
111 lines (92 loc) · 3.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
import express from 'express';
import cors from 'cors';
import multer from 'multer';
import Replicate from 'replicate';
import dotenv from 'dotenv';
import path from 'path';
import { fileURLToPath } from 'url';
dotenv.config();
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const app = express();
app.use(cors());
// Add headers for SharedArrayBuffer support in browser (required by demucs-web/onnxruntime-web)
app.use((req, res, next) => {
res.setHeader('Cross-Origin-Opener-Policy', 'same-origin');
res.setHeader('Cross-Origin-Embedder-Policy', 'require-corp');
next();
});
app.use(express.json({ limit: '50mb' }));
app.use(express.urlencoded({ extended: true, limit: '50mb' }));
const storage = multer.memoryStorage();
const upload = multer({
storage,
limits: {
fileSize: 20 * 1024 * 1024 // 20MB limit
}
});
const replicate = new Replicate({
auth: process.env.REPLICATE_API_TOKEN || "MISSING",
});
app.post('/api/separate', upload.single('audio'), async (req, res): Promise<void> => {
try {
if (!req.file) {
res.status(400).json({ error: 'No audio file uploaded' });
return;
}
if (!process.env.REPLICATE_API_TOKEN) {
res.status(500).json({ error: 'REPLICATE_API_TOKEN is not configured. Please add it to your secrets.' });
return;
}
console.log(`Processing file: ${req.file.originalname}, size: ${req.file.size} bytes, type: ${req.file.mimetype}`);
const base64Audio = req.file.buffer.toString('base64');
let mimeType = req.file.mimetype;
// Normalization logic
if (!mimeType || mimeType === 'application/octet-stream') {
const ext = path.extname(req.file.originalname).toLowerCase();
if (ext === '.mp3') mimeType = 'audio/mpeg';
else if (ext === '.wav') mimeType = 'audio/wav';
else mimeType = 'audio/mpeg';
}
const audioURI = `data:${mimeType};base64,${base64Audio}`;
console.log('Sending to Replicate...');
const output = await replicate.run(
"cjwbw/demucs:25a173108cff36ef9f80f854c162d01df9e6528be175794b81158fa03836d953",
{
input: {
audio: audioURI
}
}
);
console.log('Replicate output:', output);
res.json({ stems: output });
} catch (error: any) {
console.error("Separation Error:", error);
res.status(500).json({ error: error.message || 'Failed to process audio' });
}
});
// Setup Vite in Dev or Static in Prod
async function startServer() {
const isProd = process.env.NODE_ENV === 'production';
if (!isProd) {
console.log("Starting in DEV mode with Vite");
const { createServer: createViteServer } = await import('vite');
const vite = await createViteServer({
server: { middlewareMode: true },
appType: 'spa',
});
app.use(vite.middlewares);
} else {
console.log("Starting in PROD mode");
app.use(express.static(path.resolve(__dirname, 'dist')));
// For SharedArrayBuffer, the static files also get the headers from the earlier middleware
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, 'dist/index.html'));
});
}
const PORT = process.env.PORT ? parseInt(process.env.PORT, 10) : 3000;
app.listen(PORT, '0.0.0.0', () => {
console.log(`Server is running on port ${PORT}`);
});
}
startServer();