tgbot_misaka_5882f7/botcmd_translate.go

160 lines
3.6 KiB
Go
Raw Normal View History

2023-03-08 03:28:26 +09:00
package main
import (
"regexp"
"strings"
2023-03-19 15:45:20 +09:00
"time"
2023-03-08 03:28:26 +09:00
2023-03-08 05:25:20 +09:00
"github.com/samber/lo"
2023-03-08 03:28:26 +09:00
tele "gopkg.in/telebot.v3"
"git.gensokyo.cafe/kkyy/tgbot_misaka_5882f7/openai"
"git.gensokyo.cafe/kkyy/tgbot_misaka_5882f7/openai/prompts"
)
var (
translateMenu = &tele.ReplyMarkup{}
translateBtnZhTw = translateMenu.Data("繁中", "btn_tr_zhtw", "Taiwanese Chinese")
translateBtnZhCn = translateMenu.Data("简中", "btn_tr_zhcn", "Mandarin Chinese")
translateBtnEn = translateMenu.Data("English", "btn_tr_en", "English")
translateBtnJa = translateMenu.Data("日本語", "btn_tr_ja", "Japanese")
2023-03-08 17:20:11 +09:00
translateBtnRetry = translateMenu.Data("Try again", "btn_tr_retry")
2023-03-08 03:28:26 +09:00
translateBtns = []*tele.Btn{
&translateBtnZhTw, &translateBtnZhCn, &translateBtnEn, &translateBtnJa,
2023-03-08 17:20:11 +09:00
&translateBtnRetry,
2023-03-08 03:28:26 +09:00
}
translateCmdRe = regexp.MustCompile(`^\s*\/tr(anslate)?(@\S*)?\s*`)
)
func init() {
translateMenu.Inline(
translateMenu.Row(translateBtnZhTw, translateBtnZhCn),
translateMenu.Row(translateBtnEn, translateBtnJa),
)
}
func handleTranslateCmd(c tele.Context) error {
msg := c.Message()
if msg == nil {
return nil
}
if msg.ReplyTo != nil {
msg = msg.ReplyTo
}
payload := strings.TrimSpace(translateCmdRe.ReplaceAllString(msg.Text, ""))
if payload == "" {
return c.Reply("Usage: `/tr <text>`",
&tele.SendOptions{ParseMode: tele.ModeMarkdown},
tele.Silent,
)
}
_, err := c.Bot().Reply(msg, "Sure. To what language?", tele.Silent, translateMenu)
return err
}
func handleTranslateBtn(c tele.Context) error {
msg := c.Message()
if msg == nil || msg.ReplyTo == nil {
return nil
}
origMsg := msg.ReplyTo
targetLang := c.Data()
txt := origMsg.Text
payload := strings.TrimSpace(translateCmdRe.ReplaceAllString(txt, ""))
if targetLang == "" || payload == "" {
return nil
}
// pretend to be typing
if err := c.Bot().Notify(msg.Chat, tele.Typing); err != nil {
logger.Warnf("failed to send typing action: %v", err)
}
ai := openai.NewClient(config.OpenAIApiKey)
req := openai.ChatRequest{
Model: openai.ModelGpt0305Turbo,
Messages: []openai.ChatMessage{
{
Role: openai.ChatRoleSystem,
Content: prompts.Translate(targetLang),
},
{
Role: openai.ChatRoleUser,
Content: payload,
},
},
2023-03-08 16:53:28 +09:00
Temperature: lo.ToPtr(0.2),
2023-03-08 03:28:26 +09:00
}
2023-03-08 16:53:28 +09:00
logger.Debugf("Openai chat request: %#+v", req)
2023-03-08 03:28:26 +09:00
2023-03-19 15:45:20 +09:00
resp, err := ai.ChatCompletionStream(req)
2023-03-08 03:28:26 +09:00
if err != nil {
logger.Errorf("failed to translate: req: %#+v, err: %v", req, err)
2023-03-19 15:45:20 +09:00
_, _ = c.Bot().Reply(origMsg, stickerFromID(stickerPanic), tele.Silent)
2023-03-08 03:28:26 +09:00
return err
}
2023-03-19 15:45:20 +09:00
respBuilder := strings.Builder{}
minWait := time.After(1 * time.Second)
for {
var (
nNewChunk int
finished bool
minWaitSatisfied bool
)
Drain:
for {
select {
case chunk, ok := <-resp.Stream:
if !ok {
finished = true
break Drain
}
nNewChunk += 1
respBuilder.WriteString(chunk)
default:
if minWaitSatisfied {
break Drain
}
<-minWait
minWaitSatisfied = true
}
}
if nNewChunk == 0 {
if chunk, ok := <-resp.Stream; !ok {
finished = true
} else {
respBuilder.WriteString(chunk)
}
}
if finished {
break
}
2023-03-20 19:12:41 +09:00
respoText := respBuilder.String() + assistantWritingSign
2023-03-19 15:45:20 +09:00
minWait = time.After(691 * time.Millisecond) // renew the timer
if msg, err = c.Bot().Edit(msg, respoText, tele.Silent); err != nil {
logger.Warnf("failed to edit the temporary message: %v", err)
break
}
logger.Debugf("... message edited")
}
respText := respBuilder.String()
2023-03-08 17:20:11 +09:00
retryBtn := translateBtnRetry
retryBtn.Data = targetLang
respMenu := &tele.ReplyMarkup{}
respMenu.Inline(respMenu.Row(retryBtn))
2023-03-19 15:45:20 +09:00
_, err = c.Bot().Edit(msg, respText, tele.Silent, respMenu)
2023-03-08 03:28:26 +09:00
return err
}