231 lines
8.2 KiB
Go
231 lines
8.2 KiB
Go
package admin
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
|
|
"github.com/gogf/gf/v2/frame/g"
|
|
v1 "github.com/qianfree/team-api/api/admin/v1"
|
|
"github.com/qianfree/team-api/internal/dao"
|
|
"github.com/qianfree/team-api/internal/logic/billing"
|
|
"github.com/qianfree/team-api/internal/logic/common"
|
|
do "github.com/qianfree/team-api/internal/model/do"
|
|
)
|
|
|
|
// ListTenantModels 列出租户已分配的模型
|
|
func (s *sAdmin) ListTenantModels(ctx context.Context, req *v1.TenantModelListReq) (*v1.TenantModelListRes, error) {
|
|
var results []struct {
|
|
ID int64 `json:"id"`
|
|
TenantID int64 `json:"tenant_id"`
|
|
ModelID int64 `json:"model_id"`
|
|
Enabled bool `json:"enabled"`
|
|
BillingMode *string `json:"billing_mode"`
|
|
PerRequestPrice *float64 `json:"per_request_price"`
|
|
DiscountRatio *float64 `json:"discount_ratio"`
|
|
MaxConcurrency *int `json:"max_concurrency"`
|
|
ChannelScope string `json:"channel_scope"`
|
|
CustomInputPrice *float64 `json:"custom_input_price"`
|
|
CustomOutputPrice *float64 `json:"custom_output_price"`
|
|
CustomCacheReadPrice *float64 `json:"custom_cache_read_price"`
|
|
CustomCacheCreationPrice *float64 `json:"custom_cache_creation_price"`
|
|
CustomPricingTiers string `json:"custom_pricing_tiers"`
|
|
Multiplier float64 `json:"multiplier"`
|
|
ModelCode string `json:"model_code"`
|
|
ModelName string `json:"model_name"`
|
|
Category string `json:"category"`
|
|
}
|
|
|
|
err := dao.MdlTenantModels.Ctx(ctx).
|
|
LeftJoin("mdl_models ON mdl_tenant_models.model_id = mdl_models.id").
|
|
Where("mdl_tenant_models.tenant_id", req.TenantID).
|
|
Fields("mdl_tenant_models.id, mdl_tenant_models.tenant_id, mdl_tenant_models.model_id, mdl_tenant_models.enabled, mdl_tenant_models.billing_mode, mdl_tenant_models.per_request_price, mdl_tenant_models.discount_ratio, mdl_tenant_models.max_concurrency, mdl_tenant_models.channel_scope, mdl_tenant_models.custom_input_price, mdl_tenant_models.custom_output_price, mdl_tenant_models.custom_cache_read_price, mdl_tenant_models.custom_cache_creation_price, mdl_tenant_models.custom_pricing_tiers, mdl_tenant_models.multiplier, mdl_models.model_id as model_code, mdl_models.model_name, mdl_models.category").
|
|
OrderAsc("mdl_models.category").
|
|
OrderAsc("mdl_models.model_id").
|
|
Scan(&results)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
list := make([]v1.TenantModelItem, 0, len(results))
|
|
for _, r := range results {
|
|
item := v1.TenantModelItem{
|
|
ID: r.ID,
|
|
TenantID: r.TenantID,
|
|
ModelID: r.ModelID,
|
|
ModelCode: r.ModelCode,
|
|
ModelName: r.ModelName,
|
|
Category: r.Category,
|
|
Enabled: r.Enabled,
|
|
BillingMode: r.BillingMode,
|
|
PerRequestPrice: r.PerRequestPrice,
|
|
DiscountRatio: r.DiscountRatio,
|
|
MaxConcurrency: r.MaxConcurrency,
|
|
ChannelScope: r.ChannelScope,
|
|
CustomInputPrice: r.CustomInputPrice,
|
|
CustomOutputPrice: r.CustomOutputPrice,
|
|
CustomCacheReadPrice: r.CustomCacheReadPrice,
|
|
CustomCacheCreationPrice: r.CustomCacheCreationPrice,
|
|
Multiplier: r.Multiplier,
|
|
}
|
|
if r.CustomPricingTiers != "" && r.CustomPricingTiers != "null" && r.CustomPricingTiers != "[]" {
|
|
var tiers []*v1.PricingTier
|
|
if err := json.Unmarshal([]byte(r.CustomPricingTiers), &tiers); err == nil {
|
|
item.CustomPricingTiers = tiers
|
|
}
|
|
}
|
|
list = append(list, item)
|
|
}
|
|
|
|
return &v1.TenantModelListRes{List: list}, nil
|
|
}
|
|
|
|
// BatchAssignModels 批量分配模型给租户
|
|
func (s *sAdmin) BatchAssignModels(ctx context.Context, req *v1.TenantModelBatchAssignReq) (*v1.TenantModelBatchAssignRes, error) {
|
|
assigned := 0
|
|
|
|
for _, a := range req.Assignments {
|
|
g.Log().Debugf(ctx, "BatchAssignModels: tenant_id=%d, model_id=%d, enabled=%v", req.TenantID, a.ModelID, a.Enabled)
|
|
|
|
var model struct {
|
|
ID int64 `json:"id"`
|
|
Status string `json:"status"`
|
|
}
|
|
err := dao.MdlModels.Ctx(ctx).
|
|
Where("id", a.ModelID).
|
|
Scan(&model)
|
|
g.Log().Debugf(ctx, "BatchAssignModels: model scan result id=%d, status=%q, err=%v", model.ID, model.Status, err)
|
|
if err != nil || model.ID == 0 || model.Status != "active" {
|
|
g.Log().Warningf(ctx, "BatchAssignModels: skip model_id=%d, err=%v, id=%d, status=%q", a.ModelID, err, model.ID, model.Status)
|
|
continue
|
|
}
|
|
|
|
count, countErr := dao.MdlTenantModels.Ctx(ctx).
|
|
Where("tenant_id", req.TenantID).
|
|
Where("model_id", a.ModelID).
|
|
Count()
|
|
g.Log().Debugf(ctx, "BatchAssignModels: existing count=%d, countErr=%v", count, countErr)
|
|
if count > 0 {
|
|
g.Log().Debugf(ctx, "BatchAssignModels: skip already assigned, model_id=%d", a.ModelID)
|
|
continue
|
|
}
|
|
|
|
maxConc := a.MaxConcurrency
|
|
if maxConc == nil {
|
|
concurrency := 5
|
|
maxConc = &concurrency
|
|
}
|
|
|
|
var tiersJSON any
|
|
if len(a.CustomPricingTiers) > 0 {
|
|
b, _ := json.Marshal(a.CustomPricingTiers)
|
|
tiersJSON = string(b)
|
|
}
|
|
|
|
insertData := do.MdlTenantModels{
|
|
TenantId: req.TenantID,
|
|
ModelId: a.ModelID,
|
|
Enabled: a.Enabled,
|
|
BillingMode: a.BillingMode,
|
|
PerRequestPrice: a.PerRequestPrice,
|
|
DiscountRatio: a.DiscountRatio,
|
|
MaxConcurrency: maxConc,
|
|
ChannelScope: a.ChannelScope,
|
|
CustomInputPrice: a.CustomInputPrice,
|
|
CustomOutputPrice: a.CustomOutputPrice,
|
|
CustomCacheReadPrice: a.CustomCacheReadPrice,
|
|
CustomCacheCreationPrice: a.CustomCacheCreationPrice,
|
|
CustomPricingTiers: tiersJSON,
|
|
Multiplier: 1.0,
|
|
}
|
|
g.Log().Debugf(ctx, "BatchAssignModels: inserting data tenant_id=%v, model_id=%v, enabled=%v, max_concurrency=%v", insertData.TenantId, insertData.ModelId, insertData.Enabled, *maxConc)
|
|
_, err = dao.MdlTenantModels.Ctx(ctx).Insert(insertData)
|
|
if err != nil {
|
|
g.Log().Errorf(ctx, "BatchAssignModels: insert failed, model_id=%d, err=%v", a.ModelID, err)
|
|
} else {
|
|
assigned++
|
|
g.Log().Debugf(ctx, "BatchAssignModels: insert success, model_id=%d, assigned=%d", a.ModelID, assigned)
|
|
}
|
|
}
|
|
|
|
billing.ClearTenantPriceCache(ctx, req.TenantID)
|
|
|
|
return &v1.TenantModelBatchAssignRes{Assigned: assigned}, nil
|
|
}
|
|
|
|
// UpdateTenantModel 更新租户模型配置
|
|
func (s *sAdmin) UpdateTenantModel(ctx context.Context, req *v1.TenantModelUpdateReq) (*v1.TenantModelUpdateRes, error) {
|
|
data := do.MdlTenantModels{}
|
|
|
|
if req.Enabled != nil {
|
|
data.Enabled = *req.Enabled
|
|
}
|
|
if req.BillingMode != nil {
|
|
data.BillingMode = *req.BillingMode
|
|
}
|
|
if req.PerRequestPrice != nil {
|
|
data.PerRequestPrice = *req.PerRequestPrice
|
|
}
|
|
if req.DiscountRatio != nil {
|
|
data.DiscountRatio = *req.DiscountRatio
|
|
}
|
|
if req.MaxConcurrency != nil {
|
|
data.MaxConcurrency = *req.MaxConcurrency
|
|
}
|
|
if req.ChannelScope != nil {
|
|
data.ChannelScope = *req.ChannelScope
|
|
}
|
|
if req.CustomInputPrice != nil {
|
|
data.CustomInputPrice = *req.CustomInputPrice
|
|
}
|
|
if req.CustomCacheReadPrice != nil {
|
|
data.CustomCacheReadPrice = *req.CustomCacheReadPrice
|
|
}
|
|
if req.CustomCacheCreationPrice != nil {
|
|
data.CustomCacheCreationPrice = *req.CustomCacheCreationPrice
|
|
}
|
|
if req.CustomOutputPrice != nil {
|
|
data.CustomOutputPrice = *req.CustomOutputPrice
|
|
}
|
|
if req.CustomPricingTiers != nil {
|
|
if len(*req.CustomPricingTiers) > 0 {
|
|
b, _ := json.Marshal(*req.CustomPricingTiers)
|
|
data.CustomPricingTiers = string(b)
|
|
} else {
|
|
data.CustomPricingTiers = "[]"
|
|
}
|
|
}
|
|
|
|
_, err := dao.MdlTenantModels.Ctx(ctx).
|
|
Where("tenant_id", req.TenantID).
|
|
Where("model_id", req.ModelID).
|
|
Data(data).
|
|
Update()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
billing.ClearTenantPriceCache(ctx, req.TenantID)
|
|
|
|
return nil, nil
|
|
}
|
|
|
|
// DeleteTenantModel 移除租户模型分配
|
|
func (s *sAdmin) DeleteTenantModel(ctx context.Context, req *v1.TenantModelDeleteReq) (*v1.TenantModelDeleteRes, error) {
|
|
result, err := dao.MdlTenantModels.Ctx(ctx).
|
|
Where("tenant_id", req.TenantID).
|
|
Where("model_id", req.ModelID).
|
|
Delete()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
rowsAffected, _ := result.RowsAffected()
|
|
if rowsAffected == 0 {
|
|
return nil, common.NewNotFoundError("模型分配")
|
|
}
|
|
|
|
billing.ClearTenantPriceCache(ctx, req.TenantID)
|
|
|
|
return nil, nil
|
|
}
|