mirror of
https://github.com/APIParkLab/APIPark.git
synced 2026-06-14 20:41:15 +08:00
Merge pull request #158 from APIParkLab/feature/ai-balance
Feature/ai balance
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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{})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -32,8 +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.1 h1:3WqqecGqcHDgpa8Ljp156c1uWeZKP1CKScdU+6sOfcc=
|
||||
github.com/eolinker/go-common v1.1.1/go.mod h1:Kb/jENMN1mApnodvRgV4YwO9FJby1Jkt2EUjrBjvSX4=
|
||||
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=
|
||||
|
||||
@@ -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"`
|
||||
|
||||
@@ -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,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -10,3 +10,7 @@ type UpdateConfig struct {
|
||||
Priority *int `json:"priority"`
|
||||
Enable *bool `json:"enable"`
|
||||
}
|
||||
|
||||
type Sort struct {
|
||||
Providers []string `json:"providers"`
|
||||
}
|
||||
|
||||
+28
-5
@@ -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"`
|
||||
}
|
||||
|
||||
+148
-10
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
})
|
||||
}
|
||||
|
||||
+4
-4
@@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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:""`
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user