This commit is contained in:
Ashley Graves 2024-10-10 08:34:00 +02:00
parent 2f09b99d0b
commit 2eaadf2208
9 changed files with 224 additions and 31 deletions

View file

@ -8,6 +8,7 @@
"author": "",
"license": "MIT",
"dependencies": {
"booru": "^2.6.8",
"discord.js": "^14.16.3",
"dotenv": "^16.4.5",
"groq-sdk": "^0.7.0"

View file

@ -8,6 +8,9 @@ importers:
.:
dependencies:
booru:
specifier: ^2.6.8
version: 2.6.8
discord.js:
specifier: ^14.16.3
version: 14.16.3
@ -17,9 +20,6 @@ importers:
groq-sdk:
specifier: ^0.7.0
version: 0.7.0
uwuifier:
specifier: ^4.2.2
version: 4.2.2
packages:
@ -90,6 +90,10 @@ packages:
asynckit@0.4.0:
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
booru@2.6.8:
resolution: {integrity: sha512-/MN9Q5Yd3jBvOXgG05SLsdbGHFUWx6yoLYKU0xIoTWDsNlliUqM8Aj581pBujqFhg4E/Pi9cHdpMRN/FqustUA==}
engines: {node: '>=10.0.0'}
combined-stream@1.0.8:
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
engines: {node: '>= 0.8'}
@ -122,6 +126,10 @@ packages:
fast-deep-equal@3.1.3:
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
fast-xml-parser@4.5.0:
resolution: {integrity: sha512-/PlTQCI96+fZMAOLMZK4CWG1ItCbfZ/0jx7UIJFChPNrx7tcEgerUgWbeieCM9MfHInUDyK8DWYZ+YrywDJuTg==}
hasBin: true
form-data-encoder@1.7.2:
resolution: {integrity: sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==}
@ -172,6 +180,9 @@ packages:
encoding:
optional: true
strnum@1.0.5:
resolution: {integrity: sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==}
tr46@0.0.3:
resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
@ -191,9 +202,6 @@ packages:
resolution: {integrity: sha512-U8uCCl2x9TK3WANvmBavymRzxbfFYG+tAu+fgx3zxQy3qdagQqBLwJVrdyO1TBfUXvfKveMKJZhpvUYoOjM+4g==}
engines: {node: '>=18.17'}
uwuifier@4.2.2:
resolution: {integrity: sha512-Fhtj3Yg3rrDTEs+L1fqkgM3VYGJrP4U9GY+4fPdw08T5kzOB8NSosZnZfa5Zhv1Hh7NCpH5G6t1DIZyM1wPK1w==}
web-streams-polyfill@4.0.0-beta.3:
resolution: {integrity: sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==}
engines: {node: '>= 14'}
@ -303,6 +311,11 @@ snapshots:
asynckit@0.4.0: {}
booru@2.6.8:
dependencies:
fast-xml-parser: 4.5.0
undici: 6.19.8
combined-stream@1.0.8:
dependencies:
delayed-stream: 1.0.0
@ -339,6 +352,10 @@ snapshots:
fast-deep-equal@3.1.3: {}
fast-xml-parser@4.5.0:
dependencies:
strnum: 1.0.5
form-data-encoder@1.7.2: {}
form-data@4.0.0:
@ -388,6 +405,8 @@ snapshots:
dependencies:
whatwg-url: 5.0.0
strnum@1.0.5: {}
tr46@0.0.3: {}
ts-mixer@6.0.4: {}
@ -400,8 +419,6 @@ snapshots:
undici@6.19.8: {}
uwuifier@4.2.2: {}
web-streams-polyfill@4.0.0-beta.3: {}
webidl-conversions@3.0.1: {}

View file

@ -1,7 +1,7 @@
const { ContextMenuCommandBuilder, ApplicationCommandType, InteractionContextType, ApplicationIntegrationType, AttachmentBuilder, EmbedBuilder } = require('discord.js');
const { ContextMenuCommandBuilder, ApplicationCommandType, InteractionContextType, ApplicationIntegrationType, AttachmentBuilder, EmbedBuilder } = require("discord.js");
const data = new ContextMenuCommandBuilder()
.setName('Describe Image(s)')
.setName("Describe Image(s)")
.setType(ApplicationCommandType.Message)
.setContexts([
InteractionContextType.Guild,

View file

@ -1,7 +1,7 @@
const { ContextMenuCommandBuilder, ApplicationCommandType, InteractionContextType, ApplicationIntegrationType } = require('discord.js');
const { ContextMenuCommandBuilder, ApplicationCommandType, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const data = new ContextMenuCommandBuilder()
.setName('Summarize')
.setName("Summarize")
.setType(ApplicationCommandType.Message)
.setContexts([
InteractionContextType.Guild,

View file

@ -1,7 +1,7 @@
const { InteractionContextType, ApplicationIntegrationType, SlashCommandBuilder, EmbedBuilder } = require('discord.js');
const { InteractionContextType, ApplicationIntegrationType, SlashCommandBuilder, EmbedBuilder } = require("discord.js");
const data = new SlashCommandBuilder()
.setName('prompt')
.setName("prompt")
.setDescription("Prompt an AI model with data")
.addStringOption(builder =>
builder //

View file

@ -1,7 +1,7 @@
const { ContextMenuCommandBuilder, ApplicationCommandType, InteractionContextType, ApplicationIntegrationType } = require('discord.js');
const { ContextMenuCommandBuilder, ApplicationCommandType, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const data = new ContextMenuCommandBuilder()
.setName('Query AI')
.setName("Query AI")
.setType(ApplicationCommandType.Message)
.setContexts([
InteractionContextType.Guild,

View file

@ -0,0 +1,175 @@
const { InteractionContextType, ApplicationIntegrationType, SlashCommandBuilder, EmbedBuilder, escapeMarkdown, bold } = require("discord.js");
const { basename, extname } = require("node:path");
const Booru = require('booru');
const boorus = [];
for (const site of Object.keys(Booru.sites)) {
boorus.push({
name: site,
value: site
})
}
const defaultBooru = "gelbooru.com";
const data = new SlashCommandBuilder()
.setName("booru")
.setDescription("Select a random image from any booru")
.addStringOption(builder =>
builder //
.setName("tags")
.setRequired(true)
.setDescription("Tags to search for")
)
.addStringOption(builder =>
builder //
.setName("booru")
.setRequired(false)
.setDescription("Booru board to search (default: gelbooru)")
.addChoices(boorus)
)
.setContexts([
InteractionContextType.Guild,
InteractionContextType.BotDM,
InteractionContextType.PrivateChannel
])
.setIntegrationTypes([
ApplicationIntegrationType.GuildInstall,
ApplicationIntegrationType.UserInstall
]);
function isEmbeddableFileType(ext) {
return ['.jpg', '.jpeg', '.png', '.gif'].includes(ext)
}
function notEmpty(str) {
return str.trim() !== ''
}
const regexCutTags = /[\S\s]{1,75}[^,]{0,25}/;
function formatTags(tags) {
const tagString = tags.join(', ')
if (tagString.length < 100) {
return tagString
}
const tagCutMatch = tagString.match(regexCutTags) ?? []
return `${escapeMarkdown(tagCutMatch[0] ?? '')}...`
}
const ratingEmojis = {
s: '<:rating_safe:1293819920978804829>',
g: '<:rating_general:1293819929199513610>',
q: '<:rating_questionable:1293819907099725925>',
e: '<:rating_explicit:1293819893795389491>',
u: '<:rating_unknown:1293819936845594665>',
}
function formatRating(rating) {
return ratingEmojis[rating] ?? rating.toUpperCase()
}
function formatScore(score) {
if (score > 0) {
return `<:green_arrow_up:1293819944399667222> ${score}`
} else if (score < 0) {
return `<:red_arrow_down:1293819951764869181> ${score}`
} else {
return `<:yellow_tilde:1293819958643396608> ${score}`
}
}
function isNSFWPost(post) {
return !['s', 'g'].includes(post.rating)
}
function formatTime(time) {
return `${(Number(time) / 1e6).toFixed(2)}ms`
}
module.exports = {
data,
async execute(interaction) {
const tags = interaction.options.getString("tags").split(" ");
const booru = interaction.options.getString("booru") ?? defaultBooru;
await interaction.deferReply();
console.log(booru, tags);
const startTime = process.hrtime.bigint();
var post = null;
while (post == null) {
var newPost = (await Booru.search(booru, tags, { limit: 1, random: true }))[0];
if (newPost == null) {
await interaction.followUp("Could not find any post matching tags.");
return;
}
if (isNSFWPost(newPost)) continue;
post = newPost;
}
const endTime = process.hrtime.bigint();
const timeTaken = endTime - startTime;
const ext = extname((post['data']).file_name ?? post.fileUrl ?? '').toLowerCase();
const leadingDescription = [
`**Score:** ${formatScore(post.score)}`,
`**Rating:** ${formatRating(post.rating)}`,
`[File URL](${post.fileUrl})`,
`\`${ext}\``,
].join(' | ')
const description = [leadingDescription, `**Tags:** ${formatTags(post.tags)}`]
.filter(notEmpty)
.join('\n')
const footerText = [
post.booru.domain,
post.id,
timeTaken ? formatTime(timeTaken) : '',
].filter(notEmpty).join(' · ')
if (isEmbeddableFileType(ext)) {
const embed = new EmbedBuilder()
.setColor("#cba6f7")
.setTitle(`Post #${post.id}`)
.setURL(post.postView)
//.setDescription(description)
.setFields([{
name: "Score",
value: formatScore(post.score),
inline: true
}, {
name: "Rating",
value: formatRating(post.rating),
inline: true
}, {
name: "File",
value: `[${basename(post.fileUrl)}](${post.fileUrl})`,
inline: true
}, {
name: "Tags",
value: formatTags(post.tags),
inline: false
}])
.setImage(post.fileUrl)
.setFooter({
text: footerText,
iconURL: `https://${post.booru.domain}/favicon.ico`,
})
await interaction.followUp({ embeds: [embed] });
} else {
await interaction.followUp(
'>>> ' + bold(`[Post #${post.id}](<${post.postView}>)`) + "\n" +
description + "\n" +
footerText
);
}
},
};

View file

@ -1,7 +1,7 @@
const { ContextMenuCommandBuilder, ApplicationCommandType, InteractionContextType, ApplicationIntegrationType, AttachmentBuilder } = require('discord.js');
const { ContextMenuCommandBuilder, ApplicationCommandType, InteractionContextType, ApplicationIntegrationType, AttachmentBuilder } = require("discord.js");
const data = new ContextMenuCommandBuilder()
.setName('Message Information')
.setName("Message Information")
.setType(ApplicationCommandType.Message)
.setContexts([
InteractionContextType.Guild,

View file

@ -1,7 +1,7 @@
const { ContextMenuCommandBuilder, ApplicationCommandType, InteractionContextType, ApplicationIntegrationType } = require('discord.js');
const { ContextMenuCommandBuilder, ApplicationCommandType, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
const data = new ContextMenuCommandBuilder()
.setName('User Information')
.setName("User Information")
.setType(ApplicationCommandType.User)
.setContexts([
InteractionContextType.Guild,