Merge branch 'feature/1.5-local-model' into 'main'

fix: ai deploy bug

See merge request apipark/APIPark!198
This commit is contained in:
刘健
2025-02-17 00:37:59 +08:00
14 changed files with 227 additions and 44 deletions
+15 -22
View File
@@ -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,
+81 -21
View File
@@ -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
}
+1
View File
@@ -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() {
+1 -1
View File
@@ -26,7 +26,7 @@ func (s ServiceState) Int() int {
case ServiceStateDeployError:
return 2
default:
return -1
return 0
}
}
+1
View File
@@ -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"])
+8
View File
@@ -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")
}
+1
View File
@@ -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 {
+39
View File
@@ -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(),
})
}
+34
View File
@@ -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"
)
+11
View File
@@ -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))
})
}
+7
View File
@@ -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 {
+1
View File
@@ -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 (
+15
View File
@@ -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
}
+12
View File
@@ -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))
})
}