diff --git a/bot/installableApp.js b/bot/installableApp.js index ae66b3d..bfa6e68 100644 --- a/bot/installableApp.js +++ b/bot/installableApp.js @@ -1,27 +1,24 @@ -const { Client, GatewayIntentBits, REST, Routes, EmbedBuilder, SlashCommandBuilder } = require('discord.js'); +const { Client, GatewayIntentBits, REST, Routes, EmbedBuilder, SlashCommandBuilder, AttachmentBuilder } = require('discord.js'); const axios = require('axios'); const he = require('he'); const fs = require('fs'); +const PDFDocument = require('pdfkit'); // Import PDFKit require('dotenv').config(); -const { userResetMessages } = require('./assets/messages.js'); const client = new Client({ intents: [GatewayIntentBits.Guilds] }); -// Load or initialize the user privacy settings const userPrivacyFilePath = './userPrivacySettings.json'; let userPrivacySettings = {}; if (fs.existsSync(userPrivacyFilePath)) { userPrivacySettings = JSON.parse(fs.readFileSync(userPrivacyFilePath)); } -// Save the user privacy settings function saveUserPrivacySettings() { fs.writeFileSync(userPrivacyFilePath, JSON.stringify(userPrivacySettings, null, 2)); } -// Define the commands const commands = [ new SlashCommandBuilder().setName('reset').setDescription('Reset the conversation'), new SlashCommandBuilder().setName('restartcore').setDescription('Restart the core service'), @@ -30,13 +27,14 @@ const commands = [ option.setName('message') .setDescription('Message to send') .setRequired(true)), - new SlashCommandBuilder().setName('privacy').setDescription('Toggle between ephemeral and standard responses') + new SlashCommandBuilder().setName('privacy').setDescription('Toggle between ephemeral and standard responses'), + new SlashCommandBuilder().setName('pdf').setDescription('Download conversation history as a PDF') ].map(command => { const commandJSON = command.toJSON(); const extras = { - "integration_types": [0, 1], // 0 for guild, 1 for user - "contexts": [0, 1, 2] // 0 for guild, 1 for app DMs, 2 for GDMs and other DMs + "integration_types": [0, 1], + "contexts": [0, 1, 2] }; Object.keys(extras).forEach(key => commandJSON[key] = extras[key]); @@ -44,7 +42,6 @@ const commands = [ return commandJSON; }); -// Register commands with Discord const rest = new REST({ version: '10' }).setToken(process.env.THE_TOKEN_2); client.once('ready', async () => { @@ -63,7 +60,7 @@ client.on('interactionCreate', async interaction => { const { commandName, options } = interaction; if (commandName === 'reset') { - return await resetConversation(interaction); + await resetConversation(interaction); } else if (commandName === 'restartcore') { await restartCore(interaction); } else if (commandName === 'chat') { @@ -71,6 +68,8 @@ client.on('interactionCreate', async interaction => { await handleUserMessage(interaction, content); } else if (commandName === 'privacy') { await togglePrivacy(interaction); + } else if (commandName === 'pdf') { + await generatePDF(interaction); } }); @@ -203,5 +202,60 @@ async function sendLongMessage(interaction, responseText) { } } +// Generate a PDF of the conversation history +async function generatePDF(interaction) { + try { + // Fetch the conversation history from the API + const response = await axios.get(`http://${process.env.ROOT_IP}:${process.env.ROOT_PORT}/api/v1/conversation-history`, { + headers: { + 'x-forwarded-for-id': interaction.user.id + } + }); + + const conversationHistory = response.data; + + // Filter out system messages + const filteredHistory = conversationHistory.filter(message => message.role !== 'system'); + + // Create a PDF document + const doc = new PDFDocument(); + const pdfPath = `./conversation_${interaction.user.id}.pdf`; + const writeStream = fs.createWriteStream(pdfPath); + + // Pipe the document to a file + doc.pipe(writeStream); + + // Add conversation history to the PDF + doc.fontSize(14).text('Conversation History', { align: 'center' }); + doc.moveDown(); + + filteredHistory.forEach((message, index) => { + const role = message.role.charAt(0).toUpperCase() + message.role.slice(1); + const content = he.decode(message.content); // Decode any HTML entities + doc.fontSize(12).text(`${role}: ${content}`, { align: 'left' }); + doc.moveDown(); + }); + + doc.end(); + + // Wait for the PDF to finish writing + writeStream.on('finish', async () => { + const attachment = new AttachmentBuilder(pdfPath); + + await interaction.reply({ + content: 'Here is your conversation history in PDF format:', + files: [attachment], + ephemeral: isEphemeral(interaction.user.id) + }); + + // Clean up the PDF file after sending it + fs.unlinkSync(pdfPath); + }); + } catch (error) { + console.error('Failed to generate PDF:', error); + await interaction.reply({ content: 'Failed to generate PDF.', ephemeral: isEphemeral(interaction.user.id) }); + } +} + // Log in the bot client.login(process.env.THE_TOKEN_2);