From 015d5b904a9700e9d65c53166e3ed20c86981914 Mon Sep 17 00:00:00 2001 From: ScuroNeko Date: Thu, 22 Jan 2026 13:47:18 +0300 Subject: [PATCH] inline keyboard --- database/psql/rp.go | 12 +- plugins/economy.go | 2 +- plugins/logs.go | 3 + plugins/rp.go | 259 ++++++++++++++++++++++++------------- scripts/postgres/06-rp.sql | 3 +- 5 files changed, 180 insertions(+), 99 deletions(-) diff --git a/database/psql/rp.go b/database/psql/rp.go index 58136a9..a1c6896 100644 --- a/database/psql/rp.go +++ b/database/psql/rp.go @@ -3,6 +3,7 @@ package psql import ( "database/sql" "errors" + "kurumibot/laniakea" "github.com/vinovest/sqlx" ) @@ -15,9 +16,10 @@ type RPGeneralPreset struct { PostHistory string `db:"post_history"` } type RPScenarios struct { - ID int - Name string - Prompt string + ID int + Name string + Description string + Prompt string } type RPUser struct { UserID int64 `db:"user_id"` @@ -30,8 +32,8 @@ type RPRepository struct { db *sqlx.DB } -func NewRPRepository(db *sqlx.DB) *RPRepository { - return &RPRepository{db: db} +func NewRPRepository(db *laniakea.DatabaseContext) *RPRepository { + return &RPRepository{db: db.PostgresSQL} } func (rep *RPRepository) GetOrCreateUser(id int64) (*RPUser, error) { diff --git a/plugins/economy.go b/plugins/economy.go index 2bcb7d7..2d6938e 100644 --- a/plugins/economy.go +++ b/plugins/economy.go @@ -37,7 +37,7 @@ func RegisterEconomy(bot *laniakea.Bot) { func about(ctx *laniakea.MsgContext, _ *laniakea.DatabaseContext) { out := []string{ - fmt.Sprintf("Go: %s", runtime.Version()), + fmt.Sprintf("Версия Go: %s", runtime.Version()[2:]), fmt.Sprintf("Версия Laniakea: %s", laniakea.VersionString), fmt.Sprintf("Время сборки: %s", utils.BuildTime), fmt.Sprintf("Git хеш: %s", utils.GitCommit), diff --git a/plugins/logs.go b/plugins/logs.go index 9a8a05b..0b7c60d 100644 --- a/plugins/logs.go +++ b/plugins/logs.go @@ -16,6 +16,9 @@ func InitLogMiddleware() *laniakea.Middleware { } func logMiddleware(ctx *laniakea.MsgContext, db *laniakea.DatabaseContext) { + if ctx.Msg == nil { + return + } entry := &mdb.MessageLogEntry{ MessageID: ctx.Msg.MessageID, SenderID: ctx.FromID, diff --git a/plugins/rp.go b/plugins/rp.go index ad6179d..7ab65d6 100644 --- a/plugins/rp.go +++ b/plugins/rp.go @@ -17,66 +17,124 @@ import ( func RegisterRP(bot *laniakea.Bot) { rp := laniakea.NewPlugin("RP") - rp = rp.Command(selectWaifu, "rpwaifu", "рпвайфу") - rp = rp.Payload(selectWaifu, "rp.selwaifu") - rp = rp.Command(rpPresetsList, "rpplist") - rp = rp.Command(rpPresetSet, "rppset") - rp = rp.Command(rpScenarioList, "rpscenlist") - rp = rp.Command(newChat, "newchat") + rp = rp.Command(rpInfo, "rp", "рп") + rp = rp.Payload(rpInfo, "rp.info") + + rp = rp.Payload(rpWaifuList, "rp.waifu_list") + rp = rp.Payload(rpWaifuSet, "rp.waifu_set") + rp = rp.Payload(rpPresetsList, "rp.preset_list") + rp = rp.Payload(rpPresetSet, "rp.preset_set") + rp = rp.Payload(rpScenarioList, "rp.scenario_list") + rp = rp.Payload(rpScenarioSet, "rp.scenario_set") + rp = rp.Payload(chatStat, "rp.tokens") + rp = rp.Payload(newChat, "rp.new_chat") + rp = rp.Command(rpUserPromptGet, "rpuserpget") rp = rp.Command(rpUserPromptSet, "rpuserpset") rp = rp.Command(generate, "g", "gen", "г") - rp = rp.Command(chatStat, "chatstat") - rp = rp.Payload(debugTokens, "rp.tokens") + rp = rp.Payload(compress, "rp.compress_chat") bot.AddPlugins(rp.Build()) } -func debugTokens(ctx *laniakea.MsgContext, db *laniakea.DatabaseContext) { - rep := red.NewRPRepository(db) - waifuId := rep.GetSelectedWaifu(ctx.FromID) - tokens := rep.GetChatTokens(ctx.FromID, waifuId) - ctx.Answerf("%d", tokens) +func rpInfo(ctx *laniakea.MsgContext, db *laniakea.DatabaseContext) { + rpRepRed := red.NewRPRepository(db) + rpRepPsql := psql.NewRPRepository(db) + waifuId := rpRepRed.GetSelectedWaifu(ctx.FromID) + waifu, err := psql.GetWaifuById(waifuId) + if err != nil { + ctx.Error(err) + } + rpUser, err := rpRepPsql.GetUser(int64(ctx.FromID)) + if err != nil { + ctx.Error(err) + } + out := []string{ + fmt.Sprintf("Привет, %s!", ctx.From.FirstName), + fmt.Sprintf("Выбранная вайфу: %s", waifu.Name), + fmt.Sprintf("Выбранный пресет: %s", "_TODO_"), + fmt.Sprintf("Выбранный сценарий: %s", "_TODO_"), + fmt.Sprintf("Твое описание персонажа: %s", rpUser.UserPrompt), + } + + kb := laniakea.NewInlineKeyboard(1) + kb.AddCallbackButton("Статистика чата", "rp.tokens") + kb.AddCallbackButton("Сменить пресет", "rp.preset_list") + kb.AddCallbackButton("Выбрать сценарий", "rp.scenario_list") + kb.AddCallbackButton("Сменить вайфу", "rp.waifu_list") + kb.AddCallbackButton("Новый чат", "rp.new_chat") + if ctx.CallbackMsgId > 0 { + ctx.EditCallback(strings.Join(out, "\n"), kb) + } else { + ctx.Keyboard(strings.Join(out, "\n"), kb) + } } -func selectWaifu(ctx *laniakea.MsgContext, db *laniakea.DatabaseContext) { +func rpWaifuList(ctx *laniakea.MsgContext, db *laniakea.DatabaseContext) { + waifus, err := psql.GetUserWaifus(ctx.FromID) + if err != nil { + ctx.Error(err) + return + } + + out := make([]string, len(waifus)) + kb := laniakea.NewInlineKeyboard(2) + for i, waifu := range waifus { + out[i] = fmt.Sprintf("*%s* %d\\* из \"%s\"", waifu.Name, waifu.Rarity, waifu.Fandom) + kb.AddCallbackButton(waifu.Name, "rp.waifu_set", waifu.ID) + } + kb.AddLine() + kb.AddCallbackButton("На главную", "rp.info") + ctx.EditCallback(strings.Join(out, "\n"), kb) +} +func rpWaifuSet(ctx *laniakea.MsgContext, db *laniakea.DatabaseContext) { waifuId, err := strconv.Atoi(ctx.Args[0]) if err != nil { ctx.Error(err) return } - rpRep := red.NewRPRepository(db) - err = rpRep.SetSelectedWaifu(ctx.FromID, waifuId) + rpRepRed := red.NewRPRepository(db) + err = rpRepRed.SetSelectedWaifu(ctx.FromID, waifuId) if err != nil { ctx.Error(err) return } + //rpRepPsql := psql.NewRPRepository(db) + waifu, err := psql.GetWaifuById(waifuId) + if err != nil { + ctx.Error(err) + } - ctx.Answer(fmt.Sprintf("Была выбрана вайфу %d", waifuId)) + kb := laniakea.NewInlineKeyboard(1).AddCallbackButton("На главную", "rp.info") + ctx.EditCallbackf("Была выбрана вайфу %s", kb, waifu.Name) } func rpPresetsList(ctx *laniakea.MsgContext, db *laniakea.DatabaseContext) { - rep := psql.NewRPRepository(db.PostgresSQL) + rep := psql.NewRPRepository(db) presets, err := rep.GetAllPresets() if err != nil { ctx.Error(err) return } out := make([]string, len(presets)) + kb := laniakea.NewInlineKeyboard(2) for i, preset := range presets { out[i] = fmt.Sprintf( - "%s) *%s*\n%s", - preset.ID, laniakea.EscapeMarkdown(preset.Name), preset.Description, + "*%s*\n%s", + laniakea.EscapeMarkdown(preset.Name), preset.Description, ) + kb.AddCallbackButton(preset.Name, "rp.preset_set", preset.ID) } - ctx.Answer(strings.Join(out, "\n")) + kb.AddLine() + kb.AddCallbackButton("Назад", "rp.info") + ctx.EditCallback(strings.Join(out, "\n"), kb) } func rpPresetSet(ctx *laniakea.MsgContext, db *laniakea.DatabaseContext) { if len(ctx.Args) == 0 || ctx.Args[0] == "" { return } presetId := ctx.Args[0] - rep := psql.NewRPRepository(db.PostgresSQL) + rep := psql.NewRPRepository(db) user, err := rep.GetOrCreateUser(int64(ctx.FromID)) if err != nil { ctx.Error(err) @@ -91,21 +149,61 @@ func rpPresetSet(ctx *laniakea.MsgContext, db *laniakea.DatabaseContext) { } return } - ctx.Answer(fmt.Sprintf("Был выбран пресет %s", preset.Name)) + + kb := laniakea.NewInlineKeyboard(1).AddCallbackButton("На главную", "rp.info") + ctx.EditCallbackf("Был выбран пресет %s", kb, preset.Name) } func rpScenarioList(ctx *laniakea.MsgContext, db *laniakea.DatabaseContext) { - rep := psql.NewRPRepository(db.PostgresSQL) + rep := psql.NewRPRepository(db) scenarios, err := rep.GetAllScenarios() if err != nil { ctx.Error(err) return } out := make([]string, len(scenarios)) + kb := laniakea.NewInlineKeyboard(2) for i, scenario := range scenarios { - out[i] = fmt.Sprintf("%d) *%s*", scenario.ID, scenario.Name) + out[i] = fmt.Sprintf("%d) *%s*\n%s\n", scenario.ID, scenario.Name, scenario.Description) + kb.AddCallbackButton(scenario.Name, "rp.scenario_set", scenario.ID) } - ctx.Answer(strings.Join(out, "\n")) + kb.AddLine() + kb.AddCallbackButton("На главную", "rp.info") + ctx.EditCallback(strings.Join(out, "\n"), kb) +} +func rpScenarioSet(ctx *laniakea.MsgContext, db *laniakea.DatabaseContext) {} + +func chatStat(ctx *laniakea.MsgContext, db *laniakea.DatabaseContext) { + redisRpRep := red.NewRPRepository(db) + waifuId := redisRpRep.GetSelectedWaifu(ctx.FromID) + if waifuId == 0 { + ctx.Answer("Не выбрана вайфу") + return + } + chatId := redisRpRep.GetChatId(ctx.FromID, waifuId) + if chatId == "" { + chatId = uuid.New().String() + err := redisRpRep.SetChatId(ctx.FromID, waifuId, chatId) + if err != nil { + ctx.Error(err) + return + } + } + messageCount, err := mdb.GetChatHistorySize(db, chatId) + if err != nil { + ctx.Error(err) + return + } + + tokens := redisRpRep.GetChatTokens(ctx.FromID, waifuId) + kb := laniakea.NewInlineKeyboard(1).AddCallbackButton("На главную", "rp.info") + out := []string{ + "Статистика чата", + fmt.Sprintf("ID: `%s`", chatId), + fmt.Sprintf("Кол-во сообщений: %d", messageCount), + fmt.Sprintf("Кол-во токенов: %d", tokens), + } + ctx.EditCallback(strings.Join(out, "\n"), kb) } func newChat(ctx *laniakea.MsgContext, db *laniakea.DatabaseContext) { redisRpRep := red.NewRPRepository(db) @@ -126,7 +224,7 @@ func newChat(ctx *laniakea.MsgContext, db *laniakea.DatabaseContext) { ctx.Error(err) return } - rep := psql.NewRPRepository(db.PostgresSQL) + rep := psql.NewRPRepository(db) scenario, err := rep.GetScenario(scenarioId) if err != nil { if errors.Is(err, sql.ErrNoRows) { @@ -155,7 +253,7 @@ func newChat(ctx *laniakea.MsgContext, db *laniakea.DatabaseContext) { } func rpUserPromptGet(ctx *laniakea.MsgContext, db *laniakea.DatabaseContext) { - rep := psql.NewRPRepository(db.PostgresSQL) + rep := psql.NewRPRepository(db) user, err := rep.GetOrCreateUser(int64(ctx.FromID)) if err != nil { ctx.Error(err) @@ -172,7 +270,7 @@ func rpUserPromptSet(ctx *laniakea.MsgContext, db *laniakea.DatabaseContext) { return } prompt := strings.Join(ctx.Args[1:], " ") - rep := psql.NewRPRepository(db.PostgresSQL) + rep := psql.NewRPRepository(db) user, err := rep.GetOrCreateUser(int64(ctx.FromID)) if err != nil { ctx.Error(err) @@ -208,7 +306,7 @@ func generate(ctx *laniakea.MsgContext, db *laniakea.DatabaseContext) { ctx.Error(err) return } - rpRep := psql.NewRPRepository(db.PostgresSQL) + rpRep := psql.NewRPRepository(db) rpUser, err := rpRep.GetUser(int64(ctx.FromID)) if err != nil { ctx.Error(err) @@ -222,14 +320,14 @@ func generate(ctx *laniakea.MsgContext, db *laniakea.DatabaseContext) { userPrompt := "" if rpUser.UserPrompt != "" { - userPrompt = fmt.Sprintf("Вот описание моего персонажа %s ", rpUser.UserPrompt) + userPrompt = fmt.Sprintf("Вот описание моего персонажа %s.", rpUser.UserPrompt) } beforeHistory := ai.Message{ Role: "system", Content: fmt.Sprintf( "%s %s %s %s", ai.FormatPrompt(preset.PreHistory, waifu.Name, ctx.Msg.From.FirstName), - fmt.Sprintf("Вот краткое описание твоего персонажа: %s", waifu.RpPrompt), + fmt.Sprintf("Вот краткое описание твоего персонажа: %s.", waifu.RpPrompt), userPrompt, redisRpRep.GetChatPrompt(ctx.FromID, waifuId), ), @@ -298,65 +396,12 @@ func generate(ctx *laniakea.MsgContext, db *laniakea.DatabaseContext) { } m.Delete() - //kb := laniakea.NewInlineKeyboard() - //kb.AddCallbackButton("Перегенерировать", laniakea.CallbackData{Command: "rp.tokens"}) - //ctx.Keyboard("Test", kb) - ctx.Answer(laniakea.EscapeMarkdown(agentAnswer.Content)) - - //counter := redisRpRep.GetCounter(ctx.FromID, waifuId) + 1 - //if counter == 20 { - // m := ctx.Answer("Запущено сжатие чата.") - // history, err = mdb.GetChatHistory(db, chatId) - // if err != nil { - // ctx.Error(err) - // return - // } - // - // messages = make([]ai.Message, 0) - // for _, m := range history { - // messages = append(messages, ai.Message{ - // Role: m.Role, - // Content: m.Message, - // }) - // } - // res, err = api.CompressChat(messages) - // if err != nil { - // ctx.Error(err) - // } - // if len(res.Choices) == 0 { - // m.Edit("Не удалось сжать диалог") - // return - // } - // - // compressedHistory := res.Choices[0].Message.Content - // - // chatId = uuid.New().String() - // err := redisRpRep.SetChatId(ctx.FromID, waifuId, chatId) - // if err != nil { - // ctx.Error(err) - // return - // } - // - // err = mdb.UpdateChatHistory(db, chatId, "assistant", compressedHistory) - // if err != nil { - // ctx.Error(err) - // return - // } - // err = mdb.UpdateChatHistory(db, chatId, agentAnswer.Role, agentAnswer.Content) - // if err != nil { - // ctx.Error(err) - // return - // } - // counter = 0 - // m.Edit("Сжатие завершено") - //} - //err = redisRpRep.SetCounter(ctx.FromID, waifuId, counter) - //if err != nil { - // ctx.Error(err) - //} + kb := laniakea.NewInlineKeyboard(1).AddCallbackButton("Сжать чать", "rp.compress_chat") + ctx.Keyboard(laniakea.EscapeMarkdown(agentAnswer.Content), kb) } -func chatStat(ctx *laniakea.MsgContext, db *laniakea.DatabaseContext) { +func compress(ctx *laniakea.MsgContext, db *laniakea.DatabaseContext) { + m := ctx.Answer("Запущено сжатие чата.") redisRpRep := red.NewRPRepository(db) waifuId := redisRpRep.GetSelectedWaifu(ctx.FromID) if waifuId == 0 { @@ -372,12 +417,42 @@ func chatStat(ctx *laniakea.MsgContext, db *laniakea.DatabaseContext) { return } } - messageCount, err := mdb.GetChatHistorySize(db, chatId) + history, err := mdb.GetChatHistory(db, chatId) if err != nil { ctx.Error(err) return } - tokens := redisRpRep.GetChatTokens(ctx.FromID, waifuId) - ctx.Answerf("Кол-во сообщений: %d\nКол-во токенов: %d", messageCount, tokens) + messages := make([]ai.Message, 0) + for _, m := range history { + messages = append(messages, ai.Message{ + Role: m.Role, + Content: m.Message, + }) + } + api := ai.NewOpenAIAPI(ai.GPTBaseUrl, "", "deepseek-ai/deepseek-v3.1-terminus") + res, err := api.CompressChat(messages) + if err != nil { + ctx.Error(err) + } + if len(res.Choices) == 0 { + m.Edit("Не удалось сжать диалог") + return + } + + compressedHistory := res.Choices[0].Message.Content + + chatId = uuid.New().String() + err = redisRpRep.SetChatId(ctx.FromID, waifuId, chatId) + if err != nil { + ctx.Error(err) + return + } + + err = mdb.UpdateChatHistory(db, chatId, "assistant", compressedHistory) + if err != nil { + ctx.Error(err) + return + } + m.Edit("Сжатие завершено") } diff --git a/scripts/postgres/06-rp.sql b/scripts/postgres/06-rp.sql index 464b1ff..24455bb 100644 --- a/scripts/postgres/06-rp.sql +++ b/scripts/postgres/06-rp.sql @@ -1,7 +1,7 @@ CREATE TABLE rp_general_presets( id text NOT NULL PRIMARY KEY, name text NOT NULL, - description text NOT NULL DEFAULT '', + description text NOT NULL DEFAULT 'Нет описания', pre_history text NOT NULL DEFAULT '', post_history text NOT NULL DEFAULT '' ); @@ -9,6 +9,7 @@ CREATE UNIQUE INDEX rp_general_presets_uindex ON rp_general_presets(id); CREATE TABLE rp_scenarios( id serial NOT NULL, name text NOT NULL, + description text NOT NULL DEFAULT 'Нет описания', prompt text NOT NULL ); CREATE UNIQUE INDEX rp_scenarios_uindex ON rp_scenarios(id);