Repository: sashabaranov/go-openai
Pull request #638 (2024-01-16 12:32:14)

fix(audio): fix audioTextResponse decode
The audio api passes `audioTextResponse` to `sendRequest`,
```go
	if request.HasJSONResponse() {
		err = c.sendRequest(req, &response)
	} else {
		var textResponse audioTextResponse
		err = c.sendRequest(req, &textResponse)
		response = textResponse.ToAudioResponse()
	}
```

but it cannot be asserted as `*string` type, lead to decoding failure.
```go
func decodeResponse(body io.Reader, v any) error {
	if v == nil {
		return nil
	}

	if result, ok := v.(*string); ok {
		return decodeString(body, result)
	}
	return json.NewDecoder(body).Decode(v)
}
```

Fix this problem.


codecov[bot]: ## [Codecov](https://app.codecov.io/gh/sashabaranov/go-openai/pull/638?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Comparison is base [(`4ce03a9`)](https://app.codecov.io/gh/sashabaranov/go-openai/commit/4ce03a919ae9fdcb62e8098a03500ef77eafe348?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) 98.43% compared to head [(`222517b`)](https://app.codecov.io/gh/sashabaranov/go-openai/pull/638?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) 98.43%.


<details><summary>Additional details and impacted files</summary>


```diff
@@           Coverage Diff           @@
##           master     #638   +/-   ##
=======================================
  Coverage   98.43%   98.43%           
=======================================
  Files          24       24           
  Lines        1342     1345    +3     
=======================================
+ Hits         1321     1324    +3     
  Misses         15       15           
  Partials        6        6           
```



</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/sashabaranov/go-openai/pull/638?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None).

sashabaranov: @WqyJh thank you for the PR! Could you also please add a test for that?
WqyJh: Added test.
sashabaranov: @WqyJh thanks! There are some linter problems now

Patch:
diff --git a/client.go b/client.go
index 056226c..8bbbb87 100644
--- a/client.go
+++ b/client.go
@@ -193,10 +193,14 @@ func decodeResponse(body io.Reader, v any) error {
 		return nil
 	}
 
-	if result, ok := v.(*string); ok {
-		return decodeString(body, result)
+	switch o := v.(type) {
+	case *string:
+		return decodeString(body, o)
+	case *audioTextResponse:
+		return decodeString(body, &o.Text)
+	default:
+		return json.NewDecoder(body).Decode(v)
 	}
-	return json.NewDecoder(body).Decode(v)
 }
 
 func decodeString(body io.Reader, output *string) error {


Test patch:
diff --git a/client_test.go b/client_test.go
index 664f9fb..bc5133e 100644
--- a/client_test.go
+++ b/client_test.go
@@ -7,9 +7,11 @@ import (
 	"fmt"
 	"io"
 	"net/http"
+	"reflect"
 	"testing"
 
 	"github.com/sashabaranov/go-openai/internal/test"
+	"github.com/sashabaranov/go-openai/internal/test/checks"
 )
 
 var errTestRequestBuilderFailed = errors.New("test request builder failed")
@@ -43,23 +45,29 @@ func TestDecodeResponse(t *testing.T) {
 	testCases := []struct {
 		name     string
 		value    interface{}
+		expected interface{}
 		body     io.Reader
 		hasError bool
 	}{
 		{
-			name:  "nil input",
-			value: nil,
-			body:  bytes.NewReader([]byte("")),
+			name:     "nil input",
+			value:    nil,
+			body:     bytes.NewReader([]byte("")),
+			expected: nil,
 		},
 		{
-			name:  "string input",
-			value: &stringInput,
-			body:  bytes.NewReader([]byte("test")),
+			name:     "string input",
+			value:    &stringInput,
+			body:     bytes.NewReader([]byte("test")),
+			expected: "test",
 		},
 		{
 			name:  "map input",
 			value: &map[string]interface{}{},
 			body:  bytes.NewReader([]byte(`{"test": "test"}`)),
+			expected: map[string]interface{}{
+				"test": "test",
+			},
 		},
 		{
 			name:     "reader return error",
@@ -67,14 +75,38 @@ func TestDecodeResponse(t *testing.T) {
 			body:     &errorReader{err: errors.New("dummy")},
 			hasError: true,
 		},
+		{
+			name:  "audio text input",
+			value: &audioTextResponse{},
+			body:  bytes.NewReader([]byte("test")),
+			expected: audioTextResponse{
+				Text: "test",
+			},
+		},
+	}
+
+	assertEqual := func(t *testing.T, expected, actual interface{}) {
+		t.Helper()
+		if expected == actual {
+			return
+		}
+		v := reflect.ValueOf(actual).Elem().Interface()
+		if !reflect.DeepEqual(v, expected) {
+			t.Fatalf("Unexpected value: %v, expected: %v", v, expected)
+		}
 	}
 
 	for _, tc := range testCases {
 		t.Run(tc.name, func(t *testing.T) {
 			err := decodeResponse(tc.body, tc.value)
-			if (err != nil) != tc.hasError {
-				t.Errorf("Unexpected error: %v", err)
+			if tc.hasError {
+				checks.HasError(t, err, "Unexpected nil error")
+				return
+			}
+			if err != nil {
+				t.Fatalf("Unexpected error: %v", err)
 			}
+			assertEqual(t, tc.expected, tc.value)
 		})
 	}
 }