Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: aiproxy modelinfo and dashboard and model rpm limit #5291

Merged
merged 167 commits into from
Feb 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
167 commits
Select commit Hold shift + click to select a range
c809df7
feat: model info
zijiren233 Dec 14, 2024
76cb09b
fix: model config vision
zijiren233 Dec 15, 2024
4ffa8f9
feat: aiproxy dashboard api
zijiren233 Dec 16, 2024
2ef25c0
fix: two week and pg hour format
zijiren233 Dec 16, 2024
8a5142f
fix: model tag name
zijiren233 Dec 16, 2024
52036b2
feat: model rpm limit
zijiren233 Dec 17, 2024
1ff997f
fix: ci
zijiren233 Dec 17, 2024
35cd917
feat: search log with code type
zijiren233 Dec 17, 2024
edd526e
feat: resp detail buf use pool
zijiren233 Dec 18, 2024
1eab8af
feat: no need init client, use ctx
zijiren233 Dec 18, 2024
7b8efa7
fix: lint
zijiren233 Dec 18, 2024
9f63f43
feat: admin api log filed
zijiren233 Dec 18, 2024
0341ad0
feat: log usage
zijiren233 Dec 18, 2024
938c29e
feat: auto retry
zijiren233 Dec 19, 2024
e63b0f9
fix: retry channel exhausted, use first channel
zijiren233 Dec 19, 2024
5fe5b91
feat: init monitor
zijiren233 Dec 19, 2024
62b53fb
feat: auto ban error rate and auto test unban
zijiren233 Dec 20, 2024
27ce755
fix: getChannelWithFallback
zijiren233 Dec 20, 2024
de9cff4
feat: support google thinking
zijiren233 Dec 22, 2024
241c48f
fix: monitor
zijiren233 Dec 22, 2024
72cdcff
feat: get log detail
zijiren233 Dec 24, 2024
3b812f9
feat: no need channel config
zijiren233 Dec 24, 2024
ff6480f
feat: key validate
zijiren233 Dec 24, 2024
8c6e2bd
feat: add model error auto ban optioon
zijiren233 Dec 24, 2024
f173b12
feat: gemini tool
zijiren233 Dec 24, 2024
28e2fb4
feat: gemini openai sdk
zijiren233 Dec 24, 2024
1bfd5f4
fix: option keys
zijiren233 Dec 24, 2024
b3d4c40
feat: do not save access at
zijiren233 Dec 24, 2024
3323c7d
fix: del no use options
zijiren233 Dec 24, 2024
51bb991
fix: del no use options
zijiren233 Dec 24, 2024
5f94ee8
fix: auto test banned models need return when get from redis error ha…
zijiren233 Dec 24, 2024
f946e65
fix: remove channel db hook
zijiren233 Dec 24, 2024
4005bdf
chore: clean detail only after insert it
zijiren233 Dec 24, 2024
49e7bb8
fix: err print on debug
zijiren233 Dec 24, 2024
efc71d5
fix: cache update
zijiren233 Dec 24, 2024
aacff9a
feat: group consume level rpm ratio
zijiren233 Dec 25, 2024
853e0e1
fix: error return
zijiren233 Dec 25, 2024
0ff4cc7
feat: decode svg
zijiren233 Dec 25, 2024
69c7b00
fix: check is image
zijiren233 Dec 25, 2024
982cd0e
fix: reply raw 429 message
zijiren233 Dec 25, 2024
04895b6
feat: req and resp body max size limit
zijiren233 Dec 25, 2024
03396a1
fix: _ import lint
zijiren233 Dec 25, 2024
907f5c0
fix: get token encoder log
zijiren233 Dec 25, 2024
bf6b037
fix: sum used amount
zijiren233 Dec 26, 2024
f71a911
fix: delete no need cache
zijiren233 Dec 27, 2024
aa8ae73
feat: dashboard rpm
zijiren233 Dec 27, 2024
9d2d5e8
feat: dashboard tpm
zijiren233 Dec 27, 2024
1df8392
feat: step modelinfo
zijiren233 Dec 30, 2024
b29edf5
feat: yi
zijiren233 Dec 30, 2024
b0a4de6
fix: yi
zijiren233 Dec 30, 2024
b87b510
feat: debug banned
zijiren233 Dec 31, 2024
4bd2802
chore: bump go mod
zijiren233 Dec 31, 2024
ad47c07
chore: bump go mod
zijiren233 Dec 31, 2024
0a90e47
fix: save model time parse
zijiren233 Dec 31, 2024
26626df
feat: fill dash carts gaps
zijiren233 Dec 31, 2024
54b0ae3
feat: fill dash carts gaps
zijiren233 Dec 31, 2024
9b0840b
chore: go mod tidy
zijiren233 Dec 31, 2024
e5190b1
feat: dashboard timespan
zijiren233 Dec 31, 2024
fad3bda
feat: dashboard timespan from query
zijiren233 Dec 31, 2024
cbc620a
feat: decouple request paths
zijiren233 Dec 31, 2024
12d60b4
feat: group model tmp limit
zijiren233 Dec 31, 2024
6df69da
feat: decoupling url paths
zijiren233 Jan 2, 2025
96094f4
fix: check balance
zijiren233 Jan 2, 2025
c75d4da
refactor: relay handler
zijiren233 Jan 2, 2025
8da1e38
refactor: post relay
zijiren233 Jan 2, 2025
f56ea86
feat: fill gaps before and after point
zijiren233 Jan 2, 2025
92d48c1
fix: qwen long tokens
zijiren233 Jan 2, 2025
9158726
feat: get rpm from redis
zijiren233 Jan 2, 2025
92099d6
fix: fill gaps
zijiren233 Jan 2, 2025
b3a1024
fix: log error
zijiren233 Jan 2, 2025
28fb7d8
fix: token not fount err log
zijiren233 Jan 2, 2025
1c9d178
fix: if err resp is not json, replay raw content
zijiren233 Jan 3, 2025
01c8b2e
fix: do not save same response body and content
zijiren233 Jan 3, 2025
1cf6c8f
fix: save resp json or empty
zijiren233 Jan 3, 2025
6f36e27
feat: sort distinct values
zijiren233 Jan 3, 2025
247b3dd
fix: token models
zijiren233 Jan 4, 2025
75a9ca4
feat: redis clean expired cache
zijiren233 Jan 4, 2025
66f834d
feat: atomic model cache
zijiren233 Jan 4, 2025
66e5557
feat: consume
zijiren233 Jan 4, 2025
bdc316f
feat: group custom model rpm tpm
zijiren233 Jan 4, 2025
662bf28
fix: models
zijiren233 Jan 5, 2025
dc9eb90
fix: v1 route
zijiren233 Jan 5, 2025
a4e15a1
fix: cros
zijiren233 Jan 5, 2025
610fd8c
feat: rate limit err log record
zijiren233 Jan 5, 2025
dad91b7
fix: rpush
zijiren233 Jan 5, 2025
135e85d
fix: dashboard time span
zijiren233 Jan 6, 2025
4c749e5
feat: group model list adjusted tpm rpm
zijiren233 Jan 6, 2025
94d1936
feat: baichuan model config
zijiren233 Jan 6, 2025
bbec03a
fix: rpm limit recore ignore empty channel id
zijiren233 Jan 6, 2025
59ee65e
feat: disable model config
zijiren233 Jan 6, 2025
b23189d
feat: internal token
zijiren233 Jan 6, 2025
8e0336c
fix: lint
zijiren233 Jan 6, 2025
2c89467
fix: recore req to redis
zijiren233 Jan 6, 2025
25f0982
feat: option from env
zijiren233 Jan 6, 2025
272e9bb
fix: internal token option key
zijiren233 Jan 6, 2025
488b3b6
fix: ignore redis ping error
zijiren233 Jan 6, 2025
831b8ca
fix: ignore redis ping error
zijiren233 Jan 6, 2025
2815506
fix: subscription
zijiren233 Jan 8, 2025
25d8e07
fix: subscription
zijiren233 Jan 8, 2025
4eeb134
feat: precheck group balance
zijiren233 Jan 19, 2025
dd2f73b
fix: consume nil pointer
zijiren233 Jan 19, 2025
b4c7e7a
feat: log balance
zijiren233 Jan 23, 2025
ae0523e
feat: ip log
zijiren233 Jan 23, 2025
3e21fbc
fix: group disable
zijiren233 Jan 23, 2025
a61c4e6
fix: non stream context cancel
zijiren233 Jan 23, 2025
da7ce1e
feat: amount log
zijiren233 Jan 23, 2025
212a3c5
fix: balance and amount log format
zijiren233 Jan 23, 2025
8b690b2
fix: do not skip empty
zijiren233 Feb 4, 2025
cff9508
fix: reason system prompt
zijiren233 Feb 4, 2025
707ba6a
feat: doubao and moonshot model
zijiren233 Feb 6, 2025
eeab34a
feat: disable model config can load existed model
zijiren233 Feb 6, 2025
8c46269
chore: add shutdown timeout duration to 600 sec
zijiren233 Feb 6, 2025
ab9a912
feat: dashboard data build whit concurrent
zijiren233 Feb 6, 2025
5202f3a
feat: logs data build whit concurrent
zijiren233 Feb 6, 2025
7d734f2
fix: monitor remove banned model
zijiren233 Feb 7, 2025
504455d
feat: split think
zijiren233 Feb 7, 2025
ca5a6e2
fix: skip enpty think
zijiren233 Feb 7, 2025
09aaea5
fix: do not store large resp
zijiren233 Feb 7, 2025
26bb9c5
fix: reat limit script
zijiren233 Feb 7, 2025
d29418e
fix: reat limit use micro second
zijiren233 Feb 7, 2025
1fe4dc8
fix: ignore gemini input count error
zijiren233 Feb 7, 2025
592f964
feat: calude model config
zijiren233 Feb 8, 2025
526d619
fix: claude stream usage resp
zijiren233 Feb 8, 2025
8376d87
fix: claude stream usage resp
zijiren233 Feb 8, 2025
cb51b25
fix: claude stream usage resp
zijiren233 Feb 8, 2025
a14a7ee
feat: auto create sqlite dir
zijiren233 Feb 8, 2025
1e5f068
feat: log detail body truncated
zijiren233 Feb 8, 2025
1838887
chore: add body conv commend
zijiren233 Feb 8, 2025
b2a7959
feat: monitor ignore error rate compute when is success request
zijiren233 Feb 8, 2025
0e7eb14
feat: ollama usage support
zijiren233 Feb 8, 2025
f49ec83
feat: baseurl embed v1 prefix
zijiren233 Feb 8, 2025
0dd9742
feat: limit detail record size
zijiren233 Feb 8, 2025
daaf2f1
feat: split think config
zijiren233 Feb 9, 2025
0a4e7b6
feat: channel default priority
zijiren233 Feb 9, 2025
30896c6
fix: rate limit message
zijiren233 Feb 10, 2025
7a99c80
feat: channel meta api
zijiren233 Feb 10, 2025
2ed0e0d
feat: add channel key validate help message
zijiren233 Feb 10, 2025
8b3c23e
fix: channel config update
zijiren233 Feb 10, 2025
2470330
fix: split think
zijiren233 Feb 10, 2025
113900a
fix: claude api
zijiren233 Feb 10, 2025
904edf2
fix: record total tokens
zijiren233 Feb 10, 2025
93ff481
chore: bump go mod
zijiren233 Feb 11, 2025
257ca6c
chore: bump go mod
zijiren233 Feb 11, 2025
b11b4c6
feat: qwen open source vl models
zijiren233 Feb 11, 2025
9f10f79
fix: qwen2.5 vl tool choice
zijiren233 Feb 12, 2025
6e9c51b
feat: stt audio duration
zijiren233 Feb 12, 2025
7568984
feat: ali paraformer price
zijiren233 Feb 12, 2025
68b482d
fix: stt usage
zijiren233 Feb 13, 2025
12fcba6
feat: qwen mt
zijiren233 Feb 13, 2025
942bb25
fix: render when split skip
zijiren233 Feb 14, 2025
ee08814
feat: sealos realname check
zijiren233 Feb 14, 2025
2fa9050
feat: gemini usage support
zijiren233 Feb 17, 2025
32d9618
fix: lint
zijiren233 Feb 17, 2025
d5263ca
fix: error message
zijiren233 Feb 17, 2025
5019b03
fix: lint
zijiren233 Feb 17, 2025
6325e0c
fix: search token
zijiren233 Feb 17, 2025
7d5d014
fix: no real name limit han message
zijiren233 Feb 18, 2025
ee40454
feat: gemini model config
zijiren233 Feb 18, 2025
b02d23a
fix: get group error hans message
zijiren233 Feb 18, 2025
b4bc1a5
fix: get group dashboard models
zijiren233 Feb 18, 2025
5434c47
feat: channel and token model search
zijiren233 Feb 18, 2025
0a9453b
feat: support ali completions
zijiren233 Feb 18, 2025
3a389be
feat: internal group and search optimize
zijiren233 Feb 19, 2025
cc89fa7
feat: conv gemini tool choice
zijiren233 Feb 19, 2025
6e83f27
fix: gemini empty tool parameters
zijiren233 Feb 19, 2025
4266480
chore: env readme
zijiren233 Feb 20, 2025
0b1544f
fix: ci lint
zijiren233 Feb 20, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions service/aiproxy/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
FROM gcr.io/distroless/static:nonroot
FROM alpine:latest

ARG TARGETARCH
COPY bin/service-aiproxy-$TARGETARCH /manager
COPY bin/service-aiproxy-$TARGETARCH /aiproxy

ENV PUID=0 PGID=0 UMASK=022

ENV FFPROBE_ENABLED=true

EXPOSE 3000
USER 65532:65532

ENTRYPOINT ["/manager"]
RUN apk add --no-cache ca-certificates tzdata ffmpeg && \
rm -rf /var/cache/apk/*

ENTRYPOINT ["/aiproxy"]
10 changes: 10 additions & 0 deletions service/aiproxy/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,13 @@ sealos run ghcr.io/labring/sealos-cloud-aiproxy-service:latest \
-e cloudDomain=<cloud-domain> \
-e LOG_SQL_DSN=""
```

# Envs

- `ADMIN_KEY`: The admin key for the AI Proxy Service, admin key is used to admin api and relay api, default is empty
- `SEALOS_JWT_KEY`: Used to sealos balance service, default is empty
- `SQL_DSN`: The database connection string, default is empty
- `LOG_SQL_DSN`: The log database connection string, default is empty
- `REDIS_CONN_STRING`: The redis connection string, default is empty
- `BALANCE_SEALOS_CHECK_REAL_NAME_ENABLE`: Whether to check real name, default is `false`
- `BALANCE_SEALOS_NO_REAL_NAME_USED_AMOUNT_LIMIT`: The amount of used balance when the user has no real name, default is `1`
76 changes: 76 additions & 0 deletions service/aiproxy/common/audio/audio.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package audio

import (
"errors"
"io"
"os/exec"
"strconv"
"strings"

"github.com/labring/sealos/service/aiproxy/common/config"
)

var ErrAudioDurationNAN = errors.New("audio duration is N/A")

func GetAudioDuration(audio io.Reader) (float64, error) {
if !config.FfprobeEnabled {
return 0, nil
}

ffprobeCmd := exec.Command(
"ffprobe",
"-v", "error",
"-select_streams", "a:0",
"-show_entries", "stream=duration",
"-of", "default=noprint_wrappers=1:nokey=1",
"-i", "-",
)
ffprobeCmd.Stdin = audio
output, err := ffprobeCmd.Output()
if err != nil {
return 0, err
}

str := strings.TrimSpace(string(output))

if str == "" || str == "N/A" {
return 0, ErrAudioDurationNAN
}

duration, err := strconv.ParseFloat(str, 64)
if err != nil {
return 0, err
}
return duration, nil
}

func GetAudioDurationFromFilePath(filePath string) (float64, error) {
if !config.FfprobeEnabled {
return 0, nil
}

ffprobeCmd := exec.Command(
"ffprobe",
"-v", "error",
"-select_streams", "a:0",
"-show_entries", "format=duration",
"-of", "default=noprint_wrappers=1:nokey=1",
"-i", filePath,
)
output, err := ffprobeCmd.Output()
if err != nil {
return 0, err
}

str := strings.TrimSpace(string(output))

if str == "" || str == "N/A" {
return 0, ErrAudioDurationNAN
}

duration, err := strconv.ParseFloat(str, 64)
if err != nil {
return 0, err
}
return duration, nil
}
18 changes: 14 additions & 4 deletions service/aiproxy/common/balance/balance.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,24 @@
package balance

import "context"
import (
"context"

"github.com/labring/sealos/service/aiproxy/model"
)

type GroupBalance interface {
GetGroupRemainBalance(ctx context.Context, group string) (float64, PostGroupConsumer, error)
GetGroupRemainBalance(ctx context.Context, group model.GroupCache) (float64, PostGroupConsumer, error)
}

type PostGroupConsumer interface {
PostGroupConsume(ctx context.Context, tokenName string, usage float64) (float64, error)
GetBalance(ctx context.Context) (float64, error)
}

var Default GroupBalance = NewMockGroupBalance()
var (
mock GroupBalance = NewMockGroupBalance()
Default = mock
)

func MockGetGroupRemainBalance(ctx context.Context, group model.GroupCache) (float64, PostGroupConsumer, error) {
return mock.GetGroupRemainBalance(ctx, group)
}
12 changes: 6 additions & 6 deletions service/aiproxy/common/balance/mock.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package balance

import "context"
import (
"context"

"github.com/labring/sealos/service/aiproxy/model"
)

var _ GroupBalance = (*MockGroupBalance)(nil)

Expand All @@ -14,14 +18,10 @@ func NewMockGroupBalance() *MockGroupBalance {
return &MockGroupBalance{}
}

func (q *MockGroupBalance) GetGroupRemainBalance(_ context.Context, _ string) (float64, PostGroupConsumer, error) {
func (q *MockGroupBalance) GetGroupRemainBalance(_ context.Context, _ model.GroupCache) (float64, PostGroupConsumer, error) {
return mockBalance, q, nil
}

func (q *MockGroupBalance) PostGroupConsume(_ context.Context, _ string, usage float64) (float64, error) {
return usage, nil
}

func (q *MockGroupBalance) GetBalance(_ context.Context) (float64, error) {
return mockBalance, nil
}
120 changes: 104 additions & 16 deletions service/aiproxy/common/balance/sealos.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/labring/sealos/service/aiproxy/common"
"github.com/labring/sealos/service/aiproxy/common/conv"
"github.com/labring/sealos/service/aiproxy/common/env"
"github.com/labring/sealos/service/aiproxy/model"
"github.com/redis/go-redis/v9"
"github.com/shopspring/decimal"
log "github.com/sirupsen/logrus"
Expand All @@ -25,6 +26,7 @@ const (
appType = "LLM-TOKEN"
sealosRequester = "sealos-admin"
sealosGroupBalanceKey = "sealos:balance:%s"
sealosUserRealNameKey = "sealos:realName:%s"
getBalanceRetry = 3
)

Expand All @@ -38,6 +40,11 @@ var (
sealosCacheExpire = 3 * time.Minute
)

var (
sealosCheckRealNameEnable = env.Bool("BALANCE_SEALOS_CHECK_REAL_NAME_ENABLE", false)
sealosNoRealNameUsedAmountLimit = env.Float64("BALANCE_SEALOS_NO_REAL_NAME_USED_AMOUNT_LIMIT", 1)
)

type Sealos struct {
accountURL string
}
Expand Down Expand Up @@ -145,12 +152,20 @@ func cacheDecreaseGroupBalance(ctx context.Context, group string, amount int64)
return decreaseGroupBalanceScript.Run(ctx, common.RDB, []string{fmt.Sprintf(sealosGroupBalanceKey, group)}, amount).Err()
}

func (s *Sealos) GetGroupRemainBalance(ctx context.Context, group string) (float64, PostGroupConsumer, error) {
var ErrNoRealNameUsedAmountLimit = errors.New("达到未实名用户使用额度限制,请实名认证")

func (s *Sealos) GetGroupRemainBalance(ctx context.Context, group model.GroupCache) (float64, PostGroupConsumer, error) {
var errs []error
for i := 0; ; i++ {
balance, consumer, err := s.getGroupRemainBalance(ctx, group)
balance, userUID, err := s.getGroupRemainBalance(ctx, group.ID)
if err == nil {
return balance, consumer, nil
if sealosCheckRealNameEnable &&
group.UsedAmount > sealosNoRealNameUsedAmountLimit &&
!s.checkRealName(ctx, userUID) {
return 0, nil, ErrNoRealNameUsedAmountLimit
}
return decimal.NewFromInt(balance).Div(decimalBalancePrecision).InexactFloat64(),
newSealosPostGroupConsumer(s.accountURL, group.ID, userUID), nil
}
errs = append(errs, err)
if i == getBalanceRetry-1 {
Expand All @@ -160,26 +175,105 @@ func (s *Sealos) GetGroupRemainBalance(ctx context.Context, group string) (float
}
}

func cacheGetUserRealName(ctx context.Context, userUID string) (bool, error) {
if !common.RedisEnabled || !sealosRedisCacheEnable {
return true, redis.Nil
}
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()
realName, err := common.RDB.Get(ctx, fmt.Sprintf(sealosUserRealNameKey, userUID)).Bool()
if err != nil {
return false, err
}
return realName, nil
}

func cacheSetUserRealName(ctx context.Context, userUID string, realName bool) error {
if !common.RedisEnabled || !sealosRedisCacheEnable {
return nil
}
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()
var expireTime time.Duration
if realName {
expireTime = time.Hour * 12
} else {
expireTime = time.Minute * 1
}
return common.RDB.Set(ctx, fmt.Sprintf(sealosUserRealNameKey, userUID), realName, expireTime).Err()
}

func (s *Sealos) checkRealName(ctx context.Context, userUID string) bool {
if cache, err := cacheGetUserRealName(ctx, userUID); err == nil {
return cache
} else if !errors.Is(err, redis.Nil) {
log.Errorf("get user (%s) real name cache failed: %s", userUID, err)
}

realName, err := s.fetchRealNameFromAPI(ctx, userUID)
if err != nil {
log.Errorf("fetch user (%s) real name failed: %s", userUID, err)
return true
}

if err := cacheSetUserRealName(ctx, userUID, realName); err != nil {
log.Errorf("set user (%s) real name cache failed: %s", userUID, err)
}

return realName
}

type sealosGetRealNameInfoResp struct {
IsRealName bool `json:"isRealName"`
Error string `json:"error"`
}

func (s *Sealos) fetchRealNameFromAPI(ctx context.Context, userUID string) (bool, error) {
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()
req, err := http.NewRequestWithContext(ctx, http.MethodGet,
fmt.Sprintf("%s/admin/v1alpha1/real-name-info?userUID=%s", s.accountURL, userUID), nil)
if err != nil {
return false, err
}

req.Header.Set("Authorization", "Bearer "+jwtToken)
resp, err := sealosHTTPClient.Do(req)
if err != nil {
return false, err
}
defer resp.Body.Close()

var sealosResp sealosGetRealNameInfoResp
if err := json.NewDecoder(resp.Body).Decode(&sealosResp); err != nil {
return false, err
}

if resp.StatusCode != http.StatusOK || sealosResp.Error != "" {
return false, fmt.Errorf("get user (%s) real name failed with status code %d, error: %s", userUID, resp.StatusCode, sealosResp.Error)
}

return sealosResp.IsRealName, nil
}

// GroupBalance interface implementation
func (s *Sealos) getGroupRemainBalance(ctx context.Context, group string) (float64, PostGroupConsumer, error) {
func (s *Sealos) getGroupRemainBalance(ctx context.Context, group string) (int64, string, error) {
if cache, err := cacheGetGroupBalance(ctx, group); err == nil && cache.UserUID != "" {
return decimal.NewFromInt(cache.Balance).Div(decimalBalancePrecision).InexactFloat64(),
newSealosPostGroupConsumer(s.accountURL, group, cache.UserUID, cache.Balance), nil
return cache.Balance, cache.UserUID, nil
} else if err != nil && !errors.Is(err, redis.Nil) {
log.Errorf("get group (%s) balance cache failed: %s", group, err)
}

balance, userUID, err := s.fetchBalanceFromAPI(ctx, group)
if err != nil {
return 0, nil, err
return 0, "", err
}

if err := cacheSetGroupBalance(ctx, group, balance, userUID); err != nil {
log.Errorf("set group (%s) balance cache failed: %s", group, err)
}

return decimal.NewFromInt(balance).Div(decimalBalancePrecision).InexactFloat64(),
newSealosPostGroupConsumer(s.accountURL, group, userUID, balance), nil
return balance, userUID, nil
}

func (s *Sealos) fetchBalanceFromAPI(ctx context.Context, group string) (balance int64, userUID string, err error) {
Expand Down Expand Up @@ -218,22 +312,16 @@ type SealosPostGroupConsumer struct {
accountURL string
group string
uid string
balance int64
}

func newSealosPostGroupConsumer(accountURL, group, uid string, balance int64) *SealosPostGroupConsumer {
func newSealosPostGroupConsumer(accountURL, group, uid string) *SealosPostGroupConsumer {
return &SealosPostGroupConsumer{
accountURL: accountURL,
group: group,
uid: uid,
balance: balance,
}
}

func (s *SealosPostGroupConsumer) GetBalance(_ context.Context) (float64, error) {
return decimal.NewFromInt(s.balance).Div(decimalBalancePrecision).InexactFloat64(), nil
}

func (s *SealosPostGroupConsumer) PostGroupConsume(ctx context.Context, tokenName string, usage float64) (float64, error) {
amount := s.calculateAmount(usage)

Expand Down
Loading