File size: 4,178 Bytes
2889205
e4e9ad6
2889205
e4e9ad6
b0e1d6e
e4e9ad6
2889205
e4e9ad6
 
7f84064
2889205
7f84064
2889205
177a238
e5b45d3
 
 
 
 
 
 
 
 
 
febb60b
 
 
e4e9ad6
 
 
 
dd4dc21
 
 
 
 
 
 
e4e9ad6
 
dd4dc21
 
 
 
febb60b
 
 
 
 
 
 
 
 
 
 
dd4dc21
 
 
 
 
 
 
 
febb60b
dd4dc21
 
 
 
febb60b
dd4dc21
 
 
 
febb60b
dd4dc21
 
 
febb60b
dd4dc21
 
 
65e323a
febb60b
dd4dc21
cb7ac8f
dd4dc21
 
febb60b
 
dd4dc21
cb7ac8f
 
 
dd4dc21
 
 
febb60b
 
 
 
dd4dc21
65e323a
3e0d39c
febb60b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2889205
e4e9ad6
dd4dc21
cb7ac8f
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
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 validateModel(req, res, next) {
    const modelRequested = req.query.model; // Assuming the model name is passed as a query parameter

    if (!allowedModels.includes(modelRequested)) {
        return res.status(403).send(`Access denied for model: ${modelRequested}. This model is not allowed.`);
    }

    next();
}

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, validateModel, proxy(targetUrl, {
    proxyReqOptDecorator: function(proxyReqOpts, srcReq) {
        proxyReqOpts.headers['Authorization'] = 'Bearer ' + openaiKey;
        return proxyReqOpts;
    },
    proxyReqPathResolver: function(req) {
        const newPath = req.originalUrl.replace('/api', ''); // Adjust the path as necessary
        return newPath;
    }
}));

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
});