mirror of
https://github.com/APIParkLab/APIPark.git
synced 2026-06-04 10:13:53 +08:00
497 lines
14 KiB
Go
497 lines
14 KiB
Go
package system
|
|
|
|
import (
|
|
"archive/zip"
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
|
|
subscribe_dto "github.com/APIParkLab/APIPark/module/subscribe/dto"
|
|
|
|
"github.com/eolinker/eosc/log"
|
|
|
|
ai_dto "github.com/APIParkLab/APIPark/module/ai/dto"
|
|
|
|
"github.com/APIParkLab/APIPark/model/plugin_model"
|
|
"github.com/APIParkLab/APIPark/service/api"
|
|
|
|
ai_api "github.com/APIParkLab/APIPark/module/ai-api"
|
|
|
|
model_runtime "github.com/APIParkLab/APIPark/ai-provider/model-runtime"
|
|
ai_api_dto "github.com/APIParkLab/APIPark/module/ai-api/dto"
|
|
router_dto "github.com/APIParkLab/APIPark/module/router/dto"
|
|
|
|
"github.com/eolinker/go-common/store"
|
|
|
|
"github.com/APIParkLab/APIPark/module/ai"
|
|
|
|
catalogue_dto "github.com/APIParkLab/APIPark/module/catalogue/dto"
|
|
|
|
application_authorization_dto "github.com/APIParkLab/APIPark/module/application-authorization/dto"
|
|
service_dto "github.com/APIParkLab/APIPark/module/service/dto"
|
|
team_dto "github.com/APIParkLab/APIPark/module/team/dto"
|
|
"github.com/eolinker/go-common/register"
|
|
"github.com/eolinker/go-common/server"
|
|
"github.com/eolinker/go-common/utils"
|
|
"github.com/google/uuid"
|
|
|
|
system_dto "github.com/APIParkLab/APIPark/module/system/dto"
|
|
|
|
application_authorization "github.com/APIParkLab/APIPark/module/application-authorization"
|
|
"github.com/APIParkLab/APIPark/module/catalogue"
|
|
"github.com/APIParkLab/APIPark/module/router"
|
|
"github.com/APIParkLab/APIPark/module/service"
|
|
"github.com/APIParkLab/APIPark/module/subscribe"
|
|
"github.com/APIParkLab/APIPark/module/system"
|
|
"github.com/APIParkLab/APIPark/module/team"
|
|
"github.com/APIParkLab/APIPark/module/upstream"
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
var _ IExportConfigController = (*imlExportConfigController)(nil)
|
|
|
|
type imlExportConfigController struct {
|
|
teamModule team.ITeamExportModule `autowired:""`
|
|
serviceModule service.IExportServiceModule `autowired:""`
|
|
appModule service.IExportAppModule `autowired:""`
|
|
routerModule router.IExportRouterModule `autowired:""`
|
|
upstreamModule upstream.IExportUpstreamModule `autowired:""`
|
|
applicationAuthorizationModule application_authorization.IExportAuthorizationModule `autowired:""`
|
|
catalogueModule catalogue.IExportCatalogueModule `autowired:""`
|
|
subscribeModule subscribe.IExportSubscribeModule `autowired:""`
|
|
applyModule subscribe.IExportSubscribeApprovalModule `autowired:""`
|
|
}
|
|
|
|
type ExportFile struct {
|
|
Driver string `json:"driver"`
|
|
Data interface{} `json:"data"`
|
|
}
|
|
|
|
func (e *ExportFile) Byte() []byte {
|
|
b, _ := json.Marshal(e.Data)
|
|
return b
|
|
}
|
|
|
|
func zipFile(files []*ExportFile) (*bytes.Buffer, error) {
|
|
// 创建一个缓冲区用于存储 ZIP 文件内容
|
|
buf := new(bytes.Buffer)
|
|
zipWriter := zip.NewWriter(buf)
|
|
now := time.Now()
|
|
// 将文件写入 ZIP
|
|
for _, file := range files {
|
|
header := &zip.FileHeader{
|
|
Name: fmt.Sprintf("%s.json", file.Driver),
|
|
Method: zip.Deflate,
|
|
Modified: now,
|
|
}
|
|
f, err := zipWriter.CreateHeader(header)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to create zip file: %v", err)
|
|
}
|
|
_, err = f.Write(file.Byte())
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to write to zip file: %v", err)
|
|
}
|
|
}
|
|
|
|
// 关闭 ZIP writer,完成压缩过程
|
|
err := zipWriter.Close()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to close zip writer: %v", err)
|
|
}
|
|
return buf, nil
|
|
}
|
|
|
|
func (i *imlExportConfigController) ExportAll(ctx *gin.Context) error {
|
|
files, err := i.appendFiles(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
buf, err := zipFile(files)
|
|
if err != nil {
|
|
|
|
}
|
|
|
|
ctx.DataFromReader(http.StatusOK, int64(buf.Len()), "application/zip", buf, map[string]string{
|
|
"Content-Disposition": "attachment; filename=\"export.zip\"",
|
|
})
|
|
return nil
|
|
}
|
|
|
|
func (i *imlExportConfigController) appendFiles(ctx *gin.Context) ([]*ExportFile, error) {
|
|
type exportConfig struct {
|
|
exportFunc func(ctx *gin.Context) (interface{}, error)
|
|
driver string
|
|
}
|
|
|
|
exports := []exportConfig{
|
|
{
|
|
exportFunc: func(ctx *gin.Context) (interface{}, error) {
|
|
return i.teamModule.ExportAll(ctx)
|
|
},
|
|
driver: "team",
|
|
},
|
|
{
|
|
exportFunc: func(ctx *gin.Context) (interface{}, error) {
|
|
return i.serviceModule.ExportAll(ctx)
|
|
},
|
|
driver: "service",
|
|
},
|
|
{
|
|
exportFunc: func(ctx *gin.Context) (interface{}, error) {
|
|
return i.appModule.ExportAll(ctx)
|
|
},
|
|
driver: "app",
|
|
},
|
|
{
|
|
exportFunc: func(ctx *gin.Context) (interface{}, error) {
|
|
return i.routerModule.ExportAll(ctx)
|
|
},
|
|
driver: "api",
|
|
},
|
|
{
|
|
exportFunc: func(ctx *gin.Context) (interface{}, error) {
|
|
return i.upstreamModule.ExportAll(ctx)
|
|
},
|
|
driver: "upstream",
|
|
},
|
|
{
|
|
exportFunc: func(ctx *gin.Context) (interface{}, error) {
|
|
return i.applicationAuthorizationModule.ExportAll(ctx)
|
|
},
|
|
driver: "authorization",
|
|
},
|
|
{
|
|
exportFunc: func(ctx *gin.Context) (interface{}, error) {
|
|
return i.catalogueModule.ExportAll(ctx)
|
|
},
|
|
driver: "catalogue",
|
|
},
|
|
{
|
|
exportFunc: func(ctx *gin.Context) (interface{}, error) {
|
|
return i.subscribeModule.ExportAll(ctx)
|
|
},
|
|
driver: "subscribe",
|
|
},
|
|
{
|
|
exportFunc: func(ctx *gin.Context) (interface{}, error) {
|
|
return i.applyModule.ExportAll(ctx)
|
|
},
|
|
driver: "apply",
|
|
},
|
|
}
|
|
|
|
files := make([]*ExportFile, 0, len(exports))
|
|
for _, config := range exports {
|
|
data, err := config.exportFunc(ctx)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("[%s] failed to export data: %v", config.driver, err)
|
|
}
|
|
|
|
files = append(files, &ExportFile{
|
|
Driver: config.driver,
|
|
Data: data,
|
|
})
|
|
}
|
|
|
|
return files, nil
|
|
}
|
|
|
|
var (
|
|
_ ISettingController = (*imlSettingController)(nil)
|
|
)
|
|
|
|
type imlSettingController struct {
|
|
settingModule system.ISettingModule `autowired:""`
|
|
}
|
|
|
|
func (i *imlSettingController) Get(ctx *gin.Context) (*system_dto.Setting, error) {
|
|
return i.settingModule.Get(ctx), nil
|
|
}
|
|
|
|
func (i *imlSettingController) Set(ctx *gin.Context, input *system_dto.InputSetting) error {
|
|
return i.settingModule.Set(ctx, input)
|
|
}
|
|
|
|
type imlInitController struct {
|
|
teamModule team.ITeamModule `autowired:""`
|
|
appModule service.IAppModule `autowired:""`
|
|
serviceModule service.IServiceModule `autowired:""`
|
|
applicationAuthorizationModule application_authorization.IAuthorizationModule `autowired:""`
|
|
catalogueModule catalogue.ICatalogueModule `autowired:""`
|
|
providerModule ai.IProviderModule `autowired:""`
|
|
subscribeModule subscribe.ISubscribeModule `autowired:""`
|
|
transaction store.ITransaction `autowired:""`
|
|
aiAPIModule ai_api.IAPIModule `autowired:""`
|
|
docModule service.IServiceDocModule `autowired:""`
|
|
routerModule router.IRouterModule `autowired:""`
|
|
}
|
|
|
|
func (i *imlInitController) OnInit() {
|
|
register.Handle(func(v server.Server) {
|
|
ctx := utils.SetUserId(context.Background(), "admin")
|
|
|
|
err := i.transaction.Transaction(ctx, func(ctx context.Context) error {
|
|
teams, err := i.teamModule.Search(ctx, "")
|
|
if err != nil {
|
|
return fmt.Errorf("get teams error: %v", err)
|
|
}
|
|
if len(teams) > 0 {
|
|
return nil
|
|
}
|
|
items, err := i.catalogueModule.Search(ctx, "")
|
|
if err != nil {
|
|
return fmt.Errorf("get catalogue error: %v", err)
|
|
}
|
|
catalogueId := uuid.New().String()
|
|
if len(items) == 0 {
|
|
err = i.catalogueModule.Create(ctx, &catalogue_dto.CreateCatalogue{
|
|
Id: catalogueId,
|
|
Name: "Default Category",
|
|
})
|
|
if err != nil {
|
|
return fmt.Errorf("create default catalogue error: %v", err)
|
|
}
|
|
} else {
|
|
catalogueId = items[0].Id
|
|
}
|
|
|
|
info, err := i.teamModule.Create(ctx, &team_dto.CreateTeam{
|
|
Name: "Default Team",
|
|
Description: "Auto created By APIPark",
|
|
})
|
|
if err != nil {
|
|
return fmt.Errorf("create default team error: %v", err)
|
|
}
|
|
app, err := i.appModule.CreateApp(ctx, info.Id, &service_dto.CreateApp{
|
|
Name: "Demo Application",
|
|
Description: "Auto created By APIPark",
|
|
})
|
|
if err != nil {
|
|
return fmt.Errorf("create default app error: %v", err)
|
|
}
|
|
// 创建Rest服务
|
|
restPath := "/rest-demo"
|
|
serviceInfo, err := i.serviceModule.Create(ctx, info.Id, &service_dto.CreateService{
|
|
Name: "REST Demo Service",
|
|
Prefix: "/rest-demo",
|
|
Description: "Auto created By APIPark",
|
|
ServiceType: "public",
|
|
Catalogue: catalogueId,
|
|
ApprovalType: "auto",
|
|
Kind: "rest",
|
|
})
|
|
if err != nil {
|
|
return fmt.Errorf("create default service error: %v", err)
|
|
}
|
|
path := fmt.Sprintf("/%s/", strings.Trim(restPath, "/"))
|
|
_, err = i.routerModule.Create(ctx, serviceInfo.Id, &router_dto.Create{
|
|
Id: uuid.NewString(),
|
|
Name: "",
|
|
Path: path + "*",
|
|
Methods: []string{http.MethodGet, http.MethodPost, http.MethodPut, http.MethodDelete, http.MethodPatch, http.MethodOptions},
|
|
Description: "auto create by create service",
|
|
Protocols: []string{"http", "https"},
|
|
MatchRules: nil,
|
|
Upstream: "",
|
|
Proxy: &router_dto.InputProxy{
|
|
Path: path,
|
|
Timeout: 30000,
|
|
Retry: 0,
|
|
},
|
|
Disable: false,
|
|
})
|
|
if err != nil {
|
|
return fmt.Errorf("create default router error: %v", err)
|
|
}
|
|
err = i.subscribeModule.AddSubscriber(ctx, serviceInfo.Id, &subscribe_dto.AddSubscriber{
|
|
Application: app.Id,
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// 创建AI服务
|
|
err = i.createAIService(ctx, info.Id, &service_dto.CreateService{
|
|
Name: "AI Demo Service",
|
|
Prefix: "/ai-demo",
|
|
Description: "Auto created By APIPark",
|
|
ServiceType: "public",
|
|
Catalogue: catalogueId,
|
|
ApprovalType: "auto",
|
|
Kind: "ai",
|
|
}, app.Id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = i.applicationAuthorizationModule.AddAuthorization(ctx, app.Id, &application_authorization_dto.CreateAuthorization{
|
|
Name: "Default API Key",
|
|
Driver: "apikey",
|
|
Position: "Header",
|
|
TokenName: "Authorization",
|
|
ExpireTime: 0,
|
|
Config: map[string]interface{}{
|
|
"apikey": uuid.New().String(),
|
|
},
|
|
})
|
|
if err != nil {
|
|
return fmt.Errorf("create default api key error: %v", err)
|
|
}
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
log.Errorf("init iml error: %v", err)
|
|
}
|
|
})
|
|
}
|
|
func (i *imlInitController) createAIService(ctx context.Context, teamID string, input *service_dto.CreateService, appId string) error {
|
|
|
|
providerId := "fakegpt"
|
|
err := i.providerModule.UpdateProviderConfig(ctx, providerId, &ai_dto.UpdateConfig{
|
|
Config: "{\n \"apikey\": \"xxx\" \n}",
|
|
})
|
|
if err != nil {
|
|
return fmt.Errorf("update %s config error: %v", providerId, err)
|
|
}
|
|
input.Provider = &providerId
|
|
if input.Id == "" {
|
|
input.Id = uuid.New().String()
|
|
}
|
|
providerInfo, err := i.providerModule.Provider(ctx, *input.Provider)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
input.Model = &providerInfo.DefaultLLM
|
|
|
|
if input.Prefix == "" {
|
|
if len(input.Id) < 9 {
|
|
input.Prefix = input.Id
|
|
} else {
|
|
input.Prefix = input.Id[:8]
|
|
}
|
|
}
|
|
pv, err := i.providerModule.Provider(ctx, *input.Provider)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
p, has := model_runtime.GetProvider(*input.Provider)
|
|
if !has {
|
|
return fmt.Errorf("provider not found")
|
|
}
|
|
m, has := p.GetModel(pv.DefaultLLM)
|
|
if !has {
|
|
return fmt.Errorf("model %s not found", pv.DefaultLLM)
|
|
}
|
|
|
|
var info *service_dto.Service
|
|
err = i.transaction.Transaction(ctx, func(txCtx context.Context) error {
|
|
var err error
|
|
info, err = i.serviceModule.Create(ctx, teamID, input)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
path := fmt.Sprintf("/%s/chat/completions", strings.Trim(input.Prefix, "/"))
|
|
timeout := 300000
|
|
retry := 0
|
|
aiPrompt := &ai_api_dto.AiPrompt{
|
|
//Variables: []*ai_api_dto.AiPromptVariable{
|
|
// {
|
|
// Key: "source_lang",
|
|
// Description: "",
|
|
// Require: true,
|
|
// },
|
|
// {
|
|
// Key: "target_lang",
|
|
// Description: "",
|
|
// Require: true,
|
|
// },
|
|
// {
|
|
// Key: "text",
|
|
// Description: "",
|
|
// Require: true,
|
|
// },
|
|
//},
|
|
//Prompt: "You need to translate {{source_lang}} into {{target_lang}}, and the following is the content that needs to be translated.\n---\n{{text}}",
|
|
}
|
|
aiModel := &ai_api_dto.AiModel{
|
|
Id: m.ID(),
|
|
Config: m.DefaultConfig(),
|
|
Provider: providerId,
|
|
}
|
|
name := "Demo Chat API"
|
|
description := "A demo that shows you how to use a prompt to create a Chat API."
|
|
apiId := uuid.New().String()
|
|
err = i.aiAPIModule.Create(
|
|
ctx,
|
|
info.Id,
|
|
&ai_api_dto.CreateAPI{
|
|
Id: apiId,
|
|
Name: name,
|
|
Path: path,
|
|
Description: description,
|
|
Disable: false,
|
|
AiPrompt: aiPrompt,
|
|
AiModel: aiModel,
|
|
Timeout: timeout,
|
|
Retry: retry,
|
|
},
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
plugins := make(map[string]api.PluginSetting)
|
|
plugins["ai_prompt"] = api.PluginSetting{
|
|
Config: plugin_model.ConfigType{
|
|
"prompt": aiPrompt.Prompt,
|
|
"variables": aiPrompt.Variables,
|
|
},
|
|
}
|
|
plugins["ai_formatter"] = api.PluginSetting{
|
|
Config: plugin_model.ConfigType{
|
|
"model": aiModel.Id,
|
|
"provider": info.Provider.Id,
|
|
"config": aiModel.Config,
|
|
},
|
|
}
|
|
_, err = i.routerModule.Create(ctx, info.Id, &router_dto.Create{
|
|
Id: apiId,
|
|
Name: name,
|
|
Path: path,
|
|
Methods: []string{
|
|
http.MethodPost,
|
|
},
|
|
Description: description,
|
|
Protocols: []string{"http", "https"},
|
|
MatchRules: nil,
|
|
Proxy: &router_dto.InputProxy{
|
|
Path: path,
|
|
Timeout: timeout,
|
|
Retry: retry,
|
|
Plugins: plugins,
|
|
},
|
|
Disable: false,
|
|
//Upstream: info.Provider.Id,
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = i.subscribeModule.AddSubscriber(ctx, info.Id, &subscribe_dto.AddSubscriber{
|
|
Application: appId,
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return i.docModule.SaveServiceDoc(ctx, info.Id, &service_dto.SaveServiceDoc{
|
|
Doc: "The Translation API allows developers to translate text from one language to another. It supports multiple languages and enables easy integration of high-quality translation features into applications. With simple API requests, you can quickly translate content into different target languages.",
|
|
})
|
|
})
|
|
|
|
return err
|
|
}
|