diff --git a/service/aiproxy/controller/dashboard.go b/service/aiproxy/controller/dashboard.go index 7c79f6d4261..c3d81f5d00c 100644 --- a/service/aiproxy/controller/dashboard.go +++ b/service/aiproxy/controller/dashboard.go @@ -9,29 +9,30 @@ import ( "github.com/labring/sealos/service/aiproxy/model" ) -func getDashboardStartEndTime(t string) (time.Time, time.Time) { +func getDashboardTime(t string) (time.Time, time.Time, time.Duration) { end := time.Now() var start time.Time + var timeSpan time.Duration switch t { case "month": start = end.AddDate(0, 0, -30) + timeSpan = time.Hour * 24 case "two_week": start = end.AddDate(0, 0, -15) + timeSpan = time.Hour * 12 case "week": start = end.AddDate(0, 0, -7) + timeSpan = time.Hour * 6 case "day": fallthrough default: start = end.AddDate(0, 0, -1) + timeSpan = time.Hour * 1 } - return start, end + return start, end, timeSpan } -const ( - fillGapsInterval = 3600 -) - -func fillGaps(data []*model.HourlyChartData) []*model.HourlyChartData { +func fillGaps(data []*model.HourlyChartData, timeSpan time.Duration) []*model.HourlyChartData { if len(data) <= 1 { return data } @@ -42,7 +43,7 @@ func fillGaps(data []*model.HourlyChartData) []*model.HourlyChartData { for i := 1; i < len(data); i++ { curr := data[i] prev := data[i-1] - hourDiff := (curr.Timestamp - prev.Timestamp) / fillGapsInterval + hourDiff := (curr.Timestamp - prev.Timestamp) / int64(timeSpan.Seconds()) // If gap is 1 hour or less, continue if hourDiff <= 1 { @@ -54,18 +55,18 @@ func fillGaps(data []*model.HourlyChartData) []*model.HourlyChartData { if hourDiff > 3 { // Add point for hour after prev result = append(result, &model.HourlyChartData{ - Timestamp: prev.Timestamp + fillGapsInterval, + Timestamp: prev.Timestamp + int64(timeSpan.Seconds()), }) // Add point for hour before curr result = append(result, &model.HourlyChartData{ - Timestamp: curr.Timestamp - fillGapsInterval, + Timestamp: curr.Timestamp - int64(timeSpan.Seconds()), }) result = append(result, curr) continue } // Fill gaps of 2-3 hours with zero points - for j := prev.Timestamp + fillGapsInterval; j < curr.Timestamp; j += fillGapsInterval { + for j := prev.Timestamp + int64(timeSpan.Seconds()); j < curr.Timestamp; j += int64(timeSpan.Seconds()) { result = append(result, &model.HourlyChartData{ Timestamp: j, }) @@ -77,15 +78,15 @@ func fillGaps(data []*model.HourlyChartData) []*model.HourlyChartData { } func GetDashboard(c *gin.Context) { - start, end := getDashboardStartEndTime(c.Query("type")) + start, end, timeSpan := getDashboardTime(c.Query("type")) modelName := c.Query("model") - dashboards, err := model.GetDashboardData(start, end, modelName) + dashboards, err := model.GetDashboardData(start, end, modelName, timeSpan) if err != nil { middleware.ErrorResponse(c, http.StatusOK, err.Error()) return } - dashboards.ChartData = fillGaps(dashboards.ChartData) + dashboards.ChartData = fillGaps(dashboards.ChartData, timeSpan) middleware.SuccessResponse(c, dashboards) } @@ -96,16 +97,16 @@ func GetGroupDashboard(c *gin.Context) { return } - start, end := getDashboardStartEndTime(c.Query("type")) + start, end, timeSpan := getDashboardTime(c.Query("type")) tokenName := c.Query("token_name") modelName := c.Query("model") - dashboards, err := model.GetGroupDashboardData(group, start, end, tokenName, modelName) + dashboards, err := model.GetGroupDashboardData(group, start, end, tokenName, modelName, timeSpan) if err != nil { middleware.ErrorResponse(c, http.StatusOK, "failed to get statistics") return } - dashboards.ChartData = fillGaps(dashboards.ChartData) + dashboards.ChartData = fillGaps(dashboards.ChartData, timeSpan) middleware.SuccessResponse(c, dashboards) } diff --git a/service/aiproxy/model/log.go b/service/aiproxy/model/log.go index 80490ee9505..e2bbba7b9ba 100644 --- a/service/aiproxy/model/log.go +++ b/service/aiproxy/model/log.go @@ -627,29 +627,29 @@ type GroupDashboardResponse struct { TokenNames []string `json:"token_names"` } -func getHourTimestamp() string { +func getTimeSpanFormat(timeSpan time.Duration) string { switch { case common.UsingMySQL: - return "UNIX_TIMESTAMP(DATE_FORMAT(request_at, '%Y-%m-%d %H:00:00'))" + return fmt.Sprintf("UNIX_TIMESTAMP(DATE_FORMAT(request_at, '%%Y-%%m-%%d %%H:%%i:00')) DIV %d * %d", int64(timeSpan.Seconds()), int64(timeSpan.Seconds())) case common.UsingPostgreSQL: - return "FLOOR(EXTRACT(EPOCH FROM date_trunc('hour', request_at)))" + return fmt.Sprintf("FLOOR(EXTRACT(EPOCH FROM date_trunc('minute', request_at)) / %d) * %d", int64(timeSpan.Seconds()), int64(timeSpan.Seconds())) case common.UsingSQLite: - return "STRFTIME('%s', STRFTIME('%Y-%m-%d %H:00:00', request_at))" + return fmt.Sprintf("CAST(STRFTIME('%%s', STRFTIME('%%Y-%%m-%%d %%H:%%M:00', request_at)) AS INTEGER) / %d * %d", int64(timeSpan.Seconds()), int64(timeSpan.Seconds())) default: return "" } } -func getChartData(group string, start, end time.Time, tokenName, modelName string) ([]*HourlyChartData, error) { +func getChartData(group string, start, end time.Time, tokenName, modelName string, timeSpan time.Duration) ([]*HourlyChartData, error) { var chartData []*HourlyChartData - hourTimestamp := getHourTimestamp() - if hourTimestamp == "" { - return nil, errors.New("unsupported hour format") + timeSpanFormat := getTimeSpanFormat(timeSpan) + if timeSpanFormat == "" { + return nil, errors.New("unsupported time format") } query := LogDB.Table("logs"). - Select(hourTimestamp + " as timestamp, count(*) as request_count, sum(used_amount) as used_amount, sum(case when code != 200 then 1 else 0 end) as exception_count"). + Select(timeSpanFormat + " as timestamp, count(*) as request_count, sum(used_amount) as used_amount, sum(case when code != 200 then 1 else 0 end) as exception_count"). Group("timestamp"). Order("timestamp ASC") @@ -758,14 +758,14 @@ func getTPM(group string, end time.Time, tokenName, modelName string) (int64, er return tpm, err } -func GetDashboardData(start, end time.Time, modelName string) (*DashboardResponse, error) { +func GetDashboardData(start, end time.Time, modelName string, timeSpan time.Duration) (*DashboardResponse, error) { if end.IsZero() { end = time.Now() } else if end.Before(start) { return nil, errors.New("end time is before start time") } - chartData, err := getChartData("", start, end, "", modelName) + chartData, err := getChartData("", start, end, "", modelName, timeSpan) if err != nil { return nil, err } @@ -800,7 +800,7 @@ func GetDashboardData(start, end time.Time, modelName string) (*DashboardRespons }, nil } -func GetGroupDashboardData(group string, start, end time.Time, tokenName string, modelName string) (*GroupDashboardResponse, error) { +func GetGroupDashboardData(group string, start, end time.Time, tokenName string, modelName string, timeSpan time.Duration) (*GroupDashboardResponse, error) { if group == "" { return nil, errors.New("group is required") } @@ -811,7 +811,7 @@ func GetGroupDashboardData(group string, start, end time.Time, tokenName string, return nil, errors.New("end time is before start time") } - chartData, err := getChartData(group, start, end, tokenName, modelName) + chartData, err := getChartData(group, start, end, tokenName, modelName, timeSpan) if err != nil { return nil, err }