Compare commits
4 Commits
Author | SHA1 | Date | |
---|---|---|---|
e46acea3f1 | |||
011e63dfa1 | |||
b3125d41be | |||
88f7f29259 |
@ -23,7 +23,12 @@ func main() {
|
||||
|
||||
err = validate.ValidateKafka([]string{cfg.KafkaBrokers}, cfg.KafkaTopicTariff)
|
||||
if err != nil {
|
||||
log.Fatalf("error validating kafka: %v", err)
|
||||
log.Fatalf("error validating kafka Tariff: %v", err)
|
||||
}
|
||||
|
||||
err = validate.ValidateKafka([]string{cfg.KafkaBrokers}, cfg.KafkaTopicGigaChat)
|
||||
if err != nil {
|
||||
log.Fatalf("error validating kafka GigaChat: %v", err)
|
||||
}
|
||||
|
||||
err = validate.ValidateRedis(cfg.RedisHost, cfg.RedisPassword, int(cfg.RedisDB))
|
||||
@ -78,5 +83,13 @@ func validateNotEmpty(cfg initialize.Config) error {
|
||||
return errors.New("api url is not be empty")
|
||||
}
|
||||
|
||||
if cfg.GigaChatApiBaseURL == "" {
|
||||
return errors.New("giga chat api base url is not be empty")
|
||||
}
|
||||
|
||||
if cfg.GigaChatApiAuthKey == "" {
|
||||
return errors.New("giga chat api key is not be empty")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -20,3 +20,5 @@ KAFKA_GROUP_GIGA_CHAT=""
|
||||
GIGA_CHAT_API_AUTH_KEY=Y2MzZWUxZDMtZGE5MC00ZTFjLWI5YzItM2ViMTZmMDM0YTkwOmY1NTlkOGM3LWUyNmQtNGUwMC1hODE0LTJlYjQ5NDA5ODdjMQ==
|
||||
GIGA_CHAT_API_BASE_URL="https://gigachat.devices.sberbank.ru/api/v1"
|
||||
TELEGRAM_TOKEN=6112841016:AAH2nO1c6mqfMewBvHwdXCDp5PCclOuc99
|
||||
NOTIFY_CHANNEL_ID=-1002338593104
|
||||
NOTIFY_TELEGRAM_TOKEN=6112841016:AAH2nO1c6mqfMewBvHwdXCDp5PCclOuc99s
|
||||
|
2
go.mod
2
go.mod
@ -5,7 +5,7 @@ go 1.23.2
|
||||
toolchain go1.23.4
|
||||
|
||||
require (
|
||||
gitea.pena/PenaSide/common v0.0.0-20250421103113-7e4b3ae9e1e0
|
||||
gitea.pena/PenaSide/common v0.0.0-20250609100303-3b7c00cc97bc
|
||||
gitea.pena/PenaSide/customer v0.0.0-20250518194954-882ec684be86
|
||||
gitea.pena/PenaSide/hlog v0.0.0-20241125221102-a54c29c002a9
|
||||
gitea.pena/SQuiz/common v0.0.0-20250610100937-ce7096a3dd37
|
||||
|
2
go.sum
2
go.sum
@ -1,5 +1,7 @@
|
||||
gitea.pena/PenaSide/common v0.0.0-20250421103113-7e4b3ae9e1e0 h1:+gvpAPo1+1WtCpA+QaCWNy4R9/cIERBBzrVSYrx7hNo=
|
||||
gitea.pena/PenaSide/common v0.0.0-20250421103113-7e4b3ae9e1e0/go.mod h1:91EuBCgcqgJ6mG36n2pds8sPwwfaJytLWOzY3h2YFKU=
|
||||
gitea.pena/PenaSide/common v0.0.0-20250609100303-3b7c00cc97bc h1:xwojlRrEl2hjZxgoMqSz8pkWmQRYq7LsDdeAExtgyQE=
|
||||
gitea.pena/PenaSide/common v0.0.0-20250609100303-3b7c00cc97bc/go.mod h1:91EuBCgcqgJ6mG36n2pds8sPwwfaJytLWOzY3h2YFKU=
|
||||
gitea.pena/PenaSide/customer v0.0.0-20250407185330-82e95e8da043 h1:a/89TC0bRdWRjS875EIE1c1ZPgmRcDaKMcQoUv+sg+I=
|
||||
gitea.pena/PenaSide/customer v0.0.0-20250407185330-82e95e8da043/go.mod h1:DDg6CQDhU+aSSTv8R/LbkNGegdCx+Q++DcgPfE2LbZU=
|
||||
gitea.pena/PenaSide/customer v0.0.0-20250518194954-882ec684be86 h1:NjY7t0aerJqCcHez74sI3mQLjP3Yhc3jYG/n1/k279Y=
|
||||
|
@ -2,13 +2,11 @@ package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"gitea.pena/PenaSide/hlog"
|
||||
"gitea.pena/SQuiz/common/dal"
|
||||
"gitea.pena/SQuiz/worker/internal/answerwc"
|
||||
"gitea.pena/SQuiz/worker/internal/clients/gigachat"
|
||||
"gitea.pena/SQuiz/worker/internal/gigachatwc"
|
||||
"gitea.pena/SQuiz/worker/internal/initialize"
|
||||
"gitea.pena/SQuiz/worker/internal/privilegewc"
|
||||
@ -16,7 +14,6 @@ import (
|
||||
"gitea.pena/SQuiz/worker/internal/workers/shortstat"
|
||||
"gitea.pena/SQuiz/worker/internal/workers/timeout"
|
||||
"gitea.pena/SQuiz/worker/pkg/closer"
|
||||
"github.com/go-resty/resty/v2"
|
||||
"go.uber.org/zap"
|
||||
"time"
|
||||
)
|
||||
@ -85,7 +82,11 @@ func New(ctx context.Context, cfg initialize.Config, build Build) error {
|
||||
return err
|
||||
}
|
||||
|
||||
clients := initialize.NewClients(cfg, zapLogger)
|
||||
clients, err := initialize.NewClients(ctx, cfg, zapLogger, redisClient)
|
||||
if err != nil {
|
||||
zapLogger.Error("failed init clients", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
|
||||
// tgSender, err := senders.NewTgSender(options.TgToken)
|
||||
// if err != nil {
|
||||
@ -140,26 +141,16 @@ func New(ctx context.Context, cfg initialize.Config, build Build) error {
|
||||
go toClientWorker.Start(ctx)
|
||||
go toRespWorker.Start(ctx)
|
||||
|
||||
gigaChatClient, err := gigachat.NewGigaChatClient(ctx, gigachat.Deps{
|
||||
Logger: zapLogger,
|
||||
Client: resty.New().SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true}),
|
||||
BaseURL: cfg.GigaChatApiBaseURL,
|
||||
AuthKey: cfg.GigaChatApiAuthKey,
|
||||
RedisClient: redisClient,
|
||||
})
|
||||
if err != nil {
|
||||
zapLogger.Error("failed init giga chat client", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
// метод для обновления токенов гигачата
|
||||
go gigaChatClient.TokenResearch(ctx)
|
||||
go clients.GigaChatClient.TokenResearch(ctx)
|
||||
go clients.GigaChatClient.MonitorTokenBalance(ctx)
|
||||
|
||||
fmt.Println("INIT GGC WORKER", cfg.KafkaTopicGigaChat)
|
||||
gigaChatWorker, err := gigachatwc.NewGigaChatTaskScheduler(gigachatwc.Deps{
|
||||
KafkaBrokers: cfg.KafkaBrokers,
|
||||
KafkaTopic: cfg.KafkaTopicGigaChat,
|
||||
KafkaGroup: cfg.KafkaGroupGigaChat,
|
||||
GigaChatClient: gigaChatClient,
|
||||
GigaChatClient: clients.GigaChatClient,
|
||||
Logger: zapLogger,
|
||||
Dal: pgdal,
|
||||
})
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"gitea.pena/SQuiz/common/model"
|
||||
"gitea.pena/SQuiz/worker/internal/senders"
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/go-resty/resty/v2"
|
||||
"github.com/google/uuid"
|
||||
@ -18,6 +19,8 @@ type Deps struct {
|
||||
BaseURL string
|
||||
AuthKey string
|
||||
RedisClient *redis.Client
|
||||
TgSender *senders.TgSender
|
||||
TgChatID int64
|
||||
}
|
||||
|
||||
type GigaChatClient struct {
|
||||
@ -26,6 +29,8 @@ type GigaChatClient struct {
|
||||
baseURL string
|
||||
authKey string
|
||||
redisClient *redis.Client
|
||||
tgSender *senders.TgSender
|
||||
tgChatID int64
|
||||
}
|
||||
|
||||
func NewGigaChatClient(ctx context.Context, deps Deps) (*GigaChatClient, error) {
|
||||
@ -35,6 +40,9 @@ func NewGigaChatClient(ctx context.Context, deps Deps) (*GigaChatClient, error)
|
||||
baseURL: deps.BaseURL,
|
||||
authKey: deps.AuthKey,
|
||||
redisClient: deps.RedisClient,
|
||||
|
||||
tgSender: deps.TgSender,
|
||||
tgChatID: deps.TgChatID,
|
||||
}
|
||||
|
||||
if err := client.updateToken(ctx); err != nil {
|
||||
@ -110,7 +118,7 @@ func (r *GigaChatClient) TokenResearch(ctx context.Context) {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
ttl, err := r.redisClient.TTL(ctx, "gigachat_token").Result()
|
||||
fmt.Println("GGCHATtoken", ttl, err, ttl<2*time.Minute)
|
||||
fmt.Println("GGCHATtoken", ttl, err, ttl < 2*time.Minute)
|
||||
if err != nil || ttl < 2*time.Minute {
|
||||
if err := r.updateToken(ctx); err != nil {
|
||||
r.logger.Error("failed to update GigaChat token", zap.Error(err))
|
||||
@ -148,7 +156,7 @@ func (r *GigaChatClient) updateToken(ctx context.Context) error {
|
||||
}
|
||||
|
||||
ttl := time.Until(time.Unix(int64(respData.ExpiresAt/1000), 0))
|
||||
fmt.Println("GGCTOKENEXP", respData.ExpiresAt, ttl, ttl<2*time.Minute, time.Now())
|
||||
fmt.Println("GGCTOKENEXP", respData.ExpiresAt, ttl, ttl < 2*time.Minute, time.Now())
|
||||
err = r.redisClient.Set(ctx, "gigachat_token", respData.AccessToken, ttl).Err()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to save token to redis: %w", err)
|
||||
@ -156,3 +164,72 @@ func (r *GigaChatClient) updateToken(ctx context.Context) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *GigaChatClient) getBalance(ctx context.Context) (int, error) {
|
||||
var respData struct {
|
||||
Balance []struct {
|
||||
Usage string `json:"usage"`
|
||||
Value int `json:"value"`
|
||||
} `json:"balance"`
|
||||
}
|
||||
|
||||
token, err := r.redisClient.Get(ctx, "gigachat_token").Result()
|
||||
if err != nil {
|
||||
r.logger.Error("failed to get token from redis", zap.Error(err))
|
||||
return 0, err
|
||||
}
|
||||
|
||||
resp, err := r.client.R().
|
||||
SetHeader("Authorization", "Bearer "+token).
|
||||
SetResult(&respData).
|
||||
Get(r.baseURL + "/balance")
|
||||
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to fetch balance: %w", err)
|
||||
}
|
||||
if resp.IsError() {
|
||||
return 0, fmt.Errorf("balance request failed: %s", resp.Status())
|
||||
}
|
||||
|
||||
// прверяем то что используем для переформулирования
|
||||
for _, item := range respData.Balance {
|
||||
if item.Usage == "GigaChat-Max" {
|
||||
return item.Value, nil
|
||||
}
|
||||
}
|
||||
|
||||
return 0, errors.New("no used models found")
|
||||
}
|
||||
|
||||
func (r *GigaChatClient) MonitorTokenBalance(ctx context.Context) {
|
||||
ticker := time.NewTicker(5 * time.Minute)
|
||||
defer ticker.Stop()
|
||||
|
||||
alert := false // чтоб не спамить каждые 5 минут
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
balance, err := r.getBalance(ctx)
|
||||
if err != nil {
|
||||
r.logger.Error("failed to get GigaChat token", zap.Error(err))
|
||||
continue
|
||||
}
|
||||
|
||||
if balance < 500_000 && !alert {
|
||||
msg := fmt.Sprintf("Остаток токенов в GigaChat упал ниже 500000.\nТекущий баланс: %d токенов.", balance)
|
||||
if err := r.tgSender.SendMessage(r.tgChatID, msg); err != nil {
|
||||
r.logger.Error("failed to send Telegram alert", zap.Error(err))
|
||||
} else {
|
||||
alert = true
|
||||
}
|
||||
}
|
||||
|
||||
if balance >= 500_000 && alert {
|
||||
alert = false
|
||||
}
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,17 +1,43 @@
|
||||
package initialize
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"gitea.pena/PenaSide/customer/pkg/customer_clients"
|
||||
"gitea.pena/SQuiz/common/clients"
|
||||
"gitea.pena/SQuiz/worker/internal/clients/gigachat"
|
||||
"gitea.pena/SQuiz/worker/internal/senders"
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/go-resty/resty/v2"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type Clients struct {
|
||||
MailClient *clients.SmtpClient
|
||||
CustomerClient *customer_clients.CustomersClient
|
||||
GigaChatClient *gigachat.GigaChatClient
|
||||
}
|
||||
|
||||
func NewClients(cfg Config, logger *zap.Logger) *Clients {
|
||||
func NewClients(ctx context.Context, cfg Config, logger *zap.Logger, redisClient *redis.Client) (*Clients, error) {
|
||||
notifyTgClient, err := senders.NewTgSender(cfg.NotifyTelegramToken)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
gigaChatClient, err := gigachat.NewGigaChatClient(ctx, gigachat.Deps{
|
||||
Logger: logger,
|
||||
Client: resty.New().SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true}),
|
||||
BaseURL: cfg.GigaChatApiBaseURL,
|
||||
AuthKey: cfg.GigaChatApiAuthKey,
|
||||
RedisClient: redisClient,
|
||||
|
||||
TgSender: notifyTgClient,
|
||||
TgChatID: cfg.NotifyChannelID,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Clients{
|
||||
MailClient: clients.NewSmtpClient(clients.Deps{
|
||||
SmtpSender: cfg.Sender,
|
||||
@ -22,5 +48,6 @@ func NewClients(cfg Config, logger *zap.Logger) *Clients {
|
||||
Logger: logger,
|
||||
CustomerServiceHost: cfg.CustomerMicroserviceRPCURL,
|
||||
}),
|
||||
}
|
||||
GigaChatClient: gigaChatClient,
|
||||
}, nil
|
||||
}
|
||||
|
@ -29,6 +29,9 @@ type Config struct {
|
||||
KafkaGroupGigaChat string `env:"KAFKA_GROUP_GIGA_CHAT" default:"gigachat"`
|
||||
GigaChatApiBaseURL string `env:"GIGA_CHAT_API_BASE_URL"`
|
||||
GigaChatApiAuthKey string `env:"GIGA_CHAT_API_AUTH_KEY"`
|
||||
|
||||
NotifyTelegramToken string `env:"NOTIFY_TELEGRAM_TOKEN"`
|
||||
NotifyChannelID int64 `env:"NOTIFY_CHANNEL_ID"`
|
||||
}
|
||||
|
||||
func LoadConfig() (*Config, error) {
|
||||
|
@ -30,7 +30,7 @@ type TemplateData struct {
|
||||
AllAnswers []model.ResultAnswer
|
||||
QuestionsMap map[uint64]string
|
||||
AnswerTime string
|
||||
QuizID int64
|
||||
QuizID int64
|
||||
}
|
||||
|
||||
func generateTextFromTemplate(data TemplateData, tpl string) (string, error) {
|
||||
@ -65,7 +65,7 @@ func RenderImage(content string) template.HTML {
|
||||
contents := strings.Split(content, "`,`")
|
||||
var builder strings.Builder
|
||||
|
||||
content = strings.ReplaceAll(content, "\n","<br>")
|
||||
content = strings.ReplaceAll(content, "\n", "<br>")
|
||||
for i, cnt := range contents {
|
||||
if i == 0 {
|
||||
cnt = strings.TrimPrefix(cnt, "`")
|
||||
@ -79,7 +79,15 @@ func RenderImage(content string) template.HTML {
|
||||
if err != nil {
|
||||
return SplitContent(content)
|
||||
} else {
|
||||
builder.WriteString(fmt.Sprintf("<td>%s<br><img class=\"image\" style=\"width:100%%; max-width:250px; max-height:250px\" src=\"%s\"/></td>", res.Description, strings.Replace(res.Image, "http", "https", 1)))
|
||||
imgURL := res.Image
|
||||
if strings.HasPrefix(imgURL, "http://") {
|
||||
imgURL = strings.Replace(imgURL, "http://", "https://", 1)
|
||||
}
|
||||
builder.WriteString(
|
||||
fmt.Sprintf(`<td style="color:#9a9aaf;font-size:20px;font-style:normal;font-weight:400;line-height:normal">
|
||||
%s<br> <img class="image" style="width:100%%; max-width:250px; max-height:250px;" src="%s" alt="%s"/></td>`,
|
||||
res.Description, imgURL, res.Description))
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -49,3 +49,11 @@ func (tg *TgSender) SendLead(data LeadData) error {
|
||||
func (tg *TgSender) Name() string {
|
||||
return "telegram"
|
||||
}
|
||||
|
||||
func (tg *TgSender) SendMessage(chatID int64, msg string) error {
|
||||
_, err := tg.bot.Send(telebot.ChatID(chatID), msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
"fmt"
|
||||
"gitea.pena/SQuiz/common/model"
|
||||
"gitea.pena/SQuiz/worker/internal/clients/gigachat"
|
||||
"gitea.pena/SQuiz/worker/internal/senders"
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/go-resty/resty/v2"
|
||||
"go.uber.org/zap"
|
||||
@ -23,18 +24,27 @@ func TestGigachat(t *testing.T) {
|
||||
DB: 2,
|
||||
})
|
||||
|
||||
tgSender, err := senders.NewTgSender("6712573453:AAFqTOsgwe_j48ZQ1GzWKQDT5Nwr-SAWjz8")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
gigaChatClient, err := gigachat.NewGigaChatClient(ctx, gigachat.Deps{
|
||||
Logger: logger,
|
||||
Client: resty.New().SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true}),
|
||||
BaseURL: "https://gigachat.devices.sberbank.ru/api/v1",
|
||||
AuthKey: "ZGM3MDY0ZjAtODM4Yi00ZTQ4LTgzMTgtZDA0ZDA3NmIwYzJjOjRkZWI4Y2NhLTc1YzUtNDg5ZS04YzY4LTVkNTdmMWU1YjU5Nw==",
|
||||
AuthKey: "Y2MzZWUxZDMtZGE5MC00ZTFjLWI5YzItM2ViMTZmMDM0YTkwOmY1NTlkOGM3LWUyNmQtNGUwMC1hODE0LTJlYjQ5NDA5ODdjMQ==",
|
||||
RedisClient: redisClient,
|
||||
|
||||
TgSender: tgSender,
|
||||
TgChatID: -1002217604546,
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
go gigaChatClient.TokenResearch(ctx)
|
||||
go gigaChatClient.MonitorTokenBalance(ctx)
|
||||
|
||||
result, err := gigaChatClient.SendMsg(ctx, model.GigaChatAudience{
|
||||
Sex: 1,
|
||||
|
@ -62,10 +62,10 @@ func TestProcessMessageToSMTP(t *testing.T) {
|
||||
Messenger: "test_messenger",
|
||||
},
|
||||
AllAnswers: []model.ResultAnswer{
|
||||
{AnswerID: 1, QuestionID: 1, Content: "https://www.google.com/search?sca_esv=c51a80de1a7d45f0&sxsrf=ACQVn08xG-a0eH1Vds246-fONoSvvjzVMw:1707762485524&q=ku,n&tbm=isch&source=lnms&sa=X&ved=2ahUKEwi7ub2Ct6aEAxVVb_UHHQIQBVoQ0pQJegQIDRAB&biw=1536&bih=703&dpr=1.25#imgrc=0PWwTuuH2uBQ3M|html", CreatedAt: time.Now()},
|
||||
{AnswerID: 2, QuestionID: 2, Content: "From a friend", CreatedAt: time.Now()},
|
||||
{AnswerID: 1, QuestionID: 1, Content: "`{\"Image\":\"https://s3.timeweb.cloud/3c580be9-cf31f296-d055-49cf-b39e-30c7959dc17b/squizimages/e0927ded-5c4c-4d45-a5ba-c2e938362ffa/co0sejfg4n3c73d5umd0\",\"Description\":\"Да\"}`", CreatedAt: time.Now()},
|
||||
{AnswerID: 2, QuestionID: 2, Content: "`ыв`,`вв`", CreatedAt: time.Now()},
|
||||
{AnswerID: 3, QuestionID: 3, Content: "From a friend", CreatedAt: time.Now()},
|
||||
{AnswerID: 4, QuestionID: 4, Content: `{"Image":"https://letsenhance.io/static/8f5e523ee6b2479e26ecc91b9c25261e/1015f/MainAfter.jpg","Description":"Gekon"}`, CreatedAt: time.Now()},
|
||||
{AnswerID: 4, QuestionID: 4, Content: `{"Image":"static.tildacdn.com/tild6335-6331-4539-a664-376366653534/_problembocom.jpg","Description":"Gekon"}`, CreatedAt: time.Now()},
|
||||
},
|
||||
QuestionsMap: map[uint64]string{
|
||||
1: "?",
|
||||
|
Loading…
Reference in New Issue
Block a user