User Preferences and Setup Docs (#20)

* added message style command

* docker setup scripts

* reformat messageStyle.ts

* fix: register unregister on deploy

* add: messageStream preference

* add: json config handler

* update: messageCreate gets config

* update: shifted chat to config callback

* fix: naming conventions based on discord

* update: setup in docs now

* add: static docker ips

* version increment

* add: bot message for no config

* fix: no config case

* add: clarification for subnetting

* update: version increment in lock file

---------

Co-authored-by: JT2M0L3Y <jtsmoley@icloud.com>
This commit is contained in:
Kevin Dang
2024-03-22 10:37:06 -07:00
committed by GitHub
parent 5e74736c57
commit 43fb2ea94e
20 changed files with 377 additions and 146 deletions

View File

@@ -1,10 +1,14 @@
import { CommandInteraction, ChatInputApplicationCommandData, Client } from 'discord.js'
import { CommandInteraction, ChatInputApplicationCommandData, Client, ApplicationCommandOption } from 'discord.js'
/**
* interface for how slash commands should be run
*/
export interface SlashCommand extends ChatInputApplicationCommandData {
run: (client: Client, interaction: CommandInteraction) => void
run: (
client: Client,
interaction: CommandInteraction,
options?: ApplicationCommandOption[]
) => void
}
/**
@@ -16,7 +20,28 @@ export function registerCommands(client: Client, commands: SlashCommand[]): void
// ensure the bot is online before registering
if (!client.application) return
// map commands into an array of names, used to checking registered commands
const commandsToRegister: string[] = commands.map(command => command.name)
// fetch all the commands and delete them
client.application.commands.fetch().then((fetchedCommands) => {
for (const command of fetchedCommands.values()) {
if (!commandsToRegister.includes(command.name)) {
command.delete().catch(console.error)
console.log(`[Command: ${command.name}] Removed from Discord`)
}
}
})
// clear the cache of the commands
client.application.commands.cache.clear()
// iterate through all commands and register them with the bot
for (const command of commands)
client.application.commands.create(command)
client.application.commands
.create(command)
.then((c) => {
console.log(`[Command: ${c.name}] Registered on Discord`)
c.options?.forEach((o) => console.log(` - ${o.name}`))
})
}

56
src/utils/jsonHandler.ts Normal file
View File

@@ -0,0 +1,56 @@
import fs from 'fs'
export interface Configuration {
readonly name: string
options: {
'message-stream'?: boolean,
'message-style'?: boolean
}
}
/**
* Method to open a file in the working directory and modify/create it
*
* @param filename name of the file
* @param key key value to access
* @param value new value to assign
*/
export function openFile(filename: string, key: string, value: any) {
// check if the file exists, if not then make the config file
if (fs.existsSync(filename)) {
fs.readFile(filename, 'utf8', (error, data) => {
if (error)
console.log(`[Error: openFile] Incorrect file format`)
else {
const object = JSON.parse(data)
object['options'][key] = value
fs.writeFileSync(filename, JSON.stringify(object, null, 2))
}
})
} else {
const object: Configuration = JSON.parse('{ \"name\": \"Discord Ollama Confirgurations\" }')
// set standard information for config file and options
object['options'] = {
[key]: value
}
fs.writeFileSync(filename, JSON.stringify(object, null, 2))
console.log(`[Util: openFile] Created 'config.json' in working directory`)
}
}
export async function getConfig(filename: string, callback: (config: Configuration | undefined) => void): Promise<void> {
// attempt to read the file and get the configuration
if (fs.existsSync(filename)) {
fs.readFile(filename, 'utf8', (error, data) => {
if (error) {
callback(undefined)
return // something went wrong... stop
}
callback(JSON.parse(data))
})
} else {
callback(undefined) // file not found
}
}

View File

@@ -52,10 +52,10 @@ export async function embedMessage(
// edit the message
sentMessage.edit({ embeds: [newEmbed] })
} catch(error: any) {
console.log(`[Event: messageEmbed] Error creating message: ${error.message}`)
console.log(`[Util: messageEmbed] Error creating message: ${error.message}`)
const errorEmbed = new EmbedBuilder()
.setTitle(`Responding to ${message.author.tag}`)
.setDescription(`Issue creating response: ${error.message}`)
.setDescription(`**Response generation failed.**\n\nReason: ${error.message}`)
.setColor('#00FF00')
// send back error

View File

@@ -1,5 +1,5 @@
import { Message } from 'discord.js'
import ollama, { ChatResponse } from 'ollama'
import { ChatResponse, Ollama } from 'ollama'
import { UserMessage } from './events.js'
/**
@@ -8,8 +8,9 @@ import { UserMessage } from './events.js'
* @param tokens tokens to run query
* @param msgHist message history between user and model
*/
export function normalMessage(
message: Message,
export async function normalMessage(
message: Message,
ollama: Ollama,
tokens: {
channel: string,
model: string
@@ -19,7 +20,7 @@ export function normalMessage(
// bot's respnse
let response: ChatResponse
message.reply('Generating Response . . .').then(async sentMessage => {
await message.reply('Generating Response . . .').then(async sentMessage => {
try {
// Attempt to query model for message
response = await ollama.chat({
@@ -37,7 +38,8 @@ export function normalMessage(
// edit the 'generic' response to new message
sentMessage.edit(response.message.content)
} catch(error: any) {
sentMessage.edit(error.error)
console.log(`[Util: messageNormal] Error creating message: ${error.message}`)
sentMessage.edit(`**Response generation failed.**\n\nReason: ${error.message}`)
}
})

View File

@@ -4,6 +4,8 @@ import { AxiosResponse } from 'axios'
* When running a /api/chat stream, the output needs to be parsed into an array of objects
* This method is used for development purposes and testing
*
* This will not work as intended with the inclusion of ollama-js, needs to be modified to work with it
*
* @param stream Axios response to from Ollama
*/
export function parseStream(stream: AxiosResponse<any, any>) {