From 1c7ae7951e2c9334183bad5cc8ef8502b7c95bcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=A6=E7=A6=BB?= <101491308+jueli12@users.noreply.github.com> Date: Mon, 29 Jul 2024 22:08:28 +0800 Subject: [PATCH] feat: support ai backends (#551) /kind feature support an AI backend service that other modules can use to access AI language models. --- cmd/karpor/app/options/ai.go | 69 +++++++++++++++++++++++++++ cmd/karpor/app/server.go | 10 ++++ go.mod | 4 +- go.sum | 8 +++- pkg/core/handler/search/search.go | 5 +- pkg/core/manager/ai/manager.go | 36 +++++++++++++++ pkg/core/route/route.go | 10 +++- pkg/infra/ai/azureopenai.go | 75 ++++++++++++++++++++++++++++++ pkg/infra/ai/huggingface.go | 54 ++++++++++++++++++++++ pkg/infra/ai/openai.go | 77 +++++++++++++++++++++++++++++++ pkg/infra/ai/prompts.go | 25 ++++++++++ pkg/infra/ai/types.go | 71 ++++++++++++++++++++++++++++ pkg/kubernetes/registry/types.go | 6 +++ 13 files changed, 445 insertions(+), 5 deletions(-) create mode 100644 cmd/karpor/app/options/ai.go create mode 100644 pkg/core/manager/ai/manager.go create mode 100644 pkg/infra/ai/azureopenai.go create mode 100644 pkg/infra/ai/huggingface.go create mode 100644 pkg/infra/ai/openai.go create mode 100644 pkg/infra/ai/prompts.go create mode 100644 pkg/infra/ai/types.go diff --git a/cmd/karpor/app/options/ai.go b/cmd/karpor/app/options/ai.go new file mode 100644 index 00000000..f47d5592 --- /dev/null +++ b/cmd/karpor/app/options/ai.go @@ -0,0 +1,69 @@ +// Copyright The Karpor Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package options + +import ( + "github.com/KusionStack/karpor/pkg/kubernetes/registry" + "github.com/spf13/pflag" +) + +type AIOptions struct { + Backend string + AuthToken string + BaseURL string + Model string + Temperature float32 + TopP float32 +} + +const ( + defaultBackend = "openai" + defaultModel = "gpt-3.5-turbo" + defaultTemperature = 1 + defaultTopP = 1 +) + +func NewAIOptions() *AIOptions { + return &AIOptions{} +} + +func (o *AIOptions) Validate() []error { + return nil +} + +func (o *AIOptions) ApplyTo(config *registry.ExtraConfig) error { + // Apply the AIOptions to the provided config + config.Backend = o.Backend + config.AuthToken = o.AuthToken + config.BaseURL = o.BaseURL + config.Model = o.Model + config.Temperature = o.Temperature + config.TopP = o.TopP + return nil +} + +// AddFlags adds flags for a specific Option to the specified FlagSet +func (o *AIOptions) AddFlags(fs *pflag.FlagSet) { + if o == nil { + return + } + + fs.StringVar(&o.Backend, "ai-backend", defaultBackend, "The ai backend") + fs.StringVar(&o.AuthToken, "ai-auth-token", "", "The ai auth token") + fs.StringVar(&o.BaseURL, "ai-base-url", "", "The ai base url") + fs.StringVar(&o.Model, "ai-model", defaultModel, "The ai model") + fs.Float32Var(&o.Temperature, "ai-temperature", defaultTemperature, "The ai temperature") + fs.Float32Var(&o.TopP, "ai-top-p", defaultTopP, "The ai top-p") +} diff --git a/cmd/karpor/app/server.go b/cmd/karpor/app/server.go index 9c3627c5..57ecba59 100644 --- a/cmd/karpor/app/server.go +++ b/cmd/karpor/app/server.go @@ -50,6 +50,7 @@ type Options struct { RecommendedOptions *options.RecommendedOptions SearchStorageOptions *options.SearchStorageOptions CoreOptions *options.CoreOptions + AIOptions *options.AIOptions StdOut io.Writer StdErr io.Writer @@ -66,6 +67,7 @@ func NewOptions(out, errOut io.Writer) (*Options, error) { ), SearchStorageOptions: options.NewSearchStorageOptions(), CoreOptions: options.NewCoreOptions(), + AIOptions: options.NewAIOptions(), StdOut: out, StdErr: errOut, } @@ -97,6 +99,9 @@ func NewServerCommand(ctx context.Context) *cobra.Command { expvar.Publish("StorageOptions", expvar.Func(func() interface{} { return o.SearchStorageOptions })) + expvar.Publish("AIOptions", expvar.Func(func() interface{} { + return o.AIOptions + })) expvar.Publish("Version", expvar.Func(func() interface{} { return version.GetVersion() })) @@ -132,6 +137,7 @@ func (o *Options) AddFlags(fs *pflag.FlagSet) { o.RecommendedOptions.AddFlags(fs) o.SearchStorageOptions.AddFlags(fs) o.CoreOptions.AddFlags(fs) + o.AIOptions.AddFlags(fs) } // Validate validates Options @@ -139,6 +145,7 @@ func (o *Options) Validate(args []string) error { errors := []error{} errors = append(errors, o.RecommendedOptions.Validate()...) errors = append(errors, o.SearchStorageOptions.Validate()...) + errors = append(errors, o.AIOptions.Validate()...) return utilerrors.NewAggregate(errors) } @@ -162,6 +169,9 @@ func (o *Options) Config() (*server.Config, error) { if err := o.CoreOptions.ApplyTo(config.ExtraConfig); err != nil { return nil, err } + if err := o.AIOptions.ApplyTo(config.ExtraConfig); err != nil { + return nil, err + } config.GenericConfig.BuildHandlerChainFunc = func(handler http.Handler, c *genericapiserver.Config) http.Handler { handler = genericapiserver.DefaultBuildHandlerChain(handler, c) diff --git a/go.mod b/go.mod index e1f7f042..6344a176 100644 --- a/go.mod +++ b/go.mod @@ -15,10 +15,12 @@ require ( github.com/go-chi/render v1.0.3 github.com/go-logr/logr v1.2.3 github.com/google/gofuzz v1.2.0 - github.com/google/uuid v1.3.0 + github.com/google/uuid v1.4.0 + github.com/hupe1980/go-huggingface v0.0.15 github.com/mitchellh/hashstructure/v2 v2.0.2 github.com/oliveagle/jsonpath v0.0.0-20180606110733-2e52cf6e6852 github.com/pkg/errors v0.9.1 + github.com/sashabaranov/go-openai v1.27.0 github.com/spf13/cobra v1.6.1 github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.8.4 diff --git a/go.sum b/go.sum index 1f7770d9..4e8744d6 100644 --- a/go.sum +++ b/go.sum @@ -249,8 +249,8 @@ github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hf github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= +github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= @@ -268,6 +268,8 @@ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw= github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/hupe1980/go-huggingface v0.0.15 h1:tTWmUGGunC/BYz4hrwS8SSVtMYVYjceG2uhL8HxeXvw= +github.com/hupe1980/go-huggingface v0.0.15/go.mod h1:IRvsik3+b9BJyw9hCfw1arI6gDObcVto1UA8f3kt8mM= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= @@ -384,6 +386,8 @@ github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBO github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= 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.27.0 h1:L3hO6650YUbKrbGUC6yCjsUluhKZ9h1/jcgbTItI8Mo= +github.com/sashabaranov/go-openai v1.27.0/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg= github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= diff --git a/pkg/core/handler/search/search.go b/pkg/core/handler/search/search.go index cbbbe7bf..35bb3623 100644 --- a/pkg/core/handler/search/search.go +++ b/pkg/core/handler/search/search.go @@ -15,6 +15,7 @@ package search import ( + "github.com/KusionStack/karpor/pkg/core/manager/ai" "net/http" "strconv" @@ -45,12 +46,14 @@ import ( // @Failure 429 {string} string "Too Many Requests" // @Failure 500 {string} string "Internal Server Error" // @Router /rest-api/v1/search [get] -func SearchForResource(searchMgr *search.SearchManager, searchStorage storage.SearchStorage) http.HandlerFunc { +func SearchForResource(searchMgr *search.SearchManager, aiMgr *ai.AIManager, searchStorage storage.SearchStorage) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { // Extract the context and logger from the request. ctx := r.Context() logger := ctxutil.GetLogger(ctx) + //res, nil := aiMgr.ConvertTextToSQL("搜索集群cluster中kind为namespace的") + // Extract URL query parameters with default value searchQuery := r.URL.Query().Get("query") searchPattern := r.URL.Query().Get("pattern") diff --git a/pkg/core/manager/ai/manager.go b/pkg/core/manager/ai/manager.go new file mode 100644 index 00000000..699a4bc8 --- /dev/null +++ b/pkg/core/manager/ai/manager.go @@ -0,0 +1,36 @@ +// Copyright The Karpor Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ai + +import ( + "github.com/KusionStack/karpor/pkg/infra/ai" + "github.com/KusionStack/karpor/pkg/kubernetes/registry" +) + +type AIManager struct { + client ai.AIProvider +} + +// NewAIManager returns a new AIManager object +func NewAIManager(c registry.ExtraConfig) (*AIManager, error) { + aiClient := ai.NewClient(c.Backend) + if err := aiClient.Configure(ai.ConvertToAIConfig(c)); err != nil { + return nil, err + } + + return &AIManager{ + client: aiClient, + }, nil +} diff --git a/pkg/core/route/route.go b/pkg/core/route/route.go index b35a866c..6b2eebb3 100644 --- a/pkg/core/route/route.go +++ b/pkg/core/route/route.go @@ -16,6 +16,7 @@ package route import ( "expvar" + docs "github.com/KusionStack/karpor/api/openapispec" clusterhandler "github.com/KusionStack/karpor/pkg/core/handler/cluster" detailhandler "github.com/KusionStack/karpor/pkg/core/handler/detail" @@ -29,6 +30,7 @@ import ( summaryhandler "github.com/KusionStack/karpor/pkg/core/handler/summary" topologyhandler "github.com/KusionStack/karpor/pkg/core/handler/topology" healthhandler "github.com/KusionStack/karpor/pkg/core/health" + aimanager "github.com/KusionStack/karpor/pkg/core/manager/ai" clustermanager "github.com/KusionStack/karpor/pkg/core/manager/cluster" insightmanager "github.com/KusionStack/karpor/pkg/core/manager/insight" resourcegroupmanager "github.com/KusionStack/karpor/pkg/core/manager/resourcegroup" @@ -87,6 +89,10 @@ func NewCoreRoute( if err != nil { return nil, err } + aiMgr, err := aimanager.NewAIManager(*extraConfig) + if err != nil { + return nil, err + } clusterMgr := clustermanager.NewClusterManager() searchMgr := searchmanager.NewSearchManager() @@ -94,6 +100,7 @@ func NewCoreRoute( // Set up the API routes for version 1 of the API. router.Route("/rest-api/v1", func(r chi.Router) { setupRestAPIV1(r, + aiMgr, clusterMgr, insightMgr, resourceGroupMgr, @@ -120,6 +127,7 @@ func NewCoreRoute( // resource type and setting up proper handlers. func setupRestAPIV1( r chi.Router, + aiMgr *aimanager.AIManager, clusterMgr *clustermanager.ClusterManager, insightMgr *insightmanager.InsightManager, resourceGroupMgr *resourcegroupmanager.ResourceGroupManager, @@ -144,7 +152,7 @@ func setupRestAPIV1( }) r.Route("/search", func(r chi.Router) { - r.Get("/", searchhandler.SearchForResource(searchMgr, searchStorage)) + r.Get("/", searchhandler.SearchForResource(searchMgr, aiMgr, searchStorage)) }) r.Route("/insight", func(r chi.Router) { diff --git a/pkg/infra/ai/azureopenai.go b/pkg/infra/ai/azureopenai.go new file mode 100644 index 00000000..37f9762e --- /dev/null +++ b/pkg/infra/ai/azureopenai.go @@ -0,0 +1,75 @@ +// Copyright The Karpor Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ai + +import ( + "context" + "errors" + "github.com/sashabaranov/go-openai" +) + +type AzureAIClient struct { + client *openai.Client + model string + temperature float32 +} + +func (c *AzureAIClient) Configure(cfg AIConfig) error { + if cfg.AuthToken == "" { + return errors.New("auth token was not provided") + } + if cfg.BaseURL == "" { + return errors.New("base url was not provided") + } + + defaultConfig := openai.DefaultAzureConfig(cfg.AuthToken, cfg.BaseURL) + + client := openai.NewClientWithConfig(defaultConfig) + if client == nil { + return errors.New("error creating Azure OpenAI client") + } + + c.client = client + c.model = cfg.Model + c.temperature = cfg.Temperature + return nil +} + +func (c *AzureAIClient) Generate(ctx context.Context, prompt string, serviceType string) (string, error) { + servicePrompt := ServicePromptMap[serviceType] + + resp, err := c.client.CreateChatCompletion(ctx, openai.ChatCompletionRequest{ + Model: c.model, + Messages: []openai.ChatCompletionMessage{ + { + Role: openai.ChatMessageRoleSystem, + Content: servicePrompt, + }, + { + Role: openai.ChatMessageRoleUser, + Content: prompt, + }, + }, + Temperature: c.temperature, + }) + if err != nil { + return "", err + } + + if len(resp.Choices) == 0 { + return "", errors.New("no completion choices returned from response") + } + return resp.Choices[0].Message.Content, nil +} diff --git a/pkg/infra/ai/huggingface.go b/pkg/infra/ai/huggingface.go new file mode 100644 index 00000000..edd5e6eb --- /dev/null +++ b/pkg/infra/ai/huggingface.go @@ -0,0 +1,54 @@ +// Copyright The Karpor Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ai + +import ( + "context" + "github.com/hupe1980/go-huggingface" +) + +type HuggingfaceClient struct { + client *huggingface.InferenceClient + model string + temperature float32 +} + +func (c *HuggingfaceClient) Configure(cfg AIConfig) error { + client := huggingface.NewInferenceClient(cfg.AuthToken) + + c.client = client + c.model = cfg.Model + c.temperature = cfg.Temperature + return nil +} + +func (c *HuggingfaceClient) Generate(ctx context.Context, prompt string, serviceType string) (string, error) { + resp, err := c.client.TextGeneration(ctx, &huggingface.TextGenerationRequest{ + Inputs: prompt, + Parameters: huggingface.TextGenerationParameters{ + Temperature: huggingface.PTR(float64(c.temperature)), + }, + Options: huggingface.Options{ + WaitForModel: huggingface.PTR(true), + }, + Model: c.model, + }) + + if err != nil { + return "", err + } + return resp[0].GeneratedText[len(prompt):], nil + +} diff --git a/pkg/infra/ai/openai.go b/pkg/infra/ai/openai.go new file mode 100644 index 00000000..82ef8c14 --- /dev/null +++ b/pkg/infra/ai/openai.go @@ -0,0 +1,77 @@ +// Copyright The Karpor Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ai + +import ( + "context" + "errors" + "github.com/sashabaranov/go-openai" +) + +type OpenAIClient struct { + client *openai.Client + model string + temperature float32 + topP float32 +} + +func (c *OpenAIClient) Configure(cfg AIConfig) error { + if cfg.AuthToken == "" { + return errors.New("auth token was not provided") + } + defaultConfig := openai.DefaultConfig(cfg.AuthToken) + if cfg.BaseURL != "" { + defaultConfig.BaseURL = cfg.BaseURL + } + + client := openai.NewClientWithConfig(defaultConfig) + if client == nil { + return errors.New("error creating OpenAI client") + } + + c.client = client + c.model = cfg.Model + c.temperature = cfg.Temperature + c.topP = cfg.TopP + return nil +} + +func (c *OpenAIClient) Generate(ctx context.Context, prompt string, serviceType string) (string, error) { + servicePrompt := ServicePromptMap[serviceType] + + resp, err := c.client.CreateChatCompletion(ctx, openai.ChatCompletionRequest{ + Model: c.model, + Messages: []openai.ChatCompletionMessage{ + { + Role: openai.ChatMessageRoleSystem, + Content: servicePrompt, + }, + { + Role: openai.ChatMessageRoleUser, + Content: prompt, + }, + }, + Temperature: c.temperature, + TopP: c.topP, + }) + if err != nil { + return "", err + } + + if len(resp.Choices) == 0 { + return "", errors.New("no completion choices returned from response") + } + return resp.Choices[0].Message.Content, nil +} diff --git a/pkg/infra/ai/prompts.go b/pkg/infra/ai/prompts.go new file mode 100644 index 00000000..7d4479a5 --- /dev/null +++ b/pkg/infra/ai/prompts.go @@ -0,0 +1,25 @@ +// Copyright The Karpor Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ai + +const ( + default_prompt = "You are a helpful assistant." + search_prompt = "You are an AI specialized in writing SQL queries. Please provide the SQL statement as a formatted string." +) + +var ServicePromptMap = map[string]string{ + "default": default_prompt, + "search": search_prompt, +} diff --git a/pkg/infra/ai/types.go b/pkg/infra/ai/types.go new file mode 100644 index 00000000..0d2025eb --- /dev/null +++ b/pkg/infra/ai/types.go @@ -0,0 +1,71 @@ +// Copyright The Karpor Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ai + +import ( + "context" + "github.com/KusionStack/karpor/pkg/kubernetes/registry" +) + +const ( + AzureProvider = "azureopenai" + HuggingFaceProvider = "huggingface" + OpenAIProvider = "openai" +) + +var clients = map[string]AIProvider{ + AzureProvider: &AzureAIClient{}, + HuggingFaceProvider: &HuggingfaceClient{}, + OpenAIProvider: &OpenAIClient{}, +} + +// AIProvider is an interface all AI clients. +type AIProvider interface { + // Configure sets up the AI service with the provided configuration. + Configure(config AIConfig) error + // Generate generates a response from the AI service based on + // the provided prompt and service type. + Generate(ctx context.Context, prompt string, serviceType string) (string, error) +} + +// AIConfig represents the configuration settings for an AI client. +type AIConfig struct { + Name string + AuthToken string + BaseURL string + Model string + Temperature float32 + TopP float32 +} + +func ConvertToAIConfig(c registry.ExtraConfig) AIConfig { + return AIConfig{ + Name: c.Backend, + AuthToken: c.AuthToken, + BaseURL: c.BaseURL, + Model: c.Model, + Temperature: c.Temperature, + TopP: c.TopP, + } +} + +// NewClient returns a new AIProvider object +func NewClient(name string) AIProvider { + if client, exists := clients[name]; exists { + return client + } + // default client + return &OpenAIClient{} +} diff --git a/pkg/kubernetes/registry/types.go b/pkg/kubernetes/registry/types.go index 688269a0..333a8bef 100644 --- a/pkg/kubernetes/registry/types.go +++ b/pkg/kubernetes/registry/types.go @@ -37,4 +37,10 @@ type ExtraConfig struct { ElasticSearchPassword string ReadOnlyMode bool GithubBadge bool + Backend string + AuthToken string + BaseURL string + Model string + Temperature float32 + TopP float32 }