Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/dev' into v2
Browse files Browse the repository at this point in the history
  • Loading branch information
jfrog-ecosystem committed Jun 2, 2024
2 parents 96d62a2 + 84b33bc commit fc2b832
Showing 7 changed files with 61 additions and 41 deletions.
2 changes: 1 addition & 1 deletion build/npm/v2-jf/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion build/npm/v2-jf/package.json
Original file line number Diff line number Diff line change
@@ -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,
2 changes: 1 addition & 1 deletion build/npm/v2/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion build/npm/v2/package.json
Original file line number Diff line number Diff line change
@@ -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,
2 changes: 1 addition & 1 deletion docs/general/ai/help.go
Original file line number Diff line number Diff line change
@@ -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."
}
90 changes: 55 additions & 35 deletions general/ai/cli.go
Original file line number Diff line number Diff line change
@@ -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
}
2 changes: 1 addition & 1 deletion utils/cliutils/cli_consts.go
Original file line number Diff line number Diff line change
@@ -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:

0 comments on commit fc2b832

Please sign in to comment.