Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions core/common/consume/consume.go
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,10 @@ func CalculateAmountDetail(
inputTokens -= usage.AudioInputTokens
}

if modelPrice.VideoInputPrice > 0 {
inputTokens -= usage.VideoInputTokens
}

if modelPrice.CachedPrice > 0 {
inputTokens -= usage.CachedTokens
}
Expand All @@ -218,6 +222,10 @@ func CalculateAmountDetail(
outputTokens -= usage.ImageOutputTokens
}

if modelPrice.AudioOutputPrice > 0 {
outputTokens -= usage.AudioOutputTokens
}

outputPrice := float64(modelPrice.OutputPrice)

outputPriceUnit := modelPrice.GetOutputPriceUnit()
Expand All @@ -240,6 +248,10 @@ func CalculateAmountDetail(
Mul(decimal.NewFromFloat(float64(modelPrice.AudioInputPrice))).
Div(decimal.NewFromInt(modelPrice.GetAudioInputPriceUnit()))

videoInputAmount := decimal.NewFromInt(int64(usage.VideoInputTokens)).
Mul(decimal.NewFromFloat(float64(modelPrice.VideoInputPrice))).
Div(decimal.NewFromInt(modelPrice.GetVideoInputPriceUnit()))

cachedAmount := decimal.NewFromInt(int64(usage.CachedTokens)).
Mul(decimal.NewFromFloat(float64(modelPrice.CachedPrice))).
Div(decimal.NewFromInt(modelPrice.GetCachedPriceUnit()))
Expand All @@ -260,22 +272,30 @@ func CalculateAmountDetail(
Mul(decimal.NewFromFloat(float64(modelPrice.ImageOutputPrice))).
Div(decimal.NewFromInt(modelPrice.GetImageOutputPriceUnit()))

audioOutputAmount := decimal.NewFromInt(int64(usage.AudioOutputTokens)).
Mul(decimal.NewFromFloat(float64(modelPrice.AudioOutputPrice))).
Div(decimal.NewFromInt(modelPrice.GetAudioOutputPriceUnit()))

usedAmount := inputAmount.
Add(imageInputAmount).
Add(audioInputAmount).
Add(videoInputAmount).
Add(cachedAmount).
Add(cacheCreationAmount).
Add(webSearchAmount).
Add(outputAmount).
Add(imageOutputAmount).
Add(audioOutputAmount).
InexactFloat64()

return model.Amount{
InputAmount: inputAmount.InexactFloat64(),
ImageInputAmount: imageInputAmount.InexactFloat64(),
AudioInputAmount: audioInputAmount.InexactFloat64(),
VideoInputAmount: videoInputAmount.InexactFloat64(),
OutputAmount: outputAmount.InexactFloat64(),
ImageOutputAmount: imageOutputAmount.InexactFloat64(),
AudioOutputAmount: audioOutputAmount.InexactFloat64(),
CachedAmount: cachedAmount.InexactFloat64(),
CacheCreationAmount: cacheCreationAmount.InexactFloat64(),
WebSearchAmount: webSearchAmount.InexactFloat64(),
Expand Down
36 changes: 36 additions & 0 deletions core/common/consume/consume_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,42 @@ func TestCalculateAmount(t *testing.T) {
},
want: 0.019, // 0.001 * 1000/1000 + 0.004 * (3000-1000)/1000 + 0.01 * 1000/1000
},
{
name: "Audio Input and Output Pricing",
code: http.StatusOK,
usage: model.Usage{
InputTokens: 2000,
AudioInputTokens: 500,
OutputTokens: 3000,
AudioOutputTokens: 1000,
},
price: model.Price{
InputPrice: 0.001,
AudioInputPrice: 0.003,
OutputPrice: 0.004,
AudioOutputPrice: 0.01,
},
want: 0.021, // text in 0.0015 + audio in 0.0015 + text out 0.008 + audio out 0.01
},
{
name: "Video Input Pricing",
code: http.StatusOK,
usage: model.Usage{
InputTokens: 3000,
ImageInputTokens: 500,
AudioInputTokens: 600,
VideoInputTokens: 1000,
OutputTokens: 2000,
},
price: model.Price{
InputPrice: 0.001,
ImageInputPrice: 0.003,
AudioInputPrice: 0.004,
VideoInputPrice: 0.008,
OutputPrice: 0.002,
},
want: 0.0168, // text in 0.0009 + image in 0.0015 + audio in 0.0024 + video in 0.008 + text out 0.004
},
{
name: "Cached Token Pricing",
code: http.StatusOK,
Expand Down
12 changes: 6 additions & 6 deletions core/controller/dashboard.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ func fillGaps(
// @Param end_timestamp query int64 false "End second timestamp"
// @Param timezone query string false "Timezone, default is Local"
// @Param timespan query string false "Time span type (minute, hour, day, month)"
// @Param fields query string false "Comma-separated list of fields to select (e.g., request_count,exception_count,cache_hit_count). Available: request_count,retry_count,exception_count,status4xx_count,status5xx_count,status400_count,status429_count,status500_count,cache_hit_count,input_tokens,image_input_tokens,audio_input_tokens,output_tokens,image_output_tokens,cached_tokens,cache_creation_tokens,total_tokens,web_search_count,used_amount,total_time,total_ttfb. Groups: count,usage,time,all"
// @Param fields query string false "Comma-separated list of fields to select (e.g., request_count,exception_count,cache_hit_count). Available: request_count,retry_count,exception_count,status4xx_count,status5xx_count,status400_count,status429_count,status500_count,cache_hit_count,input_tokens,image_input_tokens,audio_input_tokens,video_input_tokens,output_tokens,image_output_tokens,audio_output_tokens,cached_tokens,cache_creation_tokens,total_tokens,web_search_count,used_amount,total_time,total_ttfb. Groups: count,usage,time,all"
// @Success 200 {object} middleware.APIResponse{data=model.DashboardResponse}
// @Router /api/dashboard/ [get]
func GetDashboard(c *gin.Context) {
Expand Down Expand Up @@ -245,7 +245,7 @@ func GetDashboard(c *gin.Context) {
// @Param end_timestamp query int64 false "End second timestamp"
// @Param timezone query string false "Timezone, default is Local"
// @Param timespan query string false "Time span type (minute, hour, day, month)"
// @Param fields query string false "Comma-separated list of fields to select (e.g., request_count,exception_count,cache_hit_count). Available: request_count,retry_count,exception_count,status4xx_count,status5xx_count,status400_count,status429_count,status500_count,cache_hit_count,input_tokens,image_input_tokens,audio_input_tokens,output_tokens,image_output_tokens,cached_tokens,cache_creation_tokens,total_tokens,web_search_count,used_amount,total_time,total_ttfb. Groups: count,usage,time,all"
// @Param fields query string false "Comma-separated list of fields to select (e.g., request_count,exception_count,cache_hit_count). Available: request_count,retry_count,exception_count,status4xx_count,status5xx_count,status400_count,status429_count,status500_count,cache_hit_count,input_tokens,image_input_tokens,audio_input_tokens,video_input_tokens,output_tokens,image_output_tokens,audio_output_tokens,cached_tokens,cache_creation_tokens,total_tokens,web_search_count,used_amount,total_time,total_ttfb. Groups: count,usage,time,all"
// @Success 200 {object} middleware.APIResponse{data=model.GroupDashboardResponse}
// @Router /api/dashboard/{group} [get]
func GetGroupDashboard(c *gin.Context) {
Expand Down Expand Up @@ -438,7 +438,7 @@ func GetGroupDashboardModels(c *gin.Context) {
// @Param end_timestamp query int64 false "End timestamp"
// @Param timezone query string false "Timezone, default is Local"
// @Param timespan query string false "Time span type (minute, hour, day, month)"
// @Param fields query string false "Comma-separated list of fields to select (e.g., request_count,exception_count,cache_hit_count). Available: request_count,retry_count,exception_count,status4xx_count,status5xx_count,status400_count,status429_count,status500_count,cache_hit_count,input_tokens,image_input_tokens,audio_input_tokens,output_tokens,image_output_tokens,cached_tokens,cache_creation_tokens,total_tokens,web_search_count,used_amount,total_time,total_ttfb. Groups: count,usage,time,all"
// @Param fields query string false "Comma-separated list of fields to select (e.g., request_count,exception_count,cache_hit_count). Available: request_count,retry_count,exception_count,status4xx_count,status5xx_count,status400_count,status429_count,status500_count,cache_hit_count,input_tokens,image_input_tokens,audio_input_tokens,video_input_tokens,output_tokens,image_output_tokens,audio_output_tokens,cached_tokens,cache_creation_tokens,total_tokens,web_search_count,used_amount,total_time,total_ttfb. Groups: count,usage,time,all"
// @Success 200 {object} middleware.APIResponse{data=[]model.TimeSummaryDataV2}
// @Router /api/dashboardv2/ [get]
func GetTimeSeriesModelData(c *gin.Context) {
Expand Down Expand Up @@ -479,7 +479,7 @@ func GetTimeSeriesModelData(c *gin.Context) {
// @Param end_timestamp query int64 false "End timestamp"
// @Param timezone query string false "Timezone, default is Local"
// @Param timespan query string false "Time span type (minute, hour, day, month)"
// @Param fields query string false "Comma-separated list of fields to select (e.g., request_count,exception_count,cache_hit_count). Available: request_count,retry_count,exception_count,status4xx_count,status5xx_count,status400_count,status429_count,status500_count,cache_hit_count,input_tokens,image_input_tokens,audio_input_tokens,output_tokens,image_output_tokens,cached_tokens,cache_creation_tokens,total_tokens,web_search_count,used_amount,total_time,total_ttfb. Groups: count,usage,time,all"
// @Param fields query string false "Comma-separated list of fields to select (e.g., request_count,exception_count,cache_hit_count). Available: request_count,retry_count,exception_count,status4xx_count,status5xx_count,status400_count,status429_count,status500_count,cache_hit_count,input_tokens,image_input_tokens,audio_input_tokens,video_input_tokens,output_tokens,image_output_tokens,audio_output_tokens,cached_tokens,cache_creation_tokens,total_tokens,web_search_count,used_amount,total_time,total_ttfb. Groups: count,usage,time,all"
// @Success 200 {object} middleware.APIResponse{data=[]model.TimeSummaryDataV2}
// @Router /api/dashboardv2/{group} [get]
func GetGroupTimeSeriesModelData(c *gin.Context) {
Expand Down Expand Up @@ -526,7 +526,7 @@ func GetGroupTimeSeriesModelData(c *gin.Context) {
// @Param end_timestamp query int64 false "End timestamp"
// @Param timezone query string false "Timezone, default is Local"
// @Param timespan query string false "Time span type (minute, hour, day, month)"
// @Param fields query string false "Comma-separated list of fields to select (e.g., request_count,exception_count,cache_hit_count). Available: request_count,retry_count,exception_count,status4xx_count,status5xx_count,status400_count,status429_count,status500_count,cache_hit_count,input_tokens,image_input_tokens,audio_input_tokens,output_tokens,image_output_tokens,cached_tokens,cache_creation_tokens,total_tokens,web_search_count,used_amount,total_time,total_ttfb. Groups: count,usage,time,all"
// @Param fields query string false "Comma-separated list of fields to select (e.g., request_count,exception_count,cache_hit_count). Available: request_count,retry_count,exception_count,status4xx_count,status5xx_count,status400_count,status429_count,status500_count,cache_hit_count,input_tokens,image_input_tokens,audio_input_tokens,video_input_tokens,output_tokens,image_output_tokens,audio_output_tokens,cached_tokens,cache_creation_tokens,total_tokens,web_search_count,used_amount,total_time,total_ttfb. Groups: count,usage,time,all"
// @Success 200 {object} middleware.APIResponse{data=model.DashboardV3Response}
// @Router /api/dashboardv3/ [get]
func GetTimeSeriesModelDataV3(c *gin.Context) {
Expand Down Expand Up @@ -577,7 +577,7 @@ func GetTimeSeriesModelDataV3(c *gin.Context) {
// @Param end_timestamp query int64 false "End timestamp"
// @Param timezone query string false "Timezone, default is Local"
// @Param timespan query string false "Time span type (minute, hour, day, month)"
// @Param fields query string false "Comma-separated list of fields to select (e.g., request_count,exception_count,cache_hit_count). Available: request_count,retry_count,exception_count,status4xx_count,status5xx_count,status400_count,status429_count,status500_count,cache_hit_count,input_tokens,image_input_tokens,audio_input_tokens,output_tokens,image_output_tokens,cached_tokens,cache_creation_tokens,total_tokens,web_search_count,used_amount,total_time,total_ttfb. Groups: count,usage,time,all"
// @Param fields query string false "Comma-separated list of fields to select (e.g., request_count,exception_count,cache_hit_count). Available: request_count,retry_count,exception_count,status4xx_count,status5xx_count,status400_count,status429_count,status500_count,cache_hit_count,input_tokens,image_input_tokens,audio_input_tokens,video_input_tokens,output_tokens,image_output_tokens,audio_output_tokens,cached_tokens,cache_creation_tokens,total_tokens,web_search_count,used_amount,total_time,total_ttfb. Groups: count,usage,time,all"
// @Success 200 {object} middleware.APIResponse{data=model.DashboardV3Response}
// @Router /api/dashboardv3/{group} [get]
func GetGroupTimeSeriesModelDataV3(c *gin.Context) {
Expand Down
8 changes: 8 additions & 0 deletions core/controller/log_export.go
Original file line number Diff line number Diff line change
Expand Up @@ -459,8 +459,10 @@ func buildLogExportHeader(includeChannel, includeRetryAt bool) []string {
"input_tokens",
"image_input_tokens",
"audio_input_tokens",
"video_input_tokens",
"output_tokens",
"image_output_tokens",
"audio_output_tokens",
"cached_tokens",
"cache_creation_tokens",
"reasoning_tokens",
Expand All @@ -469,8 +471,10 @@ func buildLogExportHeader(includeChannel, includeRetryAt bool) []string {
"input_amount",
"image_input_amount",
"audio_input_amount",
"video_input_amount",
"output_amount",
"image_output_amount",
"audio_output_amount",
"cached_amount",
"cache_creation_amount",
"web_search_amount",
Expand Down Expand Up @@ -532,8 +536,10 @@ func buildLogExportRow(
strconv.FormatInt(int64(logItem.Usage.InputTokens), 10),
strconv.FormatInt(int64(logItem.Usage.ImageInputTokens), 10),
strconv.FormatInt(int64(logItem.Usage.AudioInputTokens), 10),
strconv.FormatInt(int64(logItem.Usage.VideoInputTokens), 10),
strconv.FormatInt(int64(logItem.Usage.OutputTokens), 10),
strconv.FormatInt(int64(logItem.Usage.ImageOutputTokens), 10),
strconv.FormatInt(int64(logItem.Usage.AudioOutputTokens), 10),
strconv.FormatInt(int64(logItem.Usage.CachedTokens), 10),
strconv.FormatInt(int64(logItem.Usage.CacheCreationTokens), 10),
strconv.FormatInt(int64(logItem.Usage.ReasoningTokens), 10),
Expand All @@ -542,8 +548,10 @@ func buildLogExportRow(
formatFloatForExport(logItem.Amount.InputAmount),
formatFloatForExport(logItem.Amount.ImageInputAmount),
formatFloatForExport(logItem.Amount.AudioInputAmount),
formatFloatForExport(logItem.Amount.VideoInputAmount),
formatFloatForExport(logItem.Amount.OutputAmount),
formatFloatForExport(logItem.Amount.ImageOutputAmount),
formatFloatForExport(logItem.Amount.AudioOutputAmount),
formatFloatForExport(logItem.Amount.CachedAmount),
formatFloatForExport(logItem.Amount.CacheCreationAmount),
formatFloatForExport(logItem.Amount.WebSearchAmount),
Expand Down
Loading
Loading