So far so good!
This commit is contained in:
parent
dc167b4292
commit
b861029b4d
33 changed files with 228 additions and 969 deletions
BIN
.DS_Store
vendored
Normal file
BIN
.DS_Store
vendored
Normal file
Binary file not shown.
|
@ -1,31 +0,0 @@
|
|||
# Ignore a blackhole and the folder for development
|
||||
node_modules/
|
||||
.vs/
|
||||
.idea/
|
||||
*.iml
|
||||
|
||||
# Yarn files
|
||||
.yarn/install-state.gz
|
||||
.yarn/build-state.yml
|
||||
|
||||
# Environment variables
|
||||
.DS_Store
|
||||
|
||||
dist/
|
||||
|
||||
# Ignore the config file (contains sensitive information such as tokens)
|
||||
config.ts
|
||||
|
||||
# Ignore heapsnapshot and log files
|
||||
*.heapsnapshot
|
||||
*.log
|
||||
|
||||
# Ignore npm lockfiles file
|
||||
package-lock.json
|
||||
|
||||
# Environment variables
|
||||
.env
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
15
.github/workflows/fly.yml
vendored
15
.github/workflows/fly.yml
vendored
|
@ -1,15 +0,0 @@
|
|||
name: Fly Deploy
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
jobs:
|
||||
deploy:
|
||||
name: Deploy app
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: superfly/flyctl-actions/setup-flyctl@master
|
||||
- run: flyctl deploy --remote-only
|
||||
env:
|
||||
FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}
|
32
.gitignore
vendored
32
.gitignore
vendored
|
@ -1,31 +1 @@
|
|||
# Ignore a blackhole and the folder for development
|
||||
node_modules/
|
||||
.vs/
|
||||
.idea/
|
||||
*.iml
|
||||
|
||||
# Yarn files
|
||||
.yarn/install-state.gz
|
||||
.yarn/build-state.yml
|
||||
|
||||
# Environment variables
|
||||
.DS_Store
|
||||
|
||||
dist/
|
||||
|
||||
# Ignore the config file (contains sensitive information such as tokens)
|
||||
config.ts
|
||||
|
||||
# Ignore heapsnapshot and log files
|
||||
*.heapsnapshot
|
||||
*.log
|
||||
|
||||
# Ignore npm lockfiles file
|
||||
package-lock.json
|
||||
|
||||
# Environment variables
|
||||
.env
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
.env
|
4
.npmrc
4
.npmrc
|
@ -1,4 +0,0 @@
|
|||
# pnpm only
|
||||
shamefully-hoist=true
|
||||
auto-install-peers=true
|
||||
public-hoist-pattern[]=@sapphire/*
|
|
@ -1,4 +0,0 @@
|
|||
dist/
|
||||
node_modules/
|
||||
.yarn/
|
||||
examples/*/dist/
|
|
@ -1,16 +0,0 @@
|
|||
{
|
||||
"projectLanguage": "ts",
|
||||
"locations": {
|
||||
"base": "src",
|
||||
"arguments": "arguments",
|
||||
"commands": "commands",
|
||||
"listeners": "listeners",
|
||||
"preconditions": "preconditions",
|
||||
"interaction-handlers": "interaction-handlers",
|
||||
"routes": "routes"
|
||||
},
|
||||
"customFileTemplates": {
|
||||
"enabled": false,
|
||||
"location": ""
|
||||
}
|
||||
}
|
37
Dockerfile
37
Dockerfile
|
@ -1,37 +0,0 @@
|
|||
# syntax = docker/dockerfile:1
|
||||
|
||||
# Adjust NODE_VERSION as desired
|
||||
ARG BUN_VERSION=1.0.20
|
||||
FROM oven/bun:${BUN_VERSION} as base
|
||||
|
||||
LABEL fly_launch_runtime="Bun"
|
||||
|
||||
# Node.js app lives here
|
||||
WORKDIR /app
|
||||
|
||||
# Set production environment
|
||||
ENV NODE_ENV="production"
|
||||
|
||||
# Throw-away build stage to reduce size of final image
|
||||
FROM base as build
|
||||
|
||||
# Install packages needed to build node modules
|
||||
RUN apt-get update -qq && \
|
||||
apt-get install -y build-essential pkg-config python-is-python3
|
||||
|
||||
# Install node modules
|
||||
COPY --link .npmrc package.json bun.lockb ./
|
||||
RUN bun install --ci
|
||||
|
||||
# Copy application code
|
||||
COPY --link . .
|
||||
|
||||
# Final stage for app image
|
||||
FROM base
|
||||
|
||||
# Copy built application
|
||||
COPY --from=build /app /app
|
||||
|
||||
# Start the server by default, this can be overwritten at runtime
|
||||
EXPOSE 3000
|
||||
CMD [ "bun", "start" ]
|
BIN
bun.lockb
BIN
bun.lockb
Binary file not shown.
13
go.mod
Normal file
13
go.mod
Normal file
|
@ -0,0 +1,13 @@
|
|||
module himbot
|
||||
|
||||
go 1.21.5
|
||||
|
||||
require github.com/diamondburned/arikawa/v3 v3.3.4
|
||||
|
||||
require (
|
||||
github.com/gorilla/schema v1.2.0 // indirect
|
||||
github.com/gorilla/websocket v1.4.2 // indirect
|
||||
github.com/joho/godotenv v1.5.1
|
||||
github.com/sashabaranov/go-openai v1.17.9
|
||||
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
|
||||
)
|
40
go.sum
Normal file
40
go.sum
Normal file
|
@ -0,0 +1,40 @@
|
|||
github.com/diamondburned/arikawa/v3 v3.3.4 h1:UXOjM7PRlWLJ8kVAydX/VetqV7W4/d4xU92JRy3SpU4=
|
||||
github.com/diamondburned/arikawa/v3 v3.3.4/go.mod h1:5KMSeB9R2Kzi6K4EcqMz7mwAFpAi5jglX/Veq0+MPOo=
|
||||
github.com/gorilla/schema v1.2.0 h1:YufUaxZYCKGFuAq3c96BOhjgd5nmXiOY9NGzF247Tsc=
|
||||
github.com/gorilla/schema v1.2.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU=
|
||||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||
github.com/sashabaranov/go-openai v1.17.9 h1:QEoBiGKWW68W79YIfXWEFZ7l5cEgZBV4/Ow3uy+5hNY=
|
||||
github.com/sashabaranov/go-openai v1.17.9/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs=
|
||||
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
174
main.go
Normal file
174
main.go
Normal file
|
@ -0,0 +1,174 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"math/rand"
|
||||
"os"
|
||||
"os/signal"
|
||||
"time"
|
||||
|
||||
"github.com/diamondburned/arikawa/v3/api"
|
||||
"github.com/diamondburned/arikawa/v3/api/cmdroute"
|
||||
"github.com/diamondburned/arikawa/v3/discord"
|
||||
"github.com/diamondburned/arikawa/v3/gateway"
|
||||
"github.com/diamondburned/arikawa/v3/state"
|
||||
"github.com/diamondburned/arikawa/v3/utils/json/option"
|
||||
"github.com/joho/godotenv"
|
||||
openai "github.com/sashabaranov/go-openai"
|
||||
)
|
||||
|
||||
var commands = []api.CreateCommandData{
|
||||
{
|
||||
Name: "ping",
|
||||
Description: "ping pong!",
|
||||
},
|
||||
{
|
||||
Name: "echo",
|
||||
Description: "echo back the argument",
|
||||
Options: []discord.CommandOption{
|
||||
&discord.StringOption{
|
||||
OptionName: "argument",
|
||||
Description: "what's echoed back",
|
||||
Required: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "thonk",
|
||||
Description: "biiiig thonk",
|
||||
},
|
||||
{
|
||||
Name: "ask",
|
||||
Description: "Ask Himbot!",
|
||||
Options: []discord.CommandOption{
|
||||
&discord.StringOption{
|
||||
OptionName: "argument",
|
||||
Description: "the prompt",
|
||||
Required: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func main() {
|
||||
godotenv.Load(".env")
|
||||
|
||||
token := os.Getenv("DISCORD_TOKEN")
|
||||
if token == "" {
|
||||
log.Fatalln("No $DISCORD_TOKEN given.")
|
||||
}
|
||||
|
||||
h := newHandler(state.New("Bot " + token))
|
||||
h.s.AddInteractionHandler(h)
|
||||
h.s.AddIntents(gateway.IntentGuilds)
|
||||
h.s.AddHandler(func(*gateway.ReadyEvent) {
|
||||
me, _ := h.s.Me()
|
||||
log.Println("connected to the gateway as", me.Tag())
|
||||
})
|
||||
|
||||
if err := cmdroute.OverwriteCommands(h.s, commands); err != nil {
|
||||
log.Fatalln("cannot update commands:", err)
|
||||
}
|
||||
|
||||
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
|
||||
defer cancel()
|
||||
|
||||
if err := h.s.Connect(ctx); err != nil {
|
||||
log.Fatalln("cannot connect:", err)
|
||||
}
|
||||
}
|
||||
|
||||
type handler struct {
|
||||
*cmdroute.Router
|
||||
s *state.State
|
||||
}
|
||||
|
||||
func newHandler(s *state.State) *handler {
|
||||
h := &handler{s: s}
|
||||
|
||||
h.Router = cmdroute.NewRouter()
|
||||
// Automatically defer handles if they're slow.
|
||||
h.Use(cmdroute.Deferrable(s, cmdroute.DeferOpts{}))
|
||||
h.AddFunc("ping", h.cmdPing)
|
||||
h.AddFunc("echo", h.cmdEcho)
|
||||
h.AddFunc("thonk", h.cmdThonk)
|
||||
h.AddFunc("ask", h.cmdAsk)
|
||||
|
||||
return h
|
||||
}
|
||||
|
||||
func (h *handler) cmdPing(ctx context.Context, cmd cmdroute.CommandData) *api.InteractionResponseData {
|
||||
return &api.InteractionResponseData{
|
||||
Content: option.NewNullableString("Pong!"),
|
||||
}
|
||||
}
|
||||
|
||||
func (h *handler) cmdEcho(ctx context.Context, data cmdroute.CommandData) *api.InteractionResponseData {
|
||||
var options struct {
|
||||
Arg string `discord:"argument"`
|
||||
}
|
||||
|
||||
if err := data.Options.Unmarshal(&options); err != nil {
|
||||
return errorResponse(err)
|
||||
}
|
||||
|
||||
return &api.InteractionResponseData{
|
||||
Content: option.NewNullableString(options.Arg),
|
||||
AllowedMentions: &api.AllowedMentions{}, // don't mention anyone
|
||||
}
|
||||
}
|
||||
|
||||
func (h *handler) cmdAsk(ctx context.Context, data cmdroute.CommandData) *api.InteractionResponseData {
|
||||
var options struct {
|
||||
Arg string `discord:"argument"`
|
||||
}
|
||||
|
||||
if err := data.Options.Unmarshal(&options); err != nil {
|
||||
return errorResponse(err)
|
||||
}
|
||||
|
||||
client := openai.NewClient(os.Getenv("OPENAI_API_KEY"))
|
||||
|
||||
resp, err := client.CreateChatCompletion(
|
||||
context.Background(),
|
||||
openai.ChatCompletionRequest{
|
||||
Model: openai.GPT4TurboPreview,
|
||||
Messages: []openai.ChatCompletionMessage{
|
||||
{
|
||||
Role: openai.ChatMessageRoleUser,
|
||||
Content: options.Arg,
|
||||
},
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
fmt.Printf("ChatCompletion error: %v\n", err)
|
||||
return &api.InteractionResponseData{
|
||||
Content: option.NewNullableString("ChatCompletion Error!"),
|
||||
AllowedMentions: &api.AllowedMentions{}, // don't mention anyone
|
||||
}
|
||||
}
|
||||
|
||||
return &api.InteractionResponseData{
|
||||
Content: option.NewNullableString(resp.Choices[0].Message.Content),
|
||||
AllowedMentions: &api.AllowedMentions{}, // don't mention anyone
|
||||
}
|
||||
}
|
||||
|
||||
func (h *handler) cmdThonk(ctx context.Context, data cmdroute.CommandData) *api.InteractionResponseData {
|
||||
time.Sleep(time.Duration(3+rand.Intn(5)) * time.Second)
|
||||
return &api.InteractionResponseData{
|
||||
Content: option.NewNullableString("https://tenor.com/view/thonk-thinking-sun-thonk-sun-thinking-sun-gif-14999983"),
|
||||
}
|
||||
}
|
||||
|
||||
func errorResponse(err error) *api.InteractionResponseData {
|
||||
return &api.InteractionResponseData{
|
||||
Content: option.NewNullableString("**Error:** " + err.Error()),
|
||||
Flags: discord.EphemeralMessage,
|
||||
AllowedMentions: &api.AllowedMentions{ /* none */ },
|
||||
}
|
||||
}
|
44
package.json
44
package.json
|
@ -1,44 +0,0 @@
|
|||
{
|
||||
"name": "himbot",
|
||||
"version": "4.2.0",
|
||||
"engines": {
|
||||
"node": ">=18.12.1"
|
||||
},
|
||||
"main": "dist/index.js",
|
||||
"author": "@sapphire",
|
||||
"license": "UNLICENSE",
|
||||
"type": "commonjs",
|
||||
"dependencies": {
|
||||
"@sapphire/decorators": "^6.0.3",
|
||||
"@sapphire/discord.js-utilities": "7.1.4",
|
||||
"@sapphire/framework": "^5.0.4",
|
||||
"@sapphire/plugin-logger": "^4.0.1",
|
||||
"@sapphire/utilities": "^3.14.0",
|
||||
"@skyra/env-utilities": "^1.2.2",
|
||||
"colorette": "^2.0.20",
|
||||
"discord.js": "^14.14.1",
|
||||
"openai": "^4.20.1",
|
||||
"replicate": "^0.25.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@flydotio/dockerfile": "0.5.0",
|
||||
"@sapphire/cli": "^1.9.1",
|
||||
"@sapphire/prettier-config": "^2.0.0",
|
||||
"@sapphire/ts-config": "^5.0.0",
|
||||
"@types/node": "^20.10.4",
|
||||
"@types/ws": "^8.5.10",
|
||||
"prettier": "^3.1.1",
|
||||
"tsc-watch": "^6.0.4",
|
||||
"typescript": "^5.3.3"
|
||||
},
|
||||
"scripts": {
|
||||
"sapphire": "sapphire",
|
||||
"generate": "sapphire generate",
|
||||
"watch": "tsc -w",
|
||||
"start": "bun run src/index.ts",
|
||||
"dev": "bun run src/index.ts",
|
||||
"watch:start": "tsc-watch --onSuccess \"npm run start\"",
|
||||
"format": "prettier --write \"src/\""
|
||||
},
|
||||
"prettier": "@sapphire/prettier-config"
|
||||
}
|
|
@ -1,70 +0,0 @@
|
|||
import { Command, container } from '@sapphire/framework';
|
||||
import { AttachmentBuilder, blockQuote, codeBlock } from 'discord.js';
|
||||
import OpenAI from 'openai';
|
||||
|
||||
const openai = new OpenAI({
|
||||
apiKey: process.env.OPENAI_API_KEY
|
||||
});
|
||||
|
||||
export class AskCommand extends Command {
|
||||
public constructor(context: Command.LoaderContext) {
|
||||
super(context, {
|
||||
description: 'You can ACTUALLY ask Himbot something! So cool!',
|
||||
options: ['prompt']
|
||||
});
|
||||
}
|
||||
|
||||
public override registerApplicationCommands(registry: Command.Registry) {
|
||||
registry.registerChatInputCommand((builder) =>
|
||||
builder
|
||||
.setName(this.name)
|
||||
.setDescription(this.description)
|
||||
.addStringOption((option) =>
|
||||
option.setName('prompt').setDescription('You can ACTUALLY ask Himbot something! So cool!').setRequired(true)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public async chatInputRun(interaction: Command.ChatInputCommandInteraction) {
|
||||
const prompt = interaction.options.getString('prompt');
|
||||
|
||||
await interaction.reply({ content: '🤔 Thinking... 🤔', fetchReply: true });
|
||||
|
||||
const chatCompletion = await openai.chat.completions.create({
|
||||
model: 'gpt-4-1106-preview',
|
||||
messages: [
|
||||
{
|
||||
role: 'user',
|
||||
content: prompt
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
const content = blockQuote(`> ${prompt}\n${codeBlock(`${chatCompletion.choices[0].message?.content}`)}`);
|
||||
|
||||
const messageAttachment: AttachmentBuilder[] = [];
|
||||
|
||||
if (content.length > 2000) {
|
||||
messageAttachment.push(
|
||||
new AttachmentBuilder(Buffer.from(`> ${prompt}\n${`${chatCompletion.choices[0].message?.content}`}`, 'utf-8'), {
|
||||
name: 'response.txt',
|
||||
description: "Himbot's Response"
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
return interaction.editReply({
|
||||
content:
|
||||
content.length < 2000
|
||||
? content
|
||||
: `Discord only allows messages with 2000 characters or less. Please see your response in the attached file!`,
|
||||
files: messageAttachment
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void container.stores.loadPiece({
|
||||
store: 'commands',
|
||||
name: 'ask',
|
||||
piece: AskCommand
|
||||
});
|
|
@ -1,35 +0,0 @@
|
|||
import { Command, container } from '@sapphire/framework';
|
||||
|
||||
export class BorfCommand extends Command {
|
||||
public constructor(context: Command.LoaderContext) {
|
||||
super(context, {
|
||||
description: 'Borf! Borf!'
|
||||
});
|
||||
}
|
||||
|
||||
// Register Chat Input and Context Menu command
|
||||
public override registerApplicationCommands(registry: Command.Registry) {
|
||||
// Register Chat Input command
|
||||
registry.registerChatInputCommand({
|
||||
name: this.name,
|
||||
description: this.description
|
||||
});
|
||||
}
|
||||
|
||||
// Chat Input (slash) command
|
||||
public async chatInputRun(interaction: Command.ChatInputCommandInteraction) {
|
||||
const dogResponse = await fetch('https://dog.ceo/api/breeds/image/random');
|
||||
const dogData = (await dogResponse.json()) as { message: string; status: string };
|
||||
|
||||
await interaction.reply({
|
||||
content: dogData.status === 'success' ? dogData.message : 'Error: I had troubles fetching perfect puppies for you... :(',
|
||||
fetchReply: true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void container.stores.loadPiece({
|
||||
store: 'commands',
|
||||
name: 'borf',
|
||||
piece: BorfCommand
|
||||
});
|
|
@ -1,79 +0,0 @@
|
|||
import { BucketScope, Command, container } from '@sapphire/framework';
|
||||
import { AttachmentBuilder } from 'discord.js';
|
||||
import OpenAI from 'openai';
|
||||
|
||||
const openai = new OpenAI({
|
||||
apiKey: process.env.OPENAI_API_KEY
|
||||
});
|
||||
|
||||
export class HDPicCommand extends Command {
|
||||
public constructor(context: Command.LoaderContext) {
|
||||
super(context, {
|
||||
description: 'Generate an image using OpenAI! Cooldown of 10 Minutes due to cost!',
|
||||
options: ['prompt'],
|
||||
cooldownDelay: 480_000,
|
||||
cooldownLimit: 1,
|
||||
cooldownFilteredUsers: ['83679718401904640'],
|
||||
cooldownScope: BucketScope.User
|
||||
});
|
||||
}
|
||||
|
||||
// Register Chat Input and Context Menu command
|
||||
public override registerApplicationCommands(registry: Command.Registry) {
|
||||
registry.registerChatInputCommand((builder) =>
|
||||
builder
|
||||
.setName(this.name)
|
||||
.setDescription(this.description)
|
||||
.addStringOption((option) =>
|
||||
option.setName('prompt').setDescription('The prompt you will use to generate an image!').setRequired(true)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Chat Input (slash) command
|
||||
public async chatInputRun(interaction: Command.ChatInputCommandInteraction) {
|
||||
const prompt = interaction.options.getString('prompt') || '';
|
||||
|
||||
await interaction.reply({ content: '🤔 Thinking... 🤔', fetchReply: true });
|
||||
|
||||
try {
|
||||
const response = await openai.images.generate({
|
||||
model: 'dall-e-3',
|
||||
prompt,
|
||||
n: 1,
|
||||
size: '1024x1024',
|
||||
quality: 'standard'
|
||||
});
|
||||
|
||||
const imageUrl = response.data[0].url || '';
|
||||
// get an array buffer
|
||||
const imageBuffer = await fetch(imageUrl).then((r) => r.arrayBuffer());
|
||||
|
||||
const imageAttachment: AttachmentBuilder[] = [];
|
||||
|
||||
imageAttachment.push(
|
||||
new AttachmentBuilder(Buffer.from(new Uint8Array(imageBuffer)), {
|
||||
name: 'himbot_response.jpg',
|
||||
description: `An image generated by Himbot using the prompt: ${prompt}`
|
||||
})
|
||||
);
|
||||
|
||||
const content = `Prompt: ${prompt}:`;
|
||||
|
||||
return interaction.editReply({
|
||||
content,
|
||||
files: imageAttachment
|
||||
});
|
||||
} catch (error) {
|
||||
const content = "Sorry, I can't complete the prompt for: " + prompt + '\n' + error;
|
||||
|
||||
return interaction.editReply({ content });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void container.stores.loadPiece({
|
||||
store: 'commands',
|
||||
name: 'hdpic',
|
||||
piece: HDPicCommand
|
||||
});
|
|
@ -1,87 +0,0 @@
|
|||
import { BucketScope, Command, container } from '@sapphire/framework';
|
||||
import { AttachmentBuilder, MessageFlags } from 'discord.js';
|
||||
import OpenAI from 'openai';
|
||||
|
||||
const openai = new OpenAI({
|
||||
apiKey: process.env.OPENAI_API_KEY
|
||||
});
|
||||
|
||||
export class HDTTSCommand extends Command {
|
||||
public constructor(context: Command.LoaderContext) {
|
||||
super(context, {
|
||||
description: 'Generate "HD" TTS every 2 minutes!',
|
||||
options: ['prompt'],
|
||||
cooldownDelay: 200_000,
|
||||
cooldownLimit: 1,
|
||||
// Yes... I did hardcode myself.
|
||||
cooldownFilteredUsers: ['83679718401904640'],
|
||||
cooldownScope: BucketScope.User
|
||||
});
|
||||
}
|
||||
|
||||
// Register Chat Input and Context Menu command
|
||||
public override registerApplicationCommands(registry: Command.Registry) {
|
||||
registry.registerChatInputCommand((builder) =>
|
||||
builder
|
||||
.setName(this.name)
|
||||
.setDescription(this.description)
|
||||
.addStringOption((option) => option.setName('prompt').setDescription('The prompt you will use to generate audio!').setRequired(true))
|
||||
);
|
||||
}
|
||||
|
||||
// Chat Input (slash) command
|
||||
public async chatInputRun(interaction: Command.ChatInputCommandInteraction) {
|
||||
const prompt = interaction.options.getString('prompt') || 'NOTHING';
|
||||
|
||||
await interaction.reply({ content: '🤔 Thinking... 🤔', fetchReply: true });
|
||||
try {
|
||||
enum voice {
|
||||
alloy = 'alloy',
|
||||
echo = 'echo',
|
||||
fable = 'fable',
|
||||
onyx = 'onyx',
|
||||
nova = 'nova',
|
||||
shimmer = 'shimmer'
|
||||
}
|
||||
|
||||
const voices = [voice.alloy, voice.echo, voice.fable, voice.onyx, voice.nova, voice.shimmer];
|
||||
const mp3 = await openai.audio.speech.create({
|
||||
model: 'tts-1-hd',
|
||||
voice: voices[Math.floor(Math.random() * voices.length)],
|
||||
input: prompt
|
||||
});
|
||||
const mp3Buffer = Buffer.from(await mp3.arrayBuffer());
|
||||
|
||||
const mp3Attachment: AttachmentBuilder[] = [];
|
||||
|
||||
mp3Attachment.push(
|
||||
new AttachmentBuilder(Buffer.from(new Uint8Array(mp3Buffer)), {
|
||||
name: 'himbot_response.mp3',
|
||||
description: `An TTS message generated by Himbot using the prompt: ${prompt}`
|
||||
})
|
||||
);
|
||||
|
||||
const content = `Prompt: ${prompt}:`;
|
||||
|
||||
return interaction.editReply({
|
||||
content,
|
||||
files: mp3Attachment,
|
||||
options: {
|
||||
flags: MessageFlags.IsVoiceMessage.valueOf()
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
const content = "Sorry, I can't complete the prompt for: " + prompt + '\n' + error;
|
||||
|
||||
return interaction.editReply({
|
||||
content
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void container.stores.loadPiece({
|
||||
store: 'commands',
|
||||
name: 'hdtts',
|
||||
piece: HDTTSCommand
|
||||
});
|
|
@ -1,35 +0,0 @@
|
|||
import { Command, container } from '@sapphire/framework';
|
||||
|
||||
export class HighSchoolCommand extends Command {
|
||||
public constructor(context: Command.LoaderContext) {
|
||||
super(context, {
|
||||
description: 'This command was your nickname in highschool!',
|
||||
options: ['nickname']
|
||||
});
|
||||
}
|
||||
|
||||
// Register Chat Input and Context Menu command
|
||||
public override registerApplicationCommands(registry: Command.Registry) {
|
||||
registry.registerChatInputCommand((builder) =>
|
||||
builder //
|
||||
.setName(this.name)
|
||||
.setDescription(this.description)
|
||||
.addStringOption((option) => option.setName('nickname').setDescription('Your nickname in highschool.').setRequired(true))
|
||||
);
|
||||
}
|
||||
|
||||
// Chat Input (slash) command
|
||||
public async chatInputRun(interaction: Command.ChatInputCommandInteraction) {
|
||||
const nickname = interaction.options.getString('nickname') || 'NOTHING';
|
||||
await interaction.reply({
|
||||
content: `${nickname} was ${interaction.user.username}'s nickname in highschool!`,
|
||||
fetchReply: true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void container.stores.loadPiece({
|
||||
store: 'commands',
|
||||
name: 'hs',
|
||||
piece: HighSchoolCommand
|
||||
});
|
|
@ -1,92 +0,0 @@
|
|||
import { BucketScope, Command, container } from '@sapphire/framework';
|
||||
import { AttachmentBuilder } from 'discord.js';
|
||||
import Replicate from 'replicate';
|
||||
|
||||
const replicate = new Replicate({
|
||||
auth: process.env.REPLICATE_API_TOKEN
|
||||
});
|
||||
|
||||
export class PicCommand extends Command {
|
||||
public constructor(context: Command.LoaderContext) {
|
||||
super(context, {
|
||||
description: 'Generate an image using Stability AI! Cooldown 1 Minute to prevent spam!',
|
||||
options: ['prompt'],
|
||||
cooldownDelay: 100_000,
|
||||
cooldownLimit: 1,
|
||||
// Yes... I did hardcode myself.
|
||||
cooldownFilteredUsers: ['83679718401904640'],
|
||||
cooldownScope: BucketScope.User
|
||||
});
|
||||
}
|
||||
|
||||
// Register Chat Input and Context Menu command
|
||||
public override registerApplicationCommands(registry: Command.Registry) {
|
||||
registry.registerChatInputCommand((builder) =>
|
||||
builder
|
||||
.setName(this.name)
|
||||
.setDescription(this.description)
|
||||
.addStringOption((option) =>
|
||||
option.setName('prompt').setDescription('The prompt you will use to generate an image!').setRequired(true)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Chat Input (slash) command
|
||||
public async chatInputRun(interaction: Command.ChatInputCommandInteraction) {
|
||||
const prompt = interaction.options.getString('prompt') || 'NOTHING';
|
||||
|
||||
await interaction.reply({ content: '🤔 Thinking... 🤔', fetchReply: true });
|
||||
|
||||
let result = (await replicate.run('stability-ai/sdxl:39ed52f2a78e934b3ba6e2a89f5b1c712de7dfea535525255b1aa35c5565e08b', {
|
||||
input: {
|
||||
width: 1024,
|
||||
height: 1024,
|
||||
prompt,
|
||||
negative_prompt:
|
||||
'out of frame, lowres, text, error, cropped, worst quality, low quality, jpeg artifacts, duplicate, morbid, mutilated, out of frame, extra fingers, mutated hands, poorly drawn hands, poorly drawn face, mutation, deformed, blurry, bad anatomy, bad proportions, extra limbs, cloned face, disfigured, malformed limbs, missing arms, missing legs, extra arms, extra legs, fused fingers, too many fingers, long neck, username, watermark, signature.',
|
||||
disable_safety_checker: true,
|
||||
refine: 'expert_ensemble_refiner',
|
||||
scheduler: 'KarrasDPM',
|
||||
num_outputs: 1,
|
||||
guidance_scale: 7.5,
|
||||
high_noise_frac: 0.8,
|
||||
prompt_strength: 0.8,
|
||||
num_inference_steps: 50
|
||||
}
|
||||
})) as string[];
|
||||
|
||||
if (result.length <= 0) {
|
||||
const content = `Sorry, I can't complete the prompt for: ${prompt}`;
|
||||
|
||||
return interaction.editReply({
|
||||
content: content
|
||||
});
|
||||
} else {
|
||||
const imageUrl = result[0] || '';
|
||||
// get an array buffer
|
||||
const imageBuffer = await fetch(imageUrl).then((r) => r.arrayBuffer());
|
||||
|
||||
const imageAttachment: AttachmentBuilder[] = [];
|
||||
|
||||
imageAttachment.push(
|
||||
new AttachmentBuilder(Buffer.from(new Uint8Array(imageBuffer)), {
|
||||
name: 'himbot_response.jpg',
|
||||
description: `An image generated by Himbot using the prompt: ${prompt}`
|
||||
})
|
||||
);
|
||||
|
||||
const content = `Prompt: ${prompt}`;
|
||||
|
||||
return interaction.editReply({
|
||||
content,
|
||||
files: imageAttachment
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void container.stores.loadPiece({
|
||||
store: 'commands',
|
||||
name: 'pic',
|
||||
piece: PicCommand
|
||||
});
|
|
@ -1,36 +0,0 @@
|
|||
import { Command, container } from '@sapphire/framework';
|
||||
|
||||
export class TitleCommand extends Command {
|
||||
public constructor(context: Command.LoaderContext) {
|
||||
super(context, {
|
||||
description: 'This command is the title of your sextape.',
|
||||
options: ['title']
|
||||
});
|
||||
}
|
||||
|
||||
// Register Chat Input and Context Menu command
|
||||
public override registerApplicationCommands(registry: Command.Registry) {
|
||||
registry.registerChatInputCommand((builder) =>
|
||||
builder //
|
||||
.setName(this.name)
|
||||
.setDescription(this.description)
|
||||
.addStringOption((option) => option.setName('title').setDescription('The title of your sextape.').setRequired(true))
|
||||
);
|
||||
}
|
||||
|
||||
// Chat Input (slash) command
|
||||
public async chatInputRun(interaction: Command.ChatInputCommandInteraction) {
|
||||
const title = interaction.options.getString('title') || 'NOTHING';
|
||||
|
||||
await interaction.reply({
|
||||
content: `${title}: Title of ${interaction.user.username}'s sex tape!`,
|
||||
fetchReply: true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void container.stores.loadPiece({
|
||||
store: 'commands',
|
||||
name: 'title',
|
||||
piece: TitleCommand
|
||||
});
|
|
@ -1,88 +0,0 @@
|
|||
import { BucketScope, Command, container } from '@sapphire/framework';
|
||||
import { AttachmentBuilder, MessageFlags } from 'discord.js';
|
||||
import OpenAI from 'openai';
|
||||
|
||||
const openai = new OpenAI({
|
||||
apiKey: process.env.OPENAI_API_KEY
|
||||
});
|
||||
|
||||
export class TTSCommand extends Command {
|
||||
public constructor(context: Command.LoaderContext) {
|
||||
super(context, {
|
||||
description: 'Generate TTS every minute!',
|
||||
options: ['prompt'],
|
||||
cooldownDelay: 100_000,
|
||||
cooldownLimit: 1,
|
||||
// Yes... I did hardcode myself.
|
||||
cooldownFilteredUsers: ['83679718401904640'],
|
||||
cooldownScope: BucketScope.User
|
||||
});
|
||||
}
|
||||
|
||||
// Register Chat Input and Context Menu command
|
||||
public override registerApplicationCommands(registry: Command.Registry) {
|
||||
registry.registerChatInputCommand((builder) =>
|
||||
builder
|
||||
.setName(this.name)
|
||||
.setDescription(this.description)
|
||||
.addStringOption((option) => option.setName('prompt').setDescription('The prompt you will use to generate audio!').setRequired(true))
|
||||
);
|
||||
}
|
||||
|
||||
// Chat Input (slash) command
|
||||
public async chatInputRun(interaction: Command.ChatInputCommandInteraction) {
|
||||
const prompt = interaction.options.getString('prompt') || 'NOTHING';
|
||||
|
||||
await interaction.reply({ content: '🤔 Thinking... 🤔', fetchReply: true });
|
||||
|
||||
try {
|
||||
enum voice {
|
||||
alloy = 'alloy',
|
||||
echo = 'echo',
|
||||
fable = 'fable',
|
||||
onyx = 'onyx',
|
||||
nova = 'nova',
|
||||
shimmer = 'shimmer'
|
||||
}
|
||||
|
||||
const voices = [voice.alloy, voice.echo, voice.fable, voice.onyx, voice.nova, voice.shimmer];
|
||||
const mp3 = await openai.audio.speech.create({
|
||||
model: 'tts-1',
|
||||
voice: voices[Math.floor(Math.random() * voices.length)],
|
||||
input: prompt
|
||||
});
|
||||
const mp3Buffer = Buffer.from(await mp3.arrayBuffer());
|
||||
|
||||
const mp3Attachment: AttachmentBuilder[] = [];
|
||||
|
||||
mp3Attachment.push(
|
||||
new AttachmentBuilder(Buffer.from(new Uint8Array(mp3Buffer)), {
|
||||
name: 'himbot_response.mp3',
|
||||
description: `An TTS message generated by Himbot using the prompt: ${prompt}`
|
||||
})
|
||||
);
|
||||
|
||||
const content = `Prompt: ${prompt}:`;
|
||||
|
||||
return interaction.editReply({
|
||||
content,
|
||||
files: mp3Attachment,
|
||||
options: {
|
||||
flags: MessageFlags.IsVoiceMessage.valueOf()
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
const content = "Sorry, I can't complete the prompt for: " + prompt + '\n' + error;
|
||||
|
||||
return interaction.editReply({
|
||||
content
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void container.stores.loadPiece({
|
||||
store: 'commands',
|
||||
name: 'tts',
|
||||
piece: TTSCommand
|
||||
});
|
55
src/index.ts
55
src/index.ts
|
@ -1,55 +0,0 @@
|
|||
import './lib/setup';
|
||||
import './listeners/ready';
|
||||
import './commands/ask';
|
||||
import './commands/borf';
|
||||
import './commands/hdpic';
|
||||
import './commands/hdtts';
|
||||
import './commands/hs';
|
||||
import './commands/pic';
|
||||
import './commands/title';
|
||||
import './commands/tts';
|
||||
import './listeners/commands/chatInputCommands/chatInputCommandSuccess';
|
||||
import { LogLevel, SapphireClient, BucketScope } from '@sapphire/framework';
|
||||
import { ActivityType, GatewayIntentBits } from 'discord.js';
|
||||
|
||||
const client = new SapphireClient({
|
||||
defaultPrefix: '!',
|
||||
presence: {
|
||||
status: 'online',
|
||||
activities: [
|
||||
{
|
||||
name: 'idk',
|
||||
type: ActivityType.Custom
|
||||
}
|
||||
]
|
||||
},
|
||||
caseInsensitiveCommands: true,
|
||||
logger: {
|
||||
level: LogLevel.Debug
|
||||
},
|
||||
intents: [GatewayIntentBits.DirectMessages, GatewayIntentBits.GuildMessages, GatewayIntentBits.Guilds, GatewayIntentBits.MessageContent],
|
||||
defaultCooldown: {
|
||||
// 10s
|
||||
delay: 10_000,
|
||||
filteredCommands: ['support', 'ping', 'wryna'],
|
||||
limit: 2,
|
||||
// Yes... I did hardcode myself.
|
||||
filteredUsers: ['83679718401904640'],
|
||||
scope: BucketScope.User
|
||||
},
|
||||
baseUserDirectory: null
|
||||
});
|
||||
|
||||
const main = async () => {
|
||||
try {
|
||||
client.logger.info('Logging in');
|
||||
await client.login();
|
||||
client.logger.info('logged in');
|
||||
} catch (error) {
|
||||
client.logger.fatal(error);
|
||||
client.destroy();
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
main();
|
|
@ -1,4 +0,0 @@
|
|||
import { join } from 'path';
|
||||
|
||||
export const rootDir = join(__dirname, '..', '..');
|
||||
export const srcDir = join(rootDir, 'src');
|
|
@ -1,18 +0,0 @@
|
|||
// Unless explicitly defined, set NODE_ENV as development:
|
||||
process.env.NODE_ENV ??= 'development';
|
||||
|
||||
import { ApplicationCommandRegistries, RegisterBehavior } from '@sapphire/framework';
|
||||
import '@sapphire/plugin-logger/register';
|
||||
import { setup } from '@skyra/env-utilities';
|
||||
import * as colorette from 'colorette';
|
||||
import { join } from 'node:path';
|
||||
import { srcDir } from './constants';
|
||||
|
||||
// Set default behavior to bulk overwrite
|
||||
ApplicationCommandRegistries.setDefaultBehaviorWhenNotIdentical(RegisterBehavior.BulkOverwrite);
|
||||
|
||||
// Read env var
|
||||
setup({ path: join(srcDir, '.env') });
|
||||
|
||||
// Enable colorette
|
||||
colorette.createColors({ useColor: true });
|
|
@ -1,37 +0,0 @@
|
|||
import { container, type ChatInputCommandSuccessPayload, type Command, type ContextMenuCommandSuccessPayload } from '@sapphire/framework';
|
||||
import { cyan } from 'colorette';
|
||||
import type { APIUser, Guild, User } from 'discord.js';
|
||||
|
||||
export function logSuccessCommand(payload: ContextMenuCommandSuccessPayload | ChatInputCommandSuccessPayload): void {
|
||||
let successLoggerData: ReturnType<typeof getSuccessLoggerData>;
|
||||
|
||||
successLoggerData = getSuccessLoggerData(payload.interaction.guild, payload.interaction.user, payload.command);
|
||||
|
||||
container.logger.debug(`${successLoggerData.shard} - ${successLoggerData.commandName} ${successLoggerData.author} ${successLoggerData.sentAt}`);
|
||||
}
|
||||
|
||||
export function getSuccessLoggerData(guild: Guild | null, user: User, command: Command) {
|
||||
const shard = getShardInfo(guild?.shardId ?? 0);
|
||||
const commandName = getCommandInfo(command);
|
||||
const author = getAuthorInfo(user);
|
||||
const sentAt = getGuildInfo(guild);
|
||||
|
||||
return { shard, commandName, author, sentAt };
|
||||
}
|
||||
|
||||
function getShardInfo(id: number) {
|
||||
return `[${cyan(id.toString())}]`;
|
||||
}
|
||||
|
||||
function getCommandInfo(command: Command) {
|
||||
return cyan(command.name);
|
||||
}
|
||||
|
||||
function getAuthorInfo(author: User | APIUser) {
|
||||
return `${author.username}[${cyan(author.id)}]`;
|
||||
}
|
||||
|
||||
function getGuildInfo(guild: Guild | null) {
|
||||
if (guild === null) return 'Direct Messages';
|
||||
return `${guild.name}[${cyan(guild.id)}]`;
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
import type { ChatInputCommandDeniedPayload, Events } from '@sapphire/framework';
|
||||
import { Listener, UserError } from '@sapphire/framework';
|
||||
|
||||
export class UserEvent extends Listener<typeof Events.ChatInputCommandDenied> {
|
||||
public async run({ context, message: content }: UserError, { interaction }: ChatInputCommandDeniedPayload) {
|
||||
// `context: { silent: true }` should make UserError silent:
|
||||
// Use cases for this are for example permissions error when running the `eval` command.
|
||||
if (Reflect.get(Object(context), 'silent')) return;
|
||||
|
||||
if (interaction.deferred || interaction.replied) {
|
||||
return interaction.editReply({
|
||||
content,
|
||||
allowedMentions: { users: [interaction.user.id], roles: [] }
|
||||
});
|
||||
}
|
||||
|
||||
return interaction.reply({
|
||||
content,
|
||||
allowedMentions: { users: [interaction.user.id], roles: [] },
|
||||
ephemeral: true
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
import { Listener, LogLevel, type ChatInputCommandSuccessPayload } from '@sapphire/framework';
|
||||
import type { Logger } from '@sapphire/plugin-logger';
|
||||
import { logSuccessCommand } from '../../../lib/utils';
|
||||
|
||||
export class UserListener extends Listener {
|
||||
public run(payload: ChatInputCommandSuccessPayload) {
|
||||
logSuccessCommand(payload);
|
||||
}
|
||||
|
||||
public onLoad() {
|
||||
this.enabled = (this.container.logger as Logger).level <= LogLevel.Debug;
|
||||
return super.onLoad();
|
||||
}
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
import type { ContextMenuCommandDeniedPayload, Events } from '@sapphire/framework';
|
||||
import { Listener, UserError } from '@sapphire/framework';
|
||||
|
||||
export class UserEvent extends Listener<typeof Events.ContextMenuCommandDenied> {
|
||||
public async run({ context, message: content }: UserError, { interaction }: ContextMenuCommandDeniedPayload) {
|
||||
// `context: { silent: true }` should make UserError silent:
|
||||
// Use cases for this are for example permissions error when running the `eval` command.
|
||||
if (Reflect.get(Object(context), 'silent')) return;
|
||||
|
||||
if (interaction.deferred || interaction.replied) {
|
||||
return interaction.editReply({
|
||||
content,
|
||||
allowedMentions: { users: [interaction.user.id], roles: [] }
|
||||
});
|
||||
}
|
||||
|
||||
return interaction.reply({
|
||||
content,
|
||||
allowedMentions: { users: [interaction.user.id], roles: [] },
|
||||
ephemeral: true
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
import { Listener, LogLevel, type ContextMenuCommandSuccessPayload } from '@sapphire/framework';
|
||||
import type { Logger } from '@sapphire/plugin-logger';
|
||||
import { logSuccessCommand } from '../../../lib/utils';
|
||||
|
||||
export class UserListener extends Listener {
|
||||
public run(payload: ContextMenuCommandSuccessPayload) {
|
||||
logSuccessCommand(payload);
|
||||
}
|
||||
|
||||
public onLoad() {
|
||||
this.enabled = (this.container.logger as Logger).level <= LogLevel.Debug;
|
||||
return super.onLoad();
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
import type { Events } from '@sapphire/framework';
|
||||
import { Listener } from '@sapphire/framework';
|
||||
import type { Message } from 'discord.js';
|
||||
|
||||
export class UserEvent extends Listener<typeof Events.MentionPrefixOnly> {
|
||||
public async run(message: Message) {
|
||||
const prefix = this.container.client.options.defaultPrefix;
|
||||
return message.channel.send(prefix ? `My prefix in this guild is: \`${prefix}\`` : 'Cannot find any Prefix for Message Commands.');
|
||||
}
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
import { ApplyOptions } from '@sapphire/decorators';
|
||||
import { Listener, Store, container } from '@sapphire/framework';
|
||||
import { blue, gray, green, magenta, magentaBright, white, yellow } from 'colorette';
|
||||
|
||||
const dev = process.env.NODE_ENV !== 'production';
|
||||
|
||||
// @ts-ignore
|
||||
@ApplyOptions<Listener.Options>({ once: true })
|
||||
export class UserEvent extends Listener {
|
||||
private readonly style = dev ? yellow : blue;
|
||||
|
||||
public run() {
|
||||
this.printBanner();
|
||||
this.printStoreDebugInformation();
|
||||
}
|
||||
|
||||
private printBanner() {
|
||||
const success = green('+');
|
||||
|
||||
const llc = dev ? magentaBright : white;
|
||||
const blc = dev ? magenta : blue;
|
||||
|
||||
const line01 = llc('');
|
||||
const line02 = llc('');
|
||||
const line03 = llc('');
|
||||
|
||||
// Offset Pad
|
||||
const pad = ' '.repeat(7);
|
||||
|
||||
console.log(
|
||||
String.raw`
|
||||
${line01} ${pad}${blc('1.0.0')}
|
||||
${line02} ${pad}[${success}] Gateway
|
||||
${line03}${dev ? ` ${pad}${blc('<')}${llc('/')}${blc('>')} ${llc('DEVELOPMENT MODE')}` : ''}
|
||||
`.trim()
|
||||
);
|
||||
}
|
||||
|
||||
private printStoreDebugInformation() {
|
||||
const { client, logger } = this.container;
|
||||
const stores = [...client.stores.values()];
|
||||
const last = stores.pop()!;
|
||||
|
||||
for (const store of stores) logger.info(this.styleStore(store));
|
||||
logger.info(this.styleStore(last));
|
||||
}
|
||||
|
||||
private styleStore(store: Store<any>) {
|
||||
return gray(`${'└─'} Loaded ${this.style(store.size.toString().padEnd(3, ' '))} ${store.name}.`);
|
||||
}
|
||||
}
|
||||
|
||||
void container.stores.loadPiece({
|
||||
piece: UserEvent,
|
||||
name: 'ready',
|
||||
store: 'listeners'
|
||||
});
|
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
"extends": "@sapphire/ts-config",
|
||||
"compilerOptions": {
|
||||
"ignoreDeprecations": "5.0",
|
||||
"rootDir": "src",
|
||||
"outDir": "dist",
|
||||
"tsBuildInfoFile": "dist/.tsbuildinfo"
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
Loading…
Add table
Reference in a new issue