Skip to content

Commit

Permalink
init commit
Browse files Browse the repository at this point in the history
  • Loading branch information
seemywingz committed May 23, 2024
0 parents commit 324be67
Show file tree
Hide file tree
Showing 28 changed files with 2,009 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.github/
helm/
files/
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.DS_Store
go.work
go.work.sum
15 changes: 15 additions & 0 deletions Dockerfile
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"]
221 changes: 221 additions & 0 deletions cmd/Discord_api.go
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
}
94 changes: 94 additions & 0 deletions cmd/chat.go
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
}
25 changes: 25 additions & 0 deletions cmd/discord.go
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")
}
Loading

0 comments on commit 324be67

Please sign in to comment.