package api import ( "fmt" "image" "log" "os" "reflect" "regexp" "sort" "strings" "time" _ "github.com/doug-martin/goqu/v9/dialect/mysql" "github.com/graphql-go/graphql" "github.com/graphql-go/graphql/language/ast" "github.com/spf13/viper" "github.com/thoas/go-funk" "gorm.io/driver/mysql" "gorm.io/gorm" ) var db *gorm.DB var err error func InitDefault(config *viper.Viper) { if db, err = gorm.Open(mysql.Open(fmt.Sprintf( "%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local", config.GetString("mysql.user"), config.GetString("mysql.password"), config.GetString("mysql.host"), config.GetInt("mysql.port"), config.GetString("mysql.database"), )), &gorm.Config{}); err != nil { log.Fatal("failed to connect to database:", err) } } func ParseToken(token string) (user_id int) { if err := db.Table("web_auth").Select("user_id").Where("token = ?", token).Scan(&user_id).Error; err != nil { fmt.Println("token解析失败", err) } return user_id } // 定时检查补全颜色字段 func CheckColorNullRows(offset int) { for { time.Sleep(1 * time.Second) var list []struct { ID int Content string } fmt.Println("跳过的行数:", offset) if err := db.Table("web_images").Select("id", "content").Where("article_category_top_id = 22").Where("color_0_r IS NULL").Offset(offset).Limit(100).Scan(&list).Error; err != nil { fmt.Println("定时检查补全颜色字段查询失败", err) continue } for index, item := range list { matches := regexp.MustCompile(`^https?://image\.gameuiux\.cn/(.*)`).FindStringSubmatch(item.Content) if len(matches) < 2 { fmt.Println("转换路径失败", index, item.ID, item.Content) continue } // 打开图像文件 filepath := "oss/" + matches[1] file, err := os.Open(filepath) if err != nil { fmt.Println("打开文件失败", index, item.ID, item.Content, err) offset++ continue } defer file.Close() // 解码 JPEG 图像 img, _, err := image.Decode(file) if err != nil { fmt.Println("解码图像失败", index, item.ID, item.Content, err) continue } k := 8 centers, labels := KMeans(extractColors(img), k) // 将聚类中心和颜色数量结合,并按颜色数量降序排序 type cluster struct { center RGB count int } clusters := make([]cluster, k) for i := 0; i < k; i++ { clusters[i] = cluster{center: centers[i], count: 0} } // 统计每个聚类的颜色数量 for _, label := range labels { clusters[label].count++ } // 按颜色数量降序排序 sort.Slice(clusters, func(i, j int) bool { return clusters[i].count > clusters[j].count }) // 返回排序后的聚类中心 sortedCenters := make([]RGB, k) for i, c := range clusters { sortedCenters[i] = c.center } //fmt.Println("聚类后的颜色数量:", clusters) if err := db.Table("web_images").Where("id = ?", item.ID).Updates(map[string]interface{}{ "color_0_r": sortedCenters[0].R, "color_0_g": sortedCenters[0].G, "color_0_b": sortedCenters[0].B, "color_1_r": sortedCenters[1].R, "color_1_g": sortedCenters[1].G, "color_1_b": sortedCenters[1].B, }).Error; err != nil { fmt.Println("更新颜色字段失败", index, item.ID, item.Content, err) continue } fmt.Println("更新颜色索引:", item.ID, filepath) } } } // 获取所有字段名 func LoadItem(requestedFields []ast.Selection) (data []string) { var items = []string{"user", "article"} for _, field := range requestedFields { fieldAST, _ := field.(*ast.Field) if funk.Contains(items, fieldAST.Name.Value) { name := fieldAST.Name.Value name = strings.ToUpper(string(name[0])) + name[1:] data = append(data, name) for _, str := range LoadItem(fieldAST.SelectionSet.Selections) { data = append(data, name+"."+str) } } if fieldAST.Name.Value == "list" { for _, str := range LoadItem(fieldAST.SelectionSet.Selections) { data = append(data, str) } } } return data } // 自动生成 GraphQL 类型的函数 func generateGraphQLType(model interface{}) (*graphql.Object, error) { modelType := reflect.TypeOf(model) if modelType.Kind() != reflect.Struct { return nil, fmt.Errorf("model must be a struct") } fields := graphql.Fields{} for i := 0; i < modelType.NumField(); i++ { field := modelType.Field(i) fieldType := graphql.String // 默认使用字符串类型 // 这里可以根据需要添加更多类型映射 switch field.Type.Kind() { case reflect.String: fieldType = graphql.String case reflect.Int: fieldType = graphql.Int case reflect.Bool: fieldType = graphql.Boolean } fields[field.Name] = &graphql.Field{ Type: fieldType, } } return graphql.NewObject(graphql.ObjectConfig{ Name: modelType.Name(), Fields: fields, }), nil } // 判断指定字段是否存在 func existField(selections []ast.Selection, name string) bool { for _, field := range selections { if f, ok := field.(*ast.Field); ok && f.Name.Value == name { return true } } return false } // 将 list 中的字段提取出来用于查询 func get_fields(requestedFields []ast.Selection) (fields []string) { for _, field := range requestedFields { fieldAST, _ := field.(*ast.Field) if fieldAST.Name.Value == "list" { for _, field := range fieldAST.SelectionSet.Selections { fieldAST, _ := field.(*ast.Field) if fieldAST.Name.Value == "text_count" { continue } fields = append(fields, fieldAST.Name.Value) } } } return fields } var orderType = graphql.NewEnum(graphql.EnumConfig{ Name: "OrderType", Description: "排序类型", Values: graphql.EnumValueConfigMap{ "ASC": &graphql.EnumValueConfig{ Value: "ASC", Description: "升序", }, "DESC": &graphql.EnumValueConfig{ Value: "DESC", Description: "降序", }, }, })