Skip to content

Commit 9663b75

Browse files
committed
Add error message for non 2XX status codes
1 parent c6e6f54 commit 9663b75

File tree

5 files changed

+82
-7
lines changed

5 files changed

+82
-7
lines changed

cmd/chatgpt/main.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@ func main() {
3838
Long: "A powerful ChatGPT client that enables seamless interactions with the GPT model. " +
3939
"Provides multiple modes and context management features, including the ability to " +
4040
"pipe custom context into the conversation.",
41-
RunE: run,
41+
RunE: run,
42+
SilenceUsage: true,
43+
SilenceErrors: true,
4244
}
4345

4446
rootCmd.PersistentFlags().BoolVarP(&interactiveMode, "interactive", "i", false, "Use interactive mode")

docs/openai_api.md

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,11 @@ Output:
4545
curl --location --insecure --request POST 'https://api.openai.com/v1/chat/completions' \
4646
--header "Authorization: Bearer ${OPENAI_API_KEY}" \
4747
--header 'Content-Type: application/json' \
48-
--data-raw '{
48+
--data-raw '{
4949
"model": "gpt-3.5-turbo",
50-
"messages": [{"role": "user", "content": "What is the OpenAI mission?"}]
51-
}' | jq .
50+
"messages": [{"role": "user", "content": "What is the OpenAI mission?"}],
51+
"stream": false
52+
}' | jq .
5253
```
5354

5455
Output:
@@ -77,6 +78,31 @@ Output:
7778
}
7879
```
7980

81+
Or flip `stream` to `true` (this results in retrieving a ton of `jsonl`).
82+
83+
```shell
84+
curl --location --insecure --request POST 'https://api.openai.com/v1/chat/completions' \
85+
--header "Authorization: Bearer ${OPENAI_API_KEY}" \
86+
--header 'Content-Type: application/json' \
87+
--data-raw '{
88+
"model": "gpt-3.5-turbo",
89+
"messages": [{"role": "user", "content": "What is the OpenAI mission?"}],
90+
"stream": true
91+
}'
92+
```
93+
94+
```shell
95+
... top omitted ...
96+
97+
data: {"id":"chatcmpl-8B1ELWT5QKYmUbH0Az9anpvoOVdGZ","object":"chat.completion.chunk","created":1697637029,"model":"gpt-3.5-turbo-0613","choices":[{"index":0,"delta":{"content":" power"},"finish_reason":null}]}
98+
99+
data: {"id":"chatcmpl-8B1ELWT5QKYmUbH0Az9anpvoOVdGZ","object":"chat.completion.chunk","created":1697637029,"model":"gpt-3.5-turbo-0613","choices":[{"index":0,"delta":{"content":"."},"finish_reason":null}]}
100+
101+
data: {"id":"chatcmpl-8B1ELWT5QKYmUbH0Az9anpvoOVdGZ","object":"chat.completion.chunk","created":1697637029,"model":"gpt-3.5-turbo-0613","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}
102+
103+
data: [DONE]
104+
```
105+
80106
### Providing custom context
81107

82108
You can provide your own context in the messages array in your callout. You can split this data over multiple lines. For

http/http.go

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ const (
1818
errFailedToRead = "failed to read response: %w"
1919
errFailedToCreateRequest = "failed to create request: %w"
2020
errFailedToMakeRequest = "failed to make request: %w"
21-
errHTTP = "http error: %d"
21+
errHTTP = "http status %d: %s"
22+
errHTTPStatus = "http status: %d"
2223
headerAuthorization = "Authorization"
2324
headerContentType = "Content-Type"
2425
)
@@ -104,7 +105,17 @@ func (r *RestCaller) doRequest(method, url string, body []byte, stream bool) ([]
104105
defer response.Body.Close()
105106

106107
if response.StatusCode < 200 || response.StatusCode >= 300 {
107-
return nil, fmt.Errorf(errHTTP, response.StatusCode)
108+
errorResponse, err := io.ReadAll(response.Body)
109+
if err != nil {
110+
return nil, fmt.Errorf(errHTTPStatus, response.StatusCode)
111+
}
112+
113+
var errorData types.ErrorResponse
114+
if err := json.Unmarshal(errorResponse, &errorData); err != nil {
115+
return nil, fmt.Errorf(errHTTPStatus, response.StatusCode)
116+
}
117+
118+
return errorResponse, fmt.Errorf(errHTTP, response.StatusCode, errorData.Error.Message)
108119
}
109120

110121
if stream {

integration/contract_test.go

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ func testContract(t *testing.T, when spec.G, it spec.S) {
3737
})
3838

3939
when("accessing the completion endpoint", func() {
40-
it("should have the expected keys in the response", func() {
40+
it("should return a successful response with expected keys", func() {
4141
body := types.CompletionsRequest{
4242
Messages: []types.Message{{
4343
Role: client.SystemRole,
@@ -64,6 +64,34 @@ func testContract(t *testing.T, when spec.G, it spec.S) {
6464
Expect(data.Usage).ShouldNot(BeNil(), "Expected Usage to be present in the response")
6565
Expect(data.Choices).ShouldNot(BeNil(), "Expected Choices to be present in the response")
6666
})
67+
68+
it("should return an error response with appropriate error details", func() {
69+
// Set the wrong API key
70+
restCaller.SetAPIKey("wrong-key")
71+
72+
body := types.CompletionsRequest{
73+
Messages: []types.Message{{
74+
Role: client.SystemRole,
75+
Content: defaults.Role,
76+
}},
77+
Model: defaults.Model,
78+
Stream: false,
79+
}
80+
81+
bytes, err := json.Marshal(body)
82+
Expect(err).NotTo(HaveOccurred())
83+
84+
resp, err := restCaller.Post(defaults.URL+defaults.CompletionsPath, bytes, false)
85+
Expect(err).To(HaveOccurred())
86+
87+
var errorData types.ErrorResponse
88+
err = json.Unmarshal(resp, &errorData)
89+
Expect(err).NotTo(HaveOccurred())
90+
91+
Expect(errorData.Error.Message).ShouldNot(BeEmpty(), "Expected error message to be present in the response")
92+
Expect(errorData.Error.Type).ShouldNot(BeEmpty(), "Expected error type to be present in the response")
93+
Expect(errorData.Error.Code).ShouldNot(BeEmpty(), "Expected error code to be present in the response")
94+
})
6795
})
6896

6997
when("accessing the models endpoint", func() {

types/completions.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,11 @@ type Data struct {
4141
FinishReason string `json:"finish_reason"`
4242
} `json:"choices"`
4343
}
44+
45+
type ErrorResponse struct {
46+
Error struct {
47+
Message string `json:"message"`
48+
Type string `json:"type"`
49+
Code string `json:"code"`
50+
} `json:"error"`
51+
}

0 commit comments

Comments
 (0)