package controller import ( "encoding/json" "github.com/QuantumNous/new-api/common" "github.com/QuantumNous/new-api/model" "github.com/QuantumNous/new-api/relaykit/dto" "github.com/gin-gonic/gin" ) func relayAttemptGuardResult(a model.RelayAttempt) string { if a.GuardResult == "model_mismatch" { return "mismatch_rejected" } if a.GuardResult == "unchecked" && a.ReturnedModel != "" && a.ReturnedModel == a.RequestedModel { return "accepted" } if a.GuardResult == "accepted" && a.Number > 1 { return "switched_success" } return a.GuardResult } // Attempt history is owner-scoped; channel identifiers are administrator-only. func GetRelayAttempts(c *gin.Context) { requestID := c.Param("request_id") if requestID == "" || len(requestID) > 64 { c.AbortWithStatus(400) return } query := model.DB.Where("request_id = ?", requestID) admin := c.GetInt("role") >= common.RoleAdminUser if !admin { query = query.Where("user_id = ?", c.GetInt("id")) } var attempts []model.RelayAttempt if err := query.Order("number asc, id asc").Limit(100).Find(&attempts).Error; err != nil { common.ApiError(c, err) return } rows := make([]gin.H, 0, len(attempts)) total := 0 pending := false for _, a := range attempts { var usage dto.Usage _ = common.UnmarshalJsonStr(a.UsageJSON, &usage) row := gin.H{"number": a.Number, "group": a.GroupName, "requested_model": a.RequestedModel, "returned_model": a.ReturnedModel, "guard_result": relayAttemptGuardResult(a), "usage_source": a.UsageSource, "state": a.State, "quota": a.Quota, "billing_source": a.Funding, "usage": usage} row["charged"] = a.State == "settled" && a.Quota > 0 row["charge_explanation"] = "Each consumed attempt is charged independently, including rejected results." var log model.Log var other map[string]json.RawMessage price := map[string]json.RawMessage{} if common.UnmarshalJsonStr(a.LogJSON, &log) == nil && common.UnmarshalJsonStr(log.Other, &other) == nil { for _, key := range []string{"group_ratio", "model_ratio", "completion_ratio", "cache_ratio", "model_price", "billing_mode", "expr_b64", "matched_tier", "billing_tokens", "billing_unit", "fixed_price"} { if value, ok := other[key]; ok { price[key] = value } } } row["price"] = price if admin { row["channel_id"] = a.ChannelID } rows = append(rows, row) total += a.Quota pending = pending || a.State != "settled" } common.ApiSuccess(c, gin.H{"attempts": rows, "total_quota": total, "pending": pending}) }