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
1a8d7817
authored
Sep 13, 2025
by
CaIon
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Revert "feat: gemini-2.5-flash-image-preview 文本和图片输出计费"
This reverts commit
a45513a7
.
parent
59d6ff0c
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
20 additions
and
111 deletions
+20
-111
dto/gemini.go
+7
-9
relay/channel/gemini/relay-gemini-native.go
+0
-36
relay/compatible_handler.go
+0
-15
service/token_counter.go
+1
-1
setting/model_setting/gemini.go
+0
-1
setting/operation_setting/tools.go
+0
-11
setting/ratio_setting/model_ratio.go
+4
-6
web/src/helpers/render.jsx
+8
-30
web/src/hooks/usage-logs/useUsageLogsData.jsx
+0
-2
No files found.
dto/gemini.go
View file @
1a8d7817
...
@@ -2,12 +2,11 @@ package dto
...
@@ -2,12 +2,11 @@ package dto
import
(
import
(
"encoding/json"
"encoding/json"
"github.com/gin-gonic/gin"
"one-api/common"
"one-api/common"
"one-api/logger"
"one-api/logger"
"one-api/types"
"one-api/types"
"strings"
"strings"
"github.com/gin-gonic/gin"
)
)
type
GeminiChatRequest
struct
{
type
GeminiChatRequest
struct
{
...
@@ -269,15 +268,14 @@ type GeminiChatResponse struct {
...
@@ -269,15 +268,14 @@ type GeminiChatResponse struct {
}
}
type
GeminiUsageMetadata
struct
{
type
GeminiUsageMetadata
struct
{
PromptTokenCount
int
`json:"promptTokenCount"`
PromptTokenCount
int
`json:"promptTokenCount"`
CandidatesTokenCount
int
`json:"candidatesTokenCount"`
CandidatesTokenCount
int
`json:"candidatesTokenCount"`
TotalTokenCount
int
`json:"totalTokenCount"`
TotalTokenCount
int
`json:"totalTokenCount"`
ThoughtsTokenCount
int
`json:"thoughtsTokenCount"`
ThoughtsTokenCount
int
`json:"thoughtsTokenCount"`
PromptTokensDetails
[]
GeminiModalityTokenCount
`json:"promptTokensDetails"`
PromptTokensDetails
[]
GeminiPromptTokensDetails
`json:"promptTokensDetails"`
CandidatesTokensDetails
[]
GeminiModalityTokenCount
`json:"candidatesTokensDetails"`
}
}
type
Gemini
ModalityTokenCount
struct
{
type
Gemini
PromptTokensDetails
struct
{
Modality
string
`json:"modality"`
Modality
string
`json:"modality"`
TokenCount
int
`json:"tokenCount"`
TokenCount
int
`json:"tokenCount"`
}
}
...
...
relay/channel/gemini/relay-gemini-native.go
View file @
1a8d7817
...
@@ -46,32 +46,6 @@ func GeminiTextGenerationHandler(c *gin.Context, info *relaycommon.RelayInfo, re
...
@@ -46,32 +46,6 @@ func GeminiTextGenerationHandler(c *gin.Context, info *relaycommon.RelayInfo, re
usage
.
CompletionTokenDetails
.
ReasoningTokens
=
geminiResponse
.
UsageMetadata
.
ThoughtsTokenCount
usage
.
CompletionTokenDetails
.
ReasoningTokens
=
geminiResponse
.
UsageMetadata
.
ThoughtsTokenCount
if
strings
.
HasPrefix
(
info
.
UpstreamModelName
,
"gemini-2.5-flash-image-preview"
)
{
imageOutputCounts
:=
0
for
_
,
candidate
:=
range
geminiResponse
.
Candidates
{
for
_
,
part
:=
range
candidate
.
Content
.
Parts
{
if
part
.
InlineData
!=
nil
&&
strings
.
HasPrefix
(
part
.
InlineData
.
MimeType
,
"image/"
)
{
imageOutputCounts
++
}
}
}
if
imageOutputCounts
!=
0
{
usage
.
CompletionTokens
=
usage
.
CompletionTokens
-
imageOutputCounts
*
1290
usage
.
TotalTokens
=
usage
.
TotalTokens
-
imageOutputCounts
*
1290
c
.
Set
(
"gemini_image_tokens"
,
imageOutputCounts
*
1290
)
}
}
// if strings.HasPrefix(info.UpstreamModelName, "gemini-2.5-flash-image-preview") {
// for _, detail := range geminiResponse.UsageMetadata.CandidatesTokensDetails {
// if detail.Modality == "IMAGE" {
// usage.CompletionTokens = usage.CompletionTokens - detail.TokenCount
// usage.TotalTokens = usage.TotalTokens - detail.TokenCount
// c.Set("gemini_image_tokens", detail.TokenCount)
// }
// }
// }
for
_
,
detail
:=
range
geminiResponse
.
UsageMetadata
.
PromptTokensDetails
{
for
_
,
detail
:=
range
geminiResponse
.
UsageMetadata
.
PromptTokensDetails
{
if
detail
.
Modality
==
"AUDIO"
{
if
detail
.
Modality
==
"AUDIO"
{
usage
.
PromptTokensDetails
.
AudioTokens
=
detail
.
TokenCount
usage
.
PromptTokensDetails
.
AudioTokens
=
detail
.
TokenCount
...
@@ -162,16 +136,6 @@ func GeminiTextGenerationStreamHandler(c *gin.Context, info *relaycommon.RelayIn
...
@@ -162,16 +136,6 @@ func GeminiTextGenerationStreamHandler(c *gin.Context, info *relaycommon.RelayIn
usage
.
PromptTokensDetails
.
TextTokens
=
detail
.
TokenCount
usage
.
PromptTokensDetails
.
TextTokens
=
detail
.
TokenCount
}
}
}
}
if
strings
.
HasPrefix
(
info
.
UpstreamModelName
,
"gemini-2.5-flash-image-preview"
)
{
for
_
,
detail
:=
range
geminiResponse
.
UsageMetadata
.
CandidatesTokensDetails
{
if
detail
.
Modality
==
"IMAGE"
{
usage
.
CompletionTokens
=
usage
.
CompletionTokens
-
detail
.
TokenCount
usage
.
TotalTokens
=
usage
.
TotalTokens
-
detail
.
TokenCount
c
.
Set
(
"gemini_image_tokens"
,
detail
.
TokenCount
)
}
}
}
}
}
// 直接发送 GeminiChatResponse 响应
// 直接发送 GeminiChatResponse 响应
...
...
relay/compatible_handler.go
View file @
1a8d7817
...
@@ -326,22 +326,11 @@ func postConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo, usage
...
@@ -326,22 +326,11 @@ func postConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo, usage
}
else
{
}
else
{
quotaCalculateDecimal
=
dModelPrice
.
Mul
(
dQuotaPerUnit
)
.
Mul
(
dGroupRatio
)
quotaCalculateDecimal
=
dModelPrice
.
Mul
(
dQuotaPerUnit
)
.
Mul
(
dGroupRatio
)
}
}
var
dGeminiImageOutputQuota
decimal
.
Decimal
var
imageOutputPrice
float64
if
strings
.
HasPrefix
(
modelName
,
"gemini-2.5-flash-image-preview"
)
{
imageOutputPrice
=
operation_setting
.
GetGeminiImageOutputPricePerMillionTokens
(
modelName
)
if
imageOutputPrice
>
0
{
dImageOutputTokens
:=
decimal
.
NewFromInt
(
int64
(
ctx
.
GetInt
(
"gemini_image_tokens"
)))
dGeminiImageOutputQuota
=
decimal
.
NewFromFloat
(
imageOutputPrice
)
.
Div
(
decimal
.
NewFromInt
(
1000000
))
.
Mul
(
dImageOutputTokens
)
.
Mul
(
dGroupRatio
)
.
Mul
(
dQuotaPerUnit
)
}
}
// 添加 responses tools call 调用的配额
// 添加 responses tools call 调用的配额
quotaCalculateDecimal
=
quotaCalculateDecimal
.
Add
(
dWebSearchQuota
)
quotaCalculateDecimal
=
quotaCalculateDecimal
.
Add
(
dWebSearchQuota
)
quotaCalculateDecimal
=
quotaCalculateDecimal
.
Add
(
dFileSearchQuota
)
quotaCalculateDecimal
=
quotaCalculateDecimal
.
Add
(
dFileSearchQuota
)
// 添加 audio input 独立计费
// 添加 audio input 独立计费
quotaCalculateDecimal
=
quotaCalculateDecimal
.
Add
(
audioInputQuota
)
quotaCalculateDecimal
=
quotaCalculateDecimal
.
Add
(
audioInputQuota
)
// 添加 Gemini image output 计费
quotaCalculateDecimal
=
quotaCalculateDecimal
.
Add
(
dGeminiImageOutputQuota
)
quota
:=
int
(
quotaCalculateDecimal
.
Round
(
0
)
.
IntPart
())
quota
:=
int
(
quotaCalculateDecimal
.
Round
(
0
)
.
IntPart
())
totalTokens
:=
promptTokens
+
completionTokens
totalTokens
:=
promptTokens
+
completionTokens
...
@@ -440,10 +429,6 @@ func postConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo, usage
...
@@ -440,10 +429,6 @@ func postConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo, usage
other
[
"audio_input_token_count"
]
=
audioTokens
other
[
"audio_input_token_count"
]
=
audioTokens
other
[
"audio_input_price"
]
=
audioInputPrice
other
[
"audio_input_price"
]
=
audioInputPrice
}
}
if
!
dGeminiImageOutputQuota
.
IsZero
()
{
other
[
"image_output_token_count"
]
=
ctx
.
GetInt
(
"gemini_image_tokens"
)
other
[
"image_output_price"
]
=
imageOutputPrice
}
model
.
RecordConsumeLog
(
ctx
,
relayInfo
.
UserId
,
model
.
RecordConsumeLogParams
{
model
.
RecordConsumeLog
(
ctx
,
relayInfo
.
UserId
,
model
.
RecordConsumeLogParams
{
ChannelId
:
relayInfo
.
ChannelId
,
ChannelId
:
relayInfo
.
ChannelId
,
PromptTokens
:
promptTokens
,
PromptTokens
:
promptTokens
,
...
...
service/token_counter.go
View file @
1a8d7817
...
@@ -336,7 +336,7 @@ func CountRequestToken(c *gin.Context, meta *types.TokenCountMeta, info *relayco
...
@@ -336,7 +336,7 @@ func CountRequestToken(c *gin.Context, meta *types.TokenCountMeta, info *relayco
for
i
,
file
:=
range
meta
.
Files
{
for
i
,
file
:=
range
meta
.
Files
{
switch
file
.
FileType
{
switch
file
.
FileType
{
case
types
.
FileTypeImage
:
case
types
.
FileTypeImage
:
if
info
.
RelayFormat
==
types
.
RelayFormatGemini
&&
!
strings
.
HasPrefix
(
model
,
"gemini-2.5-flash-image-preview"
)
{
if
info
.
RelayFormat
==
types
.
RelayFormatGemini
{
tkm
+=
256
tkm
+=
256
}
else
{
}
else
{
token
,
err
:=
getImageToken
(
file
,
model
,
info
.
IsStream
)
token
,
err
:=
getImageToken
(
file
,
model
,
info
.
IsStream
)
...
...
setting/model_setting/gemini.go
View file @
1a8d7817
...
@@ -26,7 +26,6 @@ var defaultGeminiSettings = GeminiSettings{
...
@@ -26,7 +26,6 @@ var defaultGeminiSettings = GeminiSettings{
SupportedImagineModels
:
[]
string
{
SupportedImagineModels
:
[]
string
{
"gemini-2.0-flash-exp-image-generation"
,
"gemini-2.0-flash-exp-image-generation"
,
"gemini-2.0-flash-exp"
,
"gemini-2.0-flash-exp"
,
"gemini-2.5-flash-image-preview"
,
},
},
ThinkingAdapterEnabled
:
false
,
ThinkingAdapterEnabled
:
false
,
ThinkingAdapterBudgetTokensPercentage
:
0.6
,
ThinkingAdapterBudgetTokensPercentage
:
0.6
,
...
...
setting/operation_setting/tools.go
View file @
1a8d7817
...
@@ -24,10 +24,6 @@ const (
...
@@ -24,10 +24,6 @@ const (
ClaudeWebSearchPrice
=
10.00
ClaudeWebSearchPrice
=
10.00
)
)
const
(
Gemini25FlashImagePreviewImageOutputPrice
=
30.00
)
func
GetClaudeWebSearchPricePerThousand
()
float64
{
func
GetClaudeWebSearchPricePerThousand
()
float64
{
return
ClaudeWebSearchPrice
return
ClaudeWebSearchPrice
}
}
...
@@ -69,10 +65,3 @@ func GetGeminiInputAudioPricePerMillionTokens(modelName string) float64 {
...
@@ -69,10 +65,3 @@ func GetGeminiInputAudioPricePerMillionTokens(modelName string) float64 {
}
}
return
0
return
0
}
}
func
GetGeminiImageOutputPricePerMillionTokens
(
modelName
string
)
float64
{
if
strings
.
HasPrefix
(
modelName
,
"gemini-2.5-flash-image-preview"
)
{
return
Gemini25FlashImagePreviewImageOutputPrice
}
return
0
}
setting/ratio_setting/model_ratio.go
View file @
1a8d7817
...
@@ -178,7 +178,6 @@ var defaultModelRatio = map[string]float64{
...
@@ -178,7 +178,6 @@ var defaultModelRatio = map[string]float64{
"gemini-2.5-flash-lite-preview-thinking-*"
:
0.05
,
"gemini-2.5-flash-lite-preview-thinking-*"
:
0.05
,
"gemini-2.5-flash-lite-preview-06-17"
:
0.05
,
"gemini-2.5-flash-lite-preview-06-17"
:
0.05
,
"gemini-2.5-flash"
:
0.15
,
"gemini-2.5-flash"
:
0.15
,
"gemini-2.5-flash-image-preview"
:
0.15
,
// $0.30(text/image) / 1M tokens
"text-embedding-004"
:
0.001
,
"text-embedding-004"
:
0.001
,
"chatglm_turbo"
:
0.3572
,
// ¥0.005 / 1k tokens
"chatglm_turbo"
:
0.3572
,
// ¥0.005 / 1k tokens
"chatglm_pro"
:
0.7143
,
// ¥0.01 / 1k tokens
"chatglm_pro"
:
0.7143
,
// ¥0.01 / 1k tokens
...
@@ -294,11 +293,10 @@ var (
...
@@ -294,11 +293,10 @@ var (
)
)
var
defaultCompletionRatio
=
map
[
string
]
float64
{
var
defaultCompletionRatio
=
map
[
string
]
float64
{
"gpt-4-gizmo-*"
:
2
,
"gpt-4-gizmo-*"
:
2
,
"gpt-4o-gizmo-*"
:
3
,
"gpt-4o-gizmo-*"
:
3
,
"gpt-4-all"
:
2
,
"gpt-4-all"
:
2
,
"gpt-image-1"
:
8
,
"gpt-image-1"
:
8
,
"gemini-2.5-flash-image-preview"
:
8.3333333333
,
}
}
// InitRatioSettings initializes all model related settings maps
// InitRatioSettings initializes all model related settings maps
...
...
web/src/helpers/render.jsx
View file @
1a8d7817
...
@@ -1017,7 +1017,7 @@ export function renderModelPrice(
...
@@ -1017,7 +1017,7 @@ export function renderModelPrice(
cacheRatio
=
1.0
,
cacheRatio
=
1.0
,
image
=
false
,
image
=
false
,
imageRatio
=
1.0
,
imageRatio
=
1.0
,
image
In
putTokens
=
0
,
image
Out
putTokens
=
0
,
webSearch
=
false
,
webSearch
=
false
,
webSearchCallCount
=
0
,
webSearchCallCount
=
0
,
webSearchPrice
=
0
,
webSearchPrice
=
0
,
...
@@ -1027,8 +1027,6 @@ export function renderModelPrice(
...
@@ -1027,8 +1027,6 @@ export function renderModelPrice(
audioInputSeperatePrice
=
false
,
audioInputSeperatePrice
=
false
,
audioInputTokens
=
0
,
audioInputTokens
=
0
,
audioInputPrice
=
0
,
audioInputPrice
=
0
,
imageOutputTokens
=
0
,
imageOutputPrice
=
0
,
)
{
)
{
const
{
ratio
:
effectiveGroupRatio
,
label
:
ratioLabel
}
=
getEffectiveRatio
(
const
{
ratio
:
effectiveGroupRatio
,
label
:
ratioLabel
}
=
getEffectiveRatio
(
groupRatio
,
groupRatio
,
...
@@ -1059,9 +1057,9 @@ export function renderModelPrice(
...
@@ -1059,9 +1057,9 @@ export function renderModelPrice(
let
effectiveInputTokens
=
let
effectiveInputTokens
=
inputTokens
-
cacheTokens
+
cacheTokens
*
cacheRatio
;
inputTokens
-
cacheTokens
+
cacheTokens
*
cacheRatio
;
// Handle image tokens if present
// Handle image tokens if present
if
(
image
&&
image
In
putTokens
>
0
)
{
if
(
image
&&
image
Out
putTokens
>
0
)
{
effectiveInputTokens
=
effectiveInputTokens
=
inputTokens
-
image
InputTokens
+
imageIn
putTokens
*
imageRatio
;
inputTokens
-
image
OutputTokens
+
imageOut
putTokens
*
imageRatio
;
}
}
if
(
audioInputTokens
>
0
)
{
if
(
audioInputTokens
>
0
)
{
effectiveInputTokens
-=
audioInputTokens
;
effectiveInputTokens
-=
audioInputTokens
;
...
@@ -1071,8 +1069,7 @@ export function renderModelPrice(
...
@@ -1071,8 +1069,7 @@ export function renderModelPrice(
(
audioInputTokens
/
1000000
)
*
audioInputPrice
*
groupRatio
+
(
audioInputTokens
/
1000000
)
*
audioInputPrice
*
groupRatio
+
(
completionTokens
/
1000000
)
*
completionRatioPrice
*
groupRatio
+
(
completionTokens
/
1000000
)
*
completionRatioPrice
*
groupRatio
+
(
webSearchCallCount
/
1000
)
*
webSearchPrice
*
groupRatio
+
(
webSearchCallCount
/
1000
)
*
webSearchPrice
*
groupRatio
+
(
fileSearchCallCount
/
1000
)
*
fileSearchPrice
*
groupRatio
+
(
fileSearchCallCount
/
1000
)
*
fileSearchPrice
*
groupRatio
;
(
imageOutputTokens
/
1000000
)
*
imageOutputPrice
*
groupRatio
;
return
(
return
(
<>
<>
...
@@ -1107,7 +1104,7 @@ export function renderModelPrice(
...
@@ -1107,7 +1104,7 @@ export function renderModelPrice(
)
}
)
}
</
p
>
</
p
>
)
}
)
}
{
image
&&
image
In
putTokens
>
0
&&
(
{
image
&&
image
Out
putTokens
>
0
&&
(
<
p
>
<
p
>
{
i18next
.
t
(
{
i18next
.
t
(
'图片输入价格:
$
{{
price
}}
*
{{
ratio
}}
=
$
{{
total
}}
/ 1M tokens
(
图片倍率: {{imageRatio}}
)
'
,
'图片输入价格:
$
{{
price
}}
*
{{
ratio
}}
=
$
{{
total
}}
/ 1M tokens
(
图片倍率: {{imageRatio}}
)
'
,
...
@@ -1134,26 +1131,17 @@ export function renderModelPrice(
...
@@ -1134,26 +1131,17 @@ export function renderModelPrice(
})
}
})
}
</
p
>
</
p
>
)
}
)
}
{
imageOutputPrice
>
0
&&
imageOutputTokens
>
0
&&
(
<
p
>
{
i18next
.
t
(
'图片输出价格:
$
{{
price
}}
*
分组倍率
{{
ratio
}}
=
$
{{
total
}}
/ 1M tokens', {
price
:
imageOutputPrice
,
ratio
:
groupRatio
,
total
:
imageOutputPrice
*
groupRatio
,
})
}
</
p
>
)
}
<
p
></
p
>
<
p
></
p
>
<
p
>
<
p
>
{
(()
=>
{
{
(()
=>
{
// 构建输入部分描述
// 构建输入部分描述
let
inputDesc
=
''
;
let
inputDesc
=
''
;
if
(
image
&&
image
In
putTokens
>
0
)
{
if
(
image
&&
image
Out
putTokens
>
0
)
{
inputDesc
=
i18next
.
t
(
inputDesc
=
i18next
.
t
(
'
(
输入
{{
nonImageInput
}}
tokens
+
图片输入
{{
imageInput
}}
tokens
*
{{
imageRatio
}}
/ 1M tokens * ${{price}}'
,
'
(
输入
{{
nonImageInput
}}
tokens
+
图片输入
{{
imageInput
}}
tokens
*
{{
imageRatio
}}
/ 1M tokens * ${{price}}'
,
{
{
nonImageInput
:
inputTokens
-
image
In
putTokens
,
nonImageInput
:
inputTokens
-
image
Out
putTokens
,
imageInput
:
image
In
putTokens
,
imageInput
:
image
Out
putTokens
,
imageRatio
:
imageRatio
,
imageRatio
:
imageRatio
,
price
:
inputRatioPrice
,
price
:
inputRatioPrice
,
},
},
...
@@ -1223,16 +1211,6 @@ export function renderModelPrice(
...
@@ -1223,16 +1211,6 @@ export function renderModelPrice(
},
},
)
)
:
''
,
:
''
,
imageOutputPrice
>
0
&&
imageOutputTokens
>
0
?
i18next
.
t
(
'
+
图片输出
{{
tokenCounts
}}
tokens
*
$
{{
price
}}
/ 1M tokens * 分组倍率{{ratio}}'
,
{
tokenCounts
:
imageOutputTokens
,
price
:
imageOutputPrice
,
ratio
:
groupRatio
,
},
)
:
''
,
].
join
(
''
);
].
join
(
''
);
return
i18next
.
t
(
return
i18next
.
t
(
...
...
web/src/hooks/usage-logs/useUsageLogsData.jsx
View file @
1a8d7817
...
@@ -447,8 +447,6 @@ export const useLogsData = () => {
...
@@ -447,8 +447,6 @@ export const useLogsData = () => {
other
?.
audio_input_seperate_price
||
false
,
other
?.
audio_input_seperate_price
||
false
,
other
?.
audio_input_token_count
||
0
,
other
?.
audio_input_token_count
||
0
,
other
?.
audio_input_price
||
0
,
other
?.
audio_input_price
||
0
,
other
?.
image_output_token_count
||
0
,
other
?.
image_output_price
||
0
,
);
);
}
}
expandDataLocal
.
push
({
expandDataLocal
.
push
({
...
...
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