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
360012be
authored
Jul 26, 2025
by
CaIon
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: support claude convert to gemini
parent
2cb7b9ae
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
84 additions
and
37 deletions
+84
-37
model/ability.go
+1
-1
model/channel_cache.go
+1
-1
relay/channel/gemini/adaptor.go
+8
-4
relay/channel/gemini/relay-gemini.go
+49
-12
relay/channel/openai/helper.go
+2
-2
relay/channel/openai/relay-openai.go
+4
-17
relay/helper/common.go
+18
-0
types/error.go
+1
-0
No files found.
model/ability.go
View file @
360012be
...
@@ -136,7 +136,7 @@ func GetRandomSatisfiedChannel(group string, model string, retry int) (*Channel,
...
@@ -136,7 +136,7 @@ func GetRandomSatisfiedChannel(group string, model string, retry int) (*Channel,
}
}
}
}
}
else
{
}
else
{
return
nil
,
errors
.
New
(
"channel not found"
)
return
nil
,
nil
}
}
err
=
DB
.
First
(
&
channel
,
"id = ?"
,
channel
.
Id
)
.
Error
err
=
DB
.
First
(
&
channel
,
"id = ?"
,
channel
.
Id
)
.
Error
return
&
channel
,
err
return
&
channel
,
err
...
...
model/channel_cache.go
View file @
360012be
...
@@ -130,7 +130,7 @@ func getRandomSatisfiedChannel(group string, model string, retry int) (*Channel,
...
@@ -130,7 +130,7 @@ func getRandomSatisfiedChannel(group string, model string, retry int) (*Channel,
channels
:=
group2model2channels
[
group
][
model
]
channels
:=
group2model2channels
[
group
][
model
]
if
len
(
channels
)
==
0
{
if
len
(
channels
)
==
0
{
return
nil
,
errors
.
New
(
"channel not found"
)
return
nil
,
nil
}
}
if
len
(
channels
)
==
1
{
if
len
(
channels
)
==
1
{
...
...
relay/channel/gemini/adaptor.go
View file @
360012be
...
@@ -9,6 +9,7 @@ import (
...
@@ -9,6 +9,7 @@ import (
"one-api/common"
"one-api/common"
"one-api/dto"
"one-api/dto"
"one-api/relay/channel"
"one-api/relay/channel"
"one-api/relay/channel/openai"
relaycommon
"one-api/relay/common"
relaycommon
"one-api/relay/common"
"one-api/relay/constant"
"one-api/relay/constant"
"one-api/setting/model_setting"
"one-api/setting/model_setting"
...
@@ -21,10 +22,13 @@ import (
...
@@ -21,10 +22,13 @@ import (
type
Adaptor
struct
{
type
Adaptor
struct
{
}
}
func
(
a
*
Adaptor
)
ConvertClaudeRequest
(
*
gin
.
Context
,
*
relaycommon
.
RelayInfo
,
*
dto
.
ClaudeRequest
)
(
any
,
error
)
{
func
(
a
*
Adaptor
)
ConvertClaudeRequest
(
c
*
gin
.
Context
,
info
*
relaycommon
.
RelayInfo
,
req
*
dto
.
ClaudeRequest
)
(
any
,
error
)
{
//TODO implement me
adaptor
:=
openai
.
Adaptor
{}
panic
(
"implement me"
)
oaiReq
,
err
:=
adaptor
.
ConvertClaudeRequest
(
c
,
info
,
req
)
return
nil
,
nil
if
err
!=
nil
{
return
nil
,
err
}
return
a
.
ConvertOpenAIRequest
(
c
,
info
,
oaiReq
.
(
*
dto
.
GeneralOpenAIRequest
))
}
}
func
(
a
*
Adaptor
)
ConvertAudioRequest
(
c
*
gin
.
Context
,
info
*
relaycommon
.
RelayInfo
,
request
dto
.
AudioRequest
)
(
io
.
Reader
,
error
)
{
func
(
a
*
Adaptor
)
ConvertAudioRequest
(
c
*
gin
.
Context
,
info
*
relaycommon
.
RelayInfo
,
request
dto
.
AudioRequest
)
(
io
.
Reader
,
error
)
{
...
...
relay/channel/gemini/relay-gemini.go
View file @
360012be
...
@@ -9,6 +9,7 @@ import (
...
@@ -9,6 +9,7 @@ import (
"one-api/common"
"one-api/common"
"one-api/constant"
"one-api/constant"
"one-api/dto"
"one-api/dto"
"one-api/relay/channel/openai"
relaycommon
"one-api/relay/common"
relaycommon
"one-api/relay/common"
"one-api/relay/helper"
"one-api/relay/helper"
"one-api/service"
"one-api/service"
...
@@ -736,7 +737,7 @@ func streamResponseGeminiChat2OpenAI(geminiResponse *GeminiChatResponse) (*dto.C
...
@@ -736,7 +737,7 @@ func streamResponseGeminiChat2OpenAI(geminiResponse *GeminiChatResponse) (*dto.C
choice
:=
dto
.
ChatCompletionsStreamResponseChoice
{
choice
:=
dto
.
ChatCompletionsStreamResponseChoice
{
Index
:
int
(
candidate
.
Index
),
Index
:
int
(
candidate
.
Index
),
Delta
:
dto
.
ChatCompletionsStreamResponseChoiceDelta
{
Delta
:
dto
.
ChatCompletionsStreamResponseChoiceDelta
{
Role
:
"assistant"
,
//
Role: "assistant",
},
},
}
}
var
texts
[]
string
var
texts
[]
string
...
@@ -798,6 +799,27 @@ func streamResponseGeminiChat2OpenAI(geminiResponse *GeminiChatResponse) (*dto.C
...
@@ -798,6 +799,27 @@ func streamResponseGeminiChat2OpenAI(geminiResponse *GeminiChatResponse) (*dto.C
return
&
response
,
isStop
,
hasImage
return
&
response
,
isStop
,
hasImage
}
}
func
handleStream
(
c
*
gin
.
Context
,
info
*
relaycommon
.
RelayInfo
,
resp
*
dto
.
ChatCompletionsStreamResponse
)
error
{
streamData
,
err
:=
common
.
Marshal
(
resp
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"failed to marshal stream response: %w"
,
err
)
}
err
=
openai
.
HandleStreamFormat
(
c
,
info
,
string
(
streamData
),
info
.
ChannelSetting
.
ForceFormat
,
info
.
ChannelSetting
.
ThinkingToContent
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"failed to handle stream format: %w"
,
err
)
}
return
nil
}
func
handleFinalStream
(
c
*
gin
.
Context
,
info
*
relaycommon
.
RelayInfo
,
resp
*
dto
.
ChatCompletionsStreamResponse
)
error
{
streamData
,
err
:=
common
.
Marshal
(
resp
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"failed to marshal stream response: %w"
,
err
)
}
openai
.
HandleFinalResponse
(
c
,
info
,
string
(
streamData
),
resp
.
Id
,
resp
.
Created
,
resp
.
Model
,
resp
.
GetSystemFingerprint
(),
resp
.
Usage
,
info
.
ShouldIncludeUsage
)
return
nil
}
func
GeminiChatStreamHandler
(
c
*
gin
.
Context
,
info
*
relaycommon
.
RelayInfo
,
resp
*
http
.
Response
)
(
*
dto
.
Usage
,
*
types
.
NewAPIError
)
{
func
GeminiChatStreamHandler
(
c
*
gin
.
Context
,
info
*
relaycommon
.
RelayInfo
,
resp
*
http
.
Response
)
(
*
dto
.
Usage
,
*
types
.
NewAPIError
)
{
// responseText := ""
// responseText := ""
id
:=
helper
.
GetResponseID
(
c
)
id
:=
helper
.
GetResponseID
(
c
)
...
@@ -805,6 +827,8 @@ func GeminiChatStreamHandler(c *gin.Context, info *relaycommon.RelayInfo, resp *
...
@@ -805,6 +827,8 @@ func GeminiChatStreamHandler(c *gin.Context, info *relaycommon.RelayInfo, resp *
var
usage
=
&
dto
.
Usage
{}
var
usage
=
&
dto
.
Usage
{}
var
imageCount
int
var
imageCount
int
respCount
:=
0
helper
.
StreamScannerHandler
(
c
,
resp
,
info
,
func
(
data
string
)
bool
{
helper
.
StreamScannerHandler
(
c
,
resp
,
info
,
func
(
data
string
)
bool
{
var
geminiResponse
GeminiChatResponse
var
geminiResponse
GeminiChatResponse
err
:=
common
.
UnmarshalJsonStr
(
data
,
&
geminiResponse
)
err
:=
common
.
UnmarshalJsonStr
(
data
,
&
geminiResponse
)
...
@@ -833,18 +857,31 @@ func GeminiChatStreamHandler(c *gin.Context, info *relaycommon.RelayInfo, resp *
...
@@ -833,18 +857,31 @@ func GeminiChatStreamHandler(c *gin.Context, info *relaycommon.RelayInfo, resp *
}
}
}
}
}
}
err
=
helper
.
ObjectData
(
c
,
response
)
if
respCount
==
0
{
// send first response
err
=
handleStream
(
c
,
info
,
helper
.
GenerateStartEmptyResponse
(
id
,
createAt
,
info
.
UpstreamModelName
,
nil
))
if
err
!=
nil
{
common
.
LogError
(
c
,
err
.
Error
())
}
}
err
=
handleStream
(
c
,
info
,
response
)
if
err
!=
nil
{
if
err
!=
nil
{
common
.
LogError
(
c
,
err
.
Error
())
common
.
LogError
(
c
,
err
.
Error
())
}
}
if
isStop
{
if
isStop
{
response
:=
helper
.
GenerateStopResponse
(
id
,
createAt
,
info
.
UpstreamModelName
,
constant
.
FinishReasonStop
)
_
=
handleStream
(
c
,
info
,
helper
.
GenerateStopResponse
(
id
,
createAt
,
info
.
UpstreamModelName
,
constant
.
FinishReasonStop
))
helper
.
ObjectData
(
c
,
response
)
}
}
respCount
++
return
true
return
true
})
})
var
response
*
dto
.
ChatCompletionsStreamResponse
if
respCount
==
0
{
// 空补全,报错不计费
// empty response, throw an error
return
nil
,
types
.
NewOpenAIError
(
errors
.
New
(
"no response received from Gemini API"
),
types
.
ErrorCodeEmptyResponse
,
http
.
StatusInternalServerError
)
}
if
imageCount
!=
0
{
if
imageCount
!=
0
{
if
usage
.
CompletionTokens
==
0
{
if
usage
.
CompletionTokens
==
0
{
...
@@ -855,14 +892,14 @@ func GeminiChatStreamHandler(c *gin.Context, info *relaycommon.RelayInfo, resp *
...
@@ -855,14 +892,14 @@ func GeminiChatStreamHandler(c *gin.Context, info *relaycommon.RelayInfo, resp *
usage
.
PromptTokensDetails
.
TextTokens
=
usage
.
PromptTokens
usage
.
PromptTokensDetails
.
TextTokens
=
usage
.
PromptTokens
usage
.
CompletionTokens
=
usage
.
TotalTokens
-
usage
.
PromptTokens
usage
.
CompletionTokens
=
usage
.
TotalTokens
-
usage
.
PromptTokens
if
info
.
ShouldIncludeUsage
{
response
:=
helper
.
GenerateFinalUsageResponse
(
id
,
createAt
,
info
.
UpstreamModelName
,
*
usage
)
response
=
helper
.
GenerateFinalUsageResponse
(
id
,
createAt
,
info
.
UpstreamModelName
,
*
usage
)
err
:=
handleFinalStream
(
c
,
info
,
response
)
err
:=
helper
.
ObjectData
(
c
,
response
)
if
err
!=
nil
{
if
err
!=
nil
{
common
.
SysError
(
"send final response failed: "
+
err
.
Error
())
common
.
SysError
(
"send final response failed: "
+
err
.
Error
())
}
}
}
helper
.
Done
(
c
)
//if info.RelayFormat == relaycommon.RelayFormatOpenAI {
// helper.Done(c)
//}
//resp.Body.Close()
//resp.Body.Close()
return
usage
,
nil
return
usage
,
nil
}
}
...
...
relay/channel/openai/helper.go
View file @
360012be
...
@@ -14,7 +14,7 @@ import (
...
@@ -14,7 +14,7 @@ import (
)
)
// 辅助函数
// 辅助函数
func
h
andleStreamFormat
(
c
*
gin
.
Context
,
info
*
relaycommon
.
RelayInfo
,
data
string
,
forceFormat
bool
,
thinkToContent
bool
)
error
{
func
H
andleStreamFormat
(
c
*
gin
.
Context
,
info
*
relaycommon
.
RelayInfo
,
data
string
,
forceFormat
bool
,
thinkToContent
bool
)
error
{
info
.
SendResponseCount
++
info
.
SendResponseCount
++
switch
info
.
RelayFormat
{
switch
info
.
RelayFormat
{
case
relaycommon
.
RelayFormatOpenAI
:
case
relaycommon
.
RelayFormatOpenAI
:
...
@@ -158,7 +158,7 @@ func handleLastResponse(lastStreamData string, responseId *string, createAt *int
...
@@ -158,7 +158,7 @@ func handleLastResponse(lastStreamData string, responseId *string, createAt *int
return
nil
return
nil
}
}
func
h
andleFinalResponse
(
c
*
gin
.
Context
,
info
*
relaycommon
.
RelayInfo
,
lastStreamData
string
,
func
H
andleFinalResponse
(
c
*
gin
.
Context
,
info
*
relaycommon
.
RelayInfo
,
lastStreamData
string
,
responseId
string
,
createAt
int64
,
model
string
,
systemFingerprint
string
,
responseId
string
,
createAt
int64
,
model
string
,
systemFingerprint
string
,
usage
*
dto
.
Usage
,
containStreamUsage
bool
)
{
usage
*
dto
.
Usage
,
containStreamUsage
bool
)
{
...
...
relay/channel/openai/relay-openai.go
View file @
360012be
...
@@ -123,24 +123,11 @@ func OaiStreamHandler(c *gin.Context, info *relaycommon.RelayInfo, resp *http.Re
...
@@ -123,24 +123,11 @@ func OaiStreamHandler(c *gin.Context, info *relaycommon.RelayInfo, resp *http.Re
var
toolCount
int
var
toolCount
int
var
usage
=
&
dto
.
Usage
{}
var
usage
=
&
dto
.
Usage
{}
var
streamItems
[]
string
// store stream items
var
streamItems
[]
string
// store stream items
var
forceFormat
bool
var
lastStreamData
string
var
thinkToContent
bool
if
info
.
ChannelSetting
.
ForceFormat
{
forceFormat
=
true
}
if
info
.
ChannelSetting
.
ThinkingToContent
{
thinkToContent
=
true
}
var
(
lastStreamData
string
)
helper
.
StreamScannerHandler
(
c
,
resp
,
info
,
func
(
data
string
)
bool
{
helper
.
StreamScannerHandler
(
c
,
resp
,
info
,
func
(
data
string
)
bool
{
if
lastStreamData
!=
""
{
if
lastStreamData
!=
""
{
err
:=
handleStreamFormat
(
c
,
info
,
lastStreamData
,
forceFormat
,
think
ToContent
)
err
:=
HandleStreamFormat
(
c
,
info
,
lastStreamData
,
info
.
ChannelSetting
.
ForceFormat
,
info
.
ChannelSetting
.
Thinking
ToContent
)
if
err
!=
nil
{
if
err
!=
nil
{
common
.
SysError
(
"error handling stream format: "
+
err
.
Error
())
common
.
SysError
(
"error handling stream format: "
+
err
.
Error
())
}
}
...
@@ -161,7 +148,7 @@ func OaiStreamHandler(c *gin.Context, info *relaycommon.RelayInfo, resp *http.Re
...
@@ -161,7 +148,7 @@ func OaiStreamHandler(c *gin.Context, info *relaycommon.RelayInfo, resp *http.Re
if
info
.
RelayFormat
==
relaycommon
.
RelayFormatOpenAI
{
if
info
.
RelayFormat
==
relaycommon
.
RelayFormatOpenAI
{
if
shouldSendLastResp
{
if
shouldSendLastResp
{
_
=
sendStreamData
(
c
,
info
,
lastStreamData
,
forceFormat
,
think
ToContent
)
_
=
sendStreamData
(
c
,
info
,
lastStreamData
,
info
.
ChannelSetting
.
ForceFormat
,
info
.
ChannelSetting
.
Thinking
ToContent
)
}
}
}
}
...
@@ -180,7 +167,7 @@ func OaiStreamHandler(c *gin.Context, info *relaycommon.RelayInfo, resp *http.Re
...
@@ -180,7 +167,7 @@ func OaiStreamHandler(c *gin.Context, info *relaycommon.RelayInfo, resp *http.Re
}
}
}
}
}
}
h
andleFinalResponse
(
c
,
info
,
lastStreamData
,
responseId
,
createAt
,
model
,
systemFingerprint
,
usage
,
containStreamUsage
)
H
andleFinalResponse
(
c
,
info
,
lastStreamData
,
responseId
,
createAt
,
model
,
systemFingerprint
,
usage
,
containStreamUsage
)
return
usage
,
nil
return
usage
,
nil
}
}
...
...
relay/helper/common.go
View file @
360012be
...
@@ -139,6 +139,24 @@ func GetLocalRealtimeID(c *gin.Context) string {
...
@@ -139,6 +139,24 @@ func GetLocalRealtimeID(c *gin.Context) string {
return
fmt
.
Sprintf
(
"evt_%s"
,
logID
)
return
fmt
.
Sprintf
(
"evt_%s"
,
logID
)
}
}
func
GenerateStartEmptyResponse
(
id
string
,
createAt
int64
,
model
string
,
systemFingerprint
*
string
)
*
dto
.
ChatCompletionsStreamResponse
{
return
&
dto
.
ChatCompletionsStreamResponse
{
Id
:
id
,
Object
:
"chat.completion.chunk"
,
Created
:
createAt
,
Model
:
model
,
SystemFingerprint
:
systemFingerprint
,
Choices
:
[]
dto
.
ChatCompletionsStreamResponseChoice
{
{
Delta
:
dto
.
ChatCompletionsStreamResponseChoiceDelta
{
Role
:
"assistant"
,
Content
:
common
.
GetPointer
(
""
),
},
},
},
}
}
func
GenerateStopResponse
(
id
string
,
createAt
int64
,
model
string
,
finishReason
string
)
*
dto
.
ChatCompletionsStreamResponse
{
func
GenerateStopResponse
(
id
string
,
createAt
int64
,
model
string
,
finishReason
string
)
*
dto
.
ChatCompletionsStreamResponse
{
return
&
dto
.
ChatCompletionsStreamResponse
{
return
&
dto
.
ChatCompletionsStreamResponse
{
Id
:
id
,
Id
:
id
,
...
...
types/error.go
View file @
360012be
...
@@ -63,6 +63,7 @@ const (
...
@@ -63,6 +63,7 @@ const (
ErrorCodeBadResponseStatusCode
ErrorCode
=
"bad_response_status_code"
ErrorCodeBadResponseStatusCode
ErrorCode
=
"bad_response_status_code"
ErrorCodeBadResponse
ErrorCode
=
"bad_response"
ErrorCodeBadResponse
ErrorCode
=
"bad_response"
ErrorCodeBadResponseBody
ErrorCode
=
"bad_response_body"
ErrorCodeBadResponseBody
ErrorCode
=
"bad_response_body"
ErrorCodeEmptyResponse
ErrorCode
=
"empty_response"
// sql error
// sql error
ErrorCodeQueryDataError
ErrorCode
=
"query_data_error"
ErrorCodeQueryDataError
ErrorCode
=
"query_data_error"
...
...
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