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

fix: ai deploy bug

See merge request apipark/APIPark!204
This commit is contained in:
刘健
2025-02-17 15:24:28 +08:00
9 changed files with 126 additions and 119 deletions
+75 -85
View File
@@ -6,14 +6,9 @@ import (
"fmt"
"io"
"math"
"net/http"
"strings"
"github.com/APIParkLab/APIPark/module/router"
"github.com/APIParkLab/APIPark/model/plugin_model"
"github.com/APIParkLab/APIPark/service/api"
ai_api "github.com/APIParkLab/APIPark/module/ai-api"
"github.com/APIParkLab/APIPark/module/catalogue"
@@ -24,9 +19,6 @@ import (
service_dto "github.com/APIParkLab/APIPark/module/service/dto"
ai_api_dto "github.com/APIParkLab/APIPark/module/ai-api/dto"
router_dto "github.com/APIParkLab/APIPark/module/router/dto"
ai_provider_local "github.com/APIParkLab/APIPark/ai-provider/local"
"github.com/eolinker/eosc/log"
@@ -199,7 +191,7 @@ func (i *imlLocalModelController) initAILocalService(ctx context.Context, model
serviceId := uuid.NewString()
prefix := fmt.Sprintf("/%s", serviceId[:8])
providerId := "ollama"
info, err := i.serviceModule.Create(ctx, teamID, &service_dto.CreateService{
_, err = i.serviceModule.Create(ctx, teamID, &service_dto.CreateService{
Id: serviceId,
Name: model,
Prefix: prefix,
@@ -214,83 +206,81 @@ 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
aiPrompt := &ai_api_dto.AiPrompt{
Variables: []*ai_api_dto.AiPromptVariable{},
Prompt: "",
}
aiModel := &ai_api_dto.AiModel{
Id: model,
Config: ai_provider_local.OllamaConfig,
Provider: providerId,
Type: "local",
}
name := "Demo AI API"
description := "A demo that shows you how to use a e a Chat API."
apiId := uuid.NewString()
err = i.aiAPIModule.Create(
ctx,
info.Id,
&ai_api_dto.CreateAPI{
Id: apiId,
Name: name,
Path: path,
Description: description,
Disable: false,
AiPrompt: aiPrompt,
AiModel: aiModel,
Timeout: timeout,
Retry: retry,
},
)
if err != nil {
return err
}
plugins := make(map[string]api.PluginSetting)
plugins["ai_prompt"] = api.PluginSetting{
Config: plugin_model.ConfigType{
"prompt": aiPrompt.Prompt,
"variables": aiPrompt.Variables,
},
}
plugins["ai_formatter"] = api.PluginSetting{
Config: plugin_model.ConfigType{
"model": aiModel.Id,
"provider": info.Provider.Id,
"config": aiModel.Config,
},
}
_, err = i.routerModule.Create(ctx, info.Id, &router_dto.Create{
Id: apiId,
Name: name,
Path: path,
Methods: []string{
http.MethodPost,
},
Description: description,
Protocols: []string{"http", "https"},
MatchRules: nil,
Proxy: &router_dto.InputProxy{
Path: path,
Timeout: timeout,
Retry: retry,
Plugins: plugins,
},
Disable: false,
})
if err != nil {
return err
}
return i.module.SaveCache(ctx, model, serviceId)
return i.docModule.SaveServiceDoc(ctx, info.Id, &service_dto.SaveServiceDoc{
Doc: "",
})
//path := fmt.Sprintf("/%s/chat", strings.Trim(prefix, "/"))
//timeout := 300000
//retry := 0
//aiPrompt := &ai_api_dto.AiPrompt{
// Variables: []*ai_api_dto.AiPromptVariable{},
// Prompt: "",
//}
//aiModel := &ai_api_dto.AiModel{
// Id: model,
// Config: ai_provider_local.OllamaConfig,
// Provider: providerId,
// Type: "local",
//}
//name := "Demo AI API"
//description := "A demo that shows you how to use a e a Chat API."
//apiId := uuid.NewString()
//err = i.aiAPIModule.Create(
// ctx,
// info.Id,
// &ai_api_dto.CreateAPI{
// Id: apiId,
// Name: name,
// Path: path,
// Description: description,
// Disable: false,
// AiPrompt: aiPrompt,
// AiModel: aiModel,
// Timeout: timeout,
// Retry: retry,
// },
//)
//if err != nil {
// return err
//}
//plugins := make(map[string]api.PluginSetting)
//plugins["ai_prompt"] = api.PluginSetting{
// Config: plugin_model.ConfigType{
// "prompt": aiPrompt.Prompt,
// "variables": aiPrompt.Variables,
// },
//}
//plugins["ai_formatter"] = api.PluginSetting{
// Config: plugin_model.ConfigType{
// "model": aiModel.Id,
// "provider": info.Provider.Id,
// "config": aiModel.Config,
// },
//}
//_, err = i.routerModule.Create(ctx, info.Id, &router_dto.Create{
// Id: apiId,
// Name: name,
// Path: path,
// Methods: []string{
// http.MethodPost,
// },
// Description: description,
// Protocols: []string{"http", "https"},
// MatchRules: nil,
// Proxy: &router_dto.InputProxy{
// Path: path,
// Timeout: timeout,
// Retry: retry,
// Plugins: plugins,
// },
// Disable: false,
//})
//if err != nil {
// return err
//}
//
//return i.docModule.SaveServiceDoc(ctx, info.Id, &service_dto.SaveServiceDoc{
// Doc: "",
//})
})
return err
+6 -2
View File
@@ -72,9 +72,13 @@ func genResponse() *openapi3.ResponseRef {
func genRequestBodySchema(variables []*ai_api_dto.AiPromptVariable) *openapi3.Schema {
result := openapi3.NewObjectSchema()
result.WithProperty("variables", genVariableSchema(variables))
if len(variables) > 0 {
result.WithProperty("variables", genVariableSchema(variables))
result.WithRequired([]string{"variables", "messages"})
}
result.WithPropertyRef("messages", messagesSchemaRef)
result.WithRequired([]string{"variables", "messages"})
return result
}
+36 -27
View File
@@ -130,34 +130,41 @@ func (i *imlLocalModel) Search(ctx context.Context, keyword string) ([]*ai_local
}
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 != "" {
if keyword == "" {
list, err := i.localModelPackageService.Search(ctx, keyword, nil)
if err != nil {
return nil, err
}
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
} else {
info, err := i.localModelPackageService.Get(ctx, keyword)
if err != nil {
return nil, err
}
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,
})
}
//for _, v := range list {
models := ai_provider_local.ModelsCanInstallById(info.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 {
@@ -292,7 +299,7 @@ func (i *imlLocalModel) syncGateway(ctx context.Context, clusterId string, relea
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)
info, err := i.localModelService.Get(ctx, model)
if err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) {
return err
@@ -305,8 +312,10 @@ func (i *imlLocalModel) Deploy(ctx context.Context, model string, session string
})
} else {
state := ai_local_dto.LocalModelStateDeploying.Int()
err = i.localModelService.Save(ctx, model, &ai_local.EditLocalModel{State: &state})
if info.State == ai_local_dto.LocalModelStateDeployingError.Int() {
state := ai_local_dto.LocalModelStateDeploying.Int()
err = i.localModelService.Save(ctx, model, &ai_local.EditLocalModel{State: &state})
}
}
if err != nil {
return err
@@ -428,6 +437,7 @@ func (i *imlLocalModel) OnInit() {
})
models, version := ai_provider_local.ModelsCanInstall()
for _, model := range models {
delete(oldModels, model.Id)
if v, ok := oldModels[model.Id]; ok {
if v.Version == version {
continue
@@ -456,7 +466,6 @@ func (i *imlLocalModel) OnInit() {
return
}
}
delete(oldModels, model.Id)
}
for id := range oldModels {
err = i.localModelPackageService.Delete(ctx, id)
+4
View File
@@ -66,6 +66,10 @@ func (i *imlLocalModelService) fromEntity(e *ai.LocalModel) *LocalModel {
}
}
var (
_ ILocalModelPackageService = &imlLocalModelPackageService{}
)
type imlLocalModelPackageService struct {
store ai.ILocalModelPackageStore `autowired:""`
universally.IServiceGet[LocalModelPackage]
+1
View File
@@ -20,6 +20,7 @@ type ILocalModelPackageService interface {
universally.IServiceCreate[CreateLocalModelPackage]
universally.IServiceEdit[EditLocalModelPackage]
universally.IServiceDelete
//SearchByModel(ctx context.Context, model string) ([]*LocalModelPackage, error)
}
type ILocalModelInstallStateService interface {
+1 -2
View File
@@ -42,10 +42,9 @@ type imlAPIService struct {
}
func (i *imlAPIService) DeleteByService(ctx context.Context, serviceId string) error {
_, err := i.store.DeleteWhere(ctx, map[string]interface{}{
return i.store.SoftDelete(ctx, map[string]interface{}{
"service": serviceId,
})
return err
}
func (i *imlAPIService) ListForServices(ctx context.Context, serviceIds ...string) ([]*API, error) {
+1 -1
View File
@@ -48,7 +48,7 @@ func FromEntity(e *api.API) *API {
return &API{
UUID: e.UUID,
CreateAt: e.CreateAt,
IsDelete: e.IsDelete != 0,
IsDelete: e.IsDelete,
Service: e.Service,
Team: e.Team,
Creator: e.Creator,
+1 -1
View File
@@ -12,10 +12,10 @@ type API struct {
Upstream string `gorm:"size:36;not null;column:upstream;comment:上游;index:upstream"` // 上游ID
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:创建时间"`
IsDelete int `gorm:"type:tinyint(1);not null;column:is_delete;comment:是否删除 0:未删除 1:已删除"`
Method []string `gorm:"size:255;not null;column:method;comment:请求方法;serializer:json"`
Protocol []string `gorm:"type:text;not null;column:protocol;comment:协议;serializer:json"`
Path string `gorm:"size:255;not null;column:path;comment:请求路径"`
IsDelete bool `gorm:"type:tinyint(1);not null;column:is_delete;comment:是否删除 0:未删除 1:已删除"`
}
type Info struct {
Id int64 `gorm:"column:id;type:BIGINT(20);NOT NULL;comment:id;primary_key;comment:主键ID;"`
+1 -1
View File
@@ -15,7 +15,7 @@ type Service struct {
Catalogue string `gorm:"type:text;not null;column:catalogue;comment:目录"`
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 ON UPDATE CURRENT_TIMESTAMP;column:update_at;comment:修改时间"`
IsDelete int `gorm:"type:tinyint(1);not null;column:is_delete;comment:是否删除"`
IsDelete bool `gorm:"type:tinyint(1);not null;column:is_delete;comment:是否删除"`
Kind int `gorm:"type:tinyint(4);not null;column:kind;comment:服务种类,0:Rest服务,1:AI服务"`
State int `gorm:"type:tinyint(4);not null;column:state;comment:状态"`
AdditionalConfig string `gorm:"type:text;not null;column:additional_config;comment:额外配置"`