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
2d305d5b
authored
Jun 22, 2025
by
t0ng7u
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'origin/alpha' into alpha
parents
1ad9c97d
d084083e
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
69 additions
and
7 deletions
+69
-7
dto/openai_request.go
+1
-0
dto/openai_response.go
+3
-1
relay/channel/claude/relay-claude.go
+16
-0
relay/channel/openai/adaptor.go
+5
-0
relay/channel/task/kling/adaptor.go
+3
-3
service/convert.go
+6
-3
service/quota.go
+33
-0
web/src/pages/Channel/EditChannel.js
+2
-0
No files found.
dto/openai_request.go
View file @
2d305d5b
...
...
@@ -57,6 +57,7 @@ type GeneralOpenAIRequest struct {
ExtraBody
json
.
RawMessage
`json:"extra_body,omitempty"`
WebSearchOptions
*
WebSearchOptions
`json:"web_search_options,omitempty"`
// OpenRouter Params
Usage
json
.
RawMessage
`json:"usage,omitempty"`
Reasoning
json
.
RawMessage
`json:"reasoning,omitempty"`
// Ali Qwen Params
VlHighResolutionImages
json
.
RawMessage
`json:"vl_high_resolution_images,omitempty"`
...
...
dto/openai_response.go
View file @
2d305d5b
...
...
@@ -26,7 +26,7 @@ type OpenAITextResponse struct {
Id
string
`json:"id"`
Model
string
`json:"model"`
Object
string
`json:"object"`
Created
int64
`json:"created"`
Created
any
`json:"created"`
Choices
[]
OpenAITextResponseChoice
`json:"choices"`
Error
*
OpenAIError
`json:"error,omitempty"`
Usage
`json:"usage"`
...
...
@@ -178,6 +178,8 @@ type Usage struct {
InputTokens
int
`json:"input_tokens"`
OutputTokens
int
`json:"output_tokens"`
InputTokensDetails
*
InputTokenDetails
`json:"input_tokens_details"`
// OpenRouter Params
Cost
float64
`json:"cost,omitempty"`
}
type
InputTokenDetails
struct
{
...
...
relay/channel/claude/relay-claude.go
View file @
2d305d5b
...
...
@@ -7,6 +7,7 @@ import (
"net/http"
"one-api/common"
"one-api/dto"
"one-api/relay/channel/openrouter"
relaycommon
"one-api/relay/common"
"one-api/relay/helper"
"one-api/service"
...
...
@@ -122,6 +123,21 @@ func RequestOpenAI2ClaudeMessage(textRequest dto.GeneralOpenAIRequest) (*dto.Cla
claudeRequest
.
Model
=
strings
.
TrimSuffix
(
textRequest
.
Model
,
"-thinking"
)
}
if
textRequest
.
Reasoning
!=
nil
{
var
reasoning
openrouter
.
RequestReasoning
if
err
:=
common
.
DecodeJson
(
textRequest
.
Reasoning
,
&
reasoning
);
err
!=
nil
{
return
nil
,
err
}
budgetTokens
:=
reasoning
.
MaxTokens
if
budgetTokens
>
0
{
claudeRequest
.
Thinking
=
&
dto
.
Thinking
{
Type
:
"enabled"
,
BudgetTokens
:
&
budgetTokens
,
}
}
}
if
textRequest
.
Stop
!=
nil
{
// stop maybe string/array string, convert to array string
switch
textRequest
.
Stop
.
(
type
)
{
...
...
relay/channel/openai/adaptor.go
View file @
2d305d5b
...
...
@@ -159,6 +159,11 @@ func (a *Adaptor) ConvertOpenAIRequest(c *gin.Context, info *relaycommon.RelayIn
if
info
.
ChannelType
!=
common
.
ChannelTypeOpenAI
&&
info
.
ChannelType
!=
common
.
ChannelTypeAzure
{
request
.
StreamOptions
=
nil
}
if
info
.
ChannelType
==
common
.
ChannelTypeOpenRouter
{
if
len
(
request
.
Usage
)
==
0
{
request
.
Usage
=
json
.
RawMessage
(
`{"include":true}`
)
}
}
if
strings
.
HasPrefix
(
request
.
Model
,
"o"
)
{
if
request
.
MaxCompletionTokens
==
0
&&
request
.
MaxTokens
!=
0
{
request
.
MaxCompletionTokens
=
request
.
MaxTokens
...
...
relay/channel/task/kling/adaptor.go
View file @
2d305d5b
...
...
@@ -69,8 +69,8 @@ func (a *TaskAdaptor) Init(info *relaycommon.TaskRelayInfo) {
a
.
ChannelType
=
info
.
ChannelType
a
.
baseURL
=
info
.
BaseUrl
// apiKey format: "access_key
,
secret_key"
keyParts
:=
strings
.
Split
(
info
.
ApiKey
,
"
,
"
)
// apiKey format: "access_key
|
secret_key"
keyParts
:=
strings
.
Split
(
info
.
ApiKey
,
"
|
"
)
if
len
(
keyParts
)
==
2
{
a
.
accessKey
=
strings
.
TrimSpace
(
keyParts
[
0
])
a
.
secretKey
=
strings
.
TrimSpace
(
keyParts
[
1
])
...
...
@@ -264,7 +264,7 @@ func (a *TaskAdaptor) createJWTToken() (string, error) {
}
func
(
a
*
TaskAdaptor
)
createJWTTokenWithKey
(
apiKey
string
)
(
string
,
error
)
{
parts
:=
strings
.
Split
(
apiKey
,
"
,
"
)
parts
:=
strings
.
Split
(
apiKey
,
"
|
"
)
if
len
(
parts
)
!=
2
{
return
""
,
fmt
.
Errorf
(
"invalid API key format, expected 'access_key,secret_key'"
)
}
...
...
service/convert.go
View file @
2d305d5b
...
...
@@ -276,12 +276,15 @@ func StreamResponseOpenAI2Claude(openAIResponse *dto.ChatCompletionsStreamRespon
}
if
info
.
Done
{
claudeResponses
=
append
(
claudeResponses
,
generateStopBlock
(
info
.
ClaudeConvertInfo
.
Index
))
if
info
.
ClaudeConvertInfo
.
Usage
!=
nil
{
oaiUsage
:=
info
.
ClaudeConvertInfo
.
Usage
if
oaiUsage
!=
nil
{
claudeResponses
=
append
(
claudeResponses
,
&
dto
.
ClaudeResponse
{
Type
:
"message_delta"
,
Usage
:
&
dto
.
ClaudeUsage
{
InputTokens
:
info
.
ClaudeConvertInfo
.
Usage
.
PromptTokens
,
OutputTokens
:
info
.
ClaudeConvertInfo
.
Usage
.
CompletionTokens
,
InputTokens
:
oaiUsage
.
PromptTokens
,
OutputTokens
:
oaiUsage
.
CompletionTokens
,
CacheCreationInputTokens
:
oaiUsage
.
PromptTokensDetails
.
CachedCreationTokens
,
CacheReadInputTokens
:
oaiUsage
.
PromptTokensDetails
.
CachedTokens
,
},
Delta
:
&
dto
.
ClaudeMediaMessage
{
StopReason
:
common
.
GetPointer
[
string
](
stopReasonOpenAI2Claude
(
info
.
FinishReason
)),
...
...
service/quota.go
View file @
2d305d5b
...
...
@@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"log"
"math"
"one-api/common"
constant2
"one-api/constant"
"one-api/dto"
...
...
@@ -231,6 +232,17 @@ func PostClaudeConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo,
cacheCreationRatio
:=
priceData
.
CacheCreationRatio
cacheCreationTokens
:=
usage
.
PromptTokensDetails
.
CachedCreationTokens
if
relayInfo
.
ChannelType
==
common
.
ChannelTypeOpenRouter
{
promptTokens
-=
cacheTokens
if
cacheCreationTokens
==
0
&&
priceData
.
CacheCreationRatio
!=
1
&&
usage
.
Cost
!=
0
{
maybeCacheCreationTokens
:=
CalcOpenRouterCacheCreateTokens
(
*
usage
,
priceData
)
if
promptTokens
>=
maybeCacheCreationTokens
{
cacheCreationTokens
=
maybeCacheCreationTokens
}
}
promptTokens
-=
cacheCreationTokens
}
calculateQuota
:=
0.0
if
!
priceData
.
UsePrice
{
calculateQuota
=
float64
(
promptTokens
)
...
...
@@ -278,6 +290,27 @@ func PostClaudeConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo,
tokenName
,
quota
,
logContent
,
relayInfo
.
TokenId
,
userQuota
,
int
(
useTimeSeconds
),
relayInfo
.
IsStream
,
relayInfo
.
Group
,
other
)
}
func
CalcOpenRouterCacheCreateTokens
(
usage
dto
.
Usage
,
priceData
helper
.
PriceData
)
int
{
if
priceData
.
CacheCreationRatio
==
1
{
return
0
}
quotaPrice
:=
priceData
.
ModelRatio
/
common
.
QuotaPerUnit
promptCacheCreatePrice
:=
quotaPrice
*
priceData
.
CacheCreationRatio
promptCacheReadPrice
:=
quotaPrice
*
priceData
.
CacheRatio
completionPrice
:=
quotaPrice
*
priceData
.
CompletionRatio
cost
:=
usage
.
Cost
totalPromptTokens
:=
float64
(
usage
.
PromptTokens
)
completionTokens
:=
float64
(
usage
.
CompletionTokens
)
promptCacheReadTokens
:=
float64
(
usage
.
PromptTokensDetails
.
CachedTokens
)
return
int
(
math
.
Round
((
cost
-
totalPromptTokens
*
quotaPrice
+
promptCacheReadTokens
*
(
quotaPrice
-
promptCacheReadPrice
)
-
completionTokens
*
completionPrice
)
/
(
promptCacheCreatePrice
-
quotaPrice
)))
}
func
PostAudioConsumeQuota
(
ctx
*
gin
.
Context
,
relayInfo
*
relaycommon
.
RelayInfo
,
usage
*
dto
.
Usage
,
preConsumedQuota
int
,
userQuota
int
,
priceData
helper
.
PriceData
,
extraContent
string
)
{
...
...
web/src/pages/Channel/EditChannel.js
View file @
2d305d5b
...
...
@@ -64,6 +64,8 @@ function type2secretPrompt(type) {
return
'按照如下格式输入:AppId|SecretId|SecretKey'
;
case
33
:
return
'按照如下格式输入:Ak|Sk|Region'
;
case
50
:
return
'按照如下格式输入: AccessKey|SecretKey'
;
default
:
return
'请输入渠道对应的鉴权密钥'
;
}
...
...
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