|
- package controller
-
- import (
- "strconv"
- "strings"
-
- "github.com/QuantumNous/new-api/common"
- "github.com/QuantumNous/new-api/model"
- "github.com/QuantumNous/new-api/setting/ratio_setting"
-
- "github.com/gin-gonic/gin"
- )
-
- // GetAllChannelPricing 获取所有渠道定价(分页)
- func GetAllChannelPricing(c *gin.Context) {
- page, _ := strconv.Atoi(c.DefaultQuery("p", "1"))
- pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "10"))
- offset := (page - 1) * pageSize
-
- list, total, err := model.GetAllChannelPricing(offset, pageSize)
- if err != nil {
- common.ApiError(c, err)
- return
- }
-
- common.ApiSuccess(c, gin.H{
- "page": page,
- "page_size": pageSize,
- "total": total,
- "items": list,
- })
- }
-
- // GetChannelPricingByModel 获取指定模型的所有渠道定价
- func GetChannelPricingByModel(c *gin.Context) {
- modelName := c.Param("name")
- if modelName == "" {
- common.ApiErrorMsg(c, "model name is required")
- return
- }
-
- list, err := model.GetChannelPricingByModel(modelName)
- if err != nil {
- common.ApiError(c, err)
- return
- }
-
- common.ApiSuccess(c, list)
- }
-
- // CreateChannelPricingRequest 创建渠道定价请求
- type CreateChannelPricingRequest struct {
- Id int `json:"id"`
- ModelName string `json:"model_name" binding:"required"`
- ChannelId int `json:"channel_id" binding:"required"`
- QuotaType int `json:"quota_type"`
- ModelRatio float64 `json:"model_ratio"`
- CompletionRatio float64 `json:"completion_ratio"`
- ModelPrice float64 `json:"model_price"`
- TagIds string `json:"tag_ids"`
- }
-
- // CreateChannelPricing 创建或更新渠道定价
- func CreateChannelPricing(c *gin.Context) {
- var req CreateChannelPricingRequest
- if err := c.ShouldBindJSON(&req); err != nil {
- common.ApiError(c, err)
- return
- }
-
- // 检查是否已存在
- existing, _ := model.GetChannelPricing(req.ModelName, req.ChannelId)
- if existing != nil {
- // 更新
- existing.QuotaType = req.QuotaType
- existing.ModelRatio = req.ModelRatio
- existing.CompletionRatio = req.CompletionRatio
- existing.ModelPrice = req.ModelPrice
- existing.TagIds = req.TagIds
- if err := existing.Update(); err != nil {
- common.ApiError(c, err)
- return
- }
- common.ApiSuccess(c, existing)
- return
- }
-
- // 创建
- cp := &model.ChannelPricing{
- ModelName: req.ModelName,
- ChannelId: req.ChannelId,
- QuotaType: req.QuotaType,
- ModelRatio: req.ModelRatio,
- CompletionRatio: req.CompletionRatio,
- ModelPrice: req.ModelPrice,
- TagIds: req.TagIds,
- }
- if err := cp.Insert(); err != nil {
- common.ApiError(c, err)
- return
- }
-
- common.ApiSuccess(c, cp)
- }
-
- // BatchCreateChannelPricingRequest 批量创建请求
- type BatchCreateChannelPricingRequest struct {
- Items []*CreateChannelPricingRequest `json:"items" binding:"required"`
- }
-
- // BatchCreateChannelPricing 批量创建或更新渠道定价
- func BatchCreateChannelPricing(c *gin.Context) {
- var req BatchCreateChannelPricingRequest
- if err := c.ShouldBindJSON(&req); err != nil {
- common.ApiError(c, err)
- return
- }
-
- pricings := make([]*model.ChannelPricing, 0, len(req.Items))
- for _, item := range req.Items {
- pricings = append(pricings, &model.ChannelPricing{
- ModelName: item.ModelName,
- ChannelId: item.ChannelId,
- QuotaType: item.QuotaType,
- ModelRatio: item.ModelRatio,
- CompletionRatio: item.CompletionRatio,
- ModelPrice: item.ModelPrice,
- TagIds: item.TagIds,
- })
- }
-
- // 使用事务逐个处理(GORM 的批量 upsert 在不同数据库表现不一致)
- for _, cp := range pricings {
- existing, _ := model.GetChannelPricing(cp.ModelName, cp.ChannelId)
- if existing != nil {
- existing.QuotaType = cp.QuotaType
- existing.ModelRatio = cp.ModelRatio
- existing.CompletionRatio = cp.CompletionRatio
- existing.ModelPrice = cp.ModelPrice
- existing.TagIds = cp.TagIds
- if err := existing.Update(); err != nil {
- common.ApiError(c, err)
- return
- }
- } else {
- if err := cp.Insert(); err != nil {
- common.ApiError(c, err)
- return
- }
- }
- }
-
- common.ApiSuccess(c, gin.H{"affected": len(pricings)})
- }
-
- // DeleteChannelPricing 删除渠道定价
- func DeleteChannelPricing(c *gin.Context) {
- idStr := c.Param("id")
- id, err := strconv.Atoi(idStr)
- if err != nil {
- common.ApiError(c, err)
- return
- }
-
- cp := &model.ChannelPricing{Id: id}
- if err := cp.Delete(); err != nil {
- common.ApiError(c, err)
- return
- }
-
- common.ApiSuccess(c, nil)
- }
-
- // CopyGlobalPricingRequest 复制全局定价请求
- type CopyGlobalPricingRequest struct {
- Overwrite bool `json:"overwrite"` // 是否覆盖已存在的渠道定价
- }
-
- // CopyGlobalPricing 复制全局定价到指定渠道
- // 从 ratio_setting 读取全局定价信息,复制到 channel_pricing 表
- func CopyGlobalPricing(c *gin.Context) {
- channelIdStr := c.Param("channel_id")
- channelId, err := strconv.Atoi(channelIdStr)
- if err != nil {
- common.ApiError(c, err)
- return
- }
-
- var req CopyGlobalPricingRequest
- c.ShouldBindJSON(&req)
-
- // 获取该渠道支持的所有模型(使用 GetAbilitiesByChannelId)
- abilities, err := model.GetAbilitiesByChannelId(channelId)
- if err != nil {
- common.ApiError(c, err)
- return
- }
-
- imported := 0
- for _, ability := range abilities {
- // 检查是否已存在
- existing, _ := model.GetChannelPricing(ability.Model, channelId)
- if existing != nil && !req.Overwrite {
- continue
- }
-
- // 确定定价类型
- var quotaType int
- var ratio, completionRatio, price float64
-
- // 优先检查是否有按次计费的价格
- modelPrice, hasPrice := ratio_setting.GetModelPrice(ability.Model, false)
- if hasPrice {
- quotaType = model.QuotaTypeByCall
- price = modelPrice
- } else {
- // 使用按量计费
- quotaType = model.QuotaTypeByTokens
- modelRatio, hasRatio, _ := ratio_setting.GetModelRatio(ability.Model)
- if hasRatio {
- ratio = modelRatio
- }
- completionRatio = ratio_setting.GetCompletionRatio(ability.Model)
- }
-
- if existing != nil {
- existing.QuotaType = quotaType
- existing.ModelRatio = ratio
- existing.CompletionRatio = completionRatio
- existing.ModelPrice = price
- if err := existing.Update(); err == nil {
- imported++
- }
- } else {
- cp := &model.ChannelPricing{
- ModelName: ability.Model,
- ChannelId: channelId,
- QuotaType: quotaType,
- ModelRatio: ratio,
- CompletionRatio: completionRatio,
- ModelPrice: price,
- }
- if err := cp.Insert(); err == nil {
- imported++
- }
- }
- }
-
- common.ApiSuccess(c, gin.H{
- "total": len(abilities),
- "imported": imported,
- })
- }
-
- // ChannelPricingWithTags 带标签详情的渠道定价响应
- type ChannelPricingWithTags struct {
- *model.ChannelPricing
- Tags []*model.PricingTag `json:"tags"`
- }
-
- // GetChannelPricingWithTags 获取渠道定价(带标签详情)
- func GetChannelPricingWithTags(c *gin.Context) {
- page, _ := strconv.Atoi(c.DefaultQuery("p", "1"))
- pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "10"))
- offset := (page - 1) * pageSize
-
- list, total, err := model.GetAllChannelPricing(offset, pageSize)
- if err != nil {
- common.ApiError(c, err)
- return
- }
-
- // 获取所有标签
- tags, _ := model.GetAllPricingTags()
- tagMap := make(map[int]*model.PricingTag)
- for _, tag := range tags {
- tagMap[tag.Id] = tag
- }
-
- // 为每个定价填充标签详情
- result := make([]*ChannelPricingWithTags, 0, len(list))
- for _, cp := range list {
- item := &ChannelPricingWithTags{
- ChannelPricing: cp,
- Tags: make([]*model.PricingTag, 0),
- }
- if cp.TagIds != "" {
- for _, idStr := range strings.Split(cp.TagIds, ",") {
- if id, err := strconv.Atoi(idStr); err == nil {
- if tag, ok := tagMap[id]; ok {
- item.Tags = append(item.Tags, tag)
- }
- }
- }
- }
- result = append(result, item)
- }
-
- common.ApiSuccess(c, gin.H{
- "page": page,
- "page_size": pageSize,
- "total": total,
- "items": result,
- })
- }
|