mirror of
https://github.com/Ed1s0nZ/CyberStrikeAI.git
synced 2026-08-29 06:00:52 +02:00
93 lines
2.7 KiB
Go
93 lines
2.7 KiB
Go
package handler
|
|
|
|
import (
|
|
"net/http"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"cyberstrike-ai/internal/database"
|
|
"cyberstrike-ai/internal/security"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
// GetTokenUsageStats returns model token usage aggregates for dashboard views.
|
|
func (h *ConversationHandler) GetTokenUsageStats(c *gin.Context) {
|
|
filter := tokenUsageFilterFromQuery(c)
|
|
if session, ok := security.CurrentSession(c); ok {
|
|
filter.Access = database.RBACListAccess{UserID: session.UserID, Scope: session.Scope}
|
|
}
|
|
stats, err := h.db.GetModelTokenUsageStats(filter)
|
|
if err != nil {
|
|
h.logger.Error("获取Token用量统计失败", zap.Error(err))
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, stats)
|
|
}
|
|
|
|
// GetConversationTokenUsageStats returns token usage scoped to one conversation.
|
|
func (h *ConversationHandler) GetConversationTokenUsageStats(c *gin.Context) {
|
|
filter := tokenUsageFilterFromQuery(c)
|
|
filter.ConversationID = strings.TrimSpace(c.Param("id"))
|
|
if session, ok := security.CurrentSession(c); ok {
|
|
filter.Access = database.RBACListAccess{UserID: session.UserID, Scope: session.Scope}
|
|
}
|
|
stats, err := h.db.GetModelTokenUsageStats(filter)
|
|
if err != nil {
|
|
h.logger.Error("获取对话Token用量统计失败", zap.Error(err), zap.String("conversationId", filter.ConversationID))
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, stats)
|
|
}
|
|
|
|
func tokenUsageFilterFromQuery(c *gin.Context) database.ModelTokenUsageFilter {
|
|
days, _ := strconv.Atoi(strings.TrimSpace(c.DefaultQuery("days", "7")))
|
|
if days <= 0 {
|
|
days = 7
|
|
}
|
|
if days > 365 {
|
|
days = 365
|
|
}
|
|
limit, _ := strconv.Atoi(strings.TrimSpace(c.DefaultQuery("limit", "10")))
|
|
if limit <= 0 {
|
|
limit = 10
|
|
}
|
|
if limit > 500 {
|
|
limit = 500
|
|
}
|
|
filter := database.ModelTokenUsageFilter{
|
|
ConversationID: strings.TrimSpace(c.Query("conversation_id")),
|
|
ProjectID: strings.TrimSpace(c.Query("project_id")),
|
|
Days: days,
|
|
Limit: limit,
|
|
}
|
|
if since := parseTokenUsageQueryTime(c.Query("since")); !since.IsZero() {
|
|
filter.Since = since
|
|
} else if days > 0 {
|
|
now := time.Now()
|
|
start := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()).AddDate(0, 0, -(days - 1))
|
|
filter.Since = start
|
|
}
|
|
if until := parseTokenUsageQueryTime(c.Query("until")); !until.IsZero() {
|
|
filter.Until = until
|
|
}
|
|
return filter
|
|
}
|
|
|
|
func parseTokenUsageQueryTime(raw string) time.Time {
|
|
raw = strings.TrimSpace(raw)
|
|
if raw == "" {
|
|
return time.Time{}
|
|
}
|
|
for _, layout := range []string{time.RFC3339Nano, time.RFC3339, "2006-01-02"} {
|
|
if t, err := time.Parse(layout, raw); err == nil {
|
|
return t
|
|
}
|
|
}
|
|
return time.Time{}
|
|
}
|