-
-
Notifications
You must be signed in to change notification settings - Fork 2
/
index.js
161 lines (133 loc) · 4.37 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
import ollama from 'ollama';
import { ActivityType, Client, GatewayIntentBits, Partials } from 'discord.js';
import 'dotenv/config'
const BOT_TOKEN = process.env.BOT_TOKEN;
const MODEL_NAME = process.env.MODEL_NAME;
const CHANNEL_ID = process.env.CHANNEL_ID;
const previousMessageLimit = 6; // The number of previous messages to send to the model
const stopIfGenerating = true; // If true, the bot will not respond to messages if it is already generating a response
const messageUpdateInterval = 1000; // 1 second between message updates
const textCursorString = '▋';
const previousMessages = [];
let previousMessage = '';
let isGenerating = false;
function trimPreviousMessages() {
// Trim the previous messages if there are more than the limit allows
if (previousMessages.length > previousMessageLimit) {
previousMessages.shift();
}
}
const client = new Client({
intents: Object.values(GatewayIntentBits),
partials: [Partials.Channel, Partials.Message, Partials.User, Partials.GuildMember, Partials.Reaction],
});
function updateMessage(messageObject, result, generating) {
if (!result) return;
// Add the text cursor to the end of the message if the bot is still generating
let newMessage = result.trim() + (generating ? textCursorString : '');
// If the message hasn't changed, don't update it
if (previousMessage === newMessage) {
return;
}
// Discord has a 2000 character limit
if (newMessage.length > 2000) {
newMessage = newMessage.substring(0, 2000);
}
// This should never happen, but Discord throws an error if you try to send an empty message
if (newMessage.length === 0) {
newMessage = '*No response*';
}
// Update the message with the new content
messageObject.edit({
content: newMessage,
allowedMentions: {
repliedUser: false
}
});
previousMessage = newMessage;
// If the bot is done generating, add the message to the previous messages
if (!generating) {
previousMessages.push({ role: 'assistant', content: newMessage });
trimPreviousMessages();
isGenerating = false;
}
}
async function streamResponse(messageObject, content) {
// Add the user's message to the previous messages
const message = { role: 'user', content };
previousMessages.push(message);
trimPreviousMessages();
// Send the previous messages to the model
const response = await ollama.chat({ model: MODEL_NAME, messages: previousMessages, stream: true });
let result = '';
const interval = setInterval(() => {
updateMessage(messageObject, result, true);
}, messageUpdateInterval);
// Update the final result with the model's responses
for await (const part of response) {
if (!part.message || !part.message.content) continue;
result += part.message.content;
process.stdout.write(part.message.content);
}
// Stop updating the message procedurally
clearInterval(interval);
// Update the message with the final result
updateMessage(messageObject, result, false);
// Add a new line to the console
process.stdout.write('\n');
}
client.once('ready', () => {
console.log('Bot is online!');
// Set the bot's status
client.user.setPresence({
activities: [{
name: 'llama.Warze.org',
type: ActivityType.Listening,
}],
status: 'online'
});
});
client.on('messageCreate', async (message) => {
// Ignore messages from other bots
if (message.author.bot) return;
// Ignore messages from other channels
if (message.channel.id !== CHANNEL_ID) return;
// Ignore messages that start with #
if (message.content.startsWith('#')) return;
if (message.content === '!model') {
// Send the model name to the channel
await message.reply({
content: 'Model name: `' + MODEL_NAME + '`',
allowedMentions: {
repliedUser: false
}
});
return;
}
if (message.content === '!clear') {
// Clear the previous messages
previousMessages.length = 0;
await message.reply({
content: 'Previous messages cleared',
allowedMentions: {
repliedUser: false
}
});
return;
}
// Dont respond to messages if the bot is generating a response
if (isGenerating && stopIfGenerating) return;
// No longer accepting messages
isGenerating = true;
// Send the text cursor to the channel
const messageObject = await message.reply({
content: textCursorString,
allowedMentions: {
repliedUser: false
}
});
previousMessage = textCursorString;
// Send the message to the model
await streamResponse(messageObject, message.content);
});
client.login(BOT_TOKEN);