tool_billing.go 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. package service
  2. import (
  3. "math"
  4. "github.com/QuantumNous/new-api/common"
  5. "github.com/QuantumNous/new-api/setting/operation_setting"
  6. )
  7. // ToolCallUsage captures all tool call counts from a single request.
  8. type ToolCallUsage struct {
  9. ModelName string
  10. WebSearchCalls int
  11. WebSearchToolName string // "web_search_preview", "web_search", etc.
  12. FileSearchCalls int
  13. ImageGenerationCall bool
  14. ImageGenerationQuality string
  15. ImageGenerationSize string
  16. }
  17. // ToolCallItem represents a single billed tool usage line.
  18. type ToolCallItem struct {
  19. Name string `json:"name"`
  20. CallCount int `json:"call_count"`
  21. PricePer1K float64 `json:"price_per_1k"`
  22. TotalPrice float64 `json:"total_price"`
  23. Quota int `json:"quota"`
  24. }
  25. // ToolCallResult holds the aggregated tool call billing for a request.
  26. type ToolCallResult struct {
  27. TotalQuota int `json:"total_quota"`
  28. Items []ToolCallItem `json:"items,omitempty"`
  29. }
  30. // ComputeToolCallQuota calculates the total quota for all tool calls in a
  31. // request. Tool prices are resolved via GetToolPriceForModel which supports
  32. // model-prefix overrides. groupRatio is applied.
  33. func ComputeToolCallQuota(usage ToolCallUsage, groupRatio float64) ToolCallResult {
  34. var items []ToolCallItem
  35. totalQuota := 0
  36. addItem := func(toolName string, count int) {
  37. if count <= 0 {
  38. return
  39. }
  40. pricePer1K := operation_setting.GetToolPriceForModel(toolName, usage.ModelName)
  41. if pricePer1K <= 0 {
  42. return
  43. }
  44. totalPrice := pricePer1K * float64(count) / 1000
  45. quota := int(math.Round(totalPrice * common.QuotaPerUnit * groupRatio))
  46. items = append(items, ToolCallItem{
  47. Name: toolName,
  48. CallCount: count,
  49. PricePer1K: pricePer1K,
  50. TotalPrice: totalPrice,
  51. Quota: quota,
  52. })
  53. totalQuota += quota
  54. }
  55. if usage.WebSearchCalls > 0 && usage.WebSearchToolName != "" {
  56. addItem(usage.WebSearchToolName, usage.WebSearchCalls)
  57. }
  58. if usage.FileSearchCalls > 0 {
  59. addItem("file_search", usage.FileSearchCalls)
  60. }
  61. if usage.ImageGenerationCall {
  62. price := operation_setting.GetGPTImage1PriceOnceCall(usage.ImageGenerationQuality, usage.ImageGenerationSize)
  63. quota := int(math.Round(price * common.QuotaPerUnit * groupRatio))
  64. items = append(items, ToolCallItem{
  65. Name: "image_generation",
  66. CallCount: 1,
  67. PricePer1K: price,
  68. TotalPrice: price,
  69. Quota: quota,
  70. })
  71. totalQuota += quota
  72. }
  73. return ToolCallResult{
  74. TotalQuota: totalQuota,
  75. Items: items,
  76. }
  77. }