apinto对接完成

This commit is contained in:
Liujian
2024-10-08 12:09:33 +08:00
parent 9783f77110
commit 2b48c779ef
30 changed files with 734 additions and 227 deletions
@@ -22,6 +22,7 @@ type Provider struct {
SupportedModelTypes []string `json:"supported_model_types" yaml:"supported_model_types"`
ProviderCredentialSchema ProviderCredentialSchema `json:"provider_credential_schema" yaml:"provider_credential_schema"`
Default map[string]string `json:"default"`
Address string `json:"address"`
}
type ProviderCredentialSchema struct {
+38
View File
@@ -2,6 +2,7 @@ package model_runtime
import (
"embed"
"encoding/json"
"fmt"
"github.com/eolinker/eosc"
"strings"
@@ -13,9 +14,46 @@ func init() {
type IConfig interface {
Check(cfg string) error
GenConfig(target string, origin string) (string, error)
DefaultConfig() string
}
func NewConfig(cfg string, validator IParamValidator) *Config {
return &Config{cfg: cfg, validator: validator}
}
type Config struct {
cfg string
validator IParamValidator
}
func (c *Config) Check(cfg string) error {
data := make(map[string]interface{})
err := json.Unmarshal([]byte(cfg), &data)
if err != nil {
return err
}
return c.validator.Valid(data)
}
func (c *Config) GenConfig(target string, origin string) (string, error) {
var targetData map[string]interface{}
err := json.Unmarshal([]byte(target), &targetData)
if err != nil {
return "", err
}
var originData map[string]interface{}
err = json.Unmarshal([]byte(origin), &originData)
if err != nil {
return "", err
}
return c.validator.GenConfig(targetData, originData)
}
func (c *Config) DefaultConfig() string {
return c.cfg
}
const (
DirAssets = "assets"
)
@@ -37,3 +37,4 @@ provider_credential_schema:
placeholder:
zh_Hans: 在此输入您的 API URL
en_US: Enter your API URL
address: https://api.openai.com
@@ -29,3 +29,4 @@ provider_credential_schema:
placeholder:
zh_Hans: 在此输入您的 API Key
en_US: Enter your API Key
address: https://api.openai.com
@@ -87,3 +87,4 @@ provider_credential_schema:
placeholder:
zh_Hans: 在此输入您的 API Base, 如:https://api.openai.com
en_US: Enter your API Base, e.g. https://api.openai.com
address: https://api.openai.com
+8 -21
View File
@@ -14,10 +14,11 @@ type IModel interface {
}
type Model struct {
id string
logo string
defaultConfig string
validator IParamValidator
id string
logo string
//defaultConfig string
IConfig
//validator IParamValidator
}
func (m *Model) ID() string {
@@ -28,19 +29,6 @@ func (m *Model) Logo() string {
return m.logo
}
func (m *Model) Check(cfg string) error {
data := make(map[string]interface{})
err := json.Unmarshal([]byte(cfg), &data)
if err != nil {
return err
}
return m.validator.Valid(data)
}
func (m *Model) DefaultConfig() string {
return m.defaultConfig
}
func NewModel(data string, logo string) (IModel, error) {
var cfg entity.AIModel
err := yaml.Unmarshal([]byte(data), &cfg)
@@ -112,9 +100,8 @@ func NewModel(data string, logo string) (IModel, error) {
return nil, err
}
return &Model{
id: cfg.Model,
logo: logo,
defaultConfig: string(dCfg),
validator: params,
id: cfg.Model,
logo: logo,
IConfig: NewConfig(string(dCfg), params),
}, nil
}
+33 -2
View File
@@ -1,6 +1,9 @@
package model_runtime
import "fmt"
import (
"encoding/json"
"fmt"
)
const (
ParameterTypeInt = "int"
@@ -11,10 +14,33 @@ const (
type IParamValidator interface {
Valid(map[string]interface{}) error
GenConfig(target map[string]interface{}, origin map[string]interface{}) (string, error)
}
type ParamValidator []Param
func (p ParamValidator) GenConfig(target map[string]interface{}, origin map[string]interface{}) (string, error) {
for _, rule := range p {
if !rule.Secret {
continue
}
vv, ok := origin[rule.Name]
if !ok {
continue
}
v, ok := vv.(string)
if !ok || v == "******" {
continue
}
target[rule.Name] = origin[rule.Name]
}
data, err := json.Marshal(target)
if err != nil {
return "", err
}
return string(data), nil
}
type Param struct {
Name string `json:"name" yaml:"name"`
Default interface{} `json:"default" yaml:"default"`
@@ -22,6 +48,7 @@ type Param struct {
Min float64 `json:"min" yaml:"min"`
Max float64 `json:"max" yaml:"max"`
Required bool `json:"required" yaml:"required"`
Secret bool `json:"secret" yaml:"secret"`
}
func (p ParamValidator) Valid(params map[string]interface{}) error {
@@ -52,10 +79,13 @@ func (p ParamValidator) Valid(params map[string]interface{}) error {
return fmt.Errorf("invalid parameter %s: %v", rule.Name, v)
}
case ParameterTypeStr:
_, ok = v.(string)
vv, ok := v.(string)
if !ok {
return fmt.Errorf("invalid parameter %s: %v", rule.Name, v)
}
if rule.Required && len(vv) == 0 {
return fmt.Errorf("parameter %s is empty", rule.Name)
}
case ParameterTypeBool:
_, ok = v.(bool)
if !ok {
@@ -64,4 +94,5 @@ func (p ParamValidator) Valid(params map[string]interface{}) error {
}
}
return nil
}
+74 -30
View File
@@ -6,6 +6,7 @@ import (
"github.com/APIParkLab/APIPark/ai-provider/model-runtime/entity"
"github.com/eolinker/eosc"
"gopkg.in/yaml.v3"
"net/url"
"strings"
)
@@ -22,12 +23,19 @@ type IProvider interface {
MaskConfig(cfg string) string
}
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) {
@@ -36,11 +44,15 @@ func NewProvider(providerData string, modelContents map[string]eosc.Untyped[stri
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, _ := assetsFiles.Get(providerCfg.IconLarge[entity.LanguageEnglish])
modelLogo, _ := assetsFiles.Get(providerCfg.IconSmall[entity.LanguageEnglish])
@@ -53,24 +65,27 @@ func NewProvider(providerData string, modelContents map[string]eosc.Untyped[stri
defaultModels: eosc.BuildUntyped[string, IModel](),
modelsByType: eosc.BuildUntyped[string, []IModel](),
maskKeys: make([]string, 0),
uri: uri,
}
defaultCfg := make(map[string]string)
params := make(ParamValidator, 0, len(providerCfg.ProviderCredentialSchema.CredentialFormSchemas))
for _, v := range providerCfg.ProviderCredentialSchema.CredentialFormSchemas {
params = append(params, Param{
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.defaultConfig = string(defaultCfgByte)
provider.paramValidator = params
provider.IConfig = NewConfig(string(defaultCfgByte), params)
for name, f := range modelContents {
models := make([]IModel, 0, f.Count())
defaultModel := providerCfg.Default[name]
@@ -90,20 +105,25 @@ func NewProvider(providerData string, modelContents map[string]eosc.Untyped[stri
}
provider.SetModelsByType(name, models)
}
return provider, nil
}
type Provider struct {
id string
name string
logo string
helpUrl string
defaultConfig string
paramValidator IParamValidator
models eosc.Untyped[string, IModel]
defaultModels eosc.Untyped[string, IModel]
modelsByType eosc.Untyped[string, []IModel]
maskKeys []string
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
IConfig
}
func (p *Provider) URI() IProviderURI {
return p.uri
}
func (p *Provider) ID() string {
@@ -138,19 +158,6 @@ func (p *Provider) ModelsByType(modelType string) ([]IModel, bool) {
return p.modelsByType.Get(modelType)
}
func (p *Provider) Check(cfg string) error {
data := make(map[string]interface{})
err := json.Unmarshal([]byte(cfg), &data)
if err != nil {
return err
}
return p.paramValidator.Valid(data)
}
func (p *Provider) DefaultConfig() string {
return p.defaultConfig
}
func (p *Provider) MaskConfig(cfg string) string {
var data map[string]string
err := json.Unmarshal([]byte(cfg), &data)
@@ -158,8 +165,8 @@ func (p *Provider) MaskConfig(cfg string) string {
return cfg
}
for _, key := range p.maskKeys {
if v, ok := data[key]; ok {
data[key] = PartialMasking(v, 4, -1)
if _, ok := data[key]; ok {
data[key] = "******"
}
}
result, _ := json.Marshal(data)
@@ -178,6 +185,43 @@ 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
}
func PartialMasking(origin string, begin int, length int) string {
target := strings.Builder{}
runes := []rune(origin)
+146 -4
View File
@@ -1,27 +1,169 @@
package ai_api
import (
"context"
"fmt"
"github.com/APIParkLab/APIPark/model/plugin_model"
ai_api "github.com/APIParkLab/APIPark/module/ai-api"
ai_api_dto "github.com/APIParkLab/APIPark/module/ai-api/dto"
"github.com/APIParkLab/APIPark/module/router"
router_dto "github.com/APIParkLab/APIPark/module/router/dto"
"github.com/APIParkLab/APIPark/module/service"
"github.com/APIParkLab/APIPark/service/api"
"github.com/eolinker/go-common/store"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
"net/http"
"strings"
)
var _ IAPIController = (*imlAPIController)(nil)
type imlAPIController struct {
module ai_api.IAPIModule `autowired:""`
module ai_api.IAPIModule `autowired:""`
routerModule router.IRouterModule `autowired:""`
serviceModule service.IServiceModule `autowired:""`
transaction store.ITransaction `autowired:""`
}
func (i *imlAPIController) Create(ctx *gin.Context, serviceId string, input *ai_api_dto.CreateAPI) (*ai_api_dto.API, error) {
return i.module.Create(ctx, serviceId, input)
info, err := i.serviceModule.Get(ctx, serviceId)
if err != nil {
return nil, err
}
if input.Id == "" {
input.Id = uuid.New().String()
}
err = i.transaction.Transaction(ctx, func(txCtx context.Context) error {
err = i.module.Create(ctx, serviceId, input)
if err != nil {
return err
}
plugins := make(map[string]api.PluginSetting)
if input.AiPrompt != nil {
plugins["ai_prompt"] = api.PluginSetting{
Config: plugin_model.ConfigType{
"prompt": input.AiPrompt.Prompt,
"variables": input.AiPrompt.Variables,
},
}
}
if input.AiModel != nil {
plugins["ai_formatter"] = api.PluginSetting{
Config: plugin_model.ConfigType{
"model": input.AiModel.Id,
"provider": fmt.Sprintf("%s@ai-provider", info.Provider.Id),
"config": input.AiModel.Config,
},
}
}
_, err = i.routerModule.Create(ctx, serviceId, &router_dto.Create{
Id: input.Id,
Path: input.Path,
Methods: []string{
http.MethodPost,
},
Description: input.Description,
Protocols: []string{"http", "https"},
MatchRules: nil,
Proxy: &router_dto.InputProxy{
Path: input.Path,
Timeout: input.Timeout,
Retry: input.Retry,
Plugins: plugins,
},
Disable: false,
})
return err
})
if err != nil {
return nil, err
}
return i.module.Get(ctx, serviceId, input.Id)
}
func (i *imlAPIController) Edit(ctx *gin.Context, serviceId string, apiId string, input *ai_api_dto.EditAPI) (*ai_api_dto.API, error) {
return i.module.Edit(ctx, serviceId, apiId, input)
info, err := i.serviceModule.Get(ctx, serviceId)
if err != nil {
return nil, err
}
err = i.transaction.Transaction(ctx, func(txCtx context.Context) error {
apiInfo, err := i.routerModule.Detail(ctx, serviceId, apiId)
if err != nil {
return err
}
proxy := &router_dto.InputProxy{
Path: apiInfo.Proxy.Path,
Timeout: apiInfo.Proxy.Timeout,
Retry: apiInfo.Proxy.Retry,
Plugins: apiInfo.Proxy.Plugins,
}
if input.AiModel != nil {
proxy.Plugins["ai_formatter"] = api.PluginSetting{
Config: plugin_model.ConfigType{
"model": input.AiModel.Id,
"provider": fmt.Sprintf("%s@ai-provider", info.Provider.Id),
"config": input.AiModel.Config,
},
}
}
if input.AiPrompt != nil {
proxy.Plugins["ai_prompt"] = api.PluginSetting{
Config: plugin_model.ConfigType{
"prompt": input.AiPrompt.Prompt,
"variables": input.AiPrompt.Variables,
},
}
}
path := apiInfo.Path
if input.Path != nil {
inputPath := *input.Path
prefix, err := i.module.Prefix(ctx, serviceId)
if err != nil {
return err
}
if !strings.HasSuffix(inputPath, prefix) {
if inputPath[0] != '/' {
inputPath = fmt.Sprintf("/%s", inputPath)
}
path = fmt.Sprintf("%s%s", prefix, inputPath)
} else {
path = inputPath
}
}
proxy.Path = path
input.Path = &path
_, err = i.routerModule.Edit(ctx, serviceId, apiId, &router_dto.Edit{
Description: input.Description,
Proxy: proxy,
Path: input.Path,
Disable: input.Disable,
Methods: &apiInfo.Methods,
})
if err != nil {
return err
}
return i.module.Edit(ctx, serviceId, apiId, input)
})
if err != nil {
return nil, err
}
return i.module.Get(ctx, serviceId, apiId)
}
func (i *imlAPIController) Delete(ctx *gin.Context, serviceId string, apiId string) error {
return i.module.Delete(ctx, serviceId, apiId)
return i.transaction.Transaction(ctx, func(txCtx context.Context) error {
err := i.routerModule.Delete(ctx, serviceId, apiId)
if err != nil {
return err
}
return i.module.Delete(ctx, serviceId, apiId)
})
}
func (i *imlAPIController) List(ctx *gin.Context, keyword string, serviceId string) ([]*ai_api_dto.APIItem, error) {
+94 -32
View File
@@ -1,12 +1,17 @@
package service
import (
"context"
"fmt"
model_runtime "github.com/APIParkLab/APIPark/ai-provider/model-runtime"
"github.com/APIParkLab/APIPark/module/ai"
ai_api "github.com/APIParkLab/APIPark/module/ai-api"
ai_api_dto "github.com/APIParkLab/APIPark/module/ai-api/dto"
"github.com/APIParkLab/APIPark/module/service"
service_dto "github.com/APIParkLab/APIPark/module/service/dto"
"github.com/APIParkLab/APIPark/module/upstream"
upstream_dto "github.com/APIParkLab/APIPark/module/upstream/dto"
"github.com/eolinker/go-common/store"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
"strings"
@@ -23,6 +28,56 @@ type imlServiceController struct {
docModule service.IServiceDocModule `autowired:""`
aiAPIModule ai_api.IAPIModule `autowired:""`
providerModule ai.IProviderModule `autowired:""`
upstreamModule upstream.IUpstreamModule `autowired:""`
transaction store.ITransaction `autowired:""`
}
func newAIUpstream(id string, provider string, uri model_runtime.IProviderURI) *upstream_dto.Upstream {
return &upstream_dto.Upstream{
Type: "http",
Balance: "round-robin",
Timeout: 300000,
Retry: 0,
Remark: fmt.Sprintf("auto create by ai service %s,provider is %s", id, provider),
LimitPeerSecond: 0,
ProxyHeaders: nil,
Scheme: uri.Scheme(),
PassHost: "node",
Nodes: []*upstream_dto.NodeConfig{
{
Address: uri.Host(),
Weight: 100,
},
},
}
}
func (i *imlServiceController) EditAIService(ctx *gin.Context, id string, input *service_dto.EditService) (*service_dto.Service, error) {
if input.Provider == nil {
return nil, fmt.Errorf("provider is required")
}
p, has := model_runtime.GetProvider(*input.Provider)
if !has {
return nil, fmt.Errorf("provider not found")
}
info, err := i.module.Get(ctx, id)
if err != nil {
}
err = i.transaction.Transaction(ctx, func(txCtx context.Context) error {
info, err = i.module.Edit(ctx, id, input)
if err != nil {
return err
}
_, err = i.upstreamModule.Save(ctx, id, newAIUpstream(id, *input.Provider, p.URI()))
return err
})
if err != nil {
return nil, err
}
return info, nil
}
func (i *imlServiceController) CreateAIService(ctx *gin.Context, teamID string, input *service_dto.CreateService) (*service_dto.Service, error) {
@@ -31,7 +86,7 @@ func (i *imlServiceController) CreateAIService(ctx *gin.Context, teamID string,
if input.Provider == nil {
return nil, fmt.Errorf("provider is required")
}
p, err := i.providerModule.Provider(ctx, *input.Provider)
pv, err := i.providerModule.Provider(ctx, *input.Provider)
if err != nil {
return nil, err
}
@@ -45,44 +100,51 @@ func (i *imlServiceController) CreateAIService(ctx *gin.Context, teamID string,
input.Prefix = input.Id[:8]
}
}
info, err := i.module.Create(ctx, teamID, input)
if err != nil {
return nil, err
p, has := model_runtime.GetProvider(*input.Provider)
if !has {
return nil, fmt.Errorf("provider not found")
}
_, err = i.aiAPIModule.Create(
ctx,
info.Id,
&ai_api_dto.CreateAPI{
Name: "Default API",
Path: fmt.Sprintf("/%s", strings.Trim(input.Prefix, "/")),
Description: "Default API for service",
Disable: false,
AiPrompt: &ai_api_dto.AiPrompt{
Variables: []*ai_api_dto.AiPromptVariable{
{
Key: "Query",
Description: "",
Require: true,
var info *service_dto.Service
err = i.transaction.Transaction(ctx, func(txCtx context.Context) error {
info, err = i.module.Create(ctx, teamID, input)
if err != nil {
return err
}
err = i.aiAPIModule.Create(
ctx,
info.Id,
&ai_api_dto.CreateAPI{
Name: "Default API",
Path: fmt.Sprintf("/%s", strings.Trim(input.Prefix, "/")),
Description: "Default API for service",
Disable: false,
AiPrompt: &ai_api_dto.AiPrompt{
Variables: []*ai_api_dto.AiPromptVariable{
{
Key: "Query",
Description: "",
Require: true,
},
},
Prompt: "{{Query}}",
},
Prompt: "{{Query}}",
AiModel: &ai_api_dto.AiModel{
Id: pv.DefaultLLM,
Config: pv.DefaultLLMConfig,
},
Timeout: 300000,
Retry: 0,
},
AiModel: &ai_api_dto.AiModel{
Id: p.DefaultLLM,
Config: p.DefaultLLMConfig,
},
Timeout: 300000,
Retry: 0,
},
)
if err != nil {
i.module.Delete(ctx, info.Id, "ai")
return nil, err
}
return info, nil
)
_, err = i.upstreamModule.Save(ctx, info.Id, newAIUpstream(info.Id, *input.Provider, p.URI()))
return err
})
return info, err
}
func (i *imlServiceController) DeleteAIService(ctx *gin.Context, id string) error {
// TODO: 检查是否有发布过版本,若发布,则不允许删除
return i.module.Delete(ctx, id, "ai")
}
+1 -5
View File
@@ -22,15 +22,11 @@ type IServiceController interface {
Edit(ctx *gin.Context, id string, input *service_dto.EditService) (*service_dto.Service, error)
// Delete 删除
Delete(ctx *gin.Context, id string) error
// Simple 获取简易列表
//Simple(ctx *gin.Context, keyword string) ([]*service_dto.SimpleServiceItem, error)
//// MySimple 获取我的简易列表
//MySimple(ctx *gin.Context, keyword string) ([]*service_dto.SimpleServiceItem, error)
ServiceDoc(ctx *gin.Context, id string) (*service_dto.ServiceDoc, error)
SaveServiceDoc(ctx *gin.Context, id string, input *service_dto.SaveServiceDoc) error
CreateAIService(ctx *gin.Context, teamID string, input *service_dto.CreateService) (*service_dto.Service, error)
//EditAIService(ctx *gin.Context, id string, input *service_dto.EditService) (*service_dto.Service, error)
EditAIService(ctx *gin.Context, id string, input *service_dto.EditService) (*service_dto.Service, error)
DeleteAIService(ctx *gin.Context, id string) error
SearchMyAIServices(ctx *gin.Context, teamID string, keyword string) ([]*service_dto.ServiceItem, error)
SearchAIServices(ctx *gin.Context, teamID string, keyword string) ([]*service_dto.ServiceItem, error)
+11 -11
View File
@@ -4,9 +4,9 @@ import (
"fmt"
"net/textproto"
"strings"
"github.com/APIParkLab/APIPark/common"
"github.com/APIParkLab/APIPark/common/enum"
"github.com/APIParkLab/APIPark/gateway"
)
@@ -79,7 +79,7 @@ func ToRouter(r *gateway.ApiRelease, version string, matches map[string]string)
//若请求路径包含restful参数
if common.IsRestfulPath(r.Path) {
rewritePlugin.PathType = "regex" //正则替换
//如果转发路径包含restful参数
if common.IsRestfulPath(r.ProxyPath) {
r.ProxyPath = formatProxyPath(r.Path, r.ProxyPath)
@@ -100,7 +100,7 @@ func ToRouter(r *gateway.ApiRelease, version string, matches map[string]string)
},
}
}
rules := make([]*Rule, 0, len(r.Rules))
for _, m := range r.Rules {
rule := &Rule{
@@ -108,11 +108,11 @@ func ToRouter(r *gateway.ApiRelease, version string, matches map[string]string)
Name: m.Key,
Value: "",
}
if m.Position == enum.MatchPositionHeader {
rule.Name = textproto.CanonicalMIMEHeaderKey(rule.Name)
}
switch m.MatchType {
case enum.MatchTypeEqual:
rule.Value = m.Pattern
@@ -137,7 +137,7 @@ func ToRouter(r *gateway.ApiRelease, version string, matches map[string]string)
case enum.MatchTypeAny:
rule.Value = "*"
}
rules = append(rules, rule)
}
plugin := map[string]*Plugin{
@@ -148,8 +148,8 @@ func ToRouter(r *gateway.ApiRelease, version string, matches map[string]string)
}
for k, v := range r.Plugins {
plugin[k] = &Plugin{
Disable: false,
Config: v,
Disable: v.Disable,
Config: v.Config,
}
}
hosts := make([]string, 0, len(r.Host))
@@ -160,7 +160,7 @@ func ToRouter(r *gateway.ApiRelease, version string, matches map[string]string)
if r.Labels != nil {
labels = r.Labels
}
return &Router{
BasicInfo: &BasicInfo{
ID: fmt.Sprintf("%s@router", r.ID),
@@ -195,7 +195,7 @@ func formatProxyPath(requestPath, proxyPath string) string {
i += 1
}
}
for param, order := range restfulSet {
newProxyPath = strings.ReplaceAll(newProxyPath, param, order)
}
+9 -2
View File
@@ -31,6 +31,7 @@
content_typ: "text/plan"
charset: "utf-8"
body: "Forbidden"
-
id: eolinker.com:apinto:strategy-plugin-visit
name: strategy_visit
@@ -62,5 +63,11 @@
rely: eolinker.com:apinto:plugin_app
config:
cache: redis@output
-
id: eolinker.com:apinto:ai_prompt
name: ai_prompt
status: enable
-
id: eolinker.com:apinto:ai_formatter
name: ai_formatter
status: enable
+5
View File
@@ -6,6 +6,7 @@ const (
ProfessionRouter = "router"
ProfessionApplication = "app"
ProfessionService = "service"
ProfessionAIProvider = "ai-provider"
)
var dynamicResourceMap = map[string]Worker{
@@ -42,6 +43,10 @@ var dynamicResourceMap = map[string]Worker{
Profession: ProfessionCertificate,
Driver: "server",
},
"openai": {
Profession: ProfessionAIProvider,
Driver: "openai",
},
}
type Worker struct {
+52 -60
View File
@@ -86,41 +86,41 @@ func (i *imlAPIModule) deleteAPIDoc(ctx context.Context, serviceId string, path
})
}
func (i *imlAPIModule) Create(ctx context.Context, serviceId string, input *ai_api_dto.CreateAPI) (*ai_api_dto.API, error) {
func (i *imlAPIModule) Create(ctx context.Context, serviceId string, input *ai_api_dto.CreateAPI) error {
info, err := i.serviceService.Get(ctx, serviceId)
if err != nil {
return nil, err
return err
}
if info.Kind != service.AIService {
return nil, fmt.Errorf("service kind is not ai service")
return fmt.Errorf("service kind is not ai service")
}
if input.Id == "" {
input.Id = uuid.New().String()
}
err = i.transaction.Transaction(ctx, func(txCtx context.Context) error {
err = i.apiService.Exist(ctx, "", &api.Exist{Path: input.Path, Methods: []string{http.MethodPost}})
if err != nil {
return err
}
err = i.apiService.Create(ctx, &api.Create{
UUID: input.Id,
Description: input.Description,
Service: serviceId,
Team: info.Team,
Methods: []string{
http.MethodPost,
},
Protocols: []string{
"http",
"https",
},
Disable: false,
Path: input.Path,
Match: "{}",
})
if err != nil {
return err
}
return i.transaction.Transaction(ctx, func(txCtx context.Context) error {
//err = i.apiService.Exist(ctx, "", &api.Exist{Path: input.Path, Methods: []string{http.MethodPost}})
//if err != nil {
// return err
//}
//err = i.apiService.Create(ctx, &api.Create{
// UUID: input.Id,
// Description: input.Description,
// Service: serviceId,
// Team: info.Team,
// Methods: []string{
// http.MethodPost,
// },
// Protocols: []string{
// "http",
// "https",
// },
// Disable: false,
// Path: input.Path,
// Match: "{}",
//})
//if err != nil {
// return err
//}
err = i.updateAPIDoc(ctx, serviceId, input.Path, input.Description, input.AiPrompt)
if err != nil {
return err
@@ -140,50 +140,47 @@ func (i *imlAPIModule) Create(ctx context.Context, serviceId string, input *ai_a
},
})
})
if err != nil {
return nil, err
}
return i.Get(ctx, serviceId, input.Id)
}
func (i *imlAPIModule) Edit(ctx context.Context, serviceId string, apiId string, input *ai_api_dto.EditAPI) (*ai_api_dto.API, error) {
func (i *imlAPIModule) Edit(ctx context.Context, serviceId string, apiId string, input *ai_api_dto.EditAPI) error {
info, err := i.serviceService.Get(ctx, serviceId)
if err != nil {
return nil, err
return err
}
if info.Kind != service.AIService {
return nil, fmt.Errorf("service kind is not ai service")
return fmt.Errorf("service kind is not ai service")
}
err = i.transaction.Transaction(ctx, func(txCtx context.Context) error {
return i.transaction.Transaction(ctx, func(txCtx context.Context) error {
apiInfo, err := i.aiAPIService.Get(ctx, apiId)
if err != nil {
return err
}
if input.Path != nil {
apiInfo.Path = *input.Path
prefix, err := i.Prefix(ctx, serviceId)
if err != nil {
return err
}
if !strings.HasSuffix(apiInfo.Path, prefix) {
if apiInfo.Path[0] != '/' {
apiInfo.Path = fmt.Sprintf("/%s", apiInfo.Path)
}
apiInfo.Path = fmt.Sprintf("%s%s", prefix, apiInfo.Path)
err := i.apiService.Exist(ctx, apiId, &api.Exist{Path: apiInfo.Path, Methods: []string{http.MethodPost}})
if err != nil {
return err
}
err = i.apiService.Save(ctx, apiId, &api.Edit{
Path: &apiInfo.Path,
})
if err != nil {
return err
}
}
}
// prefix, err := i.Prefix(ctx, serviceId)
// if err != nil {
// return err
// }
// if !strings.HasSuffix(apiInfo.Path, prefix) {
// if apiInfo.Path[0] != '/' {
// apiInfo.Path = fmt.Sprintf("/%s", apiInfo.Path)
// }
// apiInfo.Path = fmt.Sprintf("%s%s", prefix, apiInfo.Path)
// err := i.apiService.Exist(ctx, apiId, &api.Exist{Path: apiInfo.Path, Methods: []string{http.MethodPost}})
// if err != nil {
// return err
// }
// err = i.apiService.Save(ctx, apiId, &api.Edit{
// Path: &apiInfo.Path,
// })
// if err != nil {
// return err
// }
// }
//}
if input.Description != nil {
apiInfo.Description = *input.Description
}
@@ -211,11 +208,6 @@ func (i *imlAPIModule) Edit(ctx context.Context, serviceId string, apiId string,
AdditionalConfig: &apiInfo.AdditionalConfig,
})
})
if err != nil {
return nil, err
}
return i.Get(ctx, serviceId, apiId)
}
func (i *imlAPIModule) Delete(ctx context.Context, serviceId string, apiId string) error {
+3 -2
View File
@@ -8,11 +8,12 @@ import (
)
type IAPIModule interface {
Create(ctx context.Context, serviceId string, input *ai_api_dto.CreateAPI) (*ai_api_dto.API, error)
Edit(ctx context.Context, serviceId string, apiId string, input *ai_api_dto.EditAPI) (*ai_api_dto.API, error)
Create(ctx context.Context, serviceId string, input *ai_api_dto.CreateAPI) error
Edit(ctx context.Context, serviceId string, apiId string, input *ai_api_dto.EditAPI) error
Delete(ctx context.Context, serviceId string, apiId string) error
List(ctx context.Context, keyword, serviceId string) ([]*ai_api_dto.APIItem, error)
Get(ctx context.Context, serviceId string, apiId string) (*ai_api_dto.API, error)
Prefix(ctx context.Context, serviceId string) (string, error)
}
func init() {
+192 -46
View File
@@ -2,11 +2,16 @@ package ai
import (
"context"
"encoding/json"
"errors"
"fmt"
model_runtime "github.com/APIParkLab/APIPark/ai-provider/model-runtime"
"github.com/APIParkLab/APIPark/gateway"
ai_dto "github.com/APIParkLab/APIPark/module/ai/dto"
"github.com/APIParkLab/APIPark/service/ai"
"github.com/APIParkLab/APIPark/service/cluster"
"github.com/eolinker/eosc/log"
"github.com/eolinker/go-common/store"
"github.com/eolinker/go-common/utils"
"gorm.io/gorm"
"sort"
@@ -15,7 +20,9 @@ import (
var _ IProviderModule = (*imlProviderModule)(nil)
type imlProviderModule struct {
providerService ai.IProviderService `autowired:""`
providerService ai.IProviderService `autowired:""`
clusterService cluster.IClusterService `autowired:""`
transaction store.ITransaction `autowired:""`
}
func (i *imlProviderModule) SimpleProviders(ctx context.Context) ([]*ai_dto.SimpleProviderItem, error) {
@@ -71,7 +78,7 @@ func (i *imlProviderModule) Providers(ctx context.Context) ([]*ai_dto.ProviderIt
}
items = append(items, item)
}
sort.SliceIsSorted(items, func(i, j int) bool {
sort.Slice(items, func(i, j int) bool {
return items[i].UpdateTime.After(items[j].UpdateTime)
})
@@ -160,59 +167,124 @@ func (i *imlProviderModule) LLMs(ctx context.Context, driver string) ([]*ai_dto.
}
func (i *imlProviderModule) UpdateProviderStatus(ctx context.Context, id string, enable bool) error {
_, err := i.providerService.Get(ctx, id)
info, err := i.providerService.Get(ctx, id)
if err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) {
return err
}
p, has := model_runtime.GetProvider(id)
if !has {
return fmt.Errorf("ai provider not found")
}
cfg := p.DefaultConfig()
name := p.Name()
defaultLLm, ok := p.DefaultModel(model_runtime.ModelTypeLLM)
if !ok {
return fmt.Errorf("ai provider default llm not found")
}
defaultLLmId := defaultLLm.ID()
return i.providerService.Save(ctx, id, &ai.SetProvider{
Name: &name,
DefaultLLM: &defaultLLmId,
Config: &cfg,
Status: &enable,
})
return fmt.Errorf("ai provider not found")
//p, has := model_runtime.GetProvider(id)
//if !has {
// return fmt.Errorf("ai provider not found")
//}
//cfg := p.DefaultConfig()
//name := p.Name()
//defaultLLm, ok := p.DefaultModel(model_runtime.ModelTypeLLM)
//if !ok {
// return fmt.Errorf("ai provider default llm not found")
//}
//defaultLLmId := defaultLLm.ID()
//return i.providerService.Save(ctx, id, &ai.SetProvider{
// Name: &name,
// DefaultLLM: &defaultLLmId,
// Config: &cfg,
// Status: &enable,
//})
}
return i.providerService.Save(ctx, id, &ai.SetProvider{
Status: &enable,
return i.transaction.Transaction(ctx, func(txCtx context.Context) error {
err = i.providerService.Save(txCtx, id, &ai.SetProvider{
Status: &enable,
})
if err != nil {
return err
}
if enable {
cfg := make(map[string]interface{})
err = json.Unmarshal([]byte(info.Config), &cfg)
if err != nil {
log.Errorf("unmarshal ai provider config error,id is %s,err is %v", info.Id, err)
return err
}
cfg["driver"] = info.Id
return i.syncGateway(txCtx, cluster.DefaultClusterID, &gateway.DynamicRelease{
BasicItem: &gateway.BasicItem{
ID: info.Id,
Description: info.Name,
Version: info.UpdateAt.Format("20060102150405"),
MatchLabels: map[string]string{
"module": "ai-provider",
},
},
Attr: cfg,
}, enable)
} else {
return i.syncGateway(txCtx, cluster.DefaultClusterID, &gateway.DynamicRelease{
BasicItem: &gateway.BasicItem{
ID: info.Id,
},
}, enable)
}
})
}
func (i *imlProviderModule) UpdateProviderConfig(ctx context.Context, id string, input *ai_dto.UpdateConfig) error {
_, err := i.providerService.Get(ctx, id)
p, has := model_runtime.GetProvider(id)
if !has {
return fmt.Errorf("ai provider not found")
}
info, err := i.providerService.Get(ctx, id)
if err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) {
return err
}
p, has := model_runtime.GetProvider(id)
if !has {
return fmt.Errorf("ai provider not found")
}
name := p.Name()
defaultLLm, ok := p.DefaultModel(model_runtime.ModelTypeLLM)
if !ok {
return fmt.Errorf("ai provider default llm not found")
}
defaultLLmId := defaultLLm.ID()
return i.providerService.Save(ctx, id, &ai.SetProvider{
Name: &name,
DefaultLLM: &defaultLLmId,
info = &ai.Provider{
Id: id,
Name: p.Name(),
DefaultLLM: defaultLLm.ID(),
Config: input.Config,
}
}
err = p.Check(input.Config)
if err != nil {
return err
}
input.Config, err = p.GenConfig(input.Config, info.Config)
if err != nil {
return err
}
return i.transaction.Transaction(ctx, func(txCtx context.Context) error {
err = i.providerService.Save(ctx, id, &ai.SetProvider{
Name: &info.Name,
DefaultLLM: &info.DefaultLLM,
Config: &input.Config,
})
}
return i.providerService.Save(ctx, id, &ai.SetProvider{
Config: &input.Config,
if err != nil {
return err
}
cfg := make(map[string]interface{})
err = json.Unmarshal([]byte(input.Config), &cfg)
if err != nil {
log.Errorf("unmarshal ai provider config error,id is %s,err is %v", id, err)
return err
}
return i.syncGateway(ctx, cluster.DefaultClusterID, &gateway.DynamicRelease{
BasicItem: &gateway.BasicItem{
ID: id,
Description: info.Name,
Version: info.UpdateAt.Format("20060102150405"),
MatchLabels: map[string]string{
"module": "ai-provider",
},
},
Attr: cfg,
}, true)
})
}
@@ -222,19 +294,93 @@ func (i *imlProviderModule) UpdateProviderDefaultLLM(ctx context.Context, id str
if !errors.Is(err, gorm.ErrRecordNotFound) {
return err
}
p, has := model_runtime.GetProvider(id)
if !has {
return fmt.Errorf("ai provider not found")
}
name := p.Name()
cfg := p.DefaultConfig()
return i.providerService.Save(ctx, id, &ai.SetProvider{
Name: &name,
DefaultLLM: &input.LLM,
Config: &cfg,
})
return fmt.Errorf("ai provider not found")
//p, has := model_runtime.GetProvider(id)
//if !has {
// return fmt.Errorf("ai provider not found")
//}
//name := p.Name()
//cfg := p.DefaultConfig()
//return i.providerService.Save(ctx, id, &ai.SetProvider{
// Name: &name,
// DefaultLLM: &input.LLM,
// Config: &cfg,
//})
}
return i.providerService.Save(ctx, id, &ai.SetProvider{
DefaultLLM: &input.LLM,
})
}
func (i *imlProviderModule) getAiProviders(ctx context.Context, clusterId string) ([]*gateway.DynamicRelease, error) {
list, err := i.providerService.List(ctx, clusterId)
if err != nil {
return nil, err
}
if err != nil {
return nil, err
}
providers := make([]*gateway.DynamicRelease, 0, len(list))
for _, p := range list {
if !p.Status {
// 关闭
continue
}
cfg := make(map[string]interface{})
err = json.Unmarshal([]byte(p.Config), &cfg)
if err != nil {
log.Errorf("unmarshal ai provider config error,id is %s,err is %v", p.Id, err)
continue
}
providers = append(providers, &gateway.DynamicRelease{
BasicItem: &gateway.BasicItem{
ID: p.Id,
Description: p.Name,
Version: p.UpdateAt.Format("20060102150405"),
MatchLabels: map[string]string{
"module": "ai-provider",
},
},
Attr: cfg,
})
}
return providers, nil
}
func (i *imlProviderModule) initGateway(ctx context.Context, clusterId string, clientDriver gateway.IClientDriver) error {
providers, err := i.getAiProviders(ctx, clusterId)
if err != nil {
return err
}
for _, p := range providers {
client, err := clientDriver.Dynamic(p.ID)
if err != nil {
return err
}
err = client.Online(ctx, providers...)
if err != nil {
return err
}
}
return nil
}
func (i *imlProviderModule) syncGateway(ctx context.Context, clusterId string, releaseInfo *gateway.DynamicRelease, online bool) error {
client, err := i.clusterService.GatewayClient(ctx, clusterId)
if err != nil {
return err
}
defer func() {
err := client.Close(ctx)
if err != nil {
log.Warn("close apinto client:", err)
}
}()
dynamicClient, err := client.Dynamic(releaseInfo.ID)
if err != nil {
return err
}
if online {
return dynamicClient.Online(ctx, releaseInfo)
}
return dynamicClient.Offline(ctx, releaseInfo)
}
+4 -1
View File
@@ -2,6 +2,7 @@ package ai
import (
"context"
"github.com/APIParkLab/APIPark/gateway"
ai_dto "github.com/APIParkLab/APIPark/module/ai/dto"
"github.com/eolinker/go-common/autowire"
"reflect"
@@ -19,6 +20,8 @@ type IProviderModule interface {
func init() {
autowire.Auto[IProviderModule](func() reflect.Value {
return reflect.ValueOf(&imlProviderModule{})
module := new(imlProviderModule)
gateway.RegisterInitHandleFunc(module.initGateway)
return reflect.ValueOf(module)
})
}
+1 -1
View File
@@ -50,7 +50,7 @@ type imlPublishModule struct {
}
func (m *imlPublishModule) initGateway(ctx context.Context, partitionId string, clientDriver gateway.IClientDriver) error {
return nil
projects, err := m.serviceService.List(ctx)
if err != nil {
return err
+1 -1
View File
@@ -280,7 +280,7 @@ func (i *imlRouterModule) Edit(ctx context.Context, serviceId string, apiId stri
err = i.transaction.Transaction(ctx, func(ctx context.Context) error {
if dto.Path != nil {
err = i.apiService.Exist(ctx, "", &api.Exist{Path: *dto.Path, Methods: *dto.Methods})
err = i.apiService.Exist(ctx, apiId, &api.Exist{Path: *dto.Path, Methods: *dto.Methods})
if err != nil {
return err
}
+1 -1
View File
@@ -22,7 +22,7 @@ func (p *plugin) ServiceApis() []pm3.Api {
// AI服务
pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/ai-services", []string{"context", "query:service", "query:keyword"}, []string{"services"}, p.serviceController.SearchAIServices),
pm3.CreateApiWidthDoc(http.MethodPost, "/api/v1/team/ai-service", []string{"context", "query:team", "body"}, []string{"service"}, p.serviceController.CreateAIService),
pm3.CreateApiWidthDoc(http.MethodPut, "/api/v1/ai-service/info", []string{"context", "query:service", "body"}, []string{"service"}, p.serviceController.Edit),
pm3.CreateApiWidthDoc(http.MethodPut, "/api/v1/ai-service/info", []string{"context", "query:service", "body"}, []string{"service"}, p.serviceController.EditAIService),
pm3.CreateApiWidthDoc(http.MethodDelete, "/api/v1/team/ai-service", []string{"context", "query:service"}, nil, p.serviceController.DeleteAIService),
pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/my_ai_services", []string{"context", "query:team", "query:keyword"}, []string{"services"}, p.serviceController.SearchMyAIServices),
pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/ai-service/info", []string{"context", "query:service"}, []string{"service"}, p.serviceController.Get),
+1 -1
View File
@@ -339,7 +339,7 @@ team:
value: 'manager'
apis:
- "POST:/api/v1/service/publish/release/do"
- "PUT:/api/v1/service/publish/execute"
# - "PUT:/api/v1/service/publish/execute"
- "DELETE:/api/v1/service/release"
- name: subscription management
cname: 订阅方管理
+10 -2
View File
@@ -1,4 +1,4 @@
version: v5
version: v6
sort:
- "access_log"
- "monitor"
@@ -74,4 +74,12 @@ plugin:
name: strategy_cache
status: global
config:
cache: redis@output
cache: redis@output
ai_prompt:
id: eolinker.com:apinto:ai_prompt
name: ai_prompt
status: enable
ai_formatter:
id: eolinker.com:apinto:ai_formatter
name: ai_formatter
status: enable
@@ -0,0 +1 @@
{"group":"eolinker.com","project":"apinto","name":"ai_formatter","version":"innert","render":{"type":"object","eo:type":"object","properties":{"config":{"type":"string","eo:type":"string"},"model":{"type":"string","eo:type":"string"},"provider":{"type":"string","eo:type":"require","skill":"github.com/eolinker/apinto/convert.convert.IConverterDriver"}},"ui:sort":["provider","model","config"]}}
@@ -0,0 +1 @@
{"group":"eolinker.com","project":"apinto","name":"ai_prompt","version":"innert","render":{"type":"object","eo:type":"object","properties":{"prompt":{"type":"string","eo:type":"string"},"variables":{"type":"array","eo:type":"array","items":{"type":"object","eo:type":"object","properties":{"key":{"type":"string","eo:type":"string"},"require":{"type":"boolean","eo:type":"boolean"}},"ui:sort":["key","require"]}}},"ui:sort":["prompt","variables"]}}
@@ -1 +1 @@
{"group":"eolinker.com","project":"apinto","name":"plugin_app","version":"innert","render":{"type":"object","eo:type":"object"}}
{"group":"eolinker.com","project":"apinto","name":"plugin_app","version":"innert","render":{"type":"object","eo:type":"object","properties":{"force_auth":{"type":"boolean","eo:type":"boolean","label":"是否强制认证"}},"ui:sort":["force_auth"]}}
+3 -1
View File
@@ -40,4 +40,6 @@ curl -s http://127.0.0.1:9400/extender/eolinker.com:apinto/proxy_mirror > eolink
curl -s http://127.0.0.1:9400/extender/eolinker.com:apinto/oauth2 > eolinker_com_apinto_oauth2.json
curl -s http://127.0.0.1:9400/extender/eolinker.com:apinto/strategy-plugin-grey > eolinker_com_apinto_strategy-plugin-grey.json
curl -s http://127.0.0.1:9400/extender/eolinker.com:apinto/strategy-plugin-fuse > eolinker_com_apinto_strategy-plugin-fuse.json
curl -s http://127.0.0.1:9400/extender/eolinker.com:apinto/response_file_parse > eolinker_com_apinto_response_file_parse.json
curl -s http://127.0.0.1:9400/extender/eolinker.com:apinto/response_file_parse > eolinker_com_apinto_response_file_parse.json
curl -s http://127.0.0.1:9400/extender/eolinker.com:apinto/ai_formatter > eolinker_com_apinto_ai_formatter.json
curl -s http://127.0.0.1:9400/extender/eolinker.com:apinto/ai_prompt > eolinker_com_apinto_ai_prompt.json
+28
View File
@@ -29,6 +29,7 @@ type HistoryType string
const (
HistoryRequest HistoryType = "request"
HistoryProxy HistoryType = "proxy"
HistoryPlugin HistoryType = "plugin"
)
type imlAPIService struct {
@@ -36,10 +37,31 @@ type imlAPIService struct {
apiInfoStore api.IAPIInfoStore `autowired:""`
requestCommitService commit.ICommitWithKeyService[Request] `autowired:""`
proxyCommitService commit.ICommitWithKeyService[Proxy] `autowired:""`
//pluginCommitService commit.ICommitWithKeyService[Plugin] `autowired:""`
universally.IServiceGet[API]
universally.IServiceDelete
}
//func (i *imlAPIService) ListLatestCommitPlugin(ctx context.Context, aid ...string) ([]*commit.Commit[Plugin], error) {
// return i.pluginCommitService.ListLatest(ctx, aid...)
//}
//
//func (i *imlAPIService) GetPluginCommit(ctx context.Context, commitId string) (*commit.Commit[Plugin], error) {
// return i.pluginCommitService.Get(ctx, commitId)
//}
//
//func (i *imlAPIService) ListPluginCommit(ctx context.Context, commitId ...string) ([]*commit.Commit[Plugin], error) {
// return i.pluginCommitService.List(ctx, commitId...)
//}
//
//func (i *imlAPIService) SavePlugin(ctx context.Context, aid string, data *Plugin) error {
// return i.pluginCommitService.Save(ctx, aid, data)
//}
//
//func (i *imlAPIService) LatestPlugin(ctx context.Context, aid string) (*commit.Commit[Plugin], error) {
// return i.pluginCommitService.Latest(ctx, aid)
//}
func (i *imlAPIService) ListLatestCommitRequest(ctx context.Context, aid ...string) ([]*commit.Commit[Request], error) {
return i.requestCommitService.ListLatest(ctx, aid...)
}
@@ -228,12 +250,18 @@ func (i *imlAPIService) Exist(ctx context.Context, aid string, a *Exist) error {
}
continue
}
if t.UUID == aid {
continue
}
for _, m := range t.Method {
existMethodMap[m] = struct{}{}
}
}
for _, m := range a.Methods {
if _, ok := existMethodMap[m]; ok {
return fmt.Errorf("method(%s),path(%s) is exist", m, a.Path)
}
}
+2 -1
View File
@@ -108,7 +108,6 @@ type PluginSetting struct {
}
type Request struct {
//ID string `json:"id"`
Path string `json:"path"`
Methods []string `json:"methods"`
Protocols []string `json:"protocols"`
@@ -143,3 +142,5 @@ type Match struct {
Key string `json:"key"`
Pattern string `json:"pattern"`
}
type Plugin map[string]interface{}
+10 -2
View File
@@ -20,17 +20,24 @@ type IAPIService interface {
GetInfo(ctx context.Context, aid string) (*Info, error)
ListInfo(ctx context.Context, aids ...string) ([]*Info, error)
ListInfoForService(ctx context.Context, serviceId string) ([]*Info, error)
ListLatestCommitRequest(ctx context.Context, aid ...string) ([]*commit.Commit[Request], error)
ListLatestCommitProxy(ctx context.Context, aid ...string) ([]*commit.Commit[Proxy], error)
LatestRequest(ctx context.Context, aid string) (*commit.Commit[Request], error)
LatestProxy(ctx context.Context, aid string) (*commit.Commit[Proxy], error)
GetProxyCommit(ctx context.Context, commitId string) (*commit.Commit[Proxy], error)
ListProxyCommit(ctx context.Context, commitId ...string) ([]*commit.Commit[Proxy], error)
SaveProxy(ctx context.Context, aid string, data *Proxy) error
ListLatestCommitRequest(ctx context.Context, aid ...string) ([]*commit.Commit[Request], error)
GetRequestCommit(ctx context.Context, commitId string) (*commit.Commit[Request], error)
ListRequestCommit(ctx context.Context, commitId ...string) ([]*commit.Commit[Request], error)
SaveRequest(ctx context.Context, aid string, data *Request) error
LatestRequest(ctx context.Context, aid string) (*commit.Commit[Request], error)
//ListLatestCommitPlugin(ctx context.Context, aid ...string) ([]*commit.Commit[Plugin], error)
//GetPluginCommit(ctx context.Context, commitId string) (*commit.Commit[Plugin], error)
//ListPluginCommit(ctx context.Context, commitId ...string) ([]*commit.Commit[Plugin], error)
//SavePlugin(ctx context.Context, aid string, data *Plugin) error
//LatestPlugin(ctx context.Context, aid string) (*commit.Commit[Plugin], error)
Save(ctx context.Context, id string, model *Edit) error
Create(ctx context.Context, input *Create) (err error)
@@ -47,5 +54,6 @@ func init() {
commit.InitCommitWithKeyService[Proxy]("api", string(HistoryProxy))
commit.InitCommitWithKeyService[Request]("api", string(HistoryRequest))
commit.InitCommitWithKeyService[Plugin]("api", string(HistoryPlugin))
}