Skip to content

Commit fa8d84e

Browse files
committed
feat: 引用メッセージを展開するように
1 parent 95da448 commit fa8d84e

File tree

7 files changed

+177
-4
lines changed

7 files changed

+177
-4
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ require (
2828
github.com/kr/text v0.2.0 // indirect
2929
github.com/mfridman/interpolate v0.0.2 // indirect
3030
github.com/milvus-io/milvus-proto/go-api/v2 v2.4.10-0.20240819025435-512e3b98866a // indirect
31+
github.com/motoki317/sc v1.8.2 // indirect
3132
github.com/pkg/errors v0.9.1 // indirect
3233
github.com/rogpeppe/go-internal v1.14.1 // indirect
3334
github.com/sethvargo/go-retry v0.3.0 // indirect

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ github.com/milvus-io/milvus-proto/go-api/v2 v2.4.10-0.20240819025435-512e3b98866
8484
github.com/milvus-io/milvus-proto/go-api/v2 v2.4.10-0.20240819025435-512e3b98866a/go.mod h1:1OIl0v5PQeNxIJhCvY+K55CBUOYDZevw9g9380u1Wek=
8585
github.com/milvus-io/milvus-sdk-go/v2 v2.4.2 h1:Xqf+S7iicElwYoS2Zly8Nf/zKHuZsNy1xQajfdtygVY=
8686
github.com/milvus-io/milvus-sdk-go/v2 v2.4.2/go.mod h1:ulO1YUXKH0PGg50q27grw048GDY9ayB4FPmh7D+FFTA=
87+
github.com/motoki317/sc v1.8.2 h1:JzhmFKl4ZS0VxuRYRBQ07o3DcGdvhn2NwqnUcPJmCjY=
88+
github.com/motoki317/sc v1.8.2/go.mod h1:IwywgSXTlBxHV8a6lHNiQYmTBh7Dc4f9KjzXVdl8/Bk=
8789
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
8890
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
8991
github.com/openai/openai-go/v2 v2.7.1 h1:/tfvTJhfv7hTSL8mWwc5VL4WLLSDL5yn9VqVykdu9r8=

internal/bot/channel.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package bot
2+
3+
import (
4+
"context"
5+
"time"
6+
7+
"github.com/motoki317/sc"
8+
)
9+
10+
func getChannelPathInternal(ctx context.Context, channelID string) (string, error) {
11+
bot := GetBot()
12+
13+
path, _, err := bot.API().ChannelAPI.GetChannelPath(ctx, channelID).Execute()
14+
if err != nil {
15+
return "", err
16+
}
17+
return path.Path, nil
18+
}
19+
20+
var channelPathCache = sc.NewMust(getChannelPathInternal, time.Hour, time.Hour, nil)
21+
22+
func GetChannelPath(channelID string) (string, error) {
23+
return channelPathCache.Get(context.Background(), channelID)
24+
}

internal/bot/user.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package bot
2+
3+
import (
4+
"context"
5+
"time"
6+
7+
"github.com/motoki317/sc"
8+
"github.com/traPtitech/go-traq"
9+
)
10+
11+
func getUserInternal(ctx context.Context, userID string) (*traq.UserDetail, error) {
12+
bot := GetBot()
13+
14+
user, _, err := bot.API().UserAPI.GetUser(ctx, userID).Execute()
15+
if err != nil {
16+
return nil, err
17+
}
18+
return user, nil
19+
}
20+
21+
var userCache = sc.NewMust(getUserInternal, time.Hour, time.Hour, nil)
22+
23+
func GetUser(userID string) (*traq.UserDetail, error) {
24+
return userCache.Get(context.Background(), userID)
25+
}

internal/handler/OnDirectMessageCreated.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
package handler
22

33
import (
4+
"log"
5+
46
"github.com/traPtitech/BOT_GPT/internal/bot"
7+
"github.com/traPtitech/BOT_GPT/internal/pkg/formatter"
58
"github.com/traPtitech/traq-ws-bot/payload"
6-
"log"
79
)
810

911
func (h *Handler) DirectMessageReceived() func(p *payload.DirectMessageCreated) {
@@ -17,11 +19,16 @@ func (h *Handler) DirectMessageReceived() func(p *payload.DirectMessageCreated)
1719
}
1820

1921
plainTextWithoutMention := bot.RemoveFirstBotID(p.Message.PlainText)
22+
formattedMessage, err := formatter.FormatQuotedMessage(p.Message.User.ID, plainTextWithoutMention)
23+
if err != nil {
24+
log.Printf("Error formatting quoted message: %v\n", err)
25+
formattedMessage = plainTextWithoutMention
26+
}
2027

2128
if p.Message.User.Name != "pikachu" {
2229
_ = bot.PostMessage(p.Message.ChannelID, "DMではあんまり沢山使わないでね。定期的な`/reset`を忘れない事。")
2330
}
2431

25-
messageReceived(p.Message.Text, plainTextWithoutMention, p.Message.ChannelID)
32+
messageReceived(p.Message.Text, formattedMessage, p.Message.ChannelID)
2633
}
2734
}

internal/handler/OnMessageCreated.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
package handler
22

33
import (
4+
"log"
5+
46
"github.com/traPtitech/BOT_GPT/internal/bot"
7+
"github.com/traPtitech/BOT_GPT/internal/pkg/formatter"
58
"github.com/traPtitech/traq-ws-bot/payload"
6-
"log"
79
)
810

911
func (h *Handler) MessageReceived() func(p *payload.MessageCreated) {
@@ -17,7 +19,12 @@ func (h *Handler) MessageReceived() func(p *payload.MessageCreated) {
1719
}
1820

1921
plainTextWithoutMention := bot.RemoveFirstBotID(p.Message.PlainText)
22+
formattedMessage, err := formatter.FormatQuotedMessage(p.Message.User.ID, plainTextWithoutMention)
23+
if err != nil {
24+
log.Printf("Error formatting quoted message: %v\n", err)
25+
formattedMessage = plainTextWithoutMention
26+
}
2027

21-
messageReceived(p.Message.Text, plainTextWithoutMention, p.Message.ChannelID)
28+
messageReceived(p.Message.Text, formattedMessage, p.Message.ChannelID)
2229
}
2330
}

internal/pkg/formatter/quotes.go

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
package formatter
2+
3+
import (
4+
"regexp"
5+
"strings"
6+
7+
"github.com/traPtitech/BOT_GPT/internal/bot"
8+
"github.com/traPtitech/go-traq"
9+
)
10+
11+
const quoteRegexStr = `\bhttps://q\\.trap\\.jp/messages/([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\b`
12+
13+
var quoteRegex = regexp.MustCompile(quoteRegexStr)
14+
15+
var allowingPrefixes = []string{"/event", "/general", "/random", "/services", "/team/SysAd"}
16+
17+
func isChannelAllowingQuotes(channelID string) (bool, error) {
18+
channelPath, err := bot.GetChannelPath(channelID)
19+
if err != nil {
20+
return false, err
21+
}
22+
23+
for _, prefix := range allowingPrefixes {
24+
if strings.HasPrefix(channelPath, prefix) {
25+
return true, nil
26+
}
27+
}
28+
29+
return false, nil
30+
}
31+
32+
func isUserAllowingQuotes(userID string, messageUserID string) (bool, error) {
33+
if userID == messageUserID {
34+
return true, nil
35+
}
36+
37+
messageUser, err := bot.GetUser(userID)
38+
if err != nil {
39+
return false, err
40+
}
41+
42+
if messageUser.Bot {
43+
return true, nil
44+
}
45+
46+
return false, nil
47+
}
48+
49+
func getQuoteMarkdown(message *traq.Message) (string, error) {
50+
user, err := bot.GetUser(message.UserId)
51+
if err != nil {
52+
return "", err
53+
}
54+
55+
return "> " + user.Name + ":\n> " + strings.ReplaceAll(message.Content, "\n", "\n> "), nil
56+
}
57+
58+
const maxQuoteLength = 10000
59+
60+
func FormatQuotedMessage(userID string, content string) (string, error) {
61+
matches := quoteRegex.FindAllSubmatch([]byte(content), len(content))
62+
messageIDs := make([]string, 0, len(matches))
63+
for _, match := range matches {
64+
if len(match) < 2 {
65+
continue
66+
}
67+
messageID := string(match[1])
68+
messageIDs = append(messageIDs, messageID)
69+
}
70+
71+
var formattedContent strings.Builder
72+
formattedContent.WriteString(quoteRegex.ReplaceAllString(content, ""))
73+
74+
for _, messageID := range messageIDs {
75+
message := bot.GetMessage(messageID)
76+
if message == nil {
77+
continue
78+
}
79+
80+
if len(message.Content) > maxQuoteLength {
81+
message.Content = message.Content[:maxQuoteLength] + "(以下略)"
82+
}
83+
84+
allowed, err := isChannelAllowingQuotes(message.ChannelId)
85+
if err != nil {
86+
return "", err
87+
}
88+
if !allowed {
89+
continue
90+
}
91+
92+
allowed, err = isUserAllowingQuotes(userID, message.UserId)
93+
if err != nil {
94+
return "", err
95+
}
96+
if !allowed {
97+
continue
98+
}
99+
100+
quote, err := getQuoteMarkdown(message)
101+
if err != nil {
102+
return "", err
103+
}
104+
formattedContent.WriteString("\n\n" + quote)
105+
}
106+
return formattedContent.String(), nil
107+
}

0 commit comments

Comments
 (0)