price.go 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. package helper
  2. import (
  3. "fmt"
  4. "github.com/QuantumNous/new-api/common"
  5. "github.com/QuantumNous/new-api/logger"
  6. relaycommon "github.com/QuantumNous/new-api/relay/common"
  7. "github.com/QuantumNous/new-api/setting/operation_setting"
  8. "github.com/QuantumNous/new-api/setting/ratio_setting"
  9. "github.com/QuantumNous/new-api/types"
  10. "github.com/gin-gonic/gin"
  11. )
  12. // https://docs.claude.com/en/docs/build-with-claude/prompt-caching#1-hour-cache-duration
  13. const claudeCacheCreation1hMultiplier = 6 / 3.75
  14. // HandleGroupRatio checks for "auto_group" in the context and updates the group ratio and relayInfo.UsingGroup if present
  15. func HandleGroupRatio(ctx *gin.Context, relayInfo *relaycommon.RelayInfo) types.GroupRatioInfo {
  16. groupRatioInfo := types.GroupRatioInfo{
  17. GroupRatio: 1.0, // default ratio
  18. GroupSpecialRatio: -1,
  19. }
  20. // check auto group
  21. autoGroup, exists := ctx.Get("auto_group")
  22. if exists {
  23. logger.LogDebug(ctx, fmt.Sprintf("final group: %s", autoGroup))
  24. relayInfo.UsingGroup = autoGroup.(string)
  25. }
  26. // check user group special ratio
  27. userGroupRatio, ok := ratio_setting.GetGroupGroupRatio(relayInfo.UserGroup, relayInfo.UsingGroup)
  28. if ok {
  29. // user group special ratio
  30. groupRatioInfo.GroupSpecialRatio = userGroupRatio
  31. groupRatioInfo.GroupRatio = userGroupRatio
  32. groupRatioInfo.HasSpecialRatio = true
  33. } else {
  34. // normal group ratio
  35. groupRatioInfo.GroupRatio = ratio_setting.GetGroupRatio(relayInfo.UsingGroup)
  36. }
  37. return groupRatioInfo
  38. }
  39. func ModelPriceHelper(c *gin.Context, info *relaycommon.RelayInfo, promptTokens int, meta *types.TokenCountMeta) (types.PriceData, error) {
  40. modelPrice, usePrice := ratio_setting.GetModelPrice(info.OriginModelName, false)
  41. groupRatioInfo := HandleGroupRatio(c, info)
  42. var preConsumedQuota int
  43. var modelRatio float64
  44. var completionRatio float64
  45. var cacheRatio float64
  46. var imageRatio float64
  47. var cacheCreationRatio float64
  48. var cacheCreationRatio5m float64
  49. var cacheCreationRatio1h float64
  50. var audioRatio float64
  51. var audioCompletionRatio float64
  52. var freeModel bool
  53. if !usePrice {
  54. preConsumedTokens := common.Max(promptTokens, common.PreConsumedQuota)
  55. if meta.MaxTokens != 0 {
  56. preConsumedTokens += meta.MaxTokens
  57. }
  58. var success bool
  59. var matchName string
  60. modelRatio, success, matchName = ratio_setting.GetModelRatio(info.OriginModelName)
  61. if !success {
  62. acceptUnsetRatio := false
  63. if info.UserSetting.AcceptUnsetRatioModel {
  64. acceptUnsetRatio = true
  65. }
  66. if !acceptUnsetRatio {
  67. return types.PriceData{}, fmt.Errorf("模型 %s 倍率或价格未配置,请联系管理员设置或开始自用模式;Model %s ratio or price not set, please set or start self-use mode", matchName, matchName)
  68. }
  69. }
  70. completionRatio = ratio_setting.GetCompletionRatio(info.OriginModelName)
  71. cacheRatio, _ = ratio_setting.GetCacheRatio(info.OriginModelName)
  72. cacheCreationRatio, _ = ratio_setting.GetCreateCacheRatio(info.OriginModelName)
  73. cacheCreationRatio5m = cacheCreationRatio
  74. // 固定1h和5min缓存写入价格的比例
  75. cacheCreationRatio1h = cacheCreationRatio * claudeCacheCreation1hMultiplier
  76. imageRatio, _ = ratio_setting.GetImageRatio(info.OriginModelName)
  77. audioRatio = ratio_setting.GetAudioRatio(info.OriginModelName)
  78. audioCompletionRatio = ratio_setting.GetAudioCompletionRatio(info.OriginModelName)
  79. ratio := modelRatio * groupRatioInfo.GroupRatio
  80. preConsumedQuota = int(float64(preConsumedTokens) * ratio)
  81. } else {
  82. if meta.ImagePriceRatio != 0 {
  83. modelPrice = modelPrice * meta.ImagePriceRatio
  84. }
  85. preConsumedQuota = int(modelPrice * common.QuotaPerUnit * groupRatioInfo.GroupRatio)
  86. }
  87. // check if free model pre-consume is disabled
  88. if !operation_setting.GetQuotaSetting().EnableFreeModelPreConsume {
  89. // if model price or ratio is 0, do not pre-consume quota
  90. if groupRatioInfo.GroupRatio == 0 {
  91. preConsumedQuota = 0
  92. freeModel = true
  93. } else if usePrice {
  94. if modelPrice == 0 {
  95. preConsumedQuota = 0
  96. freeModel = true
  97. }
  98. } else {
  99. if modelRatio == 0 {
  100. preConsumedQuota = 0
  101. freeModel = true
  102. }
  103. }
  104. }
  105. priceData := types.PriceData{
  106. FreeModel: freeModel,
  107. ModelPrice: modelPrice,
  108. ModelRatio: modelRatio,
  109. CompletionRatio: completionRatio,
  110. GroupRatioInfo: groupRatioInfo,
  111. UsePrice: usePrice,
  112. CacheRatio: cacheRatio,
  113. ImageRatio: imageRatio,
  114. AudioRatio: audioRatio,
  115. AudioCompletionRatio: audioCompletionRatio,
  116. CacheCreationRatio: cacheCreationRatio,
  117. CacheCreation5mRatio: cacheCreationRatio5m,
  118. CacheCreation1hRatio: cacheCreationRatio1h,
  119. QuotaToPreConsume: preConsumedQuota,
  120. }
  121. if common.DebugEnabled {
  122. println(fmt.Sprintf("model_price_helper result: %s", priceData.ToSetting()))
  123. }
  124. info.PriceData = priceData
  125. return priceData, nil
  126. }
  127. // ModelPriceHelperPerCall 按次计费的 PriceHelper (MJ、Task)
  128. func ModelPriceHelperPerCall(c *gin.Context, info *relaycommon.RelayInfo) (types.PriceData, error) {
  129. groupRatioInfo := HandleGroupRatio(c, info)
  130. modelPrice, success := ratio_setting.GetModelPrice(info.OriginModelName, true)
  131. // 如果没有配置价格,检查模型倍率配置
  132. if !success {
  133. // 没有配置费用,返回错误
  134. defaultPrice, ok := ratio_setting.GetDefaultModelPriceMap()[info.OriginModelName]
  135. if !ok {
  136. // 不再使用默认价格,而是返回错误
  137. return types.PriceData{}, fmt.Errorf("模型 %s 价格未配置,请联系管理员设置", info.OriginModelName)
  138. } else {
  139. modelPrice = defaultPrice
  140. }
  141. // 没有配置倍率也不接受没配置,那就返回错误
  142. _, ratioSuccess, matchName := ratio_setting.GetModelRatio(info.OriginModelName)
  143. if !ratioSuccess {
  144. acceptUnsetRatio := false
  145. if info.UserSetting.AcceptUnsetRatioModel {
  146. acceptUnsetRatio = true
  147. }
  148. if !acceptUnsetRatio {
  149. return types.PriceData{}, fmt.Errorf("模型 %s 倍率或价格未配置,请联系管理员设置或开始自用模式;Model %s ratio or price not set, please set or start self-use mode", matchName, matchName)
  150. }
  151. }
  152. }
  153. quota := int(modelPrice * common.QuotaPerUnit * groupRatioInfo.GroupRatio)
  154. // 免费模型检测(与 ModelPriceHelper 对齐)
  155. freeModel := false
  156. if !operation_setting.GetQuotaSetting().EnableFreeModelPreConsume {
  157. if groupRatioInfo.GroupRatio == 0 || modelPrice == 0 {
  158. quota = 0
  159. freeModel = true
  160. }
  161. }
  162. priceData := types.PriceData{
  163. FreeModel: freeModel,
  164. ModelPrice: modelPrice,
  165. Quota: quota,
  166. GroupRatioInfo: groupRatioInfo,
  167. }
  168. return priceData, nil
  169. }
  170. func ContainPriceOrRatio(modelName string) bool {
  171. _, ok := ratio_setting.GetModelPrice(modelName, false)
  172. if ok {
  173. return true
  174. }
  175. _, ok, _ = ratio_setting.GetModelRatio(modelName)
  176. if ok {
  177. return true
  178. }
  179. return false
  180. }