Skip to content

Commit

Permalink
feat: add help card
Browse files Browse the repository at this point in the history
  • Loading branch information
Leizhenpeng committed Mar 5, 2023
1 parent fe35c3b commit 7b91e98
Show file tree
Hide file tree
Showing 7 changed files with 205 additions and 43 deletions.
5 changes: 2 additions & 3 deletions code/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ require github.com/larksuite/oapi-sdk-go/v3 v3.0.14

require (
github.com/gin-gonic/gin v1.8.2
github.com/google/uuid v1.3.0
github.com/larksuite/oapi-sdk-gin v1.0.0
github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.14.0
gopkg.in/Knetic/govaluate.v2 v2.3.0
)

require (
Expand All @@ -19,7 +20,6 @@ require (
github.com/go-playground/universal-translator v0.18.0 // indirect
github.com/go-playground/validator/v10 v10.11.1 // indirect
github.com/goccy/go-json v0.10.0 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/leodido/go-urn v1.2.1 // indirect
Expand All @@ -33,7 +33,6 @@ require (
github.com/spf13/afero v1.9.3 // indirect
github.com/spf13/cast v1.5.0 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/subosito/gotenv v1.4.1 // indirect
github.com/ugorji/go/codec v1.2.8 // indirect
golang.org/x/crypto v0.5.0 // indirect
Expand Down
2 changes: 0 additions & 2 deletions code/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -519,8 +519,6 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/Knetic/govaluate.v2 v2.3.0 h1:naJVc9CZlWA8rC8f5mvECJD7jreTrn7FvGXjBthkHJQ=
gopkg.in/Knetic/govaluate.v2 v2.3.0/go.mod h1:NW0gr10J8s7aNghEg6uhdxiEaBvc0+8VgJjVViHUKp4=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
Expand Down
12 changes: 7 additions & 5 deletions code/handlers/group.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,15 +59,12 @@ func (p GroupMessageHandler) handle(ctx context.Context, event *larkim.P2Message
return nil
}

if qParsed == "/clear" || qParsed == "清除" {
if _, foundClear := utils.EitherTrimEqual(qParsed, "/clear", "清除"); foundClear {
sendClearCacheCheckCard(ctx, sessionId, msgId)
return nil
}

system, foundSystem := utils.EitherCutPrefix(qParsed, "/system ",
"角色扮演 ")

if foundSystem {
if system, foundSystem := utils.EitherCutPrefix(qParsed, "/system ", "角色扮演 "); foundSystem {
p.sessionCache.Clear(*sessionId)
systemMsg := append([]services.Messages{}, services.Messages{
Role: "system", Content: system,
Expand All @@ -77,6 +74,11 @@ func (p GroupMessageHandler) handle(ctx context.Context, event *larkim.P2Message
return nil
}

if _, foundHelp := utils.EitherTrimEqual(qParsed, "/help", "帮助"); foundHelp {
sendHelpCard(ctx, sessionId, msgId)
return nil
}

msg := p.sessionCache.Get(*sessionId)
msg = append(msg, services.Messages{
Role: "user", Content: qParsed,
Expand Down
134 changes: 107 additions & 27 deletions code/handlers/msg.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,14 @@ func newSendCard(
return cardContent, err
}

// withSplitLine 用于生成分割线
func withSplitLine() larkcard.MessageCardElement {
splitLine := larkcard.NewMessageCardHr().
Build()
return splitLine
}

// withHeader 用于生成消息头
func withHeader(title string, color string) *larkcard.
MessageCardHeader {
if title == "" {
Expand All @@ -93,6 +101,8 @@ func withHeader(title string, color string) *larkcard.
Build()
return header
}

// withNote 用于生成纯文本脚注
func withNote(note string) larkcard.MessageCardElement {
noteElement := larkcard.NewMessageCardNote().
Elements([]larkcard.MessageCardNoteElement{larkcard.NewMessageCardPlainText().
Expand All @@ -102,6 +112,7 @@ func withNote(note string) larkcard.MessageCardElement {
return noteElement
}

// withMainMd 用于生成markdown消息体
func withMainMd(msg string) larkcard.MessageCardElement {
msg, i := processMessage(msg)
msg = processNewLine(msg)
Expand All @@ -118,6 +129,8 @@ func withMainMd(msg string) larkcard.MessageCardElement {
Build()
return mainElement
}

// withMainText 用于生成纯文本消息体
func withMainText(msg string) larkcard.MessageCardElement {
msg, i := processMessage(msg)
msg = cleanTextBlock(msg)
Expand All @@ -135,36 +148,65 @@ func withMainText(msg string) larkcard.MessageCardElement {
return mainElement
}

func withDoubleCheckBtn(sessionId *string) larkcard.
MessageCardElement {
// withMdAndExtraBtn 用于生成带有额外按钮的消息体
func withMdAndExtraBtn(msg string, btn *larkcard.
MessageCardEmbedButton) larkcard.MessageCardElement {
msg, i := processMessage(msg)
msg = processNewLine(msg)
if i != nil {
return nil
}
mainElement := larkcard.NewMessageCardDiv().
Fields(
[]*larkcard.MessageCardField{
larkcard.NewMessageCardField().
Text(larkcard.NewMessageCardLarkMd().
Content(msg).
Build()).
IsShort(true).
Build()}).
Extra(btn).
Build()
return mainElement
}

func withBtn(content string, value map[string]interface{},
typename larkcard.MessageCardButtonType) *larkcard.
MessageCardEmbedButton {
btn := larkcard.NewMessageCardEmbedButton().
Type(typename).
Value(value).
Text(larkcard.NewMessageCardPlainText().
Content(content).
Build())
return btn
}

// 清除卡片按钮
func withDoubleCheckBtn(sessionID *string) larkcard.MessageCardElement {
confirmBtn := withBtn("确认清除", map[string]interface{}{
"value": "1",
"kind": ClearCardKind,
"chatType": UserChatType,
"sessionId": *sessionID,
}, larkcard.MessageCardButtonTypeDanger,
)
cancelBtn := withBtn("我再想想", map[string]interface{}{
"value": "0",
"kind": ClearCardKind,
"sessionId": *sessionID,
"chatType": UserChatType,
},
larkcard.MessageCardButtonTypeDefault)

actions := larkcard.NewMessageCardAction().
Actions([]larkcard.MessageCardActionElement{
larkcard.NewMessageCardEmbedButton().
Type(larkcard.MessageCardButtonTypeDanger).
Value(map[string]interface{}{
"value": "1", // 1 代表确认清除
"kind": ClearCardKind,
"chatType": UserChatType,
"sessionId": *sessionId,
}).
Text(larkcard.NewMessageCardPlainText().
Content("确认清除").
Build()),
larkcard.NewMessageCardEmbedButton().
Type(larkcard.MessageCardButtonTypePrimary).
Value(map[string]interface{}{
"value": "0", // 0 代表取消清除
"kind": ClearCardKind,
"sessionId": *sessionId,
"chatType": UserChatType,
}).
Text(larkcard.NewMessageCardPlainText().
Content("我再想想").
Build()),
}).Layout(larkcard.MessageCardActionLayoutBisected.Ptr()).
Actions([]larkcard.MessageCardActionElement{confirmBtn, cancelBtn}).
Layout(larkcard.MessageCardActionLayoutBisected.Ptr()).
Build()

return actions
}

func replyMsg(ctx context.Context, msg string, msgId *string) error {
fmt.Println("sendMsg", msg, msgId)
msg, i := processMessage(msg)
Expand Down Expand Up @@ -237,7 +279,7 @@ func sendMsg(ctx context.Context, msg string, chatId *string) error {
func sendClearCacheCheckCard(ctx context.Context,
sessionId *string, msgId *string) {
newCard, _ := newSendCard(
withHeader("👻️ 机器人提醒", larkcard.TemplateBlue),
withHeader("🆑 机器人提醒", larkcard.TemplateBlue),
withMainMd("您确定要清除对话上下文吗?"),
withNote("请注意,这将开始一个全新的对话,您将无法利用之前话题的历史信息"),
withDoubleCheckBtn(sessionId))
Expand Down Expand Up @@ -273,3 +315,41 @@ func sendNewTopicCard(ctx context.Context,
newCard,
)
}

func sendHelpCard(ctx context.Context,
sessionId *string, msgId *string) {
newCard, _ := newSendCard(
withHeader("🎒需要帮助吗?", larkcard.TemplateBlue),
withMainMd("**我是小飞机,一款基于chatGpt技术的智能聊天机器人!**"),
withSplitLine(),
withMdAndExtraBtn(
"** 🆑 清除话题上下文**\n文本回复 *清除* 或 */clear*",
withBtn("立刻清除", map[string]interface{}{
"value": "1",
"kind": ClearCardKind,
"chatType": UserChatType,
"sessionId": *sessionId,
}, larkcard.MessageCardButtonTypeDanger)),
withSplitLine(),
withMainMd("**🥷 开启角色扮演模式**\n文本回复*角色扮演* 或 */system*+空格+角色信息"),
withSplitLine(),
withMainMd("**📮 常用角色管理** 🚧\n"+
" 文本回复 *角色管理* 或 */manage*"),
withSplitLine(),
withMainMd("**🔃️ 历史话题回档** 🚧\n"+
" 进入话题的回复详情页,文本回复 *恢复* 或 */reload*"),
withSplitLine(),
withMainMd("**📤 话题内容导出** 🚧\n"+
" 文本回复 *导出* 或 */export*"),
withSplitLine(),
withMainMd("**🎰 连续对话与多话题模式**\n"+
" 点击对话框参与回复,可保持话题连贯。同时,单独提问即可开启全新新话题"),
withSplitLine(),
withMainMd("**🎒 需要更多帮助**\n文本回复 *帮助* 或 */help*"),
)
replyCard(
ctx,
msgId,
newCard,
)
}
15 changes: 9 additions & 6 deletions code/handlers/personal.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func CommonProcessClearCache(cardMsg CardMsg, session services.SessionServiceCac
bool) {
if cardMsg.Value == "1" {
newCard, _ := newSendCard(
withHeader("️👻 机器人提醒", larkcard.TemplateRed),
withHeader("️🆑 机器人提醒", larkcard.TemplateRed),
withMainMd("已删除此话题的上下文信息"),
withNote("我们可以开始一个全新的话题,继续找我聊天吧"),
)
Expand All @@ -47,7 +47,7 @@ func CommonProcessClearCache(cardMsg CardMsg, session services.SessionServiceCac
}
if cardMsg.Value == "0" {
newCard, _ := newSendCard(
withHeader("️👻 机器人提醒", larkcard.TemplateGreen),
withHeader("️🆑 机器人提醒", larkcard.TemplateGreen),
withMainMd("依旧保留此话题的上下文信息"),
withNote("我们可以继续探讨这个话题,期待和您聊天。如果您有其他问题或者想要讨论的话题,请告诉我哦"),
)
Expand Down Expand Up @@ -77,14 +77,12 @@ func (p PersonalMessageHandler) handle(ctx context.Context, event *larkim.P2Mess
return nil
}

if qParsed == "/clear" || qParsed == "清除" {
if _, foundClear := utils.EitherTrimEqual(qParsed, "/clear", "清除"); foundClear {
sendClearCacheCheckCard(ctx, sessionId, msgId)
return nil
}

system, foundSystem := utils.EitherCutPrefix(qParsed, "/system ",
"角色扮演 ")
if foundSystem {
if system, foundSystem := utils.EitherCutPrefix(qParsed, "/system ", "角色扮演 "); foundSystem {
p.sessionCache.Clear(*sessionId)
systemMsg := append([]services.Messages{}, services.Messages{
Role: "system", Content: system,
Expand All @@ -94,6 +92,11 @@ func (p PersonalMessageHandler) handle(ctx context.Context, event *larkim.P2Mess
return nil
}

if _, foundHelp := utils.EitherTrimEqual(qParsed, "/help", "帮助"); foundHelp {
sendHelpCard(ctx, sessionId, msgId)
return nil
}

msg := p.sessionCache.Get(*sessionId)
msg = append(msg, services.Messages{
Role: "user", Content: qParsed,
Expand Down
18 changes: 18 additions & 0 deletions code/utils/strings.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,21 @@ func EitherCutPrefix(s string, prefix ...string) (string, bool) {
}
return s, false
}

// trim space and equal
func TrimEqual(s, prefix string) (string, bool) {
if strings.TrimSpace(s) == prefix {
return "", true
}
return s, false
}

func EitherTrimEqual(s string, prefix ...string) (string, bool) {
// 任一前缀匹配则返回剩余部分
for _, p := range prefix {
if strings.TrimSpace(s) == p {
return "", true
}
}
return s, false
}
62 changes: 62 additions & 0 deletions code/utils/strings_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,65 @@ func TestEitherCutPrefix(t *testing.T) {
})
}
}

func TestEitherTrimEqual(t *testing.T) {
type args struct {
s string
prefix []string
}
tests := []struct {
name string
args args
want string
want1 bool
}{
{
name: "Prefix match",
args: args{
s: "清除",
prefix: []string{"清除"},
},
want: "",
want1: true,
},
{
name: "Prefix match",
args: args{
s: " /clear ",
prefix: []string{"清除", "/clear"},
},
want: "",
want1: true,
},
{
name: "Prefix match",
args: args{
s: " 清除 ",
prefix: []string{"清除", "/clear"},
},
want: "",
want1: true,
},
{
name: "Prefix match",
args: args{
s: " clear ",
prefix: []string{"清除", "/clear"},
},
want: " clear ",
want1: false,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, got1 := EitherTrimEqual(tt.args.s, tt.args.prefix...)
if got != tt.want {
t.Errorf("EitherTrimEqual() got = %v, want %v", got, tt.want)
}
if got1 != tt.want1 {
t.Errorf("EitherTrimEqual() got1 = %v, want %v", got1, tt.want1)
}
})
}
}

0 comments on commit 7b91e98

Please sign in to comment.