diff --git a/build/npm/v2-jf/package-lock.json b/build/npm/v2-jf/package-lock.json index f23360664..59ba713e4 100644 --- a/build/npm/v2-jf/package-lock.json +++ b/build/npm/v2-jf/package-lock.json @@ -1,5 +1,5 @@ { "name": "jfrog-cli-v2-jf", - "version": "2.57.0", + "version": "2.57.1", "lockfileVersion": 1 } diff --git a/build/npm/v2-jf/package.json b/build/npm/v2-jf/package.json index eedee72ed..ea326cfb1 100644 --- a/build/npm/v2-jf/package.json +++ b/build/npm/v2-jf/package.json @@ -1,6 +1,6 @@ { "name": "jfrog-cli-v2-jf", - "version": "2.57.0", + "version": "2.57.1", "description": "🐸 Command-line interface for JFrog Artifactory, Xray, Distribution, Pipelines and Mission Control 🐸", "homepage": "https://github.com/jfrog/jfrog-cli", "preferGlobal": true, diff --git a/build/npm/v2/package-lock.json b/build/npm/v2/package-lock.json index 214456828..cdffc01fe 100644 --- a/build/npm/v2/package-lock.json +++ b/build/npm/v2/package-lock.json @@ -1,5 +1,5 @@ { "name": "jfrog-cli-v2", - "version": "2.57.0", + "version": "2.57.1", "lockfileVersion": 2 } diff --git a/build/npm/v2/package.json b/build/npm/v2/package.json index 4f2d31518..61a95ba30 100644 --- a/build/npm/v2/package.json +++ b/build/npm/v2/package.json @@ -1,6 +1,6 @@ { "name": "jfrog-cli-v2", - "version": "2.57.0", + "version": "2.57.1", "description": "🐸 Command-line interface for JFrog Artifactory, Xray, Distribution, Pipelines and Mission Control 🐸", "homepage": "https://github.com/jfrog/jfrog-cli", "preferGlobal": true, diff --git a/docs/general/ai/help.go b/docs/general/ai/help.go index 17404995e..9c4e35142 100644 --- a/docs/general/ai/help.go +++ b/docs/general/ai/help.go @@ -3,5 +3,5 @@ package ai var Usage = []string{"how"} func GetDescription() string { - return "Ask questions about JFrog CLI commands and their usage." + return "This AI-based interface converts your natural language inputs into fully functional JFrog CLI commands. This is an interactive command that accepts no arguments." } diff --git a/general/ai/cli.go b/general/ai/cli.go index 5d513b6fd..e8afa8cba 100644 --- a/general/ai/cli.go +++ b/general/ai/cli.go @@ -1,36 +1,39 @@ package ai import ( + "bufio" "bytes" "encoding/json" "errors" "fmt" "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" - "github.com/jfrog/jfrog-cli-core/v2/utils/ioutils" "github.com/jfrog/jfrog-cli/utils/cliutils" + "github.com/jfrog/jfrog-client-go/artifactory/services/utils" "github.com/jfrog/jfrog-client-go/http/httpclient" "github.com/jfrog/jfrog-client-go/utils/errorutils" "github.com/jfrog/jfrog-client-go/utils/log" "github.com/urfave/cli" "io" "net/http" + "os" "strings" ) type ApiCommand string const ( - cliAiApiPath = "https://cli-ai.jfrog.info/" - questionApi ApiCommand = "ask" - feedbackApi ApiCommand = "feedback" + cliAiApiPath = "https://cli-ai-app.jfrog.info/" + apiPrefix = "api/" + questionApi ApiCommand = apiPrefix + "ask" + feedbackApi ApiCommand = apiPrefix + "feedback" ) -type questionBody struct { +type QuestionBody struct { Question string `json:"question"` } -type feedbackBody struct { - questionBody +type FeedbackBody struct { + QuestionBody LlmAnswer string `json:"llm_answer"` IsAccurate bool `json:"is_accurate"` ExpectedAnswer string `json:"expected_answer"` @@ -40,47 +43,63 @@ func HowCmd(c *cli.Context) error { if show, err := cliutils.ShowCmdHelpIfNeeded(c, c.Args()); show || err != nil { return err } - if c.NArg() < 1 { + if c.NArg() > 0 { return cliutils.WrongNumberOfArgumentsHandler(c) } + log.Output(coreutils.PrintTitle("This AI-based interface converts your natural language inputs into fully functional JFrog CLI commands.\n" + + "NOTE: This is a beta version and it supports mostly Artifactory and Xray commands.\n")) - args := cliutils.ExtractCommand(c) - question := questionBody{Question: fmt.Sprintf("How %s", strings.Join(args, " "))} - llmAnswer, err := askQuestion(question) - if err != nil { - return err - } - if strings.ToLower(llmAnswer) == "i dont know" { - log.Output("The current version of the AI model does not support this type of command yet.") - return nil - } - log.Output("AI generated JFrog CLI command:") - err = coreutils.PrintTable("", "", coreutils.PrintTitle(llmAnswer), false) - if err != nil { - return err - } + for { + var question string + scanner := bufio.NewScanner(os.Stdin) + fmt.Print("🐸 Your request: ") + for { + // Ask the user for a question + scanner.Scan() + question = strings.TrimSpace(scanner.Text()) + if question != "" { + // If the user entered a question, break the loop + break + } + } + questionBody := QuestionBody{Question: question} + llmAnswer, err := askQuestion(questionBody) + if err != nil { + return err + } - feedback := feedbackBody{questionBody: question, LlmAnswer: llmAnswer} - feedback.getUserFeedback() - if err = sendFeedback(feedback); err != nil { - return err + log.Output("🤖 Generated command: " + coreutils.PrintLink(llmAnswer) + "\n") + feedback := FeedbackBody{QuestionBody: questionBody, LlmAnswer: llmAnswer} + feedback.getUserFeedback() + if err = sendFeedback(feedback); err != nil { + return err + } + log.Output("\n" + coreutils.PrintComment("-------------------") + "\n") } - log.Output("Thank you for your feedback!") - return nil } -func (fb *feedbackBody) getUserFeedback() { - fb.IsAccurate = coreutils.AskYesNo(coreutils.PrintLink("Is the provided command accurate?"), true) +func (fb *FeedbackBody) getUserFeedback() { + fb.IsAccurate = coreutils.AskYesNo("Is the provided command accurate?", true) if !fb.IsAccurate { - ioutils.ScanFromConsole("Please provide the exact command you expected (Example: 'jf rt u ...')", &fb.ExpectedAnswer, "") + scanner := bufio.NewScanner(os.Stdin) + fmt.Print("Please provide the exact command you expected (Example: 'jf rt u ...'): ") + for { + scanner.Scan() + expectedAnswer := strings.TrimSpace(scanner.Text()) + if expectedAnswer != "" { + // If the user entered an expected answer, break and return + fb.ExpectedAnswer = expectedAnswer + return + } + } } } -func askQuestion(question questionBody) (response string, err error) { +func askQuestion(question QuestionBody) (response string, err error) { return sendRequestToCliAiServer(question, questionApi) } -func sendFeedback(feedback feedbackBody) (err error) { +func sendFeedback(feedback FeedbackBody) (err error) { _, err = sendRequestToCliAiServer(feedback, feedbackApi) return } @@ -123,7 +142,8 @@ func sendRequestToCliAiServer(content interface{}, apiCommand ApiCommand) (respo } }() var body []byte - body, err = io.ReadAll(resp.Body) + // Limit size of response body to 10MB + body, err = io.ReadAll(io.LimitReader(resp.Body, 10*utils.SizeMiB)) if errorutils.CheckError(err) != nil { return } diff --git a/utils/cliutils/cli_consts.go b/utils/cliutils/cli_consts.go index 79992e962..1b61b6472 100644 --- a/utils/cliutils/cli_consts.go +++ b/utils/cliutils/cli_consts.go @@ -4,7 +4,7 @@ import "time" const ( // General CLI constants - CliVersion = "2.57.0" + CliVersion = "2.57.1" ClientAgent = "jfrog-cli-go" // CLI base commands constants: