diff --git a/common/model-ratio.go b/common/model-ratio.go index 898837d..46e78ae 100644 --- a/common/model-ratio.go +++ b/common/model-ratio.go @@ -33,6 +33,7 @@ var defaultModelRatio = map[string]float64{ "gpt-4-32k-0613": 30, "gpt-4o-mini": 0.075, // $0.00015 / 1K tokens "gpt-4o-mini-2024-07-18": 0.075, + "chatgpt-4o-latest": 2.5, // $0.01 / 1K tokens "gpt-4o": 2.5, // $0.005 / 1K tokens "gpt-4o-2024-05-13": 2.5, // $0.005 / 1K tokens "gpt-4o-2024-08-06": 1.25, // $0.01 / 1K tokens @@ -343,6 +344,9 @@ func GetCompletionRatio(name string) float64 { } return 2 } + if name == "chatgpt-4o-latest" { + return 3 + } if strings.HasPrefix(name, "claude-instant-1") { return 3 } else if strings.HasPrefix(name, "claude-2") { diff --git a/controller/log.go b/controller/log.go index 70552b5..ca0e1ec 100644 --- a/controller/log.go +++ b/controller/log.go @@ -1,18 +1,19 @@ package controller import ( - "github.com/gin-gonic/gin" "net/http" "one-api/common" "one-api/model" "strconv" + + "github.com/gin-gonic/gin" ) func GetAllLogs(c *gin.Context) { p, _ := strconv.Atoi(c.Query("p")) pageSize, _ := strconv.Atoi(c.Query("page_size")) - if p < 0 { - p = 0 + if p < 1 { + p = 1 } if pageSize < 0 { pageSize = common.ItemsPerPage @@ -24,7 +25,7 @@ func GetAllLogs(c *gin.Context) { tokenName := c.Query("token_name") modelName := c.Query("model_name") channel, _ := strconv.Atoi(c.Query("channel")) - logs, total, err := model.GetAllLogs(logType, startTimestamp, endTimestamp, modelName, username, tokenName, p*pageSize, pageSize, channel) + logs, total, err := model.GetAllLogs(logType, startTimestamp, endTimestamp, modelName, username, tokenName, (p-1)*pageSize, pageSize, channel) if err != nil { c.JSON(http.StatusOK, gin.H{ "success": false, @@ -35,17 +36,20 @@ func GetAllLogs(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ "success": true, "message": "", - "total": total, - "data": logs, + "data": map[string]any{ + "items": logs, + "total": total, + "page": p, + "page_size": pageSize, + }, }) - return } func GetUserLogs(c *gin.Context) { p, _ := strconv.Atoi(c.Query("p")) pageSize, _ := strconv.Atoi(c.Query("page_size")) - if p < 0 { - p = 0 + if p < 1 { + p = 1 } if pageSize < 0 { pageSize = common.ItemsPerPage @@ -59,7 +63,7 @@ func GetUserLogs(c *gin.Context) { endTimestamp, _ := strconv.ParseInt(c.Query("end_timestamp"), 10, 64) tokenName := c.Query("token_name") modelName := c.Query("model_name") - logs, total, err := model.GetUserLogs(userId, logType, startTimestamp, endTimestamp, modelName, tokenName, p*pageSize, pageSize) + logs, total, err := model.GetUserLogs(userId, logType, startTimestamp, endTimestamp, modelName, tokenName, (p-1)*pageSize, pageSize) if err != nil { c.JSON(http.StatusOK, gin.H{ "success": false, @@ -70,8 +74,12 @@ func GetUserLogs(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ "success": true, "message": "", - "total": total, - "data": logs, + "data": map[string]any{ + "items": logs, + "total": total, + "page": p, + "page_size": pageSize, + }, }) return } diff --git a/main.go b/main.go index efee772..c7d6942 100644 --- a/main.go +++ b/main.go @@ -42,6 +42,11 @@ func main() { if err != nil { common.FatalLog("failed to initialize database: " + err.Error()) } + // Initialize SQL Database + err = model.InitLogDB() + if err != nil { + common.FatalLog("failed to initialize database: " + err.Error()) + } defer func() { err := model.CloseDB() if err != nil { diff --git a/model/channel.go b/model/channel.go index 3f9d9ed..34aae68 100644 --- a/model/channel.go +++ b/model/channel.go @@ -106,16 +106,23 @@ func SearchChannels(keyword string, group string, model string) ([]*Channel, err // 构造WHERE子句 var whereClause string var args []interface{} - if group != "" { - whereClause = "(id = ? OR name LIKE ? OR " + keyCol + " = ?) AND " + groupCol + " = ? AND " + modelsCol + " LIKE ?" - args = append(args, common.String2Int(keyword), "%"+keyword+"%", keyword, group, "%"+model+"%") + if group != "" && group != "null" { + var groupCondition string + if common.UsingMySQL { + groupCondition = `CONCAT(',', ` + groupCol + `, ',') LIKE ?` + } else { + // sqlite, PostgreSQL + groupCondition = `(',' || ` + groupCol + ` || ',') LIKE ?` + } + whereClause = "(id = ? OR name LIKE ? OR " + keyCol + " = ?) AND " + modelsCol + ` LIKE ? AND ` + groupCondition + args = append(args, common.String2Int(keyword), "%"+keyword+"%", keyword, "%"+model+"%", "%,"+group+",%") } else { whereClause = "(id = ? OR name LIKE ? OR " + keyCol + " = ?) AND " + modelsCol + " LIKE ?" args = append(args, common.String2Int(keyword), "%"+keyword+"%", keyword, "%"+model+"%") } // 执行查询 - err := baseQuery.Where(whereClause, args...).Find(&channels).Error + err := baseQuery.Where(whereClause, args...).Order("priority desc").Find(&channels).Error if err != nil { return nil, err } diff --git a/model/log.go b/model/log.go index 204e049..5493a05 100644 --- a/model/log.go +++ b/model/log.go @@ -3,11 +3,12 @@ package model import ( "context" "fmt" - "github.com/bytedance/gopkg/util/gopool" - "gorm.io/gorm" "one-api/common" "strings" "time" + + "github.com/bytedance/gopkg/util/gopool" + "gorm.io/gorm" ) type Log struct { @@ -38,7 +39,7 @@ const ( ) func GetLogByKey(key string) (logs []*Log, err error) { - err = DB.Joins("left join tokens on tokens.id = logs.token_id").Where("tokens.key = ?", strings.TrimPrefix(key, "sk-")).Find(&logs).Error + err = LOG_DB.Joins("left join tokens on tokens.id = logs.token_id").Where("tokens.key = ?", strings.TrimPrefix(key, "sk-")).Find(&logs).Error return logs, err } @@ -54,7 +55,7 @@ func RecordLog(userId int, logType int, content string) { Type: logType, Content: content, } - err := DB.Create(log).Error + err := LOG_DB.Create(log).Error if err != nil { common.SysError("failed to record log: " + err.Error()) } @@ -84,7 +85,7 @@ func RecordConsumeLog(ctx context.Context, userId int, channelId int, promptToke IsStream: isStream, Other: otherStr, } - err := DB.Create(log).Error + err := LOG_DB.Create(log).Error if err != nil { common.LogError(ctx, "failed to record log: "+err.Error()) } @@ -98,9 +99,9 @@ func RecordConsumeLog(ctx context.Context, userId int, channelId int, promptToke func GetAllLogs(logType int, startTimestamp int64, endTimestamp int64, modelName string, username string, tokenName string, startIdx int, num int, channel int) (logs []*Log, total int64, err error) { var tx *gorm.DB if logType == LogTypeUnknown { - tx = DB + tx = LOG_DB } else { - tx = DB.Where("type = ?", logType) + tx = LOG_DB.Where("type = ?", logType) } if modelName != "" { tx = tx.Where("model_name like ?", modelName) @@ -120,22 +121,23 @@ func GetAllLogs(logType int, startTimestamp int64, endTimestamp int64, modelName if channel != 0 { tx = tx.Where("channel_id = ?", channel) } - err = tx.Model(&Log{}).Count(&total).Error if err != nil { return nil, 0, err } - err = tx.Order("id desc").Limit(num).Offset(startIdx).Find(&logs).Error + if err != nil { + return nil, 0, err + } return logs, total, err } func GetUserLogs(userId int, logType int, startTimestamp int64, endTimestamp int64, modelName string, tokenName string, startIdx int, num int) (logs []*Log, total int64, err error) { var tx *gorm.DB if logType == LogTypeUnknown { - tx = DB.Where("user_id = ?", userId) + tx = LOG_DB.Where("user_id = ?", userId) } else { - tx = DB.Where("user_id = ? and type = ?", userId, logType) + tx = LOG_DB.Where("user_id = ? and type = ?", userId, logType) } if modelName != "" { tx = tx.Where("model_name like ?", modelName) @@ -149,14 +151,11 @@ func GetUserLogs(userId int, logType int, startTimestamp int64, endTimestamp int if endTimestamp != 0 { tx = tx.Where("created_at <= ?", endTimestamp) } - err = tx.Model(&Log{}).Count(&total).Error if err != nil { return nil, 0, err } - err = tx.Order("id desc").Limit(num).Offset(startIdx).Omit("id").Find(&logs).Error - return logs, total, err for i := range logs { var otherMap map[string]interface{} otherMap = common.StrToMap(logs[i].Other) @@ -170,12 +169,12 @@ func GetUserLogs(userId int, logType int, startTimestamp int64, endTimestamp int } func SearchAllLogs(keyword string) (logs []*Log, err error) { - err = DB.Where("type = ? or content LIKE ?", keyword, keyword+"%").Order("id desc").Limit(common.MaxRecentItems).Find(&logs).Error + err = LOG_DB.Where("type = ? or content LIKE ?", keyword, keyword+"%").Order("id desc").Limit(common.MaxRecentItems).Find(&logs).Error return logs, err } func SearchUserLogs(userId int, keyword string) (logs []*Log, err error) { - err = DB.Where("user_id = ? and type = ?", userId, keyword).Order("id desc").Limit(common.MaxRecentItems).Omit("id").Find(&logs).Error + err = LOG_DB.Where("user_id = ? and type = ?", userId, keyword).Order("id desc").Limit(common.MaxRecentItems).Omit("id").Find(&logs).Error return logs, err } @@ -186,10 +185,10 @@ type Stat struct { } func SumUsedQuota(logType int, startTimestamp int64, endTimestamp int64, modelName string, username string, tokenName string, channel int) (stat Stat) { - tx := DB.Table("logs").Select("sum(quota) quota") + tx := LOG_DB.Table("logs").Select("sum(quota) quota") // 为rpm和tpm创建单独的查询 - rpmTpmQuery := DB.Table("logs").Select("count(*) rpm, sum(prompt_tokens) + sum(completion_tokens) tpm") + rpmTpmQuery := LOG_DB.Table("logs").Select("count(*) rpm, sum(prompt_tokens) + sum(completion_tokens) tpm") if username != "" { tx = tx.Where("username = ?", username) @@ -206,8 +205,8 @@ func SumUsedQuota(logType int, startTimestamp int64, endTimestamp int64, modelNa tx = tx.Where("created_at <= ?", endTimestamp) } if modelName != "" { - tx = tx.Where("model_name = ?", modelName) - rpmTpmQuery = rpmTpmQuery.Where("model_name = ?", modelName) + tx = tx.Where("model_name like ?", modelName) + rpmTpmQuery = rpmTpmQuery.Where("model_name like ?", modelName) } if channel != 0 { tx = tx.Where("channel_id = ?", channel) @@ -228,7 +227,7 @@ func SumUsedQuota(logType int, startTimestamp int64, endTimestamp int64, modelNa } func SumUsedToken(logType int, startTimestamp int64, endTimestamp int64, modelName string, username string, tokenName string) (token int) { - tx := DB.Table("logs").Select("ifnull(sum(prompt_tokens),0) + ifnull(sum(completion_tokens),0)") + tx := LOG_DB.Table("logs").Select("ifnull(sum(prompt_tokens),0) + ifnull(sum(completion_tokens),0)") if username != "" { tx = tx.Where("username = ?", username) } @@ -249,6 +248,6 @@ func SumUsedToken(logType int, startTimestamp int64, endTimestamp int64, modelNa } func DeleteOldLog(targetTimestamp int64) (int64, error) { - result := DB.Where("created_at < ?", targetTimestamp).Delete(&Log{}) + result := LOG_DB.Where("created_at < ?", targetTimestamp).Delete(&Log{}) return result.RowsAffected, result.Error } diff --git a/model/main.go b/model/main.go index a70f21b..01eb6c9 100644 --- a/model/main.go +++ b/model/main.go @@ -15,6 +15,8 @@ import ( var DB *gorm.DB +var LOG_DB *gorm.DB + func createRootAccountIfNeed() error { var user User //if user.Status != common.UserStatusEnabled { @@ -38,9 +40,9 @@ func createRootAccountIfNeed() error { return nil } -func chooseDB() (*gorm.DB, error) { - if os.Getenv("SQL_DSN") != "" { - dsn := os.Getenv("SQL_DSN") +func chooseDB(envName string) (*gorm.DB, error) { + dsn := os.Getenv(envName) + if dsn != "" { if strings.HasPrefix(dsn, "postgres://") { // Use PostgreSQL common.SysLog("using PostgreSQL as database") @@ -52,6 +54,13 @@ func chooseDB() (*gorm.DB, error) { PrepareStmt: true, // precompile SQL }) } + if strings.HasPrefix(dsn, "local") { + common.SysLog("SQL_DSN not set, using SQLite as database") + common.UsingSQLite = true + return gorm.Open(sqlite.Open(common.SQLitePath), &gorm.Config{ + PrepareStmt: true, // precompile SQL + }) + } // Use MySQL common.SysLog("using MySQL as database") // check parseTime @@ -76,7 +85,7 @@ func chooseDB() (*gorm.DB, error) { } func InitDB() (err error) { - db, err := chooseDB() + db, err := chooseDB("SQL_DSN") if err == nil { if common.DebugEnabled { db = db.Debug() @@ -100,52 +109,7 @@ func InitDB() (err error) { // _, _ = sqlDB.Exec("ALTER TABLE midjourneys MODIFY status VARCHAR(20);") // TODO: delete this line when most users have upgraded //} common.SysLog("database migration started") - err = db.AutoMigrate(&Channel{}) - if err != nil { - return err - } - err = db.AutoMigrate(&Token{}) - if err != nil { - return err - } - err = db.AutoMigrate(&User{}) - if err != nil { - return err - } - err = db.AutoMigrate(&Option{}) - if err != nil { - return err - } - err = db.AutoMigrate(&Redemption{}) - if err != nil { - return err - } - err = db.AutoMigrate(&Ability{}) - if err != nil { - return err - } - err = db.AutoMigrate(&Log{}) - if err != nil { - return err - } - err = db.AutoMigrate(&Midjourney{}) - if err != nil { - return err - } - err = db.AutoMigrate(&TopUp{}) - if err != nil { - return err - } - err = db.AutoMigrate(&QuotaData{}) - if err != nil { - return err - } - err = db.AutoMigrate(&Task{}) - if err != nil { - return err - } - common.SysLog("database migrated") - err = createRootAccountIfNeed() + err = migrateDB() return err } else { common.FatalLog(err) @@ -153,8 +117,103 @@ func InitDB() (err error) { return err } -func CloseDB() error { - sqlDB, err := DB.DB() +func InitLogDB() (err error) { + if os.Getenv("LOG_SQL_DSN") == "" { + LOG_DB = DB + return + } + db, err := chooseDB("LOG_SQL_DSN") + if err == nil { + if common.DebugEnabled { + db = db.Debug() + } + LOG_DB = db + sqlDB, err := LOG_DB.DB() + if err != nil { + return err + } + sqlDB.SetMaxIdleConns(common.GetEnvOrDefault("SQL_MAX_IDLE_CONNS", 100)) + sqlDB.SetMaxOpenConns(common.GetEnvOrDefault("SQL_MAX_OPEN_CONNS", 1000)) + sqlDB.SetConnMaxLifetime(time.Second * time.Duration(common.GetEnvOrDefault("SQL_MAX_LIFETIME", 60))) + + if !common.IsMasterNode { + return nil + } + //if common.UsingMySQL { + // _, _ = sqlDB.Exec("DROP INDEX idx_channels_key ON channels;") // TODO: delete this line when most users have upgraded + // _, _ = sqlDB.Exec("ALTER TABLE midjourneys MODIFY action VARCHAR(40);") // TODO: delete this line when most users have upgraded + // _, _ = sqlDB.Exec("ALTER TABLE midjourneys MODIFY progress VARCHAR(30);") // TODO: delete this line when most users have upgraded + // _, _ = sqlDB.Exec("ALTER TABLE midjourneys MODIFY status VARCHAR(20);") // TODO: delete this line when most users have upgraded + //} + common.SysLog("database migration started") + err = migrateLOGDB() + return err + } else { + common.FatalLog(err) + } + return err +} + +func migrateDB() error { + err := DB.AutoMigrate(&Channel{}) + if err != nil { + return err + } + err = DB.AutoMigrate(&Token{}) + if err != nil { + return err + } + err = DB.AutoMigrate(&User{}) + if err != nil { + return err + } + err = DB.AutoMigrate(&Option{}) + if err != nil { + return err + } + err = DB.AutoMigrate(&Redemption{}) + if err != nil { + return err + } + err = DB.AutoMigrate(&Ability{}) + if err != nil { + return err + } + err = DB.AutoMigrate(&Log{}) + if err != nil { + return err + } + err = DB.AutoMigrate(&Midjourney{}) + if err != nil { + return err + } + err = DB.AutoMigrate(&TopUp{}) + if err != nil { + return err + } + err = DB.AutoMigrate(&QuotaData{}) + if err != nil { + return err + } + err = DB.AutoMigrate(&Task{}) + if err != nil { + return err + } + common.SysLog("database migrated") + err = createRootAccountIfNeed() + return err +} + +func migrateLOGDB() error { + var err error + if err = LOG_DB.AutoMigrate(&Log{}); err != nil { + return err + } + return nil +} + +func closeDB(db *gorm.DB) error { + sqlDB, err := db.DB() if err != nil { return err } @@ -162,6 +221,16 @@ func CloseDB() error { return err } +func CloseDB() error { + if LOG_DB != DB { + err := closeDB(LOG_DB) + if err != nil { + return err + } + } + return closeDB(DB) +} + var ( lastPingTime time.Time pingMutex sync.Mutex diff --git a/relay/channel/claude/dto.go b/relay/channel/claude/dto.go index e2a898e..8f289e3 100644 --- a/relay/channel/claude/dto.go +++ b/relay/channel/claude/dto.go @@ -31,9 +31,9 @@ type ClaudeMessage struct { } type Tool struct { - Name string `json:"name"` - Description string `json:"description,omitempty"` - InputSchema InputSchema `json:"input_schema"` + Name string `json:"name"` + Description string `json:"description,omitempty"` + InputSchema map[string]interface{} `json:"input_schema"` } type InputSchema struct { diff --git a/relay/channel/claude/relay-claude.go b/relay/channel/claude/relay-claude.go index 1e32b75..17cb593 100644 --- a/relay/channel/claude/relay-claude.go +++ b/relay/channel/claude/relay-claude.go @@ -63,15 +63,21 @@ func RequestOpenAI2ClaudeMessage(textRequest dto.GeneralOpenAIRequest) (*ClaudeR for _, tool := range textRequest.Tools { if params, ok := tool.Function.Parameters.(map[string]any); ok { - claudeTools = append(claudeTools, Tool{ + claudeTool := Tool{ Name: tool.Function.Name, Description: tool.Function.Description, - InputSchema: InputSchema{ - Type: params["type"].(string), - Properties: params["properties"], - Required: params["required"], - }, - }) + } + claudeTool.InputSchema = make(map[string]interface{}) + claudeTool.InputSchema["type"] = params["type"].(string) + claudeTool.InputSchema["properties"] = params["properties"] + claudeTool.InputSchema["required"] = params["required"] + for s, a := range params { + if s == "type" || s == "properties" || s == "required" { + continue + } + claudeTool.InputSchema[s] = a + } + claudeTools = append(claudeTools, claudeTool) } } diff --git a/relay/channel/openai/constant.go b/relay/channel/openai/constant.go index 7a0c8ca..59f415a 100644 --- a/relay/channel/openai/constant.go +++ b/relay/channel/openai/constant.go @@ -8,6 +8,7 @@ var ModelList = []string{ "gpt-4-32k", "gpt-4-32k-0314", "gpt-4-32k-0613", "gpt-4-turbo-preview", "gpt-4-turbo", "gpt-4-turbo-2024-04-09", "gpt-4-vision-preview", + "chatgpt-4o-latest", "gpt-4o", "gpt-4o-2024-05-13", "gpt-4o-2024-08-06", "gpt-4o-mini", "gpt-4o-mini-2024-07-18", "text-embedding-ada-002", "text-embedding-3-small", "text-embedding-3-large", diff --git a/relay/relay-audio.go b/relay/relay-audio.go index b2fadcc..5dbc323 100644 --- a/relay/relay-audio.go +++ b/relay/relay-audio.go @@ -75,7 +75,7 @@ func AudioHelper(c *gin.Context) *dto.OpenAIErrorWithStatusCode { return service.OpenAIErrorWrapperLocal(err, "get_user_quota_failed", http.StatusInternalServerError) } if userQuota-preConsumedQuota < 0 { - return service.OpenAIErrorWrapperLocal(errors.New("user quota is not enough"), "insufficient_user_quota", http.StatusForbidden) + return service.OpenAIErrorWrapperLocal(errors.New(fmt.Sprintf("audio pre-consumed quota failed, user quota: %d, need quota: %d", userQuota, preConsumedQuota)), "insufficient_user_quota", http.StatusBadRequest) } err = model.CacheDecreaseUserQuota(relayInfo.UserId, preConsumedQuota) if err != nil { diff --git a/relay/relay-image.go b/relay/relay-image.go index 83c7538..74d6c30 100644 --- a/relay/relay-image.go +++ b/relay/relay-image.go @@ -125,7 +125,7 @@ func ImageHelper(c *gin.Context, relayMode int) *dto.OpenAIErrorWithStatusCode { quota := int(imageRatio * groupRatio * common.QuotaPerUnit) if userQuota-quota < 0 { - return service.OpenAIErrorWrapperLocal(errors.New("user quota is not enough"), "insufficient_user_quota", http.StatusForbidden) + return service.OpenAIErrorWrapperLocal(errors.New(fmt.Sprintf("image pre-consumed quota failed, user quota: %d, need quota: %d", userQuota, quota)), "insufficient_user_quota", http.StatusBadRequest) } adaptor := GetAdaptor(relayInfo.ApiType) diff --git a/relay/relay-text.go b/relay/relay-text.go index 7b9f7d9..d5eed40 100644 --- a/relay/relay-text.go +++ b/relay/relay-text.go @@ -247,9 +247,12 @@ func preConsumeQuota(c *gin.Context, preConsumedQuota int, relayInfo *relaycommo if err != nil { return 0, 0, service.OpenAIErrorWrapperLocal(err, "get_user_quota_failed", http.StatusInternalServerError) } - if userQuota <= 0 || userQuota-preConsumedQuota < 0 { + if userQuota <= 0 { return 0, 0, service.OpenAIErrorWrapperLocal(errors.New("user quota is not enough"), "insufficient_user_quota", http.StatusForbidden) } + if userQuota-preConsumedQuota < 0 { + return 0, 0, service.OpenAIErrorWrapperLocal(errors.New(fmt.Sprintf("chat pre-consumed quota failed, user quota: %d, need quota: %d", userQuota, preConsumedQuota)), "insufficient_user_quota", http.StatusBadRequest) + } err = model.CacheDecreaseUserQuota(relayInfo.UserId, preConsumedQuota) if err != nil { return 0, 0, service.OpenAIErrorWrapperLocal(err, "decrease_user_quota_failed", http.StatusInternalServerError) diff --git a/service/error.go b/service/error.go index 3410de8..c760134 100644 --- a/service/error.go +++ b/service/error.go @@ -28,13 +28,11 @@ func MidjourneyErrorWithStatusCodeWrapper(code int, desc string, statusCode int) // OpenAIErrorWrapper wraps an error into an OpenAIErrorWithStatusCode func OpenAIErrorWrapper(err error, code string, statusCode int) *dto.OpenAIErrorWithStatusCode { text := err.Error() - // 定义一个正则表达式匹配URL - if strings.Contains(text, "Post") || strings.Contains(text, "dial") { + lowerText := strings.ToLower(text) + if strings.Contains(lowerText, "post") || strings.Contains(lowerText, "dial") || strings.Contains(lowerText, "http") { common.SysLog(fmt.Sprintf("error: %s", text)) text = "请求上游地址失败" } - //避免暴露内部错误 - openAIError := dto.OpenAIError{ Message: text, Type: "new_api_error", @@ -113,14 +111,12 @@ func TaskErrorWrapperLocal(err error, code string, statusCode int) *dto.TaskErro func TaskErrorWrapper(err error, code string, statusCode int) *dto.TaskError { text := err.Error() - - // 定义一个正则表达式匹配URL - if strings.Contains(text, "Post") || strings.Contains(text, "dial") { + lowerText := strings.ToLower(text) + if strings.Contains(lowerText, "post") || strings.Contains(lowerText, "dial") || strings.Contains(lowerText, "http") { common.SysLog(fmt.Sprintf("error: %s", text)) text = "请求上游地址失败" } //避免暴露内部错误 - taskError := &dto.TaskError{ Code: code, Message: text, diff --git a/web/package.json b/web/package.json index e814d65..3bf290f 100644 --- a/web/package.json +++ b/web/package.json @@ -50,7 +50,7 @@ ] }, "devDependencies": { - "@so1ve/prettier-config": "^2.0.0", + "@so1ve/prettier-config": "^3.1.0", "@vitejs/plugin-react": "^4.2.1", "prettier": "^3.0.0", "typescript": "4.4.2", diff --git a/web/pnpm-lock.yaml b/web/pnpm-lock.yaml index 7b7acd9..644c82e 100644 --- a/web/pnpm-lock.yaml +++ b/web/pnpm-lock.yaml @@ -12,10 +12,10 @@ importers: version: 2.53.2(react@18.2.0) '@douyinfe/semi-ui': specifier: ^2.55.3 - version: 2.55.3(react-dom@18.2.0)(react@18.2.0) + version: 2.55.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@visactor/react-vchart': specifier: ~1.8.8 - version: 1.8.11(react-dom@18.2.0)(react@18.2.0) + version: 1.8.11(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@visactor/vchart': specifier: ~1.8.8 version: 1.8.11 @@ -48,26 +48,26 @@ importers: version: 1.0.4 react-router-dom: specifier: ^6.3.0 - version: 6.22.2(react-dom@18.2.0)(react@18.2.0) + version: 6.22.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react-telegram-login: specifier: ^1.1.2 version: 1.1.2(react@18.2.0) react-toastify: specifier: ^9.0.8 - version: 9.1.3(react-dom@18.2.0)(react@18.2.0) + version: 9.1.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react-turnstile: specifier: ^1.0.5 - version: 1.1.3(react-dom@18.2.0)(react@18.2.0) + version: 1.1.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) semantic-ui-offline: specifier: ^2.5.0 version: 2.5.0 semantic-ui-react: specifier: ^2.1.3 - version: 2.1.5(react-dom@18.2.0)(react@18.2.0) + version: 2.1.5(react-dom@18.2.0(react@18.2.0))(react@18.2.0) devDependencies: '@so1ve/prettier-config': - specifier: ^2.0.0 - version: 2.0.0(prettier@3.2.5) + specifier: ^3.1.0 + version: 3.1.0(prettier@3.2.5) '@vitejs/plugin-react': specifier: ^4.2.1 version: 4.2.1(vite@5.2.5) @@ -89,10 +89,10 @@ packages: } engines: { node: '>=6.0.0' } - '@astrojs/compiler@1.8.2': + '@astrojs/compiler@2.10.2': resolution: { - integrity: sha512-o/ObKgtMzl8SlpIdzaxFnt7SATKPxu4oIP/1NL+HDJRzxfJcAkOTAb/ZKMRyULbz4q+1t2/DAebs2Z1QairkZw==, + integrity: sha512-bvH+v8AirwpRWCkYJEyWYdc5Cs/BjG2ZTxIJzttHilXgfKJAdW2496KsUQKzf5j2tOHtaHXKKn9hb9WZiBGpEg==, } '@babel/code-frame@7.23.5': @@ -873,18 +873,18 @@ packages: react: ^16.0.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0 - '@so1ve/prettier-config@2.0.0': + '@so1ve/prettier-config@3.1.0': resolution: { - integrity: sha512-s6qsH5Rf4Bl+J0LU9rKmSWe/rYRdsYw0ELyXhDDDqEaTWtah4NpHKJuVWARuKqj0TWLBeWmyWUoIH/Bkp/DHaw==, + integrity: sha512-9GJ1yXKBC4DzqCTTaZoBf8zw7WWkVuXcccZt1Aqk4lj6ab/GiNUnjPGajUVYLjaqAEOKqM7jUSUfTjk2JTjCAg==, } peerDependencies: prettier: ^3.0.0 - '@so1ve/prettier-plugin-toml@2.0.0': + '@so1ve/prettier-plugin-toml@3.1.0': resolution: { - integrity: sha512-GvuFdTqhs3qxbhKTiCXWMXITmNLSdndUp7ql1yJbzzWaGqAdb3UH+R+0ZhtAEctBSx90MWAWW3kkW/Iba02tCg==, + integrity: sha512-8WZAGjAVNIJlkfWL6wHKxlUuEBY45fdd5qY5bR/Z6r/txgzKXk/r9qi1DTwc17gi/WcNuRrcRugecRT+mWbIYg==, } peerDependencies: prettier: ^3.0.0 @@ -1887,17 +1887,17 @@ packages: } hasBin: true - prettier-plugin-astro@0.13.0: + prettier-plugin-astro@0.14.1: resolution: { - integrity: sha512-5HrJNnPmZqTUNoA97zn4gNQv9BgVhv+et03314WpQ9H9N8m2L9OSV798olwmG2YLXPl1iSstlJCR1zB3x5xG4g==, + integrity: sha512-RiBETaaP9veVstE4vUwSIcdATj6dKmXljouXc/DDNwBSPTp8FRkLGDSGFClKsAFeeg+13SB0Z1JZvbD76bigJw==, } engines: { node: ^14.15.0 || >=16.0.0 } - prettier-plugin-curly-and-jsdoc@2.0.0: + prettier-plugin-curly-and-jsdoc@3.1.0: resolution: { - integrity: sha512-uSjWOWmX8+yrCrfhJSI58ODqtX7lXx07M8JYeOC1hfRv+vCttfiDlZoM27mNChGitJNKI+pCBvMMBYh8JiV0HQ==, + integrity: sha512-4QMOHnLlkP2jTRWS0MFH6j+cuOiXLvXOqCLKbtwwVd8PPyq8NenW5AAwfwqiTNHBQG/DmzViPphRrwgN0XkUVQ==, } peerDependencies: prettier: ^3.0.0 @@ -2417,7 +2417,7 @@ snapshots: '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.24 - '@astrojs/compiler@1.8.2': {} + '@astrojs/compiler@2.10.2': {} '@babel/code-frame@7.23.5': dependencies: @@ -2565,7 +2565,7 @@ snapshots: react: 18.2.0 tslib: 2.6.2 - '@dnd-kit/core@6.1.0(react-dom@18.2.0)(react@18.2.0)': + '@dnd-kit/core@6.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@dnd-kit/accessibility': 3.1.0(react@18.2.0) '@dnd-kit/utilities': 3.2.2(react@18.2.0) @@ -2573,9 +2573,9 @@ snapshots: react-dom: 18.2.0(react@18.2.0) tslib: 2.6.2 - '@dnd-kit/sortable@7.0.2(@dnd-kit/core@6.1.0)(react@18.2.0)': + '@dnd-kit/sortable@7.0.2(@dnd-kit/core@6.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react@18.2.0)': dependencies: - '@dnd-kit/core': 6.1.0(react-dom@18.2.0)(react@18.2.0) + '@dnd-kit/core': 6.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@dnd-kit/utilities': 3.2.2(react@18.2.0) react: 18.2.0 tslib: 2.6.2 @@ -2627,10 +2627,10 @@ snapshots: dependencies: glob: 7.2.3 - '@douyinfe/semi-ui@2.55.3(react-dom@18.2.0)(react@18.2.0)': + '@douyinfe/semi-ui@2.55.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: - '@dnd-kit/core': 6.1.0(react-dom@18.2.0)(react@18.2.0) - '@dnd-kit/sortable': 7.0.2(@dnd-kit/core@6.1.0)(react@18.2.0) + '@dnd-kit/core': 6.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@dnd-kit/sortable': 7.0.2(@dnd-kit/core@6.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react@18.2.0) '@dnd-kit/utilities': 3.2.2(react@18.2.0) '@douyinfe/semi-animation': 2.55.3 '@douyinfe/semi-animation-react': 2.55.3 @@ -2648,8 +2648,8 @@ snapshots: prop-types: 15.8.1 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - react-resizable: 3.0.5(react-dom@18.2.0)(react@18.2.0) - react-window: 1.8.10(react-dom@18.2.0)(react@18.2.0) + react-resizable: 3.0.5(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + react-window: 1.8.10(react-dom@18.2.0(react@18.2.0))(react@18.2.0) scroll-into-view-if-needed: 2.2.31 utility-types: 3.11.0 @@ -2722,13 +2722,13 @@ snapshots: '@esbuild/win32-x64@0.20.2': optional: true - '@fluentui/react-component-event-listener@0.63.1(react-dom@18.2.0)(react@18.2.0)': + '@fluentui/react-component-event-listener@0.63.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.24.0 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - '@fluentui/react-component-ref@0.63.1(react-dom@18.2.0)(react@18.2.0)': + '@fluentui/react-component-ref@0.63.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.24.0 react: 18.2.0 @@ -2846,22 +2846,22 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.13.0': optional: true - '@semantic-ui-react/event-stack@3.1.3(react-dom@18.2.0)(react@18.2.0)': + '@semantic-ui-react/event-stack@3.1.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: exenv: 1.2.2 prop-types: 15.8.1 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - '@so1ve/prettier-config@2.0.0(prettier@3.2.5)': + '@so1ve/prettier-config@3.1.0(prettier@3.2.5)': dependencies: - '@so1ve/prettier-plugin-toml': 2.0.0(prettier@3.2.5) + '@so1ve/prettier-plugin-toml': 3.1.0(prettier@3.2.5) prettier: 3.2.5 - prettier-plugin-astro: 0.13.0 - prettier-plugin-curly-and-jsdoc: 2.0.0(prettier@3.2.5) + prettier-plugin-astro: 0.14.1 + prettier-plugin-curly-and-jsdoc: 3.1.0(prettier@3.2.5) prettier-plugin-pkgsort: 0.2.1(prettier@3.2.5) - '@so1ve/prettier-plugin-toml@2.0.0(prettier@3.2.5)': + '@so1ve/prettier-plugin-toml@3.1.0(prettier@3.2.5)': dependencies: prettier: 3.2.5 @@ -2926,7 +2926,7 @@ snapshots: '@types/parse-json@4.0.2': {} - '@visactor/react-vchart@1.8.11(react-dom@18.2.0)(react@18.2.0)': + '@visactor/react-vchart@1.8.11(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@visactor/vchart': 1.8.11 '@visactor/vgrammar-core': 0.10.11 @@ -3503,13 +3503,13 @@ snapshots: sort-object-keys: 1.1.3 sort-order: 1.1.2 - prettier-plugin-astro@0.13.0: + prettier-plugin-astro@0.14.1: dependencies: - '@astrojs/compiler': 1.8.2 + '@astrojs/compiler': 2.10.2 prettier: 3.2.5 sass-formatter: 0.7.9 - prettier-plugin-curly-and-jsdoc@2.0.0(prettier@3.2.5): + prettier-plugin-curly-and-jsdoc@3.1.0(prettier@3.2.5): dependencies: prettier: 3.2.5 @@ -3534,7 +3534,7 @@ snapshots: react: 18.2.0 scheduler: 0.23.0 - react-draggable@4.4.6(react-dom@18.2.0)(react@18.2.0): + react-draggable@4.4.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: clsx: 1.2.1 prop-types: 15.8.1 @@ -3556,7 +3556,7 @@ snapshots: react-is@18.2.0: {} - react-popper@2.3.0(@popperjs/core@2.11.8)(react-dom@18.2.0)(react@18.2.0): + react-popper@2.3.0(@popperjs/core@2.11.8)(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@popperjs/core': 2.11.8 react: 18.2.0 @@ -3566,15 +3566,15 @@ snapshots: react-refresh@0.14.0: {} - react-resizable@3.0.5(react-dom@18.2.0)(react@18.2.0): + react-resizable@3.0.5(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: prop-types: 15.8.1 react: 18.2.0 - react-draggable: 4.4.6(react-dom@18.2.0)(react@18.2.0) + react-draggable: 4.4.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0) transitivePeerDependencies: - react-dom - react-router-dom@6.22.2(react-dom@18.2.0)(react@18.2.0): + react-router-dom@6.22.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@remix-run/router': 1.15.2 react: 18.2.0 @@ -3590,18 +3590,18 @@ snapshots: dependencies: react: 18.2.0 - react-toastify@9.1.3(react-dom@18.2.0)(react@18.2.0): + react-toastify@9.1.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: clsx: 1.2.1 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - react-turnstile@1.1.3(react-dom@18.2.0)(react@18.2.0): + react-turnstile@1.1.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - react-window@1.8.10(react-dom@18.2.0)(react@18.2.0): + react-window@1.8.10(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.24.0 memoize-one: 5.2.1 @@ -3683,13 +3683,13 @@ snapshots: fs-extra: 4.0.3 jquery: 3.7.1 - semantic-ui-react@2.1.5(react-dom@18.2.0)(react@18.2.0): + semantic-ui-react@2.1.5(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.24.0 - '@fluentui/react-component-event-listener': 0.63.1(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-component-ref': 0.63.1(react-dom@18.2.0)(react@18.2.0) + '@fluentui/react-component-event-listener': 0.63.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@fluentui/react-component-ref': 0.63.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@popperjs/core': 2.11.8 - '@semantic-ui-react/event-stack': 3.1.3(react-dom@18.2.0)(react@18.2.0) + '@semantic-ui-react/event-stack': 3.1.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) clsx: 1.2.1 keyboard-key: 1.1.0 lodash: 4.17.21 @@ -3698,7 +3698,7 @@ snapshots: react: 18.2.0 react-dom: 18.2.0(react@18.2.0) react-is: 18.2.0 - react-popper: 2.3.0(@popperjs/core@2.11.8)(react-dom@18.2.0)(react@18.2.0) + react-popper: 2.3.0(@popperjs/core@2.11.8)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) shallowequal: 1.1.0 semver@6.3.1: {} diff --git a/web/src/components/ChannelsTable.js b/web/src/components/ChannelsTable.js index b297921..e771edc 100644 --- a/web/src/components/ChannelsTable.js +++ b/web/src/components/ChannelsTable.js @@ -749,7 +749,8 @@ const ChannelsTable = () => {