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
1ee3d1cc
authored
Aug 23, 2025
by
CaIon
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: 修复重试后请求结构混乱,修复rerank端点无法使用
parent
858585d9
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
227 additions
and
105 deletions
+227
-105
common/copy.go
+21
-0
dto/audio.go
+6
-0
dto/claude.go
+8
-2
dto/embedding.go
+6
-0
dto/gemini.go
+55
-0
dto/openai_image.go
+10
-4
dto/openai_request.go
+12
-0
dto/request_common.go
+2
-1
dto/rerank.go
+6
-0
go.mod
+9
-0
go.sum
+0
-0
relay/audio_handler.go
+9
-3
relay/claude_handler.go
+20
-15
relay/common/relay_info.go
+7
-0
relay/embedding_handler.go
+8
-4
relay/gemini_handler.go
+8
-3
relay/helper/model_mapped.go
+3
-39
relay/image_handler.go
+13
-10
relay/relay-text.go
+15
-12
relay/rerank_handler.go
+9
-12
No files found.
common/copy.go
0 → 100644
View file @
1ee3d1cc
package
common
import
(
"fmt"
"github.com/antlabs/pcopy"
)
func
DeepCopy
[
T
any
](
src
*
T
)
(
*
T
,
error
)
{
if
src
==
nil
{
return
nil
,
fmt
.
Errorf
(
"copy source cannot be nil"
)
}
var
dst
T
err
:=
pcopy
.
Copy
(
&
dst
,
src
)
if
err
!=
nil
{
return
nil
,
err
}
if
&
dst
==
nil
{
return
nil
,
fmt
.
Errorf
(
"copy result cannot be nil"
)
}
return
&
dst
,
nil
}
dto/audio.go
View file @
1ee3d1cc
...
...
@@ -26,6 +26,12 @@ func (r *AudioRequest) IsStream(c *gin.Context) bool {
return
false
}
func
(
r
*
AudioRequest
)
SetModelName
(
modelName
string
)
{
if
modelName
!=
""
{
r
.
Model
=
modelName
}
}
type
AudioResponse
struct
{
Text
string
`json:"text"`
}
...
...
dto/claude.go
View file @
1ee3d1cc
...
...
@@ -321,8 +321,14 @@ func (c *ClaudeRequest) GetTokenCountMeta() *types.TokenCountMeta {
return
&
tokenCountMeta
}
func
(
claudeRequest
*
ClaudeRequest
)
IsStream
(
c
*
gin
.
Context
)
bool
{
return
claudeRequest
.
Stream
func
(
c
*
ClaudeRequest
)
IsStream
(
ctx
*
gin
.
Context
)
bool
{
return
c
.
Stream
}
func
(
c
*
ClaudeRequest
)
SetModelName
(
modelName
string
)
{
if
modelName
!=
""
{
c
.
Model
=
modelName
}
}
func
(
c
*
ClaudeRequest
)
SearchToolNameByToolCallId
(
toolCallId
string
)
string
{
...
...
dto/embedding.go
View file @
1ee3d1cc
...
...
@@ -48,6 +48,12 @@ func (r *EmbeddingRequest) IsStream(c *gin.Context) bool {
return
false
}
func
(
r
*
EmbeddingRequest
)
SetModelName
(
modelName
string
)
{
if
modelName
!=
""
{
r
.
Model
=
modelName
}
}
func
(
r
*
EmbeddingRequest
)
ParseInput
()
[]
string
{
if
r
.
Input
==
nil
{
return
make
([]
string
,
0
)
...
...
dto/gemini.go
View file @
1ee3d1cc
...
...
@@ -73,6 +73,10 @@ func (r *GeminiChatRequest) IsStream(c *gin.Context) bool {
return
false
}
func
(
r
*
GeminiChatRequest
)
SetModelName
(
modelName
string
)
{
// GeminiChatRequest does not have a model field, so this method does nothing.
}
func
(
r
*
GeminiChatRequest
)
GetTools
()
[]
GeminiChatTool
{
var
tools
[]
GeminiChatTool
if
strings
.
HasSuffix
(
string
(
r
.
Tools
),
"["
)
{
...
...
@@ -312,10 +316,61 @@ type GeminiEmbeddingRequest struct {
OutputDimensionality
int
`json:"outputDimensionality,omitempty"`
}
func
(
r
*
GeminiEmbeddingRequest
)
IsStream
(
c
*
gin
.
Context
)
bool
{
// Gemini embedding requests are not streamed
return
false
}
func
(
r
*
GeminiEmbeddingRequest
)
GetTokenCountMeta
()
*
types
.
TokenCountMeta
{
var
inputTexts
[]
string
for
_
,
part
:=
range
r
.
Content
.
Parts
{
if
part
.
Text
!=
""
{
inputTexts
=
append
(
inputTexts
,
part
.
Text
)
}
}
inputText
:=
strings
.
Join
(
inputTexts
,
"
\n
"
)
return
&
types
.
TokenCountMeta
{
CombineText
:
inputText
,
}
}
func
(
r
*
GeminiEmbeddingRequest
)
SetModelName
(
modelName
string
)
{
if
modelName
!=
""
{
r
.
Model
=
modelName
}
}
type
GeminiBatchEmbeddingRequest
struct
{
Requests
[]
*
GeminiEmbeddingRequest
`json:"requests"`
}
func
(
r
*
GeminiBatchEmbeddingRequest
)
IsStream
(
c
*
gin
.
Context
)
bool
{
// Gemini batch embedding requests are not streamed
return
false
}
func
(
r
*
GeminiBatchEmbeddingRequest
)
GetTokenCountMeta
()
*
types
.
TokenCountMeta
{
var
inputTexts
[]
string
for
_
,
request
:=
range
r
.
Requests
{
meta
:=
request
.
GetTokenCountMeta
()
if
meta
!=
nil
&&
meta
.
CombineText
!=
""
{
inputTexts
=
append
(
inputTexts
,
meta
.
CombineText
)
}
}
inputText
:=
strings
.
Join
(
inputTexts
,
"
\n
"
)
return
&
types
.
TokenCountMeta
{
CombineText
:
inputText
,
}
}
func
(
r
*
GeminiBatchEmbeddingRequest
)
SetModelName
(
modelName
string
)
{
if
modelName
!=
""
{
for
_
,
req
:=
range
r
.
Requests
{
req
.
SetModelName
(
modelName
)
}
}
}
type
GeminiEmbeddingResponse
struct
{
Embedding
ContentEmbedding
`json:"embedding"`
}
...
...
dto/openai_image.go
View file @
1ee3d1cc
...
...
@@ -12,10 +12,10 @@ type ImageRequest struct {
Model
string
`json:"model"`
Prompt
string
`json:"prompt" binding:"required"`
N
uint
`json:"n,omitempty"`
Size
string
`json:"size,omitempty"`
Quality
string
`json:"quality,omitempty"`
ResponseFormat
string
`json:"response_format,omitempty"`
Style
json
.
RawMessage
`json:"style,omitempty"`
Size
string
`json:"size,omitempty"`
Quality
string
`json:"quality,omitempty"`
ResponseFormat
string
`json:"response_format,omitempty"`
Style
json
.
RawMessage
`json:"style,omitempty"`
User
json
.
RawMessage
`json:"user,omitempty"`
ExtraFields
json
.
RawMessage
`json:"extra_fields,omitempty"`
Background
json
.
RawMessage
`json:"background,omitempty"`
...
...
@@ -63,6 +63,12 @@ func (i *ImageRequest) IsStream(c *gin.Context) bool {
return
false
}
func
(
i
*
ImageRequest
)
SetModelName
(
modelName
string
)
{
if
modelName
!=
""
{
i
.
Model
=
modelName
}
}
type
ImageResponse
struct
{
Data
[]
ImageData
`json:"data"`
Created
int64
`json:"created"`
...
...
dto/openai_request.go
View file @
1ee3d1cc
...
...
@@ -183,6 +183,12 @@ func (r *GeneralOpenAIRequest) IsStream(c *gin.Context) bool {
return
r
.
Stream
}
func
(
r
*
GeneralOpenAIRequest
)
SetModelName
(
modelName
string
)
{
if
modelName
!=
""
{
r
.
Model
=
modelName
}
}
func
(
r
*
GeneralOpenAIRequest
)
ToMap
()
map
[
string
]
any
{
result
:=
make
(
map
[
string
]
any
)
data
,
_
:=
common
.
Marshal
(
r
)
...
...
@@ -841,6 +847,12 @@ func (r *OpenAIResponsesRequest) IsStream(c *gin.Context) bool {
return
r
.
Stream
}
func
(
r
*
OpenAIResponsesRequest
)
SetModelName
(
modelName
string
)
{
if
modelName
!=
""
{
r
.
Model
=
modelName
}
}
type
Reasoning
struct
{
Effort
string
`json:"effort,omitempty"`
Summary
string
`json:"summary,omitempty"`
...
...
dto/request_common.go
View file @
1ee3d1cc
...
...
@@ -8,6 +8,7 @@ import (
type
Request
interface
{
GetTokenCountMeta
()
*
types
.
TokenCountMeta
IsStream
(
c
*
gin
.
Context
)
bool
SetModelName
(
modelName
string
)
}
type
BaseRequest
struct
{
...
...
@@ -18,7 +19,7 @@ func (b *BaseRequest) GetTokenCountMeta() *types.TokenCountMeta {
TokenType
:
types
.
TokenTypeTokenizer
,
}
}
func
(
b
*
BaseRequest
)
IsStream
(
c
*
gin
.
Context
)
bool
{
return
false
}
func
(
b
*
BaseRequest
)
SetModelName
(
modelName
string
)
{}
dto/rerank.go
View file @
1ee3d1cc
...
...
@@ -37,6 +37,12 @@ func (r *RerankRequest) GetTokenCountMeta() *types.TokenCountMeta {
}
}
func
(
r
*
RerankRequest
)
SetModelName
(
modelName
string
)
{
if
modelName
!=
""
{
r
.
Model
=
modelName
}
}
func
(
r
*
RerankRequest
)
GetReturnDocuments
()
bool
{
if
r
.
ReturnDocuments
==
nil
{
return
false
...
...
go.mod
View file @
1ee3d1cc
...
...
@@ -44,7 +44,11 @@ require (
)
require (
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver/v3 v3.2.0 // indirect
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
github.com/anknown/darts v0.0.0-20151216065714-83ff685239e6 // indirect
github.com/antlabs/pcopy v0.1.5 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.0 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.2 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.2 // indirect
...
...
@@ -69,6 +73,8 @@ require (
github.com/gorilla/context v1.1.1 // indirect
github.com/gorilla/securecookie v1.1.1 // indirect
github.com/gorilla/sessions v1.2.1 // indirect
github.com/huandu/xstrings v1.3.3 // indirect
github.com/imdario/mergo v0.3.11 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
github.com/jackc/pgx/v5 v5.7.1 // indirect
...
...
@@ -79,11 +85,14 @@ require (
github.com/klauspost/cpuid/v2 v2.2.9 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mitchellh/copystructure v1.0.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mitchellh/reflectwalk v1.0.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.2.1 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/spf13/cast v1.3.1 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.0 // indirect
github.com/tklauser/go-sysconf v0.3.12 // indirect
...
...
go.sum
View file @
1ee3d1cc
This diff is collapsed.
Click to expand it.
relay/audio_handler.go
View file @
1ee3d1cc
...
...
@@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"net/http"
"one-api/common"
"one-api/dto"
relaycommon
"one-api/relay/common"
"one-api/relay/helper"
...
...
@@ -16,12 +17,17 @@ import (
func
AudioHelper
(
c
*
gin
.
Context
,
info
*
relaycommon
.
RelayInfo
)
(
newAPIError
*
types
.
NewAPIError
)
{
info
.
InitChannelMeta
(
c
)
audioReq
uest
,
ok
:=
info
.
Request
.
(
*
dto
.
AudioRequest
)
audioReq
,
ok
:=
info
.
Request
.
(
*
dto
.
AudioRequest
)
if
!
ok
{
return
types
.
NewError
(
errors
.
New
(
"invalid request type"
),
types
.
ErrorCodeInvalidRequest
,
types
.
ErrOptionWithSkipRetry
())
}
err
:=
helper
.
ModelMappedHelper
(
c
,
info
,
audioRequest
)
request
,
err
:=
common
.
DeepCopy
(
audioReq
)
if
err
!=
nil
{
return
types
.
NewError
(
fmt
.
Errorf
(
"failed to copy request to AudioRequest: %w"
,
err
),
types
.
ErrorCodeInvalidRequest
,
types
.
ErrOptionWithSkipRetry
())
}
err
=
helper
.
ModelMappedHelper
(
c
,
info
,
request
)
if
err
!=
nil
{
return
types
.
NewError
(
err
,
types
.
ErrorCodeChannelModelMappedError
,
types
.
ErrOptionWithSkipRetry
())
}
...
...
@@ -32,7 +38,7 @@ func AudioHelper(c *gin.Context, info *relaycommon.RelayInfo) (newAPIError *type
}
adaptor
.
Init
(
info
)
ioReader
,
err
:=
adaptor
.
ConvertAudioRequest
(
c
,
info
,
*
audioR
equest
)
ioReader
,
err
:=
adaptor
.
ConvertAudioRequest
(
c
,
info
,
*
r
equest
)
if
err
!=
nil
{
return
types
.
NewError
(
err
,
types
.
ErrorCodeConvertRequestFailed
,
types
.
ErrOptionWithSkipRetry
())
}
...
...
relay/claude_handler.go
View file @
1ee3d1cc
...
...
@@ -21,13 +21,18 @@ func ClaudeHelper(c *gin.Context, info *relaycommon.RelayInfo) (newAPIError *typ
info
.
InitChannelMeta
(
c
)
textRequest
,
ok
:=
info
.
Request
.
(
*
dto
.
ClaudeRequest
)
claudeReq
,
ok
:=
info
.
Request
.
(
*
dto
.
ClaudeRequest
)
if
!
ok
{
common
.
FatalLog
(
fmt
.
Sprintf
(
"invalid request type, expected *dto.ClaudeRequest, got %T"
,
info
.
Request
))
}
err
:=
helper
.
ModelMappedHelper
(
c
,
info
,
textRequest
)
request
,
err
:=
common
.
DeepCopy
(
claudeReq
)
if
err
!=
nil
{
return
types
.
NewError
(
fmt
.
Errorf
(
"failed to copy request to ClaudeRequest: %w"
,
err
),
types
.
ErrorCodeInvalidRequest
,
types
.
ErrOptionWithSkipRetry
())
}
err
=
helper
.
ModelMappedHelper
(
c
,
info
,
request
)
if
err
!=
nil
{
return
types
.
NewError
(
err
,
types
.
ErrorCodeChannelModelMappedError
,
types
.
ErrOptionWithSkipRetry
())
}
...
...
@@ -38,30 +43,30 @@ func ClaudeHelper(c *gin.Context, info *relaycommon.RelayInfo) (newAPIError *typ
}
adaptor
.
Init
(
info
)
if
textR
equest
.
MaxTokens
==
0
{
textRequest
.
MaxTokens
=
uint
(
model_setting
.
GetClaudeSettings
()
.
GetDefaultMaxTokens
(
textR
equest
.
Model
))
if
r
equest
.
MaxTokens
==
0
{
request
.
MaxTokens
=
uint
(
model_setting
.
GetClaudeSettings
()
.
GetDefaultMaxTokens
(
r
equest
.
Model
))
}
if
model_setting
.
GetClaudeSettings
()
.
ThinkingAdapterEnabled
&&
strings
.
HasSuffix
(
textR
equest
.
Model
,
"-thinking"
)
{
if
textR
equest
.
Thinking
==
nil
{
strings
.
HasSuffix
(
r
equest
.
Model
,
"-thinking"
)
{
if
r
equest
.
Thinking
==
nil
{
// 因为BudgetTokens 必须大于1024
if
textR
equest
.
MaxTokens
<
1280
{
textR
equest
.
MaxTokens
=
1280
if
r
equest
.
MaxTokens
<
1280
{
r
equest
.
MaxTokens
=
1280
}
// BudgetTokens 为 max_tokens 的 80%
textR
equest
.
Thinking
=
&
dto
.
Thinking
{
r
equest
.
Thinking
=
&
dto
.
Thinking
{
Type
:
"enabled"
,
BudgetTokens
:
common
.
GetPointer
[
int
](
int
(
float64
(
textR
equest
.
MaxTokens
)
*
model_setting
.
GetClaudeSettings
()
.
ThinkingAdapterBudgetTokensPercentage
)),
BudgetTokens
:
common
.
GetPointer
[
int
](
int
(
float64
(
r
equest
.
MaxTokens
)
*
model_setting
.
GetClaudeSettings
()
.
ThinkingAdapterBudgetTokensPercentage
)),
}
// TODO: 临时处理
// https://docs.anthropic.com/en/docs/build-with-claude/extended-thinking#important-considerations-when-using-extended-thinking
textR
equest
.
TopP
=
0
textR
equest
.
Temperature
=
common
.
GetPointer
[
float64
](
1.0
)
r
equest
.
TopP
=
0
r
equest
.
Temperature
=
common
.
GetPointer
[
float64
](
1.0
)
}
textRequest
.
Model
=
strings
.
TrimSuffix
(
textR
equest
.
Model
,
"-thinking"
)
info
.
UpstreamModelName
=
textR
equest
.
Model
request
.
Model
=
strings
.
TrimSuffix
(
r
equest
.
Model
,
"-thinking"
)
info
.
UpstreamModelName
=
r
equest
.
Model
}
var
requestBody
io
.
Reader
...
...
@@ -72,7 +77,7 @@ func ClaudeHelper(c *gin.Context, info *relaycommon.RelayInfo) (newAPIError *typ
}
requestBody
=
bytes
.
NewBuffer
(
body
)
}
else
{
convertedRequest
,
err
:=
adaptor
.
ConvertClaudeRequest
(
c
,
info
,
textR
equest
)
convertedRequest
,
err
:=
adaptor
.
ConvertClaudeRequest
(
c
,
info
,
r
equest
)
if
err
!=
nil
{
return
types
.
NewError
(
err
,
types
.
ErrorCodeConvertRequestFailed
,
types
.
ErrOptionWithSkipRetry
())
}
...
...
relay/common/relay_info.go
View file @
1ee3d1cc
...
...
@@ -158,7 +158,14 @@ func (info *RelayInfo) InitChannelMeta(c *gin.Context) {
if
streamSupportedChannels
[
channelMeta
.
ChannelType
]
{
channelMeta
.
SupportStreamOptions
=
true
}
info
.
ChannelMeta
=
channelMeta
// reset some fields based on channel meta
// 重置某些字段,例如模型名称等
if
info
.
Request
!=
nil
{
info
.
Request
.
SetModelName
(
info
.
OriginModelName
)
}
}
func
(
info
*
RelayInfo
)
ToString
()
string
{
...
...
relay/embedding_handler.go
View file @
1ee3d1cc
...
...
@@ -16,15 +16,19 @@ import (
)
func
EmbeddingHelper
(
c
*
gin
.
Context
,
info
*
relaycommon
.
RelayInfo
)
(
newAPIError
*
types
.
NewAPIError
)
{
info
.
InitChannelMeta
(
c
)
embeddingReq
uest
,
ok
:=
info
.
Request
.
(
*
dto
.
EmbeddingRequest
)
embeddingReq
,
ok
:=
info
.
Request
.
(
*
dto
.
EmbeddingRequest
)
if
!
ok
{
common
.
FatalLog
(
fmt
.
Sprintf
(
"invalid request type, expected *dto.EmbeddingRequest, got %T"
,
info
.
Request
))
}
err
:=
helper
.
ModelMappedHelper
(
c
,
info
,
embeddingRequest
)
request
,
err
:=
common
.
DeepCopy
(
embeddingReq
)
if
err
!=
nil
{
return
types
.
NewError
(
fmt
.
Errorf
(
"failed to copy request to EmbeddingRequest: %w"
,
err
),
types
.
ErrorCodeInvalidRequest
,
types
.
ErrOptionWithSkipRetry
())
}
err
=
helper
.
ModelMappedHelper
(
c
,
info
,
request
)
if
err
!=
nil
{
return
types
.
NewError
(
err
,
types
.
ErrorCodeChannelModelMappedError
,
types
.
ErrOptionWithSkipRetry
())
}
...
...
@@ -35,7 +39,7 @@ func EmbeddingHelper(c *gin.Context, info *relaycommon.RelayInfo) (newAPIError *
}
adaptor
.
Init
(
info
)
convertedRequest
,
err
:=
adaptor
.
ConvertEmbeddingRequest
(
c
,
info
,
*
embeddingR
equest
)
convertedRequest
,
err
:=
adaptor
.
ConvertEmbeddingRequest
(
c
,
info
,
*
r
equest
)
if
err
!=
nil
{
return
types
.
NewError
(
err
,
types
.
ErrorCodeConvertRequestFailed
,
types
.
ErrOptionWithSkipRetry
())
}
...
...
relay/gemini_handler.go
View file @
1ee3d1cc
...
...
@@ -53,13 +53,18 @@ func trimModelThinking(modelName string) string {
func
GeminiHelper
(
c
*
gin
.
Context
,
info
*
relaycommon
.
RelayInfo
)
(
newAPIError
*
types
.
NewAPIError
)
{
info
.
InitChannelMeta
(
c
)
request
,
ok
:=
info
.
Request
.
(
*
dto
.
GeminiChatRequest
)
geminiReq
,
ok
:=
info
.
Request
.
(
*
dto
.
GeminiChatRequest
)
if
!
ok
{
common
.
FatalLog
(
fmt
.
Sprintf
(
"invalid request type, expected *dto.GeminiChatRequest, got %T"
,
info
.
Request
))
}
request
,
err
:=
common
.
DeepCopy
(
geminiReq
)
if
err
!=
nil
{
return
types
.
NewError
(
fmt
.
Errorf
(
"failed to copy request to GeminiChatRequest: %w"
,
err
),
types
.
ErrorCodeInvalidRequest
,
types
.
ErrOptionWithSkipRetry
())
}
// model mapped 模型映射
err
:
=
helper
.
ModelMappedHelper
(
c
,
info
,
request
)
err
=
helper
.
ModelMappedHelper
(
c
,
info
,
request
)
if
err
!=
nil
{
return
types
.
NewError
(
err
,
types
.
ErrorCodeChannelModelMappedError
,
types
.
ErrOptionWithSkipRetry
())
}
...
...
@@ -170,7 +175,7 @@ func GeminiEmbeddingHandler(c *gin.Context, info *relaycommon.RelayInfo) (newAPI
isBatch
:=
strings
.
HasSuffix
(
c
.
Request
.
URL
.
Path
,
"batchEmbedContents"
)
info
.
IsGeminiBatchEmbedding
=
isBatch
var
req
any
var
req
dto
.
Request
var
err
error
var
inputTexts
[]
string
...
...
relay/helper/model_mapped.go
View file @
1ee3d1cc
...
...
@@ -4,15 +4,12 @@ import (
"encoding/json"
"errors"
"fmt"
"github.com/gin-gonic/gin"
"one-api/dto"
common2
"one-api/logger"
"one-api/relay/common"
"one-api/types"
"github.com/gin-gonic/gin"
)
func
ModelMappedHelper
(
c
*
gin
.
Context
,
info
*
common
.
RelayInfo
,
request
any
)
error
{
func
ModelMappedHelper
(
c
*
gin
.
Context
,
info
*
common
.
RelayInfo
,
request
dto
.
Request
)
error
{
// map model name
modelMapping
:=
c
.
GetString
(
"model_mapping"
)
if
modelMapping
!=
""
&&
modelMapping
!=
"{}"
{
...
...
@@ -54,40 +51,7 @@ func ModelMappedHelper(c *gin.Context, info *common.RelayInfo, request any) erro
}
}
if
request
!=
nil
{
switch
info
.
RelayFormat
{
case
types
.
RelayFormatGemini
:
// Gemini 模型映射
case
types
.
RelayFormatClaude
:
if
claudeRequest
,
ok
:=
request
.
(
*
dto
.
ClaudeRequest
);
ok
{
claudeRequest
.
Model
=
info
.
UpstreamModelName
}
case
types
.
RelayFormatOpenAIResponses
:
if
openAIResponsesRequest
,
ok
:=
request
.
(
*
dto
.
OpenAIResponsesRequest
);
ok
{
openAIResponsesRequest
.
Model
=
info
.
UpstreamModelName
}
case
types
.
RelayFormatOpenAIAudio
:
if
openAIAudioRequest
,
ok
:=
request
.
(
*
dto
.
AudioRequest
);
ok
{
openAIAudioRequest
.
Model
=
info
.
UpstreamModelName
}
case
types
.
RelayFormatOpenAIImage
:
if
imageRequest
,
ok
:=
request
.
(
*
dto
.
ImageRequest
);
ok
{
imageRequest
.
Model
=
info
.
UpstreamModelName
}
case
types
.
RelayFormatRerank
:
if
rerankRequest
,
ok
:=
request
.
(
*
dto
.
RerankRequest
);
ok
{
rerankRequest
.
Model
=
info
.
UpstreamModelName
}
case
types
.
RelayFormatEmbedding
:
if
embeddingRequest
,
ok
:=
request
.
(
*
dto
.
EmbeddingRequest
);
ok
{
embeddingRequest
.
Model
=
info
.
UpstreamModelName
}
default
:
if
openAIRequest
,
ok
:=
request
.
(
*
dto
.
GeneralOpenAIRequest
);
ok
{
openAIRequest
.
Model
=
info
.
UpstreamModelName
}
else
{
common2
.
LogWarn
(
c
,
fmt
.
Sprintf
(
"model mapped but request type %T not supported"
,
request
))
}
}
request
.
SetModelName
(
info
.
UpstreamModelName
)
}
return
nil
}
relay/image_handler.go
View file @
1ee3d1cc
...
...
@@ -20,16 +20,19 @@ import (
)
func
ImageHelper
(
c
*
gin
.
Context
,
info
*
relaycommon
.
RelayInfo
)
(
newAPIError
*
types
.
NewAPIError
)
{
info
.
InitChannelMeta
(
c
)
imageRequest
,
ok
:=
info
.
Request
.
(
*
dto
.
ImageRequest
)
imageReq
,
ok
:=
info
.
Request
.
(
*
dto
.
ImageRequest
)
if
!
ok
{
common
.
FatalLog
(
fmt
.
Sprintf
(
"invalid request type, expected dto.ImageRequest, got %T"
,
info
.
Request
))
}
err
:=
helper
.
ModelMappedHelper
(
c
,
info
,
imageRequest
)
request
,
err
:=
common
.
DeepCopy
(
imageReq
)
if
err
!=
nil
{
return
types
.
NewError
(
fmt
.
Errorf
(
"failed to copy request to ImageRequest: %w"
,
err
),
types
.
ErrorCodeInvalidRequest
,
types
.
ErrOptionWithSkipRetry
())
}
err
=
helper
.
ModelMappedHelper
(
c
,
info
,
request
)
if
err
!=
nil
{
return
types
.
NewError
(
err
,
types
.
ErrorCodeChannelModelMappedError
,
types
.
ErrOptionWithSkipRetry
())
}
...
...
@@ -49,7 +52,7 @@ func ImageHelper(c *gin.Context, info *relaycommon.RelayInfo) (newAPIError *type
}
requestBody
=
bytes
.
NewBuffer
(
body
)
}
else
{
convertedRequest
,
err
:=
adaptor
.
ConvertImageRequest
(
c
,
info
,
*
imageR
equest
)
convertedRequest
,
err
:=
adaptor
.
ConvertImageRequest
(
c
,
info
,
*
r
equest
)
if
err
!=
nil
{
return
types
.
NewError
(
err
,
types
.
ErrorCodeConvertRequestFailed
)
}
...
...
@@ -102,21 +105,21 @@ func ImageHelper(c *gin.Context, info *relaycommon.RelayInfo) (newAPIError *type
}
if
usage
.
(
*
dto
.
Usage
)
.
TotalTokens
==
0
{
usage
.
(
*
dto
.
Usage
)
.
TotalTokens
=
int
(
imageR
equest
.
N
)
usage
.
(
*
dto
.
Usage
)
.
TotalTokens
=
int
(
r
equest
.
N
)
}
if
usage
.
(
*
dto
.
Usage
)
.
PromptTokens
==
0
{
usage
.
(
*
dto
.
Usage
)
.
PromptTokens
=
int
(
imageR
equest
.
N
)
usage
.
(
*
dto
.
Usage
)
.
PromptTokens
=
int
(
r
equest
.
N
)
}
quality
:=
"standard"
if
imageR
equest
.
Quality
==
"hd"
{
if
r
equest
.
Quality
==
"hd"
{
quality
=
"hd"
}
var
logContent
string
if
len
(
imageR
equest
.
Size
)
>
0
{
logContent
=
fmt
.
Sprintf
(
"大小 %s, 品质 %s"
,
imageR
equest
.
Size
,
quality
)
if
len
(
r
equest
.
Size
)
>
0
{
logContent
=
fmt
.
Sprintf
(
"大小 %s, 品质 %s"
,
r
equest
.
Size
,
quality
)
}
postConsumeQuota
(
c
,
info
,
usage
.
(
*
dto
.
Usage
),
logContent
)
...
...
relay/relay-text.go
View file @
1ee3d1cc
...
...
@@ -25,38 +25,41 @@ import (
)
func
TextHelper
(
c
*
gin
.
Context
,
info
*
relaycommon
.
RelayInfo
)
(
newAPIError
*
types
.
NewAPIError
)
{
info
.
InitChannelMeta
(
c
)
textRequest
,
ok
:=
info
.
Request
.
(
*
dto
.
GeneralOpenAIRequest
)
textReq
,
ok
:=
info
.
Request
.
(
*
dto
.
GeneralOpenAIRequest
)
if
!
ok
{
//return types.NewErrorWithStatusCode(errors.New("invalid request type"), types.ErrorCodeInvalidRequest, http.StatusBadRequest, types.ErrOptionWithSkipRetry())
common
.
FatalLog
(
"invalid request type, expected dto.GeneralOpenAIRequest, got %T"
,
info
.
Request
)
}
if
textRequest
.
WebSearchOptions
!=
nil
{
c
.
Set
(
"chat_completion_web_search_context_size"
,
textRequest
.
WebSearchOptions
.
SearchContextSize
)
request
,
err
:=
common
.
DeepCopy
(
textReq
)
if
err
!=
nil
{
return
types
.
NewError
(
fmt
.
Errorf
(
"failed to copy request to GeneralOpenAIRequest: %w"
,
err
),
types
.
ErrorCodeInvalidRequest
,
types
.
ErrOptionWithSkipRetry
())
}
if
request
.
WebSearchOptions
!=
nil
{
c
.
Set
(
"chat_completion_web_search_context_size"
,
request
.
WebSearchOptions
.
SearchContextSize
)
}
err
:=
helper
.
ModelMappedHelper
(
c
,
info
,
textR
equest
)
err
=
helper
.
ModelMappedHelper
(
c
,
info
,
r
equest
)
if
err
!=
nil
{
return
types
.
NewError
(
err
,
types
.
ErrorCodeChannelModelMappedError
,
types
.
ErrOptionWithSkipRetry
())
}
includeUsage
:=
true
// 判断用户是否需要返回使用情况
if
textR
equest
.
StreamOptions
!=
nil
{
includeUsage
=
textR
equest
.
StreamOptions
.
IncludeUsage
if
r
equest
.
StreamOptions
!=
nil
{
includeUsage
=
r
equest
.
StreamOptions
.
IncludeUsage
}
// 如果不支持StreamOptions,将StreamOptions设置为nil
if
!
info
.
SupportStreamOptions
||
!
textR
equest
.
Stream
{
textR
equest
.
StreamOptions
=
nil
if
!
info
.
SupportStreamOptions
||
!
r
equest
.
Stream
{
r
equest
.
StreamOptions
=
nil
}
else
{
// 如果支持StreamOptions,且请求中没有设置StreamOptions,根据配置文件设置StreamOptions
if
constant
.
ForceStreamOption
{
textR
equest
.
StreamOptions
=
&
dto
.
StreamOptions
{
r
equest
.
StreamOptions
=
&
dto
.
StreamOptions
{
IncludeUsage
:
true
,
}
}
...
...
@@ -81,7 +84,7 @@ func TextHelper(c *gin.Context, info *relaycommon.RelayInfo) (newAPIError *types
}
requestBody
=
bytes
.
NewBuffer
(
body
)
}
else
{
convertedRequest
,
err
:=
adaptor
.
ConvertOpenAIRequest
(
c
,
info
,
textR
equest
)
convertedRequest
,
err
:=
adaptor
.
ConvertOpenAIRequest
(
c
,
info
,
r
equest
)
if
err
!=
nil
{
return
types
.
NewError
(
err
,
types
.
ErrorCodeConvertRequestFailed
,
types
.
ErrOptionWithSkipRetry
())
}
...
...
relay/rerank_handler.go
View file @
1ee3d1cc
...
...
@@ -16,23 +16,20 @@ import (
"github.com/gin-gonic/gin"
)
func
getRerankPromptToken
(
rerankRequest
dto
.
RerankRequest
)
int
{
token
:=
service
.
CountTokenInput
(
rerankRequest
.
Query
,
rerankRequest
.
Model
)
for
_
,
document
:=
range
rerankRequest
.
Documents
{
tkm
:=
service
.
CountTokenInput
(
document
,
rerankRequest
.
Model
)
token
+=
tkm
}
return
token
}
func
RerankHelper
(
c
*
gin
.
Context
,
info
*
relaycommon
.
RelayInfo
)
(
newAPIError
*
types
.
NewAPIError
)
{
info
.
InitChannelMeta
(
c
)
rerankReq
uest
,
ok
:=
info
.
Request
.
(
*
dto
.
RerankRequest
)
rerankReq
,
ok
:=
info
.
Request
.
(
*
dto
.
RerankRequest
)
if
!
ok
{
common
.
FatalLog
(
fmt
.
Sprintf
(
"invalid request type, expected dto.RerankRequest, got %T"
,
info
.
Request
))
}
err
:=
helper
.
ModelMappedHelper
(
c
,
info
,
rerankRequest
)
request
,
err
:=
common
.
DeepCopy
(
rerankReq
)
if
err
!=
nil
{
return
types
.
NewError
(
fmt
.
Errorf
(
"failed to copy request to ImageRequest: %w"
,
err
),
types
.
ErrorCodeInvalidRequest
,
types
.
ErrOptionWithSkipRetry
())
}
err
=
helper
.
ModelMappedHelper
(
c
,
info
,
request
)
if
err
!=
nil
{
return
types
.
NewError
(
err
,
types
.
ErrorCodeChannelModelMappedError
,
types
.
ErrOptionWithSkipRetry
())
}
...
...
@@ -51,7 +48,7 @@ func RerankHelper(c *gin.Context, info *relaycommon.RelayInfo) (newAPIError *typ
}
requestBody
=
bytes
.
NewBuffer
(
body
)
}
else
{
convertedRequest
,
err
:=
adaptor
.
ConvertRerankRequest
(
c
,
info
.
RelayMode
,
*
re
rankRe
quest
)
convertedRequest
,
err
:=
adaptor
.
ConvertRerankRequest
(
c
,
info
.
RelayMode
,
*
request
)
if
err
!=
nil
{
return
types
.
NewError
(
err
,
types
.
ErrorCodeConvertRequestFailed
,
types
.
ErrOptionWithSkipRetry
())
}
...
...
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