File size: 4,069 Bytes
2889205
e4e9ad6
2889205
e4e9ad6
b0e1d6e
e4e9ad6
2889205
e4e9ad6
 
7f84064
2889205
7f84064
2889205
177a238
2889205
dd4dc21
 
7f84064
e4e9ad6
 
 
 
dd4dc21
 
 
 
 
 
 
e4e9ad6
 
dd4dc21
 
 
 
 
 
 
 
 
 
 
 
e4e9ad6
dd4dc21
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65e323a
dd4dc21
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65e323a
dd4dc21
 
 
 
65e323a
3e0d39c
177a238
dd4dc21
 
 
3e0d39c
 
e4e9ad6
 
 
 
177a238
65e323a
d5b575b
 
65e323a
315c31e
65e323a
2889205
 
e4e9ad6
dd4dc21
 
3e0d39c
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
112
113
114
115
116
117
const express = require('express');
const http = require('http');
const proxy = require('express-http-proxy');
const socketIo = require('socket.io');
const moment = require('moment-timezone');

const app = express();
const server = http.createServer(app);
const io = socketIo(server);

const targetUrl = 'https://api.openai.com';
const openaiKey = process.env.OPENAI_KEY;
const port = 7860;
const baseUrl = getExternalUrl(process.env.SPACE_ID);

let requestDetails = [];
let apiKeyDetails = {}; // Track API key usage and first use timestamp

io.on('connection', (socket) => {
    console.log('A user connected to the websocket for live logs.');
});

function logAndEmit(message, includeTotal = false) {
    if (includeTotal) {
        const totalRequests = getTotalRequests();
        message += ` Total requests so far: ${totalRequests}`;
    }
    console.log(message);
    io.emit('log', message);
}

function getTotalRequests() {
    return Object.values(apiKeyDetails).reduce((acc, details) => acc + details.count, 0);
}

function authenticateApiKey(req, res, next) {
    const receivedApiKey = req.headers['authorization'];
    if (!receivedApiKey) {
        return res.status(401).send('Unauthorized: No API key provided');
    }

    const validApiKeys = (process.env.SECRET_API_KEYS || '').split(',');
    const apiKeyMatch = validApiKeys.find(key => `Bearer ${key.trim()}` === receivedApiKey);
    
    if (!apiKeyMatch) {
        return res.status(401).send('Unauthorized: API key is invalid');
    }

    const displayKey = apiKeyMatch.trim().substring(0, 7); // Only use the first four characters for display

    if (!apiKeyDetails[apiKeyMatch]) {
        apiKeyDetails[apiKeyMatch] = {
            count: 0,
            firstUse: moment()  // Set the first use to now if it's not already set
        };
    }

    // Check if more than a week has passed since the first use
    if (moment().diff(apiKeyDetails[apiKeyMatch].firstUse, 'weeks') >= 1) {
        return res.status(429).send(`API Key ${displayKey}... is blocked after one week of use.`);
    }

    // Increment the request count
    apiKeyDetails[apiKeyMatch].count++;

    const logMessage = `API Key ${displayKey}... used ${apiKeyDetails[apiKeyMatch].count} times so far.`;
    logAndEmit(logMessage, true);
    
    req.apiKey = apiKeyMatch; // Store the API key for the request
    next();
}

app.use('/api', authenticateApiKey, (req, res, next) => {
    const timestamp = moment().tz("Asia/Tbilisi").format("DD-MMM-YYYY HH:mm");
    const displayKey = req.apiKey.substring(0, 4);
    const requestData = {
        requestNumber: apiKeyDetails[req.apiKey].count,
        apiKey: displayKey,
        timestamp: timestamp,
        text: req.method + ' ' + req.url
    };
    requestDetails.push(requestData);

    const detailedLog = `Request ${requestData.requestNumber} on ${requestData.timestamp} from API Key ${displayKey}... with method "${req.method}" and text "${requestData.text}"`;
    logAndEmit(detailedLog, true);

    next();
}, proxy(targetUrl, {
    proxyReqOptDecorator: function(proxyReqOpts, srcReq) {
        proxyReqOpts.headers['Authorization'] = 'Bearer ' + openaiKey;
        return proxyReqOpts;
    }
}));

app.get("/", (req, res) => {
    let requestsInfo = requestDetails.map(detail =>
        `Request ${detail.requestNumber} on ${detail.timestamp} from API Key ${detail.apiKey}... with text "${detail.text}"`).join('<br>');
    res.send(`This is your OpenAI Reverse Proxy URL: ${baseUrl}.<br><br>Requests Overview:<br>${requestsInfo}`);
});

app.get('/logs', (req, res) => {
    res.sendFile(__dirname + '/index.html');
});

function getExternalUrl(spaceId) {
  try {
    const [username, spacename] = spaceId.split("/");
    return `https://${username}-${spacename.replace(/_/g, "-")}.hf.space/api/v1`;
  } catch (e) {
    return "Error generating external URL";
  }
}

server.listen(port, () => {
    const message = `Reverse proxy server and WebSocket running on port ${port}`;
    logAndEmit(message, true); // true to include total requests in the log
});