forked from pedrojlazevedo/twitch-chatgpt
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
273 lines (235 loc) · 8.36 KB
/
index.js
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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
import express from 'express';
import fs from 'fs';
import ws from 'ws';
import expressWs from 'express-ws';
import {job} from './keep_alive.js';
import {OpenAIOperations} from './openai_operations.js';
import {TwitchBot} from './twitch_bot.js';
// start keep alive cron job
job.start();
console.log(process.env)
// setup express app
const app = express();
const expressWsInstance = expressWs(app);
// set the view engine to ejs
app.set('view engine', 'ejs');
// load env variables
let GPT_MODE = process.env.GPT_MODE // CHAT or PROMPT
let HISTORY_LENGTH = process.env.HISTORY_LENGTH // number of messages to keep in history
let OPENAI_API_KEY = process.env.OPENAI_API_KEY // openai api key
let MODEL_NAME = process.env.MODEL_NAME // openai model name (e.g. gpt-3, gpt-3.5-turbo, gpt-4)
let TWITCH_USER = process.env.TWITCH_USER // twitch bot username
let TWITCH_AUTH = process.env.TWITCH_AUTH // tmi auth token
let COMMAND_NAME = process.env.COMMAND_NAME // comma separated list of commands to trigger bot (e.g. !gpt, !chat)
let CHANNELS = process.env.CHANNELS // comma separated list of channels to join
let SEND_USERNAME = process.env.SEND_USERNAME // send username in message to openai
let ENABLE_TTS = process.env.ENABLE_TTS // enable text to speech
let ENABLE_CHANNEL_POINTS = process.env.ENABLE_CHANNEL_POINTS; // enable channel points
if (!GPT_MODE) {
GPT_MODE = "CHAT"
}
if (!HISTORY_LENGTH) {
HISTORY_LENGTH = 5
}
if (!OPENAI_API_KEY) {
console.log("No OPENAI_API_KEY found. Please set it as environment variable.")
}
if (!MODEL_NAME) {
MODEL_NAME = "gpt-3.5-turbo"
}
if (!TWITCH_USER) {
TWITCH_USER = "oSetinhasBot"
console.log("No TWITCH_USER found. Using oSetinhasBot as default.")
}
if (!TWITCH_AUTH) {
// https://dev.twitch.tv/console
// https://twitchapps.com/tmi/
TWITCH_AUTH = "oauth:vgvx55j6qzz1lkt3cwggxki1lv53c2"
console.log("No TWITCH_AUTH found. Using oSetinhasBot auth as default.")
}
if (!COMMAND_NAME) {
COMMAND_NAME = ["!gpt"]
} else {
// split commands by comma into array
COMMAND_NAME = COMMAND_NAME.split(",")
}
COMMAND_NAME = COMMAND_NAME.map(function(x){ return x.toLowerCase() })
if (!CHANNELS) {
CHANNELS = ["oSetinhas", "jones88"]
} else {
// split channels by comma into array
CHANNELS = CHANNELS.split(",")
}
if (!SEND_USERNAME) {
SEND_USERNAME = "true"
}
if (!ENABLE_TTS) {
ENABLE_TTS = "false"
}
if (!ENABLE_CHANNEL_POINTS) {
ENABLE_CHANNEL_POINTS = "false";
}
// init global variables
const MAX_LENGTH = 399
let file_context = "You are a helpful Twitch Chatbot."
let last_user_message = ""
// setup twitch bot
const channels = CHANNELS;
const channel = channels[0];
console.log("Channels: " + channels)
const bot = new TwitchBot(TWITCH_USER, TWITCH_AUTH, channels, OPENAI_API_KEY, ENABLE_TTS);
// setup openai operations
file_context = fs.readFileSync("./file_context.txt", 'utf8');
const openai_ops = new OpenAIOperations(file_context, OPENAI_API_KEY, MODEL_NAME, HISTORY_LENGTH);
// setup twitch bot callbacks
bot.onConnected((addr, port) => {
console.log(`* Connected to ${addr}:${port}`);
// join channels
channels.forEach(channel => {
console.log(`* Joining ${channel}`);
console.log(`* Saying hello in ${channel}`)
});
});
bot.onDisconnected((reason) => {
console.log(`Disconnected: ${reason}`);
});
// connect bot
bot.connect(
() => {
console.log("Bot connected!");
},
(error) => {
console.log("Bot couldn't connect!");
console.log(error);
}
);
bot.onMessage(async (channel, user, message, self) => {
if (self) return;
if (ENABLE_CHANNEL_POINTS) {
console.log(`The message id is ${user["msg-id"]}`);
if (user["msg-id"] === "highlighted-message") {
console.log(`The message is ${message}`);
const response = await openai_ops.make_openai_call(message);
bot.say(channel, response);
}
}
// check if message is a command started with !COMMAND_NAME (e.g. !gpt) in lower-cased
if (message.toLowerCase().startsWith(COMMAND_NAME)) {
let text = message.slice(COMMAND_NAME.length);
if (SEND_USERNAME) {
text = "Message from user " + user.username + ": " + text
}
// make openai call
const response = await openai_ops.make_openai_call(text);
// split response if it exceeds twitch chat message length limit
// send multiples messages with a delay in between
if (response.length > MAX_LENGTH) {
const messages = response.match(new RegExp(`.{1,${MAX_LENGTH}}`, "g"));
messages.forEach((message, index) => {
setTimeout(() => {
bot.say(channel, message);
}, 1000 * index);
});
} else {
bot.say(channel, response);
}
if (ENABLE_TTS === "true") {
try {
console.log(user.username + ' - ' + user.userstate);
const ttsAudioUrl = await bot.sayTTS(channel, response, user.userstate);
// Notify clients about the file change
notifyFileChange(ttsAudioUrl);
} catch (error) {
console.error(error);
}
}
}
});
app.ws('/check-for-updates', (ws, req) => {
ws.on('message', (message) => {
// Handle WebSocket messages (if needed)
});
});
// setup bot
const messages = [
{role: "system", content: "You are a helpful Twitch Chatbot."}
];
console.log("GPT_MODE is " + GPT_MODE)
console.log("History length is " + HISTORY_LENGTH)
console.log("OpenAI API Key:" + OPENAI_API_KEY)
console.log("Model Name:" + MODEL_NAME)
app.use(express.json({extended: true, limit: '1mb'}))
app.use('/public', express.static('public'))
app.all('/', (req, res) => {
console.log("Just got a request!")
res.render('pages/index');
//res.sendFile(process.env.RENDER_SRC_ROOT + '/index.ejs')
//res.send('Yo!')
})
if (process.env.GPT_MODE === "CHAT"){
fs.readFile("./file_context.txt", 'utf8', function(err, data) {
if (err) throw err;
console.log("Reading context file and adding it as system level message for the agent.")
messages[0].content = data;
});
} else {
fs.readFile("./file_context.txt", 'utf8', function(err, data) {
if (err) throw err;
console.log("Reading context file and adding it in front of user prompts:")
file_context = data;
console.log(file_context);
});
}
app.get('/gpt/:text', async (req, res) => {
//The agent should receive Username:Message in the text to identify conversations with different users in his history.
const text = req.params.text
// define function to check history length and perform bot response
const answer_question = async (answer) => {
if (answer.length > MAX_LENGTH) {
const messages = answer.match(new RegExp(`.{1,${MAX_LENGTH}}`, "g"));
messages.forEach((message, index) => {
setTimeout(() => {
bot.say(channel, message);
}, 1000 * index);
});
} else {
bot.say(channel, answer);
}
}
let answer = ""
if (GPT_MODE === "CHAT") {
//CHAT MODE EXECUTION
answer = await openai_ops.make_openai_call(text);
} else if(GPT_MODE === "PROMPT") {
//PROMPT MODE EXECUTION
// create prompt based on file_context and the user prompt
let prompt = file_context;
prompt += "\n\nUser: " + text + "\nAgent:"
answer = await openai_ops.make_openai_call_completion(prompt);
} else {
//ERROR MODE EXECUTION
console.log("ERROR: GPT_MODE is not set to CHAT or PROMPT. Please set it as environment variable.")
}
// send response
await answer_question(answer)
res.send(answer)
})
// make app always listening to twitch chat and get new messages starting with !gpt on port 3000
const server = app.listen(3000, () => {
console.log('Server running on port 3000');
});
const wss = expressWsInstance.getWss();
// const wss = appWithWebSocket.ws
wss.on('connection', (ws) => {
ws.on('message', (message) => {
// Handle client messages (if needed)
});
});
// Notify clients when the file changes
function notifyFileChange() {
wss.clients.forEach((client) => {
if (client.readyState === ws.OPEN) {
client.send(JSON.stringify({ updated: true }));
}
});
}