From 299ee0fd25e4b049a0451c9afd81c28ad6b4fdec Mon Sep 17 00:00:00 2001 From: sunanzhi Date: Tue, 11 Mar 2025 12:01:20 +0800 Subject: [PATCH 1/2] refactor: adjust character limit for custom provider/model name --- common/regexp.go | 9 +++++++++ controller/ai-model/iml.go | 9 +++++---- controller/ai/iml.go | 5 +++-- module/ai-api/dto/input.go | 1 + module/ai-api/dto/output.go | 1 + module/ai-api/iml.go | 30 +++++++++++++++++++++--------- module/ai-model/iml.go | 7 +++++++ module/ai/iml.go | 14 ++++++++------ service/ai/iml.go | 4 ++-- service/ai/service.go | 2 +- 10 files changed, 58 insertions(+), 24 deletions(-) diff --git a/common/regexp.go b/common/regexp.go index 3e78ec44..bae85ac0 100644 --- a/common/regexp.go +++ b/common/regexp.go @@ -25,6 +25,8 @@ const ( CIDRIpv4Exp = `^(?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([1-9]|[1-2]\d|3[0-2]))?$` // CheckPathIPPortExp (scheme://)?ip:port CheckPathIPPortExp = `([a-zA-z]+://)?((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})(\.((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})){3}:[0-9]+` + // EnglishOrNumberOrSpecialChars a-zA-Z0-9-_.: + EnglishOrNumberOrSpecialChars = `^(?i)[-:._a-z0-9]+$` ) var ( @@ -47,6 +49,8 @@ var ( restfulPathMatchRegexp = regexp.MustCompile(`({[0-9a-zA-Z-_]+})+`) //restfulParamMatchRegexp 匹配restful参数 {xxx} restfulParamMatchRegexp = regexp.MustCompile(`^{[0-9a-zA-Z-_]+}$`) + // modelNameRegexp match model name + modelNameRegexp = regexp.MustCompile(EnglishOrNumberOrSpecialChars) ) func IsMatchString(regexpPattern RegexpPattern, s string) error { @@ -129,3 +133,8 @@ func ReplaceRestfulPath(path, replaceStr string) string { func CheckPathContainsIPPort(path string) bool { return checkIPPortRegexp.MatchString(path) } + +// ModelNameValid check model name is valid +func ModelNameValid(param string) bool { + return modelNameRegexp.MatchString(param) +} diff --git a/controller/ai-model/iml.go b/controller/ai-model/iml.go index fcb48134..a0176c3b 100644 --- a/controller/ai-model/iml.go +++ b/controller/ai-model/iml.go @@ -3,6 +3,7 @@ package ai_model import ( "encoding/json" "fmt" + "github.com/APIParkLab/APIPark/common" ai_model "github.com/APIParkLab/APIPark/module/ai-model" model_dto "github.com/APIParkLab/APIPark/module/ai-model/dto" "github.com/gin-gonic/gin" @@ -22,8 +23,8 @@ func (i *imlProviderModelController) GetModelParametersTemplate(ctx *gin.Context } func (i *imlProviderModelController) UpdateProviderModel(ctx *gin.Context, provider string, input *model_dto.EditModel) error { - if strings.TrimSpace(input.Name) == "" { - return fmt.Errorf("name is empty") + if !common.ModelNameValid(input.Name) { + return fmt.Errorf("model name is invalid(a-zA-Z0-9-_.:)") } if strings.TrimSpace(input.Id) == "" { return fmt.Errorf("id is empty") @@ -54,8 +55,8 @@ func (i *imlProviderModelController) DeleteProviderModel(ctx *gin.Context, provi } func (i *imlProviderModelController) AddProviderModel(ctx *gin.Context, provider string, input *model_dto.Model) (*model_dto.SimpleModel, error) { - if strings.TrimSpace(input.Name) == "" { - return nil, fmt.Errorf("name is empty") + if !common.ModelNameValid(input.Name) { + return nil, fmt.Errorf("model name illegal(a-zA-Z0-9-_.:)") } if strings.TrimSpace(provider) == "" { return nil, fmt.Errorf("provider is empty") diff --git a/controller/ai/iml.go b/controller/ai/iml.go index ae37239b..91885a04 100644 --- a/controller/ai/iml.go +++ b/controller/ai/iml.go @@ -3,6 +3,7 @@ package ai import ( "encoding/json" "fmt" + "github.com/APIParkLab/APIPark/common" "strconv" "strings" @@ -24,8 +25,8 @@ func (i *imlProviderController) Delete(ctx *gin.Context, id string) error { } func (i *imlProviderController) AddProvider(ctx *gin.Context, input *ai_dto.NewProvider) (*ai_dto.SimpleProvider, error) { - if strings.TrimSpace(input.Name) == "" { - return nil, fmt.Errorf("name is empty") + if !common.ModelNameValid(input.Name) { + return nil, fmt.Errorf("name illegal(a-zA-Z0-9-_.:)") } return i.module.AddProvider(ctx, input) } diff --git a/module/ai-api/dto/input.go b/module/ai-api/dto/input.go index e559dd5f..4eeb624f 100644 --- a/module/ai-api/dto/input.go +++ b/module/ai-api/dto/input.go @@ -25,6 +25,7 @@ type AiPromptVariable struct { type AiModel struct { Id string `json:"id"` + Name string `json:"name"` Config string `json:"config"` Provider string `json:"provider"` Type string `json:"type"` diff --git a/module/ai-api/dto/output.go b/module/ai-api/dto/output.go index 521d8979..23e84e20 100644 --- a/module/ai-api/dto/output.go +++ b/module/ai-api/dto/output.go @@ -66,6 +66,7 @@ type APIItem struct { type ModelItem struct { Id string `json:"id"` + Name string `json:"name"` Logo string `json:"logo"` } diff --git a/module/ai-api/iml.go b/module/ai-api/iml.go index 58b9d884..4bea9514 100644 --- a/module/ai-api/iml.go +++ b/module/ai-api/iml.go @@ -5,6 +5,7 @@ import ( "encoding/json" "errors" "fmt" + ai_model "github.com/APIParkLab/APIPark/service/ai-model" "net/http" "strings" @@ -32,11 +33,12 @@ var ( ) type imlAPIModule struct { - serviceService service.IServiceService `autowired:""` - apiDocService api_doc.IAPIDocService `autowired:""` - aiAPIService ai_api.IAPIService `autowired:""` - apiService api.IAPIService `autowired:""` - transaction store.ITransaction `autowired:""` + serviceService service.IServiceService `autowired:""` + apiDocService api_doc.IAPIDocService `autowired:""` + aiAPIService ai_api.IAPIService `autowired:""` + aiModelService ai_model.IProviderModelService `autowired:""` + apiService api.IAPIService `autowired:""` + transaction store.ITransaction `autowired:""` } func (i *imlAPIModule) getAPIDoc(ctx context.Context, serviceId string) (*openapi3.T, error) { @@ -242,19 +244,20 @@ func (i *imlAPIModule) List(ctx context.Context, keyword string, serviceId strin item.Provider = ai_api_dto.ProviderItem{ Id: p.ID(), Name: p.Name(), - Logo: p.Logo(), + Logo: "", } m, has := p.GetModel(t.Model) if has { item.Model = ai_api_dto.ModelItem{ Id: m.ID(), - Logo: m.Logo(), + Name: m.Name(), + Logo: "", } } } else { - item.Model = ai_api_dto.ModelItem{ - Id: aiModel.Id, + Id: aiModel.Id, + Name: "unknown", } } return item @@ -281,6 +284,15 @@ func (i *imlAPIModule) Get(ctx context.Context, serviceId string, apiId string) if err != nil { return nil, err } + if aiModel.Name == "" { + // get provider model + modelInfo, _ := i.aiModelService.Get(ctx, aiModel.Id) + if modelInfo != nil { + aiModel.Name = modelInfo.Name + } else { + aiModel.Name = aiModel.Id + } + } return &ai_api_dto.API{ Id: apiInfo.ID, diff --git a/module/ai-model/iml.go b/module/ai-model/iml.go index 5b3564c1..e3508355 100644 --- a/module/ai-model/iml.go +++ b/module/ai-model/iml.go @@ -5,6 +5,7 @@ import ( model_runtime "github.com/APIParkLab/APIPark/ai-provider/model-runtime" model_dto "github.com/APIParkLab/APIPark/module/ai-model/dto" "github.com/APIParkLab/APIPark/service/ai" + ai_api "github.com/APIParkLab/APIPark/service/ai-api" ai_model "github.com/APIParkLab/APIPark/service/ai-model" "github.com/gin-gonic/gin" "github.com/google/uuid" @@ -19,6 +20,7 @@ var ( type imlProviderModelModule struct { providerService ai.IProviderService `autowired:""` + aiApiService ai_api.IAPIService `autowired:""` providerModelService ai_model.IProviderModelService `autowired:""` transaction store.ITransaction `autowired:""` } @@ -91,6 +93,11 @@ func (i *imlProviderModelModule) DeleteProviderModel(ctx *gin.Context, provider if modelInfo == nil || modelInfo.Provider != provider { return fmt.Errorf("model not found") } + // check model in use + countMapByModel, _ := i.aiApiService.CountMapByModel(ctx, "", map[string]interface{}{"model": id}) + if countValue, has := countMapByModel[id]; has && countValue > 0 { + return fmt.Errorf("model in use") + } if err := i.providerModelService.Delete(ctx, id); err != nil { return err } diff --git a/module/ai/iml.go b/module/ai/iml.go index 8df42d51..94abad07 100644 --- a/module/ai/iml.go +++ b/module/ai/iml.go @@ -198,13 +198,13 @@ func (i *imlProviderModule) Delete(ctx context.Context, id string) error { } func (i *imlProviderModule) AddProvider(ctx context.Context, input *ai_dto.NewProvider) (*ai_dto.SimpleProvider, error) { - if has := i.providerService.CheckNameDuplicate(ctx, input.Name); has { + // uuid = name + if has := i.providerService.CheckUuidDuplicate(ctx, input.Name); has { return nil, fmt.Errorf("provider `%s` duplicate", input.Name) } - id := uuid.New().String() config, defaultLLM := "{\"base_url\": \"\", \"api_key\": \"\"}", "" if err := i.providerService.Create(ctx, &ai.CreateProvider{ - Id: id, + Id: input.Name, Name: input.Name, DefaultLLM: defaultLLM, Config: config, @@ -213,10 +213,10 @@ func (i *imlProviderModule) AddProvider(ctx context.Context, input *ai_dto.NewPr return nil, err } // register provider - iProvider, _ := model_runtime.NewCustomizeProvider(id, input.Name, []model_runtime.IModel{}, "", "") - model_runtime.Register(id, iProvider) + iProvider, _ := model_runtime.NewCustomizeProvider(input.Name, input.Name, []model_runtime.IModel{}, "", "") + model_runtime.Register(input.Name, iProvider) return &ai_dto.SimpleProvider{ - Id: id, + Id: input.Name, Name: input.Name, DefaultConfig: config, Logo: model_runtime.GetCustomizeLogo(), @@ -482,6 +482,8 @@ func (i *imlProviderModule) Provider(ctx context.Context, id string) (*ai_dto.Pr model, has := p.DefaultModel(model_runtime.ModelTypeLLM) if !has || model == nil { defaultLLM, _ = model_runtime.NewCustomizeModel("", "", "", "", "") + } else { + defaultLLM = model } } diff --git a/service/ai/iml.go b/service/ai/iml.go index ad99617d..7e146f5c 100644 --- a/service/ai/iml.go +++ b/service/ai/iml.go @@ -70,8 +70,8 @@ type imlProviderService struct { // return i.store.Save(ctx, info) //} -func (i *imlProviderService) CheckNameDuplicate(ctx context.Context, name string) bool { - v, _ := i.store.First(ctx, map[string]interface{}{"name": name}) +func (i *imlProviderService) CheckUuidDuplicate(ctx context.Context, uuid string) bool { + v, _ := i.store.First(ctx, map[string]interface{}{"uuid": uuid}) return v != nil } diff --git a/service/ai/service.go b/service/ai/service.go index c7eb0071..26ac92c8 100644 --- a/service/ai/service.go +++ b/service/ai/service.go @@ -15,7 +15,7 @@ type IProviderService interface { universally.IServiceDelete //Save(ctx context.Context, id string, cfg *SetProvider) error //MaxPriority(ctx context.Context) (int, error) - CheckNameDuplicate(ctx context.Context, name string) bool + CheckUuidDuplicate(ctx context.Context, uuid string) bool } func init() { From c4670e1cb1299757af6e571ac5c7ae910a042f6f Mon Sep 17 00:00:00 2001 From: sunanzhi Date: Tue, 11 Mar 2025 15:22:06 +0800 Subject: [PATCH 2/2] refactor: remove validation for checking provider existence in model addition --- module/ai-model/iml.go | 8 -------- 1 file changed, 8 deletions(-) diff --git a/module/ai-model/iml.go b/module/ai-model/iml.go index e3508355..033a05df 100644 --- a/module/ai-model/iml.go +++ b/module/ai-model/iml.go @@ -111,14 +111,6 @@ func (i *imlProviderModelModule) AddProviderModel(ctx *gin.Context, provider str if !has { return nil, fmt.Errorf("ai provider not found") } - // check provider exist - providerInfo, err := i.providerService.Get(ctx, provider) - if err != nil { - return nil, err - } - if providerInfo == nil { - return nil, fmt.Errorf("provider not found") - } // check model name duplicate if has := i.providerModelService.CheckNameDuplicate(ctx, provider, input.Name, ""); has { return nil, fmt.Errorf("model name: `%s` duplicate", input.Name)