From e5bc98cac08373327e03b9cc69add2b7382e70e6 Mon Sep 17 00:00:00 2001 From: Liujian <824010343@qq.com> Date: Tue, 24 Dec 2024 18:00:46 +0800 Subject: [PATCH 1/2] finish ai apis --- ai-provider/model-runtime/loader.go | 7 ++ controller/ai/controller.go | 8 ++ controller/ai/iml.go | 41 ++++++++ go.mod | 2 +- go.sum | 2 - module/ai-api/dto/output.go | 13 +++ module/ai-api/iml.go | 2 + module/ai-api/module.go | 3 +- module/ai/dto/input.go | 4 + module/ai/dto/output.go | 33 +++++- module/ai/iml.go | 158 ++++++++++++++++++++++++++-- module/ai/module.go | 9 ++ plugins/core/ai.go | 8 +- plugins/core/core.go | 1 + resources/access/access.yaml | 30 ++++++ resources/access/role.yaml | 12 +++ service/ai-api/iml.go | 47 +++++++++ service/ai-api/model.go | 10 ++ service/ai-api/service.go | 8 +- stores/api/api.go | 12 +++ stores/api/model.go | 23 ++++ 21 files changed, 409 insertions(+), 24 deletions(-) diff --git a/ai-provider/model-runtime/loader.go b/ai-provider/model-runtime/loader.go index 5288299f..5320ff0e 100644 --- a/ai-provider/model-runtime/loader.go +++ b/ai-provider/model-runtime/loader.go @@ -40,7 +40,14 @@ func (c *Config) Check(cfg string) error { } func (c *Config) GenConfig(target string, origin string) (string, error) { + if target == "" { + target = "{}" + } + if origin == "" { + origin = "{}" + } var targetData map[string]interface{} + err := json.Unmarshal([]byte(target), &targetData) if err != nil { return "", err diff --git a/controller/ai/controller.go b/controller/ai/controller.go index 23b8b345..9e8c48e2 100644 --- a/controller/ai/controller.go +++ b/controller/ai/controller.go @@ -20,10 +20,18 @@ type IProviderController interface { Disable(ctx *gin.Context, id string) error UpdateProviderConfig(ctx *gin.Context, id string, input *ai_dto.UpdateConfig) error UpdateProviderDefaultLLM(ctx *gin.Context, id string, input *ai_dto.UpdateLLM) error + Sort(ctx *gin.Context, input *ai_dto.Sort) error +} + +type IStatisticController interface { + APIs(ctx *gin.Context, keyword string, providerId string, start string, end string, page string, pageSize string, sortCondition string, asc string) ([]*ai_dto.APIItem, int64, error) } func init() { autowire.Auto[IProviderController](func() reflect.Value { return reflect.ValueOf(&imlProviderController{}) }) + autowire.Auto[IStatisticController](func() reflect.Value { + return reflect.ValueOf(&imlStatisticController{}) + }) } diff --git a/controller/ai/iml.go b/controller/ai/iml.go index a2f122bc..0840eeb1 100644 --- a/controller/ai/iml.go +++ b/controller/ai/iml.go @@ -1,6 +1,8 @@ package ai import ( + "strconv" + "github.com/APIParkLab/APIPark/module/ai" ai_dto "github.com/APIParkLab/APIPark/module/ai/dto" "github.com/eolinker/go-common/auto" @@ -15,6 +17,10 @@ type imlProviderController struct { module ai.IProviderModule `autowired:""` } +func (i *imlProviderController) Sort(ctx *gin.Context, input *ai_dto.Sort) error { + return i.module.Sort(ctx, input) +} + func (i *imlProviderController) ConfiguredProviders(ctx *gin.Context) ([]*ai_dto.ConfiguredProviderItem, *auto.Label, error) { return i.module.ConfiguredProviders(ctx) } @@ -50,3 +56,38 @@ func (i *imlProviderController) UpdateProviderConfig(ctx *gin.Context, id string func (i *imlProviderController) UpdateProviderDefaultLLM(ctx *gin.Context, id string, input *ai_dto.UpdateLLM) error { return i.module.UpdateProviderDefaultLLM(ctx, id, input) } + +var _ IStatisticController = (*imlStatisticController)(nil) + +type imlStatisticController struct { + module ai.IAIAPIModule `autowired:""` +} + +func (i *imlStatisticController) APIs(ctx *gin.Context, keyword string, providerId string, start string, end string, page string, pageSize string, sortCondition string, asc string) ([]*ai_dto.APIItem, int64, error) { + s, err := strconv.ParseInt(start, 10, 64) + if err != nil { + return nil, 0, err + } + + e, err := strconv.ParseInt(end, 10, 64) + if err != nil { + return nil, 0, err + } + + p, err := strconv.Atoi(page) + if err != nil { + if page != "" { + return nil, 0, err + } + p = 1 + } + + ps, err := strconv.Atoi(pageSize) + if err != nil { + if pageSize != "" { + return nil, 0, err + } + ps = 15 + } + return i.module.APIs(ctx, keyword, providerId, s, e, p, ps, sortCondition, asc == "true") +} diff --git a/go.mod b/go.mod index ab8959d3..a46deef4 100644 --- a/go.mod +++ b/go.mod @@ -81,4 +81,4 @@ require ( //replace github.com/eolinker/ap-account => ../aoaccount // -//replace github.com/eolinker/go-common => ../../eolinker/go-common +replace github.com/eolinker/go-common => ../../eolinker/go-common diff --git a/go.sum b/go.sum index 9bc1954c..e5fd313e 100644 --- a/go.sum +++ b/go.sum @@ -32,8 +32,6 @@ github.com/eolinker/ap-account v1.0.15 h1:n6DJeL6RHZ8eLlZUcY2U3H4d/GPaA5oelAx3R0 github.com/eolinker/ap-account v1.0.15/go.mod h1:zm/Ivs6waJ/M/nEszhpPmM6g50y/MKO+5eABFAdeD0g= github.com/eolinker/eosc v0.18.3 h1:3IK5HkAPnJRfLbQ0FR7kWsZr6Y/OiqqGazvN1q2BL5A= github.com/eolinker/eosc v0.18.3/go.mod h1:O9PQQXFCpB6fjHf+oFt/LN6EOAv779ItbMixMKCfTfk= -github.com/eolinker/go-common v1.1.1 h1:3WqqecGqcHDgpa8Ljp156c1uWeZKP1CKScdU+6sOfcc= -github.com/eolinker/go-common v1.1.1/go.mod h1:Kb/jENMN1mApnodvRgV4YwO9FJby1Jkt2EUjrBjvSX4= github.com/gabriel-vasile/mimetype v1.4.4 h1:QjV6pZ7/XZ7ryI2KuyeEDE8wnh7fHP9YnQy+R0LnH8I= github.com/gabriel-vasile/mimetype v1.4.4/go.mod h1:JwLei5XPtWdGiMFB5Pjle1oEeoSeEuJfJE+TtfvdB/s= github.com/getkin/kin-openapi v0.127.0 h1:Mghqi3Dhryf3F8vR370nN67pAERW+3a95vomb3MAREY= diff --git a/module/ai-api/dto/output.go b/module/ai-api/dto/output.go index 912bb878..d8c8ade8 100644 --- a/module/ai-api/dto/output.go +++ b/module/ai-api/dto/output.go @@ -30,6 +30,19 @@ type APIItem struct { Model ModelItem `json:"model"` } +type AIAPIItem struct { + Id string `json:"id"` + Name string `json:"name"` + Service auto.Label `json:"service" aolabel:"service"` + Method string `json:"method"` + RequestPath string `json:"request_path"` + Model ModelItem `json:"model"` + Provider ProviderItem `json:"provider"` + UpdateTime auto.TimeLabel `json:"update_time"` + UseToken int64 `json:"use_token"` + Disable bool `json:"disable"` +} + type ModelItem struct { Id string `json:"id"` Logo string `json:"logo"` diff --git a/module/ai-api/iml.go b/module/ai-api/iml.go index fac22270..12994aa2 100644 --- a/module/ai-api/iml.go +++ b/module/ai-api/iml.go @@ -112,6 +112,7 @@ func (i *imlAPIModule) Create(ctx context.Context, serviceId string, input *ai_a Name: input.Name, Service: serviceId, Path: input.Path, + Disable: input.Disable, Description: input.Description, Timeout: input.Timeout, Retry: input.Retry, @@ -171,6 +172,7 @@ func (i *imlAPIModule) Edit(ctx context.Context, serviceId string, apiId string, Model: modelId, Provider: providerId, AdditionalConfig: &apiInfo.AdditionalConfig, + Disable: input.Disable, }) }) } diff --git a/module/ai-api/module.go b/module/ai-api/module.go index 1119a2e0..b42714f5 100644 --- a/module/ai-api/module.go +++ b/module/ai-api/module.go @@ -2,9 +2,10 @@ package ai_api import ( "context" + "reflect" + ai_api_dto "github.com/APIParkLab/APIPark/module/ai-api/dto" "github.com/eolinker/go-common/autowire" - "reflect" ) type IAPIModule interface { diff --git a/module/ai/dto/input.go b/module/ai/dto/input.go index 924e8830..93a112f8 100644 --- a/module/ai/dto/input.go +++ b/module/ai/dto/input.go @@ -10,3 +10,7 @@ type UpdateConfig struct { Priority *int `json:"priority"` Enable *bool `json:"enable"` } + +type Sort struct { + Providers []string `json:"providers"` +} diff --git a/module/ai/dto/output.go b/module/ai/dto/output.go index 8318e21a..31272d8e 100644 --- a/module/ai/dto/output.go +++ b/module/ai/dto/output.go @@ -1,5 +1,9 @@ package ai_dto +import ( + "github.com/eolinker/go-common/auto" +) + type Provider struct { Id string `json:"id"` Name string `json:"name"` @@ -19,10 +23,16 @@ type ConfiguredProviderItem struct { Status ProviderStatus `json:"status"` APICount int64 `json:"api_count"` KeyCount int `json:"key_count"` - KeyStatus []string `json:"key_status"` + KeyStatus []*KeyStatus `json:"key_status"` Priority int `json:"priority"` } +type KeyStatus struct { + Id string `json:"id"` + Name string `json:"name"` + Status string `json:"status"` +} + type ProviderItem struct { Id string `json:"id"` Name string `json:"name"` @@ -32,10 +42,11 @@ type ProviderItem struct { } type SimpleProviderItem struct { - Id string `json:"id"` - Name string `json:"name"` - Logo string `json:"logo"` - Configured bool `json:"configured"` + Id string `json:"id"` + Name string `json:"name"` + Logo string `json:"logo"` + Configured bool `json:"configured"` + Status ProviderStatus `json:"status"` } type LLMItem struct { @@ -44,3 +55,15 @@ type LLMItem struct { Config string `json:"config"` Scopes []string `json:"scopes"` } + +type APIItem struct { + Id string `json:"id"` + Name string `json:"name"` + Service auto.Label `json:"service" aolabel:"service"` + Method string `json:"method"` + RequestPath string `json:"request_path"` + Model auto.Label `json:"model"` + UpdateTime auto.TimeLabel `json:"update_time"` + UseToken int `json:"use_token"` + Disable bool `json:"disable"` +} diff --git a/module/ai/iml.go b/module/ai/iml.go index 1ce6fa9e..7b662f61 100644 --- a/module/ai/iml.go +++ b/module/ai/iml.go @@ -5,6 +5,7 @@ import ( "encoding/json" "errors" "fmt" + "net/http" "sort" "time" @@ -59,6 +60,32 @@ type imlProviderModule struct { transaction store.ITransaction `autowired:""` } +func (i *imlProviderModule) Sort(ctx context.Context, input *ai_dto.Sort) error { + return i.transaction.Transaction(ctx, func(txCtx context.Context) error { + list, err := i.providerService.List(ctx) + if err != nil { + return err + } + providerMap := utils.SliceToMap(list, func(e *ai.Provider) string { + return e.Id + }) + for index, id := range input.Providers { + _, has := providerMap[id] + if !has { + continue + } + priority := index + 1 + err = i.providerService.Save(txCtx, id, &ai.SetProvider{ + Priority: &priority, + }) + if err != nil { + return err + } + } + return nil + }) +} + func (i *imlProviderModule) ConfiguredProviders(ctx context.Context) ([]*ai_dto.ConfiguredProviderItem, *auto.Label, error) { // 获取已配置的AI服务商 list, err := i.providerService.List(ctx) @@ -71,6 +98,28 @@ func (i *imlProviderModule) ConfiguredProviders(ctx context.Context) ([]*ai_dto. } providers := make([]*ai_dto.ConfiguredProviderItem, 0, len(list)) for _, l := range list { + // 检查是否有默认Key + _, err = i.aiKeyService.DefaultKey(ctx, l.Id) + if err != nil { + if !errors.Is(err, gorm.ErrRecordNotFound) { + return nil, nil, err + } + err = i.aiKeyService.Create(ctx, &ai_key.Create{ + ID: l.Id, + Name: l.Name, + Config: l.Config, + Provider: l.Id, + Priority: 1, + Status: 1, + ExpireTime: 0, + UseToken: 0, + Default: true, + }) + if err != nil { + return nil, nil, fmt.Errorf("create default key error:%v", err) + } + } + p, has := model_runtime.GetProvider(l.Id) if !has { continue @@ -80,7 +129,7 @@ func (i *imlProviderModule) ConfiguredProviders(ctx context.Context) ([]*ai_dto. return nil, nil, fmt.Errorf("get provider keys error:%v", err) } - keysStatus := make([]string, 0, len(keys)) + keysStatus := make([]*ai_dto.KeyStatus, 0, len(keys)) for _, k := range keys { status := ai_key_dto.ToKeyStatus(k.Status) switch status { @@ -88,11 +137,13 @@ func (i *imlProviderModule) ConfiguredProviders(ctx context.Context) ([]*ai_dto. default: status = ai_key_dto.KeyError } - keysStatus = append(keysStatus, status.String()) - } - if len(keysStatus) == 0 { - keysStatus = []string{ai_key_dto.KeyNormal.String()} + keysStatus = append(keysStatus, &ai_dto.KeyStatus{ + Id: k.ID, + Name: k.Name, + Status: status.String(), + }) } + providers = append(providers, &ai_dto.ConfiguredProviderItem{ Id: l.Id, Name: l.Name, @@ -143,12 +194,14 @@ func (i *imlProviderModule) SimpleProviders(ctx context.Context) ([]*ai_dto.Simp items := make([]*ai_dto.SimpleProviderItem, 0, len(providers)) for _, v := range providers { item := &ai_dto.SimpleProviderItem{ - Id: v.ID(), - Name: v.Name(), - Logo: v.Logo(), + Id: v.ID(), + Name: v.Name(), + Logo: v.Logo(), + Status: ai_dto.ProviderDisabled, } - if _, has := providerMap[v.ID()]; has { + if info, has := providerMap[v.ID()]; has { item.Configured = true + item.Status = ai_dto.ToProviderStatus(info.Status) } items = append(items, item) } @@ -403,7 +456,7 @@ func (i *imlProviderModule) UpdateProviderConfig(ctx context.Context, id string, } pInfo := &ai.SetProvider{ Name: &info.Name, - DefaultLLM: &info.DefaultLLM, + DefaultLLM: &input.DefaultLLM, Config: &input.Config, Priority: input.Priority, } @@ -568,3 +621,88 @@ func (i *imlProviderModule) syncGateway(ctx context.Context, clusterId string, r return nil } + +var _ IAIAPIModule = (*imlAIApiModule)(nil) + +type imlAIApiModule struct { + aiAPIService ai_api.IAPIService `autowired:""` + aiAPIUseService ai_api.IAPIUseService `autowired:""` +} + +func (i *imlAIApiModule) APIs(ctx context.Context, keyword string, providerId string, start int64, end int64, page int, pageSize int, sortCondition string, asc bool) ([]*ai_dto.APIItem, int64, error) { + sortRule := "desc" + if asc { + sortRule = "asc" + } + switch sortCondition { + default: + apis, err := i.aiAPIService.Search(ctx, keyword, map[string]interface{}{ + "provider": providerId, + }, "update_at desc") + if err != nil { + return nil, 0, err + } + + if len(apis) <= 0 { + return nil, 0, nil + } + apiMap := make(map[string]*ai_api.API) + apiIds := make([]string, 0, len(apis)) + for _, a := range apis { + apiMap[a.ID] = a + apiIds = append(apiIds, a.ID) + } + offset := (page - 1) * pageSize + results, _, err := i.aiAPIUseService.SumByApisPage(ctx, providerId, start, end, offset, pageSize, fmt.Sprintf("total_token %s", sortRule), apiIds...) + if err != nil { + return nil, 0, err + } + + apiItems := utils.SliceToSlice(results, func(e *ai_api.APIUse) *ai_dto.APIItem { + info := apiMap[e.API] + + delete(apiMap, e.API) + return &ai_dto.APIItem{ + Id: e.API, + Name: info.Name, + Service: auto.UUID(info.Service), + Method: http.MethodPost, + RequestPath: info.Path, + Model: auto.Label{ + Id: info.Model, + Name: info.Model, + }, + UpdateTime: auto.TimeLabel(info.UpdateAt), + UseToken: e.TotalToken, + Disable: info.Disable, + } + }) + sortApis := make([]*ai_dto.APIItem, 0, len(apiMap)) + for _, a := range apiMap { + sortApis = append(sortApis, &ai_dto.APIItem{ + Id: a.ID, + Name: a.Name, + Service: auto.UUID(a.Service), + Method: http.MethodPost, + RequestPath: a.Path, + Model: auto.Label{ + Id: a.Model, + Name: a.Model, + }, + UpdateTime: auto.TimeLabel(a.UpdateAt), + UseToken: 0, + Disable: a.Disable, + }) + } + // 排序 + sort.Slice(sortApis, func(i, j int) bool { + return time.Time(sortApis[i].UpdateTime).After(time.Time(sortApis[j].UpdateTime)) + }) + size := pageSize - len(apiItems) + for i := offset; i < offset+size && i < len(sortApis); i++ { + apiItems = append(apiItems, sortApis[i]) + } + total := int64(len(apis)) + return apiItems, total, nil + } +} diff --git a/module/ai/module.go b/module/ai/module.go index eb8a3513..0241484b 100644 --- a/module/ai/module.go +++ b/module/ai/module.go @@ -20,6 +20,11 @@ type IProviderModule interface { UpdateProviderStatus(ctx context.Context, id string, enable bool) error UpdateProviderConfig(ctx context.Context, id string, input *ai_dto.UpdateConfig) error UpdateProviderDefaultLLM(ctx context.Context, id string, input *ai_dto.UpdateLLM) error + Sort(ctx context.Context, input *ai_dto.Sort) error +} + +type IAIAPIModule interface { + APIs(ctx context.Context, keyword string, providerId string, start int64, end int64, page int, pageSize int, sortCondition string, asc bool) ([]*ai_dto.APIItem, int64, error) } func init() { @@ -28,4 +33,8 @@ func init() { gateway.RegisterInitHandleFunc(module.initGateway) return reflect.ValueOf(module) }) + + autowire.Auto[IAIAPIModule](func() reflect.Value { + return reflect.ValueOf(new(imlAIApiModule)) + }) } diff --git a/plugins/core/ai.go b/plugins/core/ai.go index b2ad201d..39fde966 100644 --- a/plugins/core/ai.go +++ b/plugins/core/ai.go @@ -12,13 +12,13 @@ func (p *plugin) aiAPIs() []pm3.Api { return []pm3.Api{ pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/ai/providers/unconfigured", []string{"context"}, []string{"providers"}, p.aiProviderController.UnConfiguredProviders, access.SystemSettingsAiProviderView), pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/ai/providers/configured", []string{"context"}, []string{"providers", "backup"}, p.aiProviderController.ConfiguredProviders, access.SystemSettingsAiProviderView), - pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/simple/ai/providers/configured", []string{"context"}, []string{"providers"}, p.aiProviderController.SimpleProviders), + pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/simple/ai/providers", []string{"context"}, []string{"providers"}, p.aiProviderController.SimpleProviders), pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/ai/provider/config", []string{"context", "query:provider"}, []string{"provider"}, p.aiProviderController.Provider, access.SystemSettingsAiProviderView), pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/ai/provider/llms", []string{"context", "query:provider"}, []string{"llms", "provider"}, p.aiProviderController.LLMs), - //pm3.CreateApiWidthDoc(http.MethodPut, "/api/v1/ai/provider/enable", []string{"context", "query:provider"}, nil, p.aiProviderController.isStop), - //pm3.CreateApiWidthDoc(http.MethodPut, "/api/v1/ai/provider/disable", []string{"context", "query:provider"}, nil, p.aiProviderController.Disable), + pm3.CreateApiWidthDoc(http.MethodPut, "/api/v1/ai/provider/sort", []string{"context", "body"}, nil, p.aiProviderController.Sort), pm3.CreateApiWidthDoc(http.MethodPut, "/api/v1/ai/provider/config", []string{"context", "query:provider", "body"}, nil, p.aiProviderController.UpdateProviderConfig, access.SystemSettingsAiProviderManager), - //pm3.CreateApiWidthDoc(http.MethodPut, "/api/v1/ai/provider/default-llm", []string{"context", "query:provider", "body"}, nil, p.aiProviderController.UpdateProviderDefaultLLM), + + pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/ai/apis", []string{"context", "query:keyword", "query:provider", "query:start", "query:end", "query:page", "query:page_size", "query:sort", "query:asc"}, []string{"apis", "total"}, p.aiStatisticController.APIs), } } diff --git a/plugins/core/core.go b/plugins/core/core.go index c8244129..55d8c3f2 100644 --- a/plugins/core/core.go +++ b/plugins/core/core.go @@ -76,6 +76,7 @@ type plugin struct { upstreamController upstream.IUpstreamController `autowired:""` routerController router.IRouterController `autowired:""` aiAPIController ai_api.IAPIController `autowired:""` + aiStatisticController ai.IStatisticController `autowired:""` aiKeyController ai_key.IKeyController `autowired:""` apiDocController router.IAPIDocController `autowired:""` subscribeController subscribe.ISubscribeController `autowired:""` diff --git a/resources/access/access.yaml b/resources/access/access.yaml index 6b24896f..504b01d1 100644 --- a/resources/access/access.yaml +++ b/resources/access/access.yaml @@ -100,6 +100,36 @@ system: value: 'manager' dependents: - system.settings.ai_provider.view + - name: ai key resource + value: 'ai_key_resource' + children: + - name: view + value: 'view' + guest_allow: true + - name: manager + value: 'manager' + dependents: + - system.settings.ai_key_resource.view + - name: ai api + value: 'ai_api' + children: + - name: view + value: 'view' + guest_allow: true + - name: manager + value: 'manager' + dependents: + - system.settings.ai_api.view + - name: ai log + value: 'ai_log' + children: + - name: view + value: 'view' + guest_allow: true + - name: manager + value: 'manager' + dependents: + - system.settings.ai_log.view - name: ssl certificate cname: 证书 value: 'ssl_certificate' diff --git a/resources/access/role.yaml b/resources/access/role.yaml index 9b9613db..b9f3ebe4 100644 --- a/resources/access/role.yaml +++ b/resources/access/role.yaml @@ -6,6 +6,12 @@ system: - system.api_portal.api_portal.view - system.settings.account.manager - system.settings.account.view + - system.settings.ai_api.manager + - system.settings.ai_api.view + - system.settings.ai_key_resource.manager + - system.settings.ai_key_resource.view + - system.settings.ai_log.manager + - system.settings.ai_log.view - system.settings.ai_provider.manager - system.settings.ai_provider.view - system.settings.api_gateway.manager @@ -39,6 +45,12 @@ system: permits: - system.analysis.run_view.view - system.api_portal.api_portal.view + - system.settings.ai_api.manager + - system.settings.ai_api.view + - system.settings.ai_key_resource.manager + - system.settings.ai_key_resource.view + - system.settings.ai_log.manager + - system.settings.ai_log.view - system.settings.ai_provider.manager - system.settings.ai_provider.view - system.settings.api_gateway.manager diff --git a/service/ai-api/iml.go b/service/ai-api/iml.go index 24a2eedb..97e157c2 100644 --- a/service/ai-api/iml.go +++ b/service/ai-api/iml.go @@ -5,6 +5,8 @@ import ( "encoding/json" "time" + "github.com/eolinker/go-common/utils" + "github.com/APIParkLab/APIPark/service/universally" "github.com/APIParkLab/APIPark/stores/api" ) @@ -50,6 +52,7 @@ func createEntityHandler(i *Create) *api.AiAPIInfo { Retry: i.Retry, Model: i.Model, Provider: i.Provider, + Disable: i.Disable, CreateAt: now, UpdateAt: now, AdditionalConfig: string(cfg), @@ -81,5 +84,49 @@ func updateHandler(e *api.AiAPIInfo, i *Edit) { cfg, _ := json.Marshal(i.AdditionalConfig) e.AdditionalConfig = string(cfg) } + if i.Disable != nil { + e.Disable = *i.Disable + } + e.UpdateAt = time.Now() } + +var _ IAPIUseService = (*imlAPIUseService)(nil) + +type imlAPIUseService struct { + store api.IAiAPIUseStore `autowired:""` +} + +func (i *imlAPIUseService) SumByApisPage(ctx context.Context, providerId string, start, end int64, offset, limit int, order string, apiIds ...string) ([]*APIUse, int64, error) { + list, total, err := i.store.SumByGroupPage(ctx, "api", order, offset, limit, "api,sum(input_token) as input_token,sum(output_token) as output_token,sum(total_token) as total_token", "provider = ? and api in (?) and minute >= ? and minute <= ?", providerId, apiIds, start, end) + if err != nil { + return nil, 0, err + } + + result := make([]*APIUse, 0, len(list)) + for _, v := range list { + result = append(result, &APIUse{ + API: v.API, + InputToken: v.InputToken, + OutputToken: v.OutputToken, + TotalToken: v.TotalToken, + }) + } + return result, total, nil +} + +func (i *imlAPIUseService) SumByApis(ctx context.Context, providerId string, start, end int64, apiIds ...string) ([]*APIUse, error) { + list, err := i.store.SumByGroup(ctx, "api", "api,sum(input_token) as input_token,sum(output_token) as output_token,sum(total_token) as total_token", "provider = ? and api in (?) and minute >= ? and minute <= ?", providerId, apiIds, start, end) + if err != nil { + return nil, err + } + + return utils.SliceToSlice(list, func(v *api.AiAPIUse) *APIUse { + return &APIUse{ + API: v.API, + InputToken: v.InputToken, + OutputToken: v.OutputToken, + TotalToken: v.TotalToken, + } + }), nil +} diff --git a/service/ai-api/model.go b/service/ai-api/model.go index 7ce20a72..9ba1e635 100644 --- a/service/ai-api/model.go +++ b/service/ai-api/model.go @@ -36,6 +36,7 @@ type Create struct { Model string Provider string AdditionalConfig map[string]interface{} + Disable bool } type Edit struct { @@ -46,6 +47,7 @@ type Edit struct { Retry *int Provider *string Model *string + Disable *bool AdditionalConfig *map[string]interface{} } @@ -67,6 +69,14 @@ func FromEntity(e *api.AiAPIInfo) *API { UpdateAt: e.UpdateAt, Creator: e.Creator, Updater: e.Updater, + Disable: e.Disable, AdditionalConfig: cfg, } } + +type APIUse struct { + API string + InputToken int + OutputToken int + TotalToken int +} diff --git a/service/ai-api/service.go b/service/ai-api/service.go index 7128aaae..fc411a3a 100644 --- a/service/ai-api/service.go +++ b/service/ai-api/service.go @@ -14,12 +14,18 @@ type IAPIService interface { universally.IServiceEdit[Edit] universally.IServiceDelete CountMapByProvider(ctx context.Context, keyword string, conditions map[string]interface{}) (map[string]int64, error) +} - //ListByServices(ctx context.Context, serviceIds ...string) ([]*API, error) +type IAPIUseService interface { + SumByApis(ctx context.Context, providerId string, start, end int64, apiIds ...string) ([]*APIUse, error) + SumByApisPage(ctx context.Context, providerId string, start, end int64, page, pageSize int, order string, apiIds ...string) ([]*APIUse, int64, error) } func init() { autowire.Auto[IAPIService](func() reflect.Value { return reflect.ValueOf(new(imlAPIService)) }) + autowire.Auto[IAPIUseService](func() reflect.Value { + return reflect.ValueOf(new(imlAPIUseService)) + }) } diff --git a/stores/api/api.go b/stores/api/api.go index 4eab2d83..26fd5ba4 100644 --- a/stores/api/api.go +++ b/stores/api/api.go @@ -31,6 +31,14 @@ type imlAiAPIInfoStore struct { store.SearchStoreSoftDelete[AiAPIInfo] } +type IAiAPIUseStore interface { + store.IStatisticsStore[AiAPIUse] +} + +type imlAiAPIUseStore struct { + store.StatisticsStore[AiAPIUse] +} + func init() { autowire.Auto[IApiBaseStore](func() reflect.Value { @@ -48,4 +56,8 @@ func init() { autowire.Auto[IAiAPIInfoStore](func() reflect.Value { return reflect.ValueOf(new(imlAiAPIInfoStore)) }) + + autowire.Auto[IAiAPIUseStore](func() reflect.Value { + return reflect.ValueOf(new(imlAiAPIUseStore)) + }) } diff --git a/stores/api/model.go b/stores/api/model.go index db6b55ef..b4b1add3 100644 --- a/stores/api/model.go +++ b/stores/api/model.go @@ -85,6 +85,8 @@ type AiAPIInfo struct { Updater string `gorm:"size:36;not null;column:updater;comment:更新人;index:updater" aovalue:"updater"` UpdateAt time.Time `gorm:"type:timestamp;NOT NULL;DEFAULT:CURRENT_TIMESTAMP;column:update_at;comment:更新时间"` AdditionalConfig string `gorm:"type:text;null;column:additional_config;comment:额外配置"` + UseToken int `gorm:"type:int(11);not null;column:use_token;comment:使用token"` + Disable bool `gorm:"type:tinyint(1);not null;column:disable;comment:是否禁用 0:否 1:是"` IsDelete bool `gorm:"type:tinyint(1);not null;column:is_delete;comment:是否删除 0:否 1:是"` } @@ -95,3 +97,24 @@ func (a *AiAPIInfo) TableName() string { func (a *AiAPIInfo) IdValue() int64 { return a.Id } + +type AiAPIUse struct { + Id int64 `gorm:"column:id;type:BIGINT(20);AUTO_INCREMENT;NOT NULL;comment:id;primary_key;comment:主键ID;"` + API string `gorm:"size:36;not null;column:api;comment:API;index:api"` + Service string `gorm:"size:36;not null;column:service;comment:服务;index:service"` + Provider string `gorm:"size:36;not null;column:provider;comment:提供者;index:provider"` + Day int `gorm:"type:int(11);not null;column:day;comment:当前日期"` + Hour int `gorm:"type:int(11);not null;column:hour;comment:当前小时"` + Minute int `gorm:"type:int(11);not null;column:minute;comment:当前分钟"` + InputToken int `gorm:"type:int(11);not null;column:input_token;comment:输入token"` + OutputToken int `gorm:"type:int(11);not null;column:output_token;comment:输出token"` + TotalToken int `gorm:"type:int(11);not null;column:total_token;comment:总token"` +} + +func (a *AiAPIUse) TableName() string { + return "ai_api_use" +} + +func (a *AiAPIUse) IdValue() int64 { + return a.Id +} From 9fc23ad4bea93612472b406c7e17249f7e4672bd Mon Sep 17 00:00:00 2001 From: Liujian <824010343@qq.com> Date: Tue, 24 Dec 2024 18:20:09 +0800 Subject: [PATCH 2/2] update go.mod --- go.mod | 4 ++-- go.sum | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index a46deef4..6fdc3ad9 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ go 1.21 require ( github.com/eolinker/ap-account v1.0.15 github.com/eolinker/eosc v0.18.3 - github.com/eolinker/go-common v1.1.1 + github.com/eolinker/go-common v1.1.3 github.com/gabriel-vasile/mimetype v1.4.4 github.com/getkin/kin-openapi v0.127.0 github.com/gin-gonic/gin v1.10.0 @@ -81,4 +81,4 @@ require ( //replace github.com/eolinker/ap-account => ../aoaccount // -replace github.com/eolinker/go-common => ../../eolinker/go-common +//replace github.com/eolinker/go-common => ../../eolinker/go-common diff --git a/go.sum b/go.sum index e5fd313e..b1c0e925 100644 --- a/go.sum +++ b/go.sum @@ -32,6 +32,8 @@ github.com/eolinker/ap-account v1.0.15 h1:n6DJeL6RHZ8eLlZUcY2U3H4d/GPaA5oelAx3R0 github.com/eolinker/ap-account v1.0.15/go.mod h1:zm/Ivs6waJ/M/nEszhpPmM6g50y/MKO+5eABFAdeD0g= github.com/eolinker/eosc v0.18.3 h1:3IK5HkAPnJRfLbQ0FR7kWsZr6Y/OiqqGazvN1q2BL5A= github.com/eolinker/eosc v0.18.3/go.mod h1:O9PQQXFCpB6fjHf+oFt/LN6EOAv779ItbMixMKCfTfk= +github.com/eolinker/go-common v1.1.3 h1:Chb0x6sj0hZKpIN6Qo9IMdi9pX2KLNUPmqcaAD8mmWs= +github.com/eolinker/go-common v1.1.3/go.mod h1:Kb/jENMN1mApnodvRgV4YwO9FJby1Jkt2EUjrBjvSX4= github.com/gabriel-vasile/mimetype v1.4.4 h1:QjV6pZ7/XZ7ryI2KuyeEDE8wnh7fHP9YnQy+R0LnH8I= github.com/gabriel-vasile/mimetype v1.4.4/go.mod h1:JwLei5XPtWdGiMFB5Pjle1oEeoSeEuJfJE+TtfvdB/s= github.com/getkin/kin-openapi v0.127.0 h1:Mghqi3Dhryf3F8vR370nN67pAERW+3a95vomb3MAREY=