-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.js
More file actions
106 lines (90 loc) · 2.69 KB
/
index.js
File metadata and controls
106 lines (90 loc) · 2.69 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
import express from 'express';
import dotenv from 'dotenv';
import axios from 'axios';
import rateLimit from 'express-rate-limit';
dotenv.config();
const {
OPENWEBUI_URL,
OPENWEBUI_USER,
OPENWEBUI_PASS,
PORT
} = process.env;
let token = null;
let tokenExpiry = 0;
const app = express();
app.use(express.json());
// Basic rate limiting: 60 requests per minute per IP
const limiter = rateLimit({
windowMs: 60 * 1000,
max: 60
});
app.use('/api/chat', limiter);
// Refresh JWT from OpenWebUI
async function refreshToken() {
const now = Date.now();
if (token && now < tokenExpiry - 30000) return token; // 30s buffer
try {
// const res = await axios.post(`${OPENWEBUI_URL}/api/auth/login`, {
// username: OPENWEBUI_USER,
// password: OPENWEBUI_PASS
// });
const res = await axios.post(`${OPENWEBUI_URL}/api/sessions`, {
username: OPENWEBUI_USER,
password: OPENWEBUI_PASS
}, {
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
});
token = res.data.access_token;
tokenExpiry = now + 60 * 60 * 1000; // Assume 1hr token life
return token;
} catch (err) {
console.error('Auth error:', err.response?.data || err.message);
throw new Error('Authentication with OpenWebUI failed.');
}
}
// Proxy chat request (stream or non-stream)
app.post('/api/chat', async (req, res) => {
const modelInput = req.body;
if (!modelInput?.messages) return res.status(400).send({ error: 'Invalid input' });
try {
const jwt = await refreshToken();
const headers = {
Authorization: `Bearer ${jwt}`,
'Content-Type': 'application/json',
Accept: 'application/json'
};
// Handle streaming mode
if (modelInput.stream) {
const stream = await axios({
url: `${OPENWEBUI_URL}/api/chat/completions`,
method: 'POST',
headers,
data: modelInput,
responseType: 'stream'
});
res.setHeader('Content-Type', 'text/event-stream');
stream.data.pipe(res);
} else {
const response = await axios.post(
`${OPENWEBUI_URL}/api/chat/completions`,
modelInput,
{ headers }
);
res.json(response.data);
}
} catch (error) {
console.error('Chat error:', error.response?.data || error.message);
res.status(500).json({ error: 'Proxy chat failed.' });
}
});
// Serve static frontend from /static
import path from 'path';
import { fileURLToPath } from 'url';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
app.use('/static', express.static(path.join(__dirname, 'static')));
app.listen(PORT, () => {
console.log(`🔐 OpenWebUI Proxy running on http://localhost:${PORT}`);
});