mirror of
https://github.com/pacnpal/markov-discord.git
synced 2025-12-20 11:01:04 -05:00
Some work on channel-gating
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -65,3 +65,5 @@ config.json
|
||||
# error output file
|
||||
error.json
|
||||
markovDB.json
|
||||
|
||||
config
|
||||
|
||||
@@ -1,14 +1,53 @@
|
||||
import { SlashCommandBuilder } from '@discordjs/builders';
|
||||
import { SlashCommandBuilder, SlashCommandChannelOption } from '@discordjs/builders';
|
||||
import { REST } from '@discordjs/rest';
|
||||
import { Routes } from 'discord-api-types/v9';
|
||||
import { ChannelType, Routes } from 'discord-api-types/v9';
|
||||
import { config } from './config';
|
||||
import { packageJson } from './util';
|
||||
|
||||
const CHANNEL_OPTIONS_MAX = 25;
|
||||
|
||||
const helpSlashCommand = new SlashCommandBuilder()
|
||||
.setName('help')
|
||||
.setDescription(`How to use ${packageJson().name}`);
|
||||
|
||||
const commands = [helpSlashCommand.toJSON()];
|
||||
/**
|
||||
* Helps generate a list of parameters for channel options
|
||||
*/
|
||||
const channelOptionsGenerator = (builder: SlashCommandChannelOption, index: number) =>
|
||||
builder
|
||||
.setName(`channel-${index + 1}`)
|
||||
.setDescription('A text channel')
|
||||
.setRequired(index === 0)
|
||||
.addChannelType(ChannelType.GuildText as any);
|
||||
|
||||
const listenChannelCommand = new SlashCommandBuilder()
|
||||
.setName('listen')
|
||||
.addSubcommand((sub) => {
|
||||
sub
|
||||
.setName('add')
|
||||
.setDescription(
|
||||
`Add channels to learn from. Doesn't add the channel's past messages; re-train to do that.`
|
||||
);
|
||||
|
||||
Array.from(Array(CHANNEL_OPTIONS_MAX).keys()).forEach((index) =>
|
||||
sub.addChannelOption((opt) => channelOptionsGenerator(opt, index))
|
||||
);
|
||||
return sub;
|
||||
})
|
||||
.addSubcommand((sub) => {
|
||||
sub
|
||||
.setName('remove')
|
||||
.setDescription(
|
||||
`Remove channels from being learned from. Doesn't remove the channel's data; re-train to do that.`
|
||||
);
|
||||
Array.from(Array(CHANNEL_OPTIONS_MAX).keys()).forEach((index) =>
|
||||
sub.addChannelOption((opt) => channelOptionsGenerator(opt, index))
|
||||
);
|
||||
return sub;
|
||||
})
|
||||
.setDescription(`How to use ${packageJson().name}`);
|
||||
|
||||
const commands = [helpSlashCommand.toJSON(), listenChannelCommand.toJSON()];
|
||||
|
||||
export async function deployCommands(clientId: string) {
|
||||
const rest = new REST({ version: '9' }).setToken(config.token);
|
||||
|
||||
@@ -5,10 +5,10 @@ import { Guild } from './Guild';
|
||||
@Entity()
|
||||
export class Channel extends BaseEntity {
|
||||
@PrimaryColumn()
|
||||
id: string;
|
||||
id: number;
|
||||
|
||||
@Column({
|
||||
default: true,
|
||||
default: false,
|
||||
})
|
||||
listen: boolean;
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import { Channel } from './Channel';
|
||||
@Entity()
|
||||
export class Guild extends BaseEntity {
|
||||
@PrimaryColumn()
|
||||
id: string;
|
||||
id: number;
|
||||
|
||||
@OneToMany(() => Channel, (channel) => channel.guild, { onDelete: 'CASCADE', cascade: true })
|
||||
channels: Channel[];
|
||||
|
||||
60
src/index.ts
60
src/index.ts
@@ -40,6 +40,13 @@ const markovOpts: MarkovConstructorOptions = {
|
||||
stateSize: config.stateSize,
|
||||
};
|
||||
|
||||
const markovGenerateOptions: MarkovGenerateOptions<MarkovDataCustom> = {
|
||||
filter: (result): boolean => {
|
||||
return result.score >= config.minScore;
|
||||
},
|
||||
maxTries: config.maxTries,
|
||||
};
|
||||
|
||||
/**
|
||||
* #v3-complete
|
||||
*/
|
||||
@@ -50,6 +57,20 @@ async function getMarkovByGuildId(guildId: string): Promise<Markov> {
|
||||
return markov;
|
||||
}
|
||||
|
||||
/**
|
||||
* #v3-complete
|
||||
*/
|
||||
async function isValidChannel(channelId: string): Promise<boolean> {
|
||||
const id = parseInt(channelId, 10);
|
||||
const channel = await Channel.findOne(id);
|
||||
if (!channel) {
|
||||
L.warn({ channelId }, 'Channel does not exist, setting to valid');
|
||||
await Channel.create({ id }).save();
|
||||
return false;
|
||||
}
|
||||
return channel.listen;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the author of a message as moderator-like permissions.
|
||||
* @param {GuildMember} member Sender of the message
|
||||
@@ -174,20 +195,25 @@ async function generateResponse(
|
||||
): Promise<void> {
|
||||
L.debug('Responding...');
|
||||
if (!interaction.guildId) {
|
||||
L.info('Received a message without a guildId');
|
||||
L.debug('Received an interaction without a guildId');
|
||||
return;
|
||||
}
|
||||
if (!interaction.channelId) {
|
||||
L.debug('Received an interaction without a channelId');
|
||||
return;
|
||||
}
|
||||
const isValid = await isValidChannel(interaction.channelId);
|
||||
if (!isValid) {
|
||||
L.debug(
|
||||
{ channelId: interaction.channelId },
|
||||
'Channel is not enabled for listening. Ignoring...'
|
||||
);
|
||||
return;
|
||||
}
|
||||
const options: MarkovGenerateOptions<MarkovDataCustom> = {
|
||||
filter: (result): boolean => {
|
||||
return result.score >= config.minScore;
|
||||
},
|
||||
maxTries: config.maxTries,
|
||||
};
|
||||
|
||||
const markov = await getMarkovByGuildId(interaction.guildId);
|
||||
|
||||
try {
|
||||
const response = await markov.generate<MarkovDataCustom>(options);
|
||||
const response = await markov.generate<MarkovDataCustom>(markovGenerateOptions);
|
||||
L.info({ response }, 'Generated response');
|
||||
const messageOpts: Discord.MessageOptions = { tts };
|
||||
const attachmentUrls = response.refs
|
||||
@@ -197,7 +223,6 @@ async function generateResponse(
|
||||
const randomRefAttachment = getRandomElement(attachmentUrls);
|
||||
messageOpts.files = [randomRefAttachment];
|
||||
} else {
|
||||
// TODO: This might not even work
|
||||
const randomMessage = await MarkovInputData.createQueryBuilder<
|
||||
MarkovInputData<MarkovDataCustom>
|
||||
>('input')
|
||||
@@ -297,19 +322,10 @@ client.on('ready', async (readyClient) => {
|
||||
|
||||
await deployCommands(readyClient.user.id);
|
||||
|
||||
const guildsToSave: Guild[] = [];
|
||||
const channelsToSave: Channel[] = [];
|
||||
readyClient.guilds.valueOf().forEach((guild) => {
|
||||
const dbGuild = Guild.create({ id: guild.id });
|
||||
const textChannels = guild.channels.valueOf().filter((channel) => channel.isText());
|
||||
const dbChannels = textChannels.map((channel) =>
|
||||
Channel.create({ id: channel.id, guild: dbGuild })
|
||||
);
|
||||
guildsToSave.push(dbGuild);
|
||||
channelsToSave.push(...dbChannels);
|
||||
});
|
||||
const guildsToSave = readyClient.guilds
|
||||
.valueOf()
|
||||
.map((guild) => Guild.create({ id: parseInt(guild.id, 10) }));
|
||||
await Guild.upsert(guildsToSave, ['id']);
|
||||
await Channel.upsert(channelsToSave, ['id']); // TODO: ensure this doesn't overwrite the existing `listen`
|
||||
});
|
||||
|
||||
client.on('error', (err) => {
|
||||
|
||||
Reference in New Issue
Block a user