File size: 4,895 Bytes
5cd6458
 
0e39520
5cd6458
 
3e7e8b4
fd1c59b
f406747
5cd6458
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0e39520
 
 
 
 
 
 
fd1c59b
 
5cd6458
 
0e39520
5cd6458
 
 
 
bff1373
5cd6458
 
 
 
 
 
 
bff1373
 
 
 
 
 
 
 
3e7e8b4
 
05b4e0f
 
 
f406747
f47c877
bff1373
05b4e0f
 
 
 
bff1373
05b4e0f
bff1373
 
 
1e956de
0e39520
 
 
 
 
 
3e7e8b4
0e39520
93326ac
f406747
3e7e8b4
 
 
830813f
0e39520
 
 
 
 
 
 
1e956de
bff1373
 
05b4e0f
 
 
 
 
 
 
 
 
 
 
 
bff1373
 
 
d899182
 
 
 
 
 
 
bff1373
5cd6458
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cbf3e84
5cd6458
 
 
 
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
const { Router } = require('express');
const bodyParser = require('body-parser');
const config = require('./config.json');
const slack = require('./slack');
const yup = require('yup');
const { splitJsonArray, dataToResponse, buildPrompt, wait, stats } = require("./utils");
const { Queue } = require('async-await-queue');
const { encode, decode } = require('html-entities');

const messageArraySchema = yup.array().of(
    yup.object().shape({
        role: yup.string().required(),
        content: yup.string().required(),
    })
);

const jsonParser = bodyParser.json();

const spoofModelName = 'gpt-4';

const openaiRouter = Router();
openaiRouter.get("/models", (req, res) => {
    res.json([
        {
            id: spoofModelName,
            object: spoofModelName,
            owned_by: 'user',
            permission: [],
        }
    ]);
});

const parallelQueries = config.slacks.length;
const slacks = config.slacks.map((slackConfig) => {
    return {
        ...slackConfig,
        locked: false,
    };
});
const myq = new Queue(parallelQueries, 100);

openaiRouter.post("/chat/completions", jsonParser, async (req, res) => {
    try {
        if (config.apiKey && req.token !== config.apiKey) {
            res.status(401).json({ error: "Unauthorized" });
            return;
        }

        const { messages, stream } = req.body;
        if (!messages || !(await messageArraySchema.isValid(messages))) {
            res.status(400).json({ error: "Bad request" });
            return;
        }

        const messagesSplit = splitJsonArray(messages, 12000);

        if (stream) {
            res.writeHead(200, {
                'Content-Type': 'text/event-stream',
                'Cache-Control': 'no-cache',
                Connection: 'keep-alive',
            });
        }

        const inputPrompt = buildPrompt(messages);
        const promptTokens = Math.ceil(inputPrompt.length / 4);
        let completionTokens = 0;

        let lastContent = '';
        const onData = (newContentEncoded) => {
            const newContent = decode(newContentEncoded);
            if (stream) {
                const data = newContent.slice(lastContent.length);
                lastContent = newContent;
                completionTokens = Math.ceil(newContent.length / 4);
                const chunk = dataToResponse(data, promptTokens, completionTokens, stream);
                res.write('event: data\n');
                res.write(`data: ${JSON.stringify(chunk)}\n\n`);
            }
        };

        const result = await myq.run(async () => {
            let slackConfig = slacks.find((slack) => !slack.locked);
            if (!slackConfig) {
                throw new Error('Queue full');
            }
            slackConfig.locked = true;
            try {
                const start = new Date();
                await slack.sendChatReset(slackConfig);
                await wait(500);
                const response = decode(await slack.waitForWebSocketResponse(slackConfig, messagesSplit, onData));
                const end = new Date();
                const time = end - start;
                stats.prompts.push({ time, inputLength: inputPrompt.length, outputLength: response.length });
                //slack.deleteAllMessages(slackConfig);
                slackConfig.locked = false;
                return response;
            } catch (error) {
                slackConfig.locked = false;
                console.error(error);
                throw new Error('Slack error');
            }
        });

        if (stream) {
            res.write('event: data\n');
            res.write(
                `data: ${JSON.stringify(
                    dataToResponse(
                        undefined,
                        promptTokens,
                        completionTokens,
                        stream,
                        'stop'
                    )
                )}\n\n`
            );
            res.write('event: data\n');
            res.write('data: [DONE]\n\n');
        } else {
            res.json(dataToResponse(
                result,
                promptTokens,
                completionTokens,
                stream,
                'stop'
            ));
        }
    } catch (error) {
        console.error(error);
        res.status(500).json({ error: "Internal server error" });
    }
});
// If a browser tries to visit a route that doesn't exist, redirect to the info
// page to help them find the right URL.
openaiRouter.get("*", (req, res, next) => {
    const isBrowser = req.headers["user-agent"]?.includes("Mozilla");
    if (isBrowser) {
        res.redirect("/");
    } else {
        next();
    }
});
openaiRouter.use((req, res) => {
    //logger.warn(`Blocked openai proxy request: ${req.method} ${req.path}`);
    res.status(404).json({ error: "Not found" });
});

module.exports = openaiRouter;