From 39b61f1867bfe9cefab5dd095e3d9bd3356ff4dc Mon Sep 17 00:00:00 2001 From: qhd <1766646056@qq.com> Date: Mon, 22 Jun 2026 09:08:12 +0800 Subject: [PATCH 01/24] =?UTF-8?q?chore:=20=E6=9B=B4=E6=96=B0=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E5=B9=B6=E4=BC=98=E5=8C=96=E4=BB=BB=E5=8A=A1=E9=94=99?= =?UTF-8?q?=E8=AF=AF=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将数据库、Redis、Consul及Jaeger配置切换至新环境地址,并在worker中忽略"Invalid video_url"与"Invalid audio track"错误,同时补充模型调用成功日志。 --- config.yml | 12 ++++++------ service/task/worker.go | 5 ++++- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/config.yml b/config.yml index 8da4bef..dafc77f 100644 --- a/config.yml +++ b/config.yml @@ -28,10 +28,10 @@ database: timeMaintainDisabled: false # (可选)是否完全关闭时间更新特性,为true时CreatedAt/UpdatedAt/DeletedAt都将失效 model_gateway: - type: "pgsql" - host: "192.168.3.30" - port: "5432" + host: "116.204.74.41" + port: "15432" user: "postgres" - pass: "123456" + pass: "Bjang09@686^*^" name: "model-gateway" prefix: "" role: "master" @@ -50,14 +50,14 @@ database: redis: default: - address: 192.168.3.30:6379 + address: 116.204.74.41:6379 db: 0 consul: - address: 192.168.3.30:8500 + address: 116.204.74.41:8500 jaeger: - addr: 192.168.3.30:4318 + addr: 116.204.74.41:4318 # 本地调试用:可选自动执行 worker/cleaner(默认关闭) asynch: diff --git a/service/task/worker.go b/service/task/worker.go index 20dd537..6ed9db5 100644 --- a/service/task/worker.go +++ b/service/task/worker.go @@ -72,7 +72,9 @@ func (w *asyncWorker) handleOne(ctx context.Context, task *entity.ModelGatewayTa } if !strings.Contains(err.Error(), "Timeout") && - !strings.Contains(err.Error(), "InternalServiceError") { + !strings.Contains(err.Error(), "InternalServiceError") && + !strings.Contains(err.Error(), "Invalid video_url") && + !strings.Contains(err.Error(), "Invalid audio track") { w.failTask(ctx, task, startTime, err.Error()) return } @@ -395,6 +397,7 @@ func InvokeModel(ctx context.Context, model *entity.ModelGatewayModel, body map[ msg := string(b) return nil, fmt.Errorf("模型服务返回非2xx: %d, body=%s", resp.StatusCode, msg) } + g.Log().Debugf(ctx, "[执行任务][模型调用成功] StatusCode=%v", resp.StatusCode) return b, nil } From 610481effdb807f1ce37850594c4c8fcd9c83575 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E6=96=8C?= <259278618@qq.com> Date: Mon, 22 Jun 2026 10:57:46 +0800 Subject: [PATCH 02/24] 1 --- config.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/config.yml b/config.yml index dafc77f..cc3dd83 100644 --- a/config.yml +++ b/config.yml @@ -7,7 +7,7 @@ server: database: default: - type: "pgsql" - host: "116.204.74.41" + host: "192.168.0.83" port: "15432" user: "postgres" pass: "Bjang09@686^*^" @@ -28,7 +28,7 @@ database: timeMaintainDisabled: false # (可选)是否完全关闭时间更新特性,为true时CreatedAt/UpdatedAt/DeletedAt都将失效 model_gateway: - type: "pgsql" - host: "116.204.74.41" + host: "192.168.0.83" port: "15432" user: "postgres" pass: "Bjang09@686^*^" @@ -50,14 +50,14 @@ database: redis: default: - address: 116.204.74.41:6379 + address: 192.168.0.83:6379 db: 0 consul: - address: 116.204.74.41:8500 + address: 192.168.0.83:8500 jaeger: - addr: 116.204.74.41:4318 + addr: 192.168.0.83:4318 # 本地调试用:可选自动执行 worker/cleaner(默认关闭) asynch: From 525b391f09239099edd0290730f904a428d3df9d Mon Sep 17 00:00:00 2001 From: WangLiZhao <1838393649@qq.com> Date: Tue, 23 Jun 2026 14:55:50 +0800 Subject: [PATCH 03/24] =?UTF-8?q?feat(task):=20=E6=B7=BB=E5=8A=A0=E6=9E=84?= =?UTF-8?q?=E5=BB=BA=E6=A8=A1=E5=9E=8B=E5=90=8D=E7=A7=B0=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=8A=A8=E6=80=81=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在ModelGatewayTask实体中新增BuildModelName字段 - 修改ParseAndValidate函数参数,支持传入requiredFields - 在异步工作器中实现构建模型的动态字段校验逻辑 - 添加prompt构建服务中传递构建模型名称的功能 - 实现构建模型不存在时的兜底机制 --- common/util/mapping.go | 4 ++-- model/dto/model_gateway_task_dto.go | 1 + model/entity/model_gateway_task.go | 3 +++ service/task/worker.go | 22 ++++++++++++++++++++-- 4 files changed, 26 insertions(+), 4 deletions(-) diff --git a/common/util/mapping.go b/common/util/mapping.go index 85547dd..ee61f21 100644 --- a/common/util/mapping.go +++ b/common/util/mapping.go @@ -20,7 +20,7 @@ import ( ) // ParseAndValidate 解析模型响应,并返回标准格式 -func ParseAndValidate(raw map[string]any, model *entity.ModelGatewayModel) (map[string]any, error) { +func ParseAndValidate(raw map[string]any, requiredFields []string) (map[string]any, error) { contentStr := gconv.String(raw[entity.ResponseBody]) if strings.TrimSpace(contentStr) == "" { return raw, fmt.Errorf("字段 %s 为空", entity.ResponseBody) @@ -41,7 +41,7 @@ func ParseAndValidate(raw map[string]any, model *entity.ModelGatewayModel) (map[ return raw, fmt.Errorf("解析后数组为空") } - for _, field := range model.RequiredFields { + for _, field := range requiredFields { for i, r := range arr { round, _ := r.(map[string]any) if round != nil && gjson.New(round).Get(field).IsNil() { diff --git a/model/dto/model_gateway_task_dto.go b/model/dto/model_gateway_task_dto.go index 8d7b0a1..710e39f 100644 --- a/model/dto/model_gateway_task_dto.go +++ b/model/dto/model_gateway_task_dto.go @@ -13,6 +13,7 @@ type CreateTaskReq struct { RequestPayload map[string]any `p:"requestPayload" json:"requestPayload" dc:"请求负载(透传给模型服务)"` EpicycleId int64 `json:"epicycleId" dc:"轮次ID"` BuildType int64 `json:"buildType" dc:"构建类型:1-提示词构建 2-节点构建"` + BuildModelName string `json:"buildModelName" json:"buildModelName" dc:"构建模型名称"` } type CreateTaskRes struct { diff --git a/model/entity/model_gateway_task.go b/model/entity/model_gateway_task.go index baaa13e..eabd320 100644 --- a/model/entity/model_gateway_task.go +++ b/model/entity/model_gateway_task.go @@ -21,6 +21,7 @@ type modelGatewayTaskCol struct { TmpFile string RequestPayload string EpicycleId string + BuildModelName string } var ModelGatewayTaskCol = modelGatewayTaskCol{ @@ -40,6 +41,7 @@ var ModelGatewayTaskCol = modelGatewayTaskCol{ TmpFile: "tmp_file", RequestPayload: "request_payload", EpicycleId: "epicycle_id", + BuildModelName: "build_model_name", } // ModelGatewayTask 模型网关任务 @@ -60,6 +62,7 @@ type ModelGatewayTask struct { TmpFile string `orm:"tmp_file" json:"tmpFile"` RequestPayload *RequestPayload `orm:"request_payload" json:"requestPayload"` EpicycleId int64 `orm:"epicycle_id" json:"epicycleId"` + BuildModelName string `orm:"build_model_name" json:"buildModelName"` } // ResultFile OSS 结果文件 diff --git a/service/task/worker.go b/service/task/worker.go index 6ed9db5..db52fe3 100644 --- a/service/task/worker.go +++ b/service/task/worker.go @@ -211,6 +211,24 @@ func (w *asyncWorker) callModel(ctx context.Context, task *entity.ModelGatewayTa // parseAndRetry 解析模型返回结果,并重试 func (w *asyncWorker) parseAndRetry(ctx context.Context, body map[string]any, task *entity.ModelGatewayTask, model *entity.ModelGatewayModel, req *dto.CreateTaskReq, maxRetry int, startTime time.Time) (map[string]any, error) { + // 0) 如果指定了构建模型,查出校验字段 + var requiredFields []string + if task.BuildModelName != "" { + buildModel, _ := dao.ModelGatewayModels.Get(ctx, &entity.ModelGatewayModel{ + SQLBaseDO: beans.SQLBaseDO{ + TenantId: model.TenantId, + Creator: model.Creator, + }, + ModelName: req.ModelName, + }) + if buildModel != nil { + requiredFields = buildModel.RequiredFields + } + } + if len(requiredFields) == 0 { + requiredFields = model.RequiredFields // 兜底用当前模型的 + } + var lastErr error for attempt := 0; attempt <= maxRetry; attempt++ { if attempt > 0 { @@ -236,11 +254,11 @@ func (w *asyncWorker) parseAndRetry(ctx context.Context, body map[string]any, ta }) } - // 3) 解析 + 校验 + // 3) 解析 + 校验(用 buildModel 的 RequiredFields) var parsed map[string]any switch req.BuildType { case public.BuildTypePrompt, public.BuildTypeNode: - parsed, err = util.ParseAndValidate(mapped, model) + parsed, err = util.ParseAndValidate(mapped, requiredFields) if err == nil { return parsed, nil } From 73f630636db49531cc40396ac3e97c5829954d5d Mon Sep 17 00:00:00 2001 From: WangLiZhao <1838393649@qq.com> Date: Tue, 23 Jun 2026 16:18:00 +0800 Subject: [PATCH 04/24] =?UTF-8?q?feat(task):=20=E6=B7=BB=E5=8A=A0=E6=9E=84?= =?UTF-8?q?=E5=BB=BA=E6=A8=A1=E5=9E=8B=E5=90=8D=E7=A7=B0=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- service/task/task_service.go | 3 ++- service/task/worker.go | 5 +---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/service/task/task_service.go b/service/task/task_service.go index f8905b0..06c095d 100644 --- a/service/task/task_service.go +++ b/service/task/task_service.go @@ -73,7 +73,8 @@ func (s *taskService) Create(ctx context.Context, req *dto.CreateTaskReq) (res * Body: req.RequestPayload, Headers: util.ParseHeadMsgHeaders(model.HeadMsg), }, - EpicycleId: req.EpicycleId, + EpicycleId: req.EpicycleId, + BuildModelName: req.BuildModelName, } // 4) 插入任务记录 diff --git a/service/task/worker.go b/service/task/worker.go index db52fe3..4737274 100644 --- a/service/task/worker.go +++ b/service/task/worker.go @@ -219,15 +219,12 @@ func (w *asyncWorker) parseAndRetry(ctx context.Context, body map[string]any, ta TenantId: model.TenantId, Creator: model.Creator, }, - ModelName: req.ModelName, + ModelName: req.BuildModelName, }) if buildModel != nil { requiredFields = buildModel.RequiredFields } } - if len(requiredFields) == 0 { - requiredFields = model.RequiredFields // 兜底用当前模型的 - } var lastErr error for attempt := 0; attempt <= maxRetry; attempt++ { From 16f296756931c08012fb5eebe2177e3ae441f47f Mon Sep 17 00:00:00 2001 From: qhd <1766646056@qq.com> Date: Tue, 23 Jun 2026 17:00:05 +0800 Subject: [PATCH 05/24] =?UTF-8?q?build:=20=E5=8D=87=E7=BA=A7=20common=20?= =?UTF-8?q?=E4=BE=9D=E8=B5=96=E8=87=B3=20v0.0.25?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index cc44967..5349e43 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module model-gateway go 1.26.1 require ( - gitea.redpowerfuture.com/red-future/common v0.0.23 + gitea.redpowerfuture.com/red-future/common v0.0.25 github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.10.2 github.com/gogf/gf/contrib/nosql/redis/v2 v2.10.2 github.com/gogf/gf/v2 v2.10.2 diff --git a/go.sum b/go.sum index 670f2b0..c119188 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,8 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= gitea.redpowerfuture.com/red-future/common v0.0.23 h1:xieoA00iKOCDm5SO9iXn+cSyMKBAlZwI0fuEVPWrHLg= gitea.redpowerfuture.com/red-future/common v0.0.23/go.mod h1:50U1Xi+Ie56z09S5LQbZvaken0Mxv3OeS9LgR7U/ZRY= +gitea.redpowerfuture.com/red-future/common v0.0.25 h1:TFKmcyByChLc3gBr1mgyWOBmT2acEpS8G2Asm9QmDdo= +gitea.redpowerfuture.com/red-future/common v0.0.25/go.mod h1:50U1Xi+Ie56z09S5LQbZvaken0Mxv3OeS9LgR7U/ZRY= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg= github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= From aee243d4eb5b0ba65e82f310f9e556df5178574a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E6=96=8C?= <259278618@qq.com> Date: Tue, 23 Jun 2026 18:31:59 +0800 Subject: [PATCH 06/24] =?UTF-8?q?common=E7=89=88=E6=9C=AC=E5=8D=87?= =?UTF-8?q?=E7=BA=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- go.mod | 80 +++++++++++++++++--------------- go.sum | 144 ++++++++++++++++++++------------------------------------- 2 files changed, 94 insertions(+), 130 deletions(-) diff --git a/go.mod b/go.mod index 5349e43..ee43bc1 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module model-gateway go 1.26.1 require ( - gitea.redpowerfuture.com/red-future/common v0.0.25 + gitea.redpowerfuture.com/red-future/common v0.0.26 github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.10.2 github.com/gogf/gf/contrib/nosql/redis/v2 v2.10.2 github.com/gogf/gf/v2 v2.10.2 @@ -12,22 +12,25 @@ require ( ) require ( - github.com/BurntSushi/toml v1.5.0 // indirect + github.com/BurntSushi/toml v1.6.0 // indirect github.com/armon/go-metrics v0.4.1 // indirect github.com/bwmarrin/snowflake v0.3.0 // indirect github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/clbanning/mxj/v2 v2.7.0 // indirect + github.com/clipperhouse/displaywidth v0.11.0 // indirect + github.com/clipperhouse/uax29/v2 v2.7.0 // indirect github.com/dgraph-io/badger/v4 v4.2.0 // indirect github.com/dgraph-io/ristretto v0.1.1 // indirect - github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/emirpasic/gods/v2 v2.0.0-alpha // indirect - github.com/fatih/color v1.18.0 // indirect - github.com/fsnotify/fsnotify v1.9.0 // indirect + github.com/fatih/color v1.19.0 // indirect + github.com/fsnotify/fsnotify v1.10.1 // indirect github.com/go-ego/gse v1.0.2 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-viper/mapstructure/v2 v2.5.0 // indirect + github.com/goccy/go-json v0.10.6 // indirect github.com/gogf/gf/contrib/registry/consul/v2 v2.9.5 // indirect github.com/gogf/gf/contrib/trace/otlphttp/v2 v2.9.5 // indirect github.com/gogo/protobuf v1.3.2 // indirect @@ -36,57 +39,62 @@ require ( github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v1.0.0 // indirect - github.com/google/flatbuffers v1.12.1 // indirect + github.com/google/btree v1.1.3 // indirect + github.com/google/flatbuffers v25.12.19+incompatible // indirect github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect github.com/grokify/html-strip-tags-go v0.1.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect - github.com/hashicorp/consul/api v1.26.1 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 // indirect + github.com/hashicorp/consul/api v1.33.5 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-hclog v1.5.0 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-rootcerts v1.0.2 // indirect + github.com/hashicorp/go-version v1.9.0 // indirect github.com/hashicorp/golang-lru v1.0.2 // indirect github.com/hashicorp/serf v0.10.1 // indirect - github.com/klauspost/compress v1.18.0 // indirect - github.com/lib/pq v1.10.9 // indirect + github.com/klauspost/compress v1.18.6 // indirect + github.com/klauspost/cpuid/v2 v2.3.0 // indirect + github.com/lib/pq v1.12.3 // indirect github.com/magiconair/properties v1.8.10 // indirect - github.com/mattn/go-colorable v0.1.14 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-runewidth v0.0.16 // indirect + github.com/mattn/go-colorable v0.1.15 // indirect + github.com/mattn/go-isatty v0.0.22 // indirect + github.com/mattn/go-runewidth v0.0.24 // indirect + github.com/miekg/dns v1.1.72 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect - github.com/mitchellh/mapstructure v1.5.0 // indirect - github.com/olekukonko/errors v1.1.0 // indirect - github.com/olekukonko/ll v0.0.9 // indirect - github.com/olekukonko/tablewriter v1.1.0 // indirect + github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 // indirect + github.com/olekukonko/errors v1.3.0 // indirect + github.com/olekukonko/ll v0.1.8 // indirect + github.com/olekukonko/tablewriter v1.1.4 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/r3labs/diff/v2 v2.15.1 // indirect - github.com/redis/go-redis/v9 v9.12.1 // indirect - github.com/rivo/uniseg v0.4.7 // indirect - github.com/tidwall/match v1.1.1 // indirect - github.com/tidwall/pretty v1.2.0 // indirect + github.com/redis/go-redis/v9 v9.21.0 // indirect + github.com/stretchr/objx v0.5.2 // indirect + github.com/tidwall/match v1.2.0 // indirect + github.com/tidwall/pretty v1.2.1 // indirect github.com/tiger1103/gfast-token v1.0.10 // indirect github.com/vcaesar/cedar v0.30.0 // indirect github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect - go.mongodb.org/mongo-driver/v2 v2.4.0 // indirect - go.opencensus.io v0.23.0 // indirect - go.opentelemetry.io/auto/sdk v1.1.0 // indirect - go.opentelemetry.io/otel v1.38.0 // indirect + go.mongodb.org/mongo-driver/v2 v2.6.0 // indirect + go.opencensus.io v0.24.0 // indirect + go.opentelemetry.io/auto/sdk v1.2.1 // indirect + go.opentelemetry.io/otel v1.44.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 // indirect - go.opentelemetry.io/otel/metric v1.38.0 // indirect - go.opentelemetry.io/otel/sdk v1.38.0 // indirect - go.opentelemetry.io/otel/trace v1.38.0 // indirect + go.opentelemetry.io/otel/metric v1.44.0 // indirect + go.opentelemetry.io/otel/sdk v1.44.0 // indirect + go.opentelemetry.io/otel/trace v1.44.0 // indirect go.opentelemetry.io/proto/otlp v1.7.1 // indirect - golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect - golang.org/x/net v0.47.0 // indirect - golang.org/x/sys v0.38.0 // indirect - golang.org/x/text v0.31.0 // indirect + go.uber.org/atomic v1.11.0 // indirect + golang.org/x/exp v0.0.0-20260611194520-c48552f49976 // indirect + golang.org/x/net v0.56.0 // indirect + golang.org/x/sys v0.46.0 // indirect + golang.org/x/text v0.38.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 // indirect - google.golang.org/grpc v1.75.0 // indirect - google.golang.org/protobuf v1.36.8 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20260209200024-4cfbd4190f57 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57 // indirect + google.golang.org/grpc v1.79.3 // indirect + google.golang.org/protobuf v1.36.11 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index c119188..3add795 100644 --- a/go.sum +++ b/go.sum @@ -1,11 +1,8 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -gitea.redpowerfuture.com/red-future/common v0.0.23 h1:xieoA00iKOCDm5SO9iXn+cSyMKBAlZwI0fuEVPWrHLg= -gitea.redpowerfuture.com/red-future/common v0.0.23/go.mod h1:50U1Xi+Ie56z09S5LQbZvaken0Mxv3OeS9LgR7U/ZRY= gitea.redpowerfuture.com/red-future/common v0.0.25 h1:TFKmcyByChLc3gBr1mgyWOBmT2acEpS8G2Asm9QmDdo= gitea.redpowerfuture.com/red-future/common v0.0.25/go.mod h1:50U1Xi+Ie56z09S5LQbZvaken0Mxv3OeS9LgR7U/ZRY= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg= -github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= +github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -38,6 +35,8 @@ github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME= github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/clipperhouse/displaywidth v0.11.0 h1:lBc6kY44VFw+TDx4I8opi/EtL9m20WSEFgwIwO+UVM8= +github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -49,8 +48,6 @@ github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWa github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= -github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= -github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= @@ -63,10 +60,8 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7 github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= -github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= -github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= -github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +github.com/fatih/color v1.19.0 h1:Zp3PiM21/9Ld6FzSKyL5c/BULoe/ONr9KlbYVOfG8+w= +github.com/fsnotify/fsnotify v1.10.1 h1:b0/UzAf9yR5rhf3RPm9gf3ehBPpf0oZKIjtpKrx59Ho= github.com/go-ego/gse v1.0.2 h1:+27lYFPhQEhA9igtdOsJPRKYL/k3TwYsxBF5jr6KFv4= github.com/go-ego/gse v1.0.2/go.mod h1:Fy35G+q7VV7Et1zIKO8o/sW1kkugV3znXap/lF/11zc= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= @@ -79,6 +74,8 @@ github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ4 github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro= +github.com/goccy/go-json v0.10.6 h1:p8HrPJzOakx/mn/bQtjgNjdTcN+/S6FcG2CTtQOrHVU= github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.10.2 h1:u8EpP24GkprogROnJ7htMov9Fc66pTP1eVYrWxiCYOs= github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.10.2/go.mod h1:GmvM3r8GVByVMi4RD2+MCs5+CfxVXPMeT8mVDkAaAXE= github.com/gogf/gf/contrib/nosql/redis/v2 v2.10.2 h1:iTQegT+lEg/wDKvj2mi3W1wrdrwFarjokf88EXVVgu4= @@ -116,10 +113,8 @@ github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6 github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs= github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= -github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= -github.com/google/flatbuffers v1.12.1 h1:MVlul7pQNoDzWRLTw5imwYsl+usrS1TXG2H4jg6ImGw= -github.com/google/flatbuffers v1.12.1/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= +github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= +github.com/google/flatbuffers v25.12.19+incompatible h1:haMV2JRRJCe1998HeW/p0X9UaMTK6SDo0ffLn2+DbLs= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -136,12 +131,9 @@ github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5T github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA= github.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4= github.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs= -github.com/hashicorp/consul/api v1.26.1 h1:5oSXOO5fboPZeW5SN+TdGFP/BILDgBm19OrPZ/pICIM= -github.com/hashicorp/consul/api v1.26.1/go.mod h1:B4sQTeaSO16NtynqrAdwOlahJ7IUDZM9cj2420xYL8A= -github.com/hashicorp/consul/sdk v0.15.0 h1:2qK9nDrr4tiJKRoxPGhm6B7xJjLVIQqkjiab2M4aKjU= -github.com/hashicorp/consul/sdk v0.15.0/go.mod h1:r/OmRRPbHOe0yxNahLw7G9x5WG17E1BIECMtCjcPSNo= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 h1:HWRh5R2+9EifMyIHV7ZV+MIZqgz+PMpZ14Jynv3O2Zs= +github.com/hashicorp/consul/api v1.33.5 h1:Nn6q87zudRU1rLBTJEgaWxz9STCNadilLCD7B8OA5aI= +github.com/hashicorp/consul/sdk v0.17.3 h1:oZMMxzQGSsiT+ToOH50y3Qcs0nc9Ud+7L5lRx+EmMU0= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -171,8 +163,7 @@ github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI= -github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go-version v1.9.0 h1:CeOIz6k+LoN3qX9Z0tyQrPtiB1DFYRPfCIBtaXPSCnA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= @@ -187,8 +178,8 @@ github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/u github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= -github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= +github.com/klauspost/compress v1.18.6 h1:2jupLlAwFm95+YDR+NwD2MEfFO9d4z4Prjl1XXDjuao= +github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -198,8 +189,7 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= -github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lib/pq v1.12.3 h1:tTWxr2YLKwIvK90ZXEw8GP7UFHtcbTtty8zsI+YjrfQ= github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE= github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= @@ -207,39 +197,31 @@ github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVc github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= -github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= -github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= +github.com/mattn/go-colorable v0.1.15 h1:+u9SLTRGnXv73cEsnsmoZBom+dMU88B2M0aDcWy0/jY= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= -github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= -github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-isatty v0.0.22 h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw4= +github.com/mattn/go-runewidth v0.0.24 h1:cpokDiIn0MGnhdHwuWnJBITySJ20QyNGnY2kR/ay2DU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= -github.com/miekg/dns v1.1.63 h1:8M5aAw6OMZfFXTT7K5V0Eu5YiiL8l7nUAkyN6C9YwaY= -github.com/miekg/dns v1.1.63/go.mod h1:6NGHfjhpmr5lt3XPLuyfDJi5AXbNIPM9PY6H6sF1Nfs= +github.com/miekg/dns v1.1.72 h1:vhmr+TF2A3tuoGNkLDFK9zi36F2LS+hKTRW0Uf8kbzI= github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= -github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM= -github.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y= -github.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI= -github.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g= -github.com/olekukonko/tablewriter v1.1.0 h1:N0LHrshF4T39KvI96fn6GT8HEjXRXYNDrDjKFDB7RIY= -github.com/olekukonko/tablewriter v1.1.0/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo= +github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 h1:zrbMGy9YXpIeTnGj4EljqMiZsIcE09mmF8XsD5AYOJc= +github.com/olekukonko/errors v1.3.0 h1:teJvgLGUEqMzBUms+Dj3/3szNqCG/Jdw9iDbum8fR6U= +github.com/olekukonko/ll v0.1.8 h1:ysHCJRGHYKzmBSdz9w5AySztx7lG8SQY+naTGYUbsz8= +github.com/olekukonko/tablewriter v1.1.4 h1:ORUMI3dXbMnRlRggJX3+q7OzQFDdvgbN9nVWj1drm6I= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= @@ -266,13 +248,8 @@ github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsT github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/r3labs/diff/v2 v2.15.1 h1:EOrVqPUzi+njlumoqJwiS/TgGgmZo83619FNDB9xQUg= github.com/r3labs/diff/v2 v2.15.1/go.mod h1:I8noH9Fc2fjSaMxqF3G2lhDdC0b+JXCfyx85tWFM9kc= -github.com/redis/go-redis/v9 v9.12.1 h1:k5iquqv27aBtnTm2tIkROUDp8JBXhXZIVu1InSgvovg= -github.com/redis/go-redis/v9 v9.12.1/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw= -github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= -github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= -github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/redis/go-redis/v9 v9.21.0 h1:FPBE4hhbAke+TLmcY3WkpbDffJEomdqPn3HYiqAtL9E= +github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= @@ -280,22 +257,19 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/tidwall/gjson v1.19.0 h1:xwxm7n691Uf3u5OFjzngavjGTh55KX5q/9w9xHW88JU= github.com/tidwall/gjson v1.19.0/go.mod h1:V37/opeE/JbLUOfH0QTXiNez2l0RUjYUhpT4szFQAfc= -github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= -github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= -github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= -github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/match v1.2.0 h1:0pt8FlkOwjN2fPt4bIl4BoNxb98gGHN2ObFEDkrfZnM= +github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= github.com/tiger1103/gfast-token v1.0.10 h1:fNiBE/Dq5iTHvTGlCx3DmXa2o4hr0NtumFpffZ39k6s= github.com/tiger1103/gfast-token v1.0.10/go.mod h1:a/21mxmj7zFeNvjhZSC0XpEAFHfb1aT2k6DXnufFU1s= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= @@ -307,28 +281,22 @@ github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaU github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -go.mongodb.org/mongo-driver/v2 v2.4.0 h1:Oq6BmUAAFTzMeh6AonuDlgZMuAuEiUxoAD1koK5MuFo= -go.mongodb.org/mongo-driver/v2 v2.4.0/go.mod h1:jHeEDJHJq7tm6ZF45Issun9dbogjfnPySb1vXA7EeAI= -go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= -go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= -go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= -go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= -go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= -go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= +github.com/zeebo/xxh3 v1.1.0 h1:s7DLGDK45Dyfg7++yxI0khrfwq9661w9EN78eP/UZVs= +go.mongodb.org/mongo-driver/v2 v2.6.0 h1:b9sJOYrkmt4l8bY43ZenFBcPlhYIjaOfYHLtbB/5qi8= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= +go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZFLdPRmhDUp2zFmQe3RHIOsw24= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 h1:aTL7F04bJHUlztTsNGJ2l+6he8c+y/b//eR0jjjemT4= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0/go.mod h1:kldtb7jDTeol0l3ewcmd8SDvx3EmIE7lyvqbasU3QC4= -go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= -go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= -go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= -go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= -go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= -go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= -go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= -go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= +go.opentelemetry.io/otel/metric v1.44.0 h1:1w0gILTcHdr3YI+ixLyjemwrVnsMURbTZFrSYCdDdmc= +go.opentelemetry.io/otel/sdk v1.44.0 h1:nHYwb9lK+fJPU/dnT6s7W7Z8itMWyqrnVfbheVYrZ58= +go.opentelemetry.io/otel/sdk/metric v1.44.0 h1:3LlKgI+VjbVsjNRFZJZAJ30WjXC5VkNRks6si09iEfI= +go.opentelemetry.io/otel/trace v1.44.0 h1:jxF5CsGYCe74MCRx2X4g7WsY/VBKRqqpNvXlX/6gtIk= go.opentelemetry.io/proto/otlp v1.7.1 h1:gTOMpGDb0WTBOP8JaO72iL3auEZhVmAQg4ipjOVAtj4= go.opentelemetry.io/proto/otlp v1.7.1/go.mod h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE= +go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -337,15 +305,13 @@ golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw= -golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM= +golang.org/x/exp v0.0.0-20260611194520-c48552f49976 h1:X8Hz2ImujgbmetVuW+w2YkyZChE3cBpZi2P158rTG9M= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA= -golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w= +golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -361,8 +327,7 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= -golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= -golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= +golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -371,8 +336,7 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= -golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -396,16 +360,13 @@ golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= -golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= -golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= +golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -415,8 +376,7 @@ golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ= -golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs= +golang.org/x/tools v0.46.0 h1:7jTurBkPZu4moS/Uy4OQT1M+QBlsj3wejyZwsT8Z7rk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -431,17 +391,14 @@ google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCID google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 h1:BIRfGDEjiHRrk0QKZe3Xv2ieMhtgRGeLcZQ0mIVn4EY= -google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5/go.mod h1:j3QtIyytwqGr1JUDtYXwtMXWPKsEa5LtzIFN1Wn5WvE= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 h1:eaY8u2EuxbRv7c3NiGK0/NedzVsCcV6hDuU5qPX5EGE= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5/go.mod h1:M4/wBTSeyLxupu3W3tJtOgB14jILAS/XWPSSa3TAlJc= +google.golang.org/genproto/googleapis/api v0.0.0-20260209200024-4cfbd4190f57 h1:JLQynH/LBHfCTSbDWl+py8C+Rg/k1OVH3xfcaiANuF0= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57 h1:mWPCjDEyshlQYzBpMNHaEof6UX1PmHcaUODUywQ0uac= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.75.0 h1:+TW+dqTd2Biwe6KKfhE5JpiYIBWq865PhKGSXiivqt4= -google.golang.org/grpc v1.75.0/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ= +google.golang.org/grpc v1.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -451,8 +408,7 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc= -google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From c22a38da9a9b6340fdb94d88447cdfb0429ed763 Mon Sep 17 00:00:00 2001 From: qhd <1766646056@qq.com> Date: Wed, 24 Jun 2026 16:17:25 +0800 Subject: [PATCH 07/24] =?UTF-8?q?fix:=20=E5=BF=BD=E7=95=A5=E4=B8=8B?= =?UTF-8?q?=E8=BD=BD=E9=94=99=E8=AF=AF=E4=BB=A5=E9=81=BF=E5=85=8D=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1=E8=AF=AF=E5=A4=B1=E8=B4=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- service/task/worker.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/service/task/worker.go b/service/task/worker.go index 4737274..8816381 100644 --- a/service/task/worker.go +++ b/service/task/worker.go @@ -74,7 +74,8 @@ func (w *asyncWorker) handleOne(ctx context.Context, task *entity.ModelGatewayTa if !strings.Contains(err.Error(), "Timeout") && !strings.Contains(err.Error(), "InternalServiceError") && !strings.Contains(err.Error(), "Invalid video_url") && - !strings.Contains(err.Error(), "Invalid audio track") { + !strings.Contains(err.Error(), "Invalid audio track") && + !strings.Contains(err.Error(), "Error while downloading") { w.failTask(ctx, task, startTime, err.Error()) return } From e11155b6049b2e7525dd5d6770f0b4753a108a80 Mon Sep 17 00:00:00 2001 From: qhd <1766646056@qq.com> Date: Thu, 25 Jun 2026 11:07:07 +0800 Subject: [PATCH 08/24] =?UTF-8?q?fix:=20=E5=BF=BD=E7=95=A5=E8=BF=9E?= =?UTF-8?q?=E6=8E=A5=E9=94=99=E8=AF=AF=E4=BB=A5=E9=81=BF=E5=85=8D=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1=E8=AF=AF=E5=88=A4=E5=A4=B1=E8=B4=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- service/task/worker.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/service/task/worker.go b/service/task/worker.go index 8816381..12c16c6 100644 --- a/service/task/worker.go +++ b/service/task/worker.go @@ -75,7 +75,8 @@ func (w *asyncWorker) handleOne(ctx context.Context, task *entity.ModelGatewayTa !strings.Contains(err.Error(), "InternalServiceError") && !strings.Contains(err.Error(), "Invalid video_url") && !strings.Contains(err.Error(), "Invalid audio track") && - !strings.Contains(err.Error(), "Error while downloading") { + !strings.Contains(err.Error(), "Error while downloading") && + !strings.Contains(err.Error(), "Error while connecting") { w.failTask(ctx, task, startTime, err.Error()) return } From 63092be679396001d9cec40a389d245a7ce3543f Mon Sep 17 00:00:00 2001 From: qhd <1766646056@qq.com> Date: Thu, 25 Jun 2026 11:48:27 +0800 Subject: [PATCH 09/24] =?UTF-8?q?fix:=20=E5=BF=BD=E7=95=A5=20"download=20f?= =?UTF-8?q?ailed"=20=E9=94=99=E8=AF=AF=E9=81=BF=E5=85=8D=E8=AF=AF=E5=88=A4?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E5=A4=B1=E8=B4=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- service/task/worker.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/service/task/worker.go b/service/task/worker.go index 12c16c6..9ffca46 100644 --- a/service/task/worker.go +++ b/service/task/worker.go @@ -76,7 +76,8 @@ func (w *asyncWorker) handleOne(ctx context.Context, task *entity.ModelGatewayTa !strings.Contains(err.Error(), "Invalid video_url") && !strings.Contains(err.Error(), "Invalid audio track") && !strings.Contains(err.Error(), "Error while downloading") && - !strings.Contains(err.Error(), "Error while connecting") { + !strings.Contains(err.Error(), "Error while connecting") && + !strings.Contains(err.Error(), "download failed") { w.failTask(ctx, task, startTime, err.Error()) return } From 3feb912d8602c880de4e73ab31e3cd692a382648 Mon Sep 17 00:00:00 2001 From: qhd <1766646056@qq.com> Date: Thu, 25 Jun 2026 11:57:57 +0800 Subject: [PATCH 10/24] =?UTF-8?q?fix:=20=E5=A2=9E=E5=8A=A0=E6=A8=A1?= =?UTF-8?q?=E5=9E=8B=E8=B0=83=E7=94=A8=E9=87=8D=E8=AF=95=E7=AD=89=E5=BE=85?= =?UTF-8?q?=E6=97=B6=E9=97=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- service/task/worker.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/service/task/worker.go b/service/task/worker.go index 9ffca46..274aa18 100644 --- a/service/task/worker.go +++ b/service/task/worker.go @@ -49,7 +49,7 @@ func (w *asyncWorker) handleOne(ctx context.Context, task *entity.ModelGatewayTa for attempt := 0; ; attempt++ { if attempt > 0 { g.Log().Infof(ctx, "[handleOne] 调模型重试 第%d次 taskId=%s", attempt, task.TaskID) - time.Sleep(time.Duration(attempt) * time.Second) + time.Sleep(time.Duration(attempt) * 5 * time.Second) } switch { From 85dd4e8e8478a85dc8faf26893b33ec89ccf0234 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E6=96=8C?= <259278618@qq.com> Date: Thu, 25 Jun 2026 14:49:02 +0800 Subject: [PATCH 11/24] =?UTF-8?q?common=E7=89=88=E6=9C=AC=E6=9B=B4?= =?UTF-8?q?=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- go.mod | 2 +- go.sum | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 57 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index ee43bc1..ceebe44 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module model-gateway go 1.26.1 require ( - gitea.redpowerfuture.com/red-future/common v0.0.26 + gitea.redpowerfuture.com/red-future/common v0.0.29 github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.10.2 github.com/gogf/gf/contrib/nosql/redis/v2 v2.10.2 github.com/gogf/gf/v2 v2.10.2 diff --git a/go.sum b/go.sum index 3add795..9e4e87b 100644 --- a/go.sum +++ b/go.sum @@ -1,8 +1,9 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -gitea.redpowerfuture.com/red-future/common v0.0.25 h1:TFKmcyByChLc3gBr1mgyWOBmT2acEpS8G2Asm9QmDdo= -gitea.redpowerfuture.com/red-future/common v0.0.25/go.mod h1:50U1Xi+Ie56z09S5LQbZvaken0Mxv3OeS9LgR7U/ZRY= +gitea.redpowerfuture.com/red-future/common v0.0.29 h1:5McaN5pSewvrLUHQzWMX6EaUvD+B5I5bMYoU+clHJk4= +gitea.redpowerfuture.com/red-future/common v0.0.29/go.mod h1:50U1Xi+Ie56z09S5LQbZvaken0Mxv3OeS9LgR7U/ZRY= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk= +github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -36,7 +37,9 @@ github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyM github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/clipperhouse/displaywidth v0.11.0 h1:lBc6kY44VFw+TDx4I8opi/EtL9m20WSEFgwIwO+UVM8= +github.com/clipperhouse/displaywidth v0.11.0/go.mod h1:bkrFNkf81G8HyVqmKGxsPufD3JhNl3dSqnGhOoSD/o0= github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk= +github.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -61,7 +64,9 @@ github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/color v1.19.0 h1:Zp3PiM21/9Ld6FzSKyL5c/BULoe/ONr9KlbYVOfG8+w= +github.com/fatih/color v1.19.0/go.mod h1:zNk67I0ZUT1bEGsSGyCZYZNrHuTkJJB+r6Q9VuMi0LE= github.com/fsnotify/fsnotify v1.10.1 h1:b0/UzAf9yR5rhf3RPm9gf3ehBPpf0oZKIjtpKrx59Ho= +github.com/fsnotify/fsnotify v1.10.1/go.mod h1:TLheqan6HD6GBK6PrDWyDPBaEV8LspOxvPSjC+bVfgo= github.com/go-ego/gse v1.0.2 h1:+27lYFPhQEhA9igtdOsJPRKYL/k3TwYsxBF5jr6KFv4= github.com/go-ego/gse v1.0.2/go.mod h1:Fy35G+q7VV7Et1zIKO8o/sW1kkugV3znXap/lF/11zc= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= @@ -75,7 +80,9 @@ github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro= +github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/goccy/go-json v0.10.6 h1:p8HrPJzOakx/mn/bQtjgNjdTcN+/S6FcG2CTtQOrHVU= +github.com/goccy/go-json v0.10.6/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.10.2 h1:u8EpP24GkprogROnJ7htMov9Fc66pTP1eVYrWxiCYOs= github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.10.2/go.mod h1:GmvM3r8GVByVMi4RD2+MCs5+CfxVXPMeT8mVDkAaAXE= github.com/gogf/gf/contrib/nosql/redis/v2 v2.10.2 h1:iTQegT+lEg/wDKvj2mi3W1wrdrwFarjokf88EXVVgu4= @@ -114,7 +121,9 @@ github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs= github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= +github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/flatbuffers v25.12.19+incompatible h1:haMV2JRRJCe1998HeW/p0X9UaMTK6SDo0ffLn2+DbLs= +github.com/google/flatbuffers v25.12.19+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -132,8 +141,11 @@ github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w7 github.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4= github.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc= github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 h1:HWRh5R2+9EifMyIHV7ZV+MIZqgz+PMpZ14Jynv3O2Zs= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0/go.mod h1:JfhWUomR1baixubs02l85lZYYOm7LV6om4ceouMv45c= github.com/hashicorp/consul/api v1.33.5 h1:Nn6q87zudRU1rLBTJEgaWxz9STCNadilLCD7B8OA5aI= +github.com/hashicorp/consul/api v1.33.5/go.mod h1:pa6fJOSHKLOzNHpUVeqLDtxA5+J1D7NNzLasuk8eRXA= github.com/hashicorp/consul/sdk v0.17.3 h1:oZMMxzQGSsiT+ToOH50y3Qcs0nc9Ud+7L5lRx+EmMU0= +github.com/hashicorp/consul/sdk v0.17.3/go.mod h1:jnOmYjiNfVRpBaujQ1DFFVs0N6g3S1y6wygSjLTzYfc= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -164,6 +176,7 @@ github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.9.0 h1:CeOIz6k+LoN3qX9Z0tyQrPtiB1DFYRPfCIBtaXPSCnA= +github.com/hashicorp/go-version v1.9.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= @@ -179,7 +192,9 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.18.6 h1:2jupLlAwFm95+YDR+NwD2MEfFO9d4z4Prjl1XXDjuao= +github.com/klauspost/compress v1.18.6/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= +github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -190,6 +205,7 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lib/pq v1.12.3 h1:tTWxr2YLKwIvK90ZXEw8GP7UFHtcbTtty8zsI+YjrfQ= +github.com/lib/pq v1.12.3/go.mod h1:/p+8NSbOcwzAEI7wiMXFlgydTwcgTr3OSKMsD2BitpA= github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE= github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= @@ -198,17 +214,21 @@ github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.15 h1:+u9SLTRGnXv73cEsnsmoZBom+dMU88B2M0aDcWy0/jY= +github.com/mattn/go-colorable v0.1.15/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.22 h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw4= +github.com/mattn/go-isatty v0.0.22/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4= github.com/mattn/go-runewidth v0.0.24 h1:cpokDiIn0MGnhdHwuWnJBITySJ20QyNGnY2kR/ay2DU= +github.com/mattn/go-runewidth v0.0.24/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= github.com/miekg/dns v1.1.72 h1:vhmr+TF2A3tuoGNkLDFK9zi36F2LS+hKTRW0Uf8kbzI= +github.com/miekg/dns v1.1.72/go.mod h1:+EuEPhdHOsfk6Wk5TT2CzssZdqkmFhf8r+aVyDEToIs= github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= @@ -219,9 +239,13 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 h1:zrbMGy9YXpIeTnGj4EljqMiZsIcE09mmF8XsD5AYOJc= +github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6/go.mod h1:rEKTHC9roVVicUIfZK7DYrdIoM0EOr8mK1Hj5s3JjH0= github.com/olekukonko/errors v1.3.0 h1:teJvgLGUEqMzBUms+Dj3/3szNqCG/Jdw9iDbum8fR6U= +github.com/olekukonko/errors v1.3.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y= github.com/olekukonko/ll v0.1.8 h1:ysHCJRGHYKzmBSdz9w5AySztx7lG8SQY+naTGYUbsz8= +github.com/olekukonko/ll v0.1.8/go.mod h1:RPRC6UcscfFZgjo1nulkfMH5IM0QAYim0LfnMvUuozw= github.com/olekukonko/tablewriter v1.1.4 h1:ORUMI3dXbMnRlRggJX3+q7OzQFDdvgbN9nVWj1drm6I= +github.com/olekukonko/tablewriter v1.1.4/go.mod h1:+kedxuyTtgoZLwif3P1Em4hARJs+mVnzKxmsCL/C5RY= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= @@ -249,7 +273,9 @@ github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+Gx github.com/r3labs/diff/v2 v2.15.1 h1:EOrVqPUzi+njlumoqJwiS/TgGgmZo83619FNDB9xQUg= github.com/r3labs/diff/v2 v2.15.1/go.mod h1:I8noH9Fc2fjSaMxqF3G2lhDdC0b+JXCfyx85tWFM9kc= github.com/redis/go-redis/v9 v9.21.0 h1:FPBE4hhbAke+TLmcY3WkpbDffJEomdqPn3HYiqAtL9E= +github.com/redis/go-redis/v9 v9.21.0/go.mod h1:v/M13XI1PVCDcm01VtPFOADfZtHf8YW3baQf57KlIkA= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= +github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= @@ -257,19 +283,26 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/tidwall/gjson v1.19.0 h1:xwxm7n691Uf3u5OFjzngavjGTh55KX5q/9w9xHW88JU= github.com/tidwall/gjson v1.19.0/go.mod h1:V37/opeE/JbLUOfH0QTXiNez2l0RUjYUhpT4szFQAfc= github.com/tidwall/match v1.2.0 h1:0pt8FlkOwjN2fPt4bIl4BoNxb98gGHN2ObFEDkrfZnM= +github.com/tidwall/match v1.2.0/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= +github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tiger1103/gfast-token v1.0.10 h1:fNiBE/Dq5iTHvTGlCx3DmXa2o4hr0NtumFpffZ39k6s= github.com/tiger1103/gfast-token v1.0.10/go.mod h1:a/21mxmj7zFeNvjhZSC0XpEAFHfb1aT2k6DXnufFU1s= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= @@ -282,21 +315,31 @@ github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6Ac github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/zeebo/xxh3 v1.1.0 h1:s7DLGDK45Dyfg7++yxI0khrfwq9661w9EN78eP/UZVs= +github.com/zeebo/xxh3 v1.1.0/go.mod h1:IisAie1LELR4xhVinxWS5+zf1lA4p0MW4T+w+W07F5s= go.mongodb.org/mongo-driver/v2 v2.6.0 h1:b9sJOYrkmt4l8bY43ZenFBcPlhYIjaOfYHLtbB/5qi8= +go.mongodb.org/mongo-driver/v2 v2.6.0/go.mod h1:yOI9kBsufol30iFsl1slpdq1I0eHPzybRWdyYUs8K/0= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= +go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU= +go.opentelemetry.io/otel v1.44.0/go.mod h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZFLdPRmhDUp2zFmQe3RHIOsw24= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 h1:aTL7F04bJHUlztTsNGJ2l+6he8c+y/b//eR0jjjemT4= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0/go.mod h1:kldtb7jDTeol0l3ewcmd8SDvx3EmIE7lyvqbasU3QC4= go.opentelemetry.io/otel/metric v1.44.0 h1:1w0gILTcHdr3YI+ixLyjemwrVnsMURbTZFrSYCdDdmc= +go.opentelemetry.io/otel/metric v1.44.0/go.mod h1:8O7hanEPBNgEMmybD3s2VBKcgWOCsA6tzHBPODAiquo= go.opentelemetry.io/otel/sdk v1.44.0 h1:nHYwb9lK+fJPU/dnT6s7W7Z8itMWyqrnVfbheVYrZ58= +go.opentelemetry.io/otel/sdk v1.44.0/go.mod h1:Osuydd3Se74nqjAKxid74N5eC+jfEqfTegHRnq58oK0= go.opentelemetry.io/otel/sdk/metric v1.44.0 h1:3LlKgI+VjbVsjNRFZJZAJ30WjXC5VkNRks6si09iEfI= +go.opentelemetry.io/otel/sdk/metric v1.44.0/go.mod h1:5B5pMARnXxKhltooO4xUuCBorl65a4EpnTalObqOigA= go.opentelemetry.io/otel/trace v1.44.0 h1:jxF5CsGYCe74MCRx2X4g7WsY/VBKRqqpNvXlX/6gtIk= +go.opentelemetry.io/otel/trace v1.44.0/go.mod h1:oLl1jrMQAVo6v3GAggN+1VH9VIz9iUSvW53sW1Q8PIE= go.opentelemetry.io/proto/otlp v1.7.1 h1:gTOMpGDb0WTBOP8JaO72iL3auEZhVmAQg4ipjOVAtj4= go.opentelemetry.io/proto/otlp v1.7.1/go.mod h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= +go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -306,12 +349,14 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20260611194520-c48552f49976 h1:X8Hz2ImujgbmetVuW+w2YkyZChE3cBpZi2P158rTG9M= +golang.org/x/exp v0.0.0-20260611194520-c48552f49976/go.mod h1:vnf4pv9iKZXY58sQE1L86zmNWJ4159e1RkcWiLCkeEY= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ= +golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -328,6 +373,7 @@ golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o= +golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -337,6 +383,7 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM= +golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -361,12 +408,14 @@ golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw= +golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE= +golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -377,6 +426,7 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.46.0 h1:7jTurBkPZu4moS/Uy4OQT1M+QBlsj3wejyZwsT8Z7rk= +golang.org/x/tools v0.46.0/go.mod h1:FrD85F8l+NWL+9XWBSyVSHO6Ne4jutsfIFba7AWQ5Ys= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -392,13 +442,16 @@ google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoA google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto/googleapis/api v0.0.0-20260209200024-4cfbd4190f57 h1:JLQynH/LBHfCTSbDWl+py8C+Rg/k1OVH3xfcaiANuF0= +google.golang.org/genproto/googleapis/api v0.0.0-20260209200024-4cfbd4190f57/go.mod h1:kSJwQxqmFXeo79zOmbrALdflXQeAYcUbgS7PbpMknCY= google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57 h1:mWPCjDEyshlQYzBpMNHaEof6UX1PmHcaUODUywQ0uac= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE= +google.golang.org/grpc v1.79.3/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -409,6 +462,7 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From b00e5d34f471a671400bf47ba0500511cf76d35d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E6=96=8C?= <259278618@qq.com> Date: Thu, 25 Jun 2026 17:05:13 +0800 Subject: [PATCH 12/24] =?UTF-8?q?common=E7=89=88=E6=9C=AC=E6=9B=B4?= =?UTF-8?q?=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .dockerignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 .dockerignore diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..6b8710a --- /dev/null +++ b/.dockerignore @@ -0,0 +1 @@ +.git From 2bc9d76e189748010177add0ad2e5746461c4f03 Mon Sep 17 00:00:00 2001 From: WangLiZhao <1838393649@qq.com> Date: Wed, 1 Jul 2026 15:17:15 +0800 Subject: [PATCH 13/24] =?UTF-8?q?feat(billing):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E8=AE=A1=E8=B4=B9=E7=B3=BB=E7=BB=9F=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common/util/billing.go | 308 ++++++++++++++++++++++++ consts/public/table_name.go | 9 +- model/entity/model_gateway_model.go | 6 +- model/entity/model_gateway_task.go | 3 + service/gateway/gateway_http_service.go | 45 ++++ service/task/task_service.go | 11 +- service/task/worker.go | 25 +- 7 files changed, 396 insertions(+), 11 deletions(-) create mode 100644 common/util/billing.go diff --git a/common/util/billing.go b/common/util/billing.go new file mode 100644 index 0000000..5b296c3 --- /dev/null +++ b/common/util/billing.go @@ -0,0 +1,308 @@ +package util + +import ( + "context" + "fmt" + "math" + "model-gateway/service/gateway" + "strings" + + "github.com/gogf/gf/v2/encoding/gjson" + "github.com/gogf/gf/v2/util/gconv" +) + +// ======================== 计费入口 ======================== + +func CalculateBilling(config map[string]any, billingData map[string]any) map[string]any { + if len(config) == 0 { + return nil + } + switch config["type"] { + case "inference_tier": + return calculateInferenceTierBilling(config, billingData) + case "video_resolution": + return calculateVideoResolutionBilling(config, billingData) + } + return nil +} + +// ======================== 推理模型计费 ======================== + +func calculateInferenceTierBilling(config map[string]any, data map[string]any) map[string]any { + promptTokens := gconv.Int64(data["prompt_tokens"]) + completionTokens := gconv.Int64(data["completion_tokens"]) + hasAudio := gconv.Bool(data["has_audio"]) + inputK := promptTokens / 1000 + + tiers := config["pricing"].(map[string]any)["tiers"].([]any) + var matched map[string]any + for _, t := range tiers { + tier := t.(map[string]any) + if inputK >= gconv.Int64(tier["input_min"]) && inputK <= gconv.Int64(tier["input_max"]) { + matched = tier + break + } + } + if matched == nil { + return nil + } + + var inputPrice float64 + if hasAudio && matched["audio_input_price"] != nil { + inputPrice = gconv.Float64(matched["audio_input_price"]) + } else { + inputPrice = gconv.Float64(matched["input_price"]) + } + outputPrice := gconv.Float64(matched["output_price"]) + + inputCost := float64(promptTokens) * inputPrice / 1000000 + outputCost := float64(completionTokens) * outputPrice / 1000000 + + return map[string]any{ + "model_name": data["model_name"], + "has_audio": hasAudio, + "prompt_tokens": promptTokens, + "completion_tokens": completionTokens, + "total_tokens": promptTokens + completionTokens, + "input_tier": fmt.Sprintf("[%v, %v]", matched["input_min"], matched["input_max"]), + "input_unit_price": inputPrice, + "output_unit_price": outputPrice, + "input_cost": inputCost, + "output_cost": outputCost, + "total_fee": inputCost + outputCost, + } +} + +// ======================== 视频模型计费 ======================== + +func calculateVideoResolutionBilling(config map[string]any, data map[string]any) map[string]any { + pricingPath := buildPricingPath(config, data) + + pricing := config["pricing"].(map[string]any) + unitPrice := gconv.Float64(pricing[pricingPath]) + + var effectiveMinToken float64 + if gconv.Bool(data["input_has_video"]) { + effectiveMinToken = matchMinToken(config, data) + } + + completionTokens := gconv.Float64(data["actual_tokens"]) + realChargeTokens := int64(math.Max(completionTokens, effectiveMinToken)) + totalFee := float64(realChargeTokens) * unitPrice / 1000000 + + if gconv.Bool(config["enable_audio_charge"]) { + totalFee += gconv.Float64(data["audio_word_cnt"]) * gconv.Float64(config["audio_unit_price"]) + } + + return map[string]any{ + "model_name": data["model_name"], + "is_online": data["is_online"], + "video_resolution": data["video_resolution"], + "input_has_video": data["input_has_video"], + "output_duration_sec": data["output_duration_sec"], + "aspect_ratio": data["aspect_ratio"], + "resolution": data["resolution"], + "prompt_tokens": 0, + "completion_tokens": int64(completionTokens), + "total_tokens": realChargeTokens, + "matched_path": pricingPath, + "token_unit_price": unitPrice, + "effective_min_token": effectiveMinToken, + "total_fee": totalFee, + } +} + +// ======================== 数据提取 ======================== + +func ExtractRequestBilling(ctx context.Context, config map[string]any, requestPayload map[string]any) map[string]any { + dimensions := config["dimensions"].(map[string]any) + fields := dimensions["request"].(map[string]any) + data := make(map[string]any) + + for key, path := range fields { + data[key] = extractValue(requestPayload, gconv.String(path)) + } + + if defaults, ok := config["defaults"].(map[string]any); ok { + for k, v := range defaults { + if _, exists := data[k]; !exists || data[k] == nil { + data[k] = v + } + } + } + + // 处理 compute 字段 + if compute, ok := config["compute"].(map[string]any); ok { + for targetField, rule := range compute { + r := rule.(map[string]any) + dependsOn := gconv.String(r["depends_on"]) + dependsValue := gconv.Bool(r["depends_value"]) + + if gconv.Bool(data[dependsOn]) != dependsValue { + continue + } + + switch r["service"] { + case "video_duration": + urls := extractVideoUrls(requestPayload) + if len(urls) > 0 { + resp, err := gateway.GetVideoDuration(ctx, urls) + if err == nil { + data[targetField] = resp.Data.TotalDuration + } + } + } + } + } + return data +} + +func ExtractResponseBilling(config map[string]any, response map[string]any) map[string]any { + dimensions := config["dimensions"].(map[string]any) + fields := dimensions["response"].(map[string]any) + data := make(map[string]any) + + for key, path := range fields { + data[key] = gjson.New(response).Get(gconv.String(path)).Val() + } + return data +} + +// ======================== 内部辅助 ======================== + +func buildPricingPath(config map[string]any, data map[string]any) string { + pathConfig := config["pricing_path"].(map[string]any) + segments := pathConfig["segments"].([]any) + mapping := pathConfig["mapping"].(map[string]any) + + var parts []string + for _, seg := range segments { + segName := gconv.String(seg) + val := gconv.String(data[segName]) + if m, ok := mapping[segName].(map[string]any); ok { + if mapped, exists := m[val]; exists { + val = gconv.String(mapped) + } + } + parts = append(parts, val) + } + return strings.Join(parts, ".") +} + +func matchMinToken(config map[string]any, data map[string]any) float64 { + rule, ok := config["min_token_rule"].(map[string]any) + if !ok { + return 0 + } + + conditionDefs := rule["conditions"].([]any) + rows := rule["rows"].([]any) + + for _, row := range rows { + r := row.(map[string]any) + conditions := r["conditions"].([]any) + matched := true + + for i, cond := range conditions { + condStr := gconv.String(cond) + condDef := conditionDefs[i].(map[string]any) + condName := gconv.String(condDef["name"]) + + switch condDef["type"] { + case "range": + if !matchRange(condStr, gconv.Float64(data[condName])) { + matched = false + } + case "enum": + if gconv.String(data[condName]) != condStr { + matched = false + } + } + } + if matched { + return gconv.Float64(r["min_token"]) + } + } + return 0 +} + +func matchRange(rangeStr string, val float64) bool { + rangeStr = strings.Trim(rangeStr, "[]()") + parts := strings.Split(rangeStr, ",") + if len(parts) != 2 { + return false + } + return val >= gconv.Float64(strings.TrimSpace(parts[0])) && val < gconv.Float64(strings.TrimSpace(parts[1])) +} + +func extractValue(source map[string]any, path string) any { + // 数组求和:rounds.#.duration + if strings.HasPrefix(path, "rounds.#.") && !strings.Contains(path, "==") { + field := strings.TrimPrefix(path, "rounds.#.") + rounds := gjson.New(source).Get("rounds").Array() + var sum float64 + for _, r := range rounds { + if strings.Contains(field, "#") { + parts := strings.SplitN(field, ".#.", 2) + arr := gjson.New(r).Get(parts[0]).Array() + for _, item := range arr { + sum += gconv.Float64(gjson.New(item).Get(parts[1]).Val()) + } + } else { + sum += gconv.Float64(gjson.New(r).Get(field).Val()) + } + } + return sum + } + + // 条件判断:content.#.type==xxx + if strings.Count(path, ".#.") == 1 && strings.Contains(path, "==") { + parts := strings.Split(path, "==") + basePath := parts[0] + typ := parts[1] + arr := gjson.New(source).Get(strings.Split(basePath, ".#.")[0]).Array() + for _, item := range arr { + field := strings.Split(basePath, ".#.")[1] + if gconv.String(gjson.New(item).Get(field).Val()) == typ { + return true + } + } + return false + } + + // 条件判断:rounds.#.content.#.type==xxx(嵌套数组) + if strings.Contains(path, "==video_url") || strings.Contains(path, "==input_audio") { + parts := strings.Split(path, "==") + basePath := parts[0] + typ := parts[1] + segments := strings.Split(basePath, ".#.") + topArr := gjson.New(source).Get(segments[0]).Array() + for _, item := range topArr { + subArr := gjson.New(item).Get(segments[1]).Array() + for _, sub := range subArr { + if gconv.String(gjson.New(sub).Get("type").Val()) == typ { + return true + } + } + } + return false + } + + return gjson.New(source).Get(path).Val() +} + +func extractVideoUrls(body map[string]any) []string { + var urls []string + content := gjson.New(body).Get("content").Array() + for _, c := range content { + item := c.(map[string]any) + if item["type"] == "video_url" { + if v, ok := item["video_url"].(map[string]any); ok { + if url, ok := v["url"].(string); ok { + urls = append(urls, url) + } + } + } + } + return urls +} diff --git a/consts/public/table_name.go b/consts/public/table_name.go index a7f89cb..8afde4d 100644 --- a/consts/public/table_name.go +++ b/consts/public/table_name.go @@ -5,8 +5,9 @@ const ( ) const ( - TableNameModel = "model_gateway_models" // 模型表 - TableNameTask = "model_gateway_task" // 任务表 - TableNameOpLog = "model_gateway_logs_op" // 操作日志表 - TableNameStat = "model_gateway_logs_stat" // 按天统计表 + TableNameModel = "model_gateway_models" // 模型表 + TableNameTask = "model_gateway_task" // 任务表 + TableNameUserBilling = "model_user_billing" // 用户账单表 + TableNameOpLog = "model_gateway_logs_op" // 操作日志表 + TableNameStat = "model_gateway_logs_stat" // 按天统计表 ) diff --git a/model/entity/model_gateway_model.go b/model/entity/model_gateway_model.go index afdeb3e..1640aaf 100644 --- a/model/entity/model_gateway_model.go +++ b/model/entity/model_gateway_model.go @@ -30,7 +30,7 @@ type modelGatewayModelCol struct { StreamConfig string FirstFrame string LastFrame string - MaxTokens string + BillingConfig string } var ModelGatewayModelCol = modelGatewayModelCol{ @@ -61,7 +61,7 @@ var ModelGatewayModelCol = modelGatewayModelCol{ StreamConfig: "stream_config", FirstFrame: "first_frame", LastFrame: "last_frame", - MaxTokens: "max_tokens", + BillingConfig: "billing_config", } type ModelGatewayModel struct { @@ -92,7 +92,7 @@ type ModelGatewayModel struct { StreamConfig map[string]any `orm:"stream_config" json:"streamConfig"` FirstFrame string `orm:"first_frame" json:"firstFrame"` LastFrame string `orm:"last_frame" json:"lastFrame"` - MaxTokens int `orm:"max_tokens" json:"maxTokens"` + BillingConfig map[string]any `orm:"billing_config" json:"billingConfig"` } const ( diff --git a/model/entity/model_gateway_task.go b/model/entity/model_gateway_task.go index eabd320..1bd3d1d 100644 --- a/model/entity/model_gateway_task.go +++ b/model/entity/model_gateway_task.go @@ -22,6 +22,7 @@ type modelGatewayTaskCol struct { RequestPayload string EpicycleId string BuildModelName string + BillingData string } var ModelGatewayTaskCol = modelGatewayTaskCol{ @@ -42,6 +43,7 @@ var ModelGatewayTaskCol = modelGatewayTaskCol{ RequestPayload: "request_payload", EpicycleId: "epicycle_id", BuildModelName: "build_model_name", + BillingData: "billing_data", } // ModelGatewayTask 模型网关任务 @@ -63,6 +65,7 @@ type ModelGatewayTask struct { RequestPayload *RequestPayload `orm:"request_payload" json:"requestPayload"` EpicycleId int64 `orm:"epicycle_id" json:"epicycleId"` BuildModelName string `orm:"build_model_name" json:"buildModelName"` + BillingData map[string]any `orm:"billing_data" json:"billingData"` } // ResultFile OSS 结果文件 diff --git a/service/gateway/gateway_http_service.go b/service/gateway/gateway_http_service.go index 3782545..24a2e9e 100644 --- a/service/gateway/gateway_http_service.go +++ b/service/gateway/gateway_http_service.go @@ -178,6 +178,51 @@ func IsSuperAdmin(ctx context.Context) (res bool, err error) { return r["isSuperAdmin"], err } +// VideoDurationResp 视频时长接口返回 +type VideoDurationResp struct { + Code int `json:"code"` + Message string `json:"message"` + Data struct { + Videos []VideoInfo `json:"videos"` + Count int `json:"count"` + TotalDuration float64 `json:"totalDuration"` // 秒 + TotalDurationStr string `json:"totalDurationStr"` + } `json:"data"` +} + +type VideoInfo struct { + Index int `json:"index"` + VideoUrl string `json:"videoUrl"` + Duration float64 `json:"duration"` + DurationStr string `json:"durationStr"` +} + +// GetVideoDuration 获取视频时长 +func GetVideoDuration(ctx context.Context, urls []string) (VideoDurationResp, error) { + apiURL := "medi/video/duration" + headers := make(map[string]string) + if r := g.RequestFromCtx(ctx); r != nil { + for k, v := range r.Request.Header { + if len(v) > 0 { + headers[k] = v[0] + } + } + } + + body := map[string]any{"video_urls": urls} + jsonData, _ := json.Marshal(body) + + var resp VideoDurationResp + err := commonHttp.Post(ctx, apiURL, headers, &resp, jsonData) + if err != nil { + g.Log().Warningf(ctx, "[视频时长] 获取失败 err=%v", err) + return resp, err + } + + g.Log().Infof(ctx, "[视频时长] 获取成功 count=%d totalDuration=%.2f", resp.Data.Count, resp.Data.TotalDuration) + return resp, nil +} + //// callback 向回调地址 POST 任务结果(与查询接口 GetTaskRes 出参一致) //func (s *audioTaskService) callback(ctx context.Context, taskID, status, errMsg, callbackURL string) { // if callbackURL == "" { diff --git a/service/task/task_service.go b/service/task/task_service.go index 06c095d..91336d2 100644 --- a/service/task/task_service.go +++ b/service/task/task_service.go @@ -107,7 +107,16 @@ func (s *taskService) Create(ctx context.Context, req *dto.CreateTaskReq) (res * ResponsePayload: gdb.Map{"taskId": taskID}, }) - // 6) 异步执行任务 + // 6) 模型计费 + if len(model.BillingConfig) > 0 { + task.BillingData = util.ExtractRequestBilling(ctx, model.BillingConfig, req.RequestPayload) + _, _ = dao.ModelGatewayTask.Update(ctx, &entity.ModelGatewayTask{ + SQLBaseDO: beans.SQLBaseDO{Id: task.Id}, + BillingData: task.BillingData, + }) + } + + // 7) 异步执行任务 go AsyncWorker.handleOne(util.AsyncCtx(ctx), task, model, req) return &dto.CreateTaskRes{TaskID: taskID}, nil diff --git a/service/task/worker.go b/service/task/worker.go index 4737274..6b824f6 100644 --- a/service/task/worker.go +++ b/service/task/worker.go @@ -53,12 +53,12 @@ func (w *asyncWorker) handleOne(ctx context.Context, task *entity.ModelGatewayTa } switch { - case model.CallMode != nil && *model.CallMode == public.CallModeStream: + case model.CallMode != nil && *model.CallMode == public.CallModeStream: // 流式模型 rawBytes, err = InvokeModel(ctx, model, body) if err == nil { result, err = util.ParseStreamResponse(rawBytes, model.StreamConfig) } - case model.CallMode != nil && *model.CallMode == public.CallModeAsync: + case model.CallMode != nil && *model.CallMode == public.CallModeAsync: // 异步模型 result, err = w.callModel(ctx, task, model, body) if err == nil { result, err = util.PullTaskResult(ctx, result, model.QueryConfig, model.HeadMsg) @@ -122,7 +122,27 @@ func (w *asyncWorker) handleOne(ctx context.Context, task *entity.ModelGatewayTa FileSize: int64(oss.FileSize), } task.TextResult = result + // 计费处理 + if len(model.BillingConfig) > 0 { + // 补充返回阶段数据 + responseData := util.ExtractResponseBilling(model.BillingConfig, result) + if task.BillingData == nil { + task.BillingData = make(map[string]any) + } + for k, v := range responseData { + task.BillingData[k] = v + } + // 计算费用 + billingResult := util.CalculateBilling(model.BillingConfig, task.BillingData) + if billingResult != nil { + for k, v := range billingResult { + task.BillingData[k] = v + } + } + } + + // 更新任务表(含计费数据) if _, err = dao.ModelGatewayTask.Update(ctx, task); err != nil { g.Log().Errorf(ctx, "[handleOne] 更新DB失败 taskId=%s err=%v", task.TaskID, err) return @@ -195,7 +215,6 @@ func (w *asyncWorker) callModel(ctx context.Context, task *entity.ModelGatewayTa if err != nil { return nil, err } - contentType, _ := util.DetectFileType(data) var textResult string if utf8.Valid(data) && (strings.HasPrefix(contentType, "text/") || contentType == "application/json") { From 8ef6a180f7d23082abd1fb9c6f26c7520e3065c9 Mon Sep 17 00:00:00 2001 From: WangLiZhao <1838393649@qq.com> Date: Wed, 1 Jul 2026 15:39:25 +0800 Subject: [PATCH 14/24] =?UTF-8?q?refactor(billing):=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E6=9D=A1=E4=BB=B6=E5=88=A4=E6=96=AD=E9=80=BB=E8=BE=91=E5=B9=B6?= =?UTF-8?q?=E7=A7=BB=E9=99=A4=E6=9C=AA=E4=BD=BF=E7=94=A8=E7=9A=84=E5=B8=B8?= =?UTF-8?q?=E9=87=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common/util/billing.go | 30 ++++++++++++++---------------- consts/public/table_name.go | 9 ++++----- 2 files changed, 18 insertions(+), 21 deletions(-) diff --git a/common/util/billing.go b/common/util/billing.go index 5b296c3..baf6975 100644 --- a/common/util/billing.go +++ b/common/util/billing.go @@ -255,27 +255,25 @@ func extractValue(source map[string]any, path string) any { return sum } - // 条件判断:content.#.type==xxx - if strings.Count(path, ".#.") == 1 && strings.Contains(path, "==") { - parts := strings.Split(path, "==") - basePath := parts[0] - typ := parts[1] - arr := gjson.New(source).Get(strings.Split(basePath, ".#.")[0]).Array() - for _, item := range arr { - field := strings.Split(basePath, ".#.")[1] - if gconv.String(gjson.New(item).Get(field).Val()) == typ { - return true - } - } - return false - } - - // 条件判断:rounds.#.content.#.type==xxx(嵌套数组) + // 条件判断:xxx.#.type==yyy 或 rounds.#.content.#.type==yyy if strings.Contains(path, "==video_url") || strings.Contains(path, "==input_audio") { parts := strings.Split(path, "==") basePath := parts[0] typ := parts[1] segments := strings.Split(basePath, ".#.") + + // 单层:content.#.type → segments = ["content", "type"] + if len(segments) == 2 && !strings.Contains(segments[0], ".") { + arr := gjson.New(source).Get(segments[0]).Array() + for _, item := range arr { + if gconv.String(gjson.New(item).Get(segments[1]).Val()) == typ { + return true + } + } + return false + } + + // 嵌套:rounds.#.content.#.type → segments = ["rounds", "content", "type"] topArr := gjson.New(source).Get(segments[0]).Array() for _, item := range topArr { subArr := gjson.New(item).Get(segments[1]).Array() diff --git a/consts/public/table_name.go b/consts/public/table_name.go index 8afde4d..a7f89cb 100644 --- a/consts/public/table_name.go +++ b/consts/public/table_name.go @@ -5,9 +5,8 @@ const ( ) const ( - TableNameModel = "model_gateway_models" // 模型表 - TableNameTask = "model_gateway_task" // 任务表 - TableNameUserBilling = "model_user_billing" // 用户账单表 - TableNameOpLog = "model_gateway_logs_op" // 操作日志表 - TableNameStat = "model_gateway_logs_stat" // 按天统计表 + TableNameModel = "model_gateway_models" // 模型表 + TableNameTask = "model_gateway_task" // 任务表 + TableNameOpLog = "model_gateway_logs_op" // 操作日志表 + TableNameStat = "model_gateway_logs_stat" // 按天统计表 ) From 3ca8f937789c093358526b7364c142466f7f5156 Mon Sep 17 00:00:00 2001 From: qhd <1766646056@qq.com> Date: Wed, 1 Jul 2026 15:53:28 +0800 Subject: [PATCH 15/24] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E8=A7=86?= =?UTF-8?q?=E9=A2=91=E6=97=B6=E9=95=BF=E6=8E=A5=E5=8F=A3=E5=93=8D=E5=BA=94?= =?UTF-8?q?=E7=BB=93=E6=9E=84=E5=8F=8AURL=E6=8B=BC=E5=86=99=E9=94=99?= =?UTF-8?q?=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 移除VideoDurationResp中多余的嵌套Data字段,直接访问TotalDuration等属性; 修正API路径中缺失的字母a(medi -> media)。 --- common/util/billing.go | 2 +- service/gateway/gateway_http_service.go | 16 ++++++---------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/common/util/billing.go b/common/util/billing.go index baf6975..485f5ce 100644 --- a/common/util/billing.go +++ b/common/util/billing.go @@ -148,7 +148,7 @@ func ExtractRequestBilling(ctx context.Context, config map[string]any, requestPa if len(urls) > 0 { resp, err := gateway.GetVideoDuration(ctx, urls) if err == nil { - data[targetField] = resp.Data.TotalDuration + data[targetField] = resp.TotalDuration } } } diff --git a/service/gateway/gateway_http_service.go b/service/gateway/gateway_http_service.go index 24a2e9e..db67b7e 100644 --- a/service/gateway/gateway_http_service.go +++ b/service/gateway/gateway_http_service.go @@ -180,14 +180,10 @@ func IsSuperAdmin(ctx context.Context) (res bool, err error) { // VideoDurationResp 视频时长接口返回 type VideoDurationResp struct { - Code int `json:"code"` - Message string `json:"message"` - Data struct { - Videos []VideoInfo `json:"videos"` - Count int `json:"count"` - TotalDuration float64 `json:"totalDuration"` // 秒 - TotalDurationStr string `json:"totalDurationStr"` - } `json:"data"` + Videos []VideoInfo `json:"videos"` + Count int `json:"count"` + TotalDuration float64 `json:"totalDuration"` + TotalDurationStr string `json:"totalDurationStr"` } type VideoInfo struct { @@ -199,7 +195,7 @@ type VideoInfo struct { // GetVideoDuration 获取视频时长 func GetVideoDuration(ctx context.Context, urls []string) (VideoDurationResp, error) { - apiURL := "medi/video/duration" + apiURL := "media/video/duration" headers := make(map[string]string) if r := g.RequestFromCtx(ctx); r != nil { for k, v := range r.Request.Header { @@ -219,7 +215,7 @@ func GetVideoDuration(ctx context.Context, urls []string) (VideoDurationResp, er return resp, err } - g.Log().Infof(ctx, "[视频时长] 获取成功 count=%d totalDuration=%.2f", resp.Data.Count, resp.Data.TotalDuration) + g.Log().Infof(ctx, "[视频时长] 获取成功 count=%d totalDuration=%.2f", resp.Count, resp.TotalDuration) return resp, nil } From 326a8acac903718012d88d66cb4c672e72e32634 Mon Sep 17 00:00:00 2001 From: WangLiZhao <1838393649@qq.com> Date: Wed, 1 Jul 2026 15:54:01 +0800 Subject: [PATCH 16/24] =?UTF-8?q?feat(gateway):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E8=AE=A1=E8=B4=B9=E6=97=A5=E6=9C=9F=E5=AD=97=E6=AE=B5=E5=88=B0?= =?UTF-8?q?=E5=9B=9E=E8=B0=83=E8=AF=B7=E6=B1=82=E4=BD=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在CallbackPayload结构体中添加BillingDate字段 - 将任务的BillingData赋值给回调请求体的BillingDate - 保持现有回调功能的其他字段不变 --- service/gateway/gateway_http_service.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/service/gateway/gateway_http_service.go b/service/gateway/gateway_http_service.go index 24a2e9e..3831b2c 100644 --- a/service/gateway/gateway_http_service.go +++ b/service/gateway/gateway_http_service.go @@ -77,11 +77,12 @@ func UploadByTask(ctx context.Context, data []byte, fileExt string) (oss *Upload // CallbackPayload 回调请求体 type CallbackPayload struct { - TaskId string `json:"task_id"` - State int `json:"state"` - OssFile string `json:"oss_file"` - FileType string `json:"file_type"` - ErrorMsg string `json:"error_msg"` + TaskId string `json:"task_id"` + State int `json:"state"` + OssFile string `json:"oss_file"` + FileType string `json:"file_type"` + ErrorMsg string `json:"error_msg"` + BillingDate map[string]any `json:"billing_data"` } // TriggerCallback 任务的回调 @@ -104,6 +105,7 @@ func TriggerCallback(ctx context.Context, t *entity.ModelGatewayTask) { if !g.IsEmpty(t.ResultFile) { payload.OssFile = t.ResultFile.OssFile payload.FileType = t.ResultFile.FileType + payload.BillingDate = t.BillingData } jsonData, err := json.Marshal(payload) if err != nil { From 35e955a617e7cf86748e93dba803e6959b468751 Mon Sep 17 00:00:00 2001 From: WangLiZhao <1838393649@qq.com> Date: Wed, 1 Jul 2026 17:41:01 +0800 Subject: [PATCH 17/24] =?UTF-8?q?feat(billing):=20=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=E5=A4=9A=E6=9D=A1=E8=AE=A1=E8=B4=B9=E6=95=B0=E6=8D=AE=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E5=B9=B6=E4=BC=98=E5=8C=96=E6=A8=A1=E5=9E=8B=E8=AE=A1?= =?UTF-8?q?=E8=B4=B9=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common/util/billing.go | 26 +-- model/entity/model_gateway_task.go | 34 ++-- service/gateway/gateway_http_service.go | 12 +- service/task/task_service.go | 3 +- service/task/worker.go | 222 +++++++++++------------- 5 files changed, 141 insertions(+), 156 deletions(-) diff --git a/common/util/billing.go b/common/util/billing.go index 485f5ce..1e8eb71 100644 --- a/common/util/billing.go +++ b/common/util/billing.go @@ -18,9 +18,9 @@ func CalculateBilling(config map[string]any, billingData map[string]any) map[str return nil } switch config["type"] { - case "inference_tier": + case "inference_tier": //推理模型计费 return calculateInferenceTierBilling(config, billingData) - case "video_resolution": + case "video_resolution": //视频模型计费 return calculateVideoResolutionBilling(config, billingData) } return nil @@ -58,18 +58,20 @@ func calculateInferenceTierBilling(config map[string]any, data map[string]any) m inputCost := float64(promptTokens) * inputPrice / 1000000 outputCost := float64(completionTokens) * outputPrice / 1000000 + // 推理模型 return map[string]any{ - "model_name": data["model_name"], - "has_audio": hasAudio, + "model_name": data["model_name"], + "total_tokens": promptTokens + completionTokens, + "total_fee": inputCost + outputCost, + // 明细 "prompt_tokens": promptTokens, "completion_tokens": completionTokens, - "total_tokens": promptTokens + completionTokens, + "has_audio": hasAudio, "input_tier": fmt.Sprintf("[%v, %v]", matched["input_min"], matched["input_max"]), "input_unit_price": inputPrice, "output_unit_price": outputPrice, "input_cost": inputCost, "output_cost": outputCost, - "total_fee": inputCost + outputCost, } } @@ -94,21 +96,23 @@ func calculateVideoResolutionBilling(config map[string]any, data map[string]any) totalFee += gconv.Float64(data["audio_word_cnt"]) * gconv.Float64(config["audio_unit_price"]) } + // 视频模型 return map[string]any{ - "model_name": data["model_name"], + "model_name": data["model_name"], + "total_tokens": realChargeTokens, + "total_fee": totalFee, + // 明细 + "prompt_tokens": 0, + "completion_tokens": int64(completionTokens), "is_online": data["is_online"], "video_resolution": data["video_resolution"], "input_has_video": data["input_has_video"], "output_duration_sec": data["output_duration_sec"], "aspect_ratio": data["aspect_ratio"], "resolution": data["resolution"], - "prompt_tokens": 0, - "completion_tokens": int64(completionTokens), - "total_tokens": realChargeTokens, "matched_path": pricingPath, "token_unit_price": unitPrice, "effective_min_token": effectiveMinToken, - "total_fee": totalFee, } } diff --git a/model/entity/model_gateway_task.go b/model/entity/model_gateway_task.go index 1bd3d1d..5a5eddc 100644 --- a/model/entity/model_gateway_task.go +++ b/model/entity/model_gateway_task.go @@ -49,23 +49,23 @@ var ModelGatewayTaskCol = modelGatewayTaskCol{ // ModelGatewayTask 模型网关任务 type ModelGatewayTask struct { beans.SQLBaseDO `orm:",inline"` - ModelName string `orm:"model_name" json:"modelName"` - TaskID string `orm:"task_id" json:"taskId"` - BizName string `orm:"biz_name" json:"bizName"` - CallbackURL string `orm:"callback_url" json:"callbackUrl"` - State int `orm:"state" json:"state"` - Phase int `orm:"phase" json:"phase"` - ErrorMsg string `orm:"error_msg" json:"errorMsg"` - ResultFile *ResultFile `orm:"result_file" json:"resultFile"` - TextResult map[string]any `orm:"text_result" json:"text"` - ExpendTokens int64 `orm:"expend_tokens" json:"expendTokens"` - DurationSeconds int64 `orm:"duration_seconds" json:"durationSeconds"` - RetryCount int `orm:"retry_count" json:"retryCount"` - TmpFile string `orm:"tmp_file" json:"tmpFile"` - RequestPayload *RequestPayload `orm:"request_payload" json:"requestPayload"` - EpicycleId int64 `orm:"epicycle_id" json:"epicycleId"` - BuildModelName string `orm:"build_model_name" json:"buildModelName"` - BillingData map[string]any `orm:"billing_data" json:"billingData"` + ModelName string `orm:"model_name" json:"modelName"` + TaskID string `orm:"task_id" json:"taskId"` + BizName string `orm:"biz_name" json:"bizName"` + CallbackURL string `orm:"callback_url" json:"callbackUrl"` + State int `orm:"state" json:"state"` + Phase int `orm:"phase" json:"phase"` + ErrorMsg string `orm:"error_msg" json:"errorMsg"` + ResultFile *ResultFile `orm:"result_file" json:"resultFile"` + TextResult map[string]any `orm:"text_result" json:"text"` + ExpendTokens int64 `orm:"expend_tokens" json:"expendTokens"` + DurationSeconds int64 `orm:"duration_seconds" json:"durationSeconds"` + RetryCount int `orm:"retry_count" json:"retryCount"` + TmpFile string `orm:"tmp_file" json:"tmpFile"` + RequestPayload *RequestPayload `orm:"request_payload" json:"requestPayload"` + EpicycleId int64 `orm:"epicycle_id" json:"epicycleId"` + BuildModelName string `orm:"build_model_name" json:"buildModelName"` + BillingData []map[string]any `orm:"billing_data" json:"billingData"` } // ResultFile OSS 结果文件 diff --git a/service/gateway/gateway_http_service.go b/service/gateway/gateway_http_service.go index 0600dd3..de03280 100644 --- a/service/gateway/gateway_http_service.go +++ b/service/gateway/gateway_http_service.go @@ -77,12 +77,12 @@ func UploadByTask(ctx context.Context, data []byte, fileExt string) (oss *Upload // CallbackPayload 回调请求体 type CallbackPayload struct { - TaskId string `json:"task_id"` - State int `json:"state"` - OssFile string `json:"oss_file"` - FileType string `json:"file_type"` - ErrorMsg string `json:"error_msg"` - BillingDate map[string]any `json:"billing_data"` + TaskId string `json:"task_id"` + State int `json:"state"` + OssFile string `json:"oss_file"` + FileType string `json:"file_type"` + ErrorMsg string `json:"error_msg"` + BillingDate []map[string]any `json:"billing_data"` } // TriggerCallback 任务的回调 diff --git a/service/task/task_service.go b/service/task/task_service.go index 91336d2..3d83461 100644 --- a/service/task/task_service.go +++ b/service/task/task_service.go @@ -109,7 +109,8 @@ func (s *taskService) Create(ctx context.Context, req *dto.CreateTaskReq) (res * // 6) 模型计费 if len(model.BillingConfig) > 0 { - task.BillingData = util.ExtractRequestBilling(ctx, model.BillingConfig, req.RequestPayload) + requestData := util.ExtractRequestBilling(ctx, model.BillingConfig, req.RequestPayload) + task.BillingData = append(task.BillingData, requestData) _, _ = dao.ModelGatewayTask.Update(ctx, &entity.ModelGatewayTask{ SQLBaseDO: beans.SQLBaseDO{Id: task.Id}, BillingData: task.BillingData, diff --git a/service/task/worker.go b/service/task/worker.go index 4568d69..322e1c3 100644 --- a/service/task/worker.go +++ b/service/task/worker.go @@ -6,18 +6,16 @@ import ( "encoding/json" "fmt" "io" - "net/http" - "strings" - "sync" - "time" - "unicode/utf8" - "model-gateway/common/util" "model-gateway/consts/public" "model-gateway/dao" "model-gateway/model/dto" "model-gateway/model/entity" "model-gateway/service/gateway" + "net/http" + "strings" + "sync" + "time" "gitea.redpowerfuture.com/red-future/common/beans" "github.com/gogf/gf/v2/encoding/gjson" @@ -36,7 +34,7 @@ func (w *asyncWorker) handleOne(ctx context.Context, task *entity.ModelGatewayTa body = task.RequestPayload.Body maxRetry = model.RetryTimes startTime = time.Now() - rawBytes []byte + rawData []byte result map[string]any err error ) @@ -52,25 +50,27 @@ func (w *asyncWorker) handleOne(ctx context.Context, task *entity.ModelGatewayTa time.Sleep(time.Duration(attempt) * 5 * time.Second) } + rawData, err = InvokeModel(ctx, model, body) switch { - case model.CallMode != nil && *model.CallMode == public.CallModeStream: // 流式模型 - rawBytes, err = InvokeModel(ctx, model, body) + case model.CallMode != nil && *model.CallMode == public.CallModeStream: if err == nil { - result, err = util.ParseStreamResponse(rawBytes, model.StreamConfig) + result, err = util.ParseStreamResponse(rawData, model.StreamConfig) } - case model.CallMode != nil && *model.CallMode == public.CallModeAsync: // 异步模型 - result, err = w.callModel(ctx, task, model, body) + case model.CallMode != nil && *model.CallMode == public.CallModeAsync: if err == nil { + result = gjson.New(string(rawData)).Map() result, err = util.PullTaskResult(ctx, result, model.QueryConfig, model.HeadMsg) } default: - result, err = w.callModel(ctx, task, model, body) + if err == nil { + result = gjson.New(string(rawData)).Map() + } } if err == nil { break } - + // 模型调用失败 if !strings.Contains(err.Error(), "Timeout") && !strings.Contains(err.Error(), "InternalServiceError") && !strings.Contains(err.Error(), "Invalid video_url") && @@ -86,24 +86,47 @@ func (w *asyncWorker) handleOne(ctx context.Context, task *entity.ModelGatewayTa } // ============================================ - // 2) 解析校验 + 响应映射(可重试) + // 2) 解析返回映射 + 存储 token 相关信息 // ============================================ - result, err = w.parseAndRetry(ctx, result, task, model, req, maxRetry, startTime) + mapped, err := util.MapResponsePayload(model.ResponseMapping, result) if err != nil { - task.TextResult = result w.failTask(ctx, task, startTime, err.Error()) return } + // 计费处理 + if len(model.BillingConfig) > 0 { + responseData := util.ExtractResponseBilling(model.BillingConfig, mapped) + billingResult := util.CalculateBilling(model.BillingConfig, responseData) + if billingResult != nil { + task.BillingData = append(task.BillingData, billingResult) + } + } + task.ExpendTokens = gconv.Int64(mapped[entity.TotalTokens]) + if _, err = dao.ModelGatewayTask.Update(ctx, task); err != nil { + g.Log().Errorf(ctx, "[handleOne] 更新DB失败 taskId=%s err=%v", task.TaskID, err) + return + } // ============================================ - // 3) 上传 OSS(可重试) + // 3) 处理提示词相关数据解析涵盖重试 + // ============================================ + if req.BuildType == public.BuildTypePrompt { + mapped, err = w.parseAndRetry(ctx, mapped, task, model, maxRetry) + if err != nil { + w.failTask(ctx, task, startTime, err.Error()) + return + } + } + + // ============================================ + // 4) 上传 OSS(可重试) // ============================================ var oss *gateway.UploadFileResponse for attempt := 0; attempt <= maxRetry; attempt++ { if attempt > 0 { g.Log().Infof(ctx, "[handleOne] OSS上传重试 第%d/%d次 taskId=%s", attempt, maxRetry, task.TaskID) } - oss, err = gateway.UploadByTask(ctx, gjson.New(result).MustToJson(), "json") + oss, err = gateway.UploadByTask(ctx, gjson.New(mapped).MustToJson(), "json") if err == nil { break } @@ -115,7 +138,7 @@ func (w *asyncWorker) handleOne(ctx context.Context, task *entity.ModelGatewayTa } // ============================================ - // 4) 成功收尾 + // 5) 成功收尾 // ============================================ task.State = public.TaskStatusSuccess task.DurationSeconds = int64(time.Since(startTime).Seconds()) @@ -124,28 +147,7 @@ func (w *asyncWorker) handleOne(ctx context.Context, task *entity.ModelGatewayTa FileType: oss.FileFormat, FileSize: int64(oss.FileSize), } - task.TextResult = result - // 计费处理 - if len(model.BillingConfig) > 0 { - // 补充返回阶段数据 - responseData := util.ExtractResponseBilling(model.BillingConfig, result) - if task.BillingData == nil { - task.BillingData = make(map[string]any) - } - for k, v := range responseData { - task.BillingData[k] = v - } - - // 计算费用 - billingResult := util.CalculateBilling(model.BillingConfig, task.BillingData) - if billingResult != nil { - for k, v := range billingResult { - task.BillingData[k] = v - } - } - } - - // 更新任务表(含计费数据) + task.TextResult = mapped if _, err = dao.ModelGatewayTask.Update(ctx, task); err != nil { g.Log().Errorf(ctx, "[handleOne] 更新DB失败 taskId=%s err=%v", task.TaskID, err) return @@ -171,10 +173,11 @@ var asyncTaskChan = sync.Map{} // taskID → chan asyncResult func (w *asyncWorker) callModelAsync(ctx context.Context, task *entity.ModelGatewayTask, model *entity.ModelGatewayModel, body map[string]any) (map[string]any, error) { // 1. 提交异步任务 - body, err := w.callModel(ctx, task, model, body) + rawData, err := InvokeModel(ctx, model, body) if err != nil { return nil, err } + body = gjson.New(string(rawData)).Map() // 2. 拿到 task_id taskID := gjson.New(body).Get(entity.ResponseBody).String() @@ -212,81 +215,39 @@ func NotifyAsyncResult(taskID string, result map[string]any, err error) { } } -// callModel 调用模型 + 提取文本结果 -func (w *asyncWorker) callModel(ctx context.Context, task *entity.ModelGatewayTask, model *entity.ModelGatewayModel, body map[string]any) (map[string]any, error) { - data, err := InvokeModel(ctx, model, body) - if err != nil { - return nil, err - } - contentType, _ := util.DetectFileType(data) - var textResult string - if utf8.Valid(data) && (strings.HasPrefix(contentType, "text/") || contentType == "application/json") { - textResult = string(data) - } - - if textResult == "" { - return nil, fmt.Errorf("模型返回非文本内容,contentType=%s", contentType) - } - - return gjson.New(textResult).Map(), nil -} +//// callModel 调用模型 + 提取文本结果 +//func (w *asyncWorker) callModel(ctx context.Context, task *entity.ModelGatewayTask, model *entity.ModelGatewayModel, body map[string]any) (map[string]any, error) { +// data, err := InvokeModel(ctx, model, body) +// if err != nil { +// return nil, err +// } +// contentType, _ := util.DetectFileType(data) +// var textResult string +// if utf8.Valid(data) && (strings.HasPrefix(contentType, "text/") || contentType == "application/json") { +// textResult = string(data) +// } +// +// if textResult == "" { +// return nil, fmt.Errorf("模型返回非文本内容,contentType=%s", contentType) +// } +// +// return gjson.New(textResult).Map(), nil +//} // parseAndRetry 解析模型返回结果,并重试 -func (w *asyncWorker) parseAndRetry(ctx context.Context, body map[string]any, task *entity.ModelGatewayTask, model *entity.ModelGatewayModel, req *dto.CreateTaskReq, maxRetry int, startTime time.Time) (map[string]any, error) { - // 0) 如果指定了构建模型,查出校验字段 - var requiredFields []string - if task.BuildModelName != "" { - buildModel, _ := dao.ModelGatewayModels.Get(ctx, &entity.ModelGatewayModel{ - SQLBaseDO: beans.SQLBaseDO{ - TenantId: model.TenantId, - Creator: model.Creator, - }, - ModelName: req.BuildModelName, - }) - if buildModel != nil { - requiredFields = buildModel.RequiredFields - } - } - +func (w *asyncWorker) parseAndRetry(ctx context.Context, body map[string]any, task *entity.ModelGatewayTask, model *entity.ModelGatewayModel, maxRetry int) (map[string]any, error) { var lastErr error for attempt := 0; attempt <= maxRetry; attempt++ { if attempt > 0 { g.Log().Infof(ctx, "[执行任务][重试] JSON解析 第%d/%d次 taskId=%s", attempt, maxRetry, task.TaskID) } - // 1) 响应映射 - mapped, err := util.MapResponsePayload(model.ResponseMapping, body) - if err != nil { - lastErr = err - g.Log().Warningf(ctx, "[执行任务][映射失败] taskId=%s attempt=%d/%d err=%v", task.TaskID, attempt, maxRetry, err) - if attempt == maxRetry { - return nil, fmt.Errorf("响应映射重试耗尽: %w", err) - } - continue - } - // 2) 存 token - if _, ok := mapped[entity.TotalTokens]; ok { - task.ExpendTokens = gconv.Int64(mapped[entity.TotalTokens]) - _, _ = dao.ModelGatewayTask.Update(ctx, &entity.ModelGatewayTask{ - SQLBaseDO: beans.SQLBaseDO{Id: task.Id}, - ExpendTokens: task.ExpendTokens, - }) - } - - // 3) 解析 + 校验(用 buildModel 的 RequiredFields) - var parsed map[string]any - switch req.BuildType { - case public.BuildTypePrompt, public.BuildTypeNode: - parsed, err = util.ParseAndValidate(mapped, requiredFields) - if err == nil { - return parsed, nil - } - lastErr = err - case public.BuildTypeStruct: - return util.ParseStructResult(mapped, entity.ResponseBody), nil - default: - return mapped, nil + // 解析 + 校验 + parsed, err := util.ParseAndValidate(body, model.RequiredFields) + if err == nil { + return parsed, nil } + lastErr = err g.Log().Warningf(ctx, "[执行任务][解析失败] taskId=%s attempt=%d/%d err=%v", task.TaskID, attempt, maxRetry, err) @@ -294,23 +255,45 @@ func (w *asyncWorker) parseAndRetry(ctx context.Context, body map[string]any, ta return nil, fmt.Errorf("JSON解析重试耗尽: %w", lastErr) } - // 4) 拼接错误信息到请求体,重调模型 + // 重试:重新调模型 task.RetryCount++ _, _ = dao.ModelGatewayTask.Update(ctx, task) - body = injectErrorMessage(task.RequestPayload.Body, lastErr) - rawData, callErr := InvokeModel(ctx, model, body) + reqBody := injectErrorMessage(task.RequestPayload.Body, lastErr) + rawData, callErr := InvokeModel(ctx, model, reqBody) if callErr != nil { g.Log().Warningf(ctx, "[执行任务][重调模型失败] taskId=%s attempt=%d/%d err=%v", task.TaskID, attempt, maxRetry, callErr) continue } + // 响应映射 var rawResp map[string]any - if err = json.Unmarshal(rawData, &rawResp); err != nil { + if err := json.Unmarshal(rawData, &rawResp); err != nil { g.Log().Warningf(ctx, "[执行任务][Unmarshal失败] taskId=%s err=%v", task.TaskID, err) continue } - body = rawResp + mapped, mapErr := util.MapResponsePayload(model.ResponseMapping, rawResp) + if mapErr != nil { + g.Log().Warningf(ctx, "[执行任务][映射失败] taskId=%s err=%v", task.TaskID, mapErr) + continue + } + + // 记录重试计费 + if len(model.BillingConfig) > 0 { + responseData := util.ExtractResponseBilling(model.BillingConfig, mapped) + billingResult := util.CalculateBilling(model.BillingConfig, responseData) + if billingResult != nil { + task.BillingData = append(task.BillingData, billingResult) + } + task.ExpendTokens += gconv.Int64(mapped[entity.TotalTokens]) + _, _ = dao.ModelGatewayTask.Update(ctx, &entity.ModelGatewayTask{ + SQLBaseDO: beans.SQLBaseDO{Id: task.Id}, + BillingData: task.BillingData, + ExpendTokens: task.ExpendTokens, + }) + } + + body = mapped } return body, nil @@ -361,13 +344,6 @@ func injectErrorMessage(payload map[string]any, err error) map[string]any { // InvokeModel 调用模型服务,返回二进制结果 // modelKey 用于覆盖/补充模型配置 head_msg(例如每次请求携带不同的 X-API-Key) func InvokeModel(ctx context.Context, model *entity.ModelGatewayModel, body map[string]any) ([]byte, error) { - // 1) 记录模型调用次数 - //_ = dao.ModelGatewayLogsStat.IncRequestCount(ctx, time.Now(), model.TenantId, model.Creator, model.ModelName) - - // 2)请求参数映射:将标准 payload 按模型配置的 requestMapping 转为模型需要的格式 - //—— 请求映射实际处理为提示词构建请求,因为有附加字段及其他字段的拼接。这里不方便做请求映射 - //mappedPayload := util.ReverseMap(model.RequestMapping, payload) - // 3)构建请求 URL 和超时 baseURL := strings.TrimRight(model.BaseURL, "/") timeout := time.Duration(model.TimeoutSeconds) * time.Second @@ -434,6 +410,10 @@ func InvokeModel(ctx context.Context, model *entity.ModelGatewayModel, body map[ msg := string(b) return nil, fmt.Errorf("模型服务返回非2xx: %d, body=%s", resp.StatusCode, msg) } + + // + + // g.Log().Debugf(ctx, "[执行任务][模型调用成功] StatusCode=%v", resp.StatusCode) return b, nil } From 2edbe54fdcfde0853ae39a2f50eb961bae16bd18 Mon Sep 17 00:00:00 2001 From: WangLiZhao <1838393649@qq.com> Date: Wed, 1 Jul 2026 17:51:04 +0800 Subject: [PATCH 18/24] =?UTF-8?q?fix(task):=20=E4=BF=AE=E5=A4=8D=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1=E5=A4=B1=E8=B4=A5=E6=97=B6=E6=96=87=E6=9C=AC=E7=BB=93?= =?UTF-8?q?=E6=9E=9C=E6=9C=AA=E4=BF=9D=E5=AD=98=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- service/task/worker.go | 1 + 1 file changed, 1 insertion(+) diff --git a/service/task/worker.go b/service/task/worker.go index 322e1c3..34903e1 100644 --- a/service/task/worker.go +++ b/service/task/worker.go @@ -113,6 +113,7 @@ func (w *asyncWorker) handleOne(ctx context.Context, task *entity.ModelGatewayTa if req.BuildType == public.BuildTypePrompt { mapped, err = w.parseAndRetry(ctx, mapped, task, model, maxRetry) if err != nil { + task.TextResult = mapped w.failTask(ctx, task, startTime, err.Error()) return } From 62003c25a02c0addc1846fdc97610e9f8fb2c1a1 Mon Sep 17 00:00:00 2001 From: WangLiZhao <1838393649@qq.com> Date: Wed, 1 Jul 2026 18:03:09 +0800 Subject: [PATCH 19/24] =?UTF-8?q?fix(billing):=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E8=AE=A1=E8=B4=B9=E6=95=B0=E6=8D=AE=E5=A4=84=E7=90=86=E9=80=BB?= =?UTF-8?q?=E8=BE=91=E5=B9=B6=E6=9B=B4=E6=96=B0=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在请求阶段将请求数据作为计费记录的基础字段存入数组 - 修改计费处理逻辑,使用请求阶段数据作为基础补充返回数据后进行费用计算 - 重试时使用相同的计费数据处理逻辑确保数据一致性 - 将计费结果直接替换数组第一个元素而非追加 - 更新数据库配置从 192.168.0.83 到 192.168.3.30 - 更新 Redis、Consul、Jaeger 和文件上传服务地址到新 IP - 修改数据库端口从 15432 到 5432 并更新密码 --- service/task/task_service.go | 1 + service/task/worker.go | 33 ++++++++++++++++++++++++++++----- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/service/task/task_service.go b/service/task/task_service.go index 3d83461..9b89032 100644 --- a/service/task/task_service.go +++ b/service/task/task_service.go @@ -110,6 +110,7 @@ func (s *taskService) Create(ctx context.Context, req *dto.CreateTaskReq) (res * // 6) 模型计费 if len(model.BillingConfig) > 0 { requestData := util.ExtractRequestBilling(ctx, model.BillingConfig, req.RequestPayload) + // 请求数据作为计费记录的基础字段,先存入数组 task.BillingData = append(task.BillingData, requestData) _, _ = dao.ModelGatewayTask.Update(ctx, &entity.ModelGatewayTask{ SQLBaseDO: beans.SQLBaseDO{Id: task.Id}, diff --git a/service/task/worker.go b/service/task/worker.go index 34903e1..580391c 100644 --- a/service/task/worker.go +++ b/service/task/worker.go @@ -93,14 +93,26 @@ func (w *asyncWorker) handleOne(ctx context.Context, task *entity.ModelGatewayTa w.failTask(ctx, task, startTime, err.Error()) return } + // 计费处理 - if len(model.BillingConfig) > 0 { + if len(model.BillingConfig) > 0 && len(task.BillingData) > 0 { + // 取请求阶段数据作为基础 + billingInput := make(map[string]any) + for k, v := range task.BillingData[0] { + billingInput[k] = v + } + // 补充返回数据 responseData := util.ExtractResponseBilling(model.BillingConfig, mapped) - billingResult := util.CalculateBilling(model.BillingConfig, responseData) + for k, v := range responseData { + billingInput[k] = v + } + // 计算费用,替换数组第一个元素 + billingResult := util.CalculateBilling(model.BillingConfig, billingInput) if billingResult != nil { - task.BillingData = append(task.BillingData, billingResult) + task.BillingData[0] = billingResult } } + task.ExpendTokens = gconv.Int64(mapped[entity.TotalTokens]) if _, err = dao.ModelGatewayTask.Update(ctx, task); err != nil { g.Log().Errorf(ctx, "[handleOne] 更新DB失败 taskId=%s err=%v", task.TaskID, err) @@ -279,10 +291,21 @@ func (w *asyncWorker) parseAndRetry(ctx context.Context, body map[string]any, ta continue } - // 记录重试计费 + // parseAndRetry 重试时 if len(model.BillingConfig) > 0 { + requestData := task.BillingData[0] // 请求数据从第一个元素取 + + retryData := make(map[string]any) + for k, v := range requestData { + retryData[k] = v + } + responseData := util.ExtractResponseBilling(model.BillingConfig, mapped) - billingResult := util.CalculateBilling(model.BillingConfig, responseData) + for k, v := range responseData { + retryData[k] = v + } + + billingResult := util.CalculateBilling(model.BillingConfig, retryData) if billingResult != nil { task.BillingData = append(task.BillingData, billingResult) } From 84421b4ee54d05b7202cf9ddf0749f5f14496a8d Mon Sep 17 00:00:00 2001 From: WangLiZhao <1838393649@qq.com> Date: Wed, 1 Jul 2026 18:04:39 +0800 Subject: [PATCH 20/24] =?UTF-8?q?refactor(gateway):=20=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E5=9B=9E=E8=B0=83=E8=BD=BD=E8=8D=B7=E7=BB=93=E6=9E=84=E5=AE=9A?= =?UTF-8?q?=E4=B9=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- service/gateway/gateway_http_service.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/service/gateway/gateway_http_service.go b/service/gateway/gateway_http_service.go index de03280..fca6761 100644 --- a/service/gateway/gateway_http_service.go +++ b/service/gateway/gateway_http_service.go @@ -98,14 +98,14 @@ func TriggerCallback(ctx context.Context, t *entity.ModelGatewayTask) { } var resp struct{} payload := CallbackPayload{ - TaskId: t.TaskID, - State: t.State, - ErrorMsg: t.ErrorMsg, + TaskId: t.TaskID, + State: t.State, + ErrorMsg: t.ErrorMsg, + BillingDate: t.BillingData, } if !g.IsEmpty(t.ResultFile) { payload.OssFile = t.ResultFile.OssFile payload.FileType = t.ResultFile.FileType - payload.BillingDate = t.BillingData } jsonData, err := json.Marshal(payload) if err != nil { From 7e849b1c0fe751f8d9bff9bd2ef0c3bd7fc79990 Mon Sep 17 00:00:00 2001 From: WangLiZhao <1838393649@qq.com> Date: Wed, 1 Jul 2026 18:28:00 +0800 Subject: [PATCH 21/24] =?UTF-8?q?fix(task):=20=E4=BF=AE=E5=A4=8D=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1=E5=A4=84=E7=90=86=E4=B8=AD=E7=9A=84=E5=8F=82=E6=95=B0?= =?UTF-8?q?=E4=BC=A0=E9=80=92=E5=92=8C=E6=95=B0=E6=8D=AE=E8=A7=A3=E6=9E=90?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- service/task/worker.go | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/service/task/worker.go b/service/task/worker.go index 580391c..036b9cd 100644 --- a/service/task/worker.go +++ b/service/task/worker.go @@ -18,6 +18,7 @@ import ( "time" "gitea.redpowerfuture.com/red-future/common/beans" + "gitea.redpowerfuture.com/red-future/common/utils" "github.com/gogf/gf/v2/encoding/gjson" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/util/gconv" @@ -123,7 +124,7 @@ func (w *asyncWorker) handleOne(ctx context.Context, task *entity.ModelGatewayTa // 3) 处理提示词相关数据解析涵盖重试 // ============================================ if req.BuildType == public.BuildTypePrompt { - mapped, err = w.parseAndRetry(ctx, mapped, task, model, maxRetry) + mapped, err = w.parseAndRetry(ctx, mapped, model, task, maxRetry) if err != nil { task.TextResult = mapped w.failTask(ctx, task, startTime, err.Error()) @@ -248,15 +249,28 @@ func NotifyAsyncResult(taskID string, result map[string]any, err error) { //} // parseAndRetry 解析模型返回结果,并重试 -func (w *asyncWorker) parseAndRetry(ctx context.Context, body map[string]any, task *entity.ModelGatewayTask, model *entity.ModelGatewayModel, maxRetry int) (map[string]any, error) { +func (w *asyncWorker) parseAndRetry(ctx context.Context, body map[string]any, model *entity.ModelGatewayModel, task *entity.ModelGatewayTask, maxRetry int) (map[string]any, error) { + // 获取构建模型的必填字段 + user, err := utils.GetUserInfo(ctx) + if err != nil { + return nil, err + } + buildModel, err := dao.ModelGatewayModels.Get(ctx, &entity.ModelGatewayModel{ + SQLBaseDO: beans.SQLBaseDO{TenantId: user.TenantId, Creator: user.UserName}, + ModelName: task.BuildModelName, + }) + if err != nil { + return nil, err + } + var lastErr error for attempt := 0; attempt <= maxRetry; attempt++ { if attempt > 0 { g.Log().Infof(ctx, "[执行任务][重试] JSON解析 第%d/%d次 taskId=%s", attempt, maxRetry, task.TaskID) } - // 解析 + 校验 - parsed, err := util.ParseAndValidate(body, model.RequiredFields) + // 解析 + 校验(用构建模型的 RequiredFields) + parsed, err := util.ParseAndValidate(body, buildModel.RequiredFields) if err == nil { return parsed, nil } @@ -279,7 +293,6 @@ func (w *asyncWorker) parseAndRetry(ctx context.Context, body map[string]any, ta continue } - // 响应映射 var rawResp map[string]any if err := json.Unmarshal(rawData, &rawResp); err != nil { g.Log().Warningf(ctx, "[执行任务][Unmarshal失败] taskId=%s err=%v", task.TaskID, err) @@ -291,20 +304,17 @@ func (w *asyncWorker) parseAndRetry(ctx context.Context, body map[string]any, ta continue } - // parseAndRetry 重试时 - if len(model.BillingConfig) > 0 { - requestData := task.BillingData[0] // 请求数据从第一个元素取 - + // 计费 + if len(model.BillingConfig) > 0 && len(task.BillingData) > 0 { + requestData := task.BillingData[0] retryData := make(map[string]any) for k, v := range requestData { retryData[k] = v } - responseData := util.ExtractResponseBilling(model.BillingConfig, mapped) for k, v := range responseData { retryData[k] = v } - billingResult := util.CalculateBilling(model.BillingConfig, retryData) if billingResult != nil { task.BillingData = append(task.BillingData, billingResult) From d18016e6983c1fe7203cc77cff884bcde234e251 Mon Sep 17 00:00:00 2001 From: WangLiZhao <1838393649@qq.com> Date: Wed, 1 Jul 2026 18:44:31 +0800 Subject: [PATCH 22/24] =?UTF-8?q?feat(gateway):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E7=A7=9F=E6=88=B7=E4=BD=99=E9=A2=9D=E7=AE=A1=E7=90=86=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- service/gateway/gateway_http_service.go | 60 +++++++++++++++++++++++++ service/task/worker.go | 37 ++++++++++++--- 2 files changed, 91 insertions(+), 6 deletions(-) diff --git a/service/gateway/gateway_http_service.go b/service/gateway/gateway_http_service.go index fca6761..0ad2635 100644 --- a/service/gateway/gateway_http_service.go +++ b/service/gateway/gateway_http_service.go @@ -221,6 +221,66 @@ func GetVideoDuration(ctx context.Context, urls []string) (VideoDurationResp, er return resp, nil } +// DeductBalanceReq 扣减余额请求 +type DeductBalanceReq struct { + Id uint64 `json:"id"` + Surplus float64 `json:"surplus"` +} + +// DeductBalance 扣减租户余额 +func DeductBalance(ctx context.Context, tenantId uint64, amount float64) error { + apiURL := "admin-go/api/v1/system/tenant/edit" + headers := make(map[string]string) + if r := g.RequestFromCtx(ctx); r != nil { + for k, v := range r.Request.Header { + if len(v) > 0 { + headers[k] = v[0] + } + } + } + + body := DeductBalanceReq{ + Id: tenantId, + Surplus: amount, + } + jsonData, _ := json.Marshal(body) + + var resp struct{} + err := commonHttp.Put(ctx, apiURL, headers, &resp, jsonData) + if err != nil { + g.Log().Warningf(ctx, "[扣减余额] 失败 tenantId=%d amount=%.6f err=%v", tenantId, amount, err) + return err + } + g.Log().Infof(ctx, "[扣减余额] 成功 tenantId=%d amount=%.6f", tenantId, amount) + return nil +} + +// TenantSurplusResp 租户余额返回 +type TenantSurplusResp struct { + Surplus float64 `json:"surplus"` +} + +// GetTenantSurplus 获取租户余额 +func GetTenantSurplus(ctx context.Context, tenantId uint64) (float64, error) { + apiURL := fmt.Sprintf("admin-go/api/v1/system/tenant/getTenantDetails?tenantId=%d", tenantId) + headers := make(map[string]string) + if r := g.RequestFromCtx(ctx); r != nil { + for k, v := range r.Request.Header { + if len(v) > 0 { + headers[k] = v[0] + } + } + } + + var resp TenantSurplusResp + err := commonHttp.Get(ctx, apiURL, headers, &resp, nil) + if err != nil { + g.Log().Warningf(ctx, "[获取余额] 失败 tenantId=%d err=%v", tenantId, err) + return 0, err + } + return resp.Surplus, nil +} + //// callback 向回调地址 POST 任务结果(与查询接口 GetTaskRes 出参一致) //func (s *audioTaskService) callback(ctx context.Context, taskID, status, errMsg, callbackURL string) { // if callbackURL == "" { diff --git a/service/task/worker.go b/service/task/worker.go index 036b9cd..f1229c0 100644 --- a/service/task/worker.go +++ b/service/task/worker.go @@ -39,11 +39,23 @@ func (w *asyncWorker) handleOne(ctx context.Context, task *entity.ModelGatewayTa result map[string]any err error ) - g.Log().Infof(ctx, "[handleOne] 开始 taskId=%s model=%s", task.TaskID, task.ModelName) // ============================================ - // 1) 调用模型 + // 1) 查询余额 + // ============================================ + var surplus float64 + if len(model.BillingConfig) > 0 { + surplus, _ = gateway.GetTenantSurplus(ctx, task.TenantId) + if surplus <= 0 { + w.failTask(ctx, task, startTime, "租户余额不足") + return + } + g.Log().Infof(ctx, "[handleOne] 当前余额 tenantId=%d surplus=%.2f", task.TenantId, surplus) + } + + // ============================================ + // 2) 调用模型 // ============================================ for attempt := 0; ; attempt++ { if attempt > 0 { @@ -87,7 +99,7 @@ func (w *asyncWorker) handleOne(ctx context.Context, task *entity.ModelGatewayTa } // ============================================ - // 2) 解析返回映射 + 存储 token 相关信息 + // 3) 解析返回映射 + 存储 token 相关信息 // ============================================ mapped, err := util.MapResponsePayload(model.ResponseMapping, result) if err != nil { @@ -112,6 +124,14 @@ func (w *asyncWorker) handleOne(ctx context.Context, task *entity.ModelGatewayTa if billingResult != nil { task.BillingData[0] = billingResult } + + if billingResult != nil { + task.BillingData[0] = billingResult + totalFee := gconv.Float64(billingResult["total_fee"]) + if totalFee > 0 { + _ = gateway.DeductBalance(util.AsyncCtx(ctx), task.TenantId, -totalFee) + } + } } task.ExpendTokens = gconv.Int64(mapped[entity.TotalTokens]) @@ -121,7 +141,7 @@ func (w *asyncWorker) handleOne(ctx context.Context, task *entity.ModelGatewayTa } // ============================================ - // 3) 处理提示词相关数据解析涵盖重试 + // 4) 处理提示词相关数据解析涵盖重试 // ============================================ if req.BuildType == public.BuildTypePrompt { mapped, err = w.parseAndRetry(ctx, mapped, model, task, maxRetry) @@ -133,7 +153,7 @@ func (w *asyncWorker) handleOne(ctx context.Context, task *entity.ModelGatewayTa } // ============================================ - // 4) 上传 OSS(可重试) + // 5) 上传 OSS(可重试) // ============================================ var oss *gateway.UploadFileResponse for attempt := 0; attempt <= maxRetry; attempt++ { @@ -152,7 +172,7 @@ func (w *asyncWorker) handleOne(ctx context.Context, task *entity.ModelGatewayTa } // ============================================ - // 5) 成功收尾 + // 6) 成功收尾 // ============================================ task.State = public.TaskStatusSuccess task.DurationSeconds = int64(time.Since(startTime).Seconds()) @@ -318,7 +338,12 @@ func (w *asyncWorker) parseAndRetry(ctx context.Context, body map[string]any, mo billingResult := util.CalculateBilling(model.BillingConfig, retryData) if billingResult != nil { task.BillingData = append(task.BillingData, billingResult) + totalFee := gconv.Float64(billingResult["total_fee"]) + if totalFee > 0 { + _ = gateway.DeductBalance(util.AsyncCtx(ctx), task.TenantId, -totalFee) + } } + task.ExpendTokens += gconv.Int64(mapped[entity.TotalTokens]) _, _ = dao.ModelGatewayTask.Update(ctx, &entity.ModelGatewayTask{ SQLBaseDO: beans.SQLBaseDO{Id: task.Id}, From a332aa438b1dfe992f095fd36e7c72c62c3446ec Mon Sep 17 00:00:00 2001 From: WangLiZhao <1838393649@qq.com> Date: Wed, 1 Jul 2026 18:47:13 +0800 Subject: [PATCH 23/24] =?UTF-8?q?refactor(task):=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E5=A4=84=E7=90=86=E4=B8=AD=E7=9A=84=E4=BD=99?= =?UTF-8?q?=E9=A2=9D=E6=A3=80=E6=9F=A5=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- service/task/worker.go | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/service/task/worker.go b/service/task/worker.go index f1229c0..7ae433b 100644 --- a/service/task/worker.go +++ b/service/task/worker.go @@ -38,21 +38,19 @@ func (w *asyncWorker) handleOne(ctx context.Context, task *entity.ModelGatewayTa rawData []byte result map[string]any err error + surplus float64 ) g.Log().Infof(ctx, "[handleOne] 开始 taskId=%s model=%s", task.TaskID, task.ModelName) // ============================================ // 1) 查询余额 // ============================================ - var surplus float64 - if len(model.BillingConfig) > 0 { - surplus, _ = gateway.GetTenantSurplus(ctx, task.TenantId) - if surplus <= 0 { - w.failTask(ctx, task, startTime, "租户余额不足") - return - } - g.Log().Infof(ctx, "[handleOne] 当前余额 tenantId=%d surplus=%.2f", task.TenantId, surplus) + surplus, _ = gateway.GetTenantSurplus(ctx, task.TenantId) + if surplus <= 0 { + w.failTask(ctx, task, startTime, "租户余额不足") + return } + g.Log().Infof(ctx, "[handleOne] 当前余额 tenantId=%d surplus=%.2f", task.TenantId, surplus) // ============================================ // 2) 调用模型 From 4d95ff75d29298ef5ad3597adfd7ba0f8c14e2d8 Mon Sep 17 00:00:00 2001 From: WangLiZhao <1838393649@qq.com> Date: Wed, 1 Jul 2026 18:55:16 +0800 Subject: [PATCH 24/24] =?UTF-8?q?fix(task):=20=E4=BF=AE=E5=A4=8D=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1=E6=89=A7=E8=A1=8C=E4=B8=AD=E7=A7=9F=E6=88=B7=E4=BD=99?= =?UTF-8?q?=E9=A2=9D=E6=A3=80=E6=9F=A5=E7=9A=84=E5=8F=82=E6=95=B0=E4=BC=A0?= =?UTF-8?q?=E9=80=92=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修正了 GetTenantSurplus 函数调用中的参数,从 task.TenantId 改为 model.TenantId - 注释掉了模型调用中重复的余额检查逻辑以避免冗余验证 --- service/task/worker.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/service/task/worker.go b/service/task/worker.go index 7ae433b..79d7b2e 100644 --- a/service/task/worker.go +++ b/service/task/worker.go @@ -45,7 +45,7 @@ func (w *asyncWorker) handleOne(ctx context.Context, task *entity.ModelGatewayTa // ============================================ // 1) 查询余额 // ============================================ - surplus, _ = gateway.GetTenantSurplus(ctx, task.TenantId) + surplus, _ = gateway.GetTenantSurplus(ctx, model.TenantId) if surplus <= 0 { w.failTask(ctx, task, startTime, "租户余额不足") return @@ -401,6 +401,11 @@ func injectErrorMessage(payload map[string]any, err error) map[string]any { // InvokeModel 调用模型服务,返回二进制结果 // modelKey 用于覆盖/补充模型配置 head_msg(例如每次请求携带不同的 X-API-Key) func InvokeModel(ctx context.Context, model *entity.ModelGatewayModel, body map[string]any) ([]byte, error) { + //surplus, _ := gateway.GetTenantSurplus(ctx, model.TenantId) + //if surplus <= 0 { + // return nil, fmt.Errorf("租户余额不足") + //} + // 3)构建请求 URL 和超时 baseURL := strings.TrimRight(model.BaseURL, "/") timeout := time.Duration(model.TimeoutSeconds) * time.Second