package model_runtime import ( "encoding/json" "fmt" "net/url" yaml "gopkg.in/yaml.v3" "github.com/APIParkLab/APIPark/ai-provider/model-runtime/entity" "github.com/eolinker/eosc" ) const ( ModelTypeLLM = "llm" ) type IProvider interface { IProviderInfo GetModel(name string) (IModel, bool) Models() []IModel ModelsByType(modelType string) ([]IModel, bool) IConfig MaskConfig(cfg string) string Sort() int Recommend() bool } type IProviderURI interface { Scheme() string Host() string Path() string } type IProviderInfo interface { ID() string Name() string DefaultModel(modelType string) (IModel, bool) HelpUrl() string Logo() string URI() IProviderURI } func NewProvider(providerData string, modelContents map[string]eosc.Untyped[string, string]) (IProvider, error) { var providerCfg entity.Provider err := yaml.Unmarshal([]byte(providerData), &providerCfg) if err != nil { return nil, err } uri, err := newProviderUri(providerCfg.Address) if err != nil { return nil, err } assetsFiles, ok := modelContents[DirAssets] if !ok { return nil, fmt.Errorf("assets not found") } delete(modelContents, DirAssets) //providerLogo, ok := assetsFiles.Get(providerCfg.IconLarge[entity.LanguageEnglish]) //if !ok { // return nil, fmt.Errorf("provider logo not found:%s", providerCfg.Provider) //} modelLogo, ok := assetsFiles.Get(providerCfg.IconSmall[entity.LanguageEnglish]) if !ok { return nil, fmt.Errorf("model logo not found:%s", providerCfg.Provider) } provider := &Provider{ id: providerCfg.Provider, name: providerCfg.Label[entity.LanguageEnglish], logo: modelLogo, helpUrl: providerCfg.Help.URL[entity.LanguageEnglish], models: eosc.BuildUntyped[string, IModel](), defaultModels: eosc.BuildUntyped[string, IModel](), modelsByType: eosc.BuildUntyped[string, []IModel](), maskKeys: make([]string, 0), recommend: providerCfg.Recommend, sort: providerCfg.Sort, uri: uri, } defaultCfg := make(map[string]string) params := make(ParamValidator, 0, len(providerCfg.ProviderCredentialSchema.CredentialFormSchemas)) for _, v := range providerCfg.ProviderCredentialSchema.CredentialFormSchemas { param := Param{ Name: v.Variable, Default: v.Label[entity.LanguageEnglish], Type: ParameterTypeStr, Required: v.Required, } if v.Type == "secret-input" { provider.maskKeys = append(provider.maskKeys, v.Variable) param.Secret = true } params = append(params, param) defaultCfg[v.Variable] = v.Label[entity.LanguageEnglish] } defaultCfgByte, _ := json.MarshalIndent(defaultCfg, "", " ") provider.IConfig = NewConfig(string(defaultCfgByte), params) for name, f := range modelContents { models := make([]IModel, 0, f.Count()) defaultModel := providerCfg.Default[name] for i, v := range f.List() { model, err := NewModel(v, modelLogo) if err != nil { return nil, err } provider.SetModel(model.ID(), model) if i == 0 && defaultModel == "" { defaultModel = model.ID() } if model.ID() == defaultModel { provider.SetDefaultModel(name, model) } models = append(models, model) } provider.SetModelsByType(name, models) } return provider, nil } type Provider struct { id string name string logo string helpUrl string models eosc.Untyped[string, IModel] defaultModels eosc.Untyped[string, IModel] modelsByType eosc.Untyped[string, []IModel] maskKeys []string uri IProviderURI sort int recommend bool IConfig } func (p *Provider) Sort() int { return p.sort } func (p *Provider) Recommend() bool { return p.recommend } func (p *Provider) URI() IProviderURI { return p.uri } func (p *Provider) ID() string { return p.id } func (p *Provider) Name() string { return p.name } func (p *Provider) HelpUrl() string { return p.helpUrl } func (p *Provider) Logo() string { return p.logo } func (p *Provider) DefaultModel(modelType string) (IModel, bool) { return p.defaultModels.Get(modelType) } func (p *Provider) GetModel(name string) (IModel, bool) { return p.models.Get(name) } func (p *Provider) Models() []IModel { return p.models.List() } func (p *Provider) ModelsByType(modelType string) ([]IModel, bool) { return p.modelsByType.Get(modelType) } func (p *Provider) MaskConfig(cfg string) string { var data map[string]string err := json.Unmarshal([]byte(cfg), &data) if err != nil { return cfg } for _, key := range p.maskKeys { if _, ok := data[key]; ok { data[key] = "******" } } result, _ := json.Marshal(data) return string(result) } func (p *Provider) SetDefaultModel(modelType string, model IModel) { p.defaultModels.Set(modelType, model) } func (p *Provider) SetModel(id string, model IModel) { p.models.Set(id, model) } func (p *Provider) SetModelsByType(modelType string, models []IModel) { p.modelsByType.Set(modelType, models) } type providerUri struct { scheme string host string path string } func newProviderUri(addr string) (IProviderURI, error) { uri, err := url.Parse(addr) if err != nil { return nil, err } if uri.Host == "" { return nil, fmt.Errorf("host is empty") } if uri.Scheme == "" { return nil, fmt.Errorf("scheme is empty") } return &providerUri{ scheme: uri.Scheme, host: uri.Host, path: uri.Path, }, nil } func (p *providerUri) Scheme() string { return p.scheme } func (p *providerUri) Host() string { return p.host } func (p *providerUri) Path() string { return p.path }