From 72436849778665b858cce46aa2ee2a100236587f Mon Sep 17 00:00:00 2001 From: Liujian <824010343@qq.com> Date: Mon, 17 Feb 2025 00:37:25 +0800 Subject: [PATCH] fix: ai deploy bug --- controller/ai-local/iml.go | 37 ++++++------- module/ai-local/iml.go | 102 +++++++++++++++++++++++++++-------- module/ai-local/module.go | 1 + module/service/dto/output.go | 2 +- module/service/iml.go | 1 + service/ai-api/iml.go | 8 +++ service/ai-api/service.go | 1 + service/ai-local/iml.go | 39 ++++++++++++++ service/ai-local/model.go | 34 ++++++++++++ service/ai-local/service.go | 11 ++++ service/api/iml.go | 7 +++ service/api/service.go | 1 + stores/ai/model.go | 15 ++++++ stores/ai/store.go | 12 +++++ 14 files changed, 227 insertions(+), 44 deletions(-) diff --git a/controller/ai-local/iml.go b/controller/ai-local/iml.go index 7f20520c..11ec8cf0 100644 --- a/controller/ai-local/iml.go +++ b/controller/ai-local/iml.go @@ -3,15 +3,12 @@ package ai_local import ( "context" "encoding/json" - "errors" "fmt" "io" "math" "net/http" "strings" - "gorm.io/gorm" - "github.com/APIParkLab/APIPark/module/router" "github.com/APIParkLab/APIPark/model/plugin_model" @@ -100,13 +97,13 @@ func (i *imlLocalModelController) Deploy(ctx *gin.Context) { return } - err = i.initAILocalService(ctx, input.Model, input.Team) - if err != nil { - ctx.JSON(200, gin.H{ - "code": -1, "msg": err.Error(), "success": "fail", - }) - return - } + //err = i.initAILocalService(ctx, input.Model, input.Team) + //if err != nil { + // ctx.JSON(200, gin.H{ + // "code": -1, "msg": err.Error(), "success": "fail", + // }) + // return + //} id := uuid.NewString() p, err := i.module.Deploy(ctx, input.Model, id) if err != nil { @@ -199,23 +196,15 @@ func (i *imlLocalModelController) DeployStart(ctx *gin.Context, input *ai_local_ func (i *imlLocalModelController) initAILocalService(ctx context.Context, model string, teamID string) error { err := i.transaction.Transaction(ctx, func(ctx context.Context) error { - _, err := i.serviceModule.Get(ctx, model) - if err == nil { - return nil - } else { - if !errors.Is(err, gorm.ErrRecordNotFound) { - return err - } - } catalogueInfo, err := i.catalogueModule.DefaultCatalogue(ctx) if err != nil { return err } - + serviceId := uuid.NewString() + prefix := fmt.Sprintf("/%s", serviceId[:8]) providerId := "ollama" - prefix := strings.Replace("/"+model, ":", "_", -1) info, err := i.serviceModule.Create(ctx, teamID, &service_dto.CreateService{ - Id: model, + Id: serviceId, Name: model, Prefix: prefix, Description: "Auto generated service for AI model " + model, @@ -229,6 +218,10 @@ func (i *imlLocalModelController) initAILocalService(ctx context.Context, model if err != nil { return err } + err = i.module.SaveCache(ctx, model, serviceId) + if err != nil { + return err + } path := fmt.Sprintf("/%s/chat", strings.Trim(prefix, "/")) timeout := 300000 retry := 0 @@ -244,7 +237,7 @@ func (i *imlLocalModelController) initAILocalService(ctx context.Context, model } name := "Demo AI API" description := "A demo that shows you how to use a e a Chat API." - apiId := uuid.New().String() + apiId := uuid.NewString() err = i.aiAPIModule.Create( ctx, info.Id, diff --git a/module/ai-local/iml.go b/module/ai-local/iml.go index c02a356f..55ddb380 100644 --- a/module/ai-local/iml.go +++ b/module/ai-local/iml.go @@ -7,6 +7,8 @@ import ( "net/url" "strings" + "github.com/APIParkLab/APIPark/service/api" + "github.com/eolinker/eosc/env" "github.com/APIParkLab/APIPark/gateway" @@ -43,8 +45,10 @@ type imlLocalModel struct { localModelService ai_local.ILocalModelService `autowired:""` localModelPackageService ai_local.ILocalModelPackageService `autowired:""` localModelStateService ai_local.ILocalModelInstallStateService `autowired:""` + localModelCacheService ai_local.ILocalModelCacheService `autowired:""` clusterService cluster.IClusterService `autowired:""` aiAPIService ai_api.IAPIService `autowired:""` + routerService api.IAPIService `autowired:""` serviceService service.IServiceService `autowired:""` transaction store.ITransaction `autowired:""` } @@ -181,7 +185,7 @@ func (i *imlLocalModel) pullHook() func(msg ai_provider_local.PullMessage) error State: state, Msg: msg.Msg, }) - + info, err = i.localModelStateService.Get(ctx, msg.Model) } else { if info.Complete < msg.Completed { info.Complete = msg.Completed @@ -201,30 +205,54 @@ func (i *imlLocalModel) pullHook() func(msg ai_provider_local.PullMessage) error if msg.Status == "error" { state = 2 } - err = i.serviceService.Save(ctx, msg.Model, &service.Edit{State: &serviceState}) + list, err := i.localModelCacheService.List(ctx, msg.Model, ai_local.CacheTypeService) + if err != nil { + return err + } + for _, l := range list { + _, err := i.serviceService.Get(ctx, l.Target) + if err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + continue + } + return err + } + if info.State == 0 { + continue + } + err = i.serviceService.Save(ctx, l.Target, &service.Edit{State: &serviceState}) + if err != nil { + return err + } + } + } if err != nil { return err } - cfg := make(map[string]interface{}) - cfg["provider"] = "ollama" - cfg["model"] = msg.Model - cfg["model_config"] = ollamaConfig - cfg["priority"] = 0 - cfg["base"] = ollamaBase - return i.syncGateway(ctx, cluster.DefaultClusterID, []*gateway.DynamicRelease{ - { - BasicItem: &gateway.BasicItem{ - ID: msg.Model, - Description: msg.Model, - Resource: "ai-provider", - Version: info.UpdateAt.Format("20060102150405"), - MatchLabels: map[string]string{ - "module": "ai-provider", + if state == ai_local_dto.DeployStateFinish.Int() { + cfg := make(map[string]interface{}) + cfg["provider"] = "ollama" + cfg["model"] = msg.Model + cfg["model_config"] = ollamaConfig + cfg["priority"] = 0 + cfg["base"] = ollamaBase + + return i.syncGateway(ctx, cluster.DefaultClusterID, []*gateway.DynamicRelease{ + { + BasicItem: &gateway.BasicItem{ + ID: msg.Model, + Description: msg.Model, + Resource: "ai-provider", + Version: info.UpdateAt.Format("20060102150405"), + MatchLabels: map[string]string{ + "module": "ai-provider", + }, }, - }, - Attr: cfg, - }}, true) + Attr: cfg, + }}, true) + } + return nil }) } } @@ -294,9 +322,41 @@ func (i *imlLocalModel) Deploy(ctx context.Context, model string, session string return p, nil } +func (i *imlLocalModel) SaveCache(ctx context.Context, model string, target string) error { + return i.localModelCacheService.Save(ctx, model, ai_local.CacheTypeService, target) +} + func (i *imlLocalModel) CancelDeploy(ctx context.Context, model string) error { return i.transaction.Transaction(ctx, func(txCtx context.Context) error { - err := i.serviceService.ForceDelete(ctx, model) + list, err := i.localModelCacheService.List(ctx, model, ai_local.CacheTypeService) + if err != nil { + return err + } + for _, l := range list { + info, err := i.serviceService.Get(ctx, l.Target) + if err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + continue + } + return err + } + if info.State == 0 { + continue + } + err = i.serviceService.Delete(ctx, info.Id) + if err != nil { + return err + } + err = i.aiAPIService.DeleteByService(ctx, info.Id) + if err != nil { + return err + } + err = i.routerService.DeleteByService(ctx, info.Id) + if err != nil { + return err + } + } + err = i.localModelCacheService.Delete(ctx, model) if err != nil { return err } diff --git a/module/ai-local/module.go b/module/ai-local/module.go index a96172a0..58362d16 100644 --- a/module/ai-local/module.go +++ b/module/ai-local/module.go @@ -23,6 +23,7 @@ type ILocalModelModule interface { Disable(ctx context.Context, model string) error ModelState(ctx context.Context, model string) (*ai_local_dto.DeployState, *ai_local_dto.ModelInfo, error) SimpleList(ctx context.Context) ([]*ai_local_dto.SimpleItem, error) + SaveCache(ctx context.Context, model string, target string) error } func init() { diff --git a/module/service/dto/output.go b/module/service/dto/output.go index 3fadb202..016c1007 100644 --- a/module/service/dto/output.go +++ b/module/service/dto/output.go @@ -26,7 +26,7 @@ func (s ServiceState) Int() int { case ServiceStateDeployError: return 2 default: - return -1 + return 0 } } diff --git a/module/service/iml.go b/module/service/iml.go index bbab2cf3..a0eb81d5 100644 --- a/module/service/iml.go +++ b/module/service/iml.go @@ -282,6 +282,7 @@ func toServiceItem(model *service.Service) *service_dto.ServiceItem { switch model.Kind { case service.RestService: + item.State = model.ServiceType.String() return item case service.AIService: provider := auto.UUID(model.AdditionalConfig["provider"]) diff --git a/service/ai-api/iml.go b/service/ai-api/iml.go index 6b0a4a4c..f31716c2 100644 --- a/service/ai-api/iml.go +++ b/service/ai-api/iml.go @@ -23,6 +23,14 @@ type imlAPIService struct { universally.IServiceDelete } +func (i *imlAPIService) DeleteByService(ctx context.Context, serviceId string) error { + _, err := i.store.DeleteWhere(ctx, map[string]interface{}{"service": serviceId}) + if err != nil { + return nil + } + return err +} + func (i *imlAPIService) CountMapByModel(ctx context.Context, keyword string, conditions map[string]interface{}) (map[string]int64, error) { return i.store.CountByGroup(ctx, keyword, conditions, "model") } diff --git a/service/ai-api/service.go b/service/ai-api/service.go index a2543bff..d6f3f6da 100644 --- a/service/ai-api/service.go +++ b/service/ai-api/service.go @@ -15,6 +15,7 @@ type IAPIService interface { universally.IServiceDelete CountMapByProvider(ctx context.Context, keyword string, conditions map[string]interface{}) (map[string]int64, error) CountMapByModel(ctx context.Context, keyword string, conditions map[string]interface{}) (map[string]int64, error) + DeleteByService(ctx context.Context, serviceId string) error } type IAPIUseService interface { diff --git a/service/ai-local/iml.go b/service/ai-local/iml.go index 9a7e8e2d..a970ba9d 100644 --- a/service/ai-local/iml.go +++ b/service/ai-local/iml.go @@ -1,8 +1,11 @@ package ai_local import ( + "context" "time" + "github.com/eolinker/go-common/utils" + "github.com/APIParkLab/APIPark/service/universally" "github.com/APIParkLab/APIPark/stores/ai" ) @@ -187,3 +190,39 @@ func (i *imlLocalModelInstallStateService) updateHandler(e *ai.LocalModelInstall } e.UpdateAt = time.Now() } + +var _ ILocalModelCacheService = &imlLocalModelCacheService{} + +type imlLocalModelCacheService struct { + store ai.ILocalModelCacheStore `autowired:""` +} + +func (i *imlLocalModelCacheService) List(ctx context.Context, model string, typ CacheType) ([]*LocalModelCache, error) { + list, err := i.store.List(ctx, map[string]interface{}{"model": model, "type": typ.Int()}) + if err != nil { + return nil, err + } + return utils.SliceToSlice(list, func(s *ai.LocalModelCache) *LocalModelCache { + return &LocalModelCache{ + Model: s.Model, + Target: s.Target, + Type: CacheType(s.Type), + } + }), nil +} + +func (i *imlLocalModelCacheService) Delete(ctx context.Context, model string) error { + _, err := i.store.DeleteWhere(ctx, map[string]interface{}{"model": model}) + if err != nil { + return err + } + return nil +} + +func (i *imlLocalModelCacheService) Save(ctx context.Context, model string, typ CacheType, target string) error { + return i.store.Insert(ctx, &ai.LocalModelCache{ + Model: model, + Target: target, + Type: typ.Int(), + }) +} diff --git a/service/ai-local/model.go b/service/ai-local/model.go index 2898074c..fc51508f 100644 --- a/service/ai-local/model.go +++ b/service/ai-local/model.go @@ -75,3 +75,37 @@ type EditLocalModelInstallState struct { State *int Msg *string } + +type LocalModelCache struct { + Model string + Target string + Type CacheType +} + +type CacheType string + +func (c CacheType) String() string { + return string(c) +} + +func (c CacheType) Int() int { + switch c { + case CacheTypeService: + return 0 + default: + return 0 + } +} + +func FromCacheType(s int) CacheType { + switch s { + case 0: + return CacheTypeService + default: + return CacheTypeService + } +} + +const ( + CacheTypeService CacheType = "service" +) diff --git a/service/ai-local/service.go b/service/ai-local/service.go index 6311aa50..276cec8c 100644 --- a/service/ai-local/service.go +++ b/service/ai-local/service.go @@ -1,6 +1,7 @@ package ai_local import ( + "context" "reflect" "github.com/APIParkLab/APIPark/service/universally" @@ -28,6 +29,12 @@ type ILocalModelInstallStateService interface { universally.IServiceDelete } +type ILocalModelCacheService interface { + List(ctx context.Context, model string, typ CacheType) ([]*LocalModelCache, error) + Delete(ctx context.Context, model string) error + Save(ctx context.Context, model string, typ CacheType, target string) error +} + func init() { autowire.Auto[ILocalModelService](func() reflect.Value { return reflect.ValueOf(new(imlLocalModelService)) @@ -39,4 +46,8 @@ func init() { autowire.Auto[ILocalModelInstallStateService](func() reflect.Value { return reflect.ValueOf(new(imlLocalModelInstallStateService)) }) + + autowire.Auto[ILocalModelCacheService](func() reflect.Value { + return reflect.ValueOf(new(imlLocalModelCacheService)) + }) } diff --git a/service/api/iml.go b/service/api/iml.go index 5e81c236..19117a72 100644 --- a/service/api/iml.go +++ b/service/api/iml.go @@ -41,6 +41,13 @@ type imlAPIService struct { universally.IServiceDelete } +func (i *imlAPIService) DeleteByService(ctx context.Context, serviceId string) error { + _, err := i.store.DeleteWhere(ctx, map[string]interface{}{ + "service": serviceId, + }) + return err +} + func (i *imlAPIService) ListForServices(ctx context.Context, serviceIds ...string) ([]*API, error) { w := map[string]interface{}{} if len(serviceIds) > 0 { diff --git a/service/api/service.go b/service/api/service.go index 9c58c335..7e2a758f 100644 --- a/service/api/service.go +++ b/service/api/service.go @@ -43,6 +43,7 @@ type IAPIService interface { Save(ctx context.Context, id string, model *Edit) error Create(ctx context.Context, input *Create) (err error) + DeleteByService(ctx context.Context, serviceId string) error } var ( diff --git a/stores/ai/model.go b/stores/ai/model.go index a532704a..6d607d16 100644 --- a/stores/ai/model.go +++ b/stores/ai/model.go @@ -149,3 +149,18 @@ func (i *LocalModelPackage) TableName() string { func (i *LocalModelPackage) IdValue() int64 { return i.Id } + +type LocalModelCache struct { + Id int64 `gorm:"column:id;type:BIGINT(20);AUTO_INCREMENT;NOT NULL;comment:id;primary_key;comment:主键ID;"` + Model string `gorm:"type:varchar(100);not null;column:model;comment:模型ID"` + Target string `gorm:"type:varchar(100);not null;column:target;comment:目标"` + Type int `gorm:"type:tinyint(1);not null;column:type;comment:类型,0: 服务"` +} + +func (i *LocalModelCache) TableName() string { + return "ai_local_model_cache" +} + +func (i *LocalModelCache) IdValue() int64 { + return i.Id +} diff --git a/stores/ai/store.go b/stores/ai/store.go index e0441fb9..8c462f42 100644 --- a/stores/ai/store.go +++ b/stores/ai/store.go @@ -63,6 +63,14 @@ type imlLocalModelInstallStateStore struct { store.SearchStore[LocalModelInstallState] } +type ILocalModelCacheStore interface { + store.IBaseStore[LocalModelCache] +} + +type imlLocalModelCacheStore struct { + store.Store[LocalModelCache] +} + func init() { autowire.Auto[IProviderStore](func() reflect.Value { return reflect.ValueOf(new(imlProviderStore)) @@ -91,4 +99,8 @@ func init() { autowire.Auto[ILocalModelInstallStateStore](func() reflect.Value { return reflect.ValueOf(new(imlLocalModelInstallStateStore)) }) + + autowire.Auto[ILocalModelCacheStore](func() reflect.Value { + return reflect.ValueOf(new(imlLocalModelCacheStore)) + }) }