1
1
package ai
2
2
3
3
import (
4
+ "bufio"
4
5
"bytes"
5
6
"encoding/json"
6
7
"errors"
7
8
"fmt"
8
9
"github.com/jfrog/jfrog-cli-core/v2/utils/coreutils"
9
- "github.com/jfrog/jfrog-cli-core/v2/utils/ioutils"
10
10
"github.com/jfrog/jfrog-cli/utils/cliutils"
11
+ "github.com/jfrog/jfrog-client-go/artifactory/services/utils"
11
12
"github.com/jfrog/jfrog-client-go/http/httpclient"
12
13
"github.com/jfrog/jfrog-client-go/utils/errorutils"
13
14
"github.com/jfrog/jfrog-client-go/utils/log"
14
15
"github.com/urfave/cli"
15
16
"io"
16
17
"net/http"
18
+ "os"
17
19
"strings"
18
20
)
19
21
20
22
type ApiCommand string
21
23
22
24
const (
23
- cliAiApiPath = "https://cli-ai.jfrog.info/"
24
- questionApi ApiCommand = "ask"
25
- feedbackApi ApiCommand = "feedback"
25
+ cliAiApiPath = "https://cli-ai-app.jfrog.info/"
26
+ apiPrefix = "api/"
27
+ questionApi ApiCommand = apiPrefix + "ask"
28
+ feedbackApi ApiCommand = apiPrefix + "feedback"
26
29
)
27
30
28
- type questionBody struct {
31
+ type QuestionBody struct {
29
32
Question string `json:"question"`
30
33
}
31
34
32
- type feedbackBody struct {
33
- questionBody
35
+ type FeedbackBody struct {
36
+ QuestionBody
34
37
LlmAnswer string `json:"llm_answer"`
35
38
IsAccurate bool `json:"is_accurate"`
36
39
ExpectedAnswer string `json:"expected_answer"`
@@ -40,47 +43,63 @@ func HowCmd(c *cli.Context) error {
40
43
if show , err := cliutils .ShowCmdHelpIfNeeded (c , c .Args ()); show || err != nil {
41
44
return err
42
45
}
43
- if c .NArg () < 1 {
46
+ if c .NArg () > 0 {
44
47
return cliutils .WrongNumberOfArgumentsHandler (c )
45
48
}
49
+ log .Output (coreutils .PrintTitle ("This AI-based interface converts your natural language inputs into fully functional JFrog CLI commands.\n " +
50
+ "NOTE: This is a beta version and it supports mostly Artifactory and Xray commands.\n " ))
46
51
47
- args := cliutils .ExtractCommand (c )
48
- question := questionBody {Question : fmt .Sprintf ("How %s" , strings .Join (args , " " ))}
49
- llmAnswer , err := askQuestion (question )
50
- if err != nil {
51
- return err
52
- }
53
- if strings .ToLower (llmAnswer ) == "i dont know" {
54
- log .Output ("The current version of the AI model does not support this type of command yet." )
55
- return nil
56
- }
57
- log .Output ("AI generated JFrog CLI command:" )
58
- err = coreutils .PrintTable ("" , "" , coreutils .PrintTitle (llmAnswer ), false )
59
- if err != nil {
60
- return err
61
- }
52
+ for {
53
+ var question string
54
+ scanner := bufio .NewScanner (os .Stdin )
55
+ fmt .Print ("🐸 Your request: " )
56
+ for {
57
+ // Ask the user for a question
58
+ scanner .Scan ()
59
+ question = strings .TrimSpace (scanner .Text ())
60
+ if question != "" {
61
+ // If the user entered a question, break the loop
62
+ break
63
+ }
64
+ }
65
+ questionBody := QuestionBody {Question : question }
66
+ llmAnswer , err := askQuestion (questionBody )
67
+ if err != nil {
68
+ return err
69
+ }
62
70
63
- feedback := feedbackBody {questionBody : question , LlmAnswer : llmAnswer }
64
- feedback .getUserFeedback ()
65
- if err = sendFeedback (feedback ); err != nil {
66
- return err
71
+ log .Output ("🤖 Generated command: " + coreutils .PrintLink (llmAnswer ) + "\n " )
72
+ feedback := FeedbackBody {QuestionBody : questionBody , LlmAnswer : llmAnswer }
73
+ feedback .getUserFeedback ()
74
+ if err = sendFeedback (feedback ); err != nil {
75
+ return err
76
+ }
77
+ log .Output ("\n " + coreutils .PrintComment ("-------------------" ) + "\n " )
67
78
}
68
- log .Output ("Thank you for your feedback!" )
69
- return nil
70
79
}
71
80
72
- func (fb * feedbackBody ) getUserFeedback () {
73
- fb .IsAccurate = coreutils .AskYesNo (coreutils . PrintLink ( "Is the provided command accurate?" ) , true )
81
+ func (fb * FeedbackBody ) getUserFeedback () {
82
+ fb .IsAccurate = coreutils .AskYesNo ("Is the provided command accurate?" , true )
74
83
if ! fb .IsAccurate {
75
- ioutils .ScanFromConsole ("Please provide the exact command you expected (Example: 'jf rt u ...')" , & fb .ExpectedAnswer , "" )
84
+ scanner := bufio .NewScanner (os .Stdin )
85
+ fmt .Print ("Please provide the exact command you expected (Example: 'jf rt u ...'): " )
86
+ for {
87
+ scanner .Scan ()
88
+ expectedAnswer := strings .TrimSpace (scanner .Text ())
89
+ if expectedAnswer != "" {
90
+ // If the user entered an expected answer, break and return
91
+ fb .ExpectedAnswer = expectedAnswer
92
+ return
93
+ }
94
+ }
76
95
}
77
96
}
78
97
79
- func askQuestion (question questionBody ) (response string , err error ) {
98
+ func askQuestion (question QuestionBody ) (response string , err error ) {
80
99
return sendRequestToCliAiServer (question , questionApi )
81
100
}
82
101
83
- func sendFeedback (feedback feedbackBody ) (err error ) {
102
+ func sendFeedback (feedback FeedbackBody ) (err error ) {
84
103
_ , err = sendRequestToCliAiServer (feedback , feedbackApi )
85
104
return
86
105
}
@@ -123,7 +142,8 @@ func sendRequestToCliAiServer(content interface{}, apiCommand ApiCommand) (respo
123
142
}
124
143
}()
125
144
var body []byte
126
- body , err = io .ReadAll (resp .Body )
145
+ // Limit size of response body to 10MB
146
+ body , err = io .ReadAll (io .LimitReader (resp .Body , 10 * utils .SizeMiB ))
127
147
if errorutils .CheckError (err ) != nil {
128
148
return
129
149
}
0 commit comments