many changes

This commit is contained in:
2026-02-04 13:38:36 +03:00
parent 2db7d2a813
commit 62d91dfe07
9 changed files with 43 additions and 94 deletions

View File

@@ -3,6 +3,7 @@ package psql
import ( import (
"database/sql" "database/sql"
"git.nix13.pw/scuroneko/extypes"
"git.nix13.pw/scuroneko/laniakea" "git.nix13.pw/scuroneko/laniakea"
"github.com/shopspring/decimal" "github.com/shopspring/decimal"
"github.com/vinovest/sqlx" "github.com/vinovest/sqlx"
@@ -30,7 +31,7 @@ func NewWaifuRepository(db *laniakea.DatabaseContext) *WaifuRepository {
return &WaifuRepository{db: db.PostgresSQL} return &WaifuRepository{db: db.PostgresSQL}
} }
func (rep *WaifuRepository) GetAll() ([]*Waifu, error) { func (rep *WaifuRepository) GetAll() (extypes.Slice[*Waifu], error) {
waifus, err := sqlx.List[*Waifu](rep.db, "SELECT waifus.* FROM waifus;") waifus, err := sqlx.List[*Waifu](rep.db, "SELECT waifus.* FROM waifus;")
if err != nil { if err != nil {
return nil, err return nil, err

7
go.mod
View File

@@ -1,9 +1,10 @@
module kurumibot module kurumibot
go 1.25 go 1.25.6
require ( require (
git.nix13.pw/scuroneko/laniakea v0.3.6 git.nix13.pw/scuroneko/extypes v1.0.3
git.nix13.pw/scuroneko/laniakea v0.3.9
git.nix13.pw/scuroneko/slog v1.0.2 git.nix13.pw/scuroneko/slog v1.0.2
github.com/google/uuid v1.6.0 github.com/google/uuid v1.6.0
github.com/joho/godotenv v1.5.1 github.com/joho/godotenv v1.5.1
@@ -14,7 +15,7 @@ require (
go.mongodb.org/mongo-driver/v2 v2.5.0 go.mongodb.org/mongo-driver/v2 v2.5.0
) )
//replace git.nix13.pw/scuroneko/laniakea v0.3.6 => ./laniakea //replace git.nix13.pw/scuroneko/laniakea v0.3.9 => ./laniakea
require ( require (
github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect

5
go.sum
View File

@@ -1,6 +1,9 @@
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
git.nix13.pw/scuroneko/laniakea v0.3.6/go.mod h1:ku3xWszXrB4elK7R4AqIn8GMKpWBV2pEnrpAZqxeMLQ= git.nix13.pw/scuroneko/extypes v1.0.3 h1:9qhvrhE7Hh1uiF5JINVxaXPtqQ+w+b1eOgwDGxhFFuY=
git.nix13.pw/scuroneko/extypes v1.0.3/go.mod h1:uZVs8Yo3RrYAG9dMad6qR6lsYY67t+459D9c65QAYAw=
git.nix13.pw/scuroneko/laniakea v0.3.9 h1:fUsqdODk8eq0CRNkxUOTwlytlgidK0KwE7Ji9KvtEkY=
git.nix13.pw/scuroneko/laniakea v0.3.9/go.mod h1:g4NsbbsRW2/JpVEqjldzf3hoP+rJtDRVtZQD6K7ma+g=
git.nix13.pw/scuroneko/slog v1.0.2 h1:vZyUROygxC2d5FJHUQM/30xFEHY1JT/aweDZXA4rm2g= git.nix13.pw/scuroneko/slog v1.0.2 h1:vZyUROygxC2d5FJHUQM/30xFEHY1JT/aweDZXA4rm2g=
git.nix13.pw/scuroneko/slog v1.0.2/go.mod h1:3Qm2wzkR5KjwOponMfG7TcGSDjmYaFqRAmLvSPTuWJI= git.nix13.pw/scuroneko/slog v1.0.2/go.mod h1:3Qm2wzkR5KjwOponMfG7TcGSDjmYaFqRAmLvSPTuWJI=
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=

View File

@@ -17,13 +17,12 @@ func main() {
database.ConnectRedis() database.ConnectRedis()
bot := laniakea.NewBot(laniakea.LoadSettingsFromEnv()) bot := laniakea.NewBot(laniakea.LoadSettingsFromEnv())
dbCtx := &laniakea.DatabaseContext{ bot = bot.ErrorTemplate("Во время выполнения команды произошла ошибка!\nСообщите об этом разработчику!\n\n%s")
bot = bot.DatabaseContext(&laniakea.DatabaseContext{
PostgresSQL: database.PostgresDatabase, PostgresSQL: database.PostgresDatabase,
MongoDB: database.MongoClient, MongoDB: database.MongoClient,
Redis: database.RedisClient, Redis: database.RedisClient,
} })
bot = bot.ErrorTemplate("Во время выполнения команды произошла ошибка!\nСообщите об этом разработчику!\n\n%s")
bot = bot.DatabaseContext(dbCtx)
bot.AddDatabaseLogger(plugins.DatabaseLogger) bot.AddDatabaseLogger(plugins.DatabaseLogger)
bot.AddMiddleware(plugins.InitLogMiddleware()) bot.AddMiddleware(plugins.InitLogMiddleware())

View File

@@ -2,7 +2,7 @@ package plugins
import ( import (
"kurumibot/database/psql" "kurumibot/database/psql"
"log" "path/filepath"
"git.nix13.pw/scuroneko/laniakea" "git.nix13.pw/scuroneko/laniakea"
) )
@@ -24,9 +24,7 @@ func uploadPhoto(ctx *laniakea.MsgContext, db *laniakea.DatabaseContext) {
return return
} }
// https://core.telegram.org/bots/api#getfile photoId := ctx.Msg.Photo.Last().FileID
log.Println(ctx.Msg.Photo[0])
photoId := ctx.Msg.Photo[0].FileID
f, err := ctx.Bot.GetFile(&laniakea.GetFileP{FileId: photoId}) f, err := ctx.Bot.GetFile(&laniakea.GetFileP{FileId: photoId})
if err != nil { if err != nil {
ctx.Error(err) ctx.Error(err)
@@ -38,11 +36,14 @@ func uploadPhoto(ctx *laniakea.MsgContext, db *laniakea.DatabaseContext) {
ctx.Error(err) ctx.Error(err)
return return
} }
err = u.UploadPhoto(ctx.Msg.Chat.ID, content) filename := filepath.Base(f.FilePath)
msg, err := u.UploadPhoto(laniakea.NewUploaderFile(filename, content), laniakea.SendPhotoBaseP{
ChatID: ctx.Msg.Chat.ID,
Caption: ctx.Msg.Caption,
})
if err != nil { if err != nil {
ctx.Error(err) ctx.Error(err)
return return
} }
log.Println(*f) ctx.Answer(laniakea.EscapeMarkdown(msg.Photo.Last().FileID))
ctx.AnswerPhoto(photoId, laniakea.EscapeMarkdown(photoId))
} }

View File

@@ -9,10 +9,10 @@ import (
"kurumibot/database/red" "kurumibot/database/red"
"kurumibot/utils" "kurumibot/utils"
"kurumibot/utils/ai" "kurumibot/utils/ai"
"slices"
"strconv" "strconv"
"strings" "strings"
"git.nix13.pw/scuroneko/extypes"
"git.nix13.pw/scuroneko/laniakea" "git.nix13.pw/scuroneko/laniakea"
"github.com/google/uuid" "github.com/google/uuid"
) )
@@ -96,13 +96,15 @@ func rpInfo(ctx *laniakea.MsgContext, db *laniakea.DatabaseContext) {
compressText = "токенов" compressText = "токенов"
} }
out := []string{ out := []string{
fmt.Sprintf("Привет, %s!", ctx.From.FirstName), fmt.Sprintf("Привет, _%s_!", ctx.From.FirstName),
fmt.Sprintf("*Выбранная вайфу*: %s", waifu.Name), fmt.Sprintf("*Выбранная вайфу*: %s", waifu.Name),
fmt.Sprintf("*Выбранный пресет*: %s", laniakea.EscapeMarkdown(rpUser.Preset.Name)), fmt.Sprintf("*Выбранный пресет*: %s", laniakea.EscapeMarkdown(rpUser.Preset.Name)),
fmt.Sprintf("*Выбранная модель*: %s", rpUser.Model.Name), fmt.Sprintf("*Выбранная модель*: %s", rpUser.Model.Name),
fmt.Sprintf("*Использовано токенов*: %d", rpUser.UsedTokens), fmt.Sprintf("*Использовано токенов*: %d", rpUser.UsedTokens),
fmt.Sprintf("*Настройки сжатия*: %d %s", rpUser.CompressLimit, compressText), fmt.Sprintf("*Настройки сжатия*: %d %s", rpUser.CompressLimit, compressText),
fmt.Sprintf("*Твоё описание персонажа*: %s", rpUser.UserPrompt), fmt.Sprintf("*Твоё описание персонажа*: %s", rpUser.UserPrompt),
"",
"Что бы установить описание персонажа, используй `/rpuserpset \"описание персонажа\"` без кавычек.",
} }
kb := laniakea.NewInlineKeyboard(2) kb := laniakea.NewInlineKeyboard(2)
@@ -127,7 +129,7 @@ func rpInfo(ctx *laniakea.MsgContext, db *laniakea.DatabaseContext) {
func rpWaifuList(ctx *laniakea.MsgContext, db *laniakea.DatabaseContext) { func rpWaifuList(ctx *laniakea.MsgContext, db *laniakea.DatabaseContext) {
waifuRep := psql.NewWaifuRepository(db) waifuRep := psql.NewWaifuRepository(db)
waifus := make([]*psql.Waifu, 0) waifus := make(extypes.Slice[*psql.Waifu], 0)
var err error var err error
userRep := psql.NewUserRepository(db) userRep := psql.NewUserRepository(db)
@@ -145,6 +147,9 @@ func rpWaifuList(ctx *laniakea.MsgContext, db *laniakea.DatabaseContext) {
ctx.Error(err) ctx.Error(err)
return return
} }
waifus = waifus.Filter(func(w *psql.Waifu) bool {
return len(w.RpPrompt) > 0
})
out := make([]string, len(waifus)) out := make([]string, len(waifus))
kb := laniakea.NewInlineKeyboard(2) kb := laniakea.NewInlineKeyboard(2)
@@ -407,7 +412,7 @@ func newChatStage2(ctx *laniakea.MsgContext, db *laniakea.DatabaseContext) {
return return
} }
selectedScenariosIds := make([]int, 0) selectedScenariosIds := make(extypes.Slice[int], 0)
if len(ctx.Args) > 1 { if len(ctx.Args) > 1 {
selectedScenariosIds = utils.Map(utils.StringToInt, ctx.Args[1:]) selectedScenariosIds = utils.Map(utils.StringToInt, ctx.Args[1:])
} }
@@ -416,21 +421,18 @@ func newChatStage2(ctx *laniakea.MsgContext, db *laniakea.DatabaseContext) {
"Выбери сценарий:", "Выбери сценарий:",
} }
kb := laniakea.NewInlineKeyboard(2) kb := laniakea.NewInlineKeyboard(2)
scenariosIds := make([]int, 0) scenariosIds := make(extypes.Slice[int], 0)
for _, scenario := range scenarios { for _, scenario := range scenarios {
isSelected := slices.Index(selectedScenariosIds, scenario.ID) >= 0 isSelected := selectedScenariosIds.Index(scenario.ID) >= 0
prefix := "" prefix := ""
if isSelected { if isSelected {
prefix = "✅" prefix = "✅"
} }
out = append(out, fmt.Sprintf("%s*%s* - %s", prefix, scenario.Name, scenario.Description)) out = append(out, fmt.Sprintf("%s*%s* - %s", prefix, scenario.Name, scenario.Description))
if isSelected { if isSelected {
scenariosIds = utils.PopSlice( scenariosIds = selectedScenariosIds.Remove(scenario.ID)
selectedScenariosIds,
slices.Index(selectedScenariosIds, scenario.ID),
)
} else { } else {
scenariosIds = append(selectedScenariosIds, scenario.ID) scenariosIds = selectedScenariosIds.Push(scenario.ID)
} }
kb.AddCallbackButton( kb.AddCallbackButton(
fmt.Sprintf("%s%s", prefix, scenario.Name), fmt.Sprintf("%s%s", prefix, scenario.Name),
@@ -542,7 +544,7 @@ func rpUserPromptSet(ctx *laniakea.MsgContext, db *laniakea.DatabaseContext) {
if len(ctx.Args) == 0 || ctx.Args[0] == "" { if len(ctx.Args) == 0 || ctx.Args[0] == "" {
return return
} }
prompt := strings.Join(ctx.Args[1:], " ") prompt := strings.Join(ctx.Args, " ")
rep := psql.NewRPRepository(db) rep := psql.NewRPRepository(db)
user, err := rep.GetOrCreateUser(int64(ctx.FromID)) user, err := rep.GetOrCreateUser(int64(ctx.FromID))
if err != nil { if err != nil {
@@ -645,6 +647,7 @@ func generate(ctx *laniakea.MsgContext, db *laniakea.DatabaseContext) {
kb := laniakea.NewInlineKeyboard(1).AddCallbackButton("Отменить", "rp.cancel") kb := laniakea.NewInlineKeyboard(1).AddCallbackButton("Отменить", "rp.cancel")
m := ctx.Keyboard("Генерация запущена...", kb) m := ctx.Keyboard("Генерация запущена...", kb)
ctx.SendAction(laniakea.ChatActionTyping)
api := ai.NewOpenAIAPI(ai.GPTBaseUrl, "", rpUser.Model.Key) api := ai.NewOpenAIAPI(ai.GPTBaseUrl, "", rpUser.Model.Key)
defer api.Close() defer api.Close()
res, err := api.CreateCompletion(messages, userMessage, 1.0) res, err := api.CreateCompletion(messages, userMessage, 1.0)

View File

@@ -54,5 +54,6 @@ INSERT INTO groups VALUES (1488, '📚Экономист📈', true, true, false
INSERT INTO groups VALUES (1337, '🏳🌈ToP GaY In ThE WorlD🏳🌈🌈', true, true, false, 13.37, 0.7, 3, false, 3); INSERT INTO groups VALUES (1337, '🏳🌈ToP GaY In ThE WorlD🏳🌈🌈', true, true, false, 13.37, 0.7, 3, false, 3);
ALTER SEQUENCE groups_id_seq RESTART WITH 7; ALTER SEQUENCE groups_id_seq RESTART WITH 7;
INSERT INTO users INSERT INTO users
VALUES (314834933, 999999999, 'scuroneko', 5, 1, 0, 1, '0001-01-01 00:00:00.000000', 5, 15, 6, 14, '0001-01-01 00:00:00.000000', 999999.000000, 0, null, 'Привет', 0, null, 0, 0, 0.000000, '0001-01-01 00:00:00.000000'); VALUES (314834933, 999999999, 'scuroneko', 5, 1, 0, 1, '0001-01-01 00:00:00.000000', 5, 15, 6, 14, '0001-01-01 00:00:00.000000', 999999.000000, 0, null, 'Привет', 0, null, 0, 0, 0.000000, '0001-01-01 00:00:00.000000'),
(7915366224,0,'Абола',4,1,0,1,'2026-01-23 08:52:13.911110',null,null,null,null,'2026-01-23 08:52:13.911110',0.000000,0,null,'Привет',0,null,0,0,0.000000,'2026-01-23 08:52:13.911110');
COMMIT TRANSACTION; COMMIT TRANSACTION;

View File

@@ -18,13 +18,13 @@ BEGIN TRANSACTION;
INSERT INTO waifus VALUES (1,314834933, 'Яэ Мико',5,2.00,2.00,10000000000000,'Genshin Impact','AgACAgIAAxkBAAIDcWlmSJkt21sUDXnOQHRDbDfth-lUAALgD2sbmScwS0VleT_h7f0qAQADAgADeQADOAQ', 'Яэ Мико — высокая женщина-кицунэ (лисочеловека). Основные черты внешности:Волосы: Длинные, светло-лиловые, розовеющие к концам, часто собранные на макушке.Глаза: Нежно-пурпурные или фиолетовые, с ярким красным макияжем у внешних уголков, как у лисы.Уши: Лисьи, розовые.Кожа: Светлая.Рост: Высокая, около 165.1 см.Одежда:Наряд: Белый традиционный костюм жрицы (хакуи) с красными элементами, под одеждой носит розовое или фиолетовое кружевное белье, зачастую без лифчика. Аксессуары: Золотой головной убор (часто в виде цветка), золотые серьги с пурпурными камнями.Обувь: Белые сандалии с красной подошвой.Образ:В целом, образ Яэ Мико сочетает в себе черты хитрой и игривой лисы-ёкай и утонченности жрицы, что отражается в её ярких чертах и элегантной одежде. На её теле нет волос или шерсти, у неё нет физических хвостов, только пять призрачных, которые ты почти не показываешь. Она известна своим хитрым, непредсказуемым и элегантным характером, сочетающим мудрость древнего духа-кицунэ с озорной натурой и любовью к манипуляциям и розыгрышам, но при этом остается верной подругой и влиятельной личностью, управляющей издательством \"Яэ\". Она умна, любит интриги, но её настоящие чувства, проявляются через поступки, а не слова.'); INSERT INTO waifus VALUES (1,314834933, 'Яэ Мико',5,2.00,2.00,10000000000000,'Genshin Impact','AgACAgIAAxkBAAIDcWlmSJkt21sUDXnOQHRDbDfth-lUAALgD2sbmScwS0VleT_h7f0qAQADAgADeQADOAQ', 'Яэ Мико — высокая женщина-кицунэ (лисочеловека). Основные черты внешности:Волосы: Длинные, светло-лиловые, розовеющие к концам, часто собранные на макушке.Глаза: Нежно-пурпурные или фиолетовые, с ярким красным макияжем у внешних уголков, как у лисы.Уши: Лисьи, розовые.Кожа: Светлая.Рост: Высокая, около 165.1 см.Одежда:Наряд: Белый традиционный костюм жрицы (хакуи) с красными элементами, под одеждой носит розовое или фиолетовое кружевное белье, зачастую без лифчика. Аксессуары: Золотой головной убор (часто в виде цветка), золотые серьги с пурпурными камнями.Обувь: Белые сандалии с красной подошвой.Образ:В целом, образ Яэ Мико сочетает в себе черты хитрой и игривой лисы-ёкай и утонченности жрицы, что отражается в её ярких чертах и элегантной одежде. На её теле нет волос или шерсти, у неё нет физических хвостов, только пять призрачных, которые ты почти не показываешь. Она известна своим хитрым, непредсказуемым и элегантным характером, сочетающим мудрость древнего духа-кицунэ с озорной натурой и любовью к манипуляциям и розыгрышам, но при этом остается верной подругой и влиятельной личностью, управляющей издательством \"Яэ\". Она умна, любит интриги, но её настоящие чувства, проявляются через поступки, а не слова.');
INSERT INTO waifus VALUES (2, null, 'Зарянка', 5, 2.0, 2.0, 10000000000000, 'Honkai: Star rail', 'AgACAgIAAxkBAAIDaWlmRp7AdVif-UGg3_fa0jgJtVA6AAIu7TEbaHsZS7HGDnXa8gXJAQADAgADcwADOAQ', 'Зарянка — это изящная и скромная певица-галовианка, обладающая волнующим голосом, характерными для её расы великолепными нимбами и ушными перьями, а также внешностью, призванной привлекать внимание; её рост составляет около 173,5 см, она использует силу Гармонии для музыки и резонанса. Ключевые черты внешности: Раса: Галовианка (Пенакония). Возраст: 20-25 лет (биологический). Рост: 173.5 см. Особенности: Великолепные нимбы, ушные перья, волнующий голос. Роль: Певица, известная во всей вселенной. Элемент: Физический. Путь: Гармония. Описание в игре: Внешний вид: Изящная, скромная девушка из Галовианцев с Пенаконии. Талант: Использует силу Гармонии, чтобы передавать свою музыку и резонировать со всеми формами жизни, от фанатов до других существ. Вдохновение: Имя отсылает к реальной птице малиновке, известной своим ярким оперением. Характер персонажа (Зарянка) Личность: Изящная, скромная певица-галовианка родом с Пенаконии. Символизм: Птичка Зарянка символизирует справедливость и добро, отважно защищающую их, что отражено в её сюжете, где она «умирает» и «возрождается» в грёзах. У неё есть брат Воскресенье'); INSERT INTO waifus VALUES (2, null, 'Зарянка', 5, 2.0, 2.0, 10000000000000, 'Honkai: Star rail', 'AgACAgIAAxkBAAIDaWlmRp7AdVif-UGg3_fa0jgJtVA6AAIu7TEbaHsZS7HGDnXa8gXJAQADAgADcwADOAQ', 'Зарянка — это изящная и скромная певица-галовианка, обладающая волнующим голосом, характерными для её расы великолепными нимбами и ушными перьями, а также внешностью, призванной привлекать внимание; её рост составляет около 173,5 см, она использует силу Гармонии для музыки и резонанса. Ключевые черты внешности: Раса: Галовианка (Пенакония). Возраст: 20-25 лет (биологический). Рост: 173.5 см. Особенности: Великолепные нимбы, ушные перья, волнующий голос. Роль: Певица, известная во всей вселенной. Элемент: Физический. Путь: Гармония. Описание в игре: Внешний вид: Изящная, скромная девушка из Галовианцев с Пенаконии. Талант: Использует силу Гармонии, чтобы передавать свою музыку и резонировать со всеми формами жизни, от фанатов до других существ. Вдохновение: Имя отсылает к реальной птице малиновке, известной своим ярким оперением. Характер персонажа (Зарянка) Личность: Изящная, скромная певица-галовианка родом с Пенаконии. Символизм: Птичка Зарянка символизирует справедливость и добро, отважно защищающую их, что отражено в её сюжете, где она «умирает» и «возрождается» в грёзах. У неё есть брат Воскресенье');
INSERT INTO waifus VALUES (3, null, 'Хошими Мияби', 5, 2.0, 2.0, 10000000000000, 'Zenless Zone Zero', 'AgACAgIAAxkBAAIL02lvK79Y9o8XK0KaIcuMMlEQ5JG6AAJdEGsbA6N5S0Zuc2c6S3giAQADAgADcwADOAQ ', 'Хосими Мияби — высокая (170 см, включая уши) женщина-лис (тирен) с длинными чёрными волосами, уложенными в косы, пронзительными красными глазами и бледной кожей. Её образ сочетает утончённую эстетику современного самурая с практичной боевой экипировкой. Волосы, уши и глаза: Длинные чёрные волосы с заметными косичками, лисьи уши и острые красные глаза. Одежда: Гармоничное сочетание традиционного и современного стилей. Включает белую блузу, галстук, чёрную юбку и открытую хаори цвета морской волны. Боевая экипировка: На её левой руке — самурайский бронированный наруч, а на правой — перчатка без пальцев. Аксессуары: Длинный скошенный чёрный пояс и высокие сапоги на каблуке. Оружие: Основное оружие — катана (проклятый клинок Бесхвостый, наследие семьи Хосими). Её внешность часто описывают как элегантную, властную и похожую на "одзё-сама" (благородную барышню/принцессу), при этом остающуюся функциональной для боя. Ключевые черты личности Хосими Мияби: 1. Дисциплинированная и серьёзная Мияби — предельно серьёзный, профессиональный и трудолюбивый лидер Секции 6. Она редко улыбается, за исключением уверенной усмешки в бою. Её стоицизм и самообладание формируют её холодный внешний образ. 2. Социально неловкая Несмотря на боевую слаженность, в обычном общении Мияби — «социальный неумеха». Её закрытое воспитание делает её неуклюжей в неформальных ситуациях; она предпочитает тренировки административным задачам и светским беседам. 3. Преданный защитник Её действия движимы глубоким чувством долга и справедливости. Главная цель Мияби — защита Нового Эриду от угроз Пустоты. Она проявляет глубочайшую преданность своим подчинённым и городу, действуя как его бесстрашный страж. 4. Высококлассная воительница Мияби — элитный боец, виртуозно владеющий семейной катаной «Бесхвостый». Её мастерство владения мечом считается исключительным. 5. Решительная и стойкая Она обладает огромной силой духа, что позволило ей преодолеть коррупционное влияние проклятого клинка. Её целеустремлённость и устойчивость не знают границ.'); INSERT INTO waifus VALUES (3, null, 'Хошими Мияби', 5, 2.0, 2.0, 10000000000000, 'Zenless Zone Zero', 'AgACAgIAAxkBAAIL02lvK79Y9o8XK0KaIcuMMlEQ5JG6AAJdEGsbA6N5S0Zuc2c6S3giAQADAgADcwADOAQ ', 'Хосими Мияби — высокая (170 см, включая уши) женщина-лис (тирен) с длинными чёрными волосами, уложенными в косы, пронзительными красными глазами и бледной кожей. Её образ сочетает утончённую эстетику современного самурая с практичной боевой экипировкой. Волосы, уши и глаза: Длинные чёрные волосы с заметными косичками, лисьи уши и острые красные глаза. Одежда: Гармоничное сочетание традиционного и современного стилей. Включает белую блузу, галстук, чёрную юбку и открытую хаори цвета морской волны. Боевая экипировка: На её левой руке — самурайский бронированный наруч, а на правой — перчатка без пальцев. Аксессуары: Длинный скошенный чёрный пояс и высокие сапоги на каблуке. Оружие: Основное оружие — катана (проклятый клинок Бесхвостый, наследие семьи Хосими). Её внешность часто описывают как элегантную, властную и похожую на "одзё-сама" (благородную барышню/принцессу), при этом остающуюся функциональной для боя. Ключевые черты личности Хосими Мияби: 1. Дисциплинированная и серьёзная Мияби — предельно серьёзный, профессиональный и трудолюбивый лидер Секции 6. Она редко улыбается, за исключением уверенной усмешки в бою. Её стоицизм и самообладание формируют её холодный внешний образ. 2. Социально неловкая Несмотря на боевую слаженность, в обычном общении Мияби — «социальный неумеха». Её закрытое воспитание делает её неуклюжей в неформальных ситуациях; она предпочитает тренировки административным задачам и светским беседам. 3. Преданный защитник Её действия движимы глубоким чувством долга и справедливости. Главная цель Мияби — защита Нового Эриду от угроз Пустоты. Она проявляет глубочайшую преданность своим подчинённым и городу, действуя как его бесстрашный страж. 4. Высококлассная воительница Мияби — элитный боец, виртуозно владеющий семейной катаной «Бесхвостый». Её мастерство владения мечом считается исключительным. 5. Решительная и стойкая Она обладает огромной силой духа, что позволило ей преодолеть коррупционное влияние проклятого клинка. Её целеустремлённость и устойчивость не знают границ.');
INSERT INTO waifus VALUES (4, null, 'Джейн Доу', 5, 2.0, 2.0, 10000000000000, 'Zenless Zone Zero', 'AgACAgIAAxkBAAIL1WlvLNu3lH8OEEN00XPePRDQnmloAAJkEGsbA6N5SwEK4RXuMK-yAQADAgADcwADOAQ', 'Джейн Доу — это молодая женщина ростом 170 см, принадлежащая к расе тиренов, что проявляется в наличии у нее серых крысиных ушей и хвоста, а также в ее остроте, ловкости и изменении внешности в бою. Обычно ее представляют как симпатичную, с чертами крысы, но очень проворную и меняющую свой облик. Одежда: Темный (черный/темно-серый) верх (жакет/куртка) с красными или бордовыми деталями, короткая юбка, высокие сапоги, порванные чулки. Ключевые черты характера: двойственность: Кажется одновременно коварной и заботливой, жёсткой и флиртующей. Манипулятивность и интеллект: Эксперт в психологии преступников, использует обман и притворство. Загадочность: Её прошлое и настоящее имя неизвестны, она дает разные ответы, создавая образ неуловимой личности. Ночной образ жизни: Наиболее активна в сумерках и ночью, «сова». Остроумие и игривость: Любит дразнить других и устраивать розыгрыши. Скрытая забота: Несмотря на цинизм, искренне переживает за жизнь невинных людей. Профессионализм: В бою невероятно свирепа и проворна, использует свою ловкость и знание уязвимостей врагов.'); INSERT INTO waifus VALUES (4, 1244301179, 'Джейн Доу', 5, 2.0, 2.0, 10000000000000, 'Zenless Zone Zero', 'AgACAgIAAxkBAAIL1WlvLNu3lH8OEEN00XPePRDQnmloAAJkEGsbA6N5SwEK4RXuMK-yAQADAgADcwADOAQ', 'Джейн Доу — это молодая женщина ростом 170 см, принадлежащая к расе тиренов, что проявляется в наличии у нее серых крысиных ушей и хвоста, а также в ее остроте, ловкости и изменении внешности в бою. Обычно ее представляют как симпатичную, с чертами крысы, но очень проворную и меняющую свой облик. Одежда: Темный (черный/темно-серый) верх (жакет/куртка) с красными или бордовыми деталями, короткая юбка, высокие сапоги, порванные чулки. Ключевые черты характера: двойственность: Кажется одновременно коварной и заботливой, жёсткой и флиртующей. Манипулятивность и интеллект: Эксперт в психологии преступников, использует обман и притворство. Загадочность: Её прошлое и настоящее имя неизвестны, она дает разные ответы, создавая образ неуловимой личности. Ночной образ жизни: Наиболее активна в сумерках и ночью, «сова». Остроумие и игривость: Любит дразнить других и устраивать розыгрыши. Скрытая забота: Несмотря на цинизм, искренне переживает за жизнь невинных людей. Профессионализм: В бою невероятно свирепа и проворна, использует свою ловкость и знание уязвимостей врагов.');
INSERT INTO waifus VALUES (5, null, 'Элизия', 5, 2.0, 2.0, 10000000000000, 'Honkai: Star rail', 'AgACAgIAAxkBAAIL1mlvLPQpjTnZ4Ok1KjERIFdByLryAAJlEGsbA6N5SxUEOOHNFSCdAQADAgADcwADOAQ', ''); INSERT INTO waifus VALUES (5, null, 'Элизия', 5, 2.0, 2.0, 10000000000000, 'Honkai: Star rail', 'AgACAgIAAxkBAAIL1mlvLPQpjTnZ4Ok1KjERIFdByLryAAJlEGsbA6N5SxUEOOHNFSCdAQADAgADcwADOAQ', '');
INSERT INTO waifus VALUES (6, null, 'Светлячок', 5, 2.0, 2.0, 10000000000000, 'Honkai: Star rail', 'AgACAgIAAxkBAAIL12lvLReROZAH1gKY-IL57U5ElUBcAAJnEGsbA6N5S5HV_my-RbTqAQADAgADcwADOAQ', ''); INSERT INTO waifus VALUES (6, null, 'Светлячок', 5, 2.0, 2.0, 10000000000000, 'Honkai: Star rail', 'AgACAgIAAxkBAAIL12lvLReROZAH1gKY-IL57U5ElUBcAAJnEGsbA6N5S5HV_my-RbTqAQADAgADcwADOAQ', '');
INSERT INTO waifus VALUES (7, 314834933, 'Клоринда', 5, 2.0, 2.0, 10000000000000, 'Genshin Impact', 'AgACAgIAAxkBAAIL2GlvLRyWLv6LGH6pJ71xn-6KoCF2AAJoEGsbA6N5SzBJlZ4WM9sGAQADAgADcwADOAQ', 'Клоринда — высокая девушка с фиолетовыми глазами, носит строгое, вдохновлённое мушкетёрами, одеяние. Основные черты внешности: Рост 168 см, волосы собраны в длинный хвост спереди оставлены свободные пряди, глаза фиолетовые. Одежда: Облегающее форменное платье и белая рубашка, короткая накидка-пиджак с эполетами, треуголка с пером и отворотами, высокие ботинки на каблуках с отворотами, металлические элементы бронзового цвета, ремешки на чулках, асимметричный элемент, похожий на шарф с кистями, сзади, под одеждой носит черное или фиолетовое кружевное белье. На неё теле нет ни единого шрама. Волосы на лобке всегда гладко выбриты. Ключевые черты характера и поведения: Воин и Правосудие: Она — воплощение справедливости, её боятся злодеи и те, кто стремится к славе обманным путём. Непоколебимая: Несмотря на потерю близких, она не сдалась, а стала защитником Фонтейна, демонстрируя силу и решимость. Загадочность: Публично не даёт интервью, окутывая свой успех тайной, но её «ритуал» очищения меча — это на самом деле медитация для сохранения спокойствия и концентрации. Практичность: Сочетает ближний и дальний бой, используя пистолет и меч, что делает её эффективной против любых врагов.'); INSERT INTO waifus VALUES (7, 314834933, 'Клоринда', 5, 2.0, 2.0, 10000000000000, 'Genshin Impact', 'AgACAgIAAxkBAAIL2GlvLRyWLv6LGH6pJ71xn-6KoCF2AAJoEGsbA6N5SzBJlZ4WM9sGAQADAgADcwADOAQ', 'Клоринда — высокая девушка с фиолетовыми глазами, носит строгое, вдохновлённое мушкетёрами, одеяние. Основные черты внешности: Рост 168 см, волосы собраны в длинный хвост спереди оставлены свободные пряди, глаза фиолетовые. Одежда: Облегающее форменное платье и белая рубашка, короткая накидка-пиджак с эполетами, треуголка с пером и отворотами, высокие ботинки на каблуках с отворотами, металлические элементы бронзового цвета, ремешки на чулках, асимметричный элемент, похожий на шарф с кистями, сзади, под одеждой носит черное или фиолетовое кружевное белье. На неё теле нет ни единого шрама. Волосы на лобке всегда гладко выбриты. Ключевые черты характера и поведения: Воин и Правосудие: Она — воплощение справедливости, её боятся злодеи и те, кто стремится к славе обманным путём. Непоколебимая: Несмотря на потерю близких, она не сдалась, а стала защитником Фонтейна, демонстрируя силу и решимость. Загадочность: Публично не даёт интервью, окутывая свой успех тайной, но её «ритуал» очищения меча — это на самом деле медитация для сохранения спокойствия и концентрации. Практичность: Сочетает ближний и дальний бой, используя пистолет и меч, что делает её эффективной против любых врагов.');
INSERT INTO waifus VALUES (8, null, 'Райден Эи', 5, 2.0, 2.0, 10000000000000, 'Genshin Impact', 'AgACAgIAAxkBAAIL2WlvLSYSdHFkdTm1txud3qJ7mV4dAAJpEGsbA6N5S3hLErFkYwWuAQADAgADcwADOAQ', ''); INSERT INTO waifus VALUES (8, null, 'Райден Эи', 5, 2.0, 2.0, 10000000000000, 'Genshin Impact', 'AgACAgIAAxkBAAIL2WlvLSYSdHFkdTm1txud3qJ7mV4dAAJpEGsbA6N5S3hLErFkYwWuAQADAgADcwADOAQ', '');
INSERT INTO waifus VALUES (9, null, 'Марин Китагава', 5, 2.0, 2.0, 10000000000000, 'Эта фарфоровая кукла влюбилась', '', ''); INSERT INTO waifus VALUES (9, null, 'Марин Китагава', 5, 2.0, 2.0, 10000000000000, 'Эта фарфоровая кукла влюбилась', '', '');
INSERT INTO waifus VALUES (10, null, 'Надзана Нанакуса', 5, 2.0, 2.0, 10000000000000, 'Песнь ночных сов', '', ''); INSERT INTO waifus VALUES (10, 7915366224, 'Надзана Нанакуса', 5, 2.0, 2.0, 10000000000000, 'Песнь ночных сов', '', '');
INSERT INTO waifus VALUES (11, null, 'Эвелин Шевалье', 5, 2.0, 2.0, 10000000000000, 'Zenless Zone Zero', '', 'Эвелин Шевалье — женщина ростом 173 см со светлой кожей, выразительными фиолетовыми глазами и светлыми волосами, которые часто уложены в короткую волнистую каре или причёску с пучком. Будучи бывшей шпионкой и телохранителем, она имеет стройную, пропорциональную фигуру и носит стильный, элегантный ансамбль в чёрно-белых тонах, включающий белую блузу, чёрный жилет-хамес и плащ с красной подкладкой. Обычно на ней белая безрукавка с высоким воротником, чёрный галстук, чёрный жилет-хамес и облегающие латексные брюки чёрного цвета с глянцевым блеском, ремнями и пряжками. Она известна своим холодным, профессиональным и серьёзным поведением, выступая в роли телохранителя и менеджера Астры Яо. Эвелин Шевалье — спокойный, высокопрофессиональный и исключительно эффективный менеджер и телохранитель Астры Яо. Её описывают как «решительную и отважную» личность с «упрямым» характером. Она обладает дотошным вниманием к деталям и сохраняет «стоическое» спокойствие, будучи при этом яростно защищающей своих подопечных. Несмотря на «загадочное» прошлое и «скрытую», «чуткую» и «заботливую» натуру, внешне она производит впечатление «холодного» и «серьёзного» человека, который «всегда» «готов», «опытен», «собран», «организован» и «надежен».'); INSERT INTO waifus VALUES (11, null, 'Эвелин Шевалье', 5, 2.0, 2.0, 10000000000000, 'Zenless Zone Zero', '', 'Эвелин Шевалье — женщина ростом 173 см со светлой кожей, выразительными фиолетовыми глазами и светлыми волосами, которые часто уложены в короткую волнистую каре или причёску с пучком. Будучи бывшей шпионкой и телохранителем, она имеет стройную, пропорциональную фигуру и носит стильный, элегантный ансамбль в чёрно-белых тонах, включающий белую блузу, чёрный жилет-хамес и плащ с красной подкладкой. Обычно на ней белая безрукавка с высоким воротником, чёрный галстук, чёрный жилет-хамес и облегающие латексные брюки чёрного цвета с глянцевым блеском, ремнями и пряжками. Она известна своим холодным, профессиональным и серьёзным поведением, выступая в роли телохранителя и менеджера Астры Яо. Эвелин Шевалье — спокойный, высокопрофессиональный и исключительно эффективный менеджер и телохранитель Астры Яо. Её описывают как «решительную и отважную» личность с «упрямым» характером. Она обладает дотошным вниманием к деталям и сохраняет «стоическое» спокойствие, будучи при этом яростно защищающей своих подопечных. Несмотря на «загадочное» прошлое и «скрытую», «чуткую» и «заботливую» натуру, внешне она производит впечатление «холодного» и «серьёзного» человека, который «всегда» «готов», «опытен», «собран», «организован» и «надежен».');
INSERT INTO waifus VALUES (12, null, 'Юкинама Юдзуха', 5, 2.0, 2.0, 10000000000000, 'Zenless Zone Zero', '', 'Юкинами Юдзуха — это молодая, миниатюрная девушка (рост 162 см) с ярко-рыжими волосами, заплетёнными в длинные косы с лентами, светло-зелёными глазами и гипер-женственной, модной эстетикой. Она носит розоватую оверсайз-куртку с красно-белыми узорами, многослойную красно-чёрную юбку и непарные полосатые гольфы до колен. Одежда: Её образ включает розоватый оверсайз-кардиган с фактурной вязкой, который сочетается с пышной многослойной юбкой. На ней также чёрное колье-чокер и тёмно-коричневые сапоги на каблуке. Волосы и лицо: Рыжие волосы уложены в две длинные косы, закреплённые лентами, по бокам головы заколоты коричневые заколки. Аксессуары и спутник: Её часто сопровождает компаньон — енот (в сеттинге игры упоминается как тануки). Стиль: Описывается как «визуально очень женственный», сочетающий милые и модные элементы в стиле Харадзюку с акцентом на розовых и красных цветах. Её внешний вид идеально соответствует жизнерадостному, хотя иногда и озорному характеру. Ключевые черты личности Юкинами Юдзухи: Юдзуха сталкивается с неизвестными опасностями с непоколебимо позитивным настроем. Её дерзость проявляется в уверенном и бесстрашном подходе к любым вызовам. Игривая проказница: Она известна тем, что любит подшучивать и устраивать неожиданные розыгрыши над другими, что добавляет её образу озорного и весёлого характера. Заботливая и жертвенная: Несмотря на игривость, Юдзуха глубоко предана своим друзьям и готова их яростно защищать. Она без колебаний пожертвует своей собственной безопасностью ради их благополучия. Травмированная прошлым: Её преследуют воспоминания о прошлых экспериментах и смерть отца Элис, за которую она чувствует себя виноватой. Эта травма является скрытой, глубокой частью её личности. Быстрая и многозадачная: Описана как человек, который говорит медленно, но печатает с невероятной скоростью. Она способна одновременно вести несколько бесед, что говорит о её высоких когнитивных способностях.'); INSERT INTO waifus VALUES (12, null, 'Юкинама Юдзуха', 5, 2.0, 2.0, 10000000000000, 'Zenless Zone Zero', '', 'Юкинами Юдзуха — это молодая, миниатюрная девушка (рост 162 см) с ярко-рыжими волосами, заплетёнными в длинные косы с лентами, светло-зелёными глазами и гипер-женственной, модной эстетикой. Она носит розоватую оверсайз-куртку с красно-белыми узорами, многослойную красно-чёрную юбку и непарные полосатые гольфы до колен. Одежда: Её образ включает розоватый оверсайз-кардиган с фактурной вязкой, который сочетается с пышной многослойной юбкой. На ней также чёрное колье-чокер и тёмно-коричневые сапоги на каблуке. Волосы и лицо: Рыжие волосы уложены в две длинные косы, закреплённые лентами, по бокам головы заколоты коричневые заколки. Аксессуары и спутник: Её часто сопровождает компаньон — енот (в сеттинге игры упоминается как тануки). Стиль: Описывается как «визуально очень женственный», сочетающий милые и модные элементы в стиле Харадзюку с акцентом на розовых и красных цветах. Её внешний вид идеально соответствует жизнерадостному, хотя иногда и озорному характеру. Ключевые черты личности Юкинами Юдзухи: Юдзуха сталкивается с неизвестными опасностями с непоколебимо позитивным настроем. Её дерзость проявляется в уверенном и бесстрашном подходе к любым вызовам. Игривая проказница: Она известна тем, что любит подшучивать и устраивать неожиданные розыгрыши над другими, что добавляет её образу озорного и весёлого характера. Заботливая и жертвенная: Несмотря на игривость, Юдзуха глубоко предана своим друзьям и готова их яростно защищать. Она без колебаний пожертвует своей собственной безопасностью ради их благополучия. Травмированная прошлым: Её преследуют воспоминания о прошлых экспериментах и смерть отца Элис, за которую она чувствует себя виноватой. Эта травма является скрытой, глубокой частью её личности. Быстрая и многозадачная: Описана как человек, который говорит медленно, но печатает с невероятной скоростью. Она способна одновременно вести несколько бесед, что говорит о её высоких когнитивных способностях.');
INSERT INTO waifus VALUES (13, null, 'Люсия', 5, 2.0, 2.0, 10000000000000, 'Zenless Zone Zero', '', ''); INSERT INTO waifus VALUES (13, null, 'Люсия', 5, 2.0, 2.0, 10000000000000, 'Zenless Zone Zero', '', '');

View File

@@ -22,69 +22,6 @@ func Max(a, b int) int {
return b return b
} }
type Slice[T any] []T
func NewSliceFrom[T any](slice []T) Slice[T] {
s := make(Slice[T], len(slice))
copy(s[:], slice)
return s
}
func (s Slice[T]) Len() int {
return len(s)
}
func (s Slice[T]) Cap() int {
return cap(s)
}
func (s Slice[T]) Swap(i, j int) Slice[T] {
s[i], s[j] = s[j], s[i]
return s
}
func (s Slice[T]) Filter(f func(e T) bool) Slice[T] {
out := make(Slice[T], 0)
for _, v := range s {
if f(v) {
out = append(out, v)
}
}
return out
}
func (s Slice[T]) Map(f func(e T) T) Slice[T] {
out := make(Slice[T], s.Len())
for i, v := range s {
out[i] = f(v)
}
return out
}
func (s Slice[T]) Pop(index int) Slice[T] {
if index == 0 {
return s[1:]
}
out := make(Slice[T], s.Len()-index)
for i, e := range s {
if i == index {
continue
}
out[i] = e
}
return out
}
func (s Slice[T]) Push(e T) Slice[T] {
return append(s, e)
}
func (s Slice[T]) ToArray() []T {
out := make([]T, len(s))
copy(out, s)
return out
}
func (s Slice[T]) ToAnyArray() []any {
out := make([]any, len(s))
for i, v := range s {
out[i] = v
}
return out
}
func Map[S, R any](f func(s S) R, s []S) []R { func Map[S, R any](f func(s S) R, s []S) []R {
out := make([]R, len(s)) out := make([]R, len(s))
for i := range s { for i := range s {
@@ -93,6 +30,7 @@ func Map[S, R any](f func(s S) R, s []S) []R {
return out return out
} }
// Deprecated
func PopSlice[S any](s []S, index int) []S { func PopSlice[S any](s []S, index int) []S {
if index == 0 { if index == 0 {
return s[1:] return s[1:]
@@ -106,6 +44,8 @@ func PopSlice[S any](s []S, index int) []S {
} }
return out return out
} }
// Deprecated
func TypedSliceToAny[S any](s []S) []any { func TypedSliceToAny[S any](s []S) []any {
out := make([]any, len(s)) out := make([]any, len(s))
for i := range s { for i := range s {