mirror of
https://github.com/APIParkLab/APIPark.git
synced 2026-06-04 10:13:53 +08:00
finish ai key api
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
package ai_key
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
ai_key_dto "github.com/APIParkLab/APIPark/module/ai-key/dto"
|
||||
"github.com/eolinker/go-common/autowire"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type IKeyController interface {
|
||||
Create(ctx *gin.Context, providerId string, input *ai_key_dto.Create) error
|
||||
Edit(ctx *gin.Context, providerId string, id string, input *ai_key_dto.Edit) error
|
||||
Delete(ctx *gin.Context, providerId string, id string) error
|
||||
Get(ctx *gin.Context, providerId string, id string) (*ai_key_dto.Key, error)
|
||||
List(ctx *gin.Context, providerId string, keyword string, page string, pageSize string) ([]*ai_key_dto.Item, int64, error)
|
||||
Enable(ctx *gin.Context, providerId string, id string) error
|
||||
Disable(ctx *gin.Context, providerId string, id string) error
|
||||
Sort(ctx *gin.Context, providerId string, input *ai_key_dto.Sort) error
|
||||
}
|
||||
|
||||
func init() {
|
||||
autowire.Auto[IKeyController](func() reflect.Value {
|
||||
return reflect.ValueOf(new(imlAIKeyController))
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package ai_key
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
ai_key "github.com/APIParkLab/APIPark/module/ai-key"
|
||||
ai_key_dto "github.com/APIParkLab/APIPark/module/ai-key/dto"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
var _ IKeyController = &imlAIKeyController{}
|
||||
|
||||
type imlAIKeyController struct {
|
||||
module ai_key.IKeyModule `autowired:""`
|
||||
}
|
||||
|
||||
func (i *imlAIKeyController) Enable(ctx *gin.Context, providerId string, id string) error {
|
||||
return i.module.UpdateKeyStatus(ctx, providerId, id, true)
|
||||
}
|
||||
|
||||
func (i *imlAIKeyController) Disable(ctx *gin.Context, providerId string, id string) error {
|
||||
return i.module.UpdateKeyStatus(ctx, providerId, id, false)
|
||||
}
|
||||
|
||||
func (i *imlAIKeyController) Create(ctx *gin.Context, providerId string, input *ai_key_dto.Create) error {
|
||||
return i.module.Create(ctx, providerId, input)
|
||||
}
|
||||
|
||||
func (i *imlAIKeyController) Edit(ctx *gin.Context, providerId string, id string, input *ai_key_dto.Edit) error {
|
||||
return i.module.Edit(ctx, providerId, id, input)
|
||||
}
|
||||
|
||||
func (i *imlAIKeyController) Delete(ctx *gin.Context, providerId string, id string) error {
|
||||
return i.module.Delete(ctx, providerId, id)
|
||||
}
|
||||
|
||||
func (i *imlAIKeyController) Get(ctx *gin.Context, providerId string, id string) (*ai_key_dto.Key, error) {
|
||||
return i.module.Get(ctx, providerId, id)
|
||||
}
|
||||
|
||||
func (i *imlAIKeyController) List(ctx *gin.Context, providerId string, keyword string, page string, pageSize string) ([]*ai_key_dto.Item, int64, error) {
|
||||
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.List(ctx, providerId, keyword, p, ps)
|
||||
}
|
||||
|
||||
func (i *imlAIKeyController) Sort(ctx *gin.Context, providerId string, input *ai_key_dto.Sort) error {
|
||||
return i.module.Sort(ctx, providerId, input)
|
||||
}
|
||||
@@ -1,14 +1,18 @@
|
||||
package ai
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/eolinker/go-common/auto"
|
||||
|
||||
ai_dto "github.com/APIParkLab/APIPark/module/ai/dto"
|
||||
"github.com/eolinker/go-common/autowire"
|
||||
"github.com/gin-gonic/gin"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type IProviderController interface {
|
||||
Providers(ctx *gin.Context) ([]*ai_dto.ProviderItem, error)
|
||||
ConfiguredProviders(ctx *gin.Context) ([]*ai_dto.ConfiguredProviderItem, *auto.Label, error)
|
||||
UnConfiguredProviders(ctx *gin.Context) ([]*ai_dto.ProviderItem, error)
|
||||
SimpleProviders(ctx *gin.Context) ([]*ai_dto.SimpleProviderItem, error)
|
||||
Provider(ctx *gin.Context, id string) (*ai_dto.Provider, error)
|
||||
LLMs(ctx *gin.Context, driver string) ([]*ai_dto.LLMItem, *ai_dto.ProviderItem, error)
|
||||
|
||||
@@ -3,6 +3,7 @@ package ai
|
||||
import (
|
||||
"github.com/APIParkLab/APIPark/module/ai"
|
||||
ai_dto "github.com/APIParkLab/APIPark/module/ai/dto"
|
||||
"github.com/eolinker/go-common/auto"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
@@ -14,12 +15,16 @@ type imlProviderController struct {
|
||||
module ai.IProviderModule `autowired:""`
|
||||
}
|
||||
|
||||
func (i *imlProviderController) SimpleProviders(ctx *gin.Context) ([]*ai_dto.SimpleProviderItem, error) {
|
||||
return i.module.SimpleProviders(ctx)
|
||||
func (i *imlProviderController) ConfiguredProviders(ctx *gin.Context) ([]*ai_dto.ConfiguredProviderItem, *auto.Label, error) {
|
||||
return i.module.ConfiguredProviders(ctx)
|
||||
}
|
||||
|
||||
func (i *imlProviderController) Providers(ctx *gin.Context) ([]*ai_dto.ProviderItem, error) {
|
||||
return i.module.Providers(ctx)
|
||||
func (i *imlProviderController) UnConfiguredProviders(ctx *gin.Context) ([]*ai_dto.ProviderItem, error) {
|
||||
return i.module.UnConfiguredProviders(ctx)
|
||||
}
|
||||
|
||||
func (i *imlProviderController) SimpleProviders(ctx *gin.Context) ([]*ai_dto.SimpleProviderItem, error) {
|
||||
return i.module.SimpleProviders(ctx)
|
||||
}
|
||||
|
||||
func (i *imlProviderController) Provider(ctx *gin.Context, id string) (*ai_dto.Provider, error) {
|
||||
|
||||
@@ -81,4 +81,4 @@ require (
|
||||
|
||||
//replace github.com/eolinker/ap-account => ../aoaccount
|
||||
//
|
||||
//replace github.com/eolinker/go-common => ../go-common
|
||||
replace github.com/eolinker/go-common => ../../eolinker/go-common
|
||||
|
||||
@@ -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=
|
||||
|
||||
@@ -8,6 +8,8 @@ import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/eolinker/eosc/log"
|
||||
|
||||
model_runtime "github.com/APIParkLab/APIPark/ai-provider/model-runtime"
|
||||
|
||||
ai_api_dto "github.com/APIParkLab/APIPark/module/ai-api/dto"
|
||||
@@ -114,6 +116,7 @@ func (i *imlAPIModule) Create(ctx context.Context, serviceId string, input *ai_a
|
||||
Timeout: input.Timeout,
|
||||
Retry: input.Retry,
|
||||
Model: input.AiModel.Id,
|
||||
Provider: input.AiModel.Provider,
|
||||
AdditionalConfig: map[string]interface{}{
|
||||
"ai_prompt": input.AiPrompt,
|
||||
"ai_model": input.AiModel,
|
||||
@@ -148,8 +151,10 @@ func (i *imlAPIModule) Edit(ctx context.Context, serviceId string, apiId string,
|
||||
return err
|
||||
}
|
||||
var modelId *string
|
||||
var providerId *string
|
||||
if input.AiModel != nil {
|
||||
modelId = &input.AiModel.Id
|
||||
providerId = &input.AiModel.Provider
|
||||
}
|
||||
if input.AiPrompt != nil {
|
||||
apiInfo.AdditionalConfig["ai_prompt"] = input.AiPrompt
|
||||
@@ -164,6 +169,7 @@ func (i *imlAPIModule) Edit(ctx context.Context, serviceId string, apiId string,
|
||||
Timeout: input.Timeout,
|
||||
Retry: input.Retry,
|
||||
Model: modelId,
|
||||
Provider: providerId,
|
||||
AdditionalConfig: &apiInfo.AdditionalConfig,
|
||||
})
|
||||
})
|
||||
@@ -304,3 +310,27 @@ func (i *imlAPIModule) Prefix(ctx context.Context, serviceId string) (string, er
|
||||
}
|
||||
return strings.TrimSuffix(pInfo.Prefix, "/"), nil
|
||||
}
|
||||
|
||||
func (i *imlAPIModule) OnInit() {
|
||||
ctx := context.Background()
|
||||
list, err := i.aiAPIService.List(ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, item := range list {
|
||||
if item.Provider == "" {
|
||||
aiModel, err := ConvertStruct[ai_api_dto.AiModel](item.AdditionalConfig["ai_model"])
|
||||
if err != nil {
|
||||
log.Errorf("convert ai model error:%v", err)
|
||||
continue
|
||||
}
|
||||
err = i.aiAPIService.Save(ctx, item.ID, &ai_api.Edit{
|
||||
Provider: &aiModel.Provider,
|
||||
})
|
||||
if err != nil {
|
||||
log.Errorf("update ai api provider error:%v", err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
package ai_key_dto
|
||||
|
||||
var (
|
||||
KeyNormal KeyStatus = "normal"
|
||||
KeyExceed KeyStatus = "exceed"
|
||||
KeyExpired KeyStatus = "expired"
|
||||
KeyDisable KeyStatus = "disable"
|
||||
KeyError KeyStatus = "error"
|
||||
)
|
||||
|
||||
type KeyStatus string
|
||||
|
||||
func (s KeyStatus) String() string {
|
||||
return string(s)
|
||||
}
|
||||
|
||||
func (s KeyStatus) Int() int {
|
||||
switch s {
|
||||
case KeyDisable:
|
||||
return 0
|
||||
case KeyNormal:
|
||||
return 1
|
||||
case KeyError:
|
||||
return 2
|
||||
case KeyExceed:
|
||||
return 3
|
||||
case KeyExpired:
|
||||
return 4
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
func ToKeyStatus(status int) KeyStatus {
|
||||
switch status {
|
||||
case 0:
|
||||
return KeyDisable
|
||||
case 1:
|
||||
return KeyNormal
|
||||
case 2:
|
||||
return KeyError
|
||||
case 3:
|
||||
return KeyExceed
|
||||
case 4:
|
||||
return KeyExpired
|
||||
default:
|
||||
return KeyDisable
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package ai_key_dto
|
||||
|
||||
type Create struct {
|
||||
Id string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Config string `json:"config"`
|
||||
ExpireTime int `json:"expire_time"`
|
||||
}
|
||||
|
||||
type Edit struct {
|
||||
Name *string `json:"name"`
|
||||
Config *string `json:"config"`
|
||||
ExpireTime *int `json:"expire_time"`
|
||||
}
|
||||
|
||||
type Sort struct {
|
||||
Origin string `json:"origin"`
|
||||
Target string `json:"target"`
|
||||
Sort string `json:"sort"`
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package ai_key_dto
|
||||
|
||||
import "github.com/eolinker/go-common/auto"
|
||||
|
||||
type Item struct {
|
||||
Id string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Status KeyStatus `json:"status"`
|
||||
UseToken int `json:"use_token"`
|
||||
UpdateTime auto.TimeLabel `json:"update_time"`
|
||||
ExpireTime int `json:"expire_time"`
|
||||
Priority int `json:"priority"`
|
||||
CanDelete bool `json:"can_delete"`
|
||||
}
|
||||
|
||||
type Key struct {
|
||||
Id string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Config string `json:"config"`
|
||||
ExpireTime int `json:"expire_time"`
|
||||
}
|
||||
@@ -0,0 +1,304 @@
|
||||
package ai_key
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/eolinker/go-common/auto"
|
||||
|
||||
model_runtime "github.com/APIParkLab/APIPark/ai-provider/model-runtime"
|
||||
|
||||
"github.com/google/uuid"
|
||||
|
||||
"github.com/eolinker/go-common/store"
|
||||
|
||||
"github.com/APIParkLab/APIPark/service/ai"
|
||||
|
||||
ai_key_dto "github.com/APIParkLab/APIPark/module/ai-key/dto"
|
||||
ai_key "github.com/APIParkLab/APIPark/service/ai-key"
|
||||
)
|
||||
|
||||
var _ IKeyModule = &imlKeyModule{}
|
||||
|
||||
type imlKeyModule struct {
|
||||
providerService ai.IProviderService `autowired:""`
|
||||
aiKeyService ai_key.IKeyService `autowired:""`
|
||||
transaction store.ITransaction `autowired:""`
|
||||
}
|
||||
|
||||
func (i *imlKeyModule) Create(ctx context.Context, providerId string, input *ai_key_dto.Create) error {
|
||||
_, err := i.providerService.Get(ctx, providerId)
|
||||
if err != nil {
|
||||
return fmt.Errorf("provider not found: %w", err)
|
||||
}
|
||||
p, has := model_runtime.GetProvider(providerId)
|
||||
if !has {
|
||||
return fmt.Errorf("provider not found: %w", err)
|
||||
}
|
||||
err = p.Check(input.Config)
|
||||
if err != nil {
|
||||
return fmt.Errorf("config check failed: %w", err)
|
||||
}
|
||||
priority, err := i.aiKeyService.MaxPriority(ctx, providerId)
|
||||
if err != nil {
|
||||
return fmt.Errorf("get key error: %v", err)
|
||||
}
|
||||
return i.transaction.Transaction(ctx, func(ctx context.Context) error {
|
||||
if input.Id == "" {
|
||||
input.Id = uuid.NewString()
|
||||
}
|
||||
status := ai_key_dto.KeyNormal.Int()
|
||||
if input.ExpireTime > 0 && time.Unix(int64(input.ExpireTime), 0).Before(time.Now()) {
|
||||
status = ai_key_dto.KeyExpired.Int()
|
||||
} else {
|
||||
// TODO: 发布Key到网关
|
||||
}
|
||||
|
||||
return i.aiKeyService.Create(ctx, &ai_key.Create{
|
||||
ID: input.Id,
|
||||
Name: input.Name,
|
||||
Config: input.Config,
|
||||
Provider: providerId,
|
||||
Status: status,
|
||||
ExpireTime: input.ExpireTime,
|
||||
Priority: priority + 1,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func (i *imlKeyModule) Edit(ctx context.Context, providerId string, id string, input *ai_key_dto.Edit) error {
|
||||
p, has := model_runtime.GetProvider(providerId)
|
||||
if !has {
|
||||
return fmt.Errorf("provider not found: %s", providerId)
|
||||
}
|
||||
_, err := i.providerService.Get(ctx, providerId)
|
||||
if err != nil {
|
||||
return fmt.Errorf("provider not found: %w", err)
|
||||
}
|
||||
return i.transaction.Transaction(ctx, func(ctx context.Context) error {
|
||||
info, err := i.aiKeyService.Get(ctx, id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("key not found: %w", err)
|
||||
}
|
||||
if input.Config != nil {
|
||||
err = p.Check(*input.Config)
|
||||
if err != nil {
|
||||
return fmt.Errorf("config check failed: %w", err)
|
||||
}
|
||||
cfg, err := p.GenConfig(info.Config, *input.Config)
|
||||
if err != nil {
|
||||
return fmt.Errorf("config gen failed: %w", err)
|
||||
}
|
||||
input.Config = &cfg
|
||||
if info.Default {
|
||||
err = i.providerService.Save(ctx, info.Provider, &ai.SetProvider{
|
||||
Config: input.Config,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
status := ai_key_dto.KeyNormal.Int()
|
||||
orgStatus := ai_key_dto.ToKeyStatus(info.Status)
|
||||
switch orgStatus {
|
||||
case ai_key_dto.KeyNormal, ai_key_dto.KeyError, ai_key_dto.KeyExpired:
|
||||
if input.ExpireTime != nil {
|
||||
expireTime := *input.ExpireTime
|
||||
if expireTime > 0 && time.Unix(int64(expireTime), 0).Before(time.Now()) {
|
||||
status = ai_key_dto.KeyExpired.Int()
|
||||
}
|
||||
} else if info.ExpireTime > 0 && time.Unix(int64(info.ExpireTime), 0).Before(time.Now()) {
|
||||
// 如果过期时间未更改,且已过期,则设置为过期状态
|
||||
status = ai_key_dto.KeyExpired.Int()
|
||||
}
|
||||
default:
|
||||
// 停用、超额需要启用,所以维持原状态
|
||||
status = orgStatus.Int()
|
||||
}
|
||||
if status == ai_key_dto.KeyNormal.Int() {
|
||||
// TODO: 发布Key到网关
|
||||
}
|
||||
|
||||
return i.aiKeyService.Save(ctx, id, &ai_key.Edit{
|
||||
Name: input.Name,
|
||||
Config: input.Config,
|
||||
ExpireTime: input.ExpireTime,
|
||||
Status: &status,
|
||||
})
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func (i *imlKeyModule) Delete(ctx context.Context, providerId string, id string) error {
|
||||
_, err := i.providerService.Get(ctx, providerId)
|
||||
if err != nil {
|
||||
return fmt.Errorf("provider not found: %w", err)
|
||||
}
|
||||
return i.transaction.Transaction(ctx, func(ctx context.Context) error {
|
||||
info, err := i.aiKeyService.Get(ctx, id)
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
if info.Default {
|
||||
return fmt.Errorf("default key can't be deleted: %s", id)
|
||||
}
|
||||
keys, err := i.aiKeyService.KeysAfterPriority(ctx, providerId, info.Priority)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, key := range keys {
|
||||
key.Priority--
|
||||
err = i.aiKeyService.Save(ctx, key.ID, &ai_key.Edit{
|
||||
Priority: &key.Priority,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: 操作网关下线Key
|
||||
return i.aiKeyService.Delete(ctx, id)
|
||||
})
|
||||
}
|
||||
|
||||
func (i *imlKeyModule) Get(ctx context.Context, providerId string, id string) (*ai_key_dto.Key, error) {
|
||||
p, has := model_runtime.GetProvider(providerId)
|
||||
if !has {
|
||||
return nil, fmt.Errorf("provider not found: %s", providerId)
|
||||
}
|
||||
_, err := i.providerService.Get(ctx, providerId)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("provider not found: %w", err)
|
||||
}
|
||||
info, err := i.aiKeyService.Get(ctx, id)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("key not found: %w", err)
|
||||
}
|
||||
|
||||
return &ai_key_dto.Key{
|
||||
Id: info.ID,
|
||||
Name: info.Name,
|
||||
Config: p.MaskConfig(info.Config),
|
||||
ExpireTime: info.ExpireTime,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (i *imlKeyModule) List(ctx context.Context, providerId string, keyword string, page, pageSize int) ([]*ai_key_dto.Item, int64, error) {
|
||||
_, err := i.aiKeyService.DefaultKey(ctx, providerId)
|
||||
if err != nil {
|
||||
if !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, 0, fmt.Errorf("get default key failed: %w", err)
|
||||
}
|
||||
info, err := i.providerService.Get(ctx, providerId)
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("provider is unconfigued,id is %s", providerId)
|
||||
}
|
||||
err = i.aiKeyService.Create(ctx, &ai_key.Create{
|
||||
ID: info.Id,
|
||||
Name: info.Name,
|
||||
Config: info.Config,
|
||||
Provider: info.Id,
|
||||
Status: ai_key_dto.KeyNormal.Int(),
|
||||
Priority: 1,
|
||||
ExpireTime: 0,
|
||||
UseToken: 0,
|
||||
Default: true,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("create default key failed: %w", err)
|
||||
}
|
||||
}
|
||||
list, total, err := i.aiKeyService.SearchByPage(ctx, keyword, map[string]interface{}{
|
||||
"provider": providerId,
|
||||
}, page, pageSize, "sort asc")
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
var result []*ai_key_dto.Item
|
||||
for _, item := range list {
|
||||
status := ai_key_dto.ToKeyStatus(item.Status)
|
||||
if item.ExpireTime > 0 && time.Unix(int64(item.ExpireTime), 0).Before(time.Now()) {
|
||||
status = ai_key_dto.KeyExpired
|
||||
}
|
||||
result = append(result, &ai_key_dto.Item{
|
||||
Id: item.ID,
|
||||
Name: item.Name,
|
||||
Status: status,
|
||||
UseToken: item.UseToken,
|
||||
UpdateTime: auto.TimeLabel(item.UpdateAt),
|
||||
ExpireTime: item.ExpireTime,
|
||||
CanDelete: !item.Default,
|
||||
Priority: item.Priority,
|
||||
})
|
||||
}
|
||||
|
||||
return result, total, nil
|
||||
}
|
||||
|
||||
func (i *imlKeyModule) UpdateKeyStatus(ctx context.Context, providerId string, id string, enable bool) error {
|
||||
_, err := i.providerService.Get(ctx, providerId)
|
||||
if err != nil {
|
||||
return fmt.Errorf("provider not found: %w", err)
|
||||
}
|
||||
info, err := i.aiKeyService.Get(ctx, id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("key not found: %w", err)
|
||||
}
|
||||
return i.transaction.Transaction(ctx, func(ctx context.Context) error {
|
||||
if !enable {
|
||||
// TODO:下线Key
|
||||
status := ai_key_dto.KeyDisable.Int()
|
||||
return i.aiKeyService.Save(ctx, id, &ai_key.Edit{
|
||||
Status: &status,
|
||||
})
|
||||
}
|
||||
if info.Status == ai_key_dto.KeyDisable.Int() || info.Status == ai_key_dto.KeyExceed.Int() {
|
||||
// 超额 或 停用状态,可启用
|
||||
if info.ExpireTime > 0 && time.Unix(int64(info.ExpireTime), 0).Before(time.Now()) {
|
||||
// 如果过期时间未更改,且已过期,则设置为过期状态
|
||||
status := ai_key_dto.KeyExpired.Int()
|
||||
return i.aiKeyService.Save(ctx, id, &ai_key.Edit{
|
||||
Status: &status,
|
||||
})
|
||||
}
|
||||
// TODO:发布Key到网关
|
||||
status := ai_key_dto.KeyNormal.Int()
|
||||
return i.aiKeyService.Save(ctx, id, &ai_key.Edit{
|
||||
Status: &status,
|
||||
})
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (i *imlKeyModule) Sort(ctx context.Context, providerId string, input *ai_key_dto.Sort) error {
|
||||
_, err := i.providerService.Get(ctx, providerId)
|
||||
if err != nil {
|
||||
return fmt.Errorf("provider not found: %w", err)
|
||||
}
|
||||
return i.transaction.Transaction(ctx, func(ctx context.Context) error {
|
||||
switch input.Sort {
|
||||
case "before":
|
||||
_, err = i.aiKeyService.SortBefore(ctx, providerId, input.Origin, input.Target)
|
||||
case "after":
|
||||
_, err = i.aiKeyService.SortAfter(ctx, providerId, input.Origin, input.Target)
|
||||
default:
|
||||
return fmt.Errorf("invalid sort type: %s", input.Sort)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// TODO: 全量更新key配置到网关
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package ai_key
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
|
||||
ai_key_dto "github.com/APIParkLab/APIPark/module/ai-key/dto"
|
||||
"github.com/eolinker/go-common/autowire"
|
||||
)
|
||||
|
||||
type IKeyModule interface {
|
||||
Create(ctx context.Context, providerId string, input *ai_key_dto.Create) error
|
||||
Edit(ctx context.Context, providerId string, id string, input *ai_key_dto.Edit) error
|
||||
Delete(ctx context.Context, providerId string, id string) error
|
||||
Get(ctx context.Context, providerId string, id string) (*ai_key_dto.Key, error)
|
||||
List(ctx context.Context, providerId string, keyword string, page, pageSize int) ([]*ai_key_dto.Item, int64, error)
|
||||
UpdateKeyStatus(ctx context.Context, providerId string, id string, enable bool) error
|
||||
Sort(ctx context.Context, providerId string, input *ai_key_dto.Sort) error
|
||||
}
|
||||
|
||||
func init() {
|
||||
autowire.Auto[IKeyModule](func() reflect.Value {
|
||||
return reflect.ValueOf(new(imlKeyModule))
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package ai_dto
|
||||
|
||||
var (
|
||||
ProviderEnabled ProviderStatus = "enabled"
|
||||
ProviderDisabled ProviderStatus = "disabled"
|
||||
ProviderAbnormal ProviderStatus = "abnormal"
|
||||
)
|
||||
|
||||
type ProviderStatus string
|
||||
|
||||
func (p ProviderStatus) Int() int {
|
||||
switch p {
|
||||
case ProviderAbnormal:
|
||||
return 2
|
||||
case ProviderEnabled:
|
||||
return 0
|
||||
case ProviderDisabled:
|
||||
return 1
|
||||
default:
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
func (p ProviderStatus) String() string {
|
||||
return string(p)
|
||||
}
|
||||
|
||||
func ToProviderStatus(status int) ProviderStatus {
|
||||
switch status {
|
||||
case 2:
|
||||
return ProviderAbnormal
|
||||
case 0:
|
||||
return ProviderEnabled
|
||||
case 1:
|
||||
return ProviderDisabled
|
||||
default:
|
||||
return ProviderDisabled
|
||||
}
|
||||
}
|
||||
@@ -7,4 +7,6 @@ type UpdateLLM struct {
|
||||
type UpdateConfig struct {
|
||||
DefaultLLM string `json:"default_llm"`
|
||||
Config string `json:"config"`
|
||||
Priority *int `json:"priority"`
|
||||
Enable *bool `json:"enable"`
|
||||
}
|
||||
|
||||
+25
-17
@@ -1,26 +1,34 @@
|
||||
package ai_dto
|
||||
|
||||
import "time"
|
||||
|
||||
type Provider struct {
|
||||
Id string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Config string `json:"config"`
|
||||
GetAPIKeyUrl string `json:"get_apikey_url"`
|
||||
DefaultLLM string `json:"defaultLLM"`
|
||||
DefaultLLMConfig string `json:"-"`
|
||||
Id string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Config string `json:"config"`
|
||||
GetAPIKeyUrl string `json:"get_apikey_url"`
|
||||
DefaultLLM string `json:"defaultLLM"`
|
||||
DefaultLLMConfig string `json:"-"`
|
||||
Priority int `json:"priority"`
|
||||
Status ProviderStatus `json:"status"`
|
||||
}
|
||||
|
||||
type ConfiguredProviderItem struct {
|
||||
Id string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Logo string `json:"logo"`
|
||||
DefaultLLM string `json:"default_llm"`
|
||||
Status ProviderStatus `json:"status"`
|
||||
APICount int64 `json:"api_count"`
|
||||
KeyCount int `json:"key_count"`
|
||||
KeyStatus []string `json:"key_status"`
|
||||
Priority int `json:"priority"`
|
||||
}
|
||||
|
||||
type ProviderItem struct {
|
||||
Id string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
DefaultLLM string `json:"default_llm"`
|
||||
DefaultLLMLogo string `json:"default_llm_logo"`
|
||||
Logo string `json:"logo"`
|
||||
Configured bool `json:"configured"`
|
||||
Recommend bool `json:"recommend"`
|
||||
Sort int `json:"sort"`
|
||||
UpdateTime time.Time `json:"-"`
|
||||
Id string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Logo string `json:"logo"`
|
||||
DefaultLLM string `json:"default_llm"`
|
||||
Sort int `json:"-"`
|
||||
}
|
||||
|
||||
type SimpleProviderItem struct {
|
||||
|
||||
+160
-30
@@ -8,6 +8,14 @@ import (
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
ai_key_dto "github.com/APIParkLab/APIPark/module/ai-key/dto"
|
||||
|
||||
ai_key "github.com/APIParkLab/APIPark/service/ai-key"
|
||||
|
||||
"github.com/eolinker/go-common/auto"
|
||||
|
||||
ai_api "github.com/APIParkLab/APIPark/service/ai-api"
|
||||
|
||||
model_runtime "github.com/APIParkLab/APIPark/ai-provider/model-runtime"
|
||||
"github.com/APIParkLab/APIPark/gateway"
|
||||
ai_dto "github.com/APIParkLab/APIPark/module/ai/dto"
|
||||
@@ -46,9 +54,82 @@ var _ IProviderModule = (*imlProviderModule)(nil)
|
||||
type imlProviderModule struct {
|
||||
providerService ai.IProviderService `autowired:""`
|
||||
clusterService cluster.IClusterService `autowired:""`
|
||||
aiAPIService ai_api.IAPIService `autowired:""`
|
||||
aiKeyService ai_key.IKeyService `autowired:""`
|
||||
transaction store.ITransaction `autowired:""`
|
||||
}
|
||||
|
||||
func (i *imlProviderModule) ConfiguredProviders(ctx context.Context) ([]*ai_dto.ConfiguredProviderItem, *auto.Label, error) {
|
||||
// 获取已配置的AI服务商
|
||||
list, err := i.providerService.List(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("get provider list error:%v", err)
|
||||
}
|
||||
aiAPIMap, err := i.aiAPIService.CountMapByProvider(ctx, "", nil)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("get ai api count error:%v", err)
|
||||
}
|
||||
providers := make([]*ai_dto.ConfiguredProviderItem, 0, len(list))
|
||||
for _, l := range list {
|
||||
p, has := model_runtime.GetProvider(l.Id)
|
||||
if !has {
|
||||
continue
|
||||
}
|
||||
keys, err := i.aiKeyService.KeysByProvider(ctx, l.Id)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("get provider keys error:%v", err)
|
||||
}
|
||||
|
||||
keysStatus := make([]string, 0, len(keys))
|
||||
for _, k := range keys {
|
||||
status := ai_key_dto.ToKeyStatus(k.Status)
|
||||
switch status {
|
||||
case ai_key_dto.KeyNormal, ai_key_dto.KeyDisable, ai_key_dto.KeyError:
|
||||
default:
|
||||
status = ai_key_dto.KeyError
|
||||
}
|
||||
keysStatus = append(keysStatus, status.String())
|
||||
}
|
||||
if len(keysStatus) == 0 {
|
||||
keysStatus = []string{ai_key_dto.KeyNormal.String()}
|
||||
}
|
||||
providers = append(providers, &ai_dto.ConfiguredProviderItem{
|
||||
Id: l.Id,
|
||||
Name: l.Name,
|
||||
Logo: p.Logo(),
|
||||
DefaultLLM: l.DefaultLLM,
|
||||
Status: ai_dto.ToProviderStatus(l.Status),
|
||||
APICount: aiAPIMap[l.Id],
|
||||
KeyCount: len(keysStatus),
|
||||
KeyStatus: keysStatus,
|
||||
Priority: l.Priority,
|
||||
})
|
||||
}
|
||||
sort.Slice(providers, func(i, j int) bool {
|
||||
if providers[i].Priority != providers[j].Priority {
|
||||
if providers[i].Priority == 0 {
|
||||
return false
|
||||
}
|
||||
if providers[j].Priority == 0 {
|
||||
return true
|
||||
}
|
||||
return providers[i].Priority < providers[j].Priority
|
||||
}
|
||||
return providers[i].Name < providers[j].Name
|
||||
})
|
||||
var backup *auto.Label
|
||||
for _, p := range providers {
|
||||
if p.Status == ai_dto.ProviderEnabled {
|
||||
backup = &auto.Label{
|
||||
Id: p.Id,
|
||||
Name: p.Name,
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
return providers, backup, nil
|
||||
}
|
||||
|
||||
func (i *imlProviderModule) SimpleProviders(ctx context.Context) ([]*ai_dto.SimpleProviderItem, error) {
|
||||
list, err := i.providerService.List(ctx)
|
||||
if err != nil {
|
||||
@@ -74,7 +155,7 @@ func (i *imlProviderModule) SimpleProviders(ctx context.Context) ([]*ai_dto.Simp
|
||||
return items, nil
|
||||
}
|
||||
|
||||
func (i *imlProviderModule) Providers(ctx context.Context) ([]*ai_dto.ProviderItem, error) {
|
||||
func (i *imlProviderModule) UnConfiguredProviders(ctx context.Context) ([]*ai_dto.ProviderItem, error) {
|
||||
list, err := i.providerService.List(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -85,30 +166,21 @@ func (i *imlProviderModule) Providers(ctx context.Context) ([]*ai_dto.ProviderIt
|
||||
})
|
||||
items := make([]*ai_dto.ProviderItem, 0, len(providers))
|
||||
for _, v := range providers {
|
||||
|
||||
item := &ai_dto.ProviderItem{
|
||||
Id: v.ID(),
|
||||
Name: v.Name(),
|
||||
Logo: v.Logo(),
|
||||
Recommend: v.Recommend(),
|
||||
Sort: v.Sort(),
|
||||
if _, has := providerMap[v.ID()]; has {
|
||||
// 已配置,跳过
|
||||
continue
|
||||
}
|
||||
if info, has := providerMap[v.ID()]; has {
|
||||
defaultLLM, has := v.GetModel(info.DefaultLLM)
|
||||
if !has {
|
||||
continue
|
||||
}
|
||||
item.Configured = true
|
||||
item.DefaultLLM = defaultLLM.ID()
|
||||
item.DefaultLLMLogo = defaultLLM.Logo()
|
||||
item.UpdateTime = info.UpdateAt
|
||||
defaultLLM, _ := v.DefaultModel(model_runtime.ModelTypeLLM)
|
||||
item := &ai_dto.ProviderItem{
|
||||
Id: v.ID(),
|
||||
Name: v.Name(),
|
||||
Logo: v.Logo(),
|
||||
DefaultLLM: defaultLLM.ID(),
|
||||
Sort: v.Sort(),
|
||||
}
|
||||
items = append(items, item)
|
||||
}
|
||||
sort.Slice(items, func(i, j int) bool {
|
||||
if items[i].Configured == items[j].Configured && items[i].Configured {
|
||||
return items[i].Name < items[j].Name
|
||||
}
|
||||
if items[i].Sort != items[j].Sort {
|
||||
if items[i].Sort == 0 {
|
||||
return false
|
||||
@@ -128,6 +200,13 @@ func (i *imlProviderModule) Provider(ctx context.Context, id string) (*ai_dto.Pr
|
||||
if !has {
|
||||
return nil, fmt.Errorf("ai provider not found")
|
||||
}
|
||||
maxPriority, err := i.providerService.MaxPriority(ctx)
|
||||
if err != nil {
|
||||
if !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
maxPriority = maxPriority + 1
|
||||
info, err := i.providerService.Get(ctx, id)
|
||||
if err != nil {
|
||||
if !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
@@ -144,6 +223,8 @@ func (i *imlProviderModule) Provider(ctx context.Context, id string) (*ai_dto.Pr
|
||||
GetAPIKeyUrl: p.HelpUrl(),
|
||||
DefaultLLM: defaultLLM.ID(),
|
||||
DefaultLLMConfig: defaultLLM.Logo(),
|
||||
Status: ai_dto.ProviderDisabled,
|
||||
Priority: maxPriority,
|
||||
}, nil
|
||||
}
|
||||
defaultLLM, has := p.GetModel(info.DefaultLLM)
|
||||
@@ -154,6 +235,10 @@ func (i *imlProviderModule) Provider(ctx context.Context, id string) (*ai_dto.Pr
|
||||
}
|
||||
defaultLLM = model
|
||||
}
|
||||
if info.Priority == 0 {
|
||||
info.Priority = maxPriority
|
||||
}
|
||||
|
||||
return &ai_dto.Provider{
|
||||
Id: info.Id,
|
||||
Name: info.Name,
|
||||
@@ -161,6 +246,8 @@ func (i *imlProviderModule) Provider(ctx context.Context, id string) (*ai_dto.Pr
|
||||
GetAPIKeyUrl: p.HelpUrl(),
|
||||
DefaultLLM: defaultLLM.ID(),
|
||||
DefaultLLMConfig: defaultLLM.DefaultConfig(),
|
||||
Priority: info.Priority,
|
||||
Status: ai_dto.ProviderEnabled,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -196,16 +283,19 @@ func (i *imlProviderModule) LLMs(ctx context.Context, driver string) ([]*ai_dto.
|
||||
return nil, nil, fmt.Errorf("ai provider default llm not found")
|
||||
}
|
||||
return items, &ai_dto.ProviderItem{
|
||||
Id: p.ID(),
|
||||
Name: p.Name(),
|
||||
DefaultLLM: defaultLLM.ID(),
|
||||
DefaultLLMLogo: defaultLLM.Logo(),
|
||||
Logo: p.Logo(),
|
||||
Configured: false,
|
||||
Id: p.ID(),
|
||||
Name: p.Name(),
|
||||
DefaultLLM: defaultLLM.ID(),
|
||||
Logo: p.Logo(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
return items, &ai_dto.ProviderItem{Id: info.Id, Name: info.Name, DefaultLLM: info.DefaultLLM, Logo: p.Logo(), Configured: true}, nil
|
||||
return items, &ai_dto.ProviderItem{
|
||||
Id: info.Id,
|
||||
Name: info.Name,
|
||||
DefaultLLM: info.DefaultLLM,
|
||||
Logo: p.Logo(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (i *imlProviderModule) UpdateProviderStatus(ctx context.Context, id string, enable bool) error {
|
||||
@@ -222,8 +312,12 @@ func (i *imlProviderModule) UpdateProviderStatus(ctx context.Context, id string,
|
||||
}
|
||||
|
||||
return i.transaction.Transaction(ctx, func(txCtx context.Context) error {
|
||||
status := 0
|
||||
if enable {
|
||||
status = 1
|
||||
}
|
||||
err = i.providerService.Save(txCtx, id, &ai.SetProvider{
|
||||
Status: &enable,
|
||||
Status: &status,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -303,11 +397,46 @@ func (i *imlProviderModule) UpdateProviderConfig(ctx context.Context, id string,
|
||||
return err
|
||||
}
|
||||
return i.transaction.Transaction(ctx, func(txCtx context.Context) error {
|
||||
err = i.providerService.Save(ctx, id, &ai.SetProvider{
|
||||
status := 0
|
||||
if input.Enable != nil && *input.Enable {
|
||||
status = 1
|
||||
}
|
||||
pInfo := &ai.SetProvider{
|
||||
Name: &info.Name,
|
||||
DefaultLLM: &info.DefaultLLM,
|
||||
Config: &input.Config,
|
||||
})
|
||||
Priority: input.Priority,
|
||||
}
|
||||
_, err = i.aiKeyService.DefaultKey(ctx, id)
|
||||
if err != nil {
|
||||
if !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return err
|
||||
}
|
||||
err = i.aiKeyService.Create(ctx, &ai_key.Create{
|
||||
ID: id,
|
||||
Name: info.Name,
|
||||
Config: info.Config,
|
||||
Provider: id,
|
||||
Status: 1,
|
||||
ExpireTime: 0,
|
||||
Default: true,
|
||||
})
|
||||
} else {
|
||||
err = i.aiKeyService.Save(ctx, id, &ai_key.Edit{
|
||||
Config: &info.Config,
|
||||
})
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if input.Enable != nil {
|
||||
status = 0
|
||||
if *input.Enable {
|
||||
status = 1
|
||||
}
|
||||
pInfo.Status = &status
|
||||
}
|
||||
err = i.providerService.Save(ctx, id, pInfo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -376,6 +505,7 @@ func (i *imlProviderModule) getAiProviders(ctx context.Context) ([]*gateway.Dyna
|
||||
}
|
||||
return providers, nil
|
||||
}
|
||||
|
||||
func (i *imlProviderModule) initGateway(ctx context.Context, clusterId string, clientDriver gateway.IClientDriver) error {
|
||||
providers, err := i.getAiProviders(ctx)
|
||||
if err != nil {
|
||||
|
||||
+6
-2
@@ -2,14 +2,18 @@ package ai
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
|
||||
"github.com/eolinker/go-common/auto"
|
||||
|
||||
"github.com/APIParkLab/APIPark/gateway"
|
||||
ai_dto "github.com/APIParkLab/APIPark/module/ai/dto"
|
||||
"github.com/eolinker/go-common/autowire"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type IProviderModule interface {
|
||||
Providers(ctx context.Context) ([]*ai_dto.ProviderItem, error)
|
||||
ConfiguredProviders(ctx context.Context) ([]*ai_dto.ConfiguredProviderItem, *auto.Label, error)
|
||||
UnConfiguredProviders(ctx context.Context) ([]*ai_dto.ProviderItem, error)
|
||||
SimpleProviders(ctx context.Context) ([]*ai_dto.SimpleProviderItem, error)
|
||||
Provider(ctx context.Context, id string) (*ai_dto.Provider, error)
|
||||
LLMs(ctx context.Context, driver string) ([]*ai_dto.LLMItem, *ai_dto.ProviderItem, error)
|
||||
|
||||
+16
-2
@@ -10,8 +10,9 @@ import (
|
||||
|
||||
func (p *plugin) aiAPIs() []pm3.Api {
|
||||
return []pm3.Api{
|
||||
pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/ai/providers", []string{"context"}, []string{"providers"}, p.aiProviderController.Providers, access.SystemSettingsAiProviderView),
|
||||
pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/simple/ai/providers", []string{"context"}, []string{"providers"}, p.aiProviderController.SimpleProviders),
|
||||
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/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),
|
||||
@@ -20,3 +21,16 @@ func (p *plugin) aiAPIs() []pm3.Api {
|
||||
//pm3.CreateApiWidthDoc(http.MethodPut, "/api/v1/ai/provider/default-llm", []string{"context", "query:provider", "body"}, nil, p.aiProviderController.UpdateProviderDefaultLLM),
|
||||
}
|
||||
}
|
||||
|
||||
func (p *plugin) aiKeyApis() []pm3.Api {
|
||||
return []pm3.Api{
|
||||
pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/ai/resource/key", []string{"context", "query:provider", "query:id"}, []string{"info"}, p.aiKeyController.Get),
|
||||
pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/ai/resource/keys", []string{"context", "query:provider", "query:keyword", "query:page", "query:page_size"}, []string{"keys", "total"}, p.aiKeyController.List),
|
||||
pm3.CreateApiWidthDoc(http.MethodPost, "/api/v1/ai/resource/key", []string{"context", "query:provider", "body"}, nil, p.aiKeyController.Create),
|
||||
pm3.CreateApiWidthDoc(http.MethodPut, "/api/v1/ai/resource/key", []string{"context", "query:provider", "query:id", "body"}, nil, p.aiKeyController.Edit),
|
||||
pm3.CreateApiWidthDoc(http.MethodDelete, "/api/v1/ai/resource/key", []string{"context", "query:provider", "query:id"}, nil, p.aiKeyController.Delete),
|
||||
pm3.CreateApiWidthDoc(http.MethodPut, "/api/v1/ai/resource/key/enable", []string{"context", "query:provider", "query:id"}, nil, p.aiKeyController.Enable),
|
||||
pm3.CreateApiWidthDoc(http.MethodPut, "/api/v1/ai/resource/key/disable", []string{"context", "query:provider", "query:id"}, nil, p.aiKeyController.Disable),
|
||||
pm3.CreateApiWidthDoc(http.MethodPut, "/api/v1/ai/resource/key/sort", []string{"context", "query:provider", "body"}, nil, p.aiKeyController.Sort),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ package core
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
ai_key "github.com/APIParkLab/APIPark/controller/ai-key"
|
||||
|
||||
"github.com/APIParkLab/APIPark/controller/log"
|
||||
|
||||
"github.com/APIParkLab/APIPark/controller/strategy"
|
||||
@@ -74,6 +76,7 @@ type plugin struct {
|
||||
upstreamController upstream.IUpstreamController `autowired:""`
|
||||
routerController router.IRouterController `autowired:""`
|
||||
aiAPIController ai_api.IAPIController `autowired:""`
|
||||
aiKeyController ai_key.IKeyController `autowired:""`
|
||||
apiDocController router.IAPIDocController `autowired:""`
|
||||
subscribeController subscribe.ISubscribeController `autowired:""`
|
||||
strategyController strategy.IStrategyController `autowired:""`
|
||||
@@ -111,6 +114,7 @@ func (p *plugin) OnComplete() {
|
||||
p.apis = append(p.apis, p.commonApis()...)
|
||||
p.apis = append(p.apis, p.systemApis()...)
|
||||
p.apis = append(p.apis, p.aiAPIs()...)
|
||||
p.apis = append(p.apis, p.aiKeyApis()...)
|
||||
p.apis = append(p.apis, p.strategyApis()...)
|
||||
p.apis = append(p.apis, p.logApis()...)
|
||||
}
|
||||
|
||||
+11
-1
@@ -1,10 +1,12 @@
|
||||
package ai_api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/APIParkLab/APIPark/service/universally"
|
||||
"github.com/APIParkLab/APIPark/stores/api"
|
||||
"time"
|
||||
)
|
||||
|
||||
var _ IAPIService = (*imlAPIService)(nil)
|
||||
@@ -18,6 +20,10 @@ type imlAPIService struct {
|
||||
universally.IServiceDelete
|
||||
}
|
||||
|
||||
func (i *imlAPIService) CountMapByProvider(ctx context.Context, keyword string, conditions map[string]interface{}) (map[string]int64, error) {
|
||||
return i.store.CountByGroup(ctx, keyword, conditions, "provider")
|
||||
}
|
||||
|
||||
func (i *imlAPIService) OnComplete() {
|
||||
i.IServiceGet = universally.NewGetSoftDelete[API, api.AiAPIInfo](i.store, FromEntity)
|
||||
i.IServiceCreate = universally.NewCreatorSoftDelete[Create, api.AiAPIInfo](i.store, "ai_api_info", createEntityHandler, uniquestHandler, labelHandler)
|
||||
@@ -43,6 +49,7 @@ func createEntityHandler(i *Create) *api.AiAPIInfo {
|
||||
Timeout: i.Timeout,
|
||||
Retry: i.Retry,
|
||||
Model: i.Model,
|
||||
Provider: i.Provider,
|
||||
CreateAt: now,
|
||||
UpdateAt: now,
|
||||
AdditionalConfig: string(cfg),
|
||||
@@ -67,6 +74,9 @@ func updateHandler(e *api.AiAPIInfo, i *Edit) {
|
||||
if i.Model != nil {
|
||||
e.Model = *i.Model
|
||||
}
|
||||
if i.Provider != nil {
|
||||
e.Provider = *i.Provider
|
||||
}
|
||||
if i.AdditionalConfig != nil {
|
||||
cfg, _ := json.Marshal(i.AdditionalConfig)
|
||||
e.AdditionalConfig = string(cfg)
|
||||
|
||||
@@ -16,6 +16,7 @@ type API struct {
|
||||
Timeout int
|
||||
Retry int
|
||||
Model string
|
||||
Provider string
|
||||
CreateAt time.Time
|
||||
UpdateAt time.Time
|
||||
Creator string
|
||||
@@ -33,6 +34,7 @@ type Create struct {
|
||||
Timeout int
|
||||
Retry int
|
||||
Model string
|
||||
Provider string
|
||||
AdditionalConfig map[string]interface{}
|
||||
}
|
||||
|
||||
@@ -42,6 +44,7 @@ type Edit struct {
|
||||
Description *string
|
||||
Timeout *int
|
||||
Retry *int
|
||||
Provider *string
|
||||
Model *string
|
||||
AdditionalConfig *map[string]interface{}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
package ai_api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
|
||||
"github.com/APIParkLab/APIPark/service/universally"
|
||||
"github.com/eolinker/go-common/autowire"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type IAPIService interface {
|
||||
@@ -11,6 +13,7 @@ type IAPIService interface {
|
||||
universally.IServiceCreate[Create]
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,210 @@
|
||||
package ai_key
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/eolinker/go-common/store"
|
||||
|
||||
"github.com/APIParkLab/APIPark/service/universally"
|
||||
"github.com/APIParkLab/APIPark/stores/ai"
|
||||
)
|
||||
|
||||
var _ IKeyService = &imlAIKeyService{}
|
||||
|
||||
type imlAIKeyService struct {
|
||||
store ai.IKeyStore `autowired:""`
|
||||
transaction store.ITransaction `autowired:""`
|
||||
universally.IServiceGet[Key]
|
||||
universally.IServiceCreate[Create]
|
||||
universally.IServiceEdit[Edit]
|
||||
universally.IServiceDelete
|
||||
}
|
||||
|
||||
func (i *imlAIKeyService) KeysAfterPriority(ctx context.Context, providerId string, priority int) ([]*Key, error) {
|
||||
list, err := i.store.ListQuery(ctx, "sort > ? and provider = ?", []interface{}{priority, providerId}, "sort asc")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var result []*Key
|
||||
for _, item := range list {
|
||||
result = append(result, FromEntity(item))
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (i *imlAIKeyService) MaxPriority(ctx context.Context, providerId string) (int, error) {
|
||||
info, err := i.store.First(ctx, map[string]interface{}{"provider": providerId}, "sort desc")
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return info.Sort, nil
|
||||
}
|
||||
|
||||
func (i *imlAIKeyService) DefaultKey(ctx context.Context, providerId string) (*Key, error) {
|
||||
info, err := i.store.First(ctx, map[string]interface{}{"provider": providerId, "default": true})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return FromEntity(info), nil
|
||||
}
|
||||
|
||||
func (i *imlAIKeyService) KeysByProvider(ctx context.Context, providerId string) ([]*Key, error) {
|
||||
list, err := i.store.List(ctx, map[string]interface{}{"provider": providerId})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var result []*Key
|
||||
for _, item := range list {
|
||||
result = append(result, FromEntity(item))
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (i *imlAIKeyService) SortBefore(ctx context.Context, provider string, originID string, targetID string) ([]*Key, error) {
|
||||
originKey, err := i.store.GetByUUID(ctx, originID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get key error: %v,id is %s", err, originID)
|
||||
}
|
||||
targetKey, err := i.store.GetByUUID(ctx, targetID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get key error: %v,id is %s", err, targetID)
|
||||
}
|
||||
originKeySort, targetKeySort := originKey.Sort, targetKey.Sort
|
||||
// 初始化顺序,假设原始Key在目标Key之后,中间的key往后移动,原始Key移动到`targetKeySort`位置
|
||||
originKey.Sort = targetKeySort
|
||||
fn := func(priority int) int {
|
||||
return priority + 1
|
||||
}
|
||||
sql := "sort < ? and sort >= ?"
|
||||
if originKeySort < targetKeySort {
|
||||
// 如果原始Key在目标Key之前,中间的key往前移动,原始Key移动到`targetKeySort - 1`位置
|
||||
sql = "sort > ? and sort < ?"
|
||||
originKey.Sort = targetKeySort - 1
|
||||
fn = func(priority int) int {
|
||||
return priority - 1
|
||||
}
|
||||
}
|
||||
list, err := i.store.ListQuery(ctx, sql, []interface{}{originKeySort, targetKeySort}, "sort asc")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := make([]*Key, 0, len(list)+1)
|
||||
err = i.transaction.Transaction(ctx, func(txCtx context.Context) error {
|
||||
for _, l := range list {
|
||||
l.Sort = fn(l.Sort)
|
||||
_, err := i.store.Update(ctx, l)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
result = append(result, FromEntity(l))
|
||||
}
|
||||
_, err = i.store.Update(ctx, originKey)
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, FromEntity(originKey))
|
||||
sort.Slice(list, func(i, j int) bool { return list[i].Sort < list[j].Sort })
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (i *imlAIKeyService) SortAfter(ctx context.Context, provider string, originID string, targetID string) ([]*Key, error) {
|
||||
originKey, err := i.store.GetByUUID(ctx, originID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get key error: %v,id is %s", err, originID)
|
||||
}
|
||||
targetKey, err := i.store.GetByUUID(ctx, targetID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get key error: %v,id is %s", err, targetID)
|
||||
}
|
||||
originKeySort, targetKeySort := originKey.Sort, targetKey.Sort
|
||||
// 初始化顺序,假设原始Key在目标Key之后,中间的Key往后移动,原始Key移动到`targetKeySort + 1`位置
|
||||
originKey.Sort = targetKeySort + 1
|
||||
fn := func(priority int) int {
|
||||
return priority + 1
|
||||
}
|
||||
sql := "sort < ? and sort > ?"
|
||||
if originKeySort < targetKeySort {
|
||||
// 如果原始Key在目标Key之前,中间的Key往前移动,原始Key移动到`targetKeySort`位置
|
||||
sql = "sort > ? and sort <= ?"
|
||||
originKey.Sort = targetKeySort
|
||||
fn = func(priority int) int {
|
||||
return priority - 1
|
||||
}
|
||||
}
|
||||
list, err := i.store.ListQuery(ctx, sql, []interface{}{originKeySort, targetKeySort}, "sort asc")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := make([]*Key, 0, len(list)+1)
|
||||
err = i.transaction.Transaction(ctx, func(txCtx context.Context) error {
|
||||
for _, l := range list {
|
||||
l.Sort = fn(l.Sort)
|
||||
_, err := i.store.Update(ctx, l)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
result = append(result, FromEntity(l))
|
||||
}
|
||||
_, err = i.store.Update(ctx, originKey)
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, FromEntity(originKey))
|
||||
sort.Slice(list, func(i, j int) bool { return list[i].Sort < list[j].Sort })
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (i *imlAIKeyService) OnComplete() {
|
||||
i.IServiceGet = universally.NewGet[Key, ai.Key](i.store, FromEntity)
|
||||
i.IServiceCreate = universally.NewCreator[Create, ai.Key](i.store, "ai_api_info", createEntityHandler, uniquestHandler, labelHandler)
|
||||
i.IServiceEdit = universally.NewEdit[Edit, ai.Key](i.store, updateHandler)
|
||||
i.IServiceDelete = universally.NewDelete[ai.Key](i.store)
|
||||
}
|
||||
|
||||
func labelHandler(e *ai.Key) []string {
|
||||
return []string{e.Name, e.Uuid}
|
||||
}
|
||||
func uniquestHandler(i *Create) []map[string]interface{} {
|
||||
return []map[string]interface{}{{"uuid": i.ID}}
|
||||
}
|
||||
func createEntityHandler(i *Create) *ai.Key {
|
||||
now := time.Now()
|
||||
return &ai.Key{
|
||||
Uuid: i.ID,
|
||||
Name: i.Name,
|
||||
Config: i.Config,
|
||||
Provider: i.Provider,
|
||||
Status: i.Status,
|
||||
ExpireTime: i.ExpireTime,
|
||||
Sort: i.Priority,
|
||||
UseToken: 0,
|
||||
CreateAt: now,
|
||||
UpdateAt: now,
|
||||
Default: i.Default,
|
||||
}
|
||||
}
|
||||
func updateHandler(e *ai.Key, i *Edit) {
|
||||
if i.Name != nil {
|
||||
e.Name = *i.Name
|
||||
}
|
||||
if i.Config != nil {
|
||||
e.Config = *i.Config
|
||||
}
|
||||
if i.Status != nil {
|
||||
e.Status = *i.Status
|
||||
}
|
||||
if i.ExpireTime != nil {
|
||||
e.ExpireTime = *i.ExpireTime
|
||||
}
|
||||
if i.Priority != nil {
|
||||
e.Sort = *i.Priority
|
||||
}
|
||||
e.UpdateAt = time.Now()
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package ai_key
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/APIParkLab/APIPark/stores/ai"
|
||||
)
|
||||
|
||||
type Key struct {
|
||||
ID string
|
||||
Name string
|
||||
Config string
|
||||
Provider string
|
||||
Status int
|
||||
ExpireTime int
|
||||
UseToken int
|
||||
Creator string
|
||||
Updater string
|
||||
Priority int
|
||||
CreateAt time.Time
|
||||
UpdateAt time.Time
|
||||
Default bool
|
||||
}
|
||||
|
||||
func FromEntity(e *ai.Key) *Key {
|
||||
return &Key{
|
||||
ID: e.Uuid,
|
||||
Name: e.Name,
|
||||
Config: e.Config,
|
||||
Provider: e.Provider,
|
||||
Status: e.Status,
|
||||
ExpireTime: e.ExpireTime,
|
||||
UseToken: e.UseToken,
|
||||
Creator: e.Creator,
|
||||
Updater: e.Updater,
|
||||
CreateAt: e.CreateAt,
|
||||
UpdateAt: e.UpdateAt,
|
||||
Priority: e.Sort,
|
||||
Default: e.Default,
|
||||
}
|
||||
}
|
||||
|
||||
type Create struct {
|
||||
ID string
|
||||
Name string
|
||||
Config string
|
||||
Provider string
|
||||
Priority int
|
||||
Status int
|
||||
ExpireTime int
|
||||
UseToken int
|
||||
Default bool
|
||||
}
|
||||
|
||||
type Edit struct {
|
||||
Name *string
|
||||
Config *string
|
||||
Status *int
|
||||
ExpireTime *int
|
||||
Priority *int
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package ai_key
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
|
||||
"github.com/eolinker/go-common/autowire"
|
||||
|
||||
"github.com/APIParkLab/APIPark/service/universally"
|
||||
)
|
||||
|
||||
type IKeyService interface {
|
||||
universally.IServiceGet[Key]
|
||||
universally.IServiceCreate[Create]
|
||||
universally.IServiceEdit[Edit]
|
||||
universally.IServiceDelete
|
||||
DefaultKey(ctx context.Context, providerId string) (*Key, error)
|
||||
KeysByProvider(ctx context.Context, providerId string) ([]*Key, error)
|
||||
MaxPriority(ctx context.Context, providerId string) (int, error)
|
||||
SortBefore(ctx context.Context, provider string, originID string, targetID string) ([]*Key, error)
|
||||
SortAfter(ctx context.Context, provider string, originID string, targetID string) ([]*Key, error)
|
||||
KeysAfterPriority(ctx context.Context, providerId string, priority int) ([]*Key, error)
|
||||
}
|
||||
|
||||
func init() {
|
||||
autowire.Auto[IKeyService](func() reflect.Value {
|
||||
return reflect.ValueOf(new(imlAIKeyService))
|
||||
})
|
||||
}
|
||||
+25
-2
@@ -4,12 +4,13 @@ import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/APIParkLab/APIPark/service/universally"
|
||||
"github.com/APIParkLab/APIPark/stores/ai"
|
||||
"github.com/eolinker/go-common/auto"
|
||||
"github.com/eolinker/go-common/utils"
|
||||
"gorm.io/gorm"
|
||||
"time"
|
||||
)
|
||||
|
||||
var _ IProviderService = (*imlProviderService)(nil)
|
||||
@@ -19,6 +20,14 @@ type imlProviderService struct {
|
||||
store ai.IProviderStore `autowired:""`
|
||||
}
|
||||
|
||||
func (i *imlProviderService) MaxPriority(ctx context.Context) (int, error) {
|
||||
t, err := i.store.First(ctx, nil, "priority desc")
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return t.Priority, nil
|
||||
}
|
||||
|
||||
func (i *imlProviderService) Save(ctx context.Context, id string, cfg *SetProvider) error {
|
||||
userId := utils.UserId(ctx)
|
||||
now := time.Now()
|
||||
@@ -30,10 +39,20 @@ func (i *imlProviderService) Save(ctx context.Context, id string, cfg *SetProvid
|
||||
if cfg.Name == nil || cfg.Config == nil || cfg.DefaultLLM == nil {
|
||||
return errors.New("invalid params")
|
||||
}
|
||||
status := false
|
||||
status := 1
|
||||
if cfg.Status != nil {
|
||||
status = *cfg.Status
|
||||
}
|
||||
priority := 1
|
||||
if cfg.Priority == nil {
|
||||
count, err := i.store.Count(ctx, "", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
priority = int(count) + 1
|
||||
} else {
|
||||
priority = *cfg.Priority
|
||||
}
|
||||
info = &ai.Provider{
|
||||
UUID: id,
|
||||
Name: *cfg.Name,
|
||||
@@ -42,6 +61,7 @@ func (i *imlProviderService) Save(ctx context.Context, id string, cfg *SetProvid
|
||||
Status: status,
|
||||
Creator: userId,
|
||||
Updater: userId,
|
||||
Priority: priority,
|
||||
CreateAt: now,
|
||||
UpdateAt: now,
|
||||
}
|
||||
@@ -58,6 +78,9 @@ func (i *imlProviderService) Save(ctx context.Context, id string, cfg *SetProvid
|
||||
if cfg.Status != nil {
|
||||
info.Status = *cfg.Status
|
||||
}
|
||||
if cfg.Priority != nil {
|
||||
info.Priority = *cfg.Priority
|
||||
}
|
||||
info.Updater = userId
|
||||
info.UpdateAt = now
|
||||
}
|
||||
|
||||
+7
-3
@@ -2,8 +2,9 @@ package ai
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"github.com/APIParkLab/APIPark/stores/ai"
|
||||
"time"
|
||||
|
||||
"github.com/APIParkLab/APIPark/stores/ai"
|
||||
)
|
||||
|
||||
type Provider struct {
|
||||
@@ -13,7 +14,8 @@ type Provider struct {
|
||||
Config string
|
||||
Creator string
|
||||
Updater string
|
||||
Status bool
|
||||
Status int
|
||||
Priority int
|
||||
CreateAt time.Time
|
||||
UpdateAt time.Time
|
||||
}
|
||||
@@ -22,7 +24,8 @@ type SetProvider struct {
|
||||
Name *string
|
||||
DefaultLLM *string
|
||||
Config *string
|
||||
Status *bool
|
||||
Status *int
|
||||
Priority *int
|
||||
}
|
||||
|
||||
func FromEntity(e *ai.Provider) *Provider {
|
||||
@@ -40,5 +43,6 @@ func FromEntity(e *ai.Provider) *Provider {
|
||||
CreateAt: e.CreateAt,
|
||||
UpdateAt: e.UpdateAt,
|
||||
Status: e.Status,
|
||||
Priority: e.Priority,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,14 +2,16 @@ package ai
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
|
||||
"github.com/APIParkLab/APIPark/service/universally"
|
||||
"github.com/eolinker/go-common/autowire"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type IProviderService interface {
|
||||
universally.IServiceGet[Provider]
|
||||
Save(ctx context.Context, id string, cfg *SetProvider) error
|
||||
MaxPriority(ctx context.Context) (int, error)
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
package access_log
|
||||
|
||||
import "time"
|
||||
|
||||
type Log struct {
|
||||
Id int64 `gorm:"column:id;type:BIGINT(20);AUTO_INCREMENT;NOT NULL;comment:id;primary_key;comment:主键ID;"`
|
||||
UUID string `gorm:"type:varchar(36);not null;column:uuid;uniqueIndex:uuid;comment:UUID;"`
|
||||
Cluster string `gorm:"column:cluster;type:varchar(36);NOT NULL;comment:集群ID"`
|
||||
Node string `gorm:"column:node;type:varchar(36);NOT NULL;comment:节点ID"`
|
||||
Service string `gorm:"column:service;type:varchar(36);NOT NULL;comment:服务ID"`
|
||||
API string `gorm:"column:api;type:varchar(36);NOT NULL;comment:API ID"`
|
||||
Application string `gorm:"column:application;type:varchar(36);NOT NULL;comment:应用ID"`
|
||||
Auth string `gorm:"column:auth;type:varchar(36);NOT NULL;comment:认证ID"`
|
||||
Type string `gorm:"column:type;type:varchar(36);NOT NULL;comment:日志类型;index:idx_type"`
|
||||
Target string `gorm:"column:target;type:varchar(36);NOT NULL;comment:目标ID"`
|
||||
IP string `gorm:"column:ip;type:varchar(36);NOT NULL;comment:IP"`
|
||||
RequestPath string `gorm:"column:request_path;type:varchar(255);NOT NULL;comment:请求路径"`
|
||||
Method string `gorm:"column:method;type:varchar(36);NOT NULL;comment:请求方法"`
|
||||
ResponseTime float64 `gorm:"column:response_time;type:float;NOT NULL;comment:响应时间"`
|
||||
StatusCode int64 `gorm:"column:status_code;type:BIGINT(20);NOT NULL;comment:响应状态码"`
|
||||
ReportTime time.Time `gorm:"column:report_time;type:timestamp;NOT NULL;comment:上报时间;index:idx_report_time"`
|
||||
}
|
||||
|
||||
func (c *Log) IdValue() int64 {
|
||||
return c.Id
|
||||
}
|
||||
|
||||
func (c *Log) TableName() string {
|
||||
return "access_log"
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package access_log
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/eolinker/go-common/autowire"
|
||||
"github.com/eolinker/go-common/store"
|
||||
)
|
||||
|
||||
type ILogStore interface {
|
||||
store.ISearchStore[Log]
|
||||
}
|
||||
|
||||
type imlLogStore struct {
|
||||
store.SearchStore[Log]
|
||||
}
|
||||
|
||||
func init() {
|
||||
autowire.Auto[ILogStore](func() reflect.Value {
|
||||
return reflect.ValueOf(new(imlLogStore))
|
||||
})
|
||||
}
|
||||
+47
-1
@@ -8,7 +8,8 @@ type Provider struct {
|
||||
Name string `gorm:"type:varchar(100);not null;column:name;comment:name"`
|
||||
DefaultLLM string `gorm:"type:varchar(255);not null;column:default_llm;comment:默认模型ID"`
|
||||
Config string `gorm:"type:text;not null;column:config;comment:配置信息"`
|
||||
Status bool `gorm:"type:tinyint(1);not null;column:status;comment:状态"`
|
||||
Status int `gorm:"type:tinyint(1);not null;column:status;comment:状态,0:停用;1:启用,2:异常"`
|
||||
Priority int `gorm:"type:int;not null;column:priority;comment:优先级,值越小优先级越高"`
|
||||
Creator string `gorm:"size:36;not null;column:creator;comment:创建人;index:creator" aovalue:"creator"` // 创建人
|
||||
Updater string `gorm:"size:36;not null;column:updater;comment:更新人;index:updater" aovalue:"updater"` // 更新人
|
||||
CreateAt time.Time `gorm:"type:timestamp;NOT NULL;DEFAULT:CURRENT_TIMESTAMP;column:create_at;comment:创建时间"`
|
||||
@@ -22,3 +23,48 @@ func (i *Provider) TableName() string {
|
||||
func (i *Provider) IdValue() int64 {
|
||||
return i.Id
|
||||
}
|
||||
|
||||
type LogMetrics struct {
|
||||
Id int64 `gorm:"column:id;type:BIGINT(20);AUTO_INCREMENT;NOT NULL;comment:id;primary_key;comment:主键ID;"`
|
||||
UUID string `gorm:"type:varchar(36);not null;column:uuid;uniqueIndex:uuid;comment:UUID;"`
|
||||
Provider string `gorm:"type:varchar(36);not null;column:provider;comment:供应商ID"`
|
||||
Model string `gorm:"type:varchar(36);not null;column:model;comment:模型ID"`
|
||||
InputToken int `gorm:"type:int;not null;column:input_token;comment:输入token"`
|
||||
OutputToken int `gorm:"type:int;not null;column:output_token;comment:输出token"`
|
||||
TotalToken int `gorm:"type:int;not null;column:total_token;comment:总token"`
|
||||
Cost float64 `gorm:"type:int;not null;column:cost;comment:费用"`
|
||||
Per float64 `gorm:"type:int;not null;column:per;comment:每个token的价格"`
|
||||
}
|
||||
|
||||
func (i *LogMetrics) TableName() string {
|
||||
return "ai_log_metrics"
|
||||
}
|
||||
|
||||
func (i *LogMetrics) IdValue() int64 {
|
||||
return i.Id
|
||||
}
|
||||
|
||||
type Key struct {
|
||||
Id int64 `gorm:"column:id;type:BIGINT(20);AUTO_INCREMENT;NOT NULL;comment:id;primary_key;comment:主键ID;"`
|
||||
Uuid string `gorm:"type:varchar(36);not null;column:uuid;uniqueIndex:uuid;comment:UUID;"`
|
||||
Name string `gorm:"type:varchar(100);not null;column:name;comment:名称"`
|
||||
Config string `gorm:"type:text;not null;column:config;comment:配置"`
|
||||
Provider string `gorm:"type:varchar(36);not null;column:provider;comment:供应商ID"`
|
||||
Status int `gorm:"type:tinyint(1);not null;column:status;comment:状态,0:停用;1:启用,2:错误;3:超额;4:过期"`
|
||||
ExpireTime int `gorm:"type:int;not null;column:expire_time;comment:过期时间"`
|
||||
UseToken int `gorm:"type:int;not null;column:use_token;comment:使用token数"`
|
||||
Sort int `gorm:"type:int;not null;column:sort;comment:排序"`
|
||||
Creator string `gorm:"size:36;not null;column:creator;comment:创建人;index:creator" aovalue:"creator"` // 创建人
|
||||
Updater string `gorm:"size:36;not null;column:updater;comment:更新人;index:updater" aovalue:"updater"` // 更新人
|
||||
CreateAt time.Time `gorm:"type:timestamp;NOT NULL;DEFAULT:CURRENT_TIMESTAMP;column:create_at;comment:创建时间"`
|
||||
UpdateAt time.Time `gorm:"type:timestamp;NOT NULL;DEFAULT:CURRENT_TIMESTAMP;column:update_at;comment:更新时间"`
|
||||
Default bool `gorm:"type:tinyint(1);not null;column:default;comment:是否默认"`
|
||||
}
|
||||
|
||||
func (i *Key) TableName() string {
|
||||
return "ai_key"
|
||||
}
|
||||
|
||||
func (i *Key) IdValue() int64 {
|
||||
return i.Id
|
||||
}
|
||||
|
||||
+26
-1
@@ -1,9 +1,10 @@
|
||||
package ai
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/eolinker/go-common/autowire"
|
||||
"github.com/eolinker/go-common/store"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type IProviderStore interface {
|
||||
@@ -14,8 +15,32 @@ type imlProviderStore struct {
|
||||
store.SearchStore[Provider]
|
||||
}
|
||||
|
||||
type ILogMetricsStore interface {
|
||||
store.ISearchStore[LogMetrics]
|
||||
}
|
||||
|
||||
type imlLogMetricsStore struct {
|
||||
store.SearchStore[LogMetrics]
|
||||
}
|
||||
|
||||
type IKeyStore interface {
|
||||
store.ISearchStore[Key]
|
||||
}
|
||||
|
||||
type imlKeyStore struct {
|
||||
store.SearchStore[Key]
|
||||
}
|
||||
|
||||
func init() {
|
||||
autowire.Auto[IProviderStore](func() reflect.Value {
|
||||
return reflect.ValueOf(new(imlProviderStore))
|
||||
})
|
||||
|
||||
autowire.Auto[ILogMetricsStore](func() reflect.Value {
|
||||
return reflect.ValueOf(new(imlLogMetricsStore))
|
||||
})
|
||||
|
||||
autowire.Auto[IKeyStore](func() reflect.Value {
|
||||
return reflect.ValueOf(new(imlKeyStore))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -79,6 +79,7 @@ type AiAPIInfo struct {
|
||||
Timeout int `gorm:"type:int(11);not null;column:timeout;comment:超时时间"`
|
||||
Retry int `gorm:"type:int(11);not null;column:retry;comment:重试次数"`
|
||||
Model string `gorm:"size:255;not null;column:model;comment:模型"`
|
||||
Provider string `gorm:"size:36;not null;column:provider;comment:提供者;index:provider"`
|
||||
Creator string `gorm:"size:36;not null;column:creator;comment:创建人;index:creator" aovalue:"creator"`
|
||||
CreateAt time.Time `gorm:"type:timestamp;NOT NULL;DEFAULT:CURRENT_TIMESTAMP;column:create_at;comment:创建时间"`
|
||||
Updater string `gorm:"size:36;not null;column:updater;comment:更新人;index:updater" aovalue:"updater"`
|
||||
|
||||
Reference in New Issue
Block a user