ai路由完成

This commit is contained in:
Liujian
2024-09-25 20:28:01 +08:00
parent 5d70b98cd4
commit c053aa6299
21 changed files with 786 additions and 16 deletions
+23
View File
@@ -0,0 +1,23 @@
package ai_api
import (
ai_api_dto "github.com/APIParkLab/APIPark/module/ai-api/dto"
"github.com/eolinker/go-common/autowire"
"github.com/gin-gonic/gin"
"reflect"
)
type IAPIController interface {
Create(ctx *gin.Context, serviceId string, input *ai_api_dto.CreateAPI) (*ai_api_dto.API, error)
Edit(ctx *gin.Context, serviceId string, apiId string, input *ai_api_dto.EditAPI) (*ai_api_dto.API, error)
Delete(ctx *gin.Context, serviceId string, apiId string) error
List(ctx *gin.Context, keyword string, serviceId string) ([]*ai_api_dto.APIItem, error)
Get(ctx *gin.Context, serviceId string, apiId string) (*ai_api_dto.API, error)
}
func init() {
autowire.Auto[IAPIController](func() reflect.Value {
m := new(imlAPIController)
return reflect.ValueOf(m)
})
}
+33
View File
@@ -0,0 +1,33 @@
package ai_api
import (
ai_api "github.com/APIParkLab/APIPark/module/ai-api"
ai_api_dto "github.com/APIParkLab/APIPark/module/ai-api/dto"
"github.com/gin-gonic/gin"
)
var _ IAPIController = (*imlAPIController)(nil)
type imlAPIController struct {
module ai_api.IAPIModule `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)
}
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)
}
func (i *imlAPIController) Delete(ctx *gin.Context, serviceId string, apiId string) error {
return i.module.Delete(ctx, serviceId, apiId)
}
func (i *imlAPIController) List(ctx *gin.Context, keyword string, serviceId string) ([]*ai_api_dto.APIItem, error) {
return i.module.List(ctx, keyword, serviceId)
}
func (i *imlAPIController) Get(ctx *gin.Context, serviceId string, apiId string) (*ai_api_dto.API, error) {
return i.module.Get(ctx, serviceId, apiId)
}
+40
View File
@@ -0,0 +1,40 @@
package ai_api_dto
type CreateAPI struct {
Id string `json:"id"`
Name string `json:"name"`
Path string `json:"path"`
Description string `json:"description"`
Disable bool `json:"disable"`
AiPrompt *AiPrompt `json:"ai_prompt"`
AiModel *AiModel `json:"ai_model"`
Timeout int `json:"timeout"`
Retry int `json:"retry"`
}
type AiPrompt struct {
Variables []*AiPromptVariable `json:"variables"`
Prompt string `json:"prompt"`
}
type AiPromptVariable struct {
Key string `json:"key"`
Description string `json:"description"`
Require bool `json:"require"`
}
type AiModel struct {
Id string `json:"id"`
Config string `json:"config"`
}
type EditAPI struct {
Name *string `json:"name"`
Path *string `json:"path"`
Description *string `json:"description"`
Disable *bool `json:"disable"`
AiPrompt *AiPrompt `json:"ai_prompt"`
AiModel *AiModel `json:"ai_model"`
Timeout *int `json:"timeout"`
Retry *int `json:"retry"`
}
+35
View File
@@ -0,0 +1,35 @@
package ai_api_dto
import (
"github.com/eolinker/go-common/auto"
)
type API struct {
Id string `json:"id"`
Name string `json:"name"`
Path string `json:"path"`
Description string `json:"description"`
Disable bool `json:"disable"`
AiPrompt *AiPrompt `json:"ai_prompt"`
AiModel *AiModel `json:"ai_model"`
Timeout int `json:"timeout"`
Retry int `json:"retry"`
}
type APIItem struct {
Id string `json:"id"`
Name string `json:"name"`
RequestPath string `json:"request_path"`
Description string `json:"description"`
Disable bool `json:"disable"`
Creator auto.Label `json:"creator" aolabel:"user"`
Updater auto.Label `json:"updater" aolabel:"user"`
CreateTime auto.TimeLabel `json:"create_time"`
UpdateTime auto.TimeLabel `json:"update_time"`
Model ModelItem `json:"model"`
}
type ModelItem struct {
Id string `json:"id"`
Logo string `json:"logo"`
}
+278
View File
@@ -0,0 +1,278 @@
package ai_api
import (
"context"
"encoding/json"
"errors"
"fmt"
ai_api_dto "github.com/APIParkLab/APIPark/module/ai-api/dto"
"github.com/APIParkLab/APIPark/module/ai/provider"
ai_api "github.com/APIParkLab/APIPark/service/ai-api"
api_doc "github.com/APIParkLab/APIPark/service/api-doc"
"github.com/APIParkLab/APIPark/service/service"
"github.com/eolinker/go-common/auto"
"github.com/eolinker/go-common/store"
"github.com/eolinker/go-common/utils"
"github.com/getkin/kin-openapi/openapi3"
"github.com/google/uuid"
"gorm.io/gorm"
"net/http"
)
var _ IAPIModule = (*imlAPIModule)(nil)
var (
openapi3Loader = openapi3.NewLoader()
)
type imlAPIModule struct {
serviceService service.IServiceService `autowired:""`
apiDocService api_doc.IAPIDocService `autowired:""`
aiAPIService ai_api.IAPIService `autowired:""`
transaction store.ITransaction `autowired:""`
}
func (i *imlAPIModule) getAPIDoc(ctx context.Context, serviceId string) (*openapi3.T, error) {
doc, err := i.apiDocService.GetDoc(ctx, serviceId)
if err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) {
return nil, err
}
info, err := i.serviceService.Get(ctx, serviceId)
if err != nil {
return nil, fmt.Errorf("get service info error:%v", err)
}
return genOpenAPI3Template(info.Name, info.Description), nil
}
return openapi3Loader.LoadFromData([]byte(doc.Content))
}
func (i *imlAPIModule) updateAPIDoc(ctx context.Context, serviceId string, path string, description string, aiPrompt *ai_api_dto.AiPrompt) error {
doc, err := i.getAPIDoc(ctx, serviceId)
if err != nil {
return err
}
var variables []*ai_api_dto.AiPromptVariable
if aiPrompt != nil {
variables = aiPrompt.Variables
}
doc.AddOperation(path, http.MethodPost, genOperation(description, variables))
result, err := doc.MarshalJSON()
if err != nil {
return err
}
return i.apiDocService.UpdateDoc(ctx, serviceId, &api_doc.UpdateDoc{
ID: uuid.New().String(),
Content: string(result),
})
}
func (i *imlAPIModule) deleteAPIDoc(ctx context.Context, serviceId string, path string) error {
doc, err := i.getAPIDoc(ctx, serviceId)
if err != nil {
return err
}
doc.Paths.Delete(path)
result, err := doc.MarshalJSON()
if err != nil {
return err
}
return i.apiDocService.UpdateDoc(ctx, serviceId, &api_doc.UpdateDoc{
ID: uuid.New().String(),
Content: string(result),
})
}
func (i *imlAPIModule) Create(ctx context.Context, serviceId string, input *ai_api_dto.CreateAPI) (*ai_api_dto.API, error) {
info, err := i.serviceService.Get(ctx, serviceId)
if err != nil {
return nil, err
}
if info.Kind != service.AIService {
return nil, 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.updateAPIDoc(ctx, serviceId, input.Path, input.Description, input.AiPrompt)
if err != nil {
return err
}
return i.aiAPIService.Create(ctx, &ai_api.Create{
ID: input.Id,
Name: input.Name,
Service: serviceId,
Path: input.Path,
Description: input.Description,
Timeout: input.Timeout,
Retry: input.Retry,
Model: input.AiModel.Id,
AdditionalConfig: map[string]interface{}{
"ai_prompt": input.AiPrompt,
"ai_model": input.AiModel,
},
})
})
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) {
info, err := i.serviceService.Get(ctx, serviceId)
if err != nil {
return nil, err
}
if info.Kind != service.AIService {
return nil, fmt.Errorf("service kind is not ai service")
}
err = 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
}
if input.Description != nil {
apiInfo.Description = *input.Description
}
err = i.updateAPIDoc(ctx, serviceId, apiInfo.Path, apiInfo.Description, input.AiPrompt)
if err != nil {
return err
}
var modelId *string
if input.AiModel != nil {
modelId = &input.AiModel.Id
}
if input.AiPrompt != nil {
apiInfo.AdditionalConfig["ai_prompt"] = input.AiPrompt
}
if input.AiModel != nil {
apiInfo.AdditionalConfig["ai_model"] = input.AiModel
}
return i.aiAPIService.Save(ctx, apiId, &ai_api.Edit{
Name: input.Name,
Path: input.Path,
Description: input.Description,
Timeout: input.Timeout,
Retry: input.Retry,
Model: modelId,
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 {
info, err := i.serviceService.Get(ctx, serviceId)
if err != nil {
return err
}
if info.Kind != service.AIService {
return fmt.Errorf("service kind is not ai service")
}
return i.transaction.Transaction(ctx, func(txCtx context.Context) error {
err = i.deleteAPIDoc(ctx, serviceId, apiId)
if err != nil {
return err
}
return i.aiAPIService.Delete(ctx, apiId)
})
}
func (i *imlAPIModule) List(ctx context.Context, keyword string, serviceId string) ([]*ai_api_dto.APIItem, error) {
info, err := i.serviceService.Get(ctx, serviceId)
if err != nil {
return nil, err
}
if info.Kind != service.AIService {
return nil, fmt.Errorf("service kind is not ai service")
}
apis, err := i.aiAPIService.Search(ctx, keyword, map[string]interface{}{
"service": serviceId,
}, "update_at desc")
if err != nil {
return nil, err
}
p, has := provider.GetProvider(info.AdditionalConfig["provider"])
if !has {
return nil, fmt.Errorf("provider not found")
}
return utils.SliceToSlice(apis, func(t *ai_api.API) *ai_api_dto.APIItem {
modelItem := ai_api_dto.ModelItem{
Id: t.Model,
}
model, has := p.LLM(t.Model)
if has {
modelItem.Logo = model.Logo
}
return &ai_api_dto.APIItem{
Id: t.ID,
Name: t.Name,
RequestPath: t.Path,
Description: t.Description,
Disable: t.Disable,
Creator: auto.UUID(t.Creator),
Updater: auto.UUID(t.Updater),
CreateTime: auto.TimeLabel(t.CreateAt),
UpdateTime: auto.TimeLabel(t.UpdateAt),
Model: modelItem,
}
}), nil
}
func (i *imlAPIModule) Get(ctx context.Context, serviceId string, apiId string) (*ai_api_dto.API, error) {
info, err := i.serviceService.Get(ctx, serviceId)
if err != nil {
return nil, err
}
if info.Kind != service.AIService {
return nil, fmt.Errorf("service kind is not ai service")
}
apiInfo, err := i.aiAPIService.Get(ctx, apiId)
if err != nil {
return nil, err
}
prompt, err := ConvertStruct[ai_api_dto.AiPrompt](apiInfo.AdditionalConfig["ai_prompt"])
if err != nil {
return nil, err
}
aiModel, err := ConvertStruct[ai_api_dto.AiModel](apiInfo.AdditionalConfig["ai_model"])
if err != nil {
return nil, err
}
return &ai_api_dto.API{
Id: apiInfo.ID,
Name: apiInfo.Name,
Path: apiInfo.Path,
Description: apiInfo.Description,
Disable: apiInfo.Disable,
AiPrompt: prompt,
AiModel: aiModel,
Timeout: apiInfo.Timeout,
Retry: apiInfo.Retry,
}, nil
}
func ConvertStruct[T any](data interface{}) (*T, error) {
b, err := json.Marshal(data)
if err != nil {
return nil, err
}
var t T
err = json.Unmarshal(b, &t)
if err != nil {
return nil, err
}
return &t, nil
}
+23
View File
@@ -0,0 +1,23 @@
package ai_api
import (
"context"
ai_api_dto "github.com/APIParkLab/APIPark/module/ai-api/dto"
"github.com/eolinker/go-common/autowire"
"reflect"
)
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)
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)
}
func init() {
autowire.Auto[IAPIModule](func() reflect.Value {
m := new(imlAPIModule)
return reflect.ValueOf(m)
})
}
+105
View File
@@ -0,0 +1,105 @@
package ai_api
import (
ai_api_dto "github.com/APIParkLab/APIPark/module/ai-api/dto"
"github.com/getkin/kin-openapi/openapi3"
)
func genOpenAPI3Template(title string, description string) *openapi3.T {
result := new(openapi3.T)
result.OpenAPI = "3.1.0"
result.Info = &openapi3.Info{
Title: title,
Description: description,
Version: "beta",
}
result.Components = genComponents()
result.Paths = new(openapi3.Paths)
return result
}
func genOperation(description string, variables []*ai_api_dto.AiPromptVariable) *openapi3.Operation {
operation := openapi3.NewOperation()
operation.RequestBody = genRequestBody(variables)
operation.Responses = &openapi3.Responses{}
operation.Responses.Set("200", genResponse())
operation.Description = description
return operation
}
func genRequestBody(variables []*ai_api_dto.AiPromptVariable) *openapi3.RequestBodyRef {
requestBody := openapi3.NewRequestBody()
requestBody.Content = openapi3.NewContentWithSchema(genRequestBodySchema(variables), []string{"application/json"})
return &openapi3.RequestBodyRef{
Value: requestBody,
}
}
func genResponse() *openapi3.ResponseRef {
response := openapi3.NewResponse()
response.Content = openapi3.NewContentWithSchema(genResponseSchema(), []string{"application/json"})
description := "Response from the server"
response.Description = &description
return &openapi3.ResponseRef{
Value: response,
}
}
func genRequestBodySchema(variables []*ai_api_dto.AiPromptVariable) *openapi3.Schema {
result := openapi3.NewObjectSchema()
variableSchema := openapi3.NewObjectSchema()
required := make([]string, 0, len(variables))
for _, v := range variables {
val := openapi3.NewStringSchema()
val.Description = v.Description
if v.Require {
required = append(required, v.Key)
}
variableSchema.WithProperty(v.Key, val)
}
result.WithProperty("variables", variableSchema.WithRequired(required))
result.WithProperty("messages", genMessageSchema())
result.WithRequired([]string{"variables", "messages"})
return result
}
func genComponents() *openapi3.Components {
components := openapi3.NewComponents()
components.Schemas = make(openapi3.Schemas)
components.Schemas["Message"] = genMessageSchema().NewRef()
components.Schemas["Response"] = genResponseSchema().NewRef()
return &components
}
func genMessageSchema() *openapi3.Schema {
messageSchema := openapi3.NewObjectSchema()
messageSchema.Title = "Message"
messageSchema.Description = "Chat Message"
roleSchema := openapi3.NewStringSchema()
roleSchema.Description = "Role of the message sender"
roleSchema.Example = "assistant"
contentSchema := openapi3.NewStringSchema()
contentSchema.Description = "The message content"
contentSchema.Example = "Hello, how can I help you?"
messageSchema.WithProperties(map[string]*openapi3.Schema{
"role": roleSchema,
"content": contentSchema,
})
return messageSchema
}
func genResponseSchema() *openapi3.Schema {
responseSchema := openapi3.NewObjectSchema()
responseSchema.Description = "Response from the server"
responseSchema.WithPropertyRef("message", openapi3.NewSchemaRef("#/components/schemas/Message", genMessageSchema()))
responseSchema.WithProperty("code", openapi3.NewInt32Schema().WithMin(0))
responseSchema.WithProperty("error", openapi3.NewStringSchema())
responseSchema.WithProperty("finish_reason", openapi3.NewStringSchema().WithEnum([]string{
"stop",
"length",
"function_call",
"content_filter",
"null",
}))
return responseSchema
}
+6 -5
View File
@@ -8,11 +8,12 @@ type Provider struct {
}
type ProviderItem struct {
Id string `json:"id"`
Name string `json:"name"`
DefaultLLM string `json:"default_llm"`
Logo string `json:"logo"`
Configured bool `json:"configured"`
Id string `json:"id"`
Name string `json:"name"`
DefaultLLM string `json:"default_llm"`
DefaultLLMLogo string `json:"default_llm_logo"`
Logo string `json:"logo"`
Configured bool `json:"configured"`
}
type SimpleProviderItem struct {
+5
View File
@@ -69,11 +69,16 @@ func (i *imlProviderModule) Providers(ctx context.Context) ([]*ai_dto.ProviderIt
DefaultLLM: v.Info().DefaultLLM,
}
if info, has := providerMap[v.Info().Id]; has {
llm, has := v.LLM(info.DefaultLLM)
if !has {
continue
}
err = v.GlobalConfig().CheckConfig(info.Config)
if err == nil {
item.Configured = true
}
item.DefaultLLM = info.DefaultLLM
item.DefaultLLMLogo = llm.Logo
}
items = append(items, item)
}
+22 -7
View File
@@ -4,6 +4,7 @@ import (
_ "embed"
"encoding/json"
"github.com/APIParkLab/APIPark/module/ai/provider"
"github.com/eolinker/eosc"
"sync"
)
@@ -27,19 +28,23 @@ type ModelData struct {
type Model struct {
globalConfig provider.IAIConfig
invokeConfig provider.IAIConfig
models []*ModelData
models eosc.Untyped[string, *ModelData]
locker sync.RWMutex
}
func NewModel() provider.IAIProvider {
modelData := make([]*ModelData, 0)
json.Unmarshal(modelJson, &modelData)
return &Model{
m := &Model{
globalConfig: NewGlobalConfigDriver(),
invokeConfig: NewInvokeConfigDriver(),
models: modelData,
models: eosc.BuildUntyped[string, *ModelData](),
locker: sync.RWMutex{},
}
for _, v := range modelData {
m.models.Set(v.Id, v)
}
return m
}
func (m *Model) Index() int {
@@ -83,11 +88,9 @@ func (m *Model) UpdateLLMs() error {
}
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 {
result := make([]*provider.LLM, 0, models.Count())
for _, model := range models.List() {
llm := &provider.LLM{
Id: model.Id,
Logo: model.Logo,
@@ -97,3 +100,15 @@ func (m *Model) LLMs() []*provider.LLM {
}
return result
}
func (m *Model) LLM(id string) (*provider.LLM, bool) {
model, has := m.models.Get(id)
if !has {
return nil, false
}
return &provider.LLM{
Id: model.Id,
Logo: model.Logo,
Scopes: model.Scopes,
}, true
}
+1
View File
@@ -19,6 +19,7 @@ type IAIProvider interface {
InvokeConfig() IAIConfig
UpdateLLMs() error
LLMs() []*LLM
LLM(id string) (*LLM, bool)
}
type IAIConfig interface {
-1
View File
@@ -29,7 +29,6 @@ func (i *imlAPIDocModule) UpdateDoc(ctx context.Context, serviceId string, input
}
err = i.apiDocService.UpdateDoc(ctx, serviceId, &api_doc.UpdateDoc{
ID: input.Id,
Service: serviceId,
Content: input.Content,
})
if err != nil {
+6
View File
@@ -19,5 +19,11 @@ func (p *plugin) apiApis() []pm3.Api {
pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/service/api_doc", []string{"context", "query:service"}, []string{"doc"}, p.apiDocController.GetDoc),
pm3.CreateApiWidthDoc(http.MethodPost, "/api/v1/service/api_doc/upload", []string{"context", "query:service"}, []string{"doc"}, p.apiDocController.UploadDoc),
pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/service/ai-router", []string{"context", "query:service", "query:router"}, []string{"api"}, p.aiAPIController.Get),
pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/service/ai-routers", []string{"context", "query:keyword", "query:service"}, []string{"apis"}, p.aiAPIController.List),
pm3.CreateApiWidthDoc(http.MethodPut, "/api/v1/service/ai-router", []string{"context", "query:service", "query:router", "body"}, []string{"api"}, p.aiAPIController.Edit),
pm3.CreateApiWidthDoc(http.MethodPost, "/api/v1/service/ai-router", []string{"context", "query:service", "body"}, []string{"api"}, p.aiAPIController.Create),
pm3.CreateApiWidthDoc(http.MethodDelete, "/api/v1/service/ai-router", []string{"context", "query:service", "query:router"}, nil, p.aiAPIController.Delete),
}
}
+2
View File
@@ -2,6 +2,7 @@ package core
import (
"github.com/APIParkLab/APIPark/controller/ai"
ai_api "github.com/APIParkLab/APIPark/controller/ai-api"
"github.com/APIParkLab/APIPark/controller/monitor"
"github.com/APIParkLab/APIPark/controller/router"
"github.com/APIParkLab/APIPark/controller/system"
@@ -67,6 +68,7 @@ type plugin struct {
catalogueController catalogue.ICatalogueController `autowired:""`
upstreamController upstream.IUpstreamController `autowired:""`
routerController router.IRouterController `autowired:""`
aiAPIController ai_api.IAPIController `autowired:""`
apiDocController router.IAPIDocController `autowired:""`
subscribeController subscribe.ISubscribeController `autowired:""`
appAuthorizationController application_authorization.IAuthorizationController `autowired:""`
+2 -2
View File
@@ -20,12 +20,12 @@ func (p *plugin) ServiceApis() []pm3.Api {
//pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/simple/services", []string{"context", "query:keyword"}, []string{"services"}, p.serviceController.Simple),
// AI服务
pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/ai-services", []string{"context", "query:service", "query:keyword"}, []string{"service"}, p.serviceController.SearchAIServices),
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.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{"services"}, p.serviceController.Get),
pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/ai-service/info", []string{"context", "query:service"}, []string{"service"}, p.serviceController.Get),
// 应用相关
pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/app/info", []string{"context", "query:app"}, []string{"app"}, p.appController.GetApp),
+75
View File
@@ -0,0 +1,75 @@
package ai_api
import (
"encoding/json"
"github.com/APIParkLab/APIPark/service/universally"
"github.com/APIParkLab/APIPark/stores/api"
"time"
)
var _ IAPIService = (*imlAPIService)(nil)
type imlAPIService struct {
store api.IAiAPIInfoStore `autowired:""`
universally.IServiceGet[API]
universally.IServiceCreate[Create]
universally.IServiceEdit[Edit]
universally.IServiceDelete
}
func (i *imlAPIService) OnComplete() {
i.IServiceGet = universally.NewGetSoftDelete[API, api.AiAPIInfo](i.store, FromEntity)
i.IServiceCreate = universally.NewCreatorSoftDelete[Create, api.AiAPIInfo](i.store, "ai_api_info", createEntityHandler, uniquestHandler, labelHandler)
i.IServiceEdit = universally.NewEdit[Edit, api.AiAPIInfo](i.store, updateHandler)
i.IServiceDelete = universally.NewSoftDelete[api.AiAPIInfo](i.store)
}
func labelHandler(e *api.AiAPIInfo) []string {
return []string{e.Name, e.Uuid}
}
func uniquestHandler(i *Create) []map[string]interface{} {
return []map[string]interface{}{{"uuid": i.ID}}
}
func createEntityHandler(i *Create) *api.AiAPIInfo {
now := time.Now()
cfg, _ := json.Marshal(i.AdditionalConfig)
return &api.AiAPIInfo{
Uuid: i.ID,
Name: i.Name,
Service: i.Service,
Path: i.Path,
Description: i.Description,
Timeout: i.Timeout,
Retry: i.Retry,
Model: i.Model,
CreateAt: now,
UpdateAt: now,
AdditionalConfig: string(cfg),
}
}
func updateHandler(e *api.AiAPIInfo, i *Edit) {
if i.Name != nil {
e.Name = *i.Name
}
if i.Path != nil {
e.Path = *i.Path
}
if i.Description != nil {
e.Description = *i.Description
}
if i.Timeout != nil {
e.Timeout = *i.Timeout
}
if i.Retry != nil {
e.Retry = *i.Retry
}
if i.Model != nil {
e.Model = *i.Model
}
if i.AdditionalConfig != nil {
cfg, _ := json.Marshal(i.AdditionalConfig)
e.AdditionalConfig = string(cfg)
}
e.UpdateAt = time.Now()
}
+68
View File
@@ -0,0 +1,68 @@
package ai_api
import (
"encoding/json"
"github.com/APIParkLab/APIPark/stores/api"
"time"
)
type API struct {
ID string
Name string
Service string
Path string
Description string
Timeout int
Retry int
Model string
CreateAt time.Time
UpdateAt time.Time
Creator string
Updater string
AdditionalConfig map[string]interface{}
Disable bool
}
type Create struct {
ID string
Name string
Service string
Path string
Description string
Timeout int
Retry int
Model string
AdditionalConfig map[string]interface{}
}
type Edit struct {
Name *string
Path *string
Description *string
Timeout *int
Retry *int
Model *string
AdditionalConfig *map[string]interface{}
}
func FromEntity(e *api.AiAPIInfo) *API {
cfg := make(map[string]interface{})
if e.AdditionalConfig != "" {
_ = json.Unmarshal([]byte(e.AdditionalConfig), &cfg)
}
return &API{
ID: e.Uuid,
Name: e.Name,
Service: e.Service,
Path: e.Path,
Description: e.Description,
Timeout: e.Timeout,
Retry: e.Retry,
Model: e.Model,
CreateAt: e.CreateAt,
UpdateAt: e.UpdateAt,
Creator: e.Creator,
Updater: e.Updater,
AdditionalConfig: cfg,
}
}
+22
View File
@@ -0,0 +1,22 @@
package ai_api
import (
"github.com/APIParkLab/APIPark/service/universally"
"github.com/eolinker/go-common/autowire"
"reflect"
)
type IAPIService interface {
universally.IServiceGet[API]
universally.IServiceCreate[Create]
universally.IServiceEdit[Edit]
universally.IServiceDelete
//ListByServices(ctx context.Context, serviceIds ...string) ([]*API, error)
}
func init() {
autowire.Auto[IAPIService](func() reflect.Value {
return reflect.ValueOf(new(imlAPIService))
})
}
-1
View File
@@ -4,7 +4,6 @@ import "time"
type UpdateDoc struct {
ID string
Service string
Content string
}
+14
View File
@@ -23,15 +23,29 @@ type IAPIDocStore interface {
store.IBaseStore[Doc]
}
type IAiAPIInfoStore interface {
store.ISearchStore[AiAPIInfo]
}
type imlAiAPIInfoStore struct {
store.SearchStoreSoftDelete[AiAPIInfo]
}
func init() {
autowire.Auto[IApiBaseStore](func() reflect.Value {
return reflect.ValueOf(new(imlApiBaseStore))
})
autowire.Auto[IAPIInfoStore](func() reflect.Value {
return reflect.ValueOf(new(store.Store[Info]))
})
autowire.Auto[IAPIDocStore](func() reflect.Value {
return reflect.ValueOf(new(imlAPIDocStore))
})
autowire.Auto[IAiAPIInfoStore](func() reflect.Value {
return reflect.ValueOf(new(imlAiAPIInfoStore))
})
}
+26
View File
@@ -66,3 +66,29 @@ func (i *Doc) TableName() string {
func (i *Doc) IdValue() int64 {
return i.Id
}
type AiAPIInfo 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"`
Service string `gorm:"size:36;not null;column:service;comment:服务;index:service"`
Path string `gorm:"size:512;not null;column:path;comment:请求路径"`
Description string `gorm:"size:255;not null;column:description;comment:description"`
Timeout int `gorm:"type:int(11);not null;column:timeout;comment:超时时间"`
Retry int `gorm:"type:int(11);not null;column:retry;comment:重试次数"`
Model string `gorm:"size:36;not null;column:model;comment:模型"`
Creator string `gorm:"size:36;not null;column:creator;comment:创建人;index:creator" aovalue:"creator"`
CreateAt time.Time `gorm:"type:timestamp;NOT NULL;DEFAULT:CURRENT_TIMESTAMP;column:create_at;comment:创建时间"`
Updater string `gorm:"size:36;not null;column:updater;comment:更新人;index:updater" aovalue:"updater"`
UpdateAt time.Time `gorm:"type:timestamp;NOT NULL;DEFAULT:CURRENT_TIMESTAMP;column:update_at;comment:更新时间"`
AdditionalConfig string `gorm:"type:text;null;column:additional_config;comment:额外配置"`
IsDelete bool `gorm:"type:tinyint(1);not null;column:is_delete;comment:是否删除 0:否 1:是"`
}
func (a *AiAPIInfo) TableName() string {
return "ai_api_info"
}
func (a *AiAPIInfo) IdValue() int64 {
return a.Id
}