-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathopenai.go
118 lines (105 loc) · 2.8 KB
/
openai.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
package main
import (
"fmt"
)
var OpenAICompletionsURL = "https://api.openai.com/v1/chat/completions"
// RequestPayload represents the entire request payload
type RequestPayload struct {
Model string `json:"model"`
Messages []Message `json:"messages"`
MaxTokens int `json:"max_tokens"`
}
// Message represents an individual message in the payload
type Message struct {
Role string `json:"role"`
Content []Content `json:"content"`
}
// Content represents the content of a message
type Content struct {
Type string `json:"type"`
Text string `json:"text,omitempty"` // Text field for system role content
ImageURL *ImageURL `json:"image_url,omitempty"` // ImageURL field for user role content
}
// ImageURL represents the URL of the image
type ImageURL struct {
URL string `json:"url"`
}
/* Example response content we're parsing
{
"id": "chatcmpl-aBCd...",
"object": "chat.completion",
"created": 1719504619,
"model": "gpt-4o-2024-05-13",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "ETaX"
},
"logprobs": null,
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 296,
"completion_tokens": 3,
"total_tokens": 299
},
"system_fingerprint": "fp_4008e3b719"
}
*/
type CompletionResponse struct {
Choices []ResponseChoice `json:"choices"`
}
// ResponseChoice represents a Choice in the response, with a simplified Content
type ResponseChoice struct {
Message struct {
Content string `json:"content"`
} `json:"message"`
}
// Get the payload to request a captcha solve from GPT-4o
func getCaptchaPayload(inlineImage string) *RequestPayload {
return &RequestPayload{
Model: "gpt-4o",
Messages: []Message{
{
Role: "system",
Content: []Content{
{
Type: "text",
Text: "The user will send you images containing a single word of obfuscated text. Reply only with the text in the image, with no spaces or quotes.",
},
},
},
{
Role: "user",
Content: []Content{
{
Type: "image_url",
ImageURL: &ImageURL{
URL: inlineImage,
},
},
},
},
},
MaxTokens: 300,
}
}
// Solve a captcha image, returning the pictured text or an error.
func solveCaptchaOpenAI(inline_image string) (string, error) {
payload := getCaptchaPayload(inline_image)
completion := &CompletionResponse{}
headers := map[string][]string{
"Authorization": {"Bearer " + appEnv.OpenAIAPIKey},
}
err := PostJSON[RequestPayload, CompletionResponse](OpenAICompletionsURL, headers, payload, completion)
if err != nil {
return "", fmt.Errorf("error from OpenAI: %w", err)
}
if len(completion.Choices) == 0 {
return "", fmt.Errorf("no choices in OpenAI completion %v", completion)
}
return completion.Choices[0].Message.Content, nil
}