Spaces:
Running
Running
Update server.js
Browse files
server.js
CHANGED
@@ -12,11 +12,6 @@ const targetUrl = 'https://api.openai.com';
|
|
12 |
const openaiKey = process.env.OPENAI_KEY;
|
13 |
const port = 7860;
|
14 |
const baseUrl = getExternalUrl(process.env.SPACE_ID);
|
15 |
-
|
16 |
-
let requestDetails = [];
|
17 |
-
let apiKeyDetails = {}; // Track API key usage and first use timestamp
|
18 |
-
|
19 |
-
// Allowed models array
|
20 |
const allowedModels = [
|
21 |
'gpt-3.5-turbo-0125',
|
22 |
'gpt-3.5-turbo',
|
@@ -27,6 +22,9 @@ const allowedModels = [
|
|
27 |
'gpt-3.5-turbo-16k-0613'
|
28 |
];
|
29 |
|
|
|
|
|
|
|
30 |
io.on('connection', (socket) => {
|
31 |
console.log('A user connected to the websocket for live logs.');
|
32 |
});
|
@@ -44,6 +42,17 @@ function getTotalRequests() {
|
|
44 |
return Object.values(apiKeyDetails).reduce((acc, details) => acc + details.count, 0);
|
45 |
}
|
46 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
47 |
function authenticateApiKey(req, res, next) {
|
48 |
const receivedApiKey = req.headers['authorization'];
|
49 |
if (!receivedApiKey) {
|
@@ -52,55 +61,64 @@ function authenticateApiKey(req, res, next) {
|
|
52 |
|
53 |
const validApiKeys = (process.env.SECRET_API_KEYS || '').split(',');
|
54 |
const apiKeyMatch = validApiKeys.find(key => `Bearer ${key.trim()}` === receivedApiKey);
|
55 |
-
|
56 |
if (!apiKeyMatch) {
|
57 |
return res.status(401).send('Unauthorized: API key is invalid');
|
58 |
}
|
59 |
|
60 |
-
const displayKey = apiKeyMatch.trim().substring(0, 7);
|
61 |
|
62 |
if (!apiKeyDetails[apiKeyMatch]) {
|
63 |
apiKeyDetails[apiKeyMatch] = {
|
64 |
count: 0,
|
65 |
-
firstUse: moment()
|
66 |
};
|
67 |
}
|
68 |
|
|
|
69 |
if (moment().diff(apiKeyDetails[apiKeyMatch].firstUse, 'weeks') >= 1) {
|
70 |
return res.status(429).send(`API Key ${displayKey}... is blocked after one week of use.`);
|
71 |
}
|
72 |
|
|
|
73 |
apiKeyDetails[apiKeyMatch].count++;
|
74 |
|
75 |
const logMessage = `API Key ${displayKey}... used ${apiKeyDetails[apiKeyMatch].count} times so far.`;
|
76 |
logAndEmit(logMessage, true);
|
77 |
-
|
78 |
-
req.apiKey = apiKeyMatch;
|
79 |
-
next();
|
80 |
-
}
|
81 |
-
|
82 |
-
function validateModel(req, res, next) {
|
83 |
-
const pathComponents = req.path.split('/');
|
84 |
-
const modelUsed = pathComponents.filter(component => allowedModels.includes(component))[0];
|
85 |
-
|
86 |
-
if (!modelUsed) {
|
87 |
-
return res.status(403).send("Access to this model is not allowed.");
|
88 |
-
}
|
89 |
-
|
90 |
next();
|
91 |
}
|
92 |
|
93 |
app.use('/api', authenticateApiKey, validateModel, proxy(targetUrl, {
|
94 |
-
proxyReqPathResolver: function(req) {
|
95 |
-
return require('url').parse(req.url).path;
|
96 |
-
},
|
97 |
proxyReqOptDecorator: function(proxyReqOpts, srcReq) {
|
98 |
proxyReqOpts.headers['Authorization'] = 'Bearer ' + openaiKey;
|
99 |
return proxyReqOpts;
|
|
|
|
|
|
|
|
|
100 |
}
|
101 |
}));
|
102 |
|
103 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
104 |
|
105 |
server.listen(port, () => {
|
106 |
const message = `Reverse proxy server and WebSocket running on port ${port}`;
|
|
|
12 |
const openaiKey = process.env.OPENAI_KEY;
|
13 |
const port = 7860;
|
14 |
const baseUrl = getExternalUrl(process.env.SPACE_ID);
|
|
|
|
|
|
|
|
|
|
|
15 |
const allowedModels = [
|
16 |
'gpt-3.5-turbo-0125',
|
17 |
'gpt-3.5-turbo',
|
|
|
22 |
'gpt-3.5-turbo-16k-0613'
|
23 |
];
|
24 |
|
25 |
+
let requestDetails = [];
|
26 |
+
let apiKeyDetails = {}; // Track API key usage and first use timestamp
|
27 |
+
|
28 |
io.on('connection', (socket) => {
|
29 |
console.log('A user connected to the websocket for live logs.');
|
30 |
});
|
|
|
42 |
return Object.values(apiKeyDetails).reduce((acc, details) => acc + details.count, 0);
|
43 |
}
|
44 |
|
45 |
+
|
46 |
+
function validateModel(req, res, next) {
|
47 |
+
const modelRequested = req.query.model; // Assuming the model name is passed as a query parameter
|
48 |
+
|
49 |
+
if (!allowedModels.includes(modelRequested)) {
|
50 |
+
return res.status(403).send(`Access denied for model: ${modelRequested}. This model is not allowed.`);
|
51 |
+
}
|
52 |
+
|
53 |
+
next();
|
54 |
+
}
|
55 |
+
|
56 |
function authenticateApiKey(req, res, next) {
|
57 |
const receivedApiKey = req.headers['authorization'];
|
58 |
if (!receivedApiKey) {
|
|
|
61 |
|
62 |
const validApiKeys = (process.env.SECRET_API_KEYS || '').split(',');
|
63 |
const apiKeyMatch = validApiKeys.find(key => `Bearer ${key.trim()}` === receivedApiKey);
|
64 |
+
|
65 |
if (!apiKeyMatch) {
|
66 |
return res.status(401).send('Unauthorized: API key is invalid');
|
67 |
}
|
68 |
|
69 |
+
const displayKey = apiKeyMatch.trim().substring(0, 7); // Only use the first four characters for display
|
70 |
|
71 |
if (!apiKeyDetails[apiKeyMatch]) {
|
72 |
apiKeyDetails[apiKeyMatch] = {
|
73 |
count: 0,
|
74 |
+
firstUse: moment() // Set the first use to now if it's not already set
|
75 |
};
|
76 |
}
|
77 |
|
78 |
+
// Check if more than a week has passed since the first use
|
79 |
if (moment().diff(apiKeyDetails[apiKeyMatch].firstUse, 'weeks') >= 1) {
|
80 |
return res.status(429).send(`API Key ${displayKey}... is blocked after one week of use.`);
|
81 |
}
|
82 |
|
83 |
+
// Increment the request count
|
84 |
apiKeyDetails[apiKeyMatch].count++;
|
85 |
|
86 |
const logMessage = `API Key ${displayKey}... used ${apiKeyDetails[apiKeyMatch].count} times so far.`;
|
87 |
logAndEmit(logMessage, true);
|
88 |
+
|
89 |
+
req.apiKey = apiKeyMatch; // Store the API key for the request
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
90 |
next();
|
91 |
}
|
92 |
|
93 |
app.use('/api', authenticateApiKey, validateModel, proxy(targetUrl, {
|
|
|
|
|
|
|
94 |
proxyReqOptDecorator: function(proxyReqOpts, srcReq) {
|
95 |
proxyReqOpts.headers['Authorization'] = 'Bearer ' + openaiKey;
|
96 |
return proxyReqOpts;
|
97 |
+
},
|
98 |
+
proxyReqPathResolver: function(req) {
|
99 |
+
const newPath = req.originalUrl.replace('/api', ''); // Adjust the path as necessary
|
100 |
+
return newPath;
|
101 |
}
|
102 |
}));
|
103 |
|
104 |
+
app.get("/", (req, res) => {
|
105 |
+
let requestsInfo = requestDetails.map(detail =>
|
106 |
+
`Request ${detail.requestNumber} on ${detail.timestamp} from API Key ${detail.apiKey}... with text "${detail.text}"`).join('<br>');
|
107 |
+
res.send(`This is your OpenAI Reverse Proxy URL: ${baseUrl}.<br><br>Requests Overview:<br>${requestsInfo}`);
|
108 |
+
});
|
109 |
+
|
110 |
+
app.get('/logs', (req, res) => {
|
111 |
+
res.sendFile(__dirname + '/index.html');
|
112 |
+
});
|
113 |
+
|
114 |
+
function getExternalUrl(spaceId) {
|
115 |
+
try {
|
116 |
+
const [username, spacename] = spaceId.split("/");
|
117 |
+
return `https://${username}-${spacename.replace(/_/g, "-")}.hf.space/api/v1`;
|
118 |
+
} catch (e) {
|
119 |
+
return "Error generating external URL";
|
120 |
+
}
|
121 |
+
}
|
122 |
|
123 |
server.listen(port, () => {
|
124 |
const message = `Reverse proxy server and WebSocket running on port ${port}`;
|