Não pode escolher mais do que 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 

212 linhas
5.4 KiB

  1. package controller
  2. import (
  3. "fmt"
  4. "math"
  5. "strings"
  6. "github.com/QuantumNous/new-api/common"
  7. "github.com/QuantumNous/new-api/model"
  8. "github.com/QuantumNous/new-api/service"
  9. "github.com/QuantumNous/new-api/setting/ratio_setting"
  10. "github.com/gin-gonic/gin"
  11. )
  12. // resolveCurrentUser 从 gin.Context 解析当前登录用户信息。
  13. // 未登录或查询失败时 loggedIn=false,groupRatio=1.0。
  14. func resolveCurrentUser(c *gin.Context) (loggedIn bool, userId int, userGroup string, groupRatio float64) {
  15. groupRatio = 1.0
  16. raw, exists := c.Get("id")
  17. if !exists {
  18. return
  19. }
  20. userId = raw.(int)
  21. user, err := model.GetUserCache(userId)
  22. if err != nil {
  23. return
  24. }
  25. loggedIn = true
  26. userGroup = user.Group
  27. groupRatio = service.GetUserGroupRatio(userGroup, userGroup)
  28. return
  29. }
  30. func filterPricingByUsableGroups(pricing []model.Pricing, usableGroup map[string]string) []model.Pricing {
  31. if len(pricing) == 0 {
  32. return pricing
  33. }
  34. if len(usableGroup) == 0 {
  35. return []model.Pricing{}
  36. }
  37. filtered := make([]model.Pricing, 0, len(pricing))
  38. for _, item := range pricing {
  39. if common.StringsContains(item.EnableGroup, "all") {
  40. filtered = append(filtered, item)
  41. continue
  42. }
  43. for _, group := range item.EnableGroup {
  44. if _, ok := usableGroup[group]; ok {
  45. filtered = append(filtered, item)
  46. break
  47. }
  48. }
  49. }
  50. return filtered
  51. }
  52. func GetPricing(c *gin.Context) {
  53. pricing := model.GetPricing()
  54. userId, exists := c.Get("id")
  55. usableGroup := map[string]string{}
  56. groupRatio := map[string]float64{}
  57. for s, f := range ratio_setting.GetGroupRatioCopy() {
  58. groupRatio[s] = f
  59. }
  60. var group string
  61. if exists {
  62. user, err := model.GetUserCache(userId.(int))
  63. if err == nil {
  64. group = user.Group
  65. for g := range groupRatio {
  66. ratio, ok := ratio_setting.GetGroupGroupRatio(group, g)
  67. if ok {
  68. groupRatio[g] = ratio
  69. }
  70. }
  71. }
  72. }
  73. usableGroup = service.GetUserUsableGroups(group)
  74. pricing = filterPricingByUsableGroups(pricing, usableGroup)
  75. // check groupRatio contains usableGroup
  76. for group := range ratio_setting.GetGroupRatioCopy() {
  77. if _, ok := usableGroup[group]; !ok {
  78. delete(groupRatio, group)
  79. }
  80. }
  81. c.JSON(200, gin.H{
  82. "success": true,
  83. "data": pricing,
  84. "vendors": model.GetVendors(),
  85. "group_ratio": groupRatio,
  86. "usable_group": usableGroup,
  87. "supported_endpoint": model.GetSupportedEndpointMap(),
  88. "auto_groups": service.GetUserAutoGroup(group),
  89. "_": "a42d372ccf0b5dd13ecf71203521f9d2",
  90. })
  91. }
  92. // GetUserPricing 获取用户对指定模型的价格信息(原价 vs 用户价)
  93. func GetUserPricing(c *gin.Context) {
  94. modelName := c.Param("model")
  95. // *model 通配符返回值带前导 /,需要去掉
  96. modelName = strings.TrimPrefix(modelName, "/")
  97. if modelName == "" {
  98. common.ApiErrorMsg(c, "模型名不能为空")
  99. return
  100. }
  101. pricingData := model.GetPricingByModel(modelName)
  102. if pricingData == nil {
  103. common.ApiErrorMsg(c, "未找到该模型的定价信息")
  104. return
  105. }
  106. loggedIn, _, userGroup, groupRatio := resolveCurrentUser(c)
  107. if !loggedIn {
  108. respondOriginalPrice(c, pricingData)
  109. return
  110. }
  111. totalRatio := groupRatio
  112. savingsPercent := int(math.Round((1 - totalRatio) * 100))
  113. result := gin.H{
  114. "success": true,
  115. "model_name": pricingData.ModelName,
  116. "quota_type": pricingData.QuotaType,
  117. "group": userGroup,
  118. "group_ratio": groupRatio,
  119. "savings_percent": savingsPercent,
  120. "logged_in": true,
  121. }
  122. if pricingData.QuotaType == model.QuotaTypeByTokens {
  123. originalInput := pricingData.ModelRatio * 2
  124. originalOutput := pricingData.ModelRatio * pricingData.CompletionRatio * 2
  125. result["original_input"] = originalInput
  126. result["original_output"] = originalOutput
  127. result["user_input"] = originalInput * totalRatio
  128. result["user_output"] = originalOutput * totalRatio
  129. } else {
  130. result["original_price"] = pricingData.ModelPrice
  131. result["user_price"] = pricingData.ModelPrice * totalRatio
  132. }
  133. if savingsPercent > 0 {
  134. result["discount"] = formatDiscount(totalRatio)
  135. }
  136. c.JSON(200, result)
  137. }
  138. // respondOriginalPrice 未登录或用户查询失败时,只返回原价
  139. func respondOriginalPrice(c *gin.Context, pricingData *model.Pricing) {
  140. result := gin.H{
  141. "success": true,
  142. "model_name": pricingData.ModelName,
  143. "quota_type": pricingData.QuotaType,
  144. "logged_in": false,
  145. }
  146. if pricingData.QuotaType == model.QuotaTypeByTokens {
  147. result["original_input"] = pricingData.ModelRatio * 2
  148. result["original_output"] = pricingData.ModelRatio * pricingData.CompletionRatio * 2
  149. } else {
  150. result["original_price"] = pricingData.ModelPrice
  151. }
  152. c.JSON(200, result)
  153. }
  154. // formatDiscount 将倍率转换为中文折扣格式
  155. func formatDiscount(ratio float64) string {
  156. if ratio <= 0 {
  157. return "免费"
  158. }
  159. rawDiscount := math.Round(ratio*100) / 10
  160. if rawDiscount >= 10 {
  161. return ""
  162. }
  163. if rawDiscount == math.Trunc(rawDiscount) {
  164. return fmt.Sprintf("%.0f折", rawDiscount)
  165. }
  166. return fmt.Sprintf("%.1f折", rawDiscount)
  167. }
  168. func ResetModelRatio(c *gin.Context) {
  169. defaultStr := ratio_setting.DefaultModelRatio2JSONString()
  170. err := model.UpdateOption("ModelRatio", defaultStr)
  171. if err != nil {
  172. c.JSON(200, gin.H{
  173. "success": false,
  174. "message": err.Error(),
  175. })
  176. return
  177. }
  178. err = ratio_setting.UpdateModelRatioByJSONString(defaultStr)
  179. if err != nil {
  180. c.JSON(200, gin.H{
  181. "success": false,
  182. "message": err.Error(),
  183. })
  184. return
  185. }
  186. c.JSON(200, gin.H{
  187. "success": true,
  188. "message": "重置模型倍率成功",
  189. })
  190. }