Files
webp/api/graphql.go
2024-12-28 05:44:25 +08:00

244 lines
6.2 KiB
Go

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(60 * 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)
}
}
}
// 获取 List 中的所有字段名
func ListItem(requestedFields []ast.Selection) (data []string) {
for _, field := range requestedFields {
fieldAST, _ := field.(*ast.Field)
if fieldAST.Name.Value == "list" {
for _, field := range fieldAST.SelectionSet.Selections {
data = append(data, field.(*ast.Field).Name.Value)
}
}
}
return data
}
// 获取所有字段名
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 GraphQLType(model interface{}) *graphql.Object {
modelType := reflect.TypeOf(model)
if modelType.Kind() != reflect.Struct {
fmt.Println("输入的类型必须是结构体")
return nil
}
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,
})
}
// 判断指定字段是否存在
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: "降序",
},
},
})
type Cache struct {
time time.Time
ids []string
}
var cache map[string]Cache = make(map[string]Cache)