-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 324be67
Showing
28 changed files
with
2,009 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
.github/ | ||
helm/ | ||
files/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
.DS_Store | ||
go.work | ||
go.work.sum |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
|
||
FROM golang:1.21.5-alpine3.19 AS builder | ||
ENV APP_NAME pluralia | ||
ENV WORKDIR /app | ||
WORKDIR $WORKDIR | ||
COPY . . | ||
RUN go mod download | ||
RUN go build -o /$APP_NAME | ||
|
||
## Deploy | ||
FROM alpine:3.19.0 | ||
ENV APP_NAME pluralia | ||
WORKDIR / | ||
COPY --from=builder /$APP_NAME /$APP_NAME | ||
ENTRYPOINT ["/pluralia"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,221 @@ | ||
package cmd | ||
|
||
import ( | ||
"log" | ||
"strings" | ||
|
||
"github.com/bwmarrin/discordgo" | ||
"github.com/seemywingz/goai" | ||
"github.com/spf13/viper" | ||
) | ||
|
||
var discord *discordgo.Session | ||
|
||
func initDiscord() { | ||
var err error | ||
discord, err = discordgo.New("Bot " + DISCORD_API_KEY) | ||
catchErr(err) | ||
|
||
discord.Client = httpClient // Set the HTTP client for the Discord session. | ||
|
||
// Open a websocket connection to Discord | ||
err = discord.Open() | ||
catchErr(err) | ||
defer discord.Close() | ||
|
||
setStatusOnline() | ||
registerHandlers() | ||
registerCommands() | ||
deregisterCommands() | ||
|
||
log.Println("🤖 pluralia Discord Bot is Running...") | ||
select {} // Block forever to prevent the program from terminating. | ||
} | ||
|
||
func setStatusOnline() { | ||
log.Println("🛜 Setting Status to Online...") | ||
// Set status to online with active activity | ||
err := discord.UpdateStatusComplex(discordgo.UpdateStatusData{ | ||
Status: "online", | ||
Activities: []*discordgo.Activity{ | ||
{ // Activity Type 0 is "Playing" | ||
Name: "With the API", | ||
Type: discordgo.ActivityType(0), | ||
}, | ||
}, | ||
AFK: false, | ||
}) | ||
catchErr(err) | ||
} | ||
|
||
func registerHandlers() { | ||
log.Println("💾 Registering Handlers...") | ||
discord.AddHandler(handleCommands) | ||
discord.AddHandler(handleMessages) | ||
} | ||
|
||
func deregisterCommands() { | ||
|
||
if removeCMDIds != "" { | ||
slashCommandIDs := strings.Split(removeCMDIds, ",") | ||
for _, slashCommandID := range slashCommandIDs { | ||
log.Println("➖ Removing Command: ", slashCommandID) | ||
err := discord.ApplicationCommandDelete(discord.State.User.ID, "", slashCommandID) | ||
if err != nil { | ||
log.Println("Error deleting slash command: ", err) | ||
return | ||
} | ||
} | ||
} | ||
} | ||
|
||
func registerCommands() { | ||
|
||
commands := []*discordgo.ApplicationCommand{ | ||
{ | ||
Name: "scrape", | ||
Description: "Scrape Discord channel for Upscaled Midjourney Images", | ||
}, | ||
{ | ||
Name: "pluralia-image", | ||
Description: "Use DALL-E 3 to generate an Image", | ||
Options: []*discordgo.ApplicationCommandOption{ | ||
{ | ||
Type: discordgo.ApplicationCommandOptionString, | ||
Name: "prompt", | ||
Description: "Prompt for Image Generation", | ||
Required: true, | ||
}, | ||
}, | ||
}, | ||
} | ||
|
||
for _, command := range commands { | ||
log.Println("➕ Adding Command: /"+command.Name, "-", command.Description) | ||
_, err := discord.ApplicationCommandCreate(discord.State.User.ID, "", command) | ||
catchErr(err) | ||
} | ||
} | ||
|
||
func handleCommands(s *discordgo.Session, i *discordgo.InteractionCreate) { | ||
discordInitialResponse("pluraliaing...", s, i) | ||
switch i.ApplicationCommandData().Name { | ||
default: // Handle unknown slash commands | ||
log.Printf("Unknown pluralia Command: %s", i.ApplicationCommandData().Name) | ||
} | ||
} | ||
|
||
func handleMessages(s *discordgo.Session, m *discordgo.MessageCreate) { | ||
|
||
// Ignore all messages created by the bot itself | ||
if m.Author.ID == discord.State.User.ID { | ||
return | ||
} | ||
|
||
// channelName := discordGetChannelName(m.ChannelID) | ||
|
||
// Respond to messages in the #pluralia channel | ||
if m.GuildID == "" { | ||
discordOpenAIResponse(s, m, false) | ||
return | ||
} | ||
|
||
// Check if the message contains an @mention of the bot. | ||
for _, user := range m.Mentions { | ||
if user.ID == s.State.User.ID { | ||
// Send a reply to the user who mentioned the bot. | ||
discordOpenAIResponse(s, m, true) | ||
return | ||
} | ||
} | ||
|
||
} | ||
|
||
func discordOpenAIResponse(s *discordgo.Session, m *discordgo.MessageCreate, mention bool) { | ||
discord.ChannelTyping(m.ChannelID) | ||
openaiMessages := []goai.Message{{ | ||
Role: "system", | ||
Content: viper.GetString("discord_bot_systemMessage"), | ||
}} | ||
|
||
discordMessages, err := discord.ChannelMessages(m.ChannelID, viper.GetInt("discord_message_context_count"), "", "", "") | ||
catchErr(err) | ||
discordMessages = discordReverseMessageOrder(discordMessages) | ||
|
||
for _, message := range discordMessages { | ||
role := "user" | ||
if message.Author.ID == discord.State.User.ID { | ||
role = "assistant" | ||
} | ||
newMessage := goai.Message{ | ||
Role: role, | ||
Content: message.Content, | ||
} | ||
openaiMessages = append(openaiMessages, newMessage) | ||
} | ||
|
||
// Send the messages to OpenAI | ||
ai.User = ai.User + m.Author.Username | ||
oaiResponse, err := ai.ChatCompletion(openaiMessages) | ||
catchErr(err) | ||
s.ChannelMessageSend(m.ChannelID, oaiResponse.Choices[0].Message.Content) | ||
} | ||
|
||
func discordpluraliaImage(s *discordgo.Session, i *discordgo.InteractionCreate) { | ||
channelID := i.ChannelID | ||
discord.ChannelTyping(channelID) | ||
commandData := i.ApplicationCommandData() | ||
|
||
// Check if there are options and retrieve the prompt | ||
if len(commandData.Options) > 0 { | ||
promptOption := commandData.Options[0] | ||
prompt := promptOption.StringValue() | ||
discordFollowUp("Using DALL-E 3 to generate an image: "+prompt, s, i) | ||
res := ai.ImageGen(prompt, "", 1) | ||
s.ChannelMessageSend(channelID, res.Data[0].URL) | ||
} else { | ||
discordFollowUp("Please Provide a Prompt for Image Generation", s, i) | ||
} | ||
|
||
} | ||
|
||
func discordInitialResponse(content string, s *discordgo.Session, i *discordgo.InteractionCreate) { | ||
// Send initial defer response. | ||
response := &discordgo.InteractionResponse{ | ||
Type: discordgo.InteractionResponseDeferredChannelMessageWithSource, | ||
Data: &discordgo.InteractionResponseData{ | ||
Content: content, | ||
}, | ||
} | ||
err := s.InteractionRespond(i.Interaction, response) | ||
catchErr(err) | ||
} | ||
|
||
func discordGetChannelID(s *discordgo.Session, guildID string, channelName string) string { | ||
channels, err := s.GuildChannels(guildID) | ||
catchErr(err) | ||
|
||
for _, channel := range channels { | ||
if channel.Name == channelName { | ||
return channel.ID | ||
} | ||
} | ||
|
||
return "" | ||
} | ||
|
||
func discordFollowUp(message string, s *discordgo.Session, i *discordgo.InteractionCreate) { | ||
followup := &discordgo.WebhookParams{ | ||
Content: message, | ||
} | ||
_, err := s.FollowupMessageCreate(i.Interaction, false, followup) | ||
catchErr(err) | ||
} | ||
|
||
// function to reverse the order of a slice | ||
func discordReverseMessageOrder(s []*discordgo.Message) []*discordgo.Message { | ||
for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 { | ||
s[i], s[j] = s[j], s[i] | ||
} | ||
return s | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
/* | ||
Copyright © 2023 NAME HERE [email protected] | ||
*/ | ||
package cmd | ||
|
||
import ( | ||
"bufio" | ||
"fmt" | ||
"os" | ||
"strings" | ||
|
||
"github.com/seemywingz/goai" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
func init() { | ||
rootCmd.AddCommand(chatCmd) | ||
} | ||
|
||
// chatCmd represents the chat command | ||
var chatCmd = &cobra.Command{ | ||
Use: "chat", | ||
Short: "Open ended chat with OpenAI", | ||
Long: ``, | ||
Args: cobra.ExactArgs(1), // Expect exactly one argument | ||
Run: func(cmd *cobra.Command, args []string) { | ||
prompt := args[0] | ||
var err error | ||
if convo { | ||
for { | ||
response, audio := chatResponse(prompt) | ||
fmt.Println("\npluralia:") | ||
syntaxHighlight(response) | ||
if narrate { | ||
playAudio(audio) | ||
} | ||
fmt.Print("\nYou:\n ") | ||
prompt, err = getUserInput() | ||
catchErr(err, "warn") | ||
} | ||
} else { | ||
response, audio := chatResponse(prompt) | ||
syntaxHighlight(response) | ||
if narrate { | ||
playAudio(audio) | ||
} | ||
} | ||
}, | ||
} | ||
|
||
func chatResponse(prompt string) (string, []byte) { | ||
var audio []byte | ||
var response string | ||
spinner, _ = pluraliaSpinner.Start() | ||
response = chatCompletion(prompt) | ||
if narrate { | ||
audio = tts(response) | ||
} | ||
spinner.Stop() | ||
return response, audio | ||
} | ||
|
||
func chatCompletion(prompt string) string { | ||
pluraliaMessages = append(pluraliaMessages, goai.Message{ | ||
Role: "user", | ||
Content: prompt, | ||
}) | ||
|
||
// Send the messages to OpenAI | ||
res, err := ai.ChatCompletion(pluraliaMessages) | ||
catchErr(err) | ||
pluraliaMessages = append(pluraliaMessages, goai.Message{ | ||
Role: "assistant", | ||
Content: res.Choices[0].Message.Content, | ||
}) | ||
return res.Choices[0].Message.Content | ||
} | ||
|
||
func getUserInput() (string, error) { | ||
// ReadString will block until the delimiter is entered | ||
reader := bufio.NewReader(os.Stdin) | ||
input, err := reader.ReadString('\n') | ||
if err != nil { | ||
trace() | ||
return "", err | ||
} | ||
// remove the delimiter from the string | ||
input = strings.TrimSuffix(input, "\n") | ||
if verbose { | ||
trace() | ||
fmt.Println(input) | ||
} | ||
return input, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
/* | ||
Copyright © 2023 [email protected] | ||
*/ | ||
package cmd | ||
|
||
import ( | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
var removeCMDIds string | ||
|
||
// discordCmd represents the discord command | ||
var discordCmd = &cobra.Command{ | ||
Use: "discord-bot", | ||
Short: "Discord Chat Bot Integration", | ||
Long: `Discord Chat Bot Integration utilizing Secure Gateway Websocket`, | ||
Run: func(cmd *cobra.Command, args []string) { | ||
initDiscord() | ||
}, | ||
} | ||
|
||
func init() { | ||
rootCmd.AddCommand(discordCmd) | ||
discordCmd.Flags().StringVarP(&removeCMDIds, "deregister-commands", "D", "", "A comma separated list of command IDs to deregister") | ||
} |
Oops, something went wrong.