Feat Add headers to openai responses (#506)
* feat: add headers to http response * chore: add test * fix: rename to httpHeader
This commit is contained in:
19
audio.go
19
audio.go
@@ -63,6 +63,21 @@ type AudioResponse struct {
|
|||||||
Transient bool `json:"transient"`
|
Transient bool `json:"transient"`
|
||||||
} `json:"segments"`
|
} `json:"segments"`
|
||||||
Text string `json:"text"`
|
Text string `json:"text"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
type audioTextResponse struct {
|
||||||
|
Text string `json:"text"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *audioTextResponse) ToAudioResponse() AudioResponse {
|
||||||
|
return AudioResponse{
|
||||||
|
Text: r.Text,
|
||||||
|
httpHeader: r.httpHeader,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateTranscription — API call to create a transcription. Returns transcribed text.
|
// CreateTranscription — API call to create a transcription. Returns transcribed text.
|
||||||
@@ -104,7 +119,9 @@ func (c *Client) callAudioAPI(
|
|||||||
if request.HasJSONResponse() {
|
if request.HasJSONResponse() {
|
||||||
err = c.sendRequest(req, &response)
|
err = c.sendRequest(req, &response)
|
||||||
} else {
|
} else {
|
||||||
err = c.sendRequest(req, &response.Text)
|
var textResponse audioTextResponse
|
||||||
|
err = c.sendRequest(req, &textResponse)
|
||||||
|
response = textResponse.ToAudioResponse()
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return AudioResponse{}, err
|
return AudioResponse{}, err
|
||||||
|
|||||||
2
chat.go
2
chat.go
@@ -142,6 +142,8 @@ type ChatCompletionResponse struct {
|
|||||||
Model string `json:"model"`
|
Model string `json:"model"`
|
||||||
Choices []ChatCompletionChoice `json:"choices"`
|
Choices []ChatCompletionChoice `json:"choices"`
|
||||||
Usage Usage `json:"usage"`
|
Usage Usage `json:"usage"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateChatCompletion — API call to Create a completion for the chat message.
|
// CreateChatCompletion — API call to Create a completion for the chat message.
|
||||||
|
|||||||
30
chat_test.go
30
chat_test.go
@@ -16,6 +16,11 @@ import (
|
|||||||
"github.com/sashabaranov/go-openai/jsonschema"
|
"github.com/sashabaranov/go-openai/jsonschema"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
xCustomHeader = "X-CUSTOM-HEADER"
|
||||||
|
xCustomHeaderValue = "test"
|
||||||
|
)
|
||||||
|
|
||||||
func TestChatCompletionsWrongModel(t *testing.T) {
|
func TestChatCompletionsWrongModel(t *testing.T) {
|
||||||
config := DefaultConfig("whatever")
|
config := DefaultConfig("whatever")
|
||||||
config.BaseURL = "http://localhost/v1"
|
config.BaseURL = "http://localhost/v1"
|
||||||
@@ -68,6 +73,30 @@ func TestChatCompletions(t *testing.T) {
|
|||||||
checks.NoError(t, err, "CreateChatCompletion error")
|
checks.NoError(t, err, "CreateChatCompletion error")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestCompletions Tests the completions endpoint of the API using the mocked server.
|
||||||
|
func TestChatCompletionsWithHeaders(t *testing.T) {
|
||||||
|
client, server, teardown := setupOpenAITestServer()
|
||||||
|
defer teardown()
|
||||||
|
server.RegisterHandler("/v1/chat/completions", handleChatCompletionEndpoint)
|
||||||
|
resp, err := client.CreateChatCompletion(context.Background(), ChatCompletionRequest{
|
||||||
|
MaxTokens: 5,
|
||||||
|
Model: GPT3Dot5Turbo,
|
||||||
|
Messages: []ChatCompletionMessage{
|
||||||
|
{
|
||||||
|
Role: ChatMessageRoleUser,
|
||||||
|
Content: "Hello!",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
checks.NoError(t, err, "CreateChatCompletion error")
|
||||||
|
|
||||||
|
a := resp.Header().Get(xCustomHeader)
|
||||||
|
_ = a
|
||||||
|
if resp.Header().Get(xCustomHeader) != xCustomHeaderValue {
|
||||||
|
t.Errorf("expected header %s to be %s", xCustomHeader, xCustomHeaderValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TestChatCompletionsFunctions tests including a function call.
|
// TestChatCompletionsFunctions tests including a function call.
|
||||||
func TestChatCompletionsFunctions(t *testing.T) {
|
func TestChatCompletionsFunctions(t *testing.T) {
|
||||||
client, server, teardown := setupOpenAITestServer()
|
client, server, teardown := setupOpenAITestServer()
|
||||||
@@ -281,6 +310,7 @@ func handleChatCompletionEndpoint(w http.ResponseWriter, r *http.Request) {
|
|||||||
TotalTokens: inputTokens + completionTokens,
|
TotalTokens: inputTokens + completionTokens,
|
||||||
}
|
}
|
||||||
resBytes, _ = json.Marshal(res)
|
resBytes, _ = json.Marshal(res)
|
||||||
|
w.Header().Set(xCustomHeader, xCustomHeaderValue)
|
||||||
fmt.Fprintln(w, string(resBytes))
|
fmt.Fprintln(w, string(resBytes))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
20
client.go
20
client.go
@@ -20,6 +20,20 @@ type Client struct {
|
|||||||
createFormBuilder func(io.Writer) utils.FormBuilder
|
createFormBuilder func(io.Writer) utils.FormBuilder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Response interface {
|
||||||
|
SetHeader(http.Header)
|
||||||
|
}
|
||||||
|
|
||||||
|
type httpHeader http.Header
|
||||||
|
|
||||||
|
func (h *httpHeader) SetHeader(header http.Header) {
|
||||||
|
*h = httpHeader(header)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h httpHeader) Header() http.Header {
|
||||||
|
return http.Header(h)
|
||||||
|
}
|
||||||
|
|
||||||
// NewClient creates new OpenAI API client.
|
// NewClient creates new OpenAI API client.
|
||||||
func NewClient(authToken string) *Client {
|
func NewClient(authToken string) *Client {
|
||||||
config := DefaultConfig(authToken)
|
config := DefaultConfig(authToken)
|
||||||
@@ -82,7 +96,7 @@ func (c *Client) newRequest(ctx context.Context, method, url string, setters ...
|
|||||||
return req, nil
|
return req, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) sendRequest(req *http.Request, v any) error {
|
func (c *Client) sendRequest(req *http.Request, v Response) error {
|
||||||
req.Header.Set("Accept", "application/json; charset=utf-8")
|
req.Header.Set("Accept", "application/json; charset=utf-8")
|
||||||
|
|
||||||
// Check whether Content-Type is already set, Upload Files API requires
|
// Check whether Content-Type is already set, Upload Files API requires
|
||||||
@@ -103,6 +117,10 @@ func (c *Client) sendRequest(req *http.Request, v any) error {
|
|||||||
return c.handleErrorResp(res)
|
return c.handleErrorResp(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if v != nil {
|
||||||
|
v.SetHeader(res.Header)
|
||||||
|
}
|
||||||
|
|
||||||
return decodeResponse(res.Body, v)
|
return decodeResponse(res.Body, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -154,6 +154,8 @@ type CompletionResponse struct {
|
|||||||
Model string `json:"model"`
|
Model string `json:"model"`
|
||||||
Choices []CompletionChoice `json:"choices"`
|
Choices []CompletionChoice `json:"choices"`
|
||||||
Usage Usage `json:"usage"`
|
Usage Usage `json:"usage"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateCompletion — API call to create a completion. This is the main endpoint of the API. Returns new text as well
|
// CreateCompletion — API call to create a completion. This is the main endpoint of the API. Returns new text as well
|
||||||
|
|||||||
2
edits.go
2
edits.go
@@ -28,6 +28,8 @@ type EditsResponse struct {
|
|||||||
Created int64 `json:"created"`
|
Created int64 `json:"created"`
|
||||||
Usage Usage `json:"usage"`
|
Usage Usage `json:"usage"`
|
||||||
Choices []EditsChoice `json:"choices"`
|
Choices []EditsChoice `json:"choices"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
}
|
}
|
||||||
|
|
||||||
// Edits Perform an API call to the Edits endpoint.
|
// Edits Perform an API call to the Edits endpoint.
|
||||||
|
|||||||
@@ -150,6 +150,8 @@ type EmbeddingResponse struct {
|
|||||||
Data []Embedding `json:"data"`
|
Data []Embedding `json:"data"`
|
||||||
Model EmbeddingModel `json:"model"`
|
Model EmbeddingModel `json:"model"`
|
||||||
Usage Usage `json:"usage"`
|
Usage Usage `json:"usage"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
}
|
}
|
||||||
|
|
||||||
type base64String string
|
type base64String string
|
||||||
@@ -182,6 +184,8 @@ type EmbeddingResponseBase64 struct {
|
|||||||
Data []Base64Embedding `json:"data"`
|
Data []Base64Embedding `json:"data"`
|
||||||
Model EmbeddingModel `json:"model"`
|
Model EmbeddingModel `json:"model"`
|
||||||
Usage Usage `json:"usage"`
|
Usage Usage `json:"usage"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToEmbeddingResponse converts an embeddingResponseBase64 to an EmbeddingResponse.
|
// ToEmbeddingResponse converts an embeddingResponseBase64 to an EmbeddingResponse.
|
||||||
|
|||||||
@@ -12,11 +12,15 @@ type Engine struct {
|
|||||||
Object string `json:"object"`
|
Object string `json:"object"`
|
||||||
Owner string `json:"owner"`
|
Owner string `json:"owner"`
|
||||||
Ready bool `json:"ready"`
|
Ready bool `json:"ready"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
}
|
}
|
||||||
|
|
||||||
// EnginesList is a list of engines.
|
// EnginesList is a list of engines.
|
||||||
type EnginesList struct {
|
type EnginesList struct {
|
||||||
Engines []Engine `json:"data"`
|
Engines []Engine `json:"data"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListEngines Lists the currently available engines, and provides basic
|
// ListEngines Lists the currently available engines, and provides basic
|
||||||
|
|||||||
4
files.go
4
files.go
@@ -25,11 +25,15 @@ type File struct {
|
|||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
Purpose string `json:"purpose"`
|
Purpose string `json:"purpose"`
|
||||||
StatusDetails string `json:"status_details"`
|
StatusDetails string `json:"status_details"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
}
|
}
|
||||||
|
|
||||||
// FilesList is a list of files that belong to the user or organization.
|
// FilesList is a list of files that belong to the user or organization.
|
||||||
type FilesList struct {
|
type FilesList struct {
|
||||||
Files []File `json:"data"`
|
Files []File `json:"data"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateFile uploads a jsonl file to GPT3
|
// CreateFile uploads a jsonl file to GPT3
|
||||||
|
|||||||
@@ -41,6 +41,8 @@ type FineTune struct {
|
|||||||
ValidationFiles []File `json:"validation_files"`
|
ValidationFiles []File `json:"validation_files"`
|
||||||
TrainingFiles []File `json:"training_files"`
|
TrainingFiles []File `json:"training_files"`
|
||||||
UpdatedAt int64 `json:"updated_at"`
|
UpdatedAt int64 `json:"updated_at"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deprecated: On August 22nd, 2023, OpenAI announced the deprecation of the /v1/fine-tunes API.
|
// Deprecated: On August 22nd, 2023, OpenAI announced the deprecation of the /v1/fine-tunes API.
|
||||||
@@ -69,6 +71,8 @@ type FineTuneHyperParams struct {
|
|||||||
type FineTuneList struct {
|
type FineTuneList struct {
|
||||||
Object string `json:"object"`
|
Object string `json:"object"`
|
||||||
Data []FineTune `json:"data"`
|
Data []FineTune `json:"data"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deprecated: On August 22nd, 2023, OpenAI announced the deprecation of the /v1/fine-tunes API.
|
// Deprecated: On August 22nd, 2023, OpenAI announced the deprecation of the /v1/fine-tunes API.
|
||||||
@@ -77,6 +81,8 @@ type FineTuneList struct {
|
|||||||
type FineTuneEventList struct {
|
type FineTuneEventList struct {
|
||||||
Object string `json:"object"`
|
Object string `json:"object"`
|
||||||
Data []FineTuneEvent `json:"data"`
|
Data []FineTuneEvent `json:"data"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deprecated: On August 22nd, 2023, OpenAI announced the deprecation of the /v1/fine-tunes API.
|
// Deprecated: On August 22nd, 2023, OpenAI announced the deprecation of the /v1/fine-tunes API.
|
||||||
@@ -86,6 +92,8 @@ type FineTuneDeleteResponse struct {
|
|||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Object string `json:"object"`
|
Object string `json:"object"`
|
||||||
Deleted bool `json:"deleted"`
|
Deleted bool `json:"deleted"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deprecated: On August 22nd, 2023, OpenAI announced the deprecation of the /v1/fine-tunes API.
|
// Deprecated: On August 22nd, 2023, OpenAI announced the deprecation of the /v1/fine-tunes API.
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ type FineTuningJob struct {
|
|||||||
ValidationFile string `json:"validation_file,omitempty"`
|
ValidationFile string `json:"validation_file,omitempty"`
|
||||||
ResultFiles []string `json:"result_files"`
|
ResultFiles []string `json:"result_files"`
|
||||||
TrainedTokens int `json:"trained_tokens"`
|
TrainedTokens int `json:"trained_tokens"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
}
|
}
|
||||||
|
|
||||||
type Hyperparameters struct {
|
type Hyperparameters struct {
|
||||||
@@ -39,6 +41,8 @@ type FineTuningJobEventList struct {
|
|||||||
Object string `json:"object"`
|
Object string `json:"object"`
|
||||||
Data []FineTuneEvent `json:"data"`
|
Data []FineTuneEvent `json:"data"`
|
||||||
HasMore bool `json:"has_more"`
|
HasMore bool `json:"has_more"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
}
|
}
|
||||||
|
|
||||||
type FineTuningJobEvent struct {
|
type FineTuningJobEvent struct {
|
||||||
|
|||||||
2
image.go
2
image.go
@@ -33,6 +33,8 @@ type ImageRequest struct {
|
|||||||
type ImageResponse struct {
|
type ImageResponse struct {
|
||||||
Created int64 `json:"created,omitempty"`
|
Created int64 `json:"created,omitempty"`
|
||||||
Data []ImageResponseDataInner `json:"data,omitempty"`
|
Data []ImageResponseDataInner `json:"data,omitempty"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
}
|
}
|
||||||
|
|
||||||
// ImageResponseDataInner represents a response data structure for image API.
|
// ImageResponseDataInner represents a response data structure for image API.
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ type Model struct {
|
|||||||
Permission []Permission `json:"permission"`
|
Permission []Permission `json:"permission"`
|
||||||
Root string `json:"root"`
|
Root string `json:"root"`
|
||||||
Parent string `json:"parent"`
|
Parent string `json:"parent"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
}
|
}
|
||||||
|
|
||||||
// Permission struct represents an OpenAPI permission.
|
// Permission struct represents an OpenAPI permission.
|
||||||
@@ -38,11 +40,15 @@ type FineTuneModelDeleteResponse struct {
|
|||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Object string `json:"object"`
|
Object string `json:"object"`
|
||||||
Deleted bool `json:"deleted"`
|
Deleted bool `json:"deleted"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
}
|
}
|
||||||
|
|
||||||
// ModelsList is a list of models, including those that belong to the user or organization.
|
// ModelsList is a list of models, including those that belong to the user or organization.
|
||||||
type ModelsList struct {
|
type ModelsList struct {
|
||||||
Models []Model `json:"data"`
|
Models []Model `json:"data"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListModels Lists the currently available models,
|
// ListModels Lists the currently available models,
|
||||||
|
|||||||
@@ -69,6 +69,8 @@ type ModerationResponse struct {
|
|||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Model string `json:"model"`
|
Model string `json:"model"`
|
||||||
Results []Result `json:"results"`
|
Results []Result `json:"results"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
}
|
}
|
||||||
|
|
||||||
// Moderations — perform a moderation api call over a string.
|
// Moderations — perform a moderation api call over a string.
|
||||||
|
|||||||
Reference in New Issue
Block a user