-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathapp.js
320 lines (250 loc) · 11.9 KB
/
app.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
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
import dotenv from 'dotenv';
import express, { static as expressStatic } from 'express';
import userRoutes from './routes/userRoutes.js';
import backendRoutes from './routes/backendRoutes.js';
import authRoutes from './routes/authRoutes.js';
import adminRoutes from './routes/adminRoutes.js';
import expressSession from 'express-session';
import { PrismaClient } from '@prisma/client';
import { PrismaSessionStore } from '@quixo3/prisma-session-store';
import { startMain as mainAgent } from "./agents/mainAgent.js";
import { startMain as autoAgent } from "./agents/autoAgent.js";
import { Client, GatewayIntentBits } from 'discord.js';
const client = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.MessageContent,
// ...
]
});
dotenv.config({ path: `.env.local`, override: true });
const app = express();
//APPLICATION ROUTES
app.use(
expressSession({
cookie: {
maxAge: 7 * 24 * 60 * 60 * 1000 // ms
},
secret: process.env.JWT_SECRET,
resave: true,
saveUninitialized: true,
store: new PrismaSessionStore(
new PrismaClient(),
{
checkPeriod: 2 * 60 * 1000, //ms
dbRecordIdIsSessionId: true,
dbRecordIdFunction: undefined,
}
)
})
);
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(expressStatic('public'));
app.use('/public', expressStatic('public'));
app.use('/Documentation', expressStatic('Documentation'));
app.use('/auth', authRoutes); // Add this line for authentication routes
app.use('/', userRoutes);
app.use('/backend', backendRoutes);
app.use('/admin', adminRoutes);
app.listen(80, () => {
console.log('Server started on port 80');
});
//Discord BOT
client.on("ready", () => {
console.log(`Logged in as ${client.user.tag}!`);
});
client.on("messageCreate", async (msg) => {
if (msg.channelId === "1136204139974635641" && msg.author.id != "1136201492995518515") {
try {
const channel = await client.channels.fetch(msg.channelId);
// Start typing indicator
await channel.sendTyping();
var answer = await callMainAgent(msg);
// Split the answer into chunks at sentence-ending periods
const chunks = splitResponseIntoChunks(answer, 1999);
// Send each chunk separately
for (const chunk of chunks) {
// Reply to the user in the same channel
await msg.reply(chunk);
// or, send the chunk without mentioning the user
// await msg.channel.send(chunk);
// Add a small delay before sending the next chunk
await new Promise((resolve) => setTimeout(resolve, 500));
}
} catch (error) {
console.error("Error while processing the message:", error);
// Handle any potential errors here and inform the user if necessary
msg.channel.send("An error occurred while processing your request.");
}
}
if (msg.channel.parent.name === 'Alone' && msg.author.id != "1136201492995518515") {
try {
const channel = await client.channels.fetch(msg.channelId);
// Start typing indicator
await channel.sendTyping();
var answer = await callAutoAgent(msg);
// Split the answer into chunks at sentence-ending periods
const chunks = splitResponseIntoChunks(answer, 1999);
// Send each chunk separately
for (const chunk of chunks) {
// Reply to the user in the same channel
await msg.reply(chunk);
// or, send the chunk without mentioning the user
// await msg.channel.send(chunk);
// Add a small delay before sending the next chunk
await new Promise((resolve) => setTimeout(resolve, 500));
}
} catch (error) {
console.error("Error while processing the message:", error);
// Handle any potential errors here and inform the user if necessary
msg.channel.send("An error occurred while processing your request.");
}
}
});
client.login(process.env.BOT_TOKEN);
async function callMainAgent(msg){
const discordMessage = msg.content;
const discordId = msg.author.id;
const prisma = new PrismaClient();
const user = await prisma.user.findFirst({
where: { discordId: discordId },
});
if (!user) {
console.log('User not found with discordId:', discordId);
return "Your discord account has no link to the application : https://qyuuuuu.eu/register . You must first create an account and then link it to discord.";
}
let mostRecentConversation = await prisma.conversation.findFirst({
where: { userId: user.id, NOT: { Name: 'Auto' } },
orderBy: { id: 'desc' },
});
if (!mostRecentConversation) {
console.log('No conversation found for the user with discordId:', discordId);
// Create a new conversation with no name if none exists
mostRecentConversation = await prisma.conversation.create({
data: {
User: { connect: { id: user.id } },
},
});
await prisma.message.create({
data: {
content: `Your name is GM. You are a Game Master of a tabletop RPG game and you narrate situations in which, I, the player, make decisions. The world you are making me play in is a Dark fantasy themed one. The scenario takes place in a medieval city of the kingdom of Avhorea. The ruler of the kingdom is "Sevire the Red", nickname she acquired by killing all the noble houses that were her ennemies, and by disennobling the weakest ones she still has ennemies within her kingdom, although they don't fight her upfront and scheme in the shadows.
Adrien se réveille un matin au camp militaire de son régiment. Adrien est un soldat de l’empire du soleil noir. Il fait partit du 17ème régiment, composé de 2500 hommes.
Le Culte du Soleil Noir est une religion fanatique qui prêche l'arrivée d'un nouveau Prophète et considère le soleil comme l'Œil de l'Unique. Ils organisent des fêtes religieuses appelées le Massacre du Soleil Noir, où des orgies ont lieu et des sacrifices violents sont effectués.
Son régiment, aux côtés du 16ème, est chargé d’assister Vox Aedes, l’ordre dont la mission est de répandre le Culte du soleil noir dans leur mission actuelle, faire du prosélytisme en Avhorae.
Le Culte tente d'infiltrer les terres de l'ouest en général, mais a été interdit depuis l'ascension de Sevire au trône d’Avhorae.
Des purges ont même été organisées par Sévire pour éliminer les congrégations clandestines mais les fidèles du Culte tentent maintenant de recruter parmi les survivants des familles ducales déchues lors de l’accession au pouvoir de Sévire.
Adrien est donc rapidement équipé et prêt à aider à l’installation du camp caché dans la montagne au nord de la ville de Cyridon.
Durant la matinée, Adrius est interrompu dans ses corvées par son officier responsable qui lui demande de le suivre vers la tente du général.
drien et son groupe, désormais équipés d'habits civils, commencent leur infiltration dans la ville de Cyridon. Ils doivent se mêler à la population locale pour obtenir des informations cruciales sur l'exécution publique planifiée par Sévire.
Sevire has a magical sword, that make her almost as strong as a god, and 8 other blades are weilded by her most faithful servents, and generals of her army, the silver phalanx.
To help yourself, you must use tools when necessary. Always decide the player's actions resolution via the throwing of a d20 dice.
If you have a general question about the lore of GODS or its rules use the tool gods-lore with the Action gods-lore and the Action Input set to the question asked, the tool will then answer your question.
You must be immersive for the user by describing the world and characters with precision and poetry, and by respecting the user's choices and actions. Always interact with the user and wait to be surprised by their creativity before deciding anything for them.`, // Replace with the actual content
sender: "Bot", // Replace with the actual sender
Conversation: { connect: { id: mostRecentConversation.id } },
// Add other properties for the character here
},
});
await prisma.message.create({
data: {
content: "Bienvenue dans le royaume d'Avhorea, cher voyageur. Vous incarnez un garde de l'empire du Soleil noir chargé d'espionner le royaume d'Avhorae et son impératrice Sévire, dites moi quand vous voulez commencer à jouer.'.", // Replace with the actual content
sender: "Bot", // Replace with the actual sender
Conversation: { connect: { id: mostRecentConversation.id } },
// Add other properties for the character here
},
});
}
var conversationId = mostRecentConversation.id;
await prisma.message.create({
data: {
content: discordMessage, // Replace with the actual content
sender: "User", // Replace with the actual sender
Conversation: { connect: { id: conversationId } },
// Add other properties for the character here
},
});
// Now you can use startMain as an async function.
const botAnswer = await mainAgent(discordMessage, user.id);
await prisma.message.create({
data: {
content: botAnswer.output, // Replace with the actual content
sender: "Bot", // Replace with the actual sender
Conversation: { connect: { id: conversationId } },
// Add other properties for the character here
},
});
return botAnswer.output;
}
async function callAutoAgent(msg){
const discordMessage = msg.content;
const discordId = msg.author.id;
const prisma = new PrismaClient();
const user = await prisma.user.findFirst({
where: { discordId: discordId },
});
if (!user) {
console.log('User not found with discordId:', discordId);
return "Your discord account has no link to the application : https://qyuuuuu.eu/register . You must first create an account and then link it to discord.";
}
let mostRecentConversation = await prisma.conversation.findFirst({
where: { userId: user.id, Name: 'Auto' },
orderBy: { id: 'desc' },
});
if (!mostRecentConversation) {
console.log('No conversation found for the user with discordId:', discordId);
// Create a new conversation with no name if none exists
mostRecentConversation = await prisma.conversation.create({
data: {
User: { connect: { id: user.id } },
Name: 'Auto',
},
});
}
var conversationId = mostRecentConversation.id;
await prisma.message.create({
data: {
content: discordMessage, // Replace with the actual content
sender: "User", // Replace with the actual sender
Conversation: { connect: { id: conversationId } },
// Add other properties for the character here
},
});
const messages = await prisma.message.findMany({
where: {
Conversation: {
id: conversationId,
},
},
});
// Now you can use startMain as an async function.
const botAnswer = await autoAgent(discordMessage, user.id, messages);
await prisma.message.create({
data: {
content: botAnswer.output, // Replace with the actual content
sender: "Bot", // Replace with the actual sender
Conversation: { connect: { id: conversationId } },
// Add other properties for the character here
},
});
return botAnswer.output;
}
function splitResponseIntoChunks(response, maxLength) {
const chunks = [];
const sentences = response.split('. ');
let currentChunk = "";
for (const sentence of sentences) {
if ((currentChunk + sentence + '. ').length <= maxLength) {
currentChunk += sentence + '. ';
} else {
chunks.push(currentChunk.trim());
currentChunk = sentence + '. ';
}
}
// Add the last chunk
if (currentChunk.length > 0) {
chunks.push(currentChunk.trim());
}
return chunks;
}