/
bot.go
112 lines (94 loc) · 2.96 KB
/
bot.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
package bot
import (
"strings"
"github.com/bwmarrin/discordgo"
"github.com/chad-collins/butterbird-go/internal/commands"
"github.com/chad-collins/butterbird-go/internal/config"
"github.com/chad-collins/butterbird-go/internal/gpt"
"github.com/chad-collins/butterbird-go/internal/logger"
)
// Bot represents the state of the Discord bot.
type Bot struct {
ID string
Session *discordgo.Session
GPTClient gpt.GPTClient // Use the GPTClient interface
Commands map[string]commands.Command
}
var clientFactories = map[string]func(token string) gpt.GPTClient{
"openai": func(token string) gpt.GPTClient {
return new(gpt.OpenAIGPTClient).CreateClient(token)
},
}
// LoadCommands initializes and maps the commands for the bot.
func (b *Bot) LoadCommands() {
// List of command instances
commandList := []commands.Command{
&commands.HelloCommand{},
&commands.HeyPrefixCommand{},
&commands.KrobyCommand{},
// ... add other commands here ...
}
for _, cmd := range commandList {
cmd.Init(b.GPTClient) // Initialize the command
b.Commands[cmd.Trigger()] = cmd // Load the command using its trigger
}
}
// NewBot initializes a new Bot instance.
func NewBot() *Bot {
config.ReadConfig() // Ensure configuration is loaded
session, err := discordgo.New("Bot " + config.DiscordToken)
if err != nil {
logger.Fatal(err, "Creating Discord session")
}
logger.Info("Discord session created")
// Set the client type and get the corresponding token
clientType := config.GPTClient
gptToken := config.GPTClients[clientType].Token
factory, exists := clientFactories[clientType]
if !exists {
logger.Fatal(nil, "Unknown GPT client type: "+clientType)
}
// Initialize the GPT client with the token
gptClient := factory(gptToken)
bot := &Bot{
Session: session,
GPTClient: gptClient,
Commands: make(map[string]commands.Command),
}
user, err := session.User("@me")
if err != nil {
logger.Fatal(err, "Accessing bot user details")
}
bot.ID = user.ID
logger.Info("Bot user details retrieved")
bot.LoadCommands()
return bot
}
// Start begins the bot's operation.
func (b *Bot) Start() {
b.Session.AddHandler(b.OnMessageReceived)
b.Session.Identify.Intents = discordgo.IntentsGuildMessages
if err := b.Session.Open(); err != nil {
logger.Fatal(err, "Opening WebSocket connection")
}
logger.Info(config.BotName + " is online!")
}
// OnMessageReceived is called when a message is received.
func (b *Bot) OnMessageReceived(s *discordgo.Session, m *discordgo.MessageCreate) {
// Ignore messages from bots to prevent potential loops or spam
if m.Author.Bot {
return
}
// Iterate over registered commands
for trigger, cmd := range b.Commands {
// Check if the message starts with the command trigger
if strings.HasPrefix(m.Content, trigger) {
// Execute the command and handle any errors
err := cmd.Execute(s, m)
if err != nil {
logger.Warn(err, "Executing command")
}
return // Stop processing after the first matching command
}
}
}