From 8bbb1a02677330d1a49977f5b5b8565b90b83fd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20D=C3=B6tsch?= Date: Fri, 3 Nov 2023 13:54:43 +0100 Subject: [PATCH 1/2] Openai: use message attachment as GPT context --- bot/interaction.go | 32 ++++++++++++++++++++++++++++++++ bot/stats/stats.go | 7 ++++--- command/openai/command.go | 6 ++++++ command/openai/tokens.go | 6 +++--- command/openai/tokens_test.go | 2 +- 5 files changed, 46 insertions(+), 7 deletions(-) diff --git a/bot/interaction.go b/bot/interaction.go index c9b0709b..0ae322a0 100644 --- a/bot/interaction.go +++ b/bot/interaction.go @@ -1,6 +1,8 @@ package bot import ( + "bytes" + "strings" "sync" "github.com/innogames/slack-bot/v2/bot/msg" @@ -18,12 +20,18 @@ func (b *Bot) handleEvent(eventsAPIEvent slackevents.EventsAPIEvent) { switch eventsAPIEvent.Type { case slackevents.CallbackEvent: innerEvent := eventsAPIEvent.InnerEvent + switch ev := innerEvent.Data.(type) { case *slackevents.MessageEvent: if ev.SubType == "message_changed" { // don't listen to edited messages return } + + if len(ev.Files) > 0 { + ev.Text += b.loadFileContent(ev) + } + message := &slack.MessageEvent{ Msg: slack.Msg{ Text: ev.Text, @@ -51,6 +59,30 @@ func (b *Bot) handleEvent(eventsAPIEvent slackevents.EventsAPIEvent) { } } +func (b *Bot) loadFileContent(event *slackevents.MessageEvent) string { + response := "" + + for _, file := range event.Files { + if !strings.HasPrefix(file.Mimetype, "text/") { + log.Infof("Can't load file %s: mimetype is %s", file.Name, file.Mimetype) + continue + } + + var downloadedText bytes.Buffer + log.Infof("Downloading message attachment file %s", file.Name) + + err := b.slackClient.Client.GetFile(file.URLPrivate, &downloadedText) + if err != nil { + log.Errorf("Failed to download file %s: %s", file.URLPrivate, err.Error()) + continue + } + + response += "\n" + downloadedText.String() + } + + return response +} + func (b *Bot) handleInteraction(payload slack.InteractionCallback) bool { if !b.isUserActionAllowed(payload.User.ID) { log.Warnf("User %s tried to execute a command", payload.User.ID) diff --git a/bot/stats/stats.go b/bot/stats/stats.go index 8582b2ef..20825c5f 100644 --- a/bot/stats/stats.go +++ b/bot/stats/stats.go @@ -4,6 +4,7 @@ import ( "github.com/innogames/slack-bot/v2/bot/storage" "github.com/pkg/errors" log "github.com/sirupsen/logrus" + "golang.org/x/exp/constraints" ) const collection = "stats" @@ -28,9 +29,9 @@ func IncreaseOne(key string) { } // Increase is increasing the stats counter -func Increase(key string, count uint) { +func Increase[T constraints.Signed](key string, count T) { storage.Atomic(func() { - var value uint + var value T _ = storage.Read(collection, key, &value) value += count @@ -42,7 +43,7 @@ func Increase(key string, count uint) { } // Set the stats to a specific value -func Set(key string, value uint) { +func Set[T constraints.Signed](key string, value T) { if err := storage.Write(collection, key, value); err != nil { log.Warn(errors.Wrap(err, "error while set stats")) } diff --git a/command/openai/command.go b/command/openai/command.go index 09dc171e..383cb552 100644 --- a/command/openai/command.go +++ b/command/openai/command.go @@ -11,8 +11,10 @@ import ( "github.com/innogames/slack-bot/v2/bot/config" "github.com/innogames/slack-bot/v2/bot/matcher" "github.com/innogames/slack-bot/v2/bot/msg" + "github.com/innogames/slack-bot/v2/bot/stats" "github.com/innogames/slack-bot/v2/bot/storage" "github.com/innogames/slack-bot/v2/bot/util" + log "github.com/sirupsen/logrus" "github.com/slack-go/slack" ) @@ -235,6 +237,10 @@ func (c *chatGPTCommand) callAndStore(messages []ChatMessage, storageIdentifier log.Warnf("Error while storing openai history: %s", err) } + stats.IncreaseOne("openai_calls") + stats.Increase("openai_input_tokens", inputTokens) + stats.Increase("openai_output_tokens", estimateTokensForMessage(responseText.String())) + log.Infof( "Openai %s call took %s with %d sub messages (%d tokens). Message: '%s'. Response: '%s'", c.cfg.Model, diff --git a/command/openai/tokens.go b/command/openai/tokens.go index 51972bc0..33be92bd 100644 --- a/command/openai/tokens.go +++ b/command/openai/tokens.go @@ -23,7 +23,7 @@ func truncateMessages(model string, inputMessages []ChatMessage) ([]ChatMessage, truncatedMessages := 0 maxTokens := getMaxTokensForModel(model) for _, message := range inputMessages { - tokens := estimateTokensForMessage(message) + tokens := estimateTokensForMessage(message.Content) if currentTokens+tokens >= maxTokens { truncatedMessages++ @@ -49,8 +49,8 @@ func getMaxTokensForModel(model string) int { return 4000 } -func estimateTokensForMessage(message ChatMessage) int { +func estimateTokensForMessage(message string) int { // to lower the dependency to heavy external libs we use the rule of thumbs which is totally fine here // https://platform.openai.com/tokenizer - return len(message.Content) / 4 + return len(message) / 4 } diff --git a/command/openai/tokens_test.go b/command/openai/tokens_test.go index 22f068c0..8f1e46e3 100644 --- a/command/openai/tokens_test.go +++ b/command/openai/tokens_test.go @@ -46,7 +46,7 @@ func TestTruncate(t *testing.T) { func TestCountTokens(t *testing.T) { t.Run("Count", func(t *testing.T) { - actual := estimateTokensForMessage(ChatMessage{Content: "hello you!"}) + actual := estimateTokensForMessage("hello you!") assert.Equal(t, 2, actual) }) } From 9a09e953ed89e0fec01871b10cfecd87446f4231 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20D=C3=B6tsch?= Date: Fri, 3 Nov 2023 14:33:26 +0100 Subject: [PATCH 2/2] Openai: use message attachment as GPT context --- .github/workflows/master.yaml | 2 +- .github/workflows/test.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/master.yaml b/.github/workflows/master.yaml index 9de49055..1ac9cb67 100644 --- a/.github/workflows/master.yaml +++ b/.github/workflows/master.yaml @@ -48,4 +48,4 @@ jobs: - name: Test run: make test-coverage - name: Upload Coverage - uses: codecov/codecov-action@v4 + uses: codecov/codecov-action@v3 diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 28b3a16c..19929a2d 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -49,7 +49,7 @@ jobs: env: BOT_GITHUB_ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Upload Coverage - uses: codecov/codecov-action@v4 + uses: codecov/codecov-action@v3 lint: name: Lint if: ${{ github.event_name == 'pull_request' }}