| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209 |
- package admin
- import (
- "errors"
- "net/http"
- "strconv"
- "github.com/Wei-Shaw/sub2api/internal/pkg/response"
- "github.com/Wei-Shaw/sub2api/internal/service"
- "github.com/gin-gonic/gin"
- )
- // GlobalPricingHandler 管理全站模型定价覆盖:命中模型的请求在全部分组/
- // 账号强制使用此处价格,未命中的模型走原定价链路。
- type GlobalPricingHandler struct {
- service *service.GlobalModelPricingService
- }
- func NewGlobalPricingHandler(svc *service.GlobalModelPricingService) *GlobalPricingHandler {
- return &GlobalPricingHandler{service: svc}
- }
- func (h *GlobalPricingHandler) requireService(c *gin.Context) bool {
- if h == nil || h.service == nil {
- response.ErrorFrom(c, errors.New("global pricing service unavailable"))
- return false
- }
- return true
- }
- func globalPricingNotFound(c *gin.Context, err error) bool {
- if errors.Is(err, service.ErrGlobalModelPricingNotFound) {
- response.NotFound(c, "Global pricing entry not found")
- return true
- }
- return false
- }
- func globalPricingConflict(c *gin.Context, err error) bool {
- if errors.Is(err, service.ErrGlobalModelPricingDuplicate) {
- response.Error(c, http.StatusConflict, "This model already has a global pricing entry")
- return true
- }
- return false
- }
- // List 返回全部全站定价(含禁用)。
- // GET /api/v1/admin/global-pricing
- func (h *GlobalPricingHandler) List(c *gin.Context) {
- if !h.requireService(c) {
- return
- }
- items, err := h.service.List(c.Request.Context())
- if err != nil {
- response.ErrorFrom(c, err)
- return
- }
- response.Success(c, gin.H{"items": items, "count": len(items)})
- }
- type globalPricingUpsertRequest struct {
- ModelPattern string `json:"model_pattern"`
- BillingMode service.BillingMode `json:"billing_mode"`
- InputPrice *float64 `json:"input_price"`
- OutputPrice *float64 `json:"output_price"`
- CacheWritePrice *float64 `json:"cache_write_price"`
- CacheWrite1hPrice *float64 `json:"cache_write_1h_price"`
- CacheReadPrice *float64 `json:"cache_read_price"`
- PerRequestPrice *float64 `json:"per_request_price"`
- Enabled *bool `json:"enabled"`
- }
- func (r globalPricingUpsertRequest) toInput(defaultEnabled bool) service.GlobalModelPriceInput {
- enabled := defaultEnabled
- if r.Enabled != nil {
- enabled = *r.Enabled
- }
- return service.GlobalModelPriceInput{
- ModelPattern: r.ModelPattern,
- BillingMode: r.BillingMode,
- InputPrice: r.InputPrice,
- OutputPrice: r.OutputPrice,
- CacheWritePrice: r.CacheWritePrice,
- CacheWrite1hPrice: r.CacheWrite1hPrice,
- CacheReadPrice: r.CacheReadPrice,
- PerRequestPrice: r.PerRequestPrice,
- Enabled: enabled,
- }
- }
- // Create 新建全站定价(默认启用)。
- // POST /api/v1/admin/global-pricing
- func (h *GlobalPricingHandler) Create(c *gin.Context) {
- if !h.requireService(c) {
- return
- }
- var req globalPricingUpsertRequest
- if err := c.ShouldBindJSON(&req); err != nil {
- response.BadRequest(c, "Invalid request: "+err.Error())
- return
- }
- item, err := h.service.Create(c.Request.Context(), req.toInput(true))
- if err != nil {
- if globalPricingConflict(c, err) {
- return
- }
- response.ErrorFrom(c, err)
- return
- }
- response.Success(c, item)
- }
- // Update 更新全站定价(enabled 缺省保持原值)。
- // PUT /api/v1/admin/global-pricing/:id
- func (h *GlobalPricingHandler) Update(c *gin.Context) {
- if !h.requireService(c) {
- return
- }
- id, err := strconv.ParseInt(c.Param("id"), 10, 64)
- if err != nil || id <= 0 {
- response.BadRequest(c, "Invalid pricing ID")
- return
- }
- var req globalPricingUpsertRequest
- if err := c.ShouldBindJSON(&req); err != nil {
- response.BadRequest(c, "Invalid request: "+err.Error())
- return
- }
- input := req.toInput(true)
- if req.Enabled == nil {
- existing, err := h.service.Get(c.Request.Context(), id)
- if err != nil {
- if globalPricingNotFound(c, err) {
- return
- }
- response.ErrorFrom(c, err)
- return
- }
- input.Enabled = existing.Enabled
- }
- item, err := h.service.Update(c.Request.Context(), id, input)
- if err != nil {
- if globalPricingNotFound(c, err) {
- return
- }
- if globalPricingConflict(c, err) {
- return
- }
- response.ErrorFrom(c, err)
- return
- }
- response.Success(c, item)
- }
- // Delete 删除全站定价(对应模型恢复原定价)。
- // DELETE /api/v1/admin/global-pricing/:id
- func (h *GlobalPricingHandler) Delete(c *gin.Context) {
- if !h.requireService(c) {
- return
- }
- id, err := strconv.ParseInt(c.Param("id"), 10, 64)
- if err != nil || id <= 0 {
- response.BadRequest(c, "Invalid pricing ID")
- return
- }
- if err := h.service.Delete(c.Request.Context(), id); err != nil {
- if globalPricingNotFound(c, err) {
- return
- }
- response.ErrorFrom(c, err)
- return
- }
- response.Success(c, gin.H{"message": "Global pricing deleted successfully"})
- }
- type globalPricingEnableRequest struct {
- Enabled *bool `json:"enabled"`
- }
- // SetEnabled 启停全站定价(停用后对应模型恢复原定价)。
- // POST /api/v1/admin/global-pricing/:id/enable
- func (h *GlobalPricingHandler) SetEnabled(c *gin.Context) {
- if !h.requireService(c) {
- return
- }
- id, err := strconv.ParseInt(c.Param("id"), 10, 64)
- if err != nil || id <= 0 {
- response.BadRequest(c, "Invalid pricing ID")
- return
- }
- var req globalPricingEnableRequest
- if err := c.ShouldBindJSON(&req); err != nil {
- response.BadRequest(c, "Invalid request: "+err.Error())
- return
- }
- if req.Enabled == nil {
- response.BadRequest(c, "Invalid request: enabled is required")
- return
- }
- item, err := h.service.SetEnabled(c.Request.Context(), id, *req.Enabled)
- if err != nil {
- if globalPricingNotFound(c, err) {
- return
- }
- response.ErrorFrom(c, err)
- return
- }
- response.Success(c, item)
- }
|