From 9b6b3e40f5716dfb8c182fa302b6cc6679b242a2 Mon Sep 17 00:00:00 2001 From: zijiren <84728412+zijiren233@users.noreply.github.com> Date: Fri, 28 Feb 2025 17:30:37 +0800 Subject: [PATCH] feat: model cost rank and ali tts (#5428) * feat: model cost rank api * fix: ali stt --- service/aiproxy/controller/dashboard.go | 25 ++++++++ service/aiproxy/model/log.go | 58 ++++++++++++++----- .../aiproxy/relay/adaptor/ali/stt-realtime.go | 28 +++++---- service/aiproxy/router/api.go | 6 ++ 4 files changed, 91 insertions(+), 26 deletions(-) diff --git a/service/aiproxy/controller/dashboard.go b/service/aiproxy/controller/dashboard.go index 10c557354..128d2b570 100644 --- a/service/aiproxy/controller/dashboard.go +++ b/service/aiproxy/controller/dashboard.go @@ -205,3 +205,28 @@ func GetGroupDashboardModels(c *gin.Context) { } middleware.SuccessResponse(c, newEnabledModelConfigs) } + +func GetModelCostRank(c *gin.Context) { + startTime, endTime := parseTimeRange(c) + models, err := model.GetModelCostRank("", startTime, endTime) + if err != nil { + middleware.ErrorResponse(c, http.StatusOK, err.Error()) + return + } + middleware.SuccessResponse(c, models) +} + +func GetGroupModelCostRank(c *gin.Context) { + group := c.Param("group") + if group == "" { + middleware.ErrorResponse(c, http.StatusOK, "group is required") + return + } + startTime, endTime := parseTimeRange(c) + models, err := model.GetModelCostRank(group, startTime, endTime) + if err != nil { + middleware.ErrorResponse(c, http.StatusOK, err.Error()) + return + } + middleware.SuccessResponse(c, models) +} diff --git a/service/aiproxy/model/log.go b/service/aiproxy/model/log.go index 9f9014f1a..3c47ef3be 100644 --- a/service/aiproxy/model/log.go +++ b/service/aiproxy/model/log.go @@ -81,18 +81,16 @@ func CreateLogIndexes(db *gorm.DB) error { "CREATE INDEX IF NOT EXISTS idx_group_token_reqat ON logs (group_id, token_name, request_at)", // used by search group logs "CREATE INDEX IF NOT EXISTS idx_group_model_reqat ON logs (group_id, model, request_at)", - // used by group used tokens - "CREATE INDEX IF NOT EXISTS idx_group_reqat_token ON logs (group_id, request_at, token_name)", - // used by group used models - "CREATE INDEX IF NOT EXISTS idx_group_reqat_model ON logs (group_id, request_at, model)", // used by search group logs "CREATE INDEX IF NOT EXISTS idx_group_token_model_reqat ON logs (group_id, token_name, model, request_at)", // day indexes, used by dashboard + "CREATE INDEX IF NOT EXISTS idx_group_reqat_truncday ON logs (group_id, request_at, timestamp_trunc_by_day)", "CREATE INDEX IF NOT EXISTS idx_group_model_reqat_truncday ON logs (group_id, model, request_at, timestamp_trunc_by_day)", "CREATE INDEX IF NOT EXISTS idx_group_token_reqat_truncday ON logs (group_id, token_name, request_at, timestamp_trunc_by_day)", "CREATE INDEX IF NOT EXISTS idx_group_model_token_reqat_truncday ON logs (group_id, model, token_name, request_at, timestamp_trunc_by_day)", // hour indexes, used by dashboard + "CREATE INDEX IF NOT EXISTS idx_group_reqat_trunchour ON logs (group_id, request_at, timestamp_trunc_by_hour)", "CREATE INDEX IF NOT EXISTS idx_group_model_reqat_trunchour ON logs (group_id, model, request_at, timestamp_trunc_by_hour)", "CREATE INDEX IF NOT EXISTS idx_group_token_reqat_trunchour ON logs (group_id, token_name, request_at, timestamp_trunc_by_hour)", "CREATE INDEX IF NOT EXISTS idx_group_model_token_reqat_trunchour ON logs (group_id, model, token_name, request_at, timestamp_trunc_by_hour)", @@ -100,30 +98,28 @@ func CreateLogIndexes(db *gorm.DB) error { } else { indexes = []string{ // used by global search logs - "CREATE INDEX IF NOT EXISTS idx_model_reqat ON logs (model, request_at) INCLUDE (code)", + "CREATE INDEX IF NOT EXISTS idx_model_reqat ON logs (model, request_at) INCLUDE (code, used_amount, total_tokens)", // global day indexes, used by global dashboard "CREATE INDEX IF NOT EXISTS idx_model_reqat_truncday ON logs (model, request_at, timestamp_trunc_by_day) INCLUDE (code, used_amount, total_tokens)", // global hour indexes, used by global dashboard "CREATE INDEX IF NOT EXISTS idx_model_reqat_trunchour ON logs (model, request_at, timestamp_trunc_by_hour) INCLUDE (code, used_amount, total_tokens)", // used by search group logs - "CREATE INDEX IF NOT EXISTS idx_group_token_reqat ON logs (group_id, token_name, request_at) INCLUDE (code)", + "CREATE INDEX IF NOT EXISTS idx_group_token_reqat ON logs (group_id, token_name, request_at) INCLUDE (code, used_amount, total_tokens)", // used by search group logs - "CREATE INDEX IF NOT EXISTS idx_group_model_reqat ON logs (group_id, model, request_at) INCLUDE (code)", - // used by group used tokens - "CREATE INDEX IF NOT EXISTS idx_group_reqat_token ON logs (group_id, request_at, token_name)", - // used by group used models - "CREATE INDEX IF NOT EXISTS idx_group_reqat_model ON logs (group_id, request_at, model)", + "CREATE INDEX IF NOT EXISTS idx_group_token_reqat ON logs (group_id, token_name, request_at) INCLUDE (code, used_amount, total_tokens)", // used by search group logs - "CREATE INDEX IF NOT EXISTS idx_group_token_model_reqat ON logs (group_id, token_name, model, request_at) INCLUDE (code)", + "CREATE INDEX IF NOT EXISTS idx_group_model_reqat ON logs (group_id, model, request_at) INCLUDE (code, used_amount, total_tokens)", + // used by search group logs + "CREATE INDEX IF NOT EXISTS idx_group_token_model_reqat ON logs (group_id, token_name, model, request_at) INCLUDE (code, used_amount, total_tokens)", // day indexes, used by dashboard - "CREATE INDEX IF NOT EXISTS idx_group_model_reqat_truncday ON logs (group_id, request_at, timestamp_trunc_by_day) INCLUDE (code, used_amount, total_tokens)", + "CREATE INDEX IF NOT EXISTS idx_group_reqat_truncday ON logs (group_id, request_at, timestamp_trunc_by_day) INCLUDE (code, used_amount, total_tokens)", "CREATE INDEX IF NOT EXISTS idx_group_model_reqat_truncday ON logs (group_id, model, request_at, timestamp_trunc_by_day) INCLUDE (code, used_amount, total_tokens)", "CREATE INDEX IF NOT EXISTS idx_group_token_reqat_truncday ON logs (group_id, token_name, request_at, timestamp_trunc_by_day) INCLUDE (code, used_amount, total_tokens)", "CREATE INDEX IF NOT EXISTS idx_group_model_token_reqat_truncday ON logs (group_id, model, token_name, request_at, timestamp_trunc_by_day) INCLUDE (code, used_amount, total_tokens)", // hour indexes, used by dashboard - "CREATE INDEX IF NOT EXISTS idx_group_model_reqat_trunchour ON logs (group_id, request_at, timestamp_trunc_by_hour) INCLUDE (code, used_amount, total_tokens)", + "CREATE INDEX IF NOT EXISTS idx_group_reqat_trunchour ON logs (group_id, request_at, timestamp_trunc_by_hour) INCLUDE (code, used_amount, total_tokens)", "CREATE INDEX IF NOT EXISTS idx_group_model_reqat_trunchour ON logs (group_id, model, request_at, timestamp_trunc_by_hour) INCLUDE (code, used_amount, total_tokens)", "CREATE INDEX IF NOT EXISTS idx_group_token_reqat_trunchour ON logs (group_id, token_name, request_at, timestamp_trunc_by_hour) INCLUDE (code, used_amount, total_tokens)", "CREATE INDEX IF NOT EXISTS idx_group_model_token_reqat_trunchour ON logs (group_id, model, token_name, request_at, timestamp_trunc_by_hour) INCLUDE (code, used_amount, total_tokens)", @@ -1238,3 +1234,37 @@ func GetGroupModelTPM(group string, model string) (int64, error) { Scan(&tpm).Error return tpm, err } + +type ModelCostRank struct { + Model string `json:"model"` + UsedAmount float64 `json:"used_amount"` + Total int64 `json:"total"` +} + +func GetModelCostRank(group string, start, end time.Time) ([]*ModelCostRank, error) { + var ranks []*ModelCostRank + + query := LogDB.Model(&Log{}). + Select("model, SUM(used_amount) as used_amount, COUNT(*) as total"). + Group("model"). + Order("used_amount DESC") + + if group != "" { + query = query.Where("group_id = ?", group) + } + + if !start.IsZero() && !end.IsZero() { + query = query.Where("request_at BETWEEN ? AND ?", start, end) + } else if !start.IsZero() { + query = query.Where("request_at >= ?", start) + } else if !end.IsZero() { + query = query.Where("request_at <= ?", end) + } + + err := query.Scan(&ranks).Error + if err != nil { + return nil, err + } + + return ranks, nil +} diff --git a/service/aiproxy/relay/adaptor/ali/stt-realtime.go b/service/aiproxy/relay/adaptor/ali/stt-realtime.go index 4c735c162..e53898a65 100644 --- a/service/aiproxy/relay/adaptor/ali/stt-realtime.go +++ b/service/aiproxy/relay/adaptor/ali/stt-realtime.go @@ -4,12 +4,12 @@ import ( "bytes" "io" "net/http" + "strings" "github.com/gin-gonic/gin" "github.com/google/uuid" "github.com/gorilla/websocket" json "github.com/json-iterator/go" - "github.com/labring/sealos/service/aiproxy/middleware" "github.com/labring/sealos/service/aiproxy/relay/adaptor/openai" "github.com/labring/sealos/service/aiproxy/relay/meta" relaymodel "github.com/labring/sealos/service/aiproxy/relay/model" @@ -46,12 +46,17 @@ type STTInput struct { } type STTParameters struct { - Format string `json:"format"` - SampleRate int `json:"sample_rate"` + Format string `json:"format,omitempty"` + SampleRate int `json:"sample_rate,omitempty"` } type STTOutput struct { - Text string `json:"text"` + STTSentence STTSentence `json:"sentence"` +} + +type STTSentence struct { + Text string `json:"text"` + EndTime *int `json:"end_time"` } type STTUsage struct { @@ -83,10 +88,6 @@ func ConvertSTTRequest(meta *meta.Meta, request *http.Request) (string, http.Hea TaskGroup: "audio", Function: "recognition", Input: STTInput{}, - Parameters: STTParameters{ - Format: "mp3", - SampleRate: 16000, - }, }, } @@ -128,14 +129,14 @@ func STTDoRequest(meta *meta.Meta, req *http.Request) (*http.Response, error) { } func STTDoResponse(meta *meta.Meta, c *gin.Context, _ *http.Response) (usage *relaymodel.Usage, err *relaymodel.ErrorWithStatusCode) { - log := middleware.GetLogger(c) - audioData := meta.MustGet("audio_data").([]byte) taskID := meta.MustGet("task_id").(string) conn := meta.MustGet("ws_conn").(*websocket.Conn) defer conn.Close() + output := strings.Builder{} + usage = &relaymodel.Usage{} for { @@ -178,13 +179,16 @@ func STTDoResponse(meta *meta.Meta, c *gin.Context, _ *http.Response) (usage *re return usage, openai.ErrorWrapperWithMessage("ali_wss_write_msg_failed", "ali_wss_write_msg_failed", http.StatusInternalServerError) } case "result-generated": - if msg.Payload.Output.Text != "" { - log.Info("STT result: " + msg.Payload.Output.Text) + if msg.Payload.Output.STTSentence.Text != "" { + output.WriteString(msg.Payload.Output.STTSentence.Text) } continue case "task-finished": usage.PromptTokens = msg.Payload.Usage.Characters usage.TotalTokens = msg.Payload.Usage.Characters + c.JSON(http.StatusOK, gin.H{ + "text": output.String(), + }) return usage, nil case "task-failed": return usage, openai.ErrorWrapperWithMessage(msg.Header.ErrorMessage, msg.Header.ErrorCode, http.StatusInternalServerError) diff --git a/service/aiproxy/router/api.go b/service/aiproxy/router/api.go index 489de8028..819f91a0b 100644 --- a/service/aiproxy/router/api.go +++ b/service/aiproxy/router/api.go @@ -40,6 +40,12 @@ func SetAPIRouter(router *gin.Engine) { dashboardRoute.GET("/:group/models", controller.GetGroupDashboardModels) } + modelCostRankRoute := apiRouter.Group("/model_cost_rank") + { + modelCostRankRoute.GET("/", controller.GetModelCostRank) + modelCostRankRoute.GET("/:group", controller.GetGroupModelCostRank) + } + groupsRoute := apiRouter.Group("/groups") { groupsRoute.GET("/", controller.GetGroups)