-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathaiUtils.go
304 lines (234 loc) · 8.9 KB
/
aiUtils.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
package main
import (
"bytes"
"encoding/json"
"fmt"
"github.com/jinzhu/inflection"
"io"
"log"
"math/rand"
"net/http"
"os"
"strconv"
"strings"
"time"
)
// CompletionCreateArgs is used for the ChatGPT API.
// It is defined here at the package level so any function can access it
type CompletionCreateArgs struct {
Model string `json:"model"`
Prompt string `json:"prompt"`
MaxTokens int `json:"max_tokens"`
Temperature float64 `json:"temperature"`
}
// createGrammaticalPasswordAI This function uses the OpenAI API to generate a
// grammatically correct sentence based on the user's definition of
// 'grammatical.'
func createGrammaticalPasswordAI(nonSensicalSentence string, grammaticalAIWithNumbers bool) string {
openaiAPIURL, apiKey := setupChatGPTAPI()
// Check if the API key exists
if apiKey == "" {
log.Println("Error: API key is missing. Please set the API key and try again.")
os.Exit(1)
}
// Continue execution if the environment variable exists
var promptSentence string
// Declare a variable of type CompletionCreateArgs that we'll use below
var chatGPTRequestData CompletionCreateArgs
if grammaticalAIWithNumbers == true {
r := rand.New(rand.NewSource(time.Now().UnixNano()))
randomInteger := r.Intn(101)
randomIntegerString := strconv.Itoa(randomInteger)
// Ask to add a number to the sentence it is rewriting
// Note that the nonsensical sentence was actually already rewritten by AI once
promptSentence = "Please rewrite this sentence so that it is less nonsensical and more coherent: " +
"'" + nonSensicalSentence + "'" + "Also, please add in the digit " + randomIntegerString + " to quantify the subject of the sentence."
// The sentences will be longer, so we need to allocate more tokens
chatGPTRequestData = CompletionCreateArgs{
Model: "text-davinci-003",
Prompt: promptSentence,
// Any amount of tokens < 12 will truncate some sentences.
MaxTokens: 17,
// The best outcomes seem to be with temperature set to 0.
Temperature: 0,
}
} else if grammaticalAIWithNumbers == false {
// Just ask it to rewrite the sentence
promptSentence = "Change the subject in the following nonsensical sentence so that it makes more sense. " +
"Change the adverb, adjective, noun, or verb if they don't sound like they belong together: '" +
nonSensicalSentence + "'"
chatGPTRequestData = CompletionCreateArgs{
Model: "text-davinci-003",
Prompt: promptSentence,
// Any amount of tokens < 12 will truncate some sentences.
MaxTokens: 14,
// The best outcomes seem to be with temperature set to 0.
Temperature: 0,
}
}
// Make the actual API call
chatGPTResponseBody, errorString, apiRequestError := makeChatGPTAPIRequest(chatGPTRequestData, openaiAPIURL, apiKey)
// If the API call returned and error, return the error string
if apiRequestError {
return errorString
}
rewrittenSentence := extractGPTJson(string(chatGPTResponseBody))
// Remove any surrounding single quotes. This happens sometimes.
rewrittenSentence = strings.Trim(rewrittenSentence, "'")
// If the rewrittenSentence is missing a terminating punctuation mark
// then add a trailing period character.
if !strings.HasSuffix(rewrittenSentence, ".") && !strings.HasSuffix(rewrittenSentence, "?") {
rewrittenSentence += "."
}
//fmt.Println(nonSensicalSentence)
//fmt.Println(rewrittenSentence)
return rewrittenSentence
}
func createMemorablePasswordAI() string {
openaiAPIURL, apiKey := setupChatGPTAPI()
// Check if the API key exists
if apiKey == "" {
log.Println("Error: API key is missing. Please set the API key and try again.")
os.Exit(1)
}
// Continue execution if the environment variable exists
var promptSentence string
// Declare a variable of type CompletionCreateArgs that we'll use below
var chatGPTRequestData CompletionCreateArgs
promptSentence = "Please return two nouns that are related to each other, " +
"and one adjective that is related to at least one of the nouns. " +
"Put them in a simple list, separated by commas. And don't include anything else."
chatGPTRequestData = CompletionCreateArgs{
Model: "text-davinci-003",
Prompt: promptSentence,
// Any amount of tokens < 12 will truncate some sentences.
MaxTokens: 12,
// The best outcomes seem to be with temperature set to 0.8 for this prompt.
// Otherwise you get duplicate answers.
Temperature: 1.3,
}
// Make the actual API call
chatGPTResponseBody, errorString, apiRequestError := makeChatGPTAPIRequest(chatGPTRequestData, openaiAPIURL, apiKey)
// If the API call returned and error, return the error string
if apiRequestError {
return errorString
}
commaSeparatedWords := extractGPTJson(string(chatGPTResponseBody))
// Remove any surrounding single quotes. This happens sometimes.
commaSeparatedWords = strings.Trim(commaSeparatedWords, "'")
// Split the string on the comma and space.
separatedWords := strings.Split(commaSeparatedWords, ",")
// FIXME: Create fallback lookups from local dictionary. If these are missing it errors out.
noun1 := separatedWords[0]
noun2 := separatedWords[1]
adjective := separatedWords[2]
noun1 = strings.TrimSpace(noun1)
noun2 = strings.TrimSpace(noun2)
adjective = strings.TrimSpace(adjective)
noun1 = capitalizeFirstLetter(noun1)
noun2 = capitalizeFirstLetter(noun2)
adjective = capitalizeFirstLetter(adjective)
noun1Plural := inflection.Plural(noun1)
noun2Plural := inflection.Plural(noun2)
// initialize global pseudo random generator
r := rand.New(rand.NewSource(time.Now().UnixNano()))
delimiter := RandomDelimiter()
digit := strconv.Itoa(r.Intn(10))
// Use the plural versions of the nouns unless the digit is 1
if digit != "1" {
noun1 = noun1Plural
noun2 = noun2Plural
}
// Randomly decide between variations in word order
wordOrder := r.Intn(3)
if wordOrder == 0 {
return adjective + noun1 + delimiter + digit + noun2
} else if wordOrder == 1 {
return digit + noun1 + delimiter + adjective + noun2
} else {
return noun1 + delimiter + digit + noun2 + "," + adjective
}
}
func makeChatGPTAPIRequest(chatGPTRequestData CompletionCreateArgs, openaiAPIURL string, apiKey string) ([]byte, string, bool) {
// Convert the struct data into JSON
chatGPTRequestJSON, err := json.Marshal(chatGPTRequestData)
if err != nil {
fmt.Println("Error marshaling JSON:", err)
return nil, "Error marshaling JSON", true
}
// Create a new HTTP request using our JSON as the POST body
chatGPTRequest, err := http.NewRequest("POST", openaiAPIURL, bytes.NewBuffer(chatGPTRequestJSON))
if err != nil {
fmt.Println("Error creating HTTP request:", err)
return nil, "Error creating HTTP request", true
}
// Set up headers for content type and authorization
chatGPTRequest.Header.Set("Content-Type", "application/json")
chatGPTRequest.Header.Set("Authorization", fmt.Sprintf("Bearer %s", apiKey))
//improvedProgressBar(1)
// Send the HTTP request
httpClient := &http.Client{}
resp, err := httpClient.Do(chatGPTRequest)
if err != nil {
fmt.Println("Error making HTTP request:", err)
return nil, "Error making HTTP request", true
}
defer func(Body io.ReadCloser) {
err := Body.Close()
if err != nil {
fmt.Println("Problem closing HTTP response chatGPTResponseBody after read.")
}
}(resp.Body)
// Read the HTTP response body
chatGPTResponseBody, err := io.ReadAll(resp.Body)
if err != nil {
fmt.Println("Error reading response chatGPTResponseBody:", err)
return nil, "Error reading response chatGPTResponseBody", true
}
// return response body, empty error string, and "false" if there were no errors
return chatGPTResponseBody, "", false
}
func setupChatGPTAPI() (string, string) {
openaiAPIURL := "https://api.openai.com/v1/completions"
apiKey, exists := os.LookupEnv("GPT_API_KEY")
if !exists {
log.Fatal("Error: Environment variable GPT_API_KEY does not exist.")
}
return openaiAPIURL, apiKey
}
func extractGPTJson(jsonData string) string {
var sentence string
type Response struct {
ID string `json:"id"`
Object string `json:"object"`
Created int64 `json:"created"`
Model string `json:"model"`
Choices []struct {
Text string `json:"text"`
Index int `json:"index"`
Logprobs interface{} `json:"logprobs"`
FinishReason string `json:"finish_reason"`
} `json:"choices"`
Usage struct {
PromptTokens int `json:"prompt_tokens"`
CompletionTokens int `json:"completion_tokens"`
TotalTokens int `json:"total_tokens"`
} `json:"usage"`
}
var response Response
err := json.Unmarshal([]byte(jsonData), &response)
if err != nil {
fmt.Println("Error unmarshaling JSON:", err)
return "Error unmarshaling JSON"
}
if len(response.Choices) > 0 {
sentence = response.Choices[0].Text
//fmt.Println("Extracted sentence:", sentence)
// Remove two leading newline characters
sentence = strings.TrimPrefix(sentence, "\n\n")
} else {
fmt.Println(response)
fmt.Println("No choices found in the JSON")
}
return sentence
}