From daa97f9d863cdf673b00028824ab7fd462ca1e80 Mon Sep 17 00:00:00 2001 From: Stef Dunlap Date: Tue, 7 Mar 2023 21:41:08 -0500 Subject: [PATCH] Add context, !chat clears the context !cont keeps it --- index.js | 74 ++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 61 insertions(+), 13 deletions(-) diff --git a/index.js b/index.js index 63045c4..6a330a0 100644 --- a/index.js +++ b/index.js @@ -3,13 +3,62 @@ const irc = require('irc'); const axios = require('axios'); const config = require('./config.json'); + +// context is a list of strings that are used to seed the chatgpt api and it's responses +class Context { + messages = []; + currentResponse = ''; + + add_user_message(message) { + this.messages.push({ role: 'user', content: message }); + } + + add_assistant_message(message) { + this.messages.push({ role: 'assistant', content: message }); + } + + append_current_response(message) { + this.currentResponse += message; + } + + end_line() { + const response_so_far = this.currentResponse; + this.currentResponse += "\n\n" + return response_so_far; + } + + finish_current_response() { + this.add_assistant_message(this.currentResponse); + const the_response = this.currentResponse; + this.currentResponse = ''; + return the_response; + } + + is_response_in_progress() { + return this.currentResponse !== ''; + } + + clear() { + this.messages = []; + this.currentResponse = ''; + } +} + +const context = new Context(); + const client = new irc.Client(config.server, config.nick, { channels: config.channels, }); // listen for messages that start with !chat and call the chatgpt api with a callback that prints the response line by line client.addListener('message', async (from, to, message) => { - if (message.startsWith('!chat')) { + is_chat_cmd = message.startsWith('!chat'); + is_cont_cmd = message.startsWith('!cont'); + if (is_chat_cmd || is_cont_cmd) { + if(context.is_response_in_progress()) { return; } + if(is_chat_cmd) { + context.clear(); + } const query = message.slice(6); chatgpt(query, (line) => { client.say(to, line); @@ -19,10 +68,13 @@ client.addListener('message', async (from, to, message) => { // function that calls the chatgpt streaming api (with server send events) and calls the callback function for each line async function chatgpt(query, callback) { + // a very primitive mutex to prevent multiple calls to the api at once + if(context.is_response_in_progress()) { return; } + context.add_user_message(query); const apiUrl = 'https://api.openai.com/v1/chat/completions'; - + const response = await axios.post(apiUrl, { - messages: [{ role: 'user', content: query }], + messages: [context.messages], model: 'gpt-3.5-turbo', stream: true, }, { @@ -33,7 +85,6 @@ async function chatgpt(query, callback) { responseType: 'stream', }); - let line = ''; response.data.on('data', (event) => { let data = event.toString(); let parts = data.split('\n'); @@ -41,8 +92,7 @@ async function chatgpt(query, callback) { for(part of parts) { console.log(part); if(part === 'data: [DONE]') { - callback(line); - line = ''; + callback(context.finish_current_response()); } else if(part.startsWith('data: ')) { let jsonString = part.slice(part.indexOf('{'), part.lastIndexOf('}') + 1); try { @@ -60,20 +110,18 @@ async function chatgpt(query, callback) { let hasEndNewline = chunk.endsWith("\n"); if(hasStartNewline) { - callback(line); - line = ''; + callback(context.end_line()) } for (let i = 0; i < lines.length - 1; i++) { - callback(line+lines[i]); - line = ''; + context.append_current_response(lines[i]); + callback(context.end_line()); } - line += lines[lines.length - 1]; + context.append_current_response(lines[lines.length - 1]); if(hasEndNewline) { - callback(line); - line = ''; + callback(context.end_line()); } if(line.length > 400) {