feat: added the ability to set a user default AI provider (#427)

* feat: added the ability to set a user default AI provider

Signed-off-by: Alex Jones <alexsimonjones@gmail.com>

* feat: added the ability to set a user default AI provider

Signed-off-by: Alex Jones <alexsimonjones@gmail.com>

* chore: added provider to json output

Signed-off-by: Alex Jones <alexsimonjones@gmail.com>

---------

Signed-off-by: Alex Jones <alexsimonjones@gmail.com>
This commit is contained in:
Alex Jones
2023-05-16 12:31:19 +01:00
committed by GitHub
parent 032576c728
commit cbe2fb4a4c
7 changed files with 180 additions and 26 deletions

View File

@@ -277,6 +277,38 @@ curl -X GET "http://localhost:8080/analyze?namespace=k8sgpt&explain=false"
## Additional AI providers ## Additional AI providers
### Setting a new default AI provider
<details>
There may be scenarios where you wish to have K8sGPT plugged into several default AI providers. In this case you may wish to use one as a new default, other than OpenAI which is the project default.
_To view available providers_
```
k8sgpt auth list
Default:
> openai
Active:
> openai
> azureopenai
Unused:
> localai
> noopai
```
_To set a new default provider_
```
k8sgpt auth default -p azureopenai
Default provider set to azureopenai
```
</details>
### Azure OpenAI ### Azure OpenAI
<em>Prerequisites:</em> an Azure OpenAI deployment is needed, please visit MS official [documentation](https://learn.microsoft.com/en-us/azure/cognitive-services/openai/how-to/create-resource?pivots=web-portal#create-a-resource) to create your own. <em>Prerequisites:</em> an Azure OpenAI deployment is needed, please visit MS official [documentation](https://learn.microsoft.com/en-us/azure/cognitive-services/openai/how-to/create-resource?pivots=web-portal#create-a-resource) to create your own.
@@ -286,7 +318,7 @@ To authenticate with k8sgpt, you will need the Azure OpenAI endpoint of your ten
### Run k8sgpt ### Run k8sgpt
To run k8sgpt, run `k8sgpt auth` with the `azureopenai` backend: To run k8sgpt, run `k8sgpt auth` with the `azureopenai` backend:
``` ```
k8sgpt auth --backend azureopenai --baseurl https://<your Azure OpenAI endpoint> --engine <deployment_name> --model <model_name> k8sgpt auth new --backend azureopenai --baseurl https://<your Azure OpenAI endpoint> --engine <deployment_name> --model <model_name>
``` ```
Lastly, enter your Azure API key, after the prompt. Lastly, enter your Azure API key, after the prompt.

View File

@@ -48,4 +48,6 @@ func init() {
AuthCmd.AddCommand(newCmd) AuthCmd.AddCommand(newCmd)
// add subcommand to remove new backend provider // add subcommand to remove new backend provider
AuthCmd.AddCommand(removeCmd) AuthCmd.AddCommand(removeCmd)
// add subcommand to set default backend provider
AuthCmd.AddCommand(defaultCmd)
} }

79
cmd/auth/default.go Normal file
View File

@@ -0,0 +1,79 @@
/*
Copyright 2023 The K8sGPT 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 auth
import (
"os"
"strings"
"github.com/fatih/color"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var (
providerName string
)
var defaultCmd = &cobra.Command{
Use: "default",
Short: "Set your default AI backend provider",
Long: "The command to set your new default AI backend provider (default is openai)",
Run: func(cmd *cobra.Command, args []string) {
err := viper.UnmarshalKey("ai", &configAI)
if err != nil {
color.Red("Error: %v", err)
os.Exit(1)
}
if providerName == "" {
if configAI.DefaultProvider != "" {
color.Yellow("Your default provider is %s", configAI.DefaultProvider)
} else {
color.Yellow("Your default provider is openai")
}
os.Exit(0)
}
// lowercase the provider name
providerName = strings.ToLower(providerName)
// Check if the provider is in the provider list
providerExists := false
for _, provider := range configAI.Providers {
if provider.Name == providerName {
providerExists = true
}
}
if !providerExists {
color.Red("Error: Provider %s does not exist", providerName)
os.Exit(1)
}
// Set the default provider
configAI.DefaultProvider = providerName
viper.Set("ai", configAI)
// Viper write config
err = viper.WriteConfig()
if err != nil {
color.Red("Error: %v", err)
os.Exit(1)
}
// Print acknowledgement
color.Green("Default provider set to %s", providerName)
},
}
func init() {
// provider name flag
defaultCmd.Flags().StringVarP(&providerName, "provider", "p", "", "The name of the provider to set as default")
}

View File

@@ -18,6 +18,7 @@ import (
"os" "os"
"github.com/fatih/color" "github.com/fatih/color"
"github.com/k8sgpt-ai/k8sgpt/pkg/ai"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/viper" "github.com/spf13/viper"
) )
@@ -35,12 +36,37 @@ var listCmd = &cobra.Command{
os.Exit(1) os.Exit(1)
} }
// iterate over the provider list and prints each provider name // Print the default if it is set
for _, provider := range configAI.Providers { fmt.Print(color.YellowString("Default: \n"))
if len(configAI.Providers) == 0 { if configAI.DefaultProvider != "" {
color.Red("Provider list is currently empty.") fmt.Printf("> %s\n", color.BlueString(configAI.DefaultProvider))
} else { } else {
fmt.Printf("> %s\n", provider.Name) fmt.Printf("> %s\n", color.BlueString("openai"))
}
// Get list of all AI Backends and only print htem if they are not in the provider list
fmt.Print(color.YellowString("Active: \n"))
for _, aiBackend := range ai.Backends {
providerExists := false
for _, provider := range configAI.Providers {
if provider.Name == aiBackend {
providerExists = true
}
}
if providerExists {
fmt.Printf("> %s\n", color.GreenString(aiBackend))
}
}
fmt.Print(color.YellowString("Unused: \n"))
for _, aiBackend := range ai.Backends {
providerExists := false
for _, provider := range configAI.Providers {
if provider.Name == aiBackend {
providerExists = true
}
}
if !providerExists {
fmt.Printf("> %s\n", color.RedString(aiBackend))
} }
} }
}, },

View File

@@ -60,6 +60,7 @@ func NewClient(provider string) IAI {
type AIConfiguration struct { type AIConfiguration struct {
Providers []AIProvider `mapstructure:"providers"` Providers []AIProvider `mapstructure:"providers"`
DefaultProvider string `mapstructure:"defaultprovider"`
} }
type AIProvider struct { type AIProvider struct {

View File

@@ -44,6 +44,7 @@ type Analysis struct {
Cache cache.ICache Cache cache.ICache
Explain bool Explain bool
MaxConcurrency int MaxConcurrency int
AnalysisAIProvider string // The name of the AI Provider used for this analysis
} }
type AnalysisStatus string type AnalysisStatus string
@@ -55,6 +56,7 @@ const (
) )
type JsonOutput struct { type JsonOutput struct {
Provider string `json:"provider"`
Errors AnalysisErrors `json:"errors"` Errors AnalysisErrors `json:"errors"`
Status AnalysisStatus `json:"status"` Status AnalysisStatus `json:"status"`
Problems int `json:"problems"` Problems int `json:"problems"`
@@ -74,6 +76,12 @@ func NewAnalysis(backend string, language string, filters []string, namespace st
os.Exit(1) os.Exit(1)
} }
// Backend string will have high priority than a default provider
// Backend as "openai" represents the default CLI argument passed through
if configAI.DefaultProvider != "" && backend == "openai" {
backend = configAI.DefaultProvider
}
var aiProvider ai.AIProvider var aiProvider ai.AIProvider
for _, provider := range configAI.Providers { for _, provider := range configAI.Providers {
if backend == provider.Name { if backend == provider.Name {
@@ -113,6 +121,7 @@ func NewAnalysis(backend string, language string, filters []string, namespace st
Cache: cache.New(noCache), Cache: cache.New(noCache),
Explain: explain, Explain: explain,
MaxConcurrency: maxConcurrency, MaxConcurrency: maxConcurrency,
AnalysisAIProvider: backend,
}, nil }, nil
} }

View File

@@ -42,6 +42,7 @@ func (a *Analysis) jsonOutput() ([]byte, error) {
} }
result := JsonOutput{ result := JsonOutput{
Provider: a.AnalysisAIProvider,
Problems: problems, Problems: problems,
Results: a.Results, Results: a.Results,
Errors: a.Errors, Errors: a.Errors,
@@ -56,6 +57,10 @@ func (a *Analysis) jsonOutput() ([]byte, error) {
func (a *Analysis) textOutput() ([]byte, error) { func (a *Analysis) textOutput() ([]byte, error) {
var output strings.Builder var output strings.Builder
// Print the AI provider used for this analysis
output.WriteString(fmt.Sprintf("AI Provider: %s\n", color.YellowString(a.AnalysisAIProvider)))
if len(a.Errors) != 0 { if len(a.Errors) != 0 {
output.WriteString("\n") output.WriteString("\n")
output.WriteString(color.YellowString("Warnings : \n")) output.WriteString(color.YellowString("Warnings : \n"))