AI供应商相关接口完成

This commit is contained in:
Liujian
2024-09-24 14:15:52 +08:00
parent 836f15f5d7
commit 6dab6c327c
22 changed files with 1140 additions and 33 deletions
+25
View File
@@ -0,0 +1,25 @@
package ai
import (
ai_dto "github.com/APIParkLab/APIPark/module/ai/dto"
"github.com/eolinker/go-common/autowire"
"github.com/gin-gonic/gin"
"reflect"
)
type IProviderController interface {
Providers(ctx *gin.Context) ([]*ai_dto.ProviderItem, error)
SimpleProviders(ctx *gin.Context) ([]*ai_dto.SimpleProviderItem, error)
Provider(ctx *gin.Context, id string) (*ai_dto.Provider, error)
LLMs(ctx *gin.Context, driver string) ([]*ai_dto.LLMItem, error)
Enable(ctx *gin.Context, id string) error
Disable(ctx *gin.Context, id string) error
UpdateProviderConfig(ctx *gin.Context, id string, input *ai_dto.UpdateConfig) error
UpdateProviderDefaultLLM(ctx *gin.Context, id string, input *ai_dto.UpdateLLM) error
}
func init() {
autowire.Auto[IProviderController](func() reflect.Value {
return reflect.ValueOf(&imlProviderController{})
})
}
+47
View File
@@ -0,0 +1,47 @@
package ai
import (
"github.com/APIParkLab/APIPark/module/ai"
ai_dto "github.com/APIParkLab/APIPark/module/ai/dto"
"github.com/gin-gonic/gin"
)
var (
_ IProviderController = (*imlProviderController)(nil)
)
type imlProviderController struct {
module ai.IProviderModule `autowired:""`
}
func (i *imlProviderController) SimpleProviders(ctx *gin.Context) ([]*ai_dto.SimpleProviderItem, error) {
return i.module.SimpleProviders(ctx)
}
func (i *imlProviderController) Providers(ctx *gin.Context) ([]*ai_dto.ProviderItem, error) {
return i.module.Providers(ctx)
}
func (i *imlProviderController) Provider(ctx *gin.Context, id string) (*ai_dto.Provider, error) {
return i.module.Provider(ctx, id)
}
func (i *imlProviderController) LLMs(ctx *gin.Context, driver string) ([]*ai_dto.LLMItem, error) {
return i.module.LLMs(ctx, driver)
}
func (i *imlProviderController) Enable(ctx *gin.Context, id string) error {
return i.module.UpdateProviderStatus(ctx, id, true)
}
func (i *imlProviderController) Disable(ctx *gin.Context, id string) error {
return i.module.UpdateProviderStatus(ctx, id, false)
}
func (i *imlProviderController) UpdateProviderConfig(ctx *gin.Context, id string, input *ai_dto.UpdateConfig) error {
return i.module.UpdateProviderConfig(ctx, id, input)
}
func (i *imlProviderController) UpdateProviderDefaultLLM(ctx *gin.Context, id string, input *ai_dto.UpdateLLM) error {
return i.module.UpdateProviderDefaultLLM(ctx, id, input)
}
+1 -11
View File
@@ -11,10 +11,9 @@ require (
github.com/gabriel-vasile/mimetype v1.4.4
github.com/getkin/kin-openapi v0.127.0
github.com/gin-gonic/gin v1.10.0
github.com/go-openapi/loads v0.22.0
github.com/go-openapi/validate v0.24.0
github.com/google/uuid v1.6.0
github.com/influxdata/influxdb-client-go/v2 v2.14.0
github.com/sashabaranov/go-openai v1.30.3
github.com/urfave/cli/v2 v2.27.2
golang.org/x/crypto v0.24.0
gopkg.in/yaml.v3 v3.0.1
@@ -23,7 +22,6 @@ require (
require (
github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
github.com/bytedance/sonic v1.11.6 // indirect
github.com/bytedance/sonic/loader v0.1.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
@@ -35,12 +33,7 @@ require (
github.com/ghodss/yaml v1.0.0 // indirect
github.com/gin-contrib/gzip v1.0.1 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-openapi/analysis v0.23.0 // indirect
github.com/go-openapi/errors v0.22.0 // indirect
github.com/go-openapi/jsonpointer v0.21.0 // indirect
github.com/go-openapi/jsonreference v0.21.0 // indirect
github.com/go-openapi/spec v0.21.0 // indirect
github.com/go-openapi/strfmt v0.23.0 // indirect
github.com/go-openapi/swag v0.23.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
@@ -59,12 +52,10 @@ require (
github.com/leodido/go-urn v1.4.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
github.com/oapi-codegen/runtime v1.0.0 // indirect
github.com/oklog/ulid v1.3.1 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/perimeterx/marshmallow v1.1.5 // indirect
github.com/pkg/errors v0.9.1 // indirect
@@ -74,7 +65,6 @@ require (
github.com/ugorji/go/codec v1.2.12 // indirect
github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 // indirect
go.etcd.io/etcd/client/pkg/v3 v3.5.13 // indirect
go.mongodb.org/mongo-driver v1.14.0 // indirect
go.uber.org/atomic v1.7.0 // indirect
go.uber.org/multierr v1.6.0 // indirect
go.uber.org/zap v1.23.0 // indirect
+2 -22
View File
@@ -1,8 +1,6 @@
github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk=
github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ=
github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk=
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
@@ -47,24 +45,10 @@ github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
github.com/go-openapi/analysis v0.23.0 h1:aGday7OWupfMs+LbmLZG4k0MYXIANxcuBTYUC03zFCU=
github.com/go-openapi/analysis v0.23.0/go.mod h1:9mz9ZWaSlV8TvjQHLl2mUW2PbZtemkE8yA5v22ohupo=
github.com/go-openapi/errors v0.22.0 h1:c4xY/OLxUBSTiepAg3j/MHuAv5mJhnf53LLMWFB+u/w=
github.com/go-openapi/errors v0.22.0/go.mod h1:J3DmZScxCDufmIMsdOuDHxJbdOGC0xtUynjIx092vXE=
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4=
github.com/go-openapi/loads v0.22.0 h1:ECPGd4jX1U6NApCGG1We+uEozOAvXvJSF4nnwHZ8Aco=
github.com/go-openapi/loads v0.22.0/go.mod h1:yLsaTCS92mnSAZX5WWoxszLj0u+Ojl+Zs5Stn1oF+rs=
github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY=
github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk=
github.com/go-openapi/strfmt v0.23.0 h1:nlUS6BCqcnAk0pyhi9Y+kdDVZdZMHfEKQiS4HaMgO/c=
github.com/go-openapi/strfmt v0.23.0/go.mod h1:NrtIpfKtWIygRkKVsxh7XQMDQW5HKQl6S5ik2elW+K4=
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
github.com/go-openapi/validate v0.24.0 h1:LdfDKwNbpB6Vn40xhTdNZAnfLECL81w+VX3BumrGD58=
github.com/go-openapi/validate v0.24.0/go.mod h1:iyeX1sEufmv3nPbBdX3ieNviWnOZaJ1+zquzJEf2BAQ=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
@@ -115,8 +99,6 @@ github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -126,8 +108,6 @@ github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
github.com/oapi-codegen/runtime v1.0.0 h1:P4rqFX5fMFWqRzY9M/3YF9+aPSPPB06IzP2P7oOxrWo=
github.com/oapi-codegen/runtime v1.0.0/go.mod h1:LmCUMQuPB4M/nLXilQXhHw+BLZdDb18B34OO356yJ/A=
github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s=
@@ -142,6 +122,8 @@ github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sashabaranov/go-openai v1.30.3 h1:TEdRP3otRXX2A7vLoU+kI5XpoSo7VUUlM/rEttUqgek=
github.com/sashabaranov/go-openai v1.30.3/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg=
github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
@@ -165,8 +147,6 @@ github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 h1:+qGGcbkzsfDQNPPe
github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913/go.mod h1:4aEEwZQutDLsQv2Deui4iYQ6DWTxR14g6m8Wv88+Xqk=
go.etcd.io/etcd/client/pkg/v3 v3.5.13 h1:RVZSAnWWWiI5IrYAXjQorajncORbS0zI48LQlE2kQWg=
go.etcd.io/etcd/client/pkg/v3 v3.5.13/go.mod h1:XxHT4u1qU12E2+po+UVPrEeL94Um6zL58ppuJWXSAB8=
go.mongodb.org/mongo-driver v1.14.0 h1:P98w8egYRjYe3XDjxhYJagTokP/H6HzlsnojRgZRd80=
go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c=
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
+9
View File
@@ -0,0 +1,9 @@
package ai_dto
type UpdateLLM struct {
LLM string `json:"llm"`
}
type UpdateConfig struct {
Config string `json:"config"`
}
+30
View File
@@ -0,0 +1,30 @@
package ai_dto
type Provider struct {
Id string `json:"id"`
Name string `json:"name"`
Config string `json:"config"`
GetAPIKeyUrl string `json:"get_apikey_url"`
}
type ProviderItem struct {
Id string `json:"id"`
Name string `json:"name"`
DefaultLLM string `json:"default_llm"`
Logo string `json:"logo"`
//Enable bool `json:"enable"`
Configured bool `json:"configured"`
}
type SimpleProviderItem struct {
Id string `json:"id"`
Name string `json:"name"`
Logo string `json:"logo"`
Configured bool `json:"configured"`
}
type LLMItem struct {
Id string `json:"id"`
Logo string `json:"logo"`
Scopes []string `json:"scopes"`
}
+194
View File
@@ -0,0 +1,194 @@
package ai
import (
"context"
"errors"
"fmt"
ai_dto "github.com/APIParkLab/APIPark/module/ai/dto"
"github.com/APIParkLab/APIPark/module/ai/provider"
"github.com/APIParkLab/APIPark/service/ai"
"github.com/eolinker/go-common/utils"
"gorm.io/gorm"
"sort"
)
var _ IProviderModule = (*imlProviderModule)(nil)
type imlProviderModule struct {
providerService ai.IProviderService `autowired:""`
}
func (i *imlProviderModule) SimpleProviders(ctx context.Context) ([]*ai_dto.SimpleProviderItem, error) {
list, err := i.providerService.List(ctx)
if err != nil {
return nil, err
}
providers := provider.Providers()
sort.SliceIsSorted(providers, func(i, j int) bool {
return providers[i].Index() < providers[j].Index()
})
providerMap := utils.SliceToMap(list, func(e *ai.Provider) string {
return e.Id
})
items := make([]*ai_dto.SimpleProviderItem, 0, len(providers))
for _, v := range providers {
item := &ai_dto.SimpleProviderItem{
Id: v.Info().Id,
Name: v.Info().Name,
Logo: v.Info().Logo,
}
if info, has := providerMap[v.Info().Id]; has {
err = v.GlobalConfig().CheckConfig(info.Config)
if err == nil {
item.Configured = true
}
}
items = append(items, item)
}
return items, nil
}
func (i *imlProviderModule) Providers(ctx context.Context) ([]*ai_dto.ProviderItem, error) {
list, err := i.providerService.List(ctx)
if err != nil {
return nil, err
}
providers := provider.Providers()
sort.SliceIsSorted(providers, func(i, j int) bool {
return providers[i].Index() < providers[j].Index()
})
providerMap := utils.SliceToMap(list, func(e *ai.Provider) string {
return e.Id
})
items := make([]*ai_dto.ProviderItem, 0, len(providers))
for _, v := range providers {
item := &ai_dto.ProviderItem{
Id: v.Info().Id,
Name: v.Info().Name,
Logo: v.Info().Logo,
DefaultLLM: v.Info().DefaultLLM,
}
if info, has := providerMap[v.Info().Id]; has {
//item.Enable = info.Status
err = v.GlobalConfig().CheckConfig(info.Config)
if err == nil {
item.Configured = true
}
}
items = append(items, item)
}
return items, nil
}
func (i *imlProviderModule) Provider(ctx context.Context, id string) (*ai_dto.Provider, error) {
p, has := provider.GetProvider(id)
if !has {
return nil, fmt.Errorf("ai provider not found")
}
info, err := i.providerService.Get(ctx, id)
if err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) {
return nil, err
}
return &ai_dto.Provider{
Id: p.Info().Id,
Name: p.Info().Name,
Config: p.GlobalConfig().DefaultConfig(),
GetAPIKeyUrl: p.Info().GetAPIKeyUrl,
}, nil
}
return &ai_dto.Provider{
Id: info.Id,
Name: info.Name,
Config: p.GlobalConfig().MaskConfig(info.Config),
GetAPIKeyUrl: p.Info().GetAPIKeyUrl,
}, nil
}
func (i *imlProviderModule) LLMs(ctx context.Context, driver string) ([]*ai_dto.LLMItem, error) {
p, has := provider.GetProvider(driver)
if !has {
return nil, fmt.Errorf("ai provider not found")
}
llms := p.LLMs()
items := make([]*ai_dto.LLMItem, 0, len(llms))
for _, v := range llms {
items = append(items, &ai_dto.LLMItem{
Id: v.Id,
Logo: v.Logo,
Scopes: v.Scopes,
})
}
return items, nil
}
func (i *imlProviderModule) UpdateProviderStatus(ctx context.Context, id string, enable bool) error {
_, err := i.providerService.Get(ctx, id)
if err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) {
return err
}
p, has := provider.GetProvider(id)
if !has {
return fmt.Errorf("ai provider not found")
}
cfg := p.GlobalConfig().DefaultConfig()
return i.providerService.Save(ctx, id, &ai.SetProvider{
Name: &p.Info().Name,
DefaultLLM: &p.Info().DefaultLLM,
Config: &cfg,
Status: &enable,
})
}
return i.providerService.Save(ctx, id, &ai.SetProvider{
Status: &enable,
})
}
func (i *imlProviderModule) UpdateProviderConfig(ctx context.Context, id string, input *ai_dto.UpdateConfig) error {
_, err := i.providerService.Get(ctx, id)
if err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) {
return err
}
p, has := provider.GetProvider(id)
if !has {
return fmt.Errorf("ai provider not found")
}
return i.providerService.Save(ctx, id, &ai.SetProvider{
Name: &p.Info().Name,
DefaultLLM: &p.Info().DefaultLLM,
Config: &input.Config,
})
}
return i.providerService.Save(ctx, id, &ai.SetProvider{
Config: &input.Config,
})
}
func (i *imlProviderModule) UpdateProviderDefaultLLM(ctx context.Context, id string, input *ai_dto.UpdateLLM) error {
_, err := i.providerService.Get(ctx, id)
if err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) {
return err
}
p, has := provider.GetProvider(id)
if !has {
return fmt.Errorf("ai provider not found")
}
cfg := p.GlobalConfig().DefaultConfig()
return i.providerService.Save(ctx, id, &ai.SetProvider{
Name: &p.Info().Name,
DefaultLLM: &input.LLM,
Config: &cfg,
})
}
return i.providerService.Save(ctx, id, &ai.SetProvider{
DefaultLLM: &input.LLM,
})
}
+26
View File
@@ -0,0 +1,26 @@
package ai
import (
"context"
ai_dto "github.com/APIParkLab/APIPark/module/ai/dto"
"github.com/APIParkLab/APIPark/module/ai/provider/openAI"
"github.com/eolinker/go-common/autowire"
"reflect"
)
type IProviderModule interface {
Providers(ctx context.Context) ([]*ai_dto.ProviderItem, error)
SimpleProviders(ctx context.Context) ([]*ai_dto.SimpleProviderItem, error)
Provider(ctx context.Context, id string) (*ai_dto.Provider, error)
LLMs(ctx context.Context, driver string) ([]*ai_dto.LLMItem, error)
UpdateProviderStatus(ctx context.Context, id string, enable bool) error
UpdateProviderConfig(ctx context.Context, id string, input *ai_dto.UpdateConfig) error
UpdateProviderDefaultLLM(ctx context.Context, id string, input *ai_dto.UpdateLLM) error
}
func init() {
openAI.Register()
autowire.Auto[IProviderModule](func() reflect.Value {
return reflect.ValueOf(&imlProviderModule{})
})
}
+7
View File
@@ -0,0 +1,7 @@
package provider
import "errors"
var (
ErrInvalidAPIKey = errors.New("invalid api key")
)
+43
View File
@@ -0,0 +1,43 @@
package provider
import "github.com/eolinker/eosc"
var (
defaultManager = NewManager()
)
type Manager struct {
providers eosc.Untyped[string, IAIProvider]
}
func NewManager() *Manager {
return &Manager{providers: eosc.BuildUntyped[string, IAIProvider]()}
}
func (m *Manager) Set(name string, driver IAIProvider) {
m.providers.Set(name, driver)
}
func (m *Manager) Get(name string) (IAIProvider, bool) {
return m.providers.Get(name)
}
func (m *Manager) Del(name string) {
m.providers.Del(name)
}
func (m *Manager) List() []IAIProvider {
return m.providers.List()
}
func Register(name string, driver IAIProvider) {
defaultManager.Set(name, driver)
}
func GetProvider(name string) (IAIProvider, bool) {
return defaultManager.Get(name)
}
func Providers() []IAIProvider {
return defaultManager.List()
}
+132
View File
@@ -0,0 +1,132 @@
package openAI
import (
"encoding/json"
"fmt"
"github.com/APIParkLab/APIPark/module/ai/provider"
openai "github.com/sashabaranov/go-openai"
"net/url"
)
type GlobalConfig struct {
APIKey string `json:"api_key"`
BaseUrl string `json:"base_url"`
}
type GlobalConfigDriver struct {
}
func NewGlobalConfigDriver() provider.IAIConfig {
return &GlobalConfigDriver{}
}
func (g *GlobalConfigDriver) CheckConfig(cfg string) error {
var c GlobalConfig
err := json.Unmarshal([]byte(cfg), &c)
if err != nil {
return err
}
if c.APIKey == "" {
return provider.ErrInvalidAPIKey
}
if c.APIKey == defaultAPIKey {
return fmt.Errorf("unconfigued api key")
}
if c.BaseUrl != "" {
u, err := url.Parse(c.BaseUrl)
if err != nil || u.Scheme == "" || u.Host == "" {
return fmt.Errorf("invalid base url: %s", c.BaseUrl)
}
}
return nil
}
var defaultAPIKey = "Your Open AI API Key"
func (g *GlobalConfigDriver) DefaultConfig() string {
return fmt.Sprintf(`{
"api_key":"%s",
"base_url":""
}`, defaultAPIKey)
}
func (g *GlobalConfigDriver) MaskConfig(cfg string) string {
c := new(GlobalConfig)
err := json.Unmarshal([]byte(cfg), c)
if err != nil {
return cfg
}
if c.APIKey != defaultAPIKey {
c.APIKey = provider.PartialMasking(c.APIKey, 5, 15)
}
result, _ := json.Marshal(c)
return string(result)
}
type InvokeConfig struct {
Temperature *float32 `json:"temperature"`
TopP *float32 `json:"top_p"`
PresencePenalty *float32 `json:"presence_penalty"`
FrequencyPenalty *float32 `json:"frequency_penalty"`
MaxTokens *int `json:"max_tokens"`
ResponseFormat *openai.ChatCompletionResponseFormat `json:"response_format"`
}
type InvokeConfigDriver struct {
}
func NewInvokeConfigDriver() provider.IAIConfig {
return &InvokeConfigDriver{}
}
var validResponseFormat = map[openai.ChatCompletionResponseFormatType]struct{}{
openai.ChatCompletionResponseFormatTypeText: {},
openai.ChatCompletionResponseFormatTypeJSONObject: {},
}
func (i *InvokeConfigDriver) CheckConfig(cfg string) error {
var c InvokeConfig
err := json.Unmarshal([]byte(cfg), &c)
if err != nil {
return err
}
if c.Temperature != nil && (*c.Temperature < 0 || *c.Temperature > 2) {
return fmt.Errorf("invalid temperature: %f", c.Temperature)
}
if c.TopP != nil && (*c.TopP < 0 || *c.TopP > 1) {
return fmt.Errorf("invalid top_p: %f", c.TopP)
}
if c.PresencePenalty != nil && (*c.PresencePenalty < 0 || *c.PresencePenalty > 1) {
return fmt.Errorf("invalid presence_penalty: %f", c.PresencePenalty)
}
if c.FrequencyPenalty != nil && (*c.FrequencyPenalty < 0 || *c.FrequencyPenalty > 1) {
return fmt.Errorf("invalid frequency_penalty: %f", c.FrequencyPenalty)
}
if c.MaxTokens != nil && (*c.MaxTokens < 0) {
return fmt.Errorf("invalid max_tokens: %d", c.MaxTokens)
}
if c.ResponseFormat != nil {
if _, ok := validResponseFormat[c.ResponseFormat.Type]; !ok {
return fmt.Errorf("invalid response_format: %v", c.ResponseFormat)
}
}
return nil
}
func (i *InvokeConfigDriver) DefaultConfig() string {
return `{
"temperature": 0,
"top_p": 1,
"presence_penalty": 0,
"frequency_penalty": 0,
"max_tokens": 512,
"response_format": {
"type": "json_object"
}
}`
}
func (i *InvokeConfigDriver) MaskConfig(cfg string) string {
return cfg
}
+99
View File
@@ -0,0 +1,99 @@
package openAI
import (
_ "embed"
"encoding/json"
"github.com/APIParkLab/APIPark/module/ai/provider"
"sync"
)
func Register() {
provider.Register("openai", NewModel())
}
var (
//go:embed model.json
modelJson []byte
)
type ModelData struct {
Id string `json:"id"`
OwnedBy string `json:"owned_by"`
Logo string `json:"logo"`
Scopes []string `json:"scopes"`
Features []string `json:"features"`
}
type Model struct {
globalConfig provider.IAIConfig
invokeConfig provider.IAIConfig
models []*ModelData
locker sync.RWMutex
}
func NewModel() provider.IAIProvider {
modelData := make([]*ModelData, 0)
json.Unmarshal(modelJson, &modelData)
return &Model{
globalConfig: NewGlobalConfigDriver(),
invokeConfig: NewInvokeConfigDriver(),
models: modelData,
locker: sync.RWMutex{},
}
}
func (m *Model) Index() int {
return 1
}
func (m *Model) Info() *provider.Info {
return &provider.Info{
Id: "openai",
Name: "OpenAI",
Logo: `<svg width="80" height="22" viewBox="0 0 80 22" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Group">
<path id="Vector" d="M25.1152 10.5768C25.1152 14.1739 27.4253 16.6819 30.6264 16.6819C33.8274 16.6819 36.1375 14.1739 36.1375 10.5768C36.1375 6.97973 33.8274 4.47168 30.6264 4.47168C27.4253 4.47168 25.1152 6.97973 25.1152 10.5768ZM34.0254 10.5768C34.0254 13.1509 32.6229 14.8174 30.6264 14.8174C28.6298 14.8174 27.2273 13.1509 27.2273 10.5768C27.2273 8.00275 28.6298 6.33622 30.6264 6.33622C32.6229 6.33622 34.0254 8.00275 34.0254 10.5768Z" fill="black"/>
<path id="Vector_2" d="M42.0868 16.682C44.5124 16.682 45.8984 14.636 45.8984 12.1774C45.8984 9.71889 44.5124 7.67285 42.0868 7.67285C40.9648 7.67285 40.1398 8.11836 39.5953 8.76188V7.83786H37.6152V19.4706H39.5953V15.593C40.1398 16.2365 40.9648 16.682 42.0868 16.682ZM39.5458 11.9299C39.5458 10.2964 40.4698 9.40539 41.6908 9.40539C43.1264 9.40539 43.9019 10.5274 43.9019 12.1774C43.9019 13.8275 43.1264 14.9495 41.6908 14.9495C40.4698 14.9495 39.5458 14.042 39.5458 12.4415V11.9299Z" fill="black"/>
<path id="Vector_3" d="M51.2545 16.682C52.987 16.682 54.3565 15.7745 54.967 14.2565L53.2675 13.613C53.0035 14.504 52.228 14.999 51.2545 14.999C49.9839 14.999 49.0929 14.0915 48.9444 12.6065H55.0165V11.9464C55.0165 9.57039 53.68 7.67285 51.172 7.67285C48.6639 7.67285 47.0469 9.63639 47.0469 12.1774C47.0469 14.8505 48.7794 16.682 51.2545 16.682ZM51.1555 9.33939C52.4095 9.33939 53.0035 10.1644 53.02 11.1214H49.0434C49.3404 9.9499 50.1324 9.33939 51.1555 9.33939Z" fill="black"/>
<path id="Vector_4" d="M56.5038 16.5005H58.4838V11.4184C58.4838 10.1809 59.3913 9.52089 60.2824 9.52089C61.3714 9.52089 61.8004 10.2964 61.8004 11.3689V16.5005H63.7804V10.7914C63.7804 8.92688 62.6914 7.67285 60.8764 7.67285C59.7544 7.67285 58.9788 8.18436 58.4838 8.76188V7.83786H56.5038V16.5005Z" fill="black"/>
<path id="Vector_5" d="M69.5799 4.65332L65.0918 16.5006H67.1873L68.1939 13.7945H73.309L74.332 16.5006H76.4605L71.9724 4.65332H69.5799ZM70.7349 6.99637L72.616 11.9465H68.8869L70.7349 6.99637Z" fill="black"/>
<path id="Vector_6" d="M79.8581 4.6875H77.7461V16.5348H79.8581V4.6875Z" fill="black"/>
<path id="Vector_7" d="M20.2769 9.00448C20.776 7.50639 20.6041 5.86529 19.8059 4.50264C18.6055 2.41259 16.1924 1.33732 13.8356 1.84333C12.7871 0.662179 11.2808 -0.00952316 9.70154 0.000102043C7.29248 -0.00539807 5.155 1.54563 4.41386 3.83781C2.86626 4.15475 1.53042 5.12346 0.748717 6.49643C-0.460621 8.58097 -0.184928 11.2087 1.43073 12.9962C0.931596 14.4943 1.10348 16.1354 1.90168 17.498C3.10208 19.5881 5.51526 20.6634 7.87206 20.1573C8.91983 21.3385 10.4269 22.0102 12.0061 21.9999C14.4165 22.0061 16.5547 20.4537 17.2958 18.1594C18.8434 17.8425 20.1793 16.8738 20.961 15.5008C22.1689 13.4163 21.8925 10.7906 20.2776 9.00311L20.2769 9.00448ZM12.0075 20.5623C11.0429 20.5637 10.1085 20.2261 9.36809 19.608C9.40178 19.5901 9.46022 19.5578 9.49803 19.5345L13.8789 17.0044C14.103 16.8772 14.2405 16.6386 14.2391 16.3808V10.2049L16.0906 11.274C16.1105 11.2836 16.1236 11.3028 16.1264 11.3248V16.4393C16.1236 18.7136 14.2818 20.5575 12.0075 20.5623ZM3.14952 16.7789C2.6662 15.9443 2.49225 14.9659 2.65795 14.0165C2.69026 14.0357 2.74732 14.0708 2.78789 14.0942L7.16873 16.6242C7.3908 16.7541 7.6658 16.7541 7.88856 16.6242L13.2367 13.5359V15.6741C13.2381 15.6961 13.2278 15.7174 13.2106 15.7311L8.78233 18.288C6.80985 19.4238 4.29079 18.7486 3.15021 16.7789H3.14952ZM1.99656 7.21626C2.47782 6.38024 3.23752 5.74085 4.14229 5.40878C4.14229 5.44659 4.14023 5.51328 4.14023 5.56003V10.6208C4.13885 10.878 4.27636 11.1165 4.4998 11.2437L9.84798 14.3313L7.9965 15.4004C7.97794 15.4128 7.95456 15.4149 7.93393 15.4059L3.50496 12.847C1.53661 11.7071 0.86147 9.18874 1.99587 7.21694L1.99656 7.21626ZM17.2085 10.7563L11.8603 7.66795L13.7118 6.59956C13.7304 6.58718 13.7537 6.58512 13.7744 6.59406L18.2033 9.15092C20.1751 10.2901 20.851 12.8126 19.7118 14.7844C19.2298 15.6191 18.4708 16.2584 17.5667 16.5912V11.3792C17.5688 11.122 17.432 10.8841 17.2092 10.7563H17.2085ZM19.0511 7.98284C19.0187 7.9629 18.9617 7.92852 18.9211 7.90515L14.5403 5.37509C14.3182 5.24515 14.0432 5.24515 13.8204 5.37509L8.47226 8.46341V6.32524C8.47088 6.30324 8.4812 6.28192 8.49838 6.26817L12.9267 3.71337C14.8991 2.57553 17.4209 3.25273 18.5581 5.2259C19.0387 6.05917 19.2126 7.03475 19.0497 7.98284H19.0511ZM7.46574 11.7937L5.61357 10.7246C5.59363 10.715 5.58057 10.6958 5.57782 10.6738V5.55935C5.5792 3.2823 7.42655 1.43701 9.7036 1.43838C10.6668 1.43838 11.5991 1.77664 12.3395 2.39265C12.3058 2.41053 12.2481 2.44284 12.2096 2.46622L7.82874 4.99627C7.60461 5.12346 7.46711 5.36134 7.46849 5.61916L7.46574 11.7924V11.7937ZM8.47157 9.62531L10.8538 8.24959L13.236 9.62462V12.3754L10.8538 13.7504L8.47157 12.3754V9.62531Z" fill="black"/>
</g>
</svg>
`,
GetAPIKeyUrl: "https://platform.openai.com/account/api-keys",
DefaultLLM: "gpt-3.5-turbo",
}
}
func (m *Model) GlobalConfig() provider.IAIConfig {
return m.globalConfig
}
func (m *Model) InvokeConfig() provider.IAIConfig {
return m.invokeConfig
}
func (m *Model) UpdateLLMs() error {
m.locker.Lock()
defer m.locker.Unlock()
// TODO: 后续需要实现自动更新llm逻辑
return nil
}
func (m *Model) LLMs() []*provider.LLM {
m.locker.RLock()
models := m.models
m.locker.RUnlock()
result := make([]*provider.LLM, 0, len(models))
for _, model := range models {
llm := &provider.LLM{
Id: model.Id,
Logo: model.Logo,
Scopes: model.Scopes,
}
result = append(result, llm)
}
return result
}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+69
View File
@@ -0,0 +1,69 @@
package provider
import "strings"
//type ModelScope string
//
//func (m ModelScope) String() string {
// return string(m)
//}
//
//const (
// ModelScopeChat ModelScope = "chat"
//)
type IAIProvider interface {
Index() int
Info() *Info
GlobalConfig() IAIConfig
InvokeConfig() IAIConfig
UpdateLLMs() error
LLMs() []*LLM
}
type IAIConfig interface {
CheckConfig(cfg string) error
DefaultConfig() string
MaskConfig(cfg string) string
}
type Info struct {
Id string
Name string
Logo string
DefaultLLM string
GetAPIKeyUrl string
}
type LLM struct {
Id string
Logo string
Scopes []string
}
func PartialMasking(origin string, begin int, length int) string {
target := strings.Builder{}
runes := []rune(origin)
size := len(runes)
if begin > size {
return origin
} else if length == -1 || begin+length > size {
for i := 0; i < begin; i++ {
target.WriteRune(runes[i])
}
for i := begin; i < size; i++ {
target.WriteRune('*')
}
} else {
for i := 0; i < begin; i++ {
target.WriteRune(runes[i])
}
for i := begin; i < begin+length; i++ {
target.WriteRune('*')
}
for i := begin + length; i < size; i++ {
target.WriteRune(runes[i])
}
}
return target.String()
}
+19
View File
@@ -0,0 +1,19 @@
package core
import (
"github.com/eolinker/go-common/pm3"
"net/http"
)
func (p *plugin) aiAPIs() []pm3.Api {
return []pm3.Api{
pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/ai/providers", []string{"context"}, []string{"providers"}, p.aiProviderController.Providers),
pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/simple/ai/providers", []string{"context"}, []string{"providers"}, p.aiProviderController.SimpleProviders),
pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/ai/provider/config", []string{"context", "query:provider"}, []string{"provider"}, p.aiProviderController.Provider),
pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/ai/provider/llms", []string{"context", "query:provider"}, []string{"llms"}, p.aiProviderController.LLMs),
//pm3.CreateApiWidthDoc(http.MethodPut, "/api/v1/ai/provider/enable", []string{"context", "query:provider"}, nil, p.aiProviderController.Enable),
//pm3.CreateApiWidthDoc(http.MethodPut, "/api/v1/ai/provider/disable", []string{"context", "query:provider"}, nil, p.aiProviderController.Disable),
pm3.CreateApiWidthDoc(http.MethodPut, "/api/v1/ai/provider/config", []string{"context", "query:provider", "body"}, nil, p.aiProviderController.UpdateProviderConfig),
pm3.CreateApiWidthDoc(http.MethodPut, "/api/v1/ai/provider/default-llm", []string{"context", "query:provider", "body"}, nil, p.aiProviderController.UpdateProviderDefaultLLM),
}
}
+3
View File
@@ -1,6 +1,7 @@
package core
import (
"github.com/APIParkLab/APIPark/controller/ai"
"github.com/APIParkLab/APIPark/controller/monitor"
"github.com/APIParkLab/APIPark/controller/router"
"github.com/APIParkLab/APIPark/controller/system"
@@ -77,6 +78,7 @@ type plugin struct {
commonController common.ICommonController `autowired:""`
exportConfigController system.IExportConfigController `autowired:""`
importConfigController system.IImportConfigController `autowired:""`
aiProviderController ai.IProviderController `autowired:""`
apis []pm3.Api
}
@@ -97,6 +99,7 @@ func (p *plugin) OnComplete() {
p.apis = append(p.apis, p.PartitionPluginApi()...)
p.apis = append(p.apis, p.commonApis()...)
p.apis = append(p.apis, p.systemApis()...)
p.apis = append(p.apis, p.aiAPIs()...)
}
func (p *plugin) Name() string {
+79
View File
@@ -0,0 +1,79 @@
package ai
import (
"context"
"encoding/base64"
"errors"
"github.com/APIParkLab/APIPark/service/universally"
"github.com/APIParkLab/APIPark/stores/ai"
"github.com/eolinker/go-common/auto"
"github.com/eolinker/go-common/utils"
"gorm.io/gorm"
"time"
)
var _ IProviderService = (*imlProviderService)(nil)
type imlProviderService struct {
universally.IServiceGet[Provider]
store ai.IProviderStore `autowired:""`
}
func (i *imlProviderService) Save(ctx context.Context, id string, cfg *SetProvider) error {
userId := utils.UserId(ctx)
now := time.Now()
info, err := i.store.First(ctx, map[string]interface{}{"uuid": id})
if err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) {
return err
}
if cfg.Name == nil || cfg.Config == nil || cfg.DefaultLLM == nil || cfg.Status == nil {
return errors.New("invalid params")
}
info = &ai.Provider{
UUID: id,
Name: *cfg.Name,
DefaultLLM: *cfg.DefaultLLM,
Config: base64.RawStdEncoding.EncodeToString([]byte(*cfg.Config)),
Status: *cfg.Status,
Creator: userId,
Updater: userId,
CreateAt: now,
UpdateAt: now,
}
} else {
if cfg.Name != nil {
info.Name = *cfg.Name
}
if cfg.Config != nil {
info.Config = base64.RawStdEncoding.EncodeToString([]byte(*cfg.Config))
}
if cfg.DefaultLLM != nil {
info.DefaultLLM = *cfg.DefaultLLM
}
if cfg.Status != nil {
info.Status = *cfg.Status
}
info.Updater = userId
info.UpdateAt = now
}
return i.store.Save(ctx, info)
}
func (i *imlProviderService) GetLabels(ctx context.Context, ids ...string) map[string]string {
if len(ids) == 0 {
return nil
}
list, err := i.store.ListQuery(ctx, "`uuid` in (?)", []interface{}{ids}, "id")
if err != nil {
return nil
}
return utils.SliceToMapO(list, func(i *ai.Provider) (string, string) {
return i.UUID, i.Name
})
}
func (i *imlProviderService) OnComplete() {
i.IServiceGet = universally.NewGet[Provider, ai.Provider](i.store, FromEntity)
auto.RegisterService("ai_provider", i)
}
+44
View File
@@ -0,0 +1,44 @@
package ai
import (
"encoding/base64"
"github.com/APIParkLab/APIPark/stores/ai"
"time"
)
type Provider struct {
Id string
Name string
DefaultLLM string
Config string
Creator string
Updater string
Status bool
CreateAt time.Time
UpdateAt time.Time
}
type SetProvider struct {
Name *string
DefaultLLM *string
Config *string
Status *bool
}
func FromEntity(e *ai.Provider) *Provider {
config, err := base64.RawStdEncoding.DecodeString(e.Config)
if err != nil {
config = []byte(e.Config)
}
return &Provider{
Id: e.UUID,
Name: e.Name,
DefaultLLM: e.DefaultLLM,
Config: string(config),
Creator: e.Creator,
Updater: e.Updater,
CreateAt: e.CreateAt,
UpdateAt: e.UpdateAt,
Status: e.Status,
}
}
+19
View File
@@ -0,0 +1,19 @@
package ai
import (
"context"
"github.com/APIParkLab/APIPark/service/universally"
"github.com/eolinker/go-common/autowire"
"reflect"
)
type IProviderService interface {
universally.IServiceGet[Provider]
Save(ctx context.Context, id string, cfg *SetProvider) error
}
func init() {
autowire.Auto[IProviderService](func() reflect.Value {
return reflect.ValueOf(new(imlProviderService))
})
}
+24
View File
@@ -0,0 +1,24 @@
package ai
import "time"
type Provider struct {
Id int64 `gorm:"column:id;type:BIGINT(20);AUTO_INCREMENT;NOT NULL;comment:id;primary_key;comment:主键ID;"`
UUID string `gorm:"type:varchar(36);not null;column:uuid;uniqueIndex:uuid;comment:UUID;"`
Name string `gorm:"type:varchar(100);not null;column:name;comment:name"`
DefaultLLM string `gorm:"type:varchar(255);not null;column:default_llm;comment:默认模型ID"`
Config string `gorm:"type:text;not null;column:config;comment:配置信息"`
Status bool `gorm:"type:tinyint(1);not null;column:status;comment:状态"`
Creator string `gorm:"size:36;not null;column:creator;comment:创建人;index:creator" aovalue:"creator"` // 创建人
Updater string `gorm:"size:36;not null;column:updater;comment:更新人;index:updater" aovalue:"updater"` // 更新人
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;column:update_at;comment:更新时间"`
}
func (i *Provider) TableName() string {
return "ai_provider"
}
func (i *Provider) IdValue() int64 {
return i.Id
}
+21
View File
@@ -0,0 +1,21 @@
package ai
import (
"github.com/eolinker/go-common/autowire"
"github.com/eolinker/go-common/store"
"reflect"
)
type IProviderStore interface {
store.ISearchStore[Provider]
}
type imlProviderStore struct {
store.SearchStore[Provider]
}
func init() {
autowire.Auto[IProviderStore](func() reflect.Value {
return reflect.ValueOf(new(imlProviderStore))
})
}