File size: 4,585 Bytes
2889205
e4e9ad6
2889205
e4e9ad6
b0e1d6e
e4e9ad6
2889205
e4e9ad6
 
7f84064
2889205
7f84064
2889205
177a238
2889205
e5b45d3
 
 
 
 
 
 
 
 
 
dd4dc21
 
7f84064
e4e9ad6
 
 
 
dd4dc21
 
 
 
 
 
 
e4e9ad6
 
dd4dc21
 
 
 
 
 
 
 
 
 
 
 
e4e9ad6
dd4dc21
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65e323a
dd4dc21
 
 
 
 
 
 
 
 
 
 
e5b45d3
 
 
 
 
 
 
 
dd4dc21
e5b45d3
dd4dc21
 
 
 
 
 
 
 
e5b45d3
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
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);

const allowedModels = [
    'gpt-3.5-turbo-0125',
    'gpt-3.5-turbo',
    'gpt-3.5-turbo-1106',
    'gpt-3.5-turbo-instruct',
    'gpt-3.5-turbo-16k',
    'gpt-3.5-turbo-0613',
    'gpt-3.5-turbo-16k-0613'
];

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 urlParts = req.url.split('/');
    const modelId = urlParts.length > 1 ? urlParts[1] : null;

    // Check if the model ID is part of the allowed models.
    if (!modelId || !allowedModels.includes(modelId)) {
        return res.status(403).send("Access Denied: This model is not allowed.");
    }

    const timestamp = moment().tz("Asia/Tbilisi").format("DD-MMM-YYYY HH:mm");
    const displayKey = req.apiKey.substring(0, 10);
    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 URL line "${req.url}"`;
    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
});