Added OpenAI chat bot.
This commit is contained in:
parent
a759421791
commit
c17c51dcd1
|
@ -22,6 +22,7 @@ module.exports = {
|
|||
usernamePrefix: '@',
|
||||
channels: ['GamesNight'],
|
||||
games: [
|
||||
'chat',
|
||||
'mash',
|
||||
'trivia',
|
||||
'letters',
|
||||
|
@ -61,6 +62,18 @@ module.exports = {
|
|||
grey: 'shadow',
|
||||
silver: 'shadow',
|
||||
},
|
||||
chat: {
|
||||
apiKey: null, // OpenAI
|
||||
validModels: [
|
||||
'gpt-3.5-turbo',
|
||||
'text-davinci-003',
|
||||
'gpt-4',
|
||||
],
|
||||
model: 'gpt-3.5-turbo',
|
||||
history: 3,
|
||||
rule: 'a tired game host',
|
||||
rulePublic: true,
|
||||
},
|
||||
trivia: {
|
||||
mode: 'first', // first or timeout
|
||||
rounds: 10,
|
||||
|
|
|
@ -94,15 +94,17 @@ async function onCommand(args, context) {
|
|||
purgeQuestions();
|
||||
}
|
||||
|
||||
/* AI chat module is listening instead
|
||||
function onMessage(message, context) {
|
||||
const regex = new RegExp(`^${config.usernamePrefix}${config.user.username}[\\s\\p{P}]*\\s+[\\w\\p{P}]+\\s+[\\w, \\p{P}]+.*\\?`, 'ui');
|
||||
const regex = new RegExp(`^${config.usernamePrefix}?${config.user.username}[\\s\\p{P}]*\\s+[\\w\\p{P}]+\\s+[\\w, \\p{P}]+.*\\?`, 'ui');
|
||||
|
||||
if (regex.test(message.body)) {
|
||||
onCommand([message.body.replaceAll(`${config.usernamePrefix}${config.user.username}:?`, '').trim()], context, false);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
onCommand,
|
||||
onMessage,
|
||||
// onMessage,
|
||||
};
|
||||
|
|
|
@ -0,0 +1,139 @@
|
|||
'use strict';
|
||||
|
||||
const config = require('config');
|
||||
const bhttp = require('bhttp');
|
||||
|
||||
const style = require('../utils/style');
|
||||
|
||||
const promptRegex = new RegExp(`^${config.usernamePrefix}?${config.user.username}[:,\\s]`, 'ui');
|
||||
const history = new Map();
|
||||
|
||||
const settings = config.chat;
|
||||
|
||||
function setHistory(value, context) {
|
||||
if (!value) {
|
||||
context.sendMessage(`Chat history is set to ${style.bold(settings.history)}`, context.room.id, { label: false });
|
||||
return;
|
||||
}
|
||||
|
||||
const newHistory = Number(value);
|
||||
|
||||
if (!Number.isNaN(newHistory)) {
|
||||
settings.history = newHistory;
|
||||
|
||||
context.logger.info(`Chat history set to ${newHistory} by ${context.user.username}`);
|
||||
context.sendMessage(`Chat history set to ${style.bold(newHistory)} by ${context.user.prefixedUsername}`, context.room.id, { label: false });
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
context.logger.info(`Chat history must be a valid number, ${context.user.prefixedUsername}`);
|
||||
}
|
||||
|
||||
function setModel(model, context) {
|
||||
if (!model) {
|
||||
context.sendMessage(`Chat model is set to ${style.bold(settings.model)}`, context.room.id, { label: false });
|
||||
return;
|
||||
}
|
||||
|
||||
if (config.chat.validModels.includes(model)) {
|
||||
settings.model = model;
|
||||
|
||||
context.logger.info(`Chat model set to '${model}' by ${context.user.username}`);
|
||||
context.sendMessage(`Chat model set to '${style.bold(model)}' by ${context.user.prefixedUsername}`, context.room.id, { label: false });
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
context.logger.info(`Model '${model}' is not supported right now, ${context.user.prefixedUsername}`);
|
||||
}
|
||||
|
||||
function setRule(rule, context) {
|
||||
if (!rule) {
|
||||
context.sendMessage(`Chat is ${style.bold(settings.rule)}`, context.room.id, { label: false });
|
||||
return;
|
||||
}
|
||||
|
||||
if (rule === 'reset') {
|
||||
settings.rule = config.chat.rule;
|
||||
|
||||
context.logger.info(`Chat reset by ${context.user.username} to be ${config.chat.rule}`);
|
||||
context.sendMessage(`Chat reset by ${context.user.prefixedUsername} to be ${style.bold(config.chat.rule)}`, context.room.id, { label: false });
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (rule.length > 3) {
|
||||
settings.rule = `${rule.replace(/\.+$/, '')}`;
|
||||
|
||||
context.logger.info(`Chat set by ${context.user.username} to be ${rule}`);
|
||||
context.sendMessage(`Chat set by ${context.user.prefixedUsername} to be ${style.bold(rule)}`, context.room.id, { label: false });
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
context.sendMessage(`Chat rule must be at least 3 characters long, ${context.user.prefixedUsername}`, context.room.id, { label: false });
|
||||
}
|
||||
|
||||
async function onCommand(args, context) {
|
||||
if (context.subcommand === 'history' && config.operators.includes(context.user.username)) {
|
||||
setHistory(args[0], context);
|
||||
return;
|
||||
}
|
||||
|
||||
if (context.subcommand === 'model' && config.operators.includes(context.user.username)) {
|
||||
setModel(args[0], context);
|
||||
return;
|
||||
}
|
||||
|
||||
if (['rule', 'is', 'reset'].includes(context.subcommand) && (config.chat.rulePublic || config.operators.includes(context.user.username))) {
|
||||
setRule(context.subcommand === 'reset' ? 'reset' : args.join(' '), context);
|
||||
return;
|
||||
}
|
||||
|
||||
const prompt = args.join(' ');
|
||||
|
||||
try {
|
||||
const message = {
|
||||
role: 'user',
|
||||
content: `Answer as if you're ${settings.rule}. ${prompt}`,
|
||||
};
|
||||
|
||||
const userHistory = (history.get(context.user.username) || []).concat(message);
|
||||
|
||||
context.logger.info(`${context.user.username} asked OpenAI '${config.chat.model}' (${userHistory.length}): ${message.content}`);
|
||||
|
||||
const res = await bhttp.post('https://api.openai.com/v1/chat/completions', JSON.stringify({
|
||||
model: settings.model,
|
||||
messages: userHistory,
|
||||
}), {
|
||||
headers: {
|
||||
Authorization: `Bearer ${config.chat.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
const reply = res.body.choices?.[0].message;
|
||||
|
||||
context.logger.info(`OpenAI ${config.chat.model} replied to ${context.user.username} (${res.body.usage.total_tokens} tokens): ${reply.content}`);
|
||||
context.sendMessage(`${context.user.prefixedUsername}: ${reply.content}`, context.room.id, { label: false });
|
||||
|
||||
if (config.chat.history > 0) {
|
||||
history.set(context.user.username, userHistory.concat(reply).slice(-settings.history));
|
||||
}
|
||||
} catch (error) {
|
||||
context.logger.error(error.response ? `${error.response.status}: ${JSON.stringify(error.response.data)}` : error.message);
|
||||
context.sendMessage('Sorry, I can\'t think right now', context.room.id, { label: false });
|
||||
}
|
||||
}
|
||||
|
||||
function onMessage(message, context) {
|
||||
if (promptRegex.test(message.body)) {
|
||||
onCommand([message.body.replace(promptRegex, '').trim()], context);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
onCommand,
|
||||
onMessage,
|
||||
};
|
Loading…
Reference in New Issue