Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
phsl
/
new-api
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
6e891620
authored
Mar 16, 2025
by
1808837298@qq.com
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
refactor: Enhance Claude response handling
parent
62dc8263
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
74 additions
and
64 deletions
+74
-64
dto/openai_response.go
+1
-1
relay/channel/aws/relay-aws.go
+12
-22
relay/channel/claude/relay-claude.go
+59
-40
relay/channel/openai/relay-openai.go
+2
-1
No files found.
dto/openai_response.go
View file @
6e891620
...
...
@@ -26,7 +26,7 @@ type OpenAITextResponse struct {
Object
string
`json:"object"`
Created
int64
`json:"created"`
Choices
[]
OpenAITextResponseChoice
`json:"choices"`
Error
*
OpenAIError
`json:"error"`
Error
*
OpenAIError
`json:"error
,omitempty
"`
Usage
`json:"usage"`
}
...
...
relay/channel/aws/relay-aws.go
View file @
6e891620
...
...
@@ -84,22 +84,16 @@ func awsHandler(c *gin.Context, info *relaycommon.RelayInfo, requestMode int) (*
return
wrapErr
(
errors
.
Wrap
(
err
,
"InvokeModel"
)),
nil
}
claudeResponse
:=
new
(
dto
.
ClaudeResponse
)
err
=
json
.
Unmarshal
(
awsResp
.
Body
,
claudeResponse
)
if
err
!=
nil
{
return
wrapErr
(
errors
.
Wrap
(
err
,
"unmarshal response"
)),
nil
}
openaiResp
:=
claude
.
ResponseClaude2OpenAI
(
requestMode
,
claudeResponse
)
usage
:=
dto
.
Usage
{
PromptTokens
:
claudeResponse
.
Usage
.
InputTokens
,
CompletionTokens
:
claudeResponse
.
Usage
.
OutputTokens
,
TotalTokens
:
claudeResponse
.
Usage
.
InputTokens
+
claudeResponse
.
Usage
.
OutputTokens
,
claudeInfo
:=
&
claude
.
ClaudeResponseInfo
{
ResponseId
:
fmt
.
Sprintf
(
"chatcmpl-%s"
,
common
.
GetUUID
()),
Created
:
common
.
GetTimestamp
(),
Model
:
info
.
UpstreamModelName
,
ResponseText
:
strings
.
Builder
{},
Usage
:
&
dto
.
Usage
{},
}
openaiResp
.
Usage
=
usage
c
.
JSON
(
http
.
StatusOK
,
openaiResp
)
return
nil
,
&
u
sage
c
laude
.
HandleClaudeResponseData
(
c
,
info
,
claudeInfo
,
awsResp
.
Body
,
RequestModeMessage
)
return
nil
,
claudeInfo
.
U
sage
}
func
awsStreamHandler
(
c
*
gin
.
Context
,
resp
*
http
.
Response
,
info
*
relaycommon
.
RelayInfo
,
requestMode
int
)
(
*
dto
.
OpenAIErrorWithStatusCode
,
*
dto
.
Usage
)
{
...
...
@@ -150,9 +144,9 @@ func awsStreamHandler(c *gin.Context, resp *http.Response, info *relaycommon.Rel
switch
v
:=
event
.
(
type
)
{
case
*
types
.
ResponseStreamMemberChunk
:
info
.
SetFirstResponseTime
()
err
=
claude
.
Handle
ResponseData
(
c
,
info
,
claudeInfo
,
string
(
v
.
Value
.
Bytes
),
RequestModeMessage
)
if
e
rr
!=
nil
{
return
wrapErr
(
err
)
,
nil
respErr
:=
claude
.
HandleStream
ResponseData
(
c
,
info
,
claudeInfo
,
string
(
v
.
Value
.
Bytes
),
RequestModeMessage
)
if
respE
rr
!=
nil
{
return
respErr
,
nil
}
case
*
types
.
UnknownUnionMember
:
fmt
.
Println
(
"unknown tag:"
,
v
.
Tag
)
...
...
@@ -163,10 +157,6 @@ func awsStreamHandler(c *gin.Context, resp *http.Response, info *relaycommon.Rel
}
}
claude
.
HandleFinalResponse
(
c
,
info
,
claudeInfo
,
RequestModeMessage
)
if
resp
!=
nil
{
resp
.
Body
.
Close
()
}
claude
.
HandleStreamFinalResponse
(
c
,
info
,
claudeInfo
,
RequestModeMessage
)
return
nil
,
claudeInfo
.
Usage
}
relay/channel/claude/relay-claude.go
View file @
6e891620
...
...
@@ -478,12 +478,22 @@ func FormatClaudeResponseInfo(requestMode int, claudeResponse *dto.ClaudeRespons
return
true
}
func
Handle
ResponseData
(
c
*
gin
.
Context
,
info
*
relaycommon
.
RelayInfo
,
claudeInfo
*
ClaudeResponseInfo
,
data
string
,
requestMode
int
)
error
{
func
Handle
StreamResponseData
(
c
*
gin
.
Context
,
info
*
relaycommon
.
RelayInfo
,
claudeInfo
*
ClaudeResponseInfo
,
data
string
,
requestMode
int
)
*
dto
.
OpenAIErrorWithStatusCode
{
var
claudeResponse
dto
.
ClaudeResponse
err
:=
common
.
DecodeJsonStr
(
data
,
&
claudeResponse
)
if
err
!=
nil
{
common
.
SysError
(
"error unmarshalling stream response: "
+
err
.
Error
())
return
fmt
.
Errorf
(
"error unmarshalling stream aws response: %w"
,
err
)
return
service
.
OpenAIErrorWrapper
(
err
,
"stream_response_error"
,
http
.
StatusInternalServerError
)
}
if
claudeResponse
.
Error
.
Type
!=
""
{
return
&
dto
.
OpenAIErrorWithStatusCode
{
Error
:
dto
.
OpenAIError
{
Code
:
"stream_response_error"
,
Type
:
claudeResponse
.
Error
.
Type
,
Message
:
claudeResponse
.
Error
.
Message
,
},
StatusCode
:
http
.
StatusInternalServerError
,
}
}
if
info
.
RelayFormat
==
relaycommon
.
RelayFormatClaude
{
if
requestMode
==
RequestModeCompletion
{
...
...
@@ -523,7 +533,7 @@ func HandleResponseData(c *gin.Context, info *relaycommon.RelayInfo, claudeInfo
return
nil
}
func
HandleFinalResponse
(
c
*
gin
.
Context
,
info
*
relaycommon
.
RelayInfo
,
claudeInfo
*
ClaudeResponseInfo
,
requestMode
int
)
{
func
Handle
Stream
FinalResponse
(
c
*
gin
.
Context
,
info
*
relaycommon
.
RelayInfo
,
claudeInfo
*
ClaudeResponseInfo
,
requestMode
int
)
{
if
info
.
RelayFormat
==
relaycommon
.
RelayFormatClaude
{
if
requestMode
==
RequestModeCompletion
{
claudeInfo
.
Usage
,
_
=
service
.
ResponseText2Usage
(
claudeInfo
.
ResponseText
.
String
(),
info
.
UpstreamModelName
,
info
.
PromptTokens
)
...
...
@@ -566,81 +576,90 @@ func ClaudeStreamHandler(c *gin.Context, resp *http.Response, info *relaycommon.
ResponseText
:
strings
.
Builder
{},
Usage
:
&
dto
.
Usage
{},
}
var
err
error
var
err
*
dto
.
OpenAIErrorWithStatusCode
helper
.
StreamScannerHandler
(
c
,
resp
,
info
,
func
(
data
string
)
bool
{
err
=
HandleResponseData
(
c
,
info
,
claudeInfo
,
data
,
requestMode
)
err
=
Handle
Stream
ResponseData
(
c
,
info
,
claudeInfo
,
data
,
requestMode
)
if
err
!=
nil
{
return
false
}
return
true
})
if
err
!=
nil
{
return
service
.
OpenAIErrorWrapper
(
err
,
"stream_response_error"
,
http
.
StatusInternalServerError
)
,
nil
return
err
,
nil
}
HandleFinalResponse
(
c
,
info
,
claudeInfo
,
requestMode
)
HandleStreamFinalResponse
(
c
,
info
,
claudeInfo
,
requestMode
)
return
nil
,
claudeInfo
.
Usage
}
func
ClaudeHandler
(
c
*
gin
.
Context
,
resp
*
http
.
Response
,
requestMode
int
,
info
*
relaycommon
.
RelayInfo
)
(
*
dto
.
OpenAIErrorWithStatusCode
,
*
dto
.
Usage
)
{
responseBody
,
err
:=
io
.
ReadAll
(
resp
.
Body
)
if
err
!=
nil
{
return
service
.
OpenAIErrorWrapper
(
err
,
"read_response_body_failed"
,
http
.
StatusInternalServerError
),
nil
}
err
=
resp
.
Body
.
Close
()
if
err
!=
nil
{
return
service
.
OpenAIErrorWrapper
(
err
,
"close_response_body_failed"
,
http
.
StatusInternalServerError
),
nil
}
if
common
.
DebugEnabled
{
println
(
"responseBody: "
,
string
(
responseBody
))
}
func
HandleClaudeResponseData
(
c
*
gin
.
Context
,
info
*
relaycommon
.
RelayInfo
,
claudeInfo
*
ClaudeResponseInfo
,
data
[]
byte
,
requestMode
int
)
*
dto
.
OpenAIErrorWithStatusCode
{
var
claudeResponse
dto
.
ClaudeResponse
err
=
json
.
Unmarshal
(
responseBody
,
&
claudeResponse
)
err
:=
common
.
DecodeJson
(
data
,
&
claudeResponse
)
if
err
!=
nil
{
return
service
.
OpenAIErrorWrapper
(
err
,
"unmarshal_
response_body_failed"
,
http
.
StatusInternalServerError
),
nil
return
service
.
OpenAIErrorWrapper
(
err
,
"unmarshal_
claude_response_failed"
,
http
.
StatusInternalServerError
)
}
if
claudeResponse
.
Error
.
Type
!=
""
{
return
&
dto
.
OpenAIErrorWithStatusCode
{
Error
:
dto
.
OpenAIError
{
Message
:
claudeResponse
.
Error
.
Message
,
Type
:
claudeResponse
.
Error
.
Type
,
Param
:
""
,
Code
:
claudeResponse
.
Error
.
Type
,
},
StatusCode
:
resp
.
StatusCode
,
}
,
nil
StatusCode
:
http
.
StatusInternalServerError
,
}
}
usage
:=
dto
.
Usage
{}
if
requestMode
==
RequestModeCompletion
{
completionTokens
,
err
:=
service
.
CountTextToken
(
claudeResponse
.
Completion
,
info
.
OriginModelName
)
if
err
!=
nil
{
return
service
.
OpenAIErrorWrapper
(
err
,
"count_token_text_failed"
,
http
.
StatusInternalServerError
)
,
nil
return
service
.
OpenAIErrorWrapper
(
err
,
"count_token_text_failed"
,
http
.
StatusInternalServerError
)
}
u
sage
.
PromptTokens
=
info
.
PromptTokens
u
sage
.
CompletionTokens
=
completionTokens
u
sage
.
TotalTokens
=
info
.
PromptTokens
+
completionTokens
claudeInfo
.
U
sage
.
PromptTokens
=
info
.
PromptTokens
claudeInfo
.
U
sage
.
CompletionTokens
=
completionTokens
claudeInfo
.
U
sage
.
TotalTokens
=
info
.
PromptTokens
+
completionTokens
}
else
{
u
sage
.
PromptTokens
=
claudeResponse
.
Usage
.
InputTokens
u
sage
.
CompletionTokens
=
claudeResponse
.
Usage
.
OutputTokens
u
sage
.
TotalTokens
=
claudeResponse
.
Usage
.
InputTokens
+
claudeResponse
.
Usage
.
OutputTokens
u
sage
.
PromptTokensDetails
.
CachedTokens
=
claudeResponse
.
Usage
.
CacheReadInputTokens
u
sage
.
PromptTokensDetails
.
CachedCreationTokens
=
claudeResponse
.
Usage
.
CacheCreationInputTokens
claudeInfo
.
U
sage
.
PromptTokens
=
claudeResponse
.
Usage
.
InputTokens
claudeInfo
.
U
sage
.
CompletionTokens
=
claudeResponse
.
Usage
.
OutputTokens
claudeInfo
.
U
sage
.
TotalTokens
=
claudeResponse
.
Usage
.
InputTokens
+
claudeResponse
.
Usage
.
OutputTokens
claudeInfo
.
U
sage
.
PromptTokensDetails
.
CachedTokens
=
claudeResponse
.
Usage
.
CacheReadInputTokens
claudeInfo
.
U
sage
.
PromptTokensDetails
.
CachedCreationTokens
=
claudeResponse
.
Usage
.
CacheCreationInputTokens
}
var
responseData
[]
byte
switch
info
.
RelayFormat
{
case
relaycommon
.
RelayFormatOpenAI
:
openaiResponse
:=
ResponseClaude2OpenAI
(
requestMode
,
&
claudeResponse
)
openaiResponse
.
Usage
=
u
sage
openaiResponse
.
Usage
=
*
claudeInfo
.
U
sage
responseData
,
err
=
json
.
Marshal
(
openaiResponse
)
if
err
!=
nil
{
return
service
.
OpenAIErrorWrapper
(
err
,
"marshal_response_body_failed"
,
http
.
StatusInternalServerError
)
,
nil
return
service
.
OpenAIErrorWrapper
(
err
,
"marshal_response_body_failed"
,
http
.
StatusInternalServerError
)
}
case
relaycommon
.
RelayFormatClaude
:
responseData
=
responseBody
responseData
=
data
}
c
.
Writer
.
Header
()
.
Set
(
"Content-Type"
,
"application/json"
)
c
.
Writer
.
WriteHeader
(
resp
.
StatusCode
)
c
.
Writer
.
WriteHeader
(
http
.
StatusOK
)
_
,
err
=
c
.
Writer
.
Write
(
responseData
)
return
nil
,
&
usage
return
nil
}
func
ClaudeHandler
(
c
*
gin
.
Context
,
resp
*
http
.
Response
,
requestMode
int
,
info
*
relaycommon
.
RelayInfo
)
(
*
dto
.
OpenAIErrorWithStatusCode
,
*
dto
.
Usage
)
{
claudeInfo
:=
&
ClaudeResponseInfo
{
ResponseId
:
fmt
.
Sprintf
(
"chatcmpl-%s"
,
common
.
GetUUID
()),
Created
:
common
.
GetTimestamp
(),
Model
:
info
.
UpstreamModelName
,
ResponseText
:
strings
.
Builder
{},
Usage
:
&
dto
.
Usage
{},
}
responseBody
,
err
:=
io
.
ReadAll
(
resp
.
Body
)
if
err
!=
nil
{
return
service
.
OpenAIErrorWrapper
(
err
,
"read_response_body_failed"
,
http
.
StatusInternalServerError
),
nil
}
resp
.
Body
.
Close
()
if
common
.
DebugEnabled
{
println
(
"responseBody: "
,
string
(
responseBody
))
}
handleErr
:=
HandleClaudeResponseData
(
c
,
info
,
claudeInfo
,
responseBody
,
requestMode
)
if
handleErr
!=
nil
{
return
handleErr
,
nil
}
return
nil
,
claudeInfo
.
Usage
}
relay/channel/openai/relay-openai.go
View file @
6e891620
...
...
@@ -240,7 +240,8 @@ func OpenaiHandler(c *gin.Context, resp *http.Response, info *relaycommon.RelayI
c
.
Writer
.
WriteHeader
(
resp
.
StatusCode
)
_
,
err
=
io
.
Copy
(
c
.
Writer
,
resp
.
Body
)
if
err
!=
nil
{
return
service
.
OpenAIErrorWrapper
(
err
,
"copy_response_body_failed"
,
http
.
StatusInternalServerError
),
nil
//return service.OpenAIErrorWrapper(err, "copy_response_body_failed", http.StatusInternalServerError), nil
common
.
SysError
(
"error copying response body: "
+
err
.
Error
())
}
resp
.
Body
.
Close
()
if
simpleResponse
.
Usage
.
TotalTokens
==
0
||
(
simpleResponse
.
Usage
.
PromptTokens
==
0
&&
simpleResponse
.
Usage
.
CompletionTokens
==
0
)
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment