| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102 |
- package service
- import (
- "math"
- "strings"
- "github.com/QuantumNous/new-api/common"
- "github.com/QuantumNous/new-api/setting/operation_setting"
- )
- // ToolCallUsage captures all tool call counts from a single request.
- type ToolCallUsage struct {
- WebSearchCalls int
- WebSearchModelName string
- ClaudeWebSearchCalls int
- FileSearchCalls int
- ImageGenerationCall bool
- ImageGenerationQuality string
- ImageGenerationSize string
- }
- // ToolCallItem represents a single billed tool usage line.
- type ToolCallItem struct {
- Name string `json:"name"`
- CallCount int `json:"call_count"`
- PricePer1K float64 `json:"price_per_1k"`
- TotalPrice float64 `json:"total_price"`
- Quota int `json:"quota"`
- }
- // ToolCallResult holds the aggregated tool call billing for a request.
- type ToolCallResult struct {
- TotalQuota int `json:"total_quota"`
- Items []ToolCallItem `json:"items,omitempty"`
- }
- func getWebSearchPriceKey(modelName string) string {
- isNormalPrice :=
- strings.HasPrefix(modelName, "o3") ||
- strings.HasPrefix(modelName, "o4") ||
- strings.HasPrefix(modelName, "gpt-5")
- if isNormalPrice {
- return "web_search"
- }
- return "web_search_high"
- }
- // ComputeToolCallQuota calculates the total quota for all tool calls in a
- // request. All tool prices are $/1K calls (configurable via ToolCallPrices
- // option). groupRatio is applied. Per-call billing (UsePrice) callers should
- // NOT add this result — per-call price already includes everything.
- func ComputeToolCallQuota(usage ToolCallUsage, groupRatio float64) ToolCallResult {
- var items []ToolCallItem
- totalQuota := 0
- addItem := func(name string, count int, pricePer1K float64) {
- if count <= 0 || pricePer1K <= 0 {
- return
- }
- totalPrice := pricePer1K * float64(count) / 1000
- quota := int(math.Round(totalPrice * common.QuotaPerUnit * groupRatio))
- items = append(items, ToolCallItem{
- Name: name,
- CallCount: count,
- PricePer1K: pricePer1K,
- TotalPrice: totalPrice,
- Quota: quota,
- })
- totalQuota += quota
- }
- if usage.WebSearchCalls > 0 {
- priceKey := getWebSearchPriceKey(usage.WebSearchModelName)
- addItem("web_search", usage.WebSearchCalls, operation_setting.GetToolPrice(priceKey))
- }
- if usage.ClaudeWebSearchCalls > 0 {
- addItem("claude_web_search", usage.ClaudeWebSearchCalls, operation_setting.GetToolPrice("claude_web_search"))
- }
- if usage.FileSearchCalls > 0 {
- addItem("file_search", usage.FileSearchCalls, operation_setting.GetToolPrice("file_search"))
- }
- if usage.ImageGenerationCall {
- price := operation_setting.GetGPTImage1PriceOnceCall(usage.ImageGenerationQuality, usage.ImageGenerationSize)
- quota := int(math.Round(price * common.QuotaPerUnit * groupRatio))
- items = append(items, ToolCallItem{
- Name: "image_generation",
- CallCount: 1,
- PricePer1K: price * 1000,
- TotalPrice: price,
- Quota: quota,
- })
- totalQuota += quota
- }
- return ToolCallResult{
- TotalQuota: totalQuota,
- Items: items,
- }
- }
|