feat: Introduce JSON decoding utility functions and update error handling in Claude and OpenAI response structures
This commit is contained in:
14
common/json.go
Normal file
14
common/json.go
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
)
|
||||||
|
|
||||||
|
func DecodeJson(data []byte, v any) error {
|
||||||
|
return json.NewDecoder(bytes.NewReader(data)).Decode(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func DecodeJsonStr(data string, v any) error {
|
||||||
|
return DecodeJson(StringToByteSlice(data), v)
|
||||||
|
}
|
||||||
@@ -165,8 +165,8 @@ func (c *ClaudeRequest) ParseSystem() []ClaudeMediaMessage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ClaudeError struct {
|
type ClaudeError struct {
|
||||||
Type string `json:"type"`
|
Type string `json:"type,omitempty"`
|
||||||
Message string `json:"message"`
|
Message string `json:"message,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ClaudeErrorWithStatusCode struct {
|
type ClaudeErrorWithStatusCode struct {
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
package dto
|
package dto
|
||||||
|
|
||||||
type SimpleResponse struct {
|
type SimpleResponse struct {
|
||||||
Usage `json:"usage"`
|
Usage `json:"usage"`
|
||||||
Error OpenAIError `json:"error"`
|
Error *OpenAIError `json:"error"`
|
||||||
Choices []OpenAITextResponseChoice `json:"choices"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type TextResponse struct {
|
type TextResponse struct {
|
||||||
@@ -27,6 +26,7 @@ type OpenAITextResponse struct {
|
|||||||
Object string `json:"object"`
|
Object string `json:"object"`
|
||||||
Created int64 `json:"created"`
|
Created int64 `json:"created"`
|
||||||
Choices []OpenAITextResponseChoice `json:"choices"`
|
Choices []OpenAITextResponseChoice `json:"choices"`
|
||||||
|
Error *OpenAIError `json:"error"`
|
||||||
Usage `json:"usage"`
|
Usage `json:"usage"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package claude
|
package claude
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
@@ -481,7 +480,7 @@ func FormatClaudeResponseInfo(requestMode int, claudeResponse *dto.ClaudeRespons
|
|||||||
|
|
||||||
func HandleResponseData(c *gin.Context, info *relaycommon.RelayInfo, claudeInfo *ClaudeResponseInfo, data string, requestMode int) error {
|
func HandleResponseData(c *gin.Context, info *relaycommon.RelayInfo, claudeInfo *ClaudeResponseInfo, data string, requestMode int) error {
|
||||||
var claudeResponse dto.ClaudeResponse
|
var claudeResponse dto.ClaudeResponse
|
||||||
err := json.NewDecoder(bytes.NewReader(common.StringToByteSlice(data))).Decode(&claudeResponse)
|
err := common.DecodeJsonStr(data, &claudeResponse)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
common.SysError("error unmarshalling stream response: " + err.Error())
|
common.SysError("error unmarshalling stream response: " + err.Error())
|
||||||
return fmt.Errorf("error unmarshalling stream aws response: %w", err)
|
return fmt.Errorf("error unmarshalling stream aws response: %w", err)
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ func sendStreamData(c *gin.Context, info *relaycommon.RelayInfo, data string, fo
|
|||||||
}
|
}
|
||||||
|
|
||||||
var lastStreamResponse dto.ChatCompletionsStreamResponse
|
var lastStreamResponse dto.ChatCompletionsStreamResponse
|
||||||
if err := json.Unmarshal(common.StringToByteSlice(data), &lastStreamResponse); err != nil {
|
if err := common.DecodeJsonStr(data, &lastStreamResponse); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,7 +151,7 @@ func OaiStreamHandler(c *gin.Context, resp *http.Response, info *relaycommon.Rel
|
|||||||
|
|
||||||
shouldSendLastResp := true
|
shouldSendLastResp := true
|
||||||
var lastStreamResponse dto.ChatCompletionsStreamResponse
|
var lastStreamResponse dto.ChatCompletionsStreamResponse
|
||||||
err := json.Unmarshal(common.StringToByteSlice(lastStreamData), &lastStreamResponse)
|
err := common.DecodeJsonStr(lastStreamData, &lastStreamResponse)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
responseId = lastStreamResponse.Id
|
responseId = lastStreamResponse.Id
|
||||||
createAt = lastStreamResponse.Created
|
createAt = lastStreamResponse.Created
|
||||||
@@ -196,7 +196,7 @@ func OaiStreamHandler(c *gin.Context, resp *http.Response, info *relaycommon.Rel
|
|||||||
}
|
}
|
||||||
|
|
||||||
func OpenaiHandler(c *gin.Context, resp *http.Response, info *relaycommon.RelayInfo) (*dto.OpenAIErrorWithStatusCode, *dto.Usage) {
|
func OpenaiHandler(c *gin.Context, resp *http.Response, info *relaycommon.RelayInfo) (*dto.OpenAIErrorWithStatusCode, *dto.Usage) {
|
||||||
var simpleResponse dto.SimpleResponse
|
var simpleResponse dto.OpenAITextResponse
|
||||||
responseBody, err := io.ReadAll(resp.Body)
|
responseBody, err := io.ReadAll(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return service.OpenAIErrorWrapper(err, "read_response_body_failed", http.StatusInternalServerError), nil
|
return service.OpenAIErrorWrapper(err, "read_response_body_failed", http.StatusInternalServerError), nil
|
||||||
@@ -205,16 +205,29 @@ func OpenaiHandler(c *gin.Context, resp *http.Response, info *relaycommon.RelayI
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return service.OpenAIErrorWrapper(err, "close_response_body_failed", http.StatusInternalServerError), nil
|
return service.OpenAIErrorWrapper(err, "close_response_body_failed", http.StatusInternalServerError), nil
|
||||||
}
|
}
|
||||||
err = json.Unmarshal(responseBody, &simpleResponse)
|
err = common.DecodeJson(responseBody, &simpleResponse)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return service.OpenAIErrorWrapper(err, "unmarshal_response_body_failed", http.StatusInternalServerError), nil
|
return service.OpenAIErrorWrapper(err, "unmarshal_response_body_failed", http.StatusInternalServerError), nil
|
||||||
}
|
}
|
||||||
if simpleResponse.Error.Type != "" {
|
if simpleResponse.Error != nil && simpleResponse.Error.Type != "" {
|
||||||
return &dto.OpenAIErrorWithStatusCode{
|
return &dto.OpenAIErrorWithStatusCode{
|
||||||
Error: simpleResponse.Error,
|
Error: *simpleResponse.Error,
|
||||||
StatusCode: resp.StatusCode,
|
StatusCode: resp.StatusCode,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch info.RelayFormat {
|
||||||
|
case relaycommon.RelayFormatOpenAI:
|
||||||
|
break
|
||||||
|
case relaycommon.RelayFormatClaude:
|
||||||
|
claudeResp := service.ResponseOpenAI2Claude(&simpleResponse, info)
|
||||||
|
claudeRespStr, err := json.Marshal(claudeResp)
|
||||||
|
if err != nil {
|
||||||
|
return service.OpenAIErrorWrapper(err, "marshal_response_body_failed", http.StatusInternalServerError), nil
|
||||||
|
}
|
||||||
|
responseBody = claudeRespStr
|
||||||
|
}
|
||||||
|
|
||||||
// Reset response body
|
// Reset response body
|
||||||
resp.Body = io.NopCloser(bytes.NewBuffer(responseBody))
|
resp.Body = io.NopCloser(bytes.NewBuffer(responseBody))
|
||||||
// We shouldn't set the header before we parse the response body, because the parse part may fail.
|
// We shouldn't set the header before we parse the response body, because the parse part may fail.
|
||||||
|
|||||||
@@ -60,7 +60,6 @@ func ClaudeErrorWrapper(err error, code string, statusCode int) *dto.ClaudeError
|
|||||||
claudeError := dto.ClaudeError{
|
claudeError := dto.ClaudeError{
|
||||||
Message: text,
|
Message: text,
|
||||||
Type: "new_api_error",
|
Type: "new_api_error",
|
||||||
//Code: code,
|
|
||||||
}
|
}
|
||||||
return &dto.ClaudeErrorWithStatusCode{
|
return &dto.ClaudeErrorWithStatusCode{
|
||||||
Error: claudeError,
|
Error: claudeError,
|
||||||
|
|||||||
Reference in New Issue
Block a user