local model first commit

This commit is contained in:
Liujian
2025-02-14 15:34:41 +08:00
parent 88d4c5101e
commit 2ff7458c4e
47 changed files with 66868 additions and 266 deletions
+1
View File
@@ -27,6 +27,7 @@ type AiModel struct {
Id string `json:"id"`
Config string `json:"config"`
Provider string `json:"provider"`
Type string `json:"type"`
}
type EditAPI struct {
+1 -6
View File
@@ -13,12 +13,7 @@ func genOpenAPI3Template(title string, description string) *openapi3.T {
Description: description,
Version: "beta",
}
//result.Tags = openapi3.Tags{
// {
// Name: title,
// Description: description,
// },
//}
result.Components = components
result.Paths = new(openapi3.Paths)
return result
+14
View File
@@ -0,0 +1,14 @@
package ai_balance_dto
type Create struct {
Id string `json:"id"`
Type string `json:"type"`
Provider string `json:"provider"`
Model string `json:"model"`
}
type Sort struct {
Origin string `json:"origin"`
Target string `json:"target"`
Sort string `json:"sort"`
}
+81
View File
@@ -0,0 +1,81 @@
package ai_balance_dto
const (
ModelTypeOnline = "online"
ModelTypeLocal = "local"
StateNormal = "normal"
StateAbnormal = "abnormal"
)
type ModelType string
func (m ModelType) String() string {
return string(m)
}
func (m ModelType) Int() int {
switch m {
case ModelTypeOnline:
return 0
case ModelTypeLocal:
return 1
default:
return -1
}
}
func ModelTypeFromInt(i int) ModelType {
switch i {
case 0:
return ModelTypeOnline
case 1:
return ModelTypeLocal
default:
return "unknown"
}
}
type ModelState string
func (m ModelState) String() string {
return string(m)
}
func (m ModelState) Int() int {
switch m {
case StateNormal:
return 1
case StateAbnormal:
return 0
default:
return -1
}
}
func ModelStateFromInt(i int) ModelState {
switch i {
case 1:
return StateNormal
case 0:
return StateAbnormal
default:
return "unknown"
}
}
type Item struct {
Id string `json:"id"`
Priority int `json:"priority"`
Provider *BasicItem `json:"provider"`
Model *BasicItem `json:"model"`
Type ModelType `json:"type"`
State ModelState `json:"state"`
APICount int64 `json:"api_count"`
KeyCount int64 `json:"key_count"`
}
type BasicItem struct {
Id string `json:"id"`
Name string `json:"name"`
}
+160
View File
@@ -0,0 +1,160 @@
package ai_balance
import (
"context"
"fmt"
"sort"
ai_key "github.com/APIParkLab/APIPark/service/ai-key"
ai_api "github.com/APIParkLab/APIPark/service/ai-api"
"github.com/google/uuid"
ai_balance "github.com/APIParkLab/APIPark/service/ai-balance"
"github.com/eolinker/go-common/store"
"github.com/APIParkLab/APIPark/gateway"
"github.com/APIParkLab/APIPark/service/cluster"
ai_balance_dto "github.com/APIParkLab/APIPark/module/ai-balance/dto"
"github.com/eolinker/eosc/log"
)
var _ IBalanceModule = (*imlBalanceModule)(nil)
type imlBalanceModule struct {
clusterService cluster.IClusterService `autowired:""`
aiAPIService ai_api.IAPIService `autowired:""`
aiKeyService ai_key.IKeyService `autowired:""`
balanceService ai_balance.IBalanceService `autowired:""`
transaction store.ITransaction `autowired:""`
}
func (i *imlBalanceModule) Create(ctx context.Context, input *ai_balance_dto.Create) error {
priority, err := i.balanceService.MaxPriority(ctx)
if err != nil {
return err
}
if input.Id == "" {
input.Id = uuid.NewString()
}
providerName := ""
modelName := ""
// TODO: 名称进行优化
switch input.Type {
case ai_balance_dto.ModelTypeOnline:
case ai_balance_dto.ModelTypeLocal:
}
return i.balanceService.Create(ctx, &ai_balance.Create{
Id: input.Id,
Priority: priority + 1,
Provider: input.Provider,
ProviderName: providerName,
Model: input.Model,
ModelName: modelName,
Type: ai_balance_dto.ModelType(input.Type).Int(),
})
}
func newRelease(item *ai_balance.Balance) *gateway.DynamicRelease {
return &gateway.DynamicRelease{}
}
func (i *imlBalanceModule) Sort(ctx context.Context, input *ai_balance_dto.Sort) error {
var list []*ai_balance.Balance
var err error
switch input.Sort {
case "after":
list, err = i.balanceService.SortAfter(ctx, input.Origin, input.Target)
default:
list, err = i.balanceService.SortBefore(ctx, input.Origin, input.Target)
}
if err != nil {
return err
}
for _, item := range list {
err = i.syncGateway(ctx, cluster.DefaultClusterID, []*gateway.DynamicRelease{newRelease(item)}, true)
if err != nil {
return err
}
}
return nil
}
func (i *imlBalanceModule) List(ctx context.Context) ([]*ai_balance_dto.Item, error) {
list, err := i.balanceService.List(ctx)
if err != nil {
return nil, err
}
sort.Slice(list, func(i, j int) bool {
return list[i].Priority < list[j].Priority
})
aiAPIMap, err := i.aiAPIService.CountMapByProvider(ctx, "", nil)
if err != nil {
return nil, fmt.Errorf("get ai api count error:%v", err)
}
keyMap, err := i.aiKeyService.CountMapByProvider(ctx, "", nil)
if err != nil {
return nil, fmt.Errorf("get ai key count error:%v", err)
}
result := make([]*ai_balance_dto.Item, 0, len(list))
for i, item := range list {
priority := i + 1
result = append(result, &ai_balance_dto.Item{
Id: item.Id,
Provider: &ai_balance_dto.BasicItem{
Id: item.Provider,
Name: item.ProviderName,
},
Model: &ai_balance_dto.BasicItem{
Id: item.Model,
Name: item.ModelName,
},
Priority: priority,
Type: ai_balance_dto.ModelTypeFromInt(item.Type),
State: ai_balance_dto.ModelStateFromInt(item.State),
APICount: aiAPIMap[item.Model],
KeyCount: keyMap[item.Provider],
})
}
return result, nil
}
func (i *imlBalanceModule) Delete(ctx context.Context, id string) error {
return i.balanceService.Delete(ctx, id)
}
func (i *imlBalanceModule) syncGateway(ctx context.Context, clusterId string, releases []*gateway.DynamicRelease, online bool) error {
return nil
client, err := i.clusterService.GatewayClient(ctx, clusterId)
if err != nil {
log.Errorf("get apinto client error: %v", err)
return nil
}
defer func() {
err := client.Close(ctx)
if err != nil {
log.Warn("close apinto client:", err)
}
}()
for _, releaseInfo := range releases {
dynamicClient, err := client.Dynamic(releaseInfo.Resource)
if err != nil {
return err
}
if online {
err = dynamicClient.Online(ctx, releaseInfo)
} else {
dynamicClient.Offline(ctx, releaseInfo)
}
if err != nil {
return err
}
}
return nil
}
+23
View File
@@ -0,0 +1,23 @@
package ai_balance
import (
"context"
"reflect"
"github.com/eolinker/go-common/autowire"
ai_balance_dto "github.com/APIParkLab/APIPark/module/ai-balance/dto"
)
type IBalanceModule interface {
Create(ctx context.Context, input *ai_balance_dto.Create) error
Sort(ctx context.Context, input *ai_balance_dto.Sort) error
List(ctx context.Context) ([]*ai_balance_dto.Item, error)
Delete(ctx context.Context, id string) error
}
func init() {
autowire.Auto[IBalanceModule](func() reflect.Value {
return reflect.ValueOf(new(imlBalanceModule))
})
}
+14
View File
@@ -0,0 +1,14 @@
package ai_local_dto
type Update struct {
Disable bool `json:"disable"`
}
type CancelDeploy struct {
Model string `json:"model"`
}
type DeployInput struct {
Model string `json:"model"`
Team string `json:"team"`
}
+128
View File
@@ -0,0 +1,128 @@
package ai_local_dto
import "github.com/eolinker/go-common/auto"
type LocalModelState string
const (
LocalModelStateNormal LocalModelState = "normal"
LocalModelStateDisable LocalModelState = "disabled"
LocalModelStateDeployingError LocalModelState = "deploying_error"
LocalModelStateError LocalModelState = "error"
LocalModelStateDeploying LocalModelState = "deploying"
DeployStateDownload DeployState = "download"
DeployStateDeploy DeployState = "deploy"
DeployStateInitializing DeployState = "initializing"
DeployStateFinish DeployState = "finish"
DeployStateDownloadError DeployState = "download error"
DeployStateDeployError DeployState = "deploy error"
DeployStateInitializingError DeployState = "initializing error"
)
func (l LocalModelState) String() string {
return string(l)
}
func (l LocalModelState) Int() int {
switch l {
case LocalModelStateDisable:
return 0
case LocalModelStateNormal:
return 1
case LocalModelStateError:
return 2
case LocalModelStateDeploying:
return 3
case LocalModelStateDeployingError:
return 4
default:
return 0
}
}
func FromLocalModelState(state int) LocalModelState {
switch state {
case 0:
return LocalModelStateDisable
case 1:
return LocalModelStateNormal
case 2:
return LocalModelStateError
case 3:
return LocalModelStateDeploying
case 4:
return LocalModelStateDeployingError
default:
return LocalModelStateDisable
}
}
type LocalModelItem struct {
Id string `json:"id"`
Name string `json:"name"`
State LocalModelState `json:"state"`
APICount int64 `json:"api_count"`
UpdateTime auto.TimeLabel `json:"update_time"`
}
type LocalModelPackageItem struct {
Id string `json:"id"`
Name string `json:"name"`
Size string `json:"size"`
IsPopular bool `json:"is_popular"`
}
type DeployState string
func (d DeployState) String() string {
return string(d)
}
func (d DeployState) Int() int {
switch d {
case DeployStateDownload:
return 1
case DeployStateDeploy:
return 2
case DeployStateInitializing:
return 3
case DeployStateFinish:
return 4
case DeployStateDownloadError:
return 5
case DeployStateDeployError:
return 6
case DeployStateInitializingError:
return 7
default:
return 1
}
}
func FromDeployState(state int) DeployState {
switch state {
case 1:
return DeployStateDownload
case 2:
return DeployStateDeploy
case 3:
return DeployStateInitializing
case 4:
return DeployStateFinish
case 5:
return DeployStateDownloadError
case 6:
return DeployStateDeployError
case 7:
return DeployStateInitializingError
default:
return DeployStateDownload
}
}
type ModelInfo struct {
Current int64 `json:"current"`
Total int64 `json:"total"`
LastMessage string `json:"last_message"`
}
+297
View File
@@ -0,0 +1,297 @@
package ai_local
import (
"context"
"errors"
"fmt"
"strings"
"github.com/eolinker/go-common/auto"
ai_api "github.com/APIParkLab/APIPark/service/ai-api"
"github.com/eolinker/go-common/register"
"github.com/eolinker/go-common/server"
"github.com/eolinker/go-common/utils"
"gorm.io/gorm"
ai_local "github.com/APIParkLab/APIPark/service/ai-local"
"github.com/eolinker/go-common/store"
ai_provider_local "github.com/APIParkLab/APIPark/ai-provider/local"
ai_local_dto "github.com/APIParkLab/APIPark/module/ai-local/dto"
)
var (
_ ILocalModelModule = (*imlLocalModel)(nil)
)
type imlLocalModel struct {
localModelService ai_local.ILocalModelService `autowired:""`
localModelPackageService ai_local.ILocalModelPackageService `autowired:""`
localModelStateService ai_local.ILocalModelInstallStateService `autowired:""`
aiAPIService ai_api.IAPIService `autowired:""`
transaction store.ITransaction `autowired:""`
}
func (i *imlLocalModel) ModelState(ctx context.Context, model string) (*ai_local_dto.DeployState, *ai_local_dto.ModelInfo, error) {
info, err := i.localModelStateService.Get(ctx, model)
if err != nil {
return nil, nil, err
}
state := ai_local_dto.FromDeployState(info.State)
return &state, &ai_local_dto.ModelInfo{
Current: info.Complete,
Total: info.Total,
LastMessage: info.Msg,
}, nil
}
func (i *imlLocalModel) Search(ctx context.Context, keyword string) ([]*ai_local_dto.LocalModelItem, error) {
list, err := i.localModelService.Search(ctx, keyword, nil, "update_at desc")
if err != nil {
return nil, err
}
apiCountMap, err := i.aiAPIService.CountMapByModel(ctx, "", map[string]interface{}{
"type": 1,
})
if err != nil {
return nil, err
}
return utils.SliceToSlice(list, func(s *ai_local.LocalModel) *ai_local_dto.LocalModelItem {
return &ai_local_dto.LocalModelItem{
Id: s.Id,
Name: s.Name,
State: ai_local_dto.FromLocalModelState(s.State),
APICount: apiCountMap[s.Id],
UpdateTime: auto.TimeLabel(s.UpdateAt),
}
}), nil
}
func (i *imlLocalModel) ListCanInstall(ctx context.Context, keyword string) ([]*ai_local_dto.LocalModelPackageItem, error) {
list, err := i.localModelPackageService.Search(ctx, keyword, nil)
if err != nil {
return nil, err
}
if keyword != "" {
result := make([]*ai_local_dto.LocalModelPackageItem, 0)
for _, v := range list {
models := ai_provider_local.ModelsCanInstallById(v.Id)
for _, model := range models {
result = append(result, &ai_local_dto.LocalModelPackageItem{
Id: model.Id,
Name: model.Name,
Size: model.Size,
IsPopular: model.IsPopular,
})
}
}
return result, nil
}
return utils.SliceToSlice(list, func(s *ai_local.LocalModelPackage) *ai_local_dto.LocalModelPackageItem {
return &ai_local_dto.LocalModelPackageItem{
Id: s.Id,
Name: s.Name,
Size: s.Size,
IsPopular: s.IsPopular,
}
}), nil
}
func (i *imlLocalModel) pullHook() func(msg ai_provider_local.PullMessage) error {
return func(msg ai_provider_local.PullMessage) error {
return i.transaction.Transaction(context.Background(), func(ctx context.Context) error {
state := ai_local_dto.DeployStateFinish.Int()
modelState := ai_local_dto.LocalModelStateNormal.Int()
if msg.Status == "error" {
state = ai_local_dto.DeployStateDownloadError.Int()
modelState = ai_local_dto.LocalModelStateDeployingError.Int()
}
err := i.localModelService.Save(ctx, msg.Model, &ai_local.EditLocalModel{State: &modelState})
if err != nil {
return err
}
info, err := i.localModelStateService.Get(ctx, msg.Model)
if err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) {
return err
}
return i.localModelStateService.Create(ctx, &ai_local.CreateLocalModelInstallState{
Id: msg.Model,
Complete: msg.Completed,
Total: msg.Total,
State: state,
Msg: msg.Msg,
})
}
if info.Complete < msg.Completed {
info.Complete = msg.Completed
}
if info.Total < msg.Total {
info.Total = msg.Total
}
if msg.Msg != "" {
info.Msg = msg.Msg
}
return i.localModelStateService.Save(ctx, msg.Model, &ai_local.EditLocalModelInstallState{State: &state, Complete: &info.Complete, Total: &info.Total, Msg: &info.Msg})
})
}
}
func (i *imlLocalModel) Deploy(ctx context.Context, model string, session string) (*ai_provider_local.Pipeline, error) {
var p *ai_provider_local.Pipeline
err := i.transaction.Transaction(ctx, func(txCtx context.Context) error {
_, err := i.localModelService.Get(ctx, model)
if err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) {
return err
}
names := strings.Split(model, ":")
err = i.localModelService.Create(ctx, &ai_local.CreateLocalModel{
Id: model,
Name: model,
Provider: names[0],
})
} else {
state := ai_local_dto.LocalModelStateDeploying.Int()
err = i.localModelService.Save(ctx, model, &ai_local.EditLocalModel{State: &state})
}
if err != nil {
return err
}
p, err = ai_provider_local.PullModel(model, session, i.pullHook())
if err != nil {
return err
}
return nil
})
if err != nil {
return nil, err
}
return p, nil
}
func (i *imlLocalModel) CancelDeploy(ctx context.Context, model string) error {
ai_provider_local.StopPull(model)
// 删除模型
return i.localModelService.Delete(ctx, model)
}
func (i *imlLocalModel) RemoveModel(ctx context.Context, model string) error {
err := ai_provider_local.RemoveModel(model)
if err != nil {
return err
}
return i.localModelService.Delete(ctx, model)
}
func (i *imlLocalModel) Enable(ctx context.Context, model string) error {
info, err := i.localModelService.Get(ctx, model)
if err != nil {
return err
}
if info.State == ai_local_dto.LocalModelStateDisable.Int() || info.State == ai_local_dto.LocalModelStateError.Int() {
status := ai_local_dto.LocalModelStateNormal.Int()
return i.localModelService.Save(ctx, model, &ai_local.EditLocalModel{State: &status})
}
return fmt.Errorf("model %s is not disabled state,can not enable", model)
}
func (i *imlLocalModel) Disable(ctx context.Context, model string) error {
info, err := i.localModelService.Get(ctx, model)
if err != nil {
return err
}
if info.State == ai_local_dto.LocalModelStateNormal.Int() {
disable := ai_local_dto.LocalModelStateDisable.Int()
return i.localModelService.Save(ctx, model, &ai_local.EditLocalModel{State: &disable})
}
return fmt.Errorf("model %s is not enabled state,can not disable", model)
}
func (i *imlLocalModel) OnInit() {
register.Handle(func(v server.Server) {
ctx := context.Background()
list, err := i.localModelPackageService.List(ctx)
if err != nil {
return
}
oldModels := utils.SliceToMapO(list, func(s *ai_local.LocalModelPackage) (string, *ai_local.LocalModelPackage) {
return s.Id, s
})
models, version := ai_provider_local.ModelsCanInstall()
for _, model := range models {
if v, ok := oldModels[model.Id]; ok {
if v.Version == version {
continue
}
err = i.localModelPackageService.Save(ctx, model.Id, &ai_local.EditLocalModelPackage{
Size: &model.Size,
Hash: &model.Digest,
Description: &model.Description,
Version: &version,
Popular: &model.IsPopular,
})
if err != nil {
return
}
} else {
err = i.localModelPackageService.Create(ctx, &ai_local.CreateLocalModelPackage{
Id: model.Id,
Name: model.Name,
Size: model.Size,
Hash: model.Digest,
Description: model.Description,
Version: version,
Popular: model.IsPopular,
})
if err != nil {
return
}
}
delete(oldModels, model.Id)
}
for id := range oldModels {
err = i.localModelPackageService.Delete(ctx, id)
if err != nil {
return
}
}
installModels, err := ai_provider_local.ModelsInstalled()
if err != nil {
return
}
for _, model := range installModels {
id := strings.TrimSuffix(model.Name, ":latest")
name := strings.TrimSuffix(model.Name, ":latest")
_, err = i.localModelService.Get(ctx, id)
if err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) {
return
}
err = i.localModelService.Create(ctx, &ai_local.CreateLocalModel{
Id: id,
Name: name,
State: 1,
})
if err != nil {
return
}
}
}
})
}
+29
View File
@@ -0,0 +1,29 @@
package ai_local
import (
"context"
"reflect"
"github.com/eolinker/go-common/autowire"
ai_provider_local "github.com/APIParkLab/APIPark/ai-provider/local"
ai_local_dto "github.com/APIParkLab/APIPark/module/ai-local/dto"
)
type ILocalModelModule interface {
Search(ctx context.Context, keyword string) ([]*ai_local_dto.LocalModelItem, error)
ListCanInstall(ctx context.Context, keyword string) ([]*ai_local_dto.LocalModelPackageItem, error)
Deploy(ctx context.Context, model string, session string) (*ai_provider_local.Pipeline, error)
CancelDeploy(ctx context.Context, model string) error
RemoveModel(ctx context.Context, model string) error
Enable(ctx context.Context, model string) error
Disable(ctx context.Context, model string) error
ModelState(ctx context.Context, model string) (*ai_local_dto.DeployState, *ai_local_dto.ModelInfo, error)
}
func init() {
autowire.Auto[ILocalModelModule](func() reflect.Value {
return reflect.ValueOf(&imlLocalModel{})
})
}
+11 -12
View File
@@ -13,15 +13,15 @@ type SimpleProvider struct {
}
type Provider struct {
Id string `json:"id"`
Name string `json:"name"`
Config string `json:"config"`
GetAPIKeyUrl string `json:"get_apikey_url"`
DefaultLLM string `json:"default_llm"`
DefaultLLMConfig string `json:"-"`
Priority int `json:"priority"`
Status ProviderStatus `json:"status"`
Configured bool `json:"configured"`
Id string `json:"id"`
Name string `json:"name"`
Config string `json:"config"`
GetAPIKeyUrl string `json:"get_apikey_url"`
DefaultLLM string `json:"default_llm"`
DefaultLLMConfig string `json:"-"`
//Priority int `json:"priority"`
Status ProviderStatus `json:"status"`
Configured bool `json:"configured"`
}
type ConfiguredProviderItem struct {
@@ -31,9 +31,8 @@ type ConfiguredProviderItem struct {
DefaultLLM string `json:"default_llm"`
Status ProviderStatus `json:"status"`
APICount int64 `json:"api_count"`
KeyCount int `json:"key_count"`
KeyStatus []*KeyStatus `json:"keys"`
Priority int `json:"priority"`
KeyCount int64 `json:"key_count"`
CanDelete bool `json:"can_delete"`
}
type KeyStatus struct {
+104 -143
View File
@@ -8,9 +8,9 @@ import (
"sort"
"time"
"github.com/APIParkLab/APIPark/service/service"
ai_balance "github.com/APIParkLab/APIPark/service/ai-balance"
ai_key_dto "github.com/APIParkLab/APIPark/module/ai-key/dto"
"github.com/APIParkLab/APIPark/service/service"
ai_key "github.com/APIParkLab/APIPark/service/ai-key"
@@ -54,11 +54,19 @@ func newKey(key *ai_key.Key) *gateway.DynamicRelease {
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:""`
providerService ai.IProviderService `autowired:""`
clusterService cluster.IClusterService `autowired:""`
aiAPIService ai_api.IAPIService `autowired:""`
aiKeyService ai_key.IKeyService `autowired:""`
aiBalanceService ai_balance.IBalanceService `autowired:""`
transaction store.ITransaction `autowired:""`
}
func (i *imlProviderModule) Delete(ctx context.Context, id string) error {
return i.transaction.Transaction(ctx, func(txCtx context.Context) error {
// TODO: implement Delete
return nil
})
}
func (i *imlProviderModule) SimpleProvider(ctx context.Context, id string) (*ai_dto.SimpleProvider, error) {
@@ -75,83 +83,87 @@ func (i *imlProviderModule) SimpleProvider(ctx context.Context, id string) (*ai_
}, nil
}
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
})
releases := make([]*gateway.DynamicRelease, 0, len(list))
offlineReleases := make([]*gateway.DynamicRelease, 0, len(list))
for index, id := range input.Providers {
p, has := model_runtime.GetProvider(id)
if !has {
continue
}
//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
// })
// releases := make([]*gateway.DynamicRelease, 0, len(list))
// offlineReleases := make([]*gateway.DynamicRelease, 0, len(list))
// for index, id := range input.Providers {
// p, has := model_runtime.GetProvider(id)
// if !has {
// continue
// }
//
// l, has := providerMap[id]
// if !has {
// continue
// }
// model, has := p.GetModel(l.DefaultLLM)
// if !has {
// continue
// }
// priority := index + 1
// err = i.providerService.Save(txCtx, id, &ai.SetProvider{
// Priority: &priority,
// })
// if err != nil {
// return err
// }
// if ai_dto.ToProviderStatus(l.Status) == ai_dto.ProviderDisabled {
// offlineReleases = append(offlineReleases, &gateway.DynamicRelease{
// BasicItem: &gateway.BasicItem{
// ID: l.Id,
// Resource: "ai-provider",
// }})
// } else {
// cfg := make(map[string]interface{})
// cfg["provider"] = l.Id
// cfg["model"] = l.DefaultLLM
// cfg["model_config"] = model.DefaultConfig()
// cfg["priority"] = l.Priority
// cfg["base"] = fmt.Sprintf("%s://%s", p.URI().Scheme(), p.URI().Host())
// releases = append(releases, &gateway.DynamicRelease{
// BasicItem: &gateway.BasicItem{
// ID: l.Id,
// Description: l.Name,
// Resource: "ai-provider",
// Version: l.UpdateAt.Format("20060102150405"),
// MatchLabels: map[string]string{
// "module": "ai-provider",
// },
// },
// Attr: cfg,
// })
// }
// }
// err = i.syncGateway(ctx, cluster.DefaultClusterID, releases, true)
// if err != nil {
// return err
// }
// return i.syncGateway(ctx, cluster.DefaultClusterID, offlineReleases, false)
//
// })
//}
l, has := providerMap[id]
if !has {
continue
}
model, has := p.GetModel(l.DefaultLLM)
if !has {
continue
}
priority := index + 1
err = i.providerService.Save(txCtx, id, &ai.SetProvider{
Priority: &priority,
})
if err != nil {
return err
}
if ai_dto.ToProviderStatus(l.Status) == ai_dto.ProviderDisabled {
offlineReleases = append(offlineReleases, &gateway.DynamicRelease{
BasicItem: &gateway.BasicItem{
ID: l.Id,
Resource: "ai-provider",
}})
} else {
cfg := make(map[string]interface{})
cfg["provider"] = l.Id
cfg["model"] = l.DefaultLLM
cfg["model_config"] = model.DefaultConfig()
cfg["priority"] = l.Priority
cfg["base"] = fmt.Sprintf("%s://%s", p.URI().Scheme(), p.URI().Host())
releases = append(releases, &gateway.DynamicRelease{
BasicItem: &gateway.BasicItem{
ID: l.Id,
Description: l.Name,
Resource: "ai-provider",
Version: l.UpdateAt.Format("20060102150405"),
MatchLabels: map[string]string{
"module": "ai-provider",
},
},
Attr: cfg,
})
}
}
err = i.syncGateway(ctx, cluster.DefaultClusterID, releases, true)
if err != nil {
return err
}
return i.syncGateway(ctx, cluster.DefaultClusterID, offlineReleases, false)
})
}
func (i *imlProviderModule) ConfiguredProviders(ctx context.Context) ([]*ai_dto.ConfiguredProviderItem, *ai_dto.BackupProvider, error) {
func (i *imlProviderModule) ConfiguredProviders(ctx context.Context, keyword string) ([]*ai_dto.ConfiguredProviderItem, error) {
// 获取已配置的AI服务商
list, err := i.providerService.List(ctx)
list, err := i.providerService.Search(ctx, keyword, nil, "update_at")
if err != nil {
return nil, nil, fmt.Errorf("get provider list error:%v", err)
return 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)
return nil, fmt.Errorf("get ai api count error:%v", err)
}
keyMap, err := i.aiKeyService.CountMapByProvider(ctx, "", nil)
if err != nil {
return nil, fmt.Errorf("get ai key count error:%v", err)
}
providers := make([]*ai_dto.ConfiguredProviderItem, 0, len(list))
for _, l := range list {
@@ -159,7 +171,7 @@ func (i *imlProviderModule) ConfiguredProviders(ctx context.Context) ([]*ai_dto.
_, err = i.aiKeyService.DefaultKey(ctx, l.Id)
if err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) {
return nil, nil, err
return nil, err
}
err = i.aiKeyService.Create(ctx, &ai_key.Create{
ID: l.Id,
@@ -173,7 +185,7 @@ func (i *imlProviderModule) ConfiguredProviders(ctx context.Context) ([]*ai_dto.
Default: true,
})
if err != nil {
return nil, nil, fmt.Errorf("create default key error:%v", err)
return nil, fmt.Errorf("create default key error:%v", err)
}
}
@@ -181,29 +193,6 @@ func (i *imlProviderModule) ConfiguredProviders(ctx context.Context) ([]*ai_dto.
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([]*ai_dto.KeyStatus, 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, &ai_dto.KeyStatus{
Id: k.ID,
Name: k.Name,
Status: status.String(),
Priority: k.Priority,
})
}
sort.Slice(keysStatus, func(i, j int) bool {
return keysStatus[i].Priority < keysStatus[j].Priority
})
providers = append(providers, &ai_dto.ConfiguredProviderItem{
Id: l.Id,
@@ -212,34 +201,12 @@ func (i *imlProviderModule) ConfiguredProviders(ctx context.Context) ([]*ai_dto.
DefaultLLM: l.DefaultLLM,
Status: ai_dto.ToProviderStatus(l.Status),
APICount: aiAPIMap[l.Id],
KeyCount: len(keysStatus),
KeyStatus: keysStatus,
Priority: l.Priority,
KeyCount: keyMap[l.Id],
CanDelete: len(list) > 1,
})
}
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 *ai_dto.BackupProvider
for _, p := range providers {
if p.Status == ai_dto.ProviderEnabled {
backup = &ai_dto.BackupProvider{
Id: p.Id,
Name: p.Name,
}
break
}
}
return providers, backup, nil
return providers, nil
}
func (i *imlProviderModule) SimpleProviders(ctx context.Context) ([]*ai_dto.SimpleProviderItem, error) {
@@ -388,13 +355,7 @@ 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) {
@@ -412,7 +373,7 @@ func (i *imlProviderModule) Provider(ctx context.Context, id string) (*ai_dto.Pr
DefaultLLM: defaultLLM.ID(),
DefaultLLMConfig: defaultLLM.Logo(),
Status: ai_dto.ProviderDisabled,
Priority: maxPriority,
//Priority: maxPriority,
}, nil
}
defaultLLM, has := p.GetModel(info.DefaultLLM)
@@ -423,9 +384,9 @@ func (i *imlProviderModule) Provider(ctx context.Context, id string) (*ai_dto.Pr
}
defaultLLM = model
}
if info.Priority == 0 {
info.Priority = maxPriority
}
//if info.Priority == 0 {
// info.Priority = maxPriority
//}
return &ai_dto.Provider{
Id: info.Id,
@@ -434,9 +395,9 @@ 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.ToProviderStatus(info.Status),
Configured: true,
//Priority: info.Priority,
Status: ai_dto.ToProviderStatus(info.Status),
Configured: true,
}, nil
}
+5 -4
View File
@@ -10,23 +10,24 @@ import (
)
type IProviderModule interface {
ConfiguredProviders(ctx context.Context) ([]*ai_dto.ConfiguredProviderItem, *ai_dto.BackupProvider, error)
ConfiguredProviders(ctx context.Context, keyword string) ([]*ai_dto.ConfiguredProviderItem, error)
UnConfiguredProviders(ctx context.Context) ([]*ai_dto.ProviderItem, error)
SimpleProviders(ctx context.Context) ([]*ai_dto.SimpleProviderItem, error)
SimpleConfiguredProviders(ctx context.Context) ([]*ai_dto.SimpleProviderItem, *ai_dto.BackupProvider, error)
Provider(ctx context.Context, id string) (*ai_dto.Provider, error)
SimpleProvider(ctx context.Context, id string) (*ai_dto.SimpleProvider, error)
LLMs(ctx context.Context, driver string) ([]*ai_dto.LLMItem, *ai_dto.ProviderItem, error)
//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
Delete(ctx context.Context, id string) error
}
type IAIAPIModule interface {
APIs(ctx context.Context, keyword string, providerId string, start int64, end int64, page int, pageSize int, sortCondition string, asc bool, models []string, services []string) ([]*ai_dto.APIItem, *ai_dto.Condition, int64, error)
}
type ILocalModelModule interface {
}
func init() {
autowire.Auto[IProviderModule](func() reflect.Value {
module := new(imlProviderModule)
+3 -1
View File
@@ -2,9 +2,10 @@ package catalogue
import (
"context"
"github.com/APIParkLab/APIPark/module/system"
"reflect"
"github.com/APIParkLab/APIPark/module/system"
"github.com/eolinker/go-common/autowire"
catalogue_dto "github.com/APIParkLab/APIPark/module/catalogue/dto"
@@ -28,6 +29,7 @@ type ICatalogueModule interface {
// Subscribe 订阅服务
Subscribe(ctx context.Context, subscribeInfo *catalogue_dto.SubscribeService) error
Sort(ctx context.Context, sorts []*catalogue_dto.SortItem) error
DefaultCatalogue(ctx context.Context) (*catalogue_dto.Catalogue, error)
//ExportAll(ctx context.Context) ([]*catalogue_dto.ExportCatalogue, error)
}
+18
View File
@@ -66,6 +66,24 @@ type imlCatalogueModule struct {
root *Root
}
func (i *imlCatalogueModule) DefaultCatalogue(ctx context.Context) (*catalogue_dto.Catalogue, error) {
catalogues, err := i.catalogueService.List(ctx)
if err != nil {
return nil, err
}
for _, v := range catalogues {
if v.Parent == "" {
return &catalogue_dto.Catalogue{
Id: v.Id,
Name: v.Name,
Parent: v.Parent,
Sort: v.Sort,
}, nil
}
}
return nil, errors.New("no default catalogue")
}
func (i *imlCatalogueModule) onlineSubscriber(ctx context.Context, clusterId string, sub *gateway.SubscribeRelease) error {
client, err := i.clusterService.GatewayClient(ctx, clusterId)
if err != nil {
+2
View File
@@ -11,6 +11,7 @@ type CreateService struct {
Catalogue string `json:"catalogue"`
ApprovalType string `json:"approval_type"`
Kind string `json:"service_kind"`
State string `json:"state"`
Provider *string `json:"provider" aocheck:"ai_provider"`
AsApp *bool `json:"as_app"`
AsServer *bool `json:"as_server"`
@@ -25,6 +26,7 @@ type EditService struct {
Tags *[]string `json:"tags"`
Provider *string `json:"provider" aocheck:"ai_provider"`
ApprovalType *string `json:"approval_type"`
State *string `json:"state"`
}
type CreateApp struct {
+1
View File
@@ -62,6 +62,7 @@ type Service struct {
AsServer bool `json:"as_server"`
AsApp bool `json:"as_app"`
ServiceKind string `json:"service_kind"`
State string `json:"state"`
}
type App struct {