├── ent ├── doc.go ├── runtime │ └── runtime.go ├── predicate │ └── predicate.go ├── schema │ ├── base.go │ ├── taskdetail.go │ ├── account.go │ ├── setting.go │ └── task.go ├── enttest │ └── enttest.go ├── task_delete.go ├── account_delete.go ├── setting_delete.go ├── migrate │ └── migrate.go ├── baseschema │ └── baseschema.go ├── baseschema_delete.go ├── taskdetail_delete.go ├── taskdetail │ └── taskdetail.go ├── baseschema.go ├── account │ └── account.go ├── setting │ └── setting.go ├── taskdetail.go ├── account.go └── setting.go ├── service ├── etc │ ├── gallery-api.yaml │ ├── application-dev.yaml │ └── application-prod.yaml ├── internal │ ├── model │ │ ├── model.go │ │ ├── constants.go │ │ └── enums.go │ ├── handler │ │ ├── base │ │ │ └── pinghandler.go │ │ ├── work │ │ │ ├── gettasksizehandler.go │ │ │ ├── gettaskauthorhandler.go │ │ │ ├── gettaskmodelhandler.go │ │ │ ├── gettaskhandler.go │ │ │ ├── getworkhandler.go │ │ │ ├── getworkdetailhandler.go │ │ │ └── markworkexcellenthandler.go │ │ ├── setting │ │ │ ├── getsettinghandler.go │ │ │ └── updatesettinghandler.go │ │ ├── account │ │ │ ├── getuserdetailhandler.go │ │ │ ├── adduserhandler.go │ │ │ ├── resetpwdhandler.go │ │ │ ├── deleteuserhandler.go │ │ │ ├── getuserhandler.go │ │ │ ├── updateuserhandler.go │ │ │ └── updateuserdetailhandler.go │ │ ├── analysis │ │ │ ├── getanalysisbasehandler.go │ │ │ ├── getanalysistaskhandler.go │ │ │ └── getanalysisuserhandler.go │ │ ├── task │ │ │ ├── updatetaskhandler.go │ │ │ ├── createtaskhandler.go │ │ │ └── createsubtaskhandler.go │ │ ├── anonymous │ │ │ └── authloginhandler.go │ │ └── routes.go │ ├── svc │ │ └── servicecontext.go │ ├── logic │ │ ├── base │ │ │ └── pinglogic.go │ │ ├── basic │ │ │ ├── upload │ │ │ │ ├── local.go │ │ │ │ ├── cos.go │ │ │ │ ├── oss.go │ │ │ │ └── upload.go │ │ │ └── common.go │ │ ├── account │ │ │ ├── deleteuserlogic.go │ │ │ ├── getuserdetaillogic.go │ │ │ ├── resetpwdlogic.go │ │ │ ├── adduserlogic.go │ │ │ ├── updateuserlogic.go │ │ │ ├── updateuserdetaillogic.go │ │ │ └── getuserlogic.go │ │ ├── setting │ │ │ ├── getsettinglogic.go │ │ │ └── updatesettinglogic.go │ │ ├── work │ │ │ ├── gettaskauthorlogic.go │ │ │ ├── gettasksizelogic.go │ │ │ ├── gettaskmodellogic.go │ │ │ ├── markworkexcellentlogic.go │ │ │ ├── getworkdetaillogic.go │ │ │ ├── getworklogic.go │ │ │ └── gettasklogic.go │ │ ├── anonymous │ │ │ └── authloginlogic.go │ │ ├── task │ │ │ ├── createsubtasklogic.go │ │ │ ├── updatetasklogic.go │ │ │ └── createtasklogic.go │ │ └── analysis │ │ │ ├── getanalysisuserlogic.go │ │ │ ├── getanalysistasklogic.go │ │ │ └── getanalysisbaselogic.go │ ├── config │ │ └── config.go │ ├── cron │ │ ├── jobs │ │ │ └── task.go │ │ └── cron.go │ ├── dao │ │ ├── dao.go │ │ ├── account │ │ │ └── account.go │ │ ├── task │ │ │ └── task.go │ │ └── setting │ │ │ └── setting.go │ ├── middleware │ │ ├── jwtmiddleware.go │ │ ├── corsmiddleware.go │ │ ├── headersmiddleware.go │ │ └── managejwtmiddleware.go │ └── errors │ │ └── errors.go └── gallery.go ├── wechat.png ├── cmd ├── main.go └── actions │ ├── root.go │ ├── http.go │ └── migrate.go ├── api ├── base.api ├── anonymous.api ├── setting.api ├── analysis.api ├── task.api ├── account.api └── work.api ├── .gitignore ├── Makefile ├── pkg ├── utils │ └── utils.go ├── jwt │ └── jwt.go └── errgroup │ └── errgroup.go ├── .goctl └── 1.6.3 │ └── api │ └── handler.tpl ├── go.mod ├── README_zh.md ├── sql └── sql.sql └── README.md /ent/doc.go: -------------------------------------------------------------------------------- 1 | package ent 2 | -------------------------------------------------------------------------------- /service/etc/gallery-api.yaml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /service/internal/model/model.go: -------------------------------------------------------------------------------- 1 | package model 2 | -------------------------------------------------------------------------------- /wechat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tabelf/ai-gallery/HEAD/wechat.png -------------------------------------------------------------------------------- /cmd/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "ai-gallery/cmd/actions" 4 | 5 | func main() { 6 | actions.Execute() 7 | } 8 | -------------------------------------------------------------------------------- /service/internal/model/constants.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | const ( 4 | DateStrLayout = "20060102150405" 5 | 6 | PwdSalt = "0813" // 盐 7 | 8 | Admin = "admin" // 管理员账号 9 | 10 | InitPwd = "1234567" 11 | 12 | LocalAddress = "http://127.0.0.1:8080/upload" 13 | 14 | UserToken = "user_token" 15 | ) 16 | -------------------------------------------------------------------------------- /ent/runtime/runtime.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package runtime 4 | 5 | // The schema-stitching logic is generated in ai-gallery/ent/runtime.go 6 | 7 | const ( 8 | Version = "v0.13.1" // Version of ent codegen. 9 | Sum = "h1:uD8QwN1h6SNphdCCzmkMN3feSUzNnVvV/WIkHKMbzOE=" // Sum of ent codegen. 10 | ) 11 | -------------------------------------------------------------------------------- /cmd/actions/root.go: -------------------------------------------------------------------------------- 1 | package actions 2 | 3 | import ( 4 | "log" 5 | "os" 6 | 7 | "github.com/spf13/cobra" 8 | ) 9 | 10 | var ( 11 | rootCmd = &cobra.Command{} 12 | ) 13 | 14 | func init() { 15 | rootCmd.PersistentFlags().String("env", os.Getenv("ENV"), "environment. eg: dev, prod") 16 | } 17 | 18 | func Execute() { 19 | if err := rootCmd.Execute(); err != nil { 20 | log.Fatal(err) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /api/base.api: -------------------------------------------------------------------------------- 1 | syntax = "v1" 2 | 3 | import ( 4 | "task.api" 5 | "anonymous.api" 6 | "account.api" 7 | "analysis.api" 8 | "work.api" 9 | "setting.api" 10 | ) 11 | 12 | info ( 13 | title: "base api" 14 | desc: "基础接口" 15 | ) 16 | 17 | type PingResp { 18 | Message string `json:"message"` 19 | } 20 | 21 | @server ( 22 | group: base 23 | ) 24 | service gallery-api { 25 | @doc ( 26 | summary: "心跳检查" 27 | ) 28 | @handler Ping 29 | get /api/base/ping returns (PingResp) 30 | } 31 | 32 | -------------------------------------------------------------------------------- /cmd/actions/http.go: -------------------------------------------------------------------------------- 1 | package actions 2 | 3 | import ( 4 | "log" 5 | 6 | "ai-gallery/service" 7 | 8 | "github.com/spf13/cobra" 9 | ) 10 | 11 | func init() { 12 | command := &cobra.Command{ 13 | Use: "start", 14 | Run: Run, 15 | } 16 | rootCmd.AddCommand(command) 17 | } 18 | 19 | func Run(cmd *cobra.Command, args []string) { 20 | env, err := cmd.Flags().GetString("env") 21 | if err != nil { 22 | log.Fatalf("get env failed: %v\n", err) 23 | } 24 | service.StartHTTP(env) 25 | } 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, built with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | # Dependency directories (remove the comment below to include it) 15 | # vendor/ 16 | 17 | # IDE 18 | .idea/ 19 | .vscode/ 20 | *.swp 21 | 22 | # Go 23 | go.work 24 | go.work.sum 25 | 26 | # project 27 | *.cert 28 | *.key 29 | *.log 30 | bin/ 31 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | api = "./api/base.api" 2 | api_output = "./service" 3 | api_template = ".goctl/1.6.3" 4 | 5 | .PHONY:api sql 6 | 7 | api: 8 | goctl api go --home ${api_template} --api ${api} --dir ${api_output} 9 | 10 | generate_input = "./ent/schema" 11 | generate_output = "./ent" 12 | 13 | # 出现root package or module was not found for: gen/entschema 必须先任意创建一个go文件占位 14 | sql: 15 | go install entgo.io/ent/cmd/ent@v0.13.1 16 | ent generate --feature sql/upsert --target ${generate_output} ${generate_input} 17 | -------------------------------------------------------------------------------- /pkg/utils/utils.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | func ParseYMD(timestamp string) (time.Time, error) { 8 | t, err := time.Parse(time.DateOnly, timestamp) 9 | if err != nil { 10 | return t, err 11 | } 12 | return t, nil 13 | } 14 | 15 | func FirstTime(t time.Time) time.Time { 16 | return time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location()) 17 | } 18 | 19 | func LastTime(t time.Time) time.Time { 20 | return time.Date(t.Year(), t.Month(), t.Day(), 23, 59, 59, 0, t.Location()) 21 | } 22 | -------------------------------------------------------------------------------- /service/etc/application-dev.yaml: -------------------------------------------------------------------------------- 1 | Name: ai-gallery-api 2 | Host: 0.0.0.0 3 | Port: 8888 4 | Timeout: 180000 # 3分钟 5 | MaxBytes: 10485760 # 10M 6 | 7 | logger: 8 | service_name: ai-gallery 9 | mode: console 10 | encoding: json 11 | Path: logs 12 | Level: debug 13 | 14 | jwt: 15 | jwt_key: 1218f4ee35ef6be1590c7395503644a1 16 | jwt_expire: 2592000 # 秒(30天) 17 | jwt_issuer: ai-gallery 18 | 19 | db: 20 | url: root:12345678@(127.0.0.1:3306)/ai_gallery?charset=utf8mb4&parseTime=true&loc=Local&interpolateParams=true 21 | driver: mysql 22 | max_open_conns: 100 23 | max_idle_conns: 30 24 | -------------------------------------------------------------------------------- /service/internal/handler/base/pinghandler.go: -------------------------------------------------------------------------------- 1 | package base 2 | 3 | import ( 4 | "net/http" 5 | 6 | "ai-gallery/service/internal/errors" 7 | "ai-gallery/service/internal/logic/base" 8 | "ai-gallery/service/internal/svc" 9 | 10 | "github.com/zeromicro/go-zero/rest/httpx" 11 | ) 12 | 13 | func PingHandler(ctx *svc.ServiceContext) http.HandlerFunc { 14 | return func(w http.ResponseWriter, r *http.Request) { 15 | l := base.NewPingLogic(r.Context(), ctx) 16 | resp, err := l.Ping() 17 | if err != nil { 18 | errors.HandleResponseError(w, err) 19 | } else { 20 | httpx.OkJson(w, resp) 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /service/etc/application-prod.yaml: -------------------------------------------------------------------------------- 1 | Name: ai-gallery-api 2 | Host: 0.0.0.0 3 | Port: 8888 4 | Timeout: 180000 # 3分钟 5 | MaxBytes: 10485760 # 10M 6 | 7 | logger: 8 | service_name: ai-gallery 9 | mode: file 10 | encoding: json 11 | Path: logs 12 | Level: debug 13 | KeepDays: 30 14 | Rotation: daily 15 | 16 | jwt: 17 | jwt_key: 392b3436fba28bc99a06eeb5620d8520 18 | jwt_expire: 2592000 # 秒(30天) 19 | jwt_issuer: ai-gallery 20 | 21 | db: 22 | url: root:12345678@(127.0.0.1:3306)/ai_gallery?charset=utf8mb4&parseTime=true&loc=Local&interpolateParams=true 23 | driver: mysql 24 | max_open_conns: 100 25 | max_idle_conns: 30 26 | -------------------------------------------------------------------------------- /api/anonymous.api: -------------------------------------------------------------------------------- 1 | syntax = "v1" 2 | 3 | info ( 4 | title: "匿名接口" 5 | version: "v1.0" 6 | ) 7 | 8 | @server ( 9 | group: anonymous 10 | ) 11 | service gallery-api { 12 | @doc ( 13 | summary: "用户登录" 14 | ) 15 | @handler AuthLogin 16 | post /api/v1/anonymous/login (AuthLoginRequest) returns (AuthLoginResponse) 17 | } 18 | 19 | type AuthLoginRequest { 20 | Username string `json:"username"` 21 | Password string `json:"password"` 22 | } 23 | 24 | type AuthLoginResponse { 25 | UserID int `json:"user_id"` 26 | Username string `json:"username"` 27 | Role string `json:"role"` 28 | Token string `json:"token"` 29 | } 30 | 31 | -------------------------------------------------------------------------------- /service/internal/handler/work/gettasksizehandler.go: -------------------------------------------------------------------------------- 1 | package work 2 | 3 | import ( 4 | "net/http" 5 | 6 | "ai-gallery/service/internal/errors" 7 | "ai-gallery/service/internal/logic/work" 8 | "ai-gallery/service/internal/svc" 9 | 10 | "github.com/zeromicro/go-zero/rest/httpx" 11 | ) 12 | 13 | func GetTaskSizeHandler(ctx *svc.ServiceContext) http.HandlerFunc { 14 | return func(w http.ResponseWriter, r *http.Request) { 15 | l := work.NewGetTaskSizeLogic(r.Context(), ctx) 16 | resp, err := l.GetTaskSize() 17 | if err != nil { 18 | errors.HandleResponseError(w, err) 19 | } else { 20 | httpx.OkJson(w, resp) 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /service/internal/handler/setting/getsettinghandler.go: -------------------------------------------------------------------------------- 1 | package setting 2 | 3 | import ( 4 | "net/http" 5 | 6 | "ai-gallery/service/internal/errors" 7 | "ai-gallery/service/internal/logic/setting" 8 | "ai-gallery/service/internal/svc" 9 | 10 | "github.com/zeromicro/go-zero/rest/httpx" 11 | ) 12 | 13 | func GetSettingHandler(ctx *svc.ServiceContext) http.HandlerFunc { 14 | return func(w http.ResponseWriter, r *http.Request) { 15 | l := setting.NewGetSettingLogic(r.Context(), ctx) 16 | resp, err := l.GetSetting() 17 | if err != nil { 18 | errors.HandleResponseError(w, err) 19 | } else { 20 | httpx.OkJson(w, resp) 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /service/internal/handler/work/gettaskauthorhandler.go: -------------------------------------------------------------------------------- 1 | package work 2 | 3 | import ( 4 | "net/http" 5 | 6 | "ai-gallery/service/internal/errors" 7 | "ai-gallery/service/internal/logic/work" 8 | "ai-gallery/service/internal/svc" 9 | 10 | "github.com/zeromicro/go-zero/rest/httpx" 11 | ) 12 | 13 | func GetTaskAuthorHandler(ctx *svc.ServiceContext) http.HandlerFunc { 14 | return func(w http.ResponseWriter, r *http.Request) { 15 | l := work.NewGetTaskAuthorLogic(r.Context(), ctx) 16 | resp, err := l.GetTaskAuthor() 17 | if err != nil { 18 | errors.HandleResponseError(w, err) 19 | } else { 20 | httpx.OkJson(w, resp) 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /service/internal/handler/work/gettaskmodelhandler.go: -------------------------------------------------------------------------------- 1 | package work 2 | 3 | import ( 4 | "net/http" 5 | 6 | "ai-gallery/service/internal/errors" 7 | "ai-gallery/service/internal/logic/work" 8 | "ai-gallery/service/internal/svc" 9 | 10 | "github.com/zeromicro/go-zero/rest/httpx" 11 | ) 12 | 13 | func GetTaskModelHandler(ctx *svc.ServiceContext) http.HandlerFunc { 14 | return func(w http.ResponseWriter, r *http.Request) { 15 | l := work.NewGetTaskModelLogic(r.Context(), ctx) 16 | resp, err := l.GetTaskModel() 17 | if err != nil { 18 | errors.HandleResponseError(w, err) 19 | } else { 20 | httpx.OkJson(w, resp) 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /service/internal/handler/account/getuserdetailhandler.go: -------------------------------------------------------------------------------- 1 | package account 2 | 3 | import ( 4 | "net/http" 5 | 6 | "ai-gallery/service/internal/errors" 7 | "ai-gallery/service/internal/logic/account" 8 | "ai-gallery/service/internal/svc" 9 | 10 | "github.com/zeromicro/go-zero/rest/httpx" 11 | ) 12 | 13 | func GetUserDetailHandler(ctx *svc.ServiceContext) http.HandlerFunc { 14 | return func(w http.ResponseWriter, r *http.Request) { 15 | l := account.NewGetUserDetailLogic(r.Context(), ctx) 16 | resp, err := l.GetUserDetail() 17 | if err != nil { 18 | errors.HandleResponseError(w, err) 19 | } else { 20 | httpx.OkJson(w, resp) 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /service/internal/handler/analysis/getanalysisbasehandler.go: -------------------------------------------------------------------------------- 1 | package analysis 2 | 3 | import ( 4 | "net/http" 5 | 6 | "ai-gallery/service/internal/errors" 7 | "ai-gallery/service/internal/logic/analysis" 8 | "ai-gallery/service/internal/svc" 9 | 10 | "github.com/zeromicro/go-zero/rest/httpx" 11 | ) 12 | 13 | func GetAnalysisBaseHandler(ctx *svc.ServiceContext) http.HandlerFunc { 14 | return func(w http.ResponseWriter, r *http.Request) { 15 | l := analysis.NewGetAnalysisBaseLogic(r.Context(), ctx) 16 | resp, err := l.GetAnalysisBase() 17 | if err != nil { 18 | errors.HandleResponseError(w, err) 19 | } else { 20 | httpx.OkJson(w, resp) 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ent/predicate/predicate.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package predicate 4 | 5 | import ( 6 | "entgo.io/ent/dialect/sql" 7 | ) 8 | 9 | // Account is the predicate function for account builders. 10 | type Account func(*sql.Selector) 11 | 12 | // BaseSchema is the predicate function for baseschema builders. 13 | type BaseSchema func(*sql.Selector) 14 | 15 | // Setting is the predicate function for setting builders. 16 | type Setting func(*sql.Selector) 17 | 18 | // Task is the predicate function for task builders. 19 | type Task func(*sql.Selector) 20 | 21 | // TaskDetail is the predicate function for taskdetail builders. 22 | type TaskDetail func(*sql.Selector) 23 | -------------------------------------------------------------------------------- /service/internal/svc/servicecontext.go: -------------------------------------------------------------------------------- 1 | package svc 2 | 3 | import ( 4 | "ai-gallery/service/internal/config" 5 | "ai-gallery/service/internal/middleware" 6 | 7 | "github.com/zeromicro/go-zero/rest" 8 | ) 9 | 10 | type ServiceContext struct { 11 | Config config.Config 12 | Headers rest.Middleware 13 | JWT rest.Middleware 14 | ManageJWT rest.Middleware 15 | } 16 | 17 | func NewServiceContext(c config.Config) *ServiceContext { 18 | return &ServiceContext{ 19 | Config: c, 20 | Headers: middleware.NewHeadersMiddleware().Handle, 21 | JWT: middleware.NewJWTMiddleware(c.JWT).Handle, 22 | ManageJWT: middleware.NewManageJWTMiddleware(c.JWT).Handle, 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /service/internal/logic/base/pinglogic.go: -------------------------------------------------------------------------------- 1 | package base 2 | 3 | import ( 4 | "context" 5 | 6 | "ai-gallery/service/internal/svc" 7 | "ai-gallery/service/internal/types" 8 | 9 | "github.com/zeromicro/go-zero/core/logx" 10 | ) 11 | 12 | type PingLogic struct { 13 | logx.Logger 14 | ctx context.Context 15 | svcCtx *svc.ServiceContext 16 | } 17 | 18 | func NewPingLogic(ctx context.Context, svcCtx *svc.ServiceContext) *PingLogic { 19 | return &PingLogic{ 20 | Logger: logx.WithContext(ctx), 21 | ctx: ctx, 22 | svcCtx: svcCtx, 23 | } 24 | } 25 | 26 | func (l *PingLogic) Ping() (resp *types.PingResp, err error) { 27 | return &types.PingResp{ 28 | Message: "PONG", 29 | }, nil 30 | } 31 | -------------------------------------------------------------------------------- /service/internal/config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "github.com/zeromicro/go-zero/core/logc" 5 | "github.com/zeromicro/go-zero/rest" 6 | ) 7 | 8 | type Config struct { 9 | rest.RestConf 10 | DB EntConf `json:"db"` 11 | JWT JWTConf `json:"jwt"` 12 | Logger logc.LogConf `json:"logger"` 13 | } 14 | 15 | type EntConf struct { 16 | Driver string `json:"driver"` 17 | URL string `json:"url"` 18 | MaxOpenConns int `json:"max_open_conns"` 19 | MaxIdleConns int `json:"max_idle_conns"` 20 | } 21 | 22 | type JWTConf struct { 23 | JwtKey string `json:"jwt_key"` 24 | JwtExpire int64 `json:"jwt_expire"` 25 | JwtIssuer string `json:"jwt_issuer"` 26 | } 27 | -------------------------------------------------------------------------------- /service/internal/logic/basic/upload/local.go: -------------------------------------------------------------------------------- 1 | package basic 2 | 3 | import ( 4 | "context" 5 | "io" 6 | ) 7 | 8 | type LocalService struct { 9 | URL string `json:"url"` 10 | SecretID string `json:"secret_id"` 11 | SecretKey string `json:"secret_key"` 12 | Bucket string `json:"bucket"` 13 | } 14 | 15 | func NewLocalService() *LocalService { 16 | return &LocalService{} 17 | } 18 | 19 | func (c *LocalService) SetConfig(url, secretID, secretKey, bucket string) { 20 | c.URL = url 21 | c.SecretID = secretID 22 | c.SecretKey = secretKey 23 | c.Bucket = bucket 24 | } 25 | 26 | func (c *LocalService) Put(ctx context.Context, name string, r io.Reader, options ...any) ( 27 | path string, err error, 28 | ) { 29 | return c.URL + "/" + name, nil 30 | } 31 | -------------------------------------------------------------------------------- /service/internal/handler/account/adduserhandler.go: -------------------------------------------------------------------------------- 1 | package account 2 | 3 | import ( 4 | "net/http" 5 | 6 | "ai-gallery/service/internal/errors" 7 | "ai-gallery/service/internal/logic/account" 8 | "ai-gallery/service/internal/svc" 9 | "ai-gallery/service/internal/types" 10 | 11 | "github.com/zeromicro/go-zero/rest/httpx" 12 | ) 13 | 14 | func AddUserHandler(ctx *svc.ServiceContext) http.HandlerFunc { 15 | return func(w http.ResponseWriter, r *http.Request) { 16 | var req types.AddUserRequest 17 | if err := httpx.Parse(r, &req); err != nil { 18 | httpx.Error(w, err) 19 | return 20 | } 21 | 22 | l := account.NewAddUserLogic(r.Context(), ctx) 23 | err := l.AddUser(&req) 24 | if err != nil { 25 | errors.HandleResponseError(w, err) 26 | } else { 27 | httpx.Ok(w) 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /service/internal/handler/task/updatetaskhandler.go: -------------------------------------------------------------------------------- 1 | package task 2 | 3 | import ( 4 | "net/http" 5 | 6 | "ai-gallery/service/internal/errors" 7 | "ai-gallery/service/internal/logic/task" 8 | "ai-gallery/service/internal/svc" 9 | "ai-gallery/service/internal/types" 10 | 11 | "github.com/zeromicro/go-zero/rest/httpx" 12 | ) 13 | 14 | func UpdateTaskHandler(ctx *svc.ServiceContext) http.HandlerFunc { 15 | return func(w http.ResponseWriter, r *http.Request) { 16 | var req types.UpdateTaskReq 17 | if err := httpx.Parse(r, &req); err != nil { 18 | httpx.Error(w, err) 19 | return 20 | } 21 | 22 | l := task.NewUpdateTaskLogic(r.Context(), ctx) 23 | err := l.UpdateTask(&req) 24 | if err != nil { 25 | errors.HandleResponseError(w, err) 26 | } else { 27 | httpx.Ok(w) 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /service/internal/handler/account/resetpwdhandler.go: -------------------------------------------------------------------------------- 1 | package account 2 | 3 | import ( 4 | "net/http" 5 | 6 | "ai-gallery/service/internal/errors" 7 | "ai-gallery/service/internal/logic/account" 8 | "ai-gallery/service/internal/svc" 9 | "ai-gallery/service/internal/types" 10 | 11 | "github.com/zeromicro/go-zero/rest/httpx" 12 | ) 13 | 14 | func ResetPwdHandler(ctx *svc.ServiceContext) http.HandlerFunc { 15 | return func(w http.ResponseWriter, r *http.Request) { 16 | var req types.ResetPwdRequest 17 | if err := httpx.Parse(r, &req); err != nil { 18 | httpx.Error(w, err) 19 | return 20 | } 21 | 22 | l := account.NewResetPwdLogic(r.Context(), ctx) 23 | err := l.ResetPwd(&req) 24 | if err != nil { 25 | errors.HandleResponseError(w, err) 26 | } else { 27 | httpx.Ok(w) 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /service/internal/handler/work/gettaskhandler.go: -------------------------------------------------------------------------------- 1 | package work 2 | 3 | import ( 4 | "net/http" 5 | 6 | "ai-gallery/service/internal/errors" 7 | "ai-gallery/service/internal/logic/work" 8 | "ai-gallery/service/internal/svc" 9 | "ai-gallery/service/internal/types" 10 | 11 | "github.com/zeromicro/go-zero/rest/httpx" 12 | ) 13 | 14 | func GetTaskHandler(ctx *svc.ServiceContext) http.HandlerFunc { 15 | return func(w http.ResponseWriter, r *http.Request) { 16 | var req types.GetTaskRequest 17 | if err := httpx.Parse(r, &req); err != nil { 18 | httpx.Error(w, err) 19 | return 20 | } 21 | 22 | l := work.NewGetTaskLogic(r.Context(), ctx) 23 | resp, err := l.GetTask(&req) 24 | if err != nil { 25 | errors.HandleResponseError(w, err) 26 | } else { 27 | httpx.OkJson(w, resp) 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /service/internal/handler/work/getworkhandler.go: -------------------------------------------------------------------------------- 1 | package work 2 | 3 | import ( 4 | "net/http" 5 | 6 | "ai-gallery/service/internal/errors" 7 | "ai-gallery/service/internal/logic/work" 8 | "ai-gallery/service/internal/svc" 9 | "ai-gallery/service/internal/types" 10 | 11 | "github.com/zeromicro/go-zero/rest/httpx" 12 | ) 13 | 14 | func GetWorkHandler(ctx *svc.ServiceContext) http.HandlerFunc { 15 | return func(w http.ResponseWriter, r *http.Request) { 16 | var req types.GetWorkRequest 17 | if err := httpx.Parse(r, &req); err != nil { 18 | httpx.Error(w, err) 19 | return 20 | } 21 | 22 | l := work.NewGetWorkLogic(r.Context(), ctx) 23 | resp, err := l.GetWork(&req) 24 | if err != nil { 25 | errors.HandleResponseError(w, err) 26 | } else { 27 | httpx.OkJson(w, resp) 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /service/internal/handler/account/deleteuserhandler.go: -------------------------------------------------------------------------------- 1 | package account 2 | 3 | import ( 4 | "net/http" 5 | 6 | "ai-gallery/service/internal/errors" 7 | "ai-gallery/service/internal/logic/account" 8 | "ai-gallery/service/internal/svc" 9 | "ai-gallery/service/internal/types" 10 | 11 | "github.com/zeromicro/go-zero/rest/httpx" 12 | ) 13 | 14 | func DeleteUserHandler(ctx *svc.ServiceContext) http.HandlerFunc { 15 | return func(w http.ResponseWriter, r *http.Request) { 16 | var req types.DeleteUserRequest 17 | if err := httpx.Parse(r, &req); err != nil { 18 | httpx.Error(w, err) 19 | return 20 | } 21 | 22 | l := account.NewDeleteUserLogic(r.Context(), ctx) 23 | err := l.DeleteUser(&req) 24 | if err != nil { 25 | errors.HandleResponseError(w, err) 26 | } else { 27 | httpx.Ok(w) 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /service/internal/handler/account/getuserhandler.go: -------------------------------------------------------------------------------- 1 | package account 2 | 3 | import ( 4 | "net/http" 5 | 6 | "ai-gallery/service/internal/errors" 7 | "ai-gallery/service/internal/logic/account" 8 | "ai-gallery/service/internal/svc" 9 | "ai-gallery/service/internal/types" 10 | 11 | "github.com/zeromicro/go-zero/rest/httpx" 12 | ) 13 | 14 | func GetUserHandler(ctx *svc.ServiceContext) http.HandlerFunc { 15 | return func(w http.ResponseWriter, r *http.Request) { 16 | var req types.GetUserRequest 17 | if err := httpx.Parse(r, &req); err != nil { 18 | httpx.Error(w, err) 19 | return 20 | } 21 | 22 | l := account.NewGetUserLogic(r.Context(), ctx) 23 | resp, err := l.GetUser(&req) 24 | if err != nil { 25 | errors.HandleResponseError(w, err) 26 | } else { 27 | httpx.OkJson(w, resp) 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /service/internal/handler/account/updateuserhandler.go: -------------------------------------------------------------------------------- 1 | package account 2 | 3 | import ( 4 | "net/http" 5 | 6 | "ai-gallery/service/internal/errors" 7 | "ai-gallery/service/internal/logic/account" 8 | "ai-gallery/service/internal/svc" 9 | "ai-gallery/service/internal/types" 10 | 11 | "github.com/zeromicro/go-zero/rest/httpx" 12 | ) 13 | 14 | func UpdateUserHandler(ctx *svc.ServiceContext) http.HandlerFunc { 15 | return func(w http.ResponseWriter, r *http.Request) { 16 | var req types.UpdateUserRequest 17 | if err := httpx.Parse(r, &req); err != nil { 18 | httpx.Error(w, err) 19 | return 20 | } 21 | 22 | l := account.NewUpdateUserLogic(r.Context(), ctx) 23 | err := l.UpdateUser(&req) 24 | if err != nil { 25 | errors.HandleResponseError(w, err) 26 | } else { 27 | httpx.Ok(w) 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /service/internal/handler/task/createtaskhandler.go: -------------------------------------------------------------------------------- 1 | package task 2 | 3 | import ( 4 | "net/http" 5 | 6 | "ai-gallery/service/internal/errors" 7 | "ai-gallery/service/internal/logic/task" 8 | "ai-gallery/service/internal/svc" 9 | "ai-gallery/service/internal/types" 10 | 11 | "github.com/zeromicro/go-zero/rest/httpx" 12 | ) 13 | 14 | func CreateTaskHandler(ctx *svc.ServiceContext) http.HandlerFunc { 15 | return func(w http.ResponseWriter, r *http.Request) { 16 | var req types.CreateTaskReq 17 | if err := httpx.Parse(r, &req); err != nil { 18 | httpx.Error(w, err) 19 | return 20 | } 21 | 22 | l := task.NewCreateTaskLogic(r.Context(), ctx) 23 | resp, err := l.CreateTask(&req) 24 | if err != nil { 25 | errors.HandleResponseError(w, err) 26 | } else { 27 | httpx.OkJson(w, resp) 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /.goctl/1.6.3/api/handler.tpl: -------------------------------------------------------------------------------- 1 | package {{.PkgName}} 2 | 3 | import ( 4 | "net/http" 5 | 6 | "ai-gallery/service/internal/errors" 7 | {{.ImportPackages}} 8 | 9 | "github.com/zeromicro/go-zero/rest/httpx" 10 | ) 11 | 12 | func {{.HandlerName}}(ctx *svc.ServiceContext) http.HandlerFunc { 13 | return func(w http.ResponseWriter, r *http.Request) { 14 | {{if .HasRequest}}var req types.{{.RequestType}} 15 | if err := httpx.Parse(r, &req); err != nil { 16 | httpx.Error(w, err) 17 | return 18 | } 19 | 20 | {{end}}l := {{.LogicName}}.New{{.LogicType}}(r.Context(), ctx) 21 | {{if .HasResp}}resp, {{end}}err := l.{{.Call}}({{if .HasRequest}}&req{{end}}) 22 | if err != nil { 23 | errors.HandleResponseError(w, err) 24 | } else { 25 | {{if .HasResp}}httpx.OkJson(w, resp){{else}}httpx.Ok(w){{end}} 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /service/internal/handler/setting/updatesettinghandler.go: -------------------------------------------------------------------------------- 1 | package setting 2 | 3 | import ( 4 | "net/http" 5 | 6 | "ai-gallery/service/internal/errors" 7 | "ai-gallery/service/internal/logic/setting" 8 | "ai-gallery/service/internal/svc" 9 | "ai-gallery/service/internal/types" 10 | 11 | "github.com/zeromicro/go-zero/rest/httpx" 12 | ) 13 | 14 | func UpdateSettingHandler(ctx *svc.ServiceContext) http.HandlerFunc { 15 | return func(w http.ResponseWriter, r *http.Request) { 16 | var req types.UpdateSettingRequest 17 | if err := httpx.Parse(r, &req); err != nil { 18 | httpx.Error(w, err) 19 | return 20 | } 21 | 22 | l := setting.NewUpdateSettingLogic(r.Context(), ctx) 23 | err := l.UpdateSetting(&req) 24 | if err != nil { 25 | errors.HandleResponseError(w, err) 26 | } else { 27 | httpx.Ok(w) 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /service/internal/handler/task/createsubtaskhandler.go: -------------------------------------------------------------------------------- 1 | package task 2 | 3 | import ( 4 | "net/http" 5 | 6 | "ai-gallery/service/internal/errors" 7 | "ai-gallery/service/internal/logic/task" 8 | "ai-gallery/service/internal/svc" 9 | "ai-gallery/service/internal/types" 10 | 11 | "github.com/zeromicro/go-zero/rest/httpx" 12 | ) 13 | 14 | func CreateSubTaskHandler(ctx *svc.ServiceContext) http.HandlerFunc { 15 | return func(w http.ResponseWriter, r *http.Request) { 16 | var req types.CreateSubTaskReq 17 | if err := httpx.Parse(r, &req); err != nil { 18 | httpx.Error(w, err) 19 | return 20 | } 21 | 22 | l := task.NewCreateSubTaskLogic(r.Context(), ctx) 23 | resp, err := l.CreateSubTask(&req) 24 | if err != nil { 25 | errors.HandleResponseError(w, err) 26 | } else { 27 | httpx.OkJson(w, resp) 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /service/internal/handler/anonymous/authloginhandler.go: -------------------------------------------------------------------------------- 1 | package anonymous 2 | 3 | import ( 4 | "net/http" 5 | 6 | "ai-gallery/service/internal/errors" 7 | "ai-gallery/service/internal/logic/anonymous" 8 | "ai-gallery/service/internal/svc" 9 | "ai-gallery/service/internal/types" 10 | 11 | "github.com/zeromicro/go-zero/rest/httpx" 12 | ) 13 | 14 | func AuthLoginHandler(ctx *svc.ServiceContext) http.HandlerFunc { 15 | return func(w http.ResponseWriter, r *http.Request) { 16 | var req types.AuthLoginRequest 17 | if err := httpx.Parse(r, &req); err != nil { 18 | httpx.Error(w, err) 19 | return 20 | } 21 | 22 | l := anonymous.NewAuthLoginLogic(r.Context(), ctx) 23 | resp, err := l.AuthLogin(&req) 24 | if err != nil { 25 | errors.HandleResponseError(w, err) 26 | } else { 27 | httpx.OkJson(w, resp) 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /service/internal/handler/work/getworkdetailhandler.go: -------------------------------------------------------------------------------- 1 | package work 2 | 3 | import ( 4 | "net/http" 5 | 6 | "ai-gallery/service/internal/errors" 7 | "ai-gallery/service/internal/logic/work" 8 | "ai-gallery/service/internal/svc" 9 | "ai-gallery/service/internal/types" 10 | 11 | "github.com/zeromicro/go-zero/rest/httpx" 12 | ) 13 | 14 | func GetWorkDetailHandler(ctx *svc.ServiceContext) http.HandlerFunc { 15 | return func(w http.ResponseWriter, r *http.Request) { 16 | var req types.GetWorkDetailRequest 17 | if err := httpx.Parse(r, &req); err != nil { 18 | httpx.Error(w, err) 19 | return 20 | } 21 | 22 | l := work.NewGetWorkDetailLogic(r.Context(), ctx) 23 | resp, err := l.GetWorkDetail(&req) 24 | if err != nil { 25 | errors.HandleResponseError(w, err) 26 | } else { 27 | httpx.OkJson(w, resp) 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /ent/schema/base.go: -------------------------------------------------------------------------------- 1 | package schema 2 | 3 | import ( 4 | "time" 5 | 6 | "entgo.io/ent" 7 | "entgo.io/ent/dialect" 8 | "entgo.io/ent/schema/field" 9 | "entgo.io/ent/schema/mixin" 10 | ) 11 | 12 | type BaseSchema struct { 13 | ent.Schema 14 | } 15 | 16 | func (BaseSchema) Mixin() []ent.Mixin { 17 | return []ent.Mixin{BaseMixin{}} 18 | } 19 | 20 | type BaseMixin struct { 21 | mixin.Schema 22 | } 23 | 24 | func (BaseMixin) Fields() []ent.Field { 25 | datetime := map[string]string{dialect.MySQL: "datetime"} 26 | return []ent.Field{ 27 | field.Time("create_time").Default(time.Now).Immutable().SchemaType(datetime).Comment("创建时间"), 28 | field.Time("update_time").Default(time.Now).SchemaType(datetime).UpdateDefault(time.Now).Comment("更新时间"), 29 | field.Time("delete_time").SchemaType(datetime).Optional().Nillable().Comment("删除时间"), 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /service/internal/handler/work/markworkexcellenthandler.go: -------------------------------------------------------------------------------- 1 | package work 2 | 3 | import ( 4 | "net/http" 5 | 6 | "ai-gallery/service/internal/errors" 7 | "ai-gallery/service/internal/logic/work" 8 | "ai-gallery/service/internal/svc" 9 | "ai-gallery/service/internal/types" 10 | 11 | "github.com/zeromicro/go-zero/rest/httpx" 12 | ) 13 | 14 | func MarkWorkExcellentHandler(ctx *svc.ServiceContext) http.HandlerFunc { 15 | return func(w http.ResponseWriter, r *http.Request) { 16 | var req types.MarkWorkExcellentRequest 17 | if err := httpx.Parse(r, &req); err != nil { 18 | httpx.Error(w, err) 19 | return 20 | } 21 | 22 | l := work.NewMarkWorkExcellentLogic(r.Context(), ctx) 23 | err := l.MarkWorkExcellent(&req) 24 | if err != nil { 25 | errors.HandleResponseError(w, err) 26 | } else { 27 | httpx.Ok(w) 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /service/internal/handler/account/updateuserdetailhandler.go: -------------------------------------------------------------------------------- 1 | package account 2 | 3 | import ( 4 | "net/http" 5 | 6 | "ai-gallery/service/internal/errors" 7 | "ai-gallery/service/internal/logic/account" 8 | "ai-gallery/service/internal/svc" 9 | "ai-gallery/service/internal/types" 10 | 11 | "github.com/zeromicro/go-zero/rest/httpx" 12 | ) 13 | 14 | func UpdateUserDetailHandler(ctx *svc.ServiceContext) http.HandlerFunc { 15 | return func(w http.ResponseWriter, r *http.Request) { 16 | var req types.UpdateUserDetailRequest 17 | if err := httpx.Parse(r, &req); err != nil { 18 | httpx.Error(w, err) 19 | return 20 | } 21 | 22 | l := account.NewUpdateUserDetailLogic(r.Context(), ctx) 23 | err := l.UpdateUserDetail(&req) 24 | if err != nil { 25 | errors.HandleResponseError(w, err) 26 | } else { 27 | httpx.Ok(w) 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /service/internal/handler/analysis/getanalysistaskhandler.go: -------------------------------------------------------------------------------- 1 | package analysis 2 | 3 | import ( 4 | "net/http" 5 | 6 | "ai-gallery/service/internal/errors" 7 | "ai-gallery/service/internal/logic/analysis" 8 | "ai-gallery/service/internal/svc" 9 | "ai-gallery/service/internal/types" 10 | 11 | "github.com/zeromicro/go-zero/rest/httpx" 12 | ) 13 | 14 | func GetAnalysisTaskHandler(ctx *svc.ServiceContext) http.HandlerFunc { 15 | return func(w http.ResponseWriter, r *http.Request) { 16 | var req types.GetAnalysisTaskRequest 17 | if err := httpx.Parse(r, &req); err != nil { 18 | httpx.Error(w, err) 19 | return 20 | } 21 | 22 | l := analysis.NewGetAnalysisTaskLogic(r.Context(), ctx) 23 | resp, err := l.GetAnalysisTask(&req) 24 | if err != nil { 25 | errors.HandleResponseError(w, err) 26 | } else { 27 | httpx.OkJson(w, resp) 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /service/internal/handler/analysis/getanalysisuserhandler.go: -------------------------------------------------------------------------------- 1 | package analysis 2 | 3 | import ( 4 | "net/http" 5 | 6 | "ai-gallery/service/internal/errors" 7 | "ai-gallery/service/internal/logic/analysis" 8 | "ai-gallery/service/internal/svc" 9 | "ai-gallery/service/internal/types" 10 | 11 | "github.com/zeromicro/go-zero/rest/httpx" 12 | ) 13 | 14 | func GetAnalysisUserHandler(ctx *svc.ServiceContext) http.HandlerFunc { 15 | return func(w http.ResponseWriter, r *http.Request) { 16 | var req types.GetAnalysisUserRequest 17 | if err := httpx.Parse(r, &req); err != nil { 18 | httpx.Error(w, err) 19 | return 20 | } 21 | 22 | l := analysis.NewGetAnalysisUserLogic(r.Context(), ctx) 23 | resp, err := l.GetAnalysisUser(&req) 24 | if err != nil { 25 | errors.HandleResponseError(w, err) 26 | } else { 27 | httpx.OkJson(w, resp) 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /service/internal/logic/account/deleteuserlogic.go: -------------------------------------------------------------------------------- 1 | package account 2 | 3 | import ( 4 | "context" 5 | "time" 6 | 7 | "ai-gallery/service/internal/dao/account" 8 | "ai-gallery/service/internal/svc" 9 | "ai-gallery/service/internal/types" 10 | 11 | "github.com/zeromicro/go-zero/core/logx" 12 | ) 13 | 14 | type DeleteUserLogic struct { 15 | logx.Logger 16 | ctx context.Context 17 | svcCtx *svc.ServiceContext 18 | } 19 | 20 | func NewDeleteUserLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DeleteUserLogic { 21 | return &DeleteUserLogic{ 22 | Logger: logx.WithContext(ctx), 23 | ctx: ctx, 24 | svcCtx: svcCtx, 25 | } 26 | } 27 | 28 | func (l *DeleteUserLogic) DeleteUser(req *types.DeleteUserRequest) error { 29 | now := time.Now() 30 | return account.Update(l.ctx, &account.PO{ 31 | ID: req.UserID, 32 | DeleteTime: &now, 33 | }) 34 | } 35 | -------------------------------------------------------------------------------- /ent/schema/taskdetail.go: -------------------------------------------------------------------------------- 1 | package schema 2 | 3 | import ( 4 | "entgo.io/ent" 5 | "entgo.io/ent/dialect/entsql" 6 | "entgo.io/ent/schema" 7 | "entgo.io/ent/schema/field" 8 | "entgo.io/ent/schema/index" 9 | ) 10 | 11 | type TaskDetail struct { 12 | BaseSchema 13 | } 14 | 15 | func (TaskDetail) Fields() []ent.Field { 16 | return []ent.Field{ 17 | field.Int("task_id").Optional().Comment("任务ID"), 18 | field.String("image_url").MaxLen(255).Optional().Comment("图片地址"), 19 | field.Bool("has_excellent").Optional().Comment("是否为优秀作品"), 20 | } 21 | } 22 | 23 | func (TaskDetail) Edges() []ent.Edge { 24 | return nil 25 | } 26 | 27 | func (TaskDetail) Indexes() []ent.Index { 28 | return []ent.Index{ 29 | index.Fields("task_id"), 30 | } 31 | } 32 | 33 | func (TaskDetail) Annotations() []schema.Annotation { 34 | return []schema.Annotation{ 35 | entsql.Annotation{Table: "core_task_detail"}, 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /ent/schema/account.go: -------------------------------------------------------------------------------- 1 | package schema 2 | 3 | import ( 4 | "entgo.io/ent" 5 | "entgo.io/ent/dialect/entsql" 6 | "entgo.io/ent/schema" 7 | "entgo.io/ent/schema/field" 8 | "entgo.io/ent/schema/index" 9 | ) 10 | 11 | type Account struct { 12 | BaseSchema 13 | } 14 | 15 | func (Account) Fields() []ent.Field { 16 | return []ent.Field{ 17 | field.String("username").MaxLen(30).Optional().Comment("用户名"), 18 | field.String("password").MaxLen(255).Optional().Comment("密码"), 19 | field.String("nickname").MaxLen(30).Optional().Comment("昵称"), 20 | field.String("role").MaxLen(20).Optional().Comment("角色: ADMIN, USER"), 21 | field.Int("status").Optional().Comment("状态: 0 禁用, 1 可用"), 22 | } 23 | } 24 | 25 | func (Account) Edges() []ent.Edge { 26 | return nil 27 | } 28 | 29 | func (Account) Indexes() []ent.Index { 30 | return []ent.Index{ 31 | index.Fields("username").Unique(), 32 | } 33 | } 34 | 35 | func (Account) Annotations() []schema.Annotation { 36 | return []schema.Annotation{ 37 | entsql.Annotation{Table: "core_account"}, 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /ent/schema/setting.go: -------------------------------------------------------------------------------- 1 | package schema 2 | 3 | import ( 4 | "entgo.io/ent" 5 | "entgo.io/ent/dialect/entsql" 6 | "entgo.io/ent/schema" 7 | "entgo.io/ent/schema/field" 8 | "entgo.io/ent/schema/index" 9 | ) 10 | 11 | type Setting struct { 12 | BaseSchema 13 | } 14 | 15 | func (Setting) Fields() []ent.Field { 16 | return []ent.Field{ 17 | field.String("config_key").MaxLen(30).Optional().Comment("配置名"), 18 | field.String("config_value").MaxLen(255).Optional().Comment("配置值"), 19 | field.String("mark").MaxLen(255).Optional().Comment("说明"), 20 | field.Int("operate_id").Optional().Comment("操作人ID"), 21 | field.String("operate_name").MaxLen(50).Optional().Comment("操作人名称"), 22 | } 23 | } 24 | 25 | func (Setting) Edges() []ent.Edge { 26 | return nil 27 | } 28 | 29 | func (Setting) Indexes() []ent.Index { 30 | return []ent.Index{ 31 | index.Fields("config_key").Unique(), 32 | } 33 | } 34 | 35 | func (Setting) Annotations() []schema.Annotation { 36 | return []schema.Annotation{ 37 | entsql.Annotation{Table: "core_setting"}, 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /cmd/actions/migrate.go: -------------------------------------------------------------------------------- 1 | package actions 2 | 3 | import ( 4 | "context" 5 | "log" 6 | 7 | "ai-gallery/ent/migrate" 8 | "ai-gallery/service" 9 | 10 | "entgo.io/ent/dialect/sql/schema" 11 | "github.com/spf13/cobra" 12 | ) 13 | 14 | func init() { 15 | cmd := &cobra.Command{ 16 | Use: "migrate", 17 | Run: MigrateDB, 18 | } 19 | rootCmd.AddCommand(cmd) 20 | } 21 | 22 | func MigrateDB(cmd *cobra.Command, args []string) { 23 | env, err := cmd.Flags().GetString("env") 24 | if err != nil { 25 | log.Fatalf("get env failed: %v\n", err) 26 | } 27 | 28 | c := service.LoadConfig(env) 29 | client, err := service.InitDB(c) 30 | 31 | if err := client.Debug().Schema.Create( 32 | context.Background(), 33 | schema.WithHooks(func(next schema.Creator) schema.Creator { 34 | return schema.CreateFunc(func(ctx context.Context, tables ...*schema.Table) error { 35 | return next.Create(ctx, tables...) 36 | }) 37 | }), 38 | migrate.WithForeignKeys(false), 39 | ); err != nil { 40 | log.Fatal(err.Error()) 41 | } 42 | log.Println("migrate successfully") 43 | } 44 | -------------------------------------------------------------------------------- /service/internal/logic/setting/getsettinglogic.go: -------------------------------------------------------------------------------- 1 | package setting 2 | 3 | import ( 4 | "ai-gallery/service/internal/dao/setting" 5 | "ai-gallery/service/internal/svc" 6 | "ai-gallery/service/internal/types" 7 | "context" 8 | 9 | "github.com/zeromicro/go-zero/core/logx" 10 | ) 11 | 12 | type GetSettingLogic struct { 13 | logx.Logger 14 | ctx context.Context 15 | svcCtx *svc.ServiceContext 16 | } 17 | 18 | func NewGetSettingLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetSettingLogic { 19 | return &GetSettingLogic{ 20 | Logger: logx.WithContext(ctx), 21 | ctx: ctx, 22 | svcCtx: svcCtx, 23 | } 24 | } 25 | 26 | func (l *GetSettingLogic) GetSetting() (resp *types.GetSettingResponse, err error) { 27 | po, err := setting.GetPO(l.ctx) 28 | if err != nil { 29 | return nil, err 30 | } 31 | return &types.GetSettingResponse{ 32 | StoreName: po.StoreName, 33 | StoreAddress: po.StoreAddress, 34 | SecureID: po.SecureID, 35 | SecureKey: po.SecureKey, 36 | StoreBucket: po.StoreBucket, 37 | InitPwd: po.InitPwd, 38 | }, nil 39 | } 40 | -------------------------------------------------------------------------------- /service/internal/logic/work/gettaskauthorlogic.go: -------------------------------------------------------------------------------- 1 | package work 2 | 3 | import ( 4 | "ai-gallery/service/internal/dao" 5 | "context" 6 | 7 | enttask "ai-gallery/ent/task" 8 | "ai-gallery/service/internal/svc" 9 | "ai-gallery/service/internal/types" 10 | 11 | "github.com/zeromicro/go-zero/core/logx" 12 | ) 13 | 14 | type GetTaskAuthorLogic struct { 15 | logx.Logger 16 | ctx context.Context 17 | svcCtx *svc.ServiceContext 18 | } 19 | 20 | func NewGetTaskAuthorLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetTaskAuthorLogic { 21 | return &GetTaskAuthorLogic{ 22 | Logger: logx.WithContext(ctx), 23 | ctx: ctx, 24 | svcCtx: svcCtx, 25 | } 26 | } 27 | 28 | func (l *GetTaskAuthorLogic) GetTaskAuthor() (resp *types.GetTaskAuthorResponse, err error) { 29 | authorBos := make([]*types.TaskAuthorBo, 0) 30 | if err = dao.EntClient.Task.Query(). 31 | GroupBy(enttask.FieldAuthorID, enttask.FieldAuthorName). 32 | Scan(l.ctx, &authorBos); err != nil { 33 | return nil, err 34 | } 35 | return &types.GetTaskAuthorResponse{ 36 | TaskAuthorBo: authorBos, 37 | }, nil 38 | } 39 | -------------------------------------------------------------------------------- /api/setting.api: -------------------------------------------------------------------------------- 1 | syntax = "v1" 2 | 3 | info ( 4 | title: "系统设置" 5 | version: "v1.0" 6 | ) 7 | 8 | @server ( 9 | group: setting 10 | middleware: ManageJWT 11 | ) 12 | service gallery-api { 13 | @doc ( 14 | summary: "查询系统配置" 15 | ) 16 | @handler GetSetting 17 | get /api/v1/manage/setting returns (GetSettingResponse) 18 | 19 | @doc ( 20 | summary: "修改系统配置" 21 | ) 22 | @handler UpdateSetting 23 | put /api/v1/manage/setting (UpdateSettingRequest) 24 | } 25 | 26 | type GetSettingResponse { 27 | StoreName string `json:"store_name"` 28 | StoreAddress string `json:"store_address"` 29 | SecureID string `json:"secure_id"` 30 | SecureKey string `json:"secure_key"` 31 | StoreBucket string `json:"store_bucket"` 32 | InitPwd string `json:"init_pwd"` 33 | } 34 | 35 | type UpdateSettingRequest { 36 | StoreName string `json:"store_name"` 37 | StoreAddress string `json:"store_address"` 38 | SecureID string `json:"secure_id,optional"` 39 | SecureKey string `json:"secure_key,optional"` 40 | StoreBucket string `json:"store_bucket,optional"` 41 | InitPwd string `json:"init_pwd"` 42 | } 43 | 44 | -------------------------------------------------------------------------------- /service/internal/logic/work/gettasksizelogic.go: -------------------------------------------------------------------------------- 1 | package work 2 | 3 | import ( 4 | "ai-gallery/service/internal/dao" 5 | "context" 6 | 7 | enttask "ai-gallery/ent/task" 8 | "ai-gallery/service/internal/svc" 9 | "ai-gallery/service/internal/types" 10 | 11 | "github.com/zeromicro/go-zero/core/logx" 12 | ) 13 | 14 | type GetTaskSizeLogic struct { 15 | logx.Logger 16 | ctx context.Context 17 | svcCtx *svc.ServiceContext 18 | } 19 | 20 | func NewGetTaskSizeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetTaskSizeLogic { 21 | return &GetTaskSizeLogic{ 22 | Logger: logx.WithContext(ctx), 23 | ctx: ctx, 24 | svcCtx: svcCtx, 25 | } 26 | } 27 | 28 | func (l *GetTaskSizeLogic) GetTaskSize() (resp *types.GetTaskSizeResponse, err error) { 29 | var size []struct { 30 | Size string `json:"img_size"` 31 | } 32 | if err = dao.EntClient.Task.Query(). 33 | GroupBy(enttask.FieldImgSize). 34 | Scan(l.ctx, &size); err != nil { 35 | return nil, err 36 | } 37 | sizes := make([]string, 0) 38 | for _, s := range size { 39 | sizes = append(sizes, s.Size) 40 | } 41 | return &types.GetTaskSizeResponse{ 42 | Sizes: sizes, 43 | }, nil 44 | } 45 | -------------------------------------------------------------------------------- /service/internal/logic/account/getuserdetaillogic.go: -------------------------------------------------------------------------------- 1 | package account 2 | 3 | import ( 4 | "context" 5 | 6 | "ai-gallery/service/internal/dao/account" 7 | "ai-gallery/service/internal/logic/basic" 8 | "ai-gallery/service/internal/svc" 9 | "ai-gallery/service/internal/types" 10 | 11 | "github.com/zeromicro/go-zero/core/logx" 12 | ) 13 | 14 | type GetUserDetailLogic struct { 15 | logx.Logger 16 | ctx context.Context 17 | svcCtx *svc.ServiceContext 18 | } 19 | 20 | func NewGetUserDetailLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetUserDetailLogic { 21 | return &GetUserDetailLogic{ 22 | Logger: logx.WithContext(ctx), 23 | ctx: ctx, 24 | svcCtx: svcCtx, 25 | } 26 | } 27 | 28 | func (l *GetUserDetailLogic) GetUserDetail() (resp *types.GetUserDetailResponse, err error) { 29 | jwtInfo, err := basic.ContextElement(l.ctx) 30 | if err != nil { 31 | return nil, err 32 | } 33 | acc, err := account.GetByID(l.ctx, jwtInfo.ID) 34 | if err != nil { 35 | return nil, err 36 | } 37 | return &types.GetUserDetailResponse{ 38 | UserID: acc.ID, 39 | Username: acc.Username, 40 | Nickname: acc.Nickname, 41 | Role: acc.Role, 42 | }, nil 43 | } 44 | -------------------------------------------------------------------------------- /service/internal/logic/work/gettaskmodellogic.go: -------------------------------------------------------------------------------- 1 | package work 2 | 3 | import ( 4 | "ai-gallery/service/internal/dao" 5 | "context" 6 | 7 | enttask "ai-gallery/ent/task" 8 | "ai-gallery/service/internal/svc" 9 | "ai-gallery/service/internal/types" 10 | 11 | "github.com/zeromicro/go-zero/core/logx" 12 | ) 13 | 14 | type GetTaskModelLogic struct { 15 | logx.Logger 16 | ctx context.Context 17 | svcCtx *svc.ServiceContext 18 | } 19 | 20 | func NewGetTaskModelLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetTaskModelLogic { 21 | return &GetTaskModelLogic{ 22 | Logger: logx.WithContext(ctx), 23 | ctx: ctx, 24 | svcCtx: svcCtx, 25 | } 26 | } 27 | 28 | func (l *GetTaskModelLogic) GetTaskModel() (resp *types.GetTaskModelResponse, err error) { 29 | var sd []struct { 30 | SdModelName string `json:"sd_model_name"` 31 | } 32 | if err = dao.EntClient.Task.Query(). 33 | GroupBy(enttask.FieldSdModelName). 34 | Scan(l.ctx, &sd); err != nil { 35 | return nil, err 36 | } 37 | models := make([]string, 0) 38 | for _, s := range sd { 39 | models = append(models, s.SdModelName) 40 | } 41 | return &types.GetTaskModelResponse{ 42 | Models: models, 43 | }, nil 44 | } 45 | -------------------------------------------------------------------------------- /service/internal/logic/account/resetpwdlogic.go: -------------------------------------------------------------------------------- 1 | package account 2 | 3 | import ( 4 | "context" 5 | 6 | "ai-gallery/service/internal/dao/account" 7 | "ai-gallery/service/internal/dao/setting" 8 | "ai-gallery/service/internal/model" 9 | "ai-gallery/service/internal/svc" 10 | "ai-gallery/service/internal/types" 11 | 12 | "github.com/zeromicro/go-zero/core/logx" 13 | "golang.org/x/crypto/bcrypt" 14 | ) 15 | 16 | type ResetPwdLogic struct { 17 | logx.Logger 18 | ctx context.Context 19 | svcCtx *svc.ServiceContext 20 | } 21 | 22 | func NewResetPwdLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ResetPwdLogic { 23 | return &ResetPwdLogic{ 24 | Logger: logx.WithContext(ctx), 25 | ctx: ctx, 26 | svcCtx: svcCtx, 27 | } 28 | } 29 | 30 | func (l *ResetPwdLogic) ResetPwd(req *types.ResetPwdRequest) error { 31 | initPwd, err := setting.GetInitPwd(l.ctx) 32 | if err != nil { 33 | return err 34 | } 35 | password, err := bcrypt.GenerateFromPassword([]byte(initPwd+model.PwdSalt), bcrypt.DefaultCost) 36 | if err != nil { 37 | return err 38 | } 39 | return account.Update(l.ctx, &account.PO{ 40 | ID: req.UserID, 41 | Password: string(password), 42 | Status: -1, 43 | }) 44 | } 45 | -------------------------------------------------------------------------------- /service/internal/logic/setting/updatesettinglogic.go: -------------------------------------------------------------------------------- 1 | package setting 2 | 3 | import ( 4 | "ai-gallery/service/internal/dao/setting" 5 | "ai-gallery/service/internal/logic/basic" 6 | "ai-gallery/service/internal/svc" 7 | "ai-gallery/service/internal/types" 8 | "context" 9 | 10 | "github.com/zeromicro/go-zero/core/logx" 11 | ) 12 | 13 | type UpdateSettingLogic struct { 14 | logx.Logger 15 | ctx context.Context 16 | svcCtx *svc.ServiceContext 17 | } 18 | 19 | func NewUpdateSettingLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdateSettingLogic { 20 | return &UpdateSettingLogic{ 21 | Logger: logx.WithContext(ctx), 22 | ctx: ctx, 23 | svcCtx: svcCtx, 24 | } 25 | } 26 | 27 | func (l *UpdateSettingLogic) UpdateSetting(req *types.UpdateSettingRequest) error { 28 | jwtInfo, err := basic.ContextElement(l.ctx) 29 | if err != nil { 30 | return err 31 | } 32 | return setting.Update(l.ctx, &setting.PO{ 33 | StoreName: req.StoreName, 34 | StoreAddress: req.StoreAddress, 35 | SecureID: req.SecureID, 36 | SecureKey: req.SecureKey, 37 | StoreBucket: req.StoreBucket, 38 | InitPwd: req.InitPwd, 39 | OperateID: jwtInfo.ID, 40 | OperateName: jwtInfo.Nickname, 41 | }) 42 | } 43 | -------------------------------------------------------------------------------- /service/internal/logic/basic/upload/cos.go: -------------------------------------------------------------------------------- 1 | package basic 2 | 3 | import ( 4 | "context" 5 | "io" 6 | "net/http" 7 | "net/url" 8 | "time" 9 | 10 | "github.com/tencentyun/cos-go-sdk-v5" 11 | ) 12 | 13 | type CosService struct { 14 | URL string `json:"url"` 15 | SecretID string `json:"secret_id"` 16 | SecretKey string `json:"secret_key"` 17 | Bucket string `json:"bucket"` 18 | } 19 | 20 | func NewCosService() *CosService { 21 | return &CosService{} 22 | } 23 | 24 | func (c *CosService) SetConfig(url, secretID, secretKey, bucket string) { 25 | c.URL = url 26 | c.SecretID = secretID 27 | c.SecretKey = secretKey 28 | c.Bucket = bucket 29 | } 30 | 31 | func (c *CosService) Put(ctx context.Context, name string, r io.Reader, options ...any) ( 32 | path string, err error, 33 | ) { 34 | u, _ := url.Parse(c.URL) 35 | b := &cos.BaseURL{BucketURL: u} 36 | 37 | client := cos.NewClient(b, &http.Client{ 38 | //设置超时时间 39 | Timeout: 10 * time.Second, 40 | Transport: &cos.AuthorizationTransport{ 41 | //如实填写账号和密钥,也可以设置为环境变量 42 | SecretID: c.SecretID, 43 | SecretKey: c.SecretKey, 44 | }, 45 | }) 46 | if _, err = client.Object.Put(ctx, name, r, nil); err != nil { 47 | return "", err 48 | } 49 | return c.URL + "/" + name, nil 50 | } 51 | -------------------------------------------------------------------------------- /service/internal/logic/basic/upload/oss.go: -------------------------------------------------------------------------------- 1 | package basic 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "io" 7 | "strings" 8 | 9 | "github.com/aliyun/aliyun-oss-go-sdk/oss" 10 | ) 11 | 12 | type OssService struct { 13 | URL string `json:"url"` 14 | SecretID string `json:"secret_id"` 15 | SecretKey string `json:"secret_key"` 16 | Bucket string `json:"bucket"` 17 | } 18 | 19 | func NewOssService() *OssService { 20 | return &OssService{} 21 | } 22 | 23 | func (c *OssService) SetConfig(url, secretID, secretKey, bucket string) { 24 | c.URL = url 25 | c.SecretID = secretID 26 | c.SecretKey = secretKey 27 | c.Bucket = bucket 28 | } 29 | 30 | func (c *OssService) Put(ctx context.Context, name string, r io.Reader, options ...any) ( 31 | path string, err error, 32 | ) { 33 | client, err := oss.New(c.URL, c.SecretID, c.SecretKey) 34 | if err != nil { 35 | return "", err 36 | } 37 | bucket, err := client.Bucket(c.Bucket) 38 | if err != nil { 39 | return "", err 40 | } 41 | if err = bucket.PutObject(name, r); err != nil { 42 | return "", err 43 | } 44 | region := strings.TrimPrefix(strings.TrimPrefix(c.URL, "http://"), "https://") 45 | // 构造完整的URL 46 | url := fmt.Sprintf("https://%s.%s/%s", c.Bucket, region, name) 47 | return url, err 48 | } 49 | -------------------------------------------------------------------------------- /service/internal/cron/jobs/task.go: -------------------------------------------------------------------------------- 1 | package jobs 2 | 3 | import ( 4 | "ai-gallery/service/internal/dao" 5 | "context" 6 | "time" 7 | 8 | enttask "ai-gallery/ent/task" 9 | "ai-gallery/pkg/utils" 10 | "ai-gallery/service/internal/config" 11 | "ai-gallery/service/internal/model" 12 | 13 | "github.com/zeromicro/go-zero/core/logc" 14 | ) 15 | 16 | func CheckTaskStatus(ctx context.Context, config config.Config) { 17 | logc.Info(ctx, "check task status cron.") 18 | // 检查 今天0晨 至 30 分钟前未完成的任务 19 | tasks, err := dao.EntClient.Task.Query().Where( 20 | enttask.CreateTimeGTE(utils.FirstTime(time.Now())), 21 | enttask.CreateTimeLTE(time.Now().Add(time.Minute*30)), 22 | enttask.Status(model.TaskStatusEnums.Progress.Code), 23 | enttask.DeleteTimeIsNil(), 24 | ).All(ctx) 25 | if err != nil { 26 | logc.Errorf(ctx, "select task error: %+v", err) 27 | return 28 | } 29 | if len(tasks) == 0 { 30 | return 31 | } 32 | taskIDs := make([]int, 0) 33 | for _, t := range tasks { 34 | taskIDs = append(taskIDs, t.ID) 35 | } 36 | if err = dao.EntClient.Task.Update(). 37 | SetStatus(model.TaskStatusEnums.Exception.Code). 38 | Where(enttask.IDIn(taskIDs...)). 39 | Exec(ctx); err != nil { 40 | logc.Errorf(ctx, "update task status error: %+v", err) 41 | return 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /service/internal/logic/basic/upload/upload.go: -------------------------------------------------------------------------------- 1 | package basic 2 | 3 | import ( 4 | "ai-gallery/service/internal/dao/setting" 5 | "context" 6 | "io" 7 | 8 | "ai-gallery/service/internal/errors" 9 | "ai-gallery/service/internal/model" 10 | ) 11 | 12 | var uploadServiceMap = make(map[string]UploadService, 0) 13 | 14 | type UploadService interface { 15 | SetConfig(url, secretID, secretKey, bucket string) 16 | Put(ctx context.Context, name string, r io.Reader, options ...any) (path string, err error) 17 | } 18 | 19 | func UploadStrategy(ctx context.Context) (string, UploadService, error) { 20 | _initService() 21 | conf, err := setting.GetPO(ctx) 22 | if err != nil { 23 | return "", nil, err 24 | } 25 | service := uploadServiceMap[conf.StoreName] 26 | if service == nil { 27 | return "", nil, errors.ErrUploadServiceNotFound(ctx) 28 | } 29 | service.SetConfig(conf.StoreAddress, conf.SecureID, conf.SecureKey, conf.StoreBucket) 30 | return conf.StoreName, service, nil 31 | } 32 | 33 | func _initService() { 34 | if len(uploadServiceMap) > 0 { 35 | return 36 | } 37 | uploadServiceMap[model.UploadEnums.Tx.Code] = NewCosService() 38 | uploadServiceMap[model.UploadEnums.Aliyun.Code] = NewOssService() 39 | uploadServiceMap[model.UploadEnums.Local.Code] = NewLocalService() 40 | } 41 | -------------------------------------------------------------------------------- /service/internal/dao/dao.go: -------------------------------------------------------------------------------- 1 | package dao 2 | 3 | import ( 4 | "context" 5 | "database/sql" 6 | "errors" 7 | "fmt" 8 | 9 | "ai-gallery/ent" 10 | "ai-gallery/service/internal/config" 11 | 12 | entsql "entgo.io/ent/dialect/sql" 13 | _ "github.com/go-sql-driver/mysql" 14 | ) 15 | 16 | var ( 17 | EntClient *ent.Client 18 | ) 19 | 20 | func NewDB(conf config.EntConf) (*ent.Client, error) { 21 | db, err := sql.Open(conf.Driver, conf.URL) 22 | if err != nil { 23 | return nil, err 24 | } 25 | db.SetMaxOpenConns(conf.MaxOpenConns) 26 | db.SetMaxIdleConns(conf.MaxIdleConns) 27 | 28 | EntClient = ent.NewClient(ent.Driver(entsql.OpenDB(conf.Driver, db))) 29 | 30 | return EntClient, nil 31 | } 32 | 33 | func WithTx(ctx context.Context, client *ent.Client, fn func(tx *ent.Tx) error) error { 34 | tx, err := client.Tx(ctx) 35 | if err != nil { 36 | return err 37 | } 38 | defer func() { 39 | if v := recover(); v != nil { 40 | err = tx.Rollback() 41 | panic(v) 42 | } 43 | }() 44 | if err = fn(tx); err != nil { 45 | if r := tx.Rollback(); r != nil { 46 | err = errors.New(fmt.Sprintf("transaction rollback, err: %+v", r)) 47 | } 48 | return err 49 | } 50 | if err = tx.Commit(); err != nil { 51 | return errors.New(fmt.Sprintf("transaction commint, err: %+v", err)) 52 | } 53 | return nil 54 | } 55 | -------------------------------------------------------------------------------- /service/internal/middleware/jwtmiddleware.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "ai-gallery/service/internal/errors" 5 | "context" 6 | "net/http" 7 | 8 | "ai-gallery/pkg/jwt" 9 | "ai-gallery/service/internal/config" 10 | "ai-gallery/service/internal/logic/basic" 11 | "ai-gallery/service/internal/model" 12 | ) 13 | 14 | type JWTMiddleware struct { 15 | config.JWTConf 16 | } 17 | 18 | func NewJWTMiddleware(conf config.JWTConf) *JWTMiddleware { 19 | return &JWTMiddleware{conf} 20 | } 21 | 22 | func (m *JWTMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc { 23 | return func(w http.ResponseWriter, r *http.Request) { 24 | token := r.Header.Get("Authorization") 25 | if token == "" { 26 | http.Error(w, errors.ErrPermissionProvider(r.Context()).Error(), http.StatusUnauthorized) 27 | return 28 | } 29 | tokenType, claims := jwt.IsValidateOfToken(token, m.JwtKey) 30 | var resultMessage string 31 | reqCtx := r.Context() 32 | switch tokenType { 33 | case jwt.ValidateToken: 34 | { 35 | if err := basic.CheckAccountStatus(reqCtx, claims.ID); err != nil { 36 | http.Error(w, err.Error(), http.StatusUnauthorized) 37 | return 38 | } 39 | r = r.WithContext(context.WithValue(reqCtx, model.UserToken, claims)) 40 | next(w, r) 41 | return 42 | } 43 | case jwt.ExpiredToken: 44 | resultMessage = errors.ErrTokenExpired(reqCtx).Error() 45 | case jwt.BadToken: 46 | resultMessage = errors.ErrTokenValid(reqCtx).Error() 47 | } 48 | http.Error(w, resultMessage, http.StatusUnauthorized) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /service/internal/logic/account/adduserlogic.go: -------------------------------------------------------------------------------- 1 | package account 2 | 3 | import ( 4 | "context" 5 | 6 | "ai-gallery/ent" 7 | "ai-gallery/service/internal/dao/account" 8 | "ai-gallery/service/internal/dao/setting" 9 | "ai-gallery/service/internal/errors" 10 | "ai-gallery/service/internal/model" 11 | "ai-gallery/service/internal/svc" 12 | "ai-gallery/service/internal/types" 13 | 14 | "github.com/zeromicro/go-zero/core/logx" 15 | "golang.org/x/crypto/bcrypt" 16 | ) 17 | 18 | type AddUserLogic struct { 19 | logx.Logger 20 | ctx context.Context 21 | svcCtx *svc.ServiceContext 22 | } 23 | 24 | func NewAddUserLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AddUserLogic { 25 | return &AddUserLogic{ 26 | Logger: logx.WithContext(ctx), 27 | ctx: ctx, 28 | svcCtx: svcCtx, 29 | } 30 | } 31 | 32 | func (l *AddUserLogic) AddUser(req *types.AddUserRequest) error { 33 | acc, err := account.GetByUsername(l.ctx, req.Username) 34 | if err != nil && !ent.IsNotFound(err) { 35 | return err 36 | } 37 | err = nil 38 | if acc != nil { 39 | return errors.ErrAccountUsernameExist(l.ctx) 40 | } 41 | initPwd, err := setting.GetInitPwd(l.ctx) 42 | if err != nil { 43 | return err 44 | } 45 | password, err := bcrypt.GenerateFromPassword([]byte(initPwd+model.PwdSalt), bcrypt.DefaultCost) 46 | if err != nil { 47 | return err 48 | } 49 | return account.Create(l.ctx, &account.PO{ 50 | Username: req.Username, 51 | Nickname: req.Nickname, 52 | Password: string(password), 53 | Status: model.DISABLED, 54 | Role: req.Role, 55 | }) 56 | } 57 | -------------------------------------------------------------------------------- /service/internal/middleware/corsmiddleware.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import "net/http" 4 | 5 | // CorsMiddleware 跨域请求处理中间件 6 | type CorsMiddleware struct { 7 | } 8 | 9 | // NewCorsMiddleware 新建跨域请求处理中间件 10 | func NewCorsMiddleware() *CorsMiddleware { 11 | return &CorsMiddleware{} 12 | } 13 | 14 | // Handle 跨域请求处理 15 | func (m *CorsMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc { 16 | return func(w http.ResponseWriter, r *http.Request) { 17 | setHeader(w) 18 | 19 | // 放行所有 OPTIONS 方法 20 | if r.Method == "OPTIONS" { 21 | w.WriteHeader(http.StatusNoContent) 22 | return 23 | } 24 | 25 | // 处理请求 26 | next(w, r) 27 | } 28 | } 29 | 30 | // Handler 跨域请求处理器 31 | func (m *CorsMiddleware) Handler() http.Handler { 32 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 33 | setHeader(w) 34 | 35 | if r.Method == "OPTIONS" { 36 | w.WriteHeader(http.StatusNoContent) 37 | } else { 38 | w.WriteHeader(http.StatusNotFound) 39 | } 40 | }) 41 | } 42 | 43 | // setHeader 设置响应头 44 | func setHeader(w http.ResponseWriter) { 45 | w.Header().Set("Access-Control-Allow-Origin", "*") 46 | w.Header().Set("Access-Control-Allow-Headers", 47 | "Content-Type, X-CSRF-Token, Authorization, AccessToken, Token, X-Ag-H-U") 48 | w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, PATCH") 49 | w.Header().Set("Access-Control-Expose-Headers", "Content-Length, Content-Type, Access-Control-Allow-Origin, Access-Control-Allow-Headers") 50 | w.Header().Set("Access-Control-Allow-Credentials", "true") 51 | } 52 | -------------------------------------------------------------------------------- /service/internal/cron/cron.go: -------------------------------------------------------------------------------- 1 | package cron 2 | 3 | import ( 4 | "context" 5 | "time" 6 | 7 | "ai-gallery/service/internal/config" 8 | "ai-gallery/service/internal/cron/jobs" 9 | 10 | "github.com/robfig/cron/v3" 11 | "github.com/zeromicro/go-zero/core/logc" 12 | ) 13 | 14 | type JobFunc func(ctx context.Context, config config.Config) 15 | 16 | type Job struct { 17 | Name string `json:"name"` 18 | Spec string `json:"spec"` 19 | Func JobFunc `json:"func"` 20 | } 21 | 22 | var cronJobs = []Job{ 23 | // 每 10 分钟执行一次 24 | {Spec: "@every 10m", Name: "CheckTaskStatus", Func: jobs.CheckTaskStatus}, 25 | } 26 | 27 | func CreateCronJob(config config.Config) (*cron.Cron, error) { 28 | c := cron.New(cron.WithChain(cron.Recover(NewLogger()))) 29 | for _, j := range cronJobs { 30 | _, err := c.AddFunc(j.Spec, func() { 31 | ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) 32 | defer cancel() 33 | j.Func(ctx, config) 34 | }) 35 | if err != nil { 36 | return nil, err 37 | } 38 | } 39 | 40 | return c, nil 41 | } 42 | 43 | // Logger 自定义Cron.Logger. 44 | type Logger struct { 45 | ctx context.Context 46 | } 47 | 48 | func NewLogger() Logger { 49 | return Logger{ctx: context.Background()} 50 | } 51 | 52 | // Info level为debug. 53 | func (l Logger) Info(msg string, keysAndValues ...interface{}) { 54 | logc.Infof(l.ctx, "%s %+v", msg, keysAndValues) 55 | } 56 | 57 | // Error level为error. 58 | func (l Logger) Error(err error, msg string, keysAndValues ...interface{}) { 59 | logc.Errorf(l.ctx, "%w %s %+v", err, msg, keysAndValues) 60 | } 61 | -------------------------------------------------------------------------------- /service/internal/logic/work/markworkexcellentlogic.go: -------------------------------------------------------------------------------- 1 | package work 2 | 3 | import ( 4 | "ai-gallery/service/internal/dao" 5 | "context" 6 | 7 | "ai-gallery/ent" 8 | enttask "ai-gallery/ent/task" 9 | "ai-gallery/ent/taskdetail" 10 | "ai-gallery/service/internal/svc" 11 | "ai-gallery/service/internal/types" 12 | 13 | "github.com/zeromicro/go-zero/core/logx" 14 | ) 15 | 16 | type MarkWorkExcellentLogic struct { 17 | logx.Logger 18 | ctx context.Context 19 | svcCtx *svc.ServiceContext 20 | } 21 | 22 | func NewMarkWorkExcellentLogic(ctx context.Context, svcCtx *svc.ServiceContext) *MarkWorkExcellentLogic { 23 | return &MarkWorkExcellentLogic{ 24 | Logger: logx.WithContext(ctx), 25 | ctx: ctx, 26 | svcCtx: svcCtx, 27 | } 28 | } 29 | 30 | func (l *MarkWorkExcellentLogic) MarkWorkExcellent(req *types.MarkWorkExcellentRequest) error { 31 | if err := dao.WithTx(l.ctx, dao.EntClient, func(tx *ent.Tx) (err error) { 32 | if err = tx.TaskDetail.Update(). 33 | SetHasExcellent(req.HasExcellent). 34 | Where( 35 | taskdetail.ID(req.SubTaskID), 36 | taskdetail.DeleteTimeIsNil(), 37 | ).Exec(l.ctx); err != nil { 38 | return err 39 | } 40 | exist, err := tx.TaskDetail.Query().Where( 41 | taskdetail.TaskID(req.TaskID), 42 | taskdetail.HasExcellent(true), 43 | taskdetail.DeleteTimeIsNil(), 44 | ).Exist(l.ctx) 45 | if err != nil { 46 | return err 47 | } 48 | return tx.Task.Update(). 49 | SetHasExcellent(exist). 50 | Where(enttask.ID(req.TaskID)). 51 | Exec(l.ctx) 52 | }); err != nil { 53 | return err 54 | } 55 | return nil 56 | } 57 | -------------------------------------------------------------------------------- /service/internal/logic/account/updateuserlogic.go: -------------------------------------------------------------------------------- 1 | package account 2 | 3 | import ( 4 | "context" 5 | 6 | "ai-gallery/ent" 7 | "ai-gallery/service/internal/dao/account" 8 | "ai-gallery/service/internal/dao/task" 9 | "ai-gallery/service/internal/errors" 10 | "ai-gallery/service/internal/svc" 11 | "ai-gallery/service/internal/types" 12 | 13 | "github.com/zeromicro/go-zero/core/logx" 14 | ) 15 | 16 | type UpdateUserLogic struct { 17 | logx.Logger 18 | ctx context.Context 19 | svcCtx *svc.ServiceContext 20 | } 21 | 22 | func NewUpdateUserLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdateUserLogic { 23 | return &UpdateUserLogic{ 24 | Logger: logx.WithContext(ctx), 25 | ctx: ctx, 26 | svcCtx: svcCtx, 27 | } 28 | } 29 | 30 | func (l *UpdateUserLogic) UpdateUser(req *types.UpdateUserRequest) error { 31 | acc, err := account.GetByID(l.ctx, req.UserID) 32 | if err != nil { 33 | return err 34 | } 35 | if acc.Username != req.Username { 36 | other, err := account.GetByUsername(l.ctx, req.Username) 37 | if err != nil && !ent.IsNotFound(err) { 38 | return err 39 | } 40 | err = nil 41 | if other != nil { 42 | return errors.ErrAccountUsernameExist(l.ctx) 43 | } 44 | } 45 | if err = account.Update(l.ctx, &account.PO{ 46 | ID: req.UserID, 47 | Username: req.Username, 48 | Nickname: req.Nickname, 49 | Status: req.Status, 50 | Role: req.Role, 51 | }); err != nil { 52 | return err 53 | } 54 | if acc.Nickname != req.Nickname { 55 | // 修改了昵称 56 | return task.UpdateAuthorInfo(l.ctx, acc.ID, req.Nickname) 57 | } 58 | return nil 59 | } 60 | -------------------------------------------------------------------------------- /service/internal/logic/anonymous/authloginlogic.go: -------------------------------------------------------------------------------- 1 | package anonymous 2 | 3 | import ( 4 | "context" 5 | 6 | pkg "ai-gallery/pkg/jwt" 7 | "ai-gallery/service/internal/errors" 8 | "ai-gallery/service/internal/logic/basic" 9 | "ai-gallery/service/internal/model" 10 | "ai-gallery/service/internal/svc" 11 | "ai-gallery/service/internal/types" 12 | 13 | "github.com/golang-jwt/jwt/v4" 14 | "github.com/zeromicro/go-zero/core/logx" 15 | ) 16 | 17 | type AuthLoginLogic struct { 18 | logx.Logger 19 | ctx context.Context 20 | svcCtx *svc.ServiceContext 21 | } 22 | 23 | func NewAuthLoginLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AuthLoginLogic { 24 | return &AuthLoginLogic{ 25 | Logger: logx.WithContext(ctx), 26 | ctx: ctx, 27 | svcCtx: svcCtx, 28 | } 29 | } 30 | 31 | func (l *AuthLoginLogic) AuthLogin(req *types.AuthLoginRequest) (resp *types.AuthLoginResponse, err error) { 32 | user, err := basic.ValidateAccount(l.ctx, req.Username, req.Password) 33 | if err != nil { 34 | return nil, err 35 | } 36 | JWTClaims := pkg.Claims{ 37 | ID: user.ID, 38 | Nickname: user.Nickname, 39 | Role: user.Role, 40 | } 41 | if user.Role == model.ADMIN { 42 | JWTClaims.Audience = jwt.ClaimStrings{pkg.AudienceAdmin} 43 | } else { 44 | JWTClaims.Audience = jwt.ClaimStrings{pkg.AudienceUser} 45 | } 46 | token, err := pkg.GetJwtToken( 47 | l.svcCtx.Config.JWT.JwtKey, 48 | l.svcCtx.Config.JWT.JwtIssuer, 49 | l.svcCtx.Config.JWT.JwtExpire, 50 | JWTClaims) 51 | if err != nil { 52 | return nil, errors.ErrAccountTokenGen(l.ctx) 53 | } 54 | return &types.AuthLoginResponse{ 55 | UserID: user.ID, 56 | Username: user.Username, 57 | Role: user.Role, 58 | Token: token, 59 | }, nil 60 | } 61 | -------------------------------------------------------------------------------- /service/internal/middleware/headersmiddleware.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "ai-gallery/service/internal/errors" 5 | "context" 6 | "encoding/json" 7 | "net/http" 8 | 9 | "ai-gallery/pkg/jwt" 10 | "ai-gallery/service/internal/model" 11 | 12 | "ai-gallery/service/internal/logic/basic" 13 | "github.com/duke-git/lancet/v2/strutil" 14 | ) 15 | 16 | type HeadersMiddleware struct{} 17 | 18 | func NewHeadersMiddleware() *HeadersMiddleware { 19 | return &HeadersMiddleware{} 20 | } 21 | 22 | const NewHeaderKey = "user_header" 23 | 24 | type HeaderUserBoInfo struct { 25 | UserID int `json:"user_id"` 26 | Nickname string `json:"nickname"` 27 | } 28 | 29 | type UserRo struct { 30 | Username string `json:"username"` 31 | Password string `json:"password"` 32 | } 33 | 34 | func (m *HeadersMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc { 35 | return func(w http.ResponseWriter, r *http.Request) { 36 | headers := r.Header.Get("X-Ag-H-U") 37 | if strutil.IsBlank(headers) { 38 | http.Error(w, errors.ErrHeaderNotFound(r.Context()).Error(), http.StatusUnauthorized) 39 | return 40 | } 41 | var user UserRo 42 | if err := json.Unmarshal([]byte(headers), &user); err != nil { 43 | http.Error(w, errors.ErrHeaderParsing(r.Context()).Error(), http.StatusUnauthorized) 44 | return 45 | } 46 | account, err := basic.ValidateAccount(r.Context(), user.Username, user.Password) 47 | if err != nil { 48 | http.Error(w, err.Error(), http.StatusUnauthorized) 49 | return 50 | } 51 | r = r.WithContext(context.WithValue(r.Context(), model.UserToken, &jwt.Claims{ 52 | ID: account.ID, 53 | Role: account.Role, 54 | Nickname: account.Nickname, 55 | })) 56 | next(w, r) 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /service/internal/middleware/managejwtmiddleware.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "ai-gallery/service/internal/errors" 5 | "context" 6 | "net/http" 7 | 8 | "ai-gallery/pkg/jwt" 9 | "ai-gallery/service/internal/config" 10 | "ai-gallery/service/internal/logic/basic" 11 | "ai-gallery/service/internal/model" 12 | ) 13 | 14 | type ManageJWTMiddleware struct { 15 | config.JWTConf 16 | } 17 | 18 | func NewManageJWTMiddleware(conf config.JWTConf) *ManageJWTMiddleware { 19 | return &ManageJWTMiddleware{conf} 20 | } 21 | 22 | func (m *ManageJWTMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc { 23 | return func(w http.ResponseWriter, r *http.Request) { 24 | token := r.Header.Get("Authorization") 25 | if token == "" { 26 | http.Error(w, errors.ErrPermissionProvider(r.Context()).Error(), http.StatusUnauthorized) 27 | return 28 | } 29 | tokenType, claims := jwt.IsValidateOfToken(token, m.JwtKey) 30 | var resultMessage string 31 | reqCtx := r.Context() 32 | switch tokenType { 33 | case jwt.ValidateToken: 34 | { 35 | if err := basic.CheckAccountStatus(reqCtx, claims.ID); err != nil { 36 | http.Error(w, err.Error(), http.StatusUnauthorized) 37 | return 38 | } 39 | if err := basic.CheckPermission(r.Context(), claims); err != nil { 40 | http.Error(w, err.Error(), http.StatusUnauthorized) 41 | return 42 | } 43 | r = r.WithContext(context.WithValue(reqCtx, model.UserToken, claims)) 44 | next(w, r) 45 | return 46 | } 47 | case jwt.ExpiredToken: 48 | resultMessage = errors.ErrTokenExpired(reqCtx).Error() 49 | case jwt.BadToken: 50 | resultMessage = errors.ErrTokenValid(reqCtx).Error() 51 | } 52 | http.Error(w, resultMessage, http.StatusUnauthorized) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /pkg/jwt/jwt.go: -------------------------------------------------------------------------------- 1 | package jwt 2 | 3 | import ( 4 | "strings" 5 | "time" 6 | 7 | "github.com/golang-jwt/jwt/v4" 8 | ) 9 | 10 | type TokenType int 11 | 12 | // token的状态. 13 | const ( 14 | ValidateToken TokenType = 0 15 | BadToken TokenType = 1 16 | ExpiredToken TokenType = 2 17 | ) 18 | 19 | const AudienceUser = "user" 20 | const AudienceAdmin = "admin" 21 | 22 | type Claims struct { 23 | ID int `json:"id"` 24 | Role string `json:"role"` 25 | Nickname string `json:"nickname"` 26 | jwt.RegisteredClaims 27 | } 28 | 29 | func GetJwtToken(secretKey, issuer string, seconds int64, claims Claims) (string, error) { 30 | expireTime := time.Now().Add(time.Duration(seconds) * time.Second) 31 | claims.ExpiresAt = jwt.NewNumericDate(expireTime) 32 | claims.Issuer = issuer 33 | 34 | aToken := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) 35 | token, err := aToken.SignedString([]byte(secretKey)) 36 | 37 | return token, err 38 | } 39 | 40 | func ParseToken(token string, secret string) (*Claims, error) { 41 | tokenClaims, err := jwt.ParseWithClaims( 42 | strings.TrimPrefix(token, "Bearer "), &Claims{}, func(token *jwt.Token) (interface{}, error) { 43 | return secret, nil 44 | }) 45 | if tokenClaims != nil { 46 | if claims, ok := tokenClaims.Claims.(*Claims); ok { 47 | return claims, nil 48 | } 49 | } 50 | return nil, err 51 | } 52 | 53 | func IsValidateOfToken(token string, secret string) (TokenType, *Claims) { 54 | claims, err := ParseToken(token, secret) 55 | if err != nil { 56 | return BadToken, nil 57 | } 58 | if !claims.VerifyExpiresAt(time.Now(), true) { 59 | return ExpiredToken, nil 60 | } 61 | if err := claims.Valid(); err != nil { 62 | return BadToken, nil 63 | } 64 | return ValidateToken, claims 65 | } 66 | -------------------------------------------------------------------------------- /service/internal/logic/task/createsubtasklogic.go: -------------------------------------------------------------------------------- 1 | package task 2 | 3 | import ( 4 | "ai-gallery/service/internal/dao" 5 | "bytes" 6 | "context" 7 | "encoding/base64" 8 | "time" 9 | 10 | enttask "ai-gallery/ent/task" 11 | "ai-gallery/service/internal/errors" 12 | basic "ai-gallery/service/internal/logic/basic/upload" 13 | "ai-gallery/service/internal/svc" 14 | "ai-gallery/service/internal/types" 15 | 16 | "github.com/zeromicro/go-zero/core/logx" 17 | ) 18 | 19 | type CreateSubTaskLogic struct { 20 | logx.Logger 21 | ctx context.Context 22 | svcCtx *svc.ServiceContext 23 | } 24 | 25 | func NewCreateSubTaskLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateSubTaskLogic { 26 | return &CreateSubTaskLogic{ 27 | Logger: logx.WithContext(ctx), 28 | ctx: ctx, 29 | svcCtx: svcCtx, 30 | } 31 | } 32 | 33 | func (l *CreateSubTaskLogic) CreateSubTask(req *types.CreateSubTaskReq) (resp *types.CreateSubTaskResp, err error) { 34 | task, err := dao.EntClient.Task.Query(). 35 | Where(enttask.ID(int(req.TaskID))). 36 | First(l.ctx) 37 | if err != nil { 38 | return nil, err 39 | } 40 | data, err := base64.StdEncoding.DecodeString(req.Base64) 41 | if err != nil { 42 | return nil, errors.ErrTaskImageBase64Parse(l.ctx) 43 | } 44 | _, upload, err := basic.UploadStrategy(l.ctx) 45 | if err != nil { 46 | return nil, err 47 | } 48 | path, err := upload.Put(l.ctx, req.Filename, bytes.NewReader(data)) 49 | if err != nil { 50 | return nil, err 51 | } 52 | subTask, err := dao.EntClient.TaskDetail.Create(). 53 | SetCreateTime(time.Now()). 54 | SetUpdateTime(time.Now()). 55 | SetImageURL(path). 56 | SetTaskID(task.ID). 57 | Save(l.ctx) 58 | if err != nil { 59 | return nil, err 60 | } 61 | return &types.CreateSubTaskResp{ 62 | SubTaskID: subTask.ID, 63 | }, nil 64 | } 65 | -------------------------------------------------------------------------------- /service/internal/logic/analysis/getanalysisuserlogic.go: -------------------------------------------------------------------------------- 1 | package analysis 2 | 3 | import ( 4 | "context" 5 | "time" 6 | 7 | "ai-gallery/ent/account" 8 | enttask "ai-gallery/ent/task" 9 | "ai-gallery/pkg/utils" 10 | "ai-gallery/service/internal/dao" 11 | "ai-gallery/service/internal/model" 12 | "ai-gallery/service/internal/svc" 13 | "ai-gallery/service/internal/types" 14 | 15 | "github.com/zeromicro/go-zero/core/logx" 16 | ) 17 | 18 | type GetAnalysisUserLogic struct { 19 | logx.Logger 20 | ctx context.Context 21 | svcCtx *svc.ServiceContext 22 | } 23 | 24 | func NewGetAnalysisUserLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetAnalysisUserLogic { 25 | return &GetAnalysisUserLogic{ 26 | Logger: logx.WithContext(ctx), 27 | ctx: ctx, 28 | svcCtx: svcCtx, 29 | } 30 | } 31 | 32 | func (l *GetAnalysisUserLogic) GetAnalysisUser(req *types.GetAnalysisUserRequest) (resp *types.GetAnalysisUserResponse, err error) { 33 | start := utils.FirstTime(time.Now()).AddDate(0, 0, -1*req.Day-1) 34 | end := utils.LastTime(time.Now()) 35 | 36 | authorBo := make([]*types.AnalysisUserBo, 0) 37 | accounts, err := dao.EntClient.Account.Query().Where( 38 | account.DeleteTimeIsNil(), 39 | account.Status(model.ACTIVE), 40 | ).All(l.ctx) 41 | if err != nil { 42 | return nil, err 43 | } 44 | for _, acc := range accounts { 45 | count, err := dao.EntClient.Task.Query().Where( 46 | enttask.DeleteTimeIsNil(), 47 | enttask.CreateTimeGTE(start), 48 | enttask.CreateTimeLTE(end), 49 | enttask.AuthorID(acc.ID), 50 | ).Count(l.ctx) 51 | if err != nil { 52 | return nil, err 53 | } 54 | authorBo = append(authorBo, &types.AnalysisUserBo{ 55 | AuthorID: acc.ID, 56 | AuthorName: acc.Nickname, 57 | Count: count, 58 | }) 59 | } 60 | return &types.GetAnalysisUserResponse{ 61 | AnalysisUserBo: authorBo, 62 | }, nil 63 | } 64 | -------------------------------------------------------------------------------- /api/analysis.api: -------------------------------------------------------------------------------- 1 | syntax = "v1" 2 | 3 | info ( 4 | title: "数据统计" 5 | version: "v1.0" 6 | ) 7 | 8 | @server ( 9 | group: analysis 10 | middleware: ManageJWT 11 | ) 12 | service gallery-api { 13 | @doc ( 14 | summary: "获取统计基础数据" 15 | ) 16 | @handler GetAnalysisBase 17 | get /api/v1/manage/analysis/base returns (GetAnalysisBaseResponse) 18 | 19 | @doc ( 20 | summary: "获取统计任务数据" 21 | ) 22 | @handler GetAnalysisTask 23 | get /api/v1/manage/analysis/task (GetAnalysisTaskRequest) returns (GetAnalysisTaskResponse) 24 | 25 | @doc ( 26 | summary: "获取统计用户数据" 27 | ) 28 | @handler GetAnalysisUser 29 | get /api/v1/manage/analysis/user (GetAnalysisUserRequest) returns (GetAnalysisUserResponse) 30 | } 31 | 32 | type GetAnalysisUserRequest { 33 | Day int `form:"day,default=1"` // 几天内 34 | } 35 | 36 | type GetAnalysisUserResponse { 37 | AnalysisUserBo []*AnalysisUserBo `json:"users"` 38 | } 39 | 40 | type AnalysisUserBo { 41 | AuthorID int `json:"author_id"` 42 | AuthorName string `json:"author_name"` 43 | Count int `json:"count"` 44 | } 45 | 46 | type GetAnalysisTaskRequest { 47 | Day int `form:"day,default=7"` // 几天内 48 | } 49 | 50 | type GetAnalysisTaskResponse { 51 | Times []string `json:"times"` 52 | AnalysisTaskBo []*AnalysisTaskBo `json:"tasks"` 53 | } 54 | 55 | type AnalysisTaskBo { 56 | Name string `json:"name"` 57 | EnName string `json:"en_name"` 58 | Data []int `json:"data"` 59 | } 60 | 61 | type GetAnalysisBaseResponse { 62 | TaskTotal int `json:"task_total"` // 任务总数 63 | WorkTotal int `json:"work_total"` // 作品总数 64 | ExcellentTotal int `json:"excellent_total"` // 优秀作品数 65 | AccountTotal int `json:"account_total"` // 用户总数 66 | TodayTaskCount int `json:"today_task_count"` // 今日任务数 67 | TodayWorkCount int `json:"today_work_count"` // 今日作品总数 68 | TodayExcellentCount int `json:"today_excellent_count"` // 今日优秀作品数 69 | } 70 | 71 | -------------------------------------------------------------------------------- /service/internal/logic/basic/common.go: -------------------------------------------------------------------------------- 1 | package basic 2 | 3 | import ( 4 | "ai-gallery/pkg/jwt" 5 | "ai-gallery/service/internal/dao/account" 6 | "context" 7 | 8 | "ai-gallery/ent" 9 | "ai-gallery/service/internal/errors" 10 | "ai-gallery/service/internal/model" 11 | 12 | "golang.org/x/crypto/bcrypt" 13 | ) 14 | 15 | func GetAuthorIDsByRole(ctx context.Context, authorIDs []int) ([]int, error) { 16 | jwtInfo, err := ContextElement(ctx) 17 | if err != nil { 18 | return nil, err 19 | } 20 | // 普通用户只能看自己的数据. 21 | if jwtInfo.Role == model.USER { 22 | return []int{jwtInfo.ID}, nil 23 | } 24 | return authorIDs, nil 25 | } 26 | 27 | func ContextElement(ctx context.Context) (*jwt.Claims, error) { 28 | if info, ok := ctx.Value(model.UserToken).(*jwt.Claims); ok { 29 | return info, nil 30 | } 31 | return nil, errors.ErrAccountTokenNotFound(ctx) 32 | } 33 | 34 | func ValidateAccount(ctx context.Context, username, password string) (*ent.Account, error) { 35 | user, err := account.GetByUsername(ctx, username) 36 | if err != nil { 37 | if ent.IsNotFound(err) { 38 | return nil, errors.ErrAccountNotFound(ctx) 39 | } 40 | return nil, err 41 | } 42 | if user.Status == model.DISABLED { 43 | return nil, errors.ErrAccountDisabled(ctx) 44 | } 45 | if err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password+model.PwdSalt)); err != nil { 46 | return nil, errors.ErrAccountPwd(ctx) 47 | } 48 | return user, nil 49 | } 50 | 51 | func CheckAccountStatus(ctx context.Context, id int) error { 52 | acc, err := account.GetByID(ctx, id) 53 | if err != nil { 54 | if ent.IsNotFound(err) { 55 | return errors.ErrAccountNotFound(ctx) 56 | } 57 | return err 58 | } 59 | if acc.Status == model.DISABLED { 60 | return errors.ErrAccountDisabled(ctx) 61 | } 62 | return nil 63 | } 64 | 65 | func CheckPermission(ctx context.Context, claims *jwt.Claims) error { 66 | if claims.Role != model.ADMIN { 67 | return errors.ErrAccountPermission(ctx) 68 | } 69 | return nil 70 | } 71 | -------------------------------------------------------------------------------- /service/internal/dao/account/account.go: -------------------------------------------------------------------------------- 1 | package account 2 | 3 | import ( 4 | "ai-gallery/service/internal/dao" 5 | "context" 6 | "time" 7 | 8 | "ai-gallery/ent" 9 | entaccount "ai-gallery/ent/account" 10 | "github.com/duke-git/lancet/v2/strutil" 11 | ) 12 | 13 | type PO struct { 14 | ID int `json:"id"` 15 | Username string `json:"username"` 16 | Nickname string `json:"nickname"` 17 | Password string `json:"password"` 18 | Role string `json:"role"` 19 | Status int `json:"status"` 20 | DeleteTime *time.Time `json:"delete_time"` 21 | } 22 | 23 | func GetByID(ctx context.Context, id int) (*ent.Account, error) { 24 | return dao.EntClient.Account.Query().Where( 25 | entaccount.ID(id), 26 | entaccount.DeleteTimeIsNil(), 27 | ).First(ctx) 28 | } 29 | 30 | func GetByUsername(ctx context.Context, username string) (*ent.Account, error) { 31 | return dao.EntClient.Account.Query().Where( 32 | entaccount.Username(username), 33 | entaccount.DeleteTimeIsNil(), 34 | ).First(ctx) 35 | } 36 | 37 | func Create(ctx context.Context, po *PO) error { 38 | return dao.EntClient.Account.Create(). 39 | SetCreateTime(time.Now()). 40 | SetUpdateTime(time.Now()). 41 | SetUsername(po.Username). 42 | SetNickname(po.Nickname). 43 | SetPassword(po.Password). 44 | SetStatus(po.Status). 45 | SetRole(po.Role). 46 | Exec(ctx) 47 | } 48 | 49 | func Update(ctx context.Context, po *PO) error { 50 | update := dao.EntClient.Account.Update() 51 | if strutil.IsNotBlank(po.Username) { 52 | update.SetUsername(po.Username) 53 | } 54 | if strutil.IsNotBlank(po.Nickname) { 55 | update.SetNickname(po.Nickname) 56 | } 57 | if strutil.IsNotBlank(po.Role) { 58 | update.SetRole(po.Role) 59 | } 60 | if strutil.IsNotBlank(po.Password) { 61 | update.SetPassword(po.Password) 62 | } 63 | if po.Status != -1 { 64 | update.SetStatus(po.Status) 65 | } 66 | if po.DeleteTime != nil { 67 | update.SetNillableDeleteTime(po.DeleteTime) 68 | } 69 | return update. 70 | Where(entaccount.ID(po.ID), entaccount.DeleteTimeIsNil()). 71 | Exec(ctx) 72 | } 73 | -------------------------------------------------------------------------------- /service/internal/logic/account/updateuserdetaillogic.go: -------------------------------------------------------------------------------- 1 | package account 2 | 3 | import ( 4 | "context" 5 | 6 | "ai-gallery/ent" 7 | "ai-gallery/service/internal/dao/account" 8 | "ai-gallery/service/internal/dao/task" 9 | "ai-gallery/service/internal/errors" 10 | "ai-gallery/service/internal/model" 11 | "ai-gallery/service/internal/svc" 12 | "ai-gallery/service/internal/types" 13 | 14 | "github.com/duke-git/lancet/v2/strutil" 15 | "github.com/zeromicro/go-zero/core/logx" 16 | "golang.org/x/crypto/bcrypt" 17 | ) 18 | 19 | type UpdateUserDetailLogic struct { 20 | logx.Logger 21 | ctx context.Context 22 | svcCtx *svc.ServiceContext 23 | } 24 | 25 | func NewUpdateUserDetailLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdateUserDetailLogic { 26 | return &UpdateUserDetailLogic{ 27 | Logger: logx.WithContext(ctx), 28 | ctx: ctx, 29 | svcCtx: svcCtx, 30 | } 31 | } 32 | 33 | func (l *UpdateUserDetailLogic) UpdateUserDetail(req *types.UpdateUserDetailRequest) error { 34 | acc, err := account.GetByID(l.ctx, req.UserID) 35 | if err != nil { 36 | return err 37 | } 38 | if acc.Username != req.Username { 39 | other, err := account.GetByUsername(l.ctx, req.Username) 40 | if err != nil && !ent.IsNotFound(err) { 41 | return err 42 | } 43 | err = nil 44 | if other != nil { 45 | return errors.ErrAccountUsernameExist(l.ctx) 46 | } 47 | } 48 | newPwd := make([]byte, 0) 49 | if strutil.IsNotBlank(req.NewPassword) { 50 | if err = bcrypt.CompareHashAndPassword([]byte(acc.Password), []byte(req.OldPassword+model.PwdSalt)); err != nil { 51 | return errors.ErrAccountPwd(l.ctx) 52 | } 53 | newPwd, err = bcrypt.GenerateFromPassword([]byte(req.NewPassword+model.PwdSalt), bcrypt.DefaultCost) 54 | if err != nil { 55 | return err 56 | } 57 | } 58 | if err = account.Update(l.ctx, &account.PO{ 59 | ID: req.UserID, 60 | Username: req.Username, 61 | Nickname: req.Nickname, 62 | Password: string(newPwd), 63 | Status: -1, 64 | }); err != nil { 65 | return err 66 | } 67 | if acc.Nickname != req.Nickname { 68 | // 修改了昵称 69 | return task.UpdateAuthorInfo(l.ctx, acc.ID, req.Nickname) 70 | } 71 | return nil 72 | } 73 | -------------------------------------------------------------------------------- /service/internal/logic/account/getuserlogic.go: -------------------------------------------------------------------------------- 1 | package account 2 | 3 | import ( 4 | "context" 5 | 6 | entaccount "ai-gallery/ent/account" 7 | "ai-gallery/service/internal/dao" 8 | "ai-gallery/service/internal/svc" 9 | "ai-gallery/service/internal/types" 10 | 11 | "entgo.io/ent/dialect/sql" 12 | "github.com/duke-git/lancet/v2/strutil" 13 | "github.com/zeromicro/go-zero/core/logx" 14 | ) 15 | 16 | type GetUserLogic struct { 17 | logx.Logger 18 | ctx context.Context 19 | svcCtx *svc.ServiceContext 20 | } 21 | 22 | func NewGetUserLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetUserLogic { 23 | return &GetUserLogic{ 24 | Logger: logx.WithContext(ctx), 25 | ctx: ctx, 26 | svcCtx: svcCtx, 27 | } 28 | } 29 | 30 | func (l *GetUserLogic) GetUser(req *types.GetUserRequest) (resp *types.GetUserResponse, err error) { 31 | query := dao.EntClient.Account.Query().Where( 32 | entaccount.DeleteTimeIsNil(), 33 | ) 34 | if strutil.IsNotBlank(req.Username) { 35 | query.Where(func(s *sql.Selector) { 36 | s.Where(sql.Like(entaccount.FieldUsername, "%"+req.Username+"%")) 37 | }) 38 | } 39 | if strutil.IsNotBlank(req.Nickname) { 40 | query.Where(func(s *sql.Selector) { 41 | s.Where(sql.Like(entaccount.FieldNickname, "%"+req.Nickname+"%")) 42 | }) 43 | } 44 | if strutil.IsNotBlank(req.Role) { 45 | query.Where(entaccount.Role(req.Role)) 46 | } 47 | if req.Status != -1 { 48 | query.Where(entaccount.Status(req.Status)) 49 | } 50 | count, err := query.Count(l.ctx) 51 | if err != nil { 52 | return nil, err 53 | } 54 | userBo := make([]*types.UserBo, 0) 55 | if count == 0 { 56 | return &types.GetUserResponse{ 57 | Total: count, 58 | Data: userBo, 59 | }, nil 60 | } 61 | accounts, err := query.Offset(req.Offset).Limit(req.Limit).All(l.ctx) 62 | if err != nil { 63 | return nil, err 64 | } 65 | for _, acc := range accounts { 66 | userBo = append(userBo, &types.UserBo{ 67 | UserID: acc.ID, 68 | Username: acc.Username, 69 | Nickname: acc.Nickname, 70 | Role: acc.Role, 71 | Status: acc.Status, 72 | }) 73 | } 74 | return &types.GetUserResponse{ 75 | Total: count, 76 | Data: userBo, 77 | }, nil 78 | } 79 | -------------------------------------------------------------------------------- /ent/enttest/enttest.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package enttest 4 | 5 | import ( 6 | "ai-gallery/ent" 7 | "context" 8 | // required by schema hooks. 9 | _ "ai-gallery/ent/runtime" 10 | 11 | "ai-gallery/ent/migrate" 12 | 13 | "entgo.io/ent/dialect/sql/schema" 14 | ) 15 | 16 | type ( 17 | // TestingT is the interface that is shared between 18 | // testing.T and testing.B and used by enttest. 19 | TestingT interface { 20 | FailNow() 21 | Error(...any) 22 | } 23 | 24 | // Option configures client creation. 25 | Option func(*options) 26 | 27 | options struct { 28 | opts []ent.Option 29 | migrateOpts []schema.MigrateOption 30 | } 31 | ) 32 | 33 | // WithOptions forwards options to client creation. 34 | func WithOptions(opts ...ent.Option) Option { 35 | return func(o *options) { 36 | o.opts = append(o.opts, opts...) 37 | } 38 | } 39 | 40 | // WithMigrateOptions forwards options to auto migration. 41 | func WithMigrateOptions(opts ...schema.MigrateOption) Option { 42 | return func(o *options) { 43 | o.migrateOpts = append(o.migrateOpts, opts...) 44 | } 45 | } 46 | 47 | func newOptions(opts []Option) *options { 48 | o := &options{} 49 | for _, opt := range opts { 50 | opt(o) 51 | } 52 | return o 53 | } 54 | 55 | // Open calls ent.Open and auto-run migration. 56 | func Open(t TestingT, driverName, dataSourceName string, opts ...Option) *ent.Client { 57 | o := newOptions(opts) 58 | c, err := ent.Open(driverName, dataSourceName, o.opts...) 59 | if err != nil { 60 | t.Error(err) 61 | t.FailNow() 62 | } 63 | migrateSchema(t, c, o) 64 | return c 65 | } 66 | 67 | // NewClient calls ent.NewClient and auto-run migration. 68 | func NewClient(t TestingT, opts ...Option) *ent.Client { 69 | o := newOptions(opts) 70 | c := ent.NewClient(o.opts...) 71 | migrateSchema(t, c, o) 72 | return c 73 | } 74 | func migrateSchema(t TestingT, c *ent.Client, o *options) { 75 | tables, err := schema.CopyTables(migrate.Tables) 76 | if err != nil { 77 | t.Error(err) 78 | t.FailNow() 79 | } 80 | if err := migrate.Create(context.Background(), c.Schema, tables, o.migrateOpts...); err != nil { 81 | t.Error(err) 82 | t.FailNow() 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /service/internal/model/enums.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import "reflect" 4 | 5 | // 用户状态 6 | const ( 7 | DISABLED = 0 // 不可用 8 | ACTIVE = 1 // 可用 9 | ) 10 | 11 | // 用户权限码 12 | const ( 13 | ADMIN = "ADMIN" // 管理用户 14 | USER = "USER" // 普通用户 15 | ) 16 | 17 | type Enum struct { 18 | Code string `json:"code"` 19 | Name string `json:"name"` 20 | } 21 | 22 | func NewEnum(code, name string) *Enum { 23 | return &Enum{Code: code, Name: name} 24 | } 25 | 26 | func Values(obj any) []*Enum { 27 | var enums []*Enum 28 | val := reflect.ValueOf(obj).Elem() 29 | 30 | for i := 0; i < val.NumField(); i++ { 31 | field := val.Field(i) 32 | if !field.IsNil() { 33 | enums = append(enums, field.Interface().(*Enum)) 34 | } 35 | } 36 | return enums 37 | } 38 | 39 | // UploadServiceEnum 上传配置 40 | type UploadServiceEnum struct { 41 | Local *Enum 42 | Tx *Enum 43 | Aliyun *Enum 44 | } 45 | 46 | var UploadEnums = &UploadServiceEnum{ 47 | Local: NewEnum("local", "本地存储"), 48 | Tx: NewEnum("cos", "腾讯云"), 49 | Aliyun: NewEnum("oss", "阿里云"), 50 | } 51 | 52 | func (t *UploadServiceEnum) Values() []*Enum { 53 | return Values(t) 54 | } 55 | 56 | // SettingEnum 系统配置 57 | type SettingEnum struct { 58 | StoreName *Enum 59 | StoreAddress *Enum 60 | SecureID *Enum 61 | SecureKey *Enum 62 | StoreBucket *Enum 63 | InitPwd *Enum 64 | } 65 | 66 | var SettingEnums = &SettingEnum{ 67 | StoreName: NewEnum("STORE_NAME", "存储名称"), 68 | StoreAddress: NewEnum("STORE_ADDRESS", "存储地址"), 69 | SecureID: NewEnum("SECURE_ID", "存储ID"), 70 | SecureKey: NewEnum("SECURE_KEY", "存储KEY"), 71 | StoreBucket: NewEnum("STORE_BUCKET", "存储桶"), 72 | InitPwd: NewEnum("INIT_PWD", "初始化密码"), 73 | } 74 | 75 | func (t *SettingEnum) Values() []*Enum { 76 | return Values(t) 77 | } 78 | 79 | // TaskStatusEnum 任务状态. 80 | type TaskStatusEnum struct { 81 | Progress *Enum 82 | Complete *Enum 83 | Exception *Enum 84 | } 85 | 86 | var TaskStatusEnums = &TaskStatusEnum{ 87 | Progress: NewEnum("PROGRESS", "处理中"), 88 | Complete: NewEnum("COMPLETE", "已完成"), 89 | Exception: NewEnum("EXCEPTION", "异常"), 90 | } 91 | 92 | func (t *TaskStatusEnum) Values() []*Enum { 93 | return Values(t) 94 | } 95 | -------------------------------------------------------------------------------- /api/task.api: -------------------------------------------------------------------------------- 1 | syntax = "v1" 2 | 3 | info ( 4 | title: "任务功能" 5 | version: "v1.0" 6 | ) 7 | 8 | @server ( 9 | group: task 10 | middleware: Headers 11 | ) 12 | service gallery-api { 13 | @doc ( 14 | summary: "创建任务" 15 | ) 16 | @handler CreateTask 17 | post /api/v1/task (CreateTaskReq) returns (CreateTaskResp) 18 | 19 | @doc ( 20 | summary: "创建子任务" 21 | ) 22 | @handler CreateSubTask 23 | post /api/v1/sub_task (CreateSubTaskReq) returns (CreateSubTaskResp) 24 | 25 | @doc ( 26 | summary: "更新任务" 27 | ) 28 | @handler UpdateTask 29 | put /api/v1/task/:task_id (UpdateTaskReq) 30 | } 31 | 32 | type CreateTaskReq { 33 | Category string `json:"category"` 34 | Prompt string `json:"prompt"` 35 | NegativePrompt string `json:"negative_prompt"` 36 | RefImages []TaskImage `json:"ref_images"` 37 | Width float32 `json:"width"` 38 | Height float32 `json:"height"` 39 | Seed string `json:"seed"` 40 | SamplerName string `json:"sampler_name"` 41 | Steps int `json:"steps"` // 采样步数 42 | CfgScale int `json:"cfg_scale"` 43 | BatchSize int `json:"batch_size"` 44 | Total int `json:"total"` 45 | SdModelName string `json:"sd_model_name"` 46 | SdModelHash string `json:"sd_model_hash"` 47 | SdVaeName *string `json:"sd_vae_name,optional"` 48 | SdVaeHash *string `json:"sd_vae_hash,optional"` 49 | JobTimestamp string `json:"job_timestamp"` 50 | Version string `json:"version"` 51 | } 52 | 53 | type CreateTaskResp { 54 | TaskID int `json:"task_id"` 55 | } 56 | 57 | type CreateSubTaskReq { 58 | TaskID int64 `json:"task_id"` 59 | Base64 string `json:"base64"` 60 | Filename string `json:"filename"` 61 | } 62 | 63 | type CreateSubTaskResp { 64 | SubTaskID int `json:"sub_task_id"` 65 | } 66 | 67 | type TaskImage { 68 | Base64 string `json:"base64"` 69 | Filename string `json:"filename"` 70 | } 71 | 72 | type UpdateTaskReq { 73 | TaskID int `path:"task_id"` 74 | Base64 string `json:"base64,optional"` 75 | Filename string `json:"filename,optional"` 76 | Extra string `json:"extra,optional"` 77 | } 78 | 79 | -------------------------------------------------------------------------------- /service/internal/logic/task/updatetasklogic.go: -------------------------------------------------------------------------------- 1 | package task 2 | 3 | import ( 4 | "ai-gallery/service/internal/dao" 5 | "bytes" 6 | "context" 7 | "encoding/base64" 8 | "time" 9 | 10 | enttask "ai-gallery/ent/task" 11 | "ai-gallery/ent/taskdetail" 12 | "ai-gallery/service/internal/errors" 13 | basic "ai-gallery/service/internal/logic/basic/upload" 14 | "ai-gallery/service/internal/model" 15 | "ai-gallery/service/internal/svc" 16 | "ai-gallery/service/internal/types" 17 | 18 | "github.com/duke-git/lancet/v2/strutil" 19 | "github.com/zeromicro/go-zero/core/logx" 20 | ) 21 | 22 | type UpdateTaskLogic struct { 23 | logx.Logger 24 | ctx context.Context 25 | svcCtx *svc.ServiceContext 26 | } 27 | 28 | func NewUpdateTaskLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdateTaskLogic { 29 | return &UpdateTaskLogic{ 30 | Logger: logx.WithContext(ctx), 31 | ctx: ctx, 32 | svcCtx: svcCtx, 33 | } 34 | } 35 | 36 | func (l *UpdateTaskLogic) UpdateTask(req *types.UpdateTaskReq) error { 37 | task, err := dao.EntClient.Task.Query(). 38 | Where(enttask.ID(req.TaskID)). 39 | First(l.ctx) 40 | if err != nil { 41 | return err 42 | } 43 | count, err := dao.EntClient.TaskDetail.Query().Where( 44 | taskdetail.TaskID(req.TaskID), 45 | taskdetail.DeleteTimeIsNil(), 46 | ).Count(l.ctx) 47 | if err != nil { 48 | return err 49 | } 50 | status := model.TaskStatusEnums.Complete.Code 51 | if task.Total != count { 52 | status = model.TaskStatusEnums.Exception.Code 53 | } 54 | path := "" 55 | if strutil.IsNotBlank(req.Base64) { 56 | data, err := base64.StdEncoding.DecodeString(req.Base64) 57 | if err != nil { 58 | return errors.ErrTaskImageBase64Parse(l.ctx) 59 | } 60 | _, upload, err := basic.UploadStrategy(l.ctx) 61 | if err != nil { 62 | return err 63 | } 64 | path, err = upload.Put(l.ctx, req.Filename, bytes.NewReader(data)) 65 | if err != nil { 66 | return err 67 | } 68 | } 69 | if err = dao.EntClient.Task.Update(). 70 | SetStatus(status). 71 | SetUpdateTime(time.Now()). 72 | SetGridImageURL(path). 73 | SetCount(count). 74 | SetExtra(req.Extra). 75 | Where(enttask.ID(req.TaskID)). 76 | Exec(l.ctx); err != nil { 77 | return err 78 | } 79 | return nil 80 | } 81 | -------------------------------------------------------------------------------- /service/internal/logic/work/getworkdetaillogic.go: -------------------------------------------------------------------------------- 1 | package work 2 | 3 | import ( 4 | "ai-gallery/service/internal/dao" 5 | "ai-gallery/service/internal/dao/task" 6 | "context" 7 | "time" 8 | 9 | enttaskdetail "ai-gallery/ent/taskdetail" 10 | "ai-gallery/service/internal/svc" 11 | "ai-gallery/service/internal/types" 12 | 13 | "github.com/zeromicro/go-zero/core/logx" 14 | ) 15 | 16 | type GetWorkDetailLogic struct { 17 | logx.Logger 18 | ctx context.Context 19 | svcCtx *svc.ServiceContext 20 | } 21 | 22 | func NewGetWorkDetailLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetWorkDetailLogic { 23 | return &GetWorkDetailLogic{ 24 | Logger: logx.WithContext(ctx), 25 | ctx: ctx, 26 | svcCtx: svcCtx, 27 | } 28 | } 29 | 30 | func (l *GetWorkDetailLogic) GetWorkDetail(req *types.GetWorkDetailRequest) (resp *types.GetWorkDetailResponse, err error) { 31 | t, err := task.GetByID(l.ctx, req.TaskID) 32 | if err != nil { 33 | return nil, err 34 | } 35 | details, err := dao.EntClient.TaskDetail.Query().Where( 36 | enttaskdetail.DeleteTimeIsNil(), 37 | enttaskdetail.TaskID(t.ID), 38 | ).All(l.ctx) 39 | if err != nil { 40 | return nil, err 41 | } 42 | bos := make([]*types.WorkDetailBo, 0) 43 | for _, d := range details { 44 | bos = append(bos, &types.WorkDetailBo{ 45 | SubTaskID: d.ID, 46 | ImageURL: d.ImageURL, 47 | HasExcellent: d.HasExcellent, 48 | }) 49 | } 50 | return &types.GetWorkDetailResponse{ 51 | TaskID: t.ID, 52 | Category: t.Category, 53 | Prompt: t.Prompt, 54 | NegativePrompt: t.NegativePrompt, 55 | Width: t.Weight, 56 | Height: t.Height, 57 | Size: t.ImgSize, 58 | Seed: t.Seed, 59 | SamplerName: t.SamplerName, 60 | Steps: t.Steps, 61 | CfgScale: t.CfgScale, 62 | BatchSize: t.BatchSize, 63 | Total: t.Total, 64 | SdModelHash: t.SdModelHash, 65 | SdModelName: t.SdModelName, 66 | SdVaeHash: t.SdVaeHash, 67 | SdVaeName: t.SdVaeName, 68 | JobTimestamp: t.JobTimestamp.Format(time.DateTime), 69 | Version: t.Version, 70 | AuthorID: t.AuthorID, 71 | AuthorName: t.AuthorName, 72 | RefImages: t.RefImages, 73 | WorkDetailBos: bos, 74 | }, nil 75 | } 76 | -------------------------------------------------------------------------------- /ent/task_delete.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | import ( 6 | "ai-gallery/ent/predicate" 7 | "ai-gallery/ent/task" 8 | "context" 9 | 10 | "entgo.io/ent/dialect/sql" 11 | "entgo.io/ent/dialect/sql/sqlgraph" 12 | "entgo.io/ent/schema/field" 13 | ) 14 | 15 | // TaskDelete is the builder for deleting a Task entity. 16 | type TaskDelete struct { 17 | config 18 | hooks []Hook 19 | mutation *TaskMutation 20 | } 21 | 22 | // Where appends a list predicates to the TaskDelete builder. 23 | func (td *TaskDelete) Where(ps ...predicate.Task) *TaskDelete { 24 | td.mutation.Where(ps...) 25 | return td 26 | } 27 | 28 | // Exec executes the deletion query and returns how many vertices were deleted. 29 | func (td *TaskDelete) Exec(ctx context.Context) (int, error) { 30 | return withHooks(ctx, td.sqlExec, td.mutation, td.hooks) 31 | } 32 | 33 | // ExecX is like Exec, but panics if an error occurs. 34 | func (td *TaskDelete) ExecX(ctx context.Context) int { 35 | n, err := td.Exec(ctx) 36 | if err != nil { 37 | panic(err) 38 | } 39 | return n 40 | } 41 | 42 | func (td *TaskDelete) sqlExec(ctx context.Context) (int, error) { 43 | _spec := sqlgraph.NewDeleteSpec(task.Table, sqlgraph.NewFieldSpec(task.FieldID, field.TypeInt)) 44 | if ps := td.mutation.predicates; len(ps) > 0 { 45 | _spec.Predicate = func(selector *sql.Selector) { 46 | for i := range ps { 47 | ps[i](selector) 48 | } 49 | } 50 | } 51 | affected, err := sqlgraph.DeleteNodes(ctx, td.driver, _spec) 52 | if err != nil && sqlgraph.IsConstraintError(err) { 53 | err = &ConstraintError{msg: err.Error(), wrap: err} 54 | } 55 | td.mutation.done = true 56 | return affected, err 57 | } 58 | 59 | // TaskDeleteOne is the builder for deleting a single Task entity. 60 | type TaskDeleteOne struct { 61 | td *TaskDelete 62 | } 63 | 64 | // Where appends a list predicates to the TaskDelete builder. 65 | func (tdo *TaskDeleteOne) Where(ps ...predicate.Task) *TaskDeleteOne { 66 | tdo.td.mutation.Where(ps...) 67 | return tdo 68 | } 69 | 70 | // Exec executes the deletion query. 71 | func (tdo *TaskDeleteOne) Exec(ctx context.Context) error { 72 | n, err := tdo.td.Exec(ctx) 73 | switch { 74 | case err != nil: 75 | return err 76 | case n == 0: 77 | return &NotFoundError{task.Label} 78 | default: 79 | return nil 80 | } 81 | } 82 | 83 | // ExecX is like Exec, but panics if an error occurs. 84 | func (tdo *TaskDeleteOne) ExecX(ctx context.Context) { 85 | if err := tdo.Exec(ctx); err != nil { 86 | panic(err) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /ent/schema/task.go: -------------------------------------------------------------------------------- 1 | package schema 2 | 3 | import ( 4 | "entgo.io/ent" 5 | "entgo.io/ent/dialect" 6 | "entgo.io/ent/dialect/entsql" 7 | "entgo.io/ent/schema" 8 | "entgo.io/ent/schema/field" 9 | "entgo.io/ent/schema/index" 10 | ) 11 | 12 | type Task struct { 13 | BaseSchema 14 | } 15 | 16 | func (Task) Fields() []ent.Field { 17 | datetime := map[string]string{dialect.MySQL: "datetime"} 18 | return []ent.Field{ 19 | field.Text("prompt").Optional().Comment("提示词"), 20 | field.Text("negative_prompt").Optional().Comment("反向提示词"), 21 | field.String("category").MaxLen(20).Optional().Comment("类型: txt2img, img2img"), 22 | field.Float32("weight").Optional().Comment("长度"), 23 | field.Float32("height").Optional().Comment("宽度"), 24 | field.String("img_size").MaxLen(20).Optional().Comment("图片比例"), 25 | field.String("seed").MaxLen(20).Optional().Comment("随机数"), 26 | field.String("sampler_name").MaxLen(50).Optional().Comment("采样器"), 27 | field.Int("steps").Optional().Comment("采样步数"), 28 | field.Int("cfg_scale").Optional().Comment("引导系数"), 29 | field.Int("batch_size").Optional().Comment("批次"), 30 | field.Int("total").Optional().Comment("总量"), 31 | field.String("sd_model_name").MaxLen(100).Optional().Comment("模型名称"), 32 | field.String("sd_model_hash").MaxLen(50).Optional().Comment("模型hash值"), 33 | field.String("sd_vae_name").MaxLen(100).Optional().Comment("VAE名称"), 34 | field.String("sd_vae_hash").MaxLen(50).Optional().Comment("VAE hash值"), 35 | field.Time("job_timestamp").SchemaType(datetime).Optional().Comment("任务时间"), 36 | field.String("version").MaxLen(20).Optional().Comment("SD 版本号"), 37 | field.String("grid_image_url").MaxLen(255).Optional().Comment("网格图片地址"), 38 | field.String("status").MaxLen(20).Optional().Comment("状态:INIT, PROCESS, COMPLETE, EXCEPTION"), 39 | field.Int("author_id").Optional().Comment("作者ID"), 40 | field.String("author_name").MaxLen(30).Optional().Comment("作者名称"), 41 | field.JSON("ref_images", []string{}).Optional().Comment("参考图片"), 42 | field.String("store").Optional().Comment("服务存储名称"), 43 | field.Int("count").Optional().Comment("实际作品数量"), 44 | field.Bool("has_excellent").Optional().Comment("是否存在优秀作品"), 45 | field.Text("extra").Optional().Comment("扩展信息"), 46 | } 47 | } 48 | 49 | func (Task) Edges() []ent.Edge { 50 | return nil 51 | } 52 | 53 | func (Task) Indexes() []ent.Index { 54 | return []ent.Index{ 55 | index.Fields("author_id"), 56 | } 57 | } 58 | 59 | func (Task) Annotations() []schema.Annotation { 60 | return []schema.Annotation{ 61 | entsql.Annotation{Table: "core_task"}, 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /service/internal/logic/work/getworklogic.go: -------------------------------------------------------------------------------- 1 | package work 2 | 3 | import ( 4 | "ai-gallery/service/internal/dao" 5 | "ai-gallery/service/internal/dao/task" 6 | "context" 7 | 8 | "ai-gallery/ent" 9 | enttask "ai-gallery/ent/task" 10 | enttaskdetail "ai-gallery/ent/taskdetail" 11 | "ai-gallery/service/internal/svc" 12 | "ai-gallery/service/internal/types" 13 | 14 | "github.com/zeromicro/go-zero/core/logx" 15 | ) 16 | 17 | type GetWorkLogic struct { 18 | logx.Logger 19 | ctx context.Context 20 | svcCtx *svc.ServiceContext 21 | } 22 | 23 | func NewGetWorkLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetWorkLogic { 24 | return &GetWorkLogic{ 25 | Logger: logx.WithContext(ctx), 26 | ctx: ctx, 27 | svcCtx: svcCtx, 28 | } 29 | } 30 | 31 | func (l *GetWorkLogic) GetWork(req *types.GetWorkRequest) (resp *types.GetWorkResponse, err error) { 32 | query := task.GetQueryByPO(&task.PO{ 33 | Size: req.Size, 34 | SdModelName: req.SdModelName, 35 | HasRefImage: req.HasRefImage, 36 | HasExcellent: req.HasExcellent, 37 | Sorted: req.Sorted, 38 | }).Where(enttask.CountGT(0)) 39 | 40 | count, err := query.Count(l.ctx) 41 | if err != nil { 42 | return nil, err 43 | } 44 | 45 | data := make([]*types.WorkBo, 0) 46 | if count == 0 { 47 | return &types.GetWorkResponse{ 48 | Data: data, 49 | Total: count, 50 | }, nil 51 | } 52 | tasks, err := query.Offset(req.Offset).Limit(req.Limit).All(l.ctx) 53 | if err != nil { 54 | return nil, err 55 | } 56 | taskIDs := make([]int, 0) 57 | for _, t := range tasks { 58 | taskIDs = append(taskIDs, t.ID) 59 | } 60 | headImageMap := make(map[int]*ent.TaskDetail, 0) 61 | details, err := dao.EntClient.TaskDetail.Query().Where( 62 | enttaskdetail.DeleteTimeIsNil(), 63 | enttaskdetail.TaskIDIn(taskIDs...), 64 | ).All(l.ctx) 65 | if err != nil { 66 | return nil, err 67 | } 68 | for _, detail := range details { 69 | if headImageMap[detail.TaskID] == nil || 70 | (detail.HasExcellent && !headImageMap[detail.TaskID].HasExcellent) { 71 | headImageMap[detail.TaskID] = detail 72 | } 73 | } 74 | for _, t := range tasks { 75 | if headImageMap[t.ID] == nil { 76 | continue 77 | } 78 | data = append(data, &types.WorkBo{ 79 | TaskID: t.ID, 80 | Category: t.Category, 81 | Prompt: t.Prompt, 82 | Size: t.ImgSize, 83 | AuthorID: t.AuthorID, 84 | AuthorName: t.AuthorName, 85 | Count: t.Count, 86 | HeadImage: headImageMap[t.ID].ImageURL, 87 | }) 88 | } 89 | return &types.GetWorkResponse{ 90 | Data: data, 91 | Total: count, 92 | }, nil 93 | } 94 | -------------------------------------------------------------------------------- /ent/account_delete.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | import ( 6 | "ai-gallery/ent/account" 7 | "ai-gallery/ent/predicate" 8 | "context" 9 | 10 | "entgo.io/ent/dialect/sql" 11 | "entgo.io/ent/dialect/sql/sqlgraph" 12 | "entgo.io/ent/schema/field" 13 | ) 14 | 15 | // AccountDelete is the builder for deleting a Account entity. 16 | type AccountDelete struct { 17 | config 18 | hooks []Hook 19 | mutation *AccountMutation 20 | } 21 | 22 | // Where appends a list predicates to the AccountDelete builder. 23 | func (ad *AccountDelete) Where(ps ...predicate.Account) *AccountDelete { 24 | ad.mutation.Where(ps...) 25 | return ad 26 | } 27 | 28 | // Exec executes the deletion query and returns how many vertices were deleted. 29 | func (ad *AccountDelete) Exec(ctx context.Context) (int, error) { 30 | return withHooks(ctx, ad.sqlExec, ad.mutation, ad.hooks) 31 | } 32 | 33 | // ExecX is like Exec, but panics if an error occurs. 34 | func (ad *AccountDelete) ExecX(ctx context.Context) int { 35 | n, err := ad.Exec(ctx) 36 | if err != nil { 37 | panic(err) 38 | } 39 | return n 40 | } 41 | 42 | func (ad *AccountDelete) sqlExec(ctx context.Context) (int, error) { 43 | _spec := sqlgraph.NewDeleteSpec(account.Table, sqlgraph.NewFieldSpec(account.FieldID, field.TypeInt)) 44 | if ps := ad.mutation.predicates; len(ps) > 0 { 45 | _spec.Predicate = func(selector *sql.Selector) { 46 | for i := range ps { 47 | ps[i](selector) 48 | } 49 | } 50 | } 51 | affected, err := sqlgraph.DeleteNodes(ctx, ad.driver, _spec) 52 | if err != nil && sqlgraph.IsConstraintError(err) { 53 | err = &ConstraintError{msg: err.Error(), wrap: err} 54 | } 55 | ad.mutation.done = true 56 | return affected, err 57 | } 58 | 59 | // AccountDeleteOne is the builder for deleting a single Account entity. 60 | type AccountDeleteOne struct { 61 | ad *AccountDelete 62 | } 63 | 64 | // Where appends a list predicates to the AccountDelete builder. 65 | func (ado *AccountDeleteOne) Where(ps ...predicate.Account) *AccountDeleteOne { 66 | ado.ad.mutation.Where(ps...) 67 | return ado 68 | } 69 | 70 | // Exec executes the deletion query. 71 | func (ado *AccountDeleteOne) Exec(ctx context.Context) error { 72 | n, err := ado.ad.Exec(ctx) 73 | switch { 74 | case err != nil: 75 | return err 76 | case n == 0: 77 | return &NotFoundError{account.Label} 78 | default: 79 | return nil 80 | } 81 | } 82 | 83 | // ExecX is like Exec, but panics if an error occurs. 84 | func (ado *AccountDeleteOne) ExecX(ctx context.Context) { 85 | if err := ado.Exec(ctx); err != nil { 86 | panic(err) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /ent/setting_delete.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | import ( 6 | "ai-gallery/ent/predicate" 7 | "ai-gallery/ent/setting" 8 | "context" 9 | 10 | "entgo.io/ent/dialect/sql" 11 | "entgo.io/ent/dialect/sql/sqlgraph" 12 | "entgo.io/ent/schema/field" 13 | ) 14 | 15 | // SettingDelete is the builder for deleting a Setting entity. 16 | type SettingDelete struct { 17 | config 18 | hooks []Hook 19 | mutation *SettingMutation 20 | } 21 | 22 | // Where appends a list predicates to the SettingDelete builder. 23 | func (sd *SettingDelete) Where(ps ...predicate.Setting) *SettingDelete { 24 | sd.mutation.Where(ps...) 25 | return sd 26 | } 27 | 28 | // Exec executes the deletion query and returns how many vertices were deleted. 29 | func (sd *SettingDelete) Exec(ctx context.Context) (int, error) { 30 | return withHooks(ctx, sd.sqlExec, sd.mutation, sd.hooks) 31 | } 32 | 33 | // ExecX is like Exec, but panics if an error occurs. 34 | func (sd *SettingDelete) ExecX(ctx context.Context) int { 35 | n, err := sd.Exec(ctx) 36 | if err != nil { 37 | panic(err) 38 | } 39 | return n 40 | } 41 | 42 | func (sd *SettingDelete) sqlExec(ctx context.Context) (int, error) { 43 | _spec := sqlgraph.NewDeleteSpec(setting.Table, sqlgraph.NewFieldSpec(setting.FieldID, field.TypeInt)) 44 | if ps := sd.mutation.predicates; len(ps) > 0 { 45 | _spec.Predicate = func(selector *sql.Selector) { 46 | for i := range ps { 47 | ps[i](selector) 48 | } 49 | } 50 | } 51 | affected, err := sqlgraph.DeleteNodes(ctx, sd.driver, _spec) 52 | if err != nil && sqlgraph.IsConstraintError(err) { 53 | err = &ConstraintError{msg: err.Error(), wrap: err} 54 | } 55 | sd.mutation.done = true 56 | return affected, err 57 | } 58 | 59 | // SettingDeleteOne is the builder for deleting a single Setting entity. 60 | type SettingDeleteOne struct { 61 | sd *SettingDelete 62 | } 63 | 64 | // Where appends a list predicates to the SettingDelete builder. 65 | func (sdo *SettingDeleteOne) Where(ps ...predicate.Setting) *SettingDeleteOne { 66 | sdo.sd.mutation.Where(ps...) 67 | return sdo 68 | } 69 | 70 | // Exec executes the deletion query. 71 | func (sdo *SettingDeleteOne) Exec(ctx context.Context) error { 72 | n, err := sdo.sd.Exec(ctx) 73 | switch { 74 | case err != nil: 75 | return err 76 | case n == 0: 77 | return &NotFoundError{setting.Label} 78 | default: 79 | return nil 80 | } 81 | } 82 | 83 | // ExecX is like Exec, but panics if an error occurs. 84 | func (sdo *SettingDeleteOne) ExecX(ctx context.Context) { 85 | if err := sdo.Exec(ctx); err != nil { 86 | panic(err) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /ent/migrate/migrate.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package migrate 4 | 5 | import ( 6 | "context" 7 | "fmt" 8 | "io" 9 | 10 | "entgo.io/ent/dialect" 11 | "entgo.io/ent/dialect/sql/schema" 12 | ) 13 | 14 | var ( 15 | // WithGlobalUniqueID sets the universal ids options to the migration. 16 | // If this option is enabled, ent migration will allocate a 1<<32 range 17 | // for the ids of each entity (table). 18 | // Note that this option cannot be applied on tables that already exist. 19 | WithGlobalUniqueID = schema.WithGlobalUniqueID 20 | // WithDropColumn sets the drop column option to the migration. 21 | // If this option is enabled, ent migration will drop old columns 22 | // that were used for both fields and edges. This defaults to false. 23 | WithDropColumn = schema.WithDropColumn 24 | // WithDropIndex sets the drop index option to the migration. 25 | // If this option is enabled, ent migration will drop old indexes 26 | // that were defined in the schema. This defaults to false. 27 | // Note that unique constraints are defined using `UNIQUE INDEX`, 28 | // and therefore, it's recommended to enable this option to get more 29 | // flexibility in the schema changes. 30 | WithDropIndex = schema.WithDropIndex 31 | // WithForeignKeys enables creating foreign-key in schema DDL. This defaults to true. 32 | WithForeignKeys = schema.WithForeignKeys 33 | ) 34 | 35 | // Schema is the API for creating, migrating and dropping a schema. 36 | type Schema struct { 37 | drv dialect.Driver 38 | } 39 | 40 | // NewSchema creates a new schema client. 41 | func NewSchema(drv dialect.Driver) *Schema { return &Schema{drv: drv} } 42 | 43 | // Create creates all schema resources. 44 | func (s *Schema) Create(ctx context.Context, opts ...schema.MigrateOption) error { 45 | return Create(ctx, s, Tables, opts...) 46 | } 47 | 48 | // Create creates all table resources using the given schema driver. 49 | func Create(ctx context.Context, s *Schema, tables []*schema.Table, opts ...schema.MigrateOption) error { 50 | migrate, err := schema.NewMigrate(s.drv, opts...) 51 | if err != nil { 52 | return fmt.Errorf("ent/migrate: %w", err) 53 | } 54 | return migrate.Create(ctx, tables...) 55 | } 56 | 57 | // WriteTo writes the schema changes to w instead of running them against the database. 58 | // 59 | // if err := client.Schema.WriteTo(context.Background(), os.Stdout); err != nil { 60 | // log.Fatal(err) 61 | // } 62 | func (s *Schema) WriteTo(ctx context.Context, w io.Writer, opts ...schema.MigrateOption) error { 63 | return Create(ctx, &Schema{drv: &schema.WriteDriver{Writer: w, Driver: s.drv}}, Tables, opts...) 64 | } 65 | -------------------------------------------------------------------------------- /ent/baseschema/baseschema.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package baseschema 4 | 5 | import ( 6 | "time" 7 | 8 | "entgo.io/ent/dialect/sql" 9 | ) 10 | 11 | const ( 12 | // Label holds the string label denoting the baseschema type in the database. 13 | Label = "base_schema" 14 | // FieldID holds the string denoting the id field in the database. 15 | FieldID = "id" 16 | // FieldCreateTime holds the string denoting the create_time field in the database. 17 | FieldCreateTime = "create_time" 18 | // FieldUpdateTime holds the string denoting the update_time field in the database. 19 | FieldUpdateTime = "update_time" 20 | // FieldDeleteTime holds the string denoting the delete_time field in the database. 21 | FieldDeleteTime = "delete_time" 22 | // Table holds the table name of the baseschema in the database. 23 | Table = "base_schemas" 24 | ) 25 | 26 | // Columns holds all SQL columns for baseschema fields. 27 | var Columns = []string{ 28 | FieldID, 29 | FieldCreateTime, 30 | FieldUpdateTime, 31 | FieldDeleteTime, 32 | } 33 | 34 | // ValidColumn reports if the column name is valid (part of the table columns). 35 | func ValidColumn(column string) bool { 36 | for i := range Columns { 37 | if column == Columns[i] { 38 | return true 39 | } 40 | } 41 | return false 42 | } 43 | 44 | var ( 45 | // DefaultCreateTime holds the default value on creation for the "create_time" field. 46 | DefaultCreateTime func() time.Time 47 | // DefaultUpdateTime holds the default value on creation for the "update_time" field. 48 | DefaultUpdateTime func() time.Time 49 | // UpdateDefaultUpdateTime holds the default value on update for the "update_time" field. 50 | UpdateDefaultUpdateTime func() time.Time 51 | ) 52 | 53 | // OrderOption defines the ordering options for the BaseSchema queries. 54 | type OrderOption func(*sql.Selector) 55 | 56 | // ByID orders the results by the id field. 57 | func ByID(opts ...sql.OrderTermOption) OrderOption { 58 | return sql.OrderByField(FieldID, opts...).ToFunc() 59 | } 60 | 61 | // ByCreateTime orders the results by the create_time field. 62 | func ByCreateTime(opts ...sql.OrderTermOption) OrderOption { 63 | return sql.OrderByField(FieldCreateTime, opts...).ToFunc() 64 | } 65 | 66 | // ByUpdateTime orders the results by the update_time field. 67 | func ByUpdateTime(opts ...sql.OrderTermOption) OrderOption { 68 | return sql.OrderByField(FieldUpdateTime, opts...).ToFunc() 69 | } 70 | 71 | // ByDeleteTime orders the results by the delete_time field. 72 | func ByDeleteTime(opts ...sql.OrderTermOption) OrderOption { 73 | return sql.OrderByField(FieldDeleteTime, opts...).ToFunc() 74 | } 75 | -------------------------------------------------------------------------------- /ent/baseschema_delete.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | import ( 6 | "ai-gallery/ent/baseschema" 7 | "ai-gallery/ent/predicate" 8 | "context" 9 | 10 | "entgo.io/ent/dialect/sql" 11 | "entgo.io/ent/dialect/sql/sqlgraph" 12 | "entgo.io/ent/schema/field" 13 | ) 14 | 15 | // BaseSchemaDelete is the builder for deleting a BaseSchema entity. 16 | type BaseSchemaDelete struct { 17 | config 18 | hooks []Hook 19 | mutation *BaseSchemaMutation 20 | } 21 | 22 | // Where appends a list predicates to the BaseSchemaDelete builder. 23 | func (bsd *BaseSchemaDelete) Where(ps ...predicate.BaseSchema) *BaseSchemaDelete { 24 | bsd.mutation.Where(ps...) 25 | return bsd 26 | } 27 | 28 | // Exec executes the deletion query and returns how many vertices were deleted. 29 | func (bsd *BaseSchemaDelete) Exec(ctx context.Context) (int, error) { 30 | return withHooks(ctx, bsd.sqlExec, bsd.mutation, bsd.hooks) 31 | } 32 | 33 | // ExecX is like Exec, but panics if an error occurs. 34 | func (bsd *BaseSchemaDelete) ExecX(ctx context.Context) int { 35 | n, err := bsd.Exec(ctx) 36 | if err != nil { 37 | panic(err) 38 | } 39 | return n 40 | } 41 | 42 | func (bsd *BaseSchemaDelete) sqlExec(ctx context.Context) (int, error) { 43 | _spec := sqlgraph.NewDeleteSpec(baseschema.Table, sqlgraph.NewFieldSpec(baseschema.FieldID, field.TypeInt)) 44 | if ps := bsd.mutation.predicates; len(ps) > 0 { 45 | _spec.Predicate = func(selector *sql.Selector) { 46 | for i := range ps { 47 | ps[i](selector) 48 | } 49 | } 50 | } 51 | affected, err := sqlgraph.DeleteNodes(ctx, bsd.driver, _spec) 52 | if err != nil && sqlgraph.IsConstraintError(err) { 53 | err = &ConstraintError{msg: err.Error(), wrap: err} 54 | } 55 | bsd.mutation.done = true 56 | return affected, err 57 | } 58 | 59 | // BaseSchemaDeleteOne is the builder for deleting a single BaseSchema entity. 60 | type BaseSchemaDeleteOne struct { 61 | bsd *BaseSchemaDelete 62 | } 63 | 64 | // Where appends a list predicates to the BaseSchemaDelete builder. 65 | func (bsdo *BaseSchemaDeleteOne) Where(ps ...predicate.BaseSchema) *BaseSchemaDeleteOne { 66 | bsdo.bsd.mutation.Where(ps...) 67 | return bsdo 68 | } 69 | 70 | // Exec executes the deletion query. 71 | func (bsdo *BaseSchemaDeleteOne) Exec(ctx context.Context) error { 72 | n, err := bsdo.bsd.Exec(ctx) 73 | switch { 74 | case err != nil: 75 | return err 76 | case n == 0: 77 | return &NotFoundError{baseschema.Label} 78 | default: 79 | return nil 80 | } 81 | } 82 | 83 | // ExecX is like Exec, but panics if an error occurs. 84 | func (bsdo *BaseSchemaDeleteOne) ExecX(ctx context.Context) { 85 | if err := bsdo.Exec(ctx); err != nil { 86 | panic(err) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /ent/taskdetail_delete.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | import ( 6 | "ai-gallery/ent/predicate" 7 | "ai-gallery/ent/taskdetail" 8 | "context" 9 | 10 | "entgo.io/ent/dialect/sql" 11 | "entgo.io/ent/dialect/sql/sqlgraph" 12 | "entgo.io/ent/schema/field" 13 | ) 14 | 15 | // TaskDetailDelete is the builder for deleting a TaskDetail entity. 16 | type TaskDetailDelete struct { 17 | config 18 | hooks []Hook 19 | mutation *TaskDetailMutation 20 | } 21 | 22 | // Where appends a list predicates to the TaskDetailDelete builder. 23 | func (tdd *TaskDetailDelete) Where(ps ...predicate.TaskDetail) *TaskDetailDelete { 24 | tdd.mutation.Where(ps...) 25 | return tdd 26 | } 27 | 28 | // Exec executes the deletion query and returns how many vertices were deleted. 29 | func (tdd *TaskDetailDelete) Exec(ctx context.Context) (int, error) { 30 | return withHooks(ctx, tdd.sqlExec, tdd.mutation, tdd.hooks) 31 | } 32 | 33 | // ExecX is like Exec, but panics if an error occurs. 34 | func (tdd *TaskDetailDelete) ExecX(ctx context.Context) int { 35 | n, err := tdd.Exec(ctx) 36 | if err != nil { 37 | panic(err) 38 | } 39 | return n 40 | } 41 | 42 | func (tdd *TaskDetailDelete) sqlExec(ctx context.Context) (int, error) { 43 | _spec := sqlgraph.NewDeleteSpec(taskdetail.Table, sqlgraph.NewFieldSpec(taskdetail.FieldID, field.TypeInt)) 44 | if ps := tdd.mutation.predicates; len(ps) > 0 { 45 | _spec.Predicate = func(selector *sql.Selector) { 46 | for i := range ps { 47 | ps[i](selector) 48 | } 49 | } 50 | } 51 | affected, err := sqlgraph.DeleteNodes(ctx, tdd.driver, _spec) 52 | if err != nil && sqlgraph.IsConstraintError(err) { 53 | err = &ConstraintError{msg: err.Error(), wrap: err} 54 | } 55 | tdd.mutation.done = true 56 | return affected, err 57 | } 58 | 59 | // TaskDetailDeleteOne is the builder for deleting a single TaskDetail entity. 60 | type TaskDetailDeleteOne struct { 61 | tdd *TaskDetailDelete 62 | } 63 | 64 | // Where appends a list predicates to the TaskDetailDelete builder. 65 | func (tddo *TaskDetailDeleteOne) Where(ps ...predicate.TaskDetail) *TaskDetailDeleteOne { 66 | tddo.tdd.mutation.Where(ps...) 67 | return tddo 68 | } 69 | 70 | // Exec executes the deletion query. 71 | func (tddo *TaskDetailDeleteOne) Exec(ctx context.Context) error { 72 | n, err := tddo.tdd.Exec(ctx) 73 | switch { 74 | case err != nil: 75 | return err 76 | case n == 0: 77 | return &NotFoundError{taskdetail.Label} 78 | default: 79 | return nil 80 | } 81 | } 82 | 83 | // ExecX is like Exec, but panics if an error occurs. 84 | func (tddo *TaskDetailDeleteOne) ExecX(ctx context.Context) { 85 | if err := tddo.Exec(ctx); err != nil { 86 | panic(err) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /api/account.api: -------------------------------------------------------------------------------- 1 | syntax = "v1" 2 | 3 | info ( 4 | title: "后台管理" 5 | version: "v1.0" 6 | ) 7 | 8 | @server ( 9 | group: account 10 | middleware: JWT 11 | ) 12 | service gallery-api { 13 | @doc ( 14 | summary: "获取账号信息" 15 | ) 16 | @handler GetUserDetail 17 | get /api/v1/manage/user/detail returns (GetUserDetailResponse) 18 | 19 | @doc ( 20 | summary: "修改账号信息" 21 | ) 22 | @handler UpdateUserDetail 23 | put /api/v1/manage/user/detail (UpdateUserDetailRequest) 24 | } 25 | 26 | type UpdateUserDetailRequest { 27 | UserID int `json:"user_id"` 28 | Username string `json:"username"` 29 | Nickname string `json:"nickname"` 30 | OldPassword string `json:"old_password,optional"` 31 | NewPassword string `json:"new_password,optional"` 32 | } 33 | 34 | type GetUserDetailResponse { 35 | UserID int `json:"user_id"` 36 | Username string `json:"username"` 37 | Nickname string `json:"nickname"` 38 | Role string `json:"role"` 39 | } 40 | 41 | @server ( 42 | group: account 43 | middleware: ManageJWT 44 | ) 45 | service gallery-api { 46 | @doc ( 47 | summary: "新建用户" 48 | ) 49 | @handler AddUser 50 | post /api/v1/manage/user (AddUserRequest) 51 | 52 | @doc ( 53 | summary: "修改用户信息" 54 | ) 55 | @handler UpdateUser 56 | put /api/v1/manage/user/:user_id (UpdateUserRequest) 57 | 58 | @doc ( 59 | summary: "用户列表" 60 | ) 61 | @handler GetUser 62 | get /api/v1/manage/user (GetUserRequest) returns (GetUserResponse) 63 | 64 | @doc ( 65 | summary: "重置密码" 66 | ) 67 | @handler ResetPwd 68 | put /api/v1/manage/user/:user_id/reset (ResetPwdRequest) 69 | 70 | @doc ( 71 | summary: "删除用户" 72 | ) 73 | @handler DeleteUser 74 | delete /api/v1/manage/user/:user_id (DeleteUserRequest) 75 | } 76 | 77 | type DeleteUserRequest { 78 | UserID int `path:"user_id"` 79 | } 80 | 81 | type AddUserRequest { 82 | Username string `json:"username"` 83 | Nickname string `json:"nickname"` 84 | Role string `json:"role,options=ADMIN|USER"` 85 | } 86 | 87 | type UpdateUserRequest { 88 | UserID int `path:"user_id"` 89 | Username string `json:"username,optional"` 90 | Nickname string `json:"nickname,optional"` 91 | Role string `json:"role,options=ADMIN|USER,optional"` 92 | Status int `json:"status,default=-1,optional"` 93 | } 94 | 95 | type GetUserRequest { 96 | Offset int `form:"offset,default=0"` 97 | Limit int `form:"limit,default=10"` 98 | Username string `form:"username,optional"` 99 | Nickname string `form:"nickname,optional"` 100 | Role string `form:"role,options=ADMIN|USER,optional"` 101 | Status int `form:"status,default=-1,optional"` 102 | } 103 | 104 | type UserBo { 105 | UserID int `json:"user_id"` 106 | Username string `json:"username"` 107 | Nickname string `json:"nickname"` 108 | Role string `json:"role"` 109 | Status int `json:"status"` 110 | } 111 | 112 | type GetUserResponse { 113 | Total int `json:"total"` 114 | Data []*UserBo `json:"data"` 115 | } 116 | 117 | type ResetPwdRequest { 118 | UserID int `path:"user_id"` 119 | } 120 | 121 | -------------------------------------------------------------------------------- /service/internal/logic/analysis/getanalysistasklogic.go: -------------------------------------------------------------------------------- 1 | package analysis 2 | 3 | import ( 4 | "context" 5 | "time" 6 | 7 | enttask "ai-gallery/ent/task" 8 | "ai-gallery/ent/taskdetail" 9 | "ai-gallery/pkg/errgroup" 10 | "ai-gallery/pkg/utils" 11 | "ai-gallery/service/internal/dao" 12 | "ai-gallery/service/internal/svc" 13 | "ai-gallery/service/internal/types" 14 | 15 | "github.com/zeromicro/go-zero/core/logx" 16 | ) 17 | 18 | type GetAnalysisTaskLogic struct { 19 | logx.Logger 20 | ctx context.Context 21 | svcCtx *svc.ServiceContext 22 | } 23 | 24 | func NewGetAnalysisTaskLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetAnalysisTaskLogic { 25 | return &GetAnalysisTaskLogic{ 26 | Logger: logx.WithContext(ctx), 27 | ctx: ctx, 28 | svcCtx: svcCtx, 29 | } 30 | } 31 | 32 | func (l *GetAnalysisTaskLogic) GetAnalysisTask(req *types.GetAnalysisTaskRequest) (resp *types.GetAnalysisTaskResponse, err error) { 33 | var ( 34 | // 任务数 35 | taskData = make([]int, req.Day) 36 | workData = make([]int, req.Day) 37 | excellentData = make([]int, req.Day) 38 | 39 | g = errgroup.WithContext(l.ctx) 40 | times = make([]string, 0) 41 | ) 42 | 43 | for i := req.Day - 1; i >= 0; i-- { 44 | idx := req.Day - (i + 1) 45 | curr := time.Now().AddDate(0, 0, -1*i) 46 | times = append(times, curr.Format(time.DateOnly)) 47 | start := utils.FirstTime(curr) 48 | end := utils.LastTime(curr) 49 | 50 | g.Go(func(ctx context.Context) (err error) { 51 | count, err := dao.EntClient.Task.Query().Where( 52 | enttask.DeleteTimeIsNil(), 53 | enttask.CreateTimeGTE(start), 54 | enttask.CreateTimeLTE(end), 55 | ).Count(ctx) 56 | if err != nil { 57 | return err 58 | } 59 | taskData[idx] = count 60 | return nil 61 | }) 62 | g.Go(func(ctx context.Context) (err error) { 63 | count, err := dao.EntClient.TaskDetail.Query().Where( 64 | taskdetail.DeleteTimeIsNil(), 65 | taskdetail.CreateTimeGTE(start), 66 | taskdetail.CreateTimeLTE(end), 67 | ).Count(ctx) 68 | if err != nil { 69 | return err 70 | } 71 | workData[idx] = count 72 | return nil 73 | }) 74 | g.Go(func(ctx context.Context) (err error) { 75 | count, err := dao.EntClient.TaskDetail.Query(). 76 | Where( 77 | taskdetail.DeleteTimeIsNil(), 78 | taskdetail.HasExcellent(true), 79 | taskdetail.CreateTimeGTE(start), 80 | taskdetail.CreateTimeLTE(end), 81 | ). 82 | Count(ctx) 83 | if err != nil { 84 | return err 85 | } 86 | excellentData[idx] = count 87 | return nil 88 | }) 89 | } 90 | if err = g.Wait(); err != nil { 91 | return nil, err 92 | } 93 | return &types.GetAnalysisTaskResponse{ 94 | Times: times, 95 | AnalysisTaskBo: []*types.AnalysisTaskBo{ 96 | { 97 | Name: "任务数", 98 | EnName: "tasks", 99 | Data: taskData, 100 | }, 101 | { 102 | Name: "作品数", 103 | EnName: "works", 104 | Data: workData, 105 | }, 106 | { 107 | Name: "优秀作品数", 108 | EnName: "excellent works", 109 | Data: excellentData, 110 | }, 111 | }, 112 | }, nil 113 | } 114 | -------------------------------------------------------------------------------- /pkg/errgroup/errgroup.go: -------------------------------------------------------------------------------- 1 | package errgroup 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "runtime" 7 | "sync" 8 | ) 9 | 10 | // A Group is a collection of goroutines working on subtasks that are part of 11 | // the same overall task. 12 | // 13 | // A zero Group is valid and does not cancel on error. 14 | type Group struct { 15 | err error 16 | wg sync.WaitGroup 17 | errOnce sync.Once 18 | 19 | workerOnce sync.Once 20 | ch chan func(ctx context.Context) error 21 | chs []func(ctx context.Context) error 22 | 23 | ctx context.Context 24 | cancel func() 25 | } 26 | 27 | // WithContext create a Group. 28 | // given function from Go will receive this context, 29 | func WithContext(ctx context.Context) *Group { 30 | return &Group{ctx: ctx} 31 | } 32 | 33 | // WithCancel create a new Group and an associated Context derived from ctx. 34 | // 35 | // given function from Go will receive context derived from this ctx, 36 | // The derived Context is canceled the first time a function passed to Go 37 | // returns a non-nil error or the first time Wait returns, whichever occurs 38 | // first. 39 | func WithCancel(ctx context.Context) *Group { 40 | ctx, cancel := context.WithCancel(ctx) 41 | return &Group{ctx: ctx, cancel: cancel} 42 | } 43 | 44 | func (g *Group) do(f func(ctx context.Context) error) { 45 | ctx := g.ctx 46 | if ctx == nil { 47 | ctx = context.Background() 48 | } 49 | var err error 50 | defer func() { 51 | if r := recover(); r != nil { 52 | buf := make([]byte, 64<<10) 53 | buf = buf[:runtime.Stack(buf, false)] 54 | err = fmt.Errorf("errgroup: panic recovered: %s\n%s", r, buf) 55 | } 56 | if err != nil { 57 | g.errOnce.Do(func() { 58 | g.err = err 59 | if g.cancel != nil { 60 | g.cancel() 61 | } 62 | }) 63 | } 64 | g.wg.Done() 65 | }() 66 | err = f(ctx) 67 | } 68 | 69 | // GOMAXPROCS set max goroutine to work. 70 | func (g *Group) GOMAXPROCS(n int) { 71 | if n <= 0 { 72 | panic("errgroup: GOMAXPROCS must great than 0") 73 | } 74 | g.workerOnce.Do(func() { 75 | g.ch = make(chan func(context.Context) error, n) 76 | for i := 0; i < n; i++ { 77 | go func() { 78 | for f := range g.ch { 79 | g.do(f) 80 | } 81 | }() 82 | } 83 | }) 84 | } 85 | 86 | // Go calls the given function in a new goroutine. 87 | // 88 | // The first call to return a non-nil error cancels the group; its error will be 89 | // returned by Wait. 90 | func (g *Group) Go(f func(ctx context.Context) error) { 91 | g.wg.Add(1) 92 | if g.ch != nil { 93 | select { 94 | case g.ch <- f: 95 | default: 96 | g.chs = append(g.chs, f) 97 | } 98 | return 99 | } 100 | go g.do(f) 101 | } 102 | 103 | // Wait blocks until all function calls from the Go method have returned, then 104 | // returns the first non-nil error (if any) from them. 105 | func (g *Group) Wait() error { 106 | if g.ch != nil { 107 | for _, f := range g.chs { 108 | g.ch <- f 109 | } 110 | } 111 | g.wg.Wait() 112 | if g.ch != nil { 113 | close(g.ch) // let all receiver exit 114 | } 115 | if g.cancel != nil { 116 | g.cancel() 117 | } 118 | return g.err 119 | } 120 | -------------------------------------------------------------------------------- /service/internal/dao/task/task.go: -------------------------------------------------------------------------------- 1 | package task 2 | 3 | import ( 4 | "ai-gallery/service/internal/dao" 5 | "context" 6 | "time" 7 | 8 | "ai-gallery/ent" 9 | enttask "ai-gallery/ent/task" 10 | "entgo.io/ent/dialect/sql" 11 | "github.com/duke-git/lancet/v2/strutil" 12 | ) 13 | 14 | type PO struct { 15 | Category string `json:"category"` 16 | Prompt string `json:"prompt"` 17 | AuthorIDs []int `json:"author_ids"` 18 | Size string `json:"size"` 19 | SdModelName string `json:"sd_model_name"` 20 | Status string `json:"status"` 21 | StartTime time.Time `json:"start_time"` 22 | EndTime time.Time `json:"end_time"` 23 | Sorted string `json:"sorted"` 24 | HasRefImage *int `json:"has_ref_image"` 25 | HasExcellent *int `json:"has_excellent"` 26 | } 27 | 28 | func GetByIDs(ctx context.Context, ids []int) ([]*ent.Task, error) { 29 | return dao.EntClient.Task.Query().Where( 30 | enttask.IDIn(ids...), 31 | enttask.DeleteTimeIsNil(), 32 | ).All(ctx) 33 | } 34 | 35 | func GetByID(ctx context.Context, id int) (*ent.Task, error) { 36 | return dao.EntClient.Task.Query().Where( 37 | enttask.ID(id), 38 | enttask.DeleteTimeIsNil(), 39 | ).First(ctx) 40 | } 41 | 42 | func GetQueryByPO(po *PO) *ent.TaskQuery { 43 | taskQuery := dao.EntClient.Task.Query().Where(enttask.DeleteTimeIsNil()) 44 | if strutil.IsNotBlank(po.Category) { 45 | taskQuery.Where(enttask.Category(po.Category)) 46 | } 47 | if strutil.IsNotBlank(po.Prompt) { 48 | taskQuery.Where(func(s *sql.Selector) { 49 | s.Where(sql.Like(enttask.FieldPrompt, "%"+po.Prompt+"%")) 50 | }) 51 | } 52 | if len(po.AuthorIDs) > 0 { 53 | taskQuery.Where(enttask.AuthorIDIn(po.AuthorIDs...)) 54 | } 55 | if strutil.IsNotBlank(po.Size) { 56 | taskQuery.Where(enttask.ImgSize(po.Size)) 57 | } 58 | if strutil.IsNotBlank(po.SdModelName) { 59 | taskQuery.Where(enttask.SdModelName(po.SdModelName)) 60 | } 61 | if po.HasRefImage != nil { 62 | if *po.HasRefImage == 0 { 63 | taskQuery.Where(enttask.RefImagesIsNil()) 64 | } 65 | if *po.HasRefImage == 1 { 66 | taskQuery.Where(enttask.RefImagesNotNil()) 67 | } 68 | } 69 | if strutil.IsNotBlank(po.Status) { 70 | taskQuery.Where(enttask.Status(po.Status)) 71 | } 72 | if po.HasExcellent != nil { 73 | if *po.HasExcellent == 1 { 74 | taskQuery.Where(enttask.HasExcellent(true)) 75 | } 76 | if *po.HasExcellent == 0 { 77 | taskQuery.Where(enttask.HasExcellent(false)) 78 | } 79 | } 80 | if !po.StartTime.IsZero() { 81 | taskQuery.Where(enttask.CreateTimeGTE(po.StartTime)) 82 | } 83 | if !po.EndTime.IsZero() { 84 | taskQuery.Where(enttask.CreateTimeLTE(po.EndTime)) 85 | } 86 | if po.Sorted == "asc" { 87 | taskQuery.Order(ent.Asc(enttask.FieldCreateTime)) 88 | } 89 | if po.Sorted == "desc" { 90 | taskQuery.Order(ent.Desc(enttask.FieldCreateTime)) 91 | } 92 | return taskQuery 93 | } 94 | 95 | func UpdateAuthorInfo(ctx context.Context, authorID int, authorName string) error { 96 | return dao.EntClient.Task.Update(). 97 | SetAuthorName(authorName). 98 | Where(enttask.AuthorID(authorID)). 99 | Exec(ctx) 100 | } 101 | -------------------------------------------------------------------------------- /service/internal/logic/work/gettasklogic.go: -------------------------------------------------------------------------------- 1 | package work 2 | 3 | import ( 4 | "ai-gallery/service/internal/dao" 5 | "ai-gallery/service/internal/dao/task" 6 | "context" 7 | "time" 8 | 9 | enttaskdetail "ai-gallery/ent/taskdetail" 10 | "ai-gallery/pkg/utils" 11 | "ai-gallery/service/internal/logic/basic" 12 | "ai-gallery/service/internal/svc" 13 | "ai-gallery/service/internal/types" 14 | 15 | "github.com/duke-git/lancet/v2/strutil" 16 | "github.com/zeromicro/go-zero/core/logx" 17 | ) 18 | 19 | type GetTaskLogic struct { 20 | logx.Logger 21 | ctx context.Context 22 | svcCtx *svc.ServiceContext 23 | } 24 | 25 | func NewGetTaskLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetTaskLogic { 26 | return &GetTaskLogic{ 27 | Logger: logx.WithContext(ctx), 28 | ctx: ctx, 29 | svcCtx: svcCtx, 30 | } 31 | } 32 | 33 | func (l *GetTaskLogic) GetTask(req *types.GetTaskRequest) (resp *types.GetTaskResponse, err error) { 34 | data := make([]*types.TaskBo, 0) 35 | 36 | authorIDs, err := basic.GetAuthorIDsByRole(l.ctx, req.AuthorIDs) 37 | if err != nil { 38 | return nil, err 39 | } 40 | start, end := time.Time{}, time.Time{} 41 | if strutil.IsNotBlank(req.StartTime) { 42 | start, err = utils.ParseYMD(req.StartTime) 43 | if err != nil { 44 | return nil, err 45 | } 46 | start = utils.FirstTime(start) 47 | } 48 | if strutil.IsNotBlank(req.EndTime) { 49 | end, err = utils.ParseYMD(req.EndTime) 50 | if err != nil { 51 | return nil, err 52 | } 53 | end = utils.LastTime(end) 54 | } 55 | query := task.GetQueryByPO(&task.PO{ 56 | Category: req.Category, 57 | AuthorIDs: authorIDs, 58 | Status: req.Status, 59 | StartTime: start, 60 | EndTime: end, 61 | }) 62 | count, err := query.Count(l.ctx) 63 | if err != nil { 64 | return nil, err 65 | } 66 | if count == 0 { 67 | return &types.GetTaskResponse{ 68 | Data: data, 69 | Total: count, 70 | }, nil 71 | } 72 | tasks, err := query.Offset(req.Offset).Limit(req.Limit).All(l.ctx) 73 | if err != nil { 74 | return nil, err 75 | } 76 | taskIDs := make([]int, 0) 77 | for _, t := range tasks { 78 | taskIDs = append(taskIDs, t.ID) 79 | } 80 | taskImageMap := make(map[int][]string, 0) 81 | details, err := dao.EntClient.TaskDetail.Query().Where( 82 | enttaskdetail.DeleteTimeIsNil(), 83 | enttaskdetail.TaskIDIn(taskIDs...), 84 | ).All(l.ctx) 85 | if err != nil { 86 | return nil, err 87 | } 88 | for _, detail := range details { 89 | taskImageMap[detail.TaskID] = append(taskImageMap[detail.TaskID], detail.ImageURL) 90 | } 91 | for _, t := range tasks { 92 | data = append(data, &types.TaskBo{ 93 | TaskID: t.ID, 94 | Category: t.Category, 95 | Prompt: t.Prompt, 96 | Size: t.ImgSize, 97 | AuthorID: t.AuthorID, 98 | AuthorName: t.AuthorName, 99 | Total: t.Total, 100 | JobTimestamp: t.JobTimestamp.Format(time.DateTime), 101 | Status: t.Status, 102 | Count: len(taskImageMap[t.ID]), 103 | ImageUrls: taskImageMap[t.ID], 104 | }) 105 | } 106 | return &types.GetTaskResponse{ 107 | Data: data, 108 | Total: count, 109 | }, nil 110 | } 111 | -------------------------------------------------------------------------------- /service/internal/errors/errors.go: -------------------------------------------------------------------------------- 1 | package errors 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "fmt" 7 | "net/http" 8 | 9 | "github.com/zeromicro/go-zero/rest/httpx" 10 | ) 11 | 12 | var ( 13 | ErrServiceInternal = func(ctx context.Context) *ErrorMessage { 14 | return NewError(10000, "Service internal error", "服务内部错误") 15 | } 16 | ErrHeaderNotFound = func(ctx context.Context) *ErrorMessage { 17 | return NewError(10001, "The request header information does not exist", "请求头信息不存在") 18 | } 19 | ErrHeaderParsing = func(ctx context.Context) *ErrorMessage { 20 | return NewError(10002, "Request header information parsing failed", "请求头信息解析失败") 21 | } 22 | ErrPermissionProvider = func(ctx context.Context) *ErrorMessage { 23 | return NewError(10003, "No valid identity permission provided", "未提供有效身份许可") 24 | } 25 | ErrTokenExpired = func(ctx context.Context) *ErrorMessage { 26 | return NewError(10004, "Token has expired", "令牌已失效") 27 | } 28 | ErrTokenValid = func(ctx context.Context) *ErrorMessage { 29 | return NewError(10005, "No valid token provided", "未提供有效令牌") 30 | } 31 | ) 32 | 33 | var ( 34 | ErrTaskImageBase64Parse = func(ctx context.Context) *ErrorMessage { 35 | return NewError(10100, "Image base64 parsing error", "图片base64解析错误") 36 | } 37 | ErrUploadServiceNotFound = func(ctx context.Context) *ErrorMessage { 38 | return NewError(10101, "Upload service does not exist", "上传服务不存在") 39 | } 40 | ) 41 | 42 | var ( 43 | ErrAccountNotFound = func(ctx context.Context) *ErrorMessage { 44 | return NewError(10200, "Account does not exist", "账号不存在") 45 | } 46 | ErrAccountDisabled = func(ctx context.Context) *ErrorMessage { 47 | return NewError(10201, "Account is unavailable", "账号不可用") 48 | } 49 | ErrAccountPwd = func(ctx context.Context) *ErrorMessage { 50 | return NewError(10202, "wrong password", "密码错误") 51 | } 52 | ErrAccountTokenGen = func(ctx context.Context) *ErrorMessage { 53 | return NewError(10203, "token invalid data", "无效 token 数据") 54 | } 55 | ErrAccountPermission = func(ctx context.Context) *ErrorMessage { 56 | return NewError(10204, "Account has no permissions", "账号无权限") 57 | } 58 | ErrAccountTokenNotFound = func(ctx context.Context) *ErrorMessage { 59 | return NewError(10205, "token does not exist", "token不存在") 60 | } 61 | ErrAccountUsernameExist = func(ctx context.Context) *ErrorMessage { 62 | return NewError(10206, "Username already exists", "用户名已存在") 63 | } 64 | ) 65 | 66 | type ErrorMessage struct { 67 | Code int `json:"code"` 68 | Message string `json:"message"` 69 | Desc string `json:"desc"` 70 | } 71 | 72 | func (e ErrorMessage) Error() string { 73 | return fmt.Sprintf("%d: %s", e.Code, e.Message) 74 | } 75 | 76 | func NewError(code int, message, desc string) *ErrorMessage { 77 | return &ErrorMessage{ 78 | Code: code, 79 | Message: message, 80 | Desc: desc, 81 | } 82 | } 83 | 84 | func HandleResponseError(w http.ResponseWriter, err error) { 85 | respErr := &ErrorMessage{ 86 | Code: http.StatusBadRequest, 87 | Message: err.Error(), 88 | } 89 | var m *ErrorMessage 90 | if ok := errors.As(err, &m); ok { 91 | respErr.Code = m.Code 92 | respErr.Message = m.Message 93 | respErr.Desc = m.Desc 94 | } 95 | httpx.WriteJson(w, http.StatusBadRequest, respErr) 96 | } 97 | -------------------------------------------------------------------------------- /service/gallery.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "context" 5 | "flag" 6 | "fmt" 7 | 8 | "ai-gallery/ent" 9 | "ai-gallery/service/internal/config" 10 | "ai-gallery/service/internal/cron" 11 | "ai-gallery/service/internal/dao" 12 | "ai-gallery/service/internal/dao/account" 13 | "ai-gallery/service/internal/dao/setting" 14 | "ai-gallery/service/internal/handler" 15 | "ai-gallery/service/internal/middleware" 16 | "ai-gallery/service/internal/model" 17 | "ai-gallery/service/internal/svc" 18 | 19 | "github.com/zeromicro/go-zero/core/conf" 20 | "github.com/zeromicro/go-zero/core/logc" 21 | "github.com/zeromicro/go-zero/rest" 22 | "golang.org/x/crypto/bcrypt" 23 | ) 24 | 25 | func StartHTTP(env string) { 26 | c := LoadConfig(env) 27 | ctx := context.Background() 28 | 29 | server := rest.MustNewServer(c.RestConf, 30 | rest.WithNotAllowedHandler(middleware.NewCorsMiddleware().Handler())) 31 | defer server.Stop() 32 | 33 | svcCtx := svc.NewServiceContext(c) 34 | 35 | _, err := InitDB(c) 36 | if err != nil { 37 | logc.Errorf(ctx, "init db failed: %+v", err) 38 | return 39 | } 40 | // 创建系统数据. 41 | if err = createSystemData(ctx); err != nil { 42 | logc.Errorf(ctx, "init admin account failed: %+v", err) 43 | return 44 | } 45 | 46 | server.Use(middleware.NewCorsMiddleware().Handle) 47 | 48 | handler.RegisterHandlers(server, svcCtx) 49 | 50 | cronJob, err := cron.CreateCronJob(c) 51 | if err != nil { 52 | logc.Errorf(ctx, "init cron failed: %+v", err) 53 | return 54 | } 55 | 56 | fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port) 57 | cronJob.Start() 58 | server.Start() 59 | } 60 | 61 | func InitDB(c config.Config) (*ent.Client, error) { 62 | return dao.NewDB(c.DB) 63 | } 64 | 65 | const ( 66 | Dev = "dev" 67 | Prod = "prod" 68 | ) 69 | 70 | var devConfigFile = flag.String(Dev, "service/etc/application-dev.yaml", "loading dev config file") 71 | var prodConfigFile = flag.String(Prod, "service/etc/application-prod.yaml", "loading prod config file") 72 | 73 | func LoadConfig(env string) config.Config { 74 | var ( 75 | c config.Config 76 | file *string 77 | ) 78 | if env == Prod { 79 | file = prodConfigFile 80 | } else { 81 | file = devConfigFile 82 | } 83 | 84 | conf.MustLoad(*file, &c) 85 | logc.MustSetup(c.Logger) 86 | return c 87 | } 88 | 89 | func createSystemData(ctx context.Context) error { 90 | if err := setting.Create(ctx, &setting.PO{ 91 | StoreName: model.UploadEnums.Local.Code, 92 | StoreAddress: model.LocalAddress, 93 | SecureID: "", 94 | SecureKey: "", 95 | StoreBucket: "", 96 | InitPwd: model.InitPwd, 97 | }); err != nil { 98 | return err 99 | } 100 | _, err := account.GetByUsername(ctx, model.Admin) 101 | if err != nil { 102 | if ent.IsNotFound(err) { 103 | initPwd, err := setting.GetInitPwd(ctx) 104 | if err != nil { 105 | return err 106 | } 107 | password, err := bcrypt.GenerateFromPassword([]byte(initPwd+model.PwdSalt), bcrypt.DefaultCost) 108 | if err != nil { 109 | return err 110 | } 111 | return account.Create(ctx, &account.PO{ 112 | Username: model.Admin, 113 | Nickname: model.Admin, 114 | Password: string(password), 115 | Status: model.ACTIVE, 116 | Role: model.ADMIN, 117 | }) 118 | } 119 | return err 120 | } 121 | return nil 122 | } 123 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module ai-gallery 2 | 3 | go 1.21.0 4 | 5 | require ( 6 | entgo.io/ent v0.13.1 7 | github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible 8 | github.com/duke-git/lancet/v2 v2.3.1 9 | github.com/go-sql-driver/mysql v1.8.1 10 | github.com/golang-jwt/jwt/v4 v4.5.0 11 | github.com/robfig/cron/v3 v3.0.1 12 | github.com/tencentyun/cos-go-sdk-v5 v0.7.54 13 | github.com/zeromicro/go-zero v1.6.6 14 | golang.org/x/crypto v0.24.0 15 | ) 16 | 17 | require ( 18 | ariga.io/atlas v0.19.1-0.20240203083654-5948b60a8e43 // indirect 19 | filippo.io/edwards25519 v1.1.0 // indirect 20 | github.com/agext/levenshtein v1.2.1 // indirect 21 | github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect 22 | github.com/beorn7/perks v1.0.1 // indirect 23 | github.com/cenkalti/backoff/v4 v4.2.1 // indirect 24 | github.com/cespare/xxhash/v2 v2.2.0 // indirect 25 | github.com/clbanning/mxj v1.8.4 // indirect 26 | github.com/fatih/color v1.17.0 // indirect 27 | github.com/go-logr/logr v1.3.0 // indirect 28 | github.com/go-logr/stdr v1.2.2 // indirect 29 | github.com/go-openapi/inflect v0.19.0 // indirect 30 | github.com/google/go-cmp v0.6.0 // indirect 31 | github.com/google/go-querystring v1.0.0 // indirect 32 | github.com/google/uuid v1.6.0 // indirect 33 | github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0 // indirect 34 | github.com/hashicorp/hcl/v2 v2.13.0 // indirect 35 | github.com/inconshreveable/mousetrap v1.1.0 // indirect 36 | github.com/mattn/go-colorable v0.1.13 // indirect 37 | github.com/mattn/go-isatty v0.0.20 // indirect 38 | github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect 39 | github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 // indirect 40 | github.com/mitchellh/mapstructure v1.5.0 // indirect 41 | github.com/mozillazg/go-httpheader v0.2.1 // indirect 42 | github.com/openzipkin/zipkin-go v0.4.2 // indirect 43 | github.com/pelletier/go-toml/v2 v2.2.2 // indirect 44 | github.com/prometheus/client_golang v1.18.0 // indirect 45 | github.com/prometheus/client_model v0.5.0 // indirect 46 | github.com/prometheus/common v0.45.0 // indirect 47 | github.com/prometheus/procfs v0.12.0 // indirect 48 | github.com/spaolacci/murmur3 v1.1.0 // indirect 49 | github.com/spf13/cobra v1.8.1 // indirect 50 | github.com/spf13/pflag v1.0.5 // indirect 51 | github.com/zclconf/go-cty v1.8.0 // indirect 52 | go.opentelemetry.io/otel v1.19.0 // indirect 53 | go.opentelemetry.io/otel/exporters/jaeger v1.17.0 // indirect 54 | go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 // indirect 55 | go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0 // indirect 56 | go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 // indirect 57 | go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.19.0 // indirect 58 | go.opentelemetry.io/otel/exporters/zipkin v1.19.0 // indirect 59 | go.opentelemetry.io/otel/metric v1.19.0 // indirect 60 | go.opentelemetry.io/otel/sdk v1.19.0 // indirect 61 | go.opentelemetry.io/otel/trace v1.19.0 // indirect 62 | go.opentelemetry.io/proto/otlp v1.0.0 // indirect 63 | go.uber.org/automaxprocs v1.5.3 // indirect 64 | golang.org/x/mod v0.17.0 // indirect 65 | golang.org/x/net v0.26.0 // indirect 66 | golang.org/x/sys v0.21.0 // indirect 67 | golang.org/x/text v0.16.0 // indirect 68 | golang.org/x/time v0.5.0 // indirect 69 | google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237 // indirect 70 | google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect 71 | google.golang.org/grpc v1.64.0 // indirect 72 | google.golang.org/protobuf v1.34.2 // indirect 73 | gopkg.in/yaml.v2 v2.4.0 // indirect 74 | ) 75 | -------------------------------------------------------------------------------- /service/internal/logic/analysis/getanalysisbaselogic.go: -------------------------------------------------------------------------------- 1 | package analysis 2 | 3 | import ( 4 | "context" 5 | "time" 6 | 7 | "ai-gallery/ent/account" 8 | enttask "ai-gallery/ent/task" 9 | "ai-gallery/ent/taskdetail" 10 | "ai-gallery/pkg/errgroup" 11 | "ai-gallery/pkg/utils" 12 | "ai-gallery/service/internal/dao" 13 | "ai-gallery/service/internal/model" 14 | "ai-gallery/service/internal/svc" 15 | "ai-gallery/service/internal/types" 16 | 17 | "github.com/zeromicro/go-zero/core/logx" 18 | ) 19 | 20 | type GetAnalysisBaseLogic struct { 21 | logx.Logger 22 | ctx context.Context 23 | svcCtx *svc.ServiceContext 24 | } 25 | 26 | func NewGetAnalysisBaseLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetAnalysisBaseLogic { 27 | return &GetAnalysisBaseLogic{ 28 | Logger: logx.WithContext(ctx), 29 | ctx: ctx, 30 | svcCtx: svcCtx, 31 | } 32 | } 33 | 34 | func (l *GetAnalysisBaseLogic) GetAnalysisBase() (resp *types.GetAnalysisBaseResponse, err error) { 35 | var ( 36 | taskTotal = 0 37 | workTotal = 0 38 | excellentTotal = 0 39 | accountTotal = 0 40 | todayTaskCount = 0 41 | todayWorkCount = 0 42 | todayExcellentCount = 0 43 | g = errgroup.WithContext(l.ctx) 44 | start = utils.FirstTime(time.Now()) 45 | end = utils.LastTime(time.Now()) 46 | ) 47 | g.Go(func(ctx context.Context) (err error) { 48 | taskTotal, err = dao.EntClient.Task.Query(). 49 | Where(enttask.DeleteTimeIsNil()). 50 | Count(ctx) 51 | return err 52 | }) 53 | g.Go(func(ctx context.Context) (err error) { 54 | workTotal, err = dao.EntClient.TaskDetail.Query(). 55 | Where(taskdetail.DeleteTimeIsNil()). 56 | Count(ctx) 57 | return err 58 | }) 59 | g.Go(func(ctx context.Context) error { 60 | excellentTotal, err = dao.EntClient.TaskDetail.Query(). 61 | Where( 62 | taskdetail.DeleteTimeIsNil(), 63 | taskdetail.HasExcellent(true), 64 | ). 65 | Count(ctx) 66 | return err 67 | }) 68 | g.Go(func(ctx context.Context) error { 69 | accountTotal, err = dao.EntClient.Account.Query().Where( 70 | account.DeleteTimeIsNil(), 71 | account.Status(model.ACTIVE), 72 | ).Count(ctx) 73 | return err 74 | }) 75 | g.Go(func(ctx context.Context) (err error) { 76 | todayTaskCount, err = dao.EntClient.Task.Query(). 77 | Where( 78 | enttask.DeleteTimeIsNil(), 79 | enttask.CreateTimeGTE(start), 80 | enttask.CreateTimeLTE(end), 81 | ).Count(ctx) 82 | return err 83 | }) 84 | g.Go(func(ctx context.Context) (err error) { 85 | todayWorkCount, err = dao.EntClient.TaskDetail.Query(). 86 | Where( 87 | taskdetail.DeleteTimeIsNil(), 88 | taskdetail.CreateTimeGTE(start), 89 | taskdetail.CreateTimeLTE(end), 90 | ). 91 | Count(ctx) 92 | return err 93 | }) 94 | g.Go(func(ctx context.Context) error { 95 | todayExcellentCount, err = dao.EntClient.TaskDetail.Query(). 96 | Where( 97 | taskdetail.DeleteTimeIsNil(), 98 | taskdetail.HasExcellent(true), 99 | taskdetail.CreateTimeGTE(start), 100 | taskdetail.CreateTimeLTE(end), 101 | ). 102 | Count(ctx) 103 | return err 104 | }) 105 | if err = g.Wait(); err != nil { 106 | return nil, err 107 | } 108 | return &types.GetAnalysisBaseResponse{ 109 | TaskTotal: taskTotal, 110 | WorkTotal: workTotal, 111 | ExcellentTotal: excellentTotal, 112 | AccountTotal: accountTotal, 113 | TodayTaskCount: todayTaskCount, 114 | TodayWorkCount: todayWorkCount, 115 | TodayExcellentCount: todayExcellentCount, 116 | }, nil 117 | } 118 | -------------------------------------------------------------------------------- /service/internal/logic/task/createtasklogic.go: -------------------------------------------------------------------------------- 1 | package task 2 | 3 | import ( 4 | "ai-gallery/service/internal/dao" 5 | "bytes" 6 | "context" 7 | "encoding/base64" 8 | "fmt" 9 | "math" 10 | "time" 11 | 12 | "ai-gallery/service/internal/errors" 13 | "ai-gallery/service/internal/logic/basic" 14 | u "ai-gallery/service/internal/logic/basic/upload" 15 | "ai-gallery/service/internal/model" 16 | "ai-gallery/service/internal/svc" 17 | "ai-gallery/service/internal/types" 18 | 19 | "github.com/zeromicro/go-zero/core/logx" 20 | ) 21 | 22 | type CreateTaskLogic struct { 23 | logx.Logger 24 | ctx context.Context 25 | svcCtx *svc.ServiceContext 26 | } 27 | 28 | func NewCreateTaskLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateTaskLogic { 29 | return &CreateTaskLogic{ 30 | Logger: logx.WithContext(ctx), 31 | ctx: ctx, 32 | svcCtx: svcCtx, 33 | } 34 | } 35 | 36 | func (l *CreateTaskLogic) CreateTask(req *types.CreateTaskReq) (resp *types.CreateTaskResp, err error) { 37 | info, err := basic.ContextElement(l.ctx) 38 | if err != nil { 39 | return nil, err 40 | } 41 | jobTime, err := time.ParseInLocation(model.DateStrLayout, req.JobTimestamp, time.Local) 42 | if err != nil { 43 | return nil, err 44 | } 45 | refImages := make([]string, 0) 46 | store, upload, err := u.UploadStrategy(l.ctx) 47 | if err != nil { 48 | return nil, err 49 | } 50 | for _, baseData := range req.RefImages { 51 | data, err := base64.StdEncoding.DecodeString(baseData.Base64) 52 | if err != nil { 53 | return nil, errors.ErrTaskImageBase64Parse(l.ctx) 54 | } 55 | path, err := upload.Put(l.ctx, baseData.Filename, bytes.NewReader(data)) 56 | if err != nil { 57 | return nil, err 58 | } 59 | refImages = append(refImages, path) 60 | } 61 | ratio := calculateRatio(req.Width, req.Height) 62 | createSQL := dao.EntClient.Task.Create(). 63 | SetCreateTime(time.Now()). 64 | SetUpdateTime(time.Now()). 65 | SetCategory(req.Category). 66 | SetPrompt(req.Prompt). 67 | SetImgSize(ratio). 68 | SetNegativePrompt(req.NegativePrompt). 69 | SetWeight(req.Width). 70 | SetHeight(req.Height). 71 | SetSeed(req.Seed). 72 | SetSamplerName(req.SamplerName). 73 | SetSteps(req.Steps). 74 | SetCfgScale(req.CfgScale). 75 | SetBatchSize(req.BatchSize). 76 | SetTotal(req.Total). 77 | SetSdModelName(req.SdModelName). 78 | SetSdModelHash(req.SdModelHash). 79 | SetNillableSdVaeName(req.SdVaeName). 80 | SetNillableSdVaeHash(req.SdVaeHash). 81 | SetJobTimestamp(jobTime). 82 | SetVersion(req.Version). 83 | SetStatus(model.TaskStatusEnums.Progress.Code). 84 | SetAuthorID(info.ID). 85 | SetAuthorName(info.Nickname). 86 | SetStore(store) 87 | if len(refImages) > 0 { 88 | createSQL.SetRefImages(refImages) 89 | } 90 | task, err := createSQL.Save(l.ctx) 91 | if err != nil { 92 | return nil, err 93 | } 94 | return &types.CreateTaskResp{ 95 | TaskID: task.ID, 96 | }, nil 97 | } 98 | 99 | func calculateRatio(length, width float32) string { 100 | if width == 0 { 101 | return "undefined" // 防止除以零错误 102 | } 103 | 104 | // 求最大公约数 105 | gcdValue := gcd(float64(length), float64(width)) 106 | 107 | // 计算比例 108 | ratio1 := length / float32(gcdValue) 109 | ratio2 := width / float32(gcdValue) 110 | 111 | // 保留最多一位小数 112 | ratio1Str := formatRatio(ratio1) 113 | ratio2Str := formatRatio(ratio2) 114 | 115 | return ratio1Str + ":" + ratio2Str 116 | } 117 | 118 | // gcd 计算两个数的最大公约数 119 | func gcd(a, b float64) float64 { 120 | for b != 0 { 121 | t := b 122 | b = math.Mod(a, b) 123 | a = t 124 | } 125 | return a 126 | } 127 | 128 | func formatRatio(value float32) string { 129 | if value == float32(int(value)) { 130 | return fmt.Sprintf("%d", int(value)) 131 | } 132 | return fmt.Sprintf("%.2f", value) 133 | } 134 | -------------------------------------------------------------------------------- /ent/taskdetail/taskdetail.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package taskdetail 4 | 5 | import ( 6 | "time" 7 | 8 | "entgo.io/ent/dialect/sql" 9 | ) 10 | 11 | const ( 12 | // Label holds the string label denoting the taskdetail type in the database. 13 | Label = "task_detail" 14 | // FieldID holds the string denoting the id field in the database. 15 | FieldID = "id" 16 | // FieldCreateTime holds the string denoting the create_time field in the database. 17 | FieldCreateTime = "create_time" 18 | // FieldUpdateTime holds the string denoting the update_time field in the database. 19 | FieldUpdateTime = "update_time" 20 | // FieldDeleteTime holds the string denoting the delete_time field in the database. 21 | FieldDeleteTime = "delete_time" 22 | // FieldTaskID holds the string denoting the task_id field in the database. 23 | FieldTaskID = "task_id" 24 | // FieldImageURL holds the string denoting the image_url field in the database. 25 | FieldImageURL = "image_url" 26 | // FieldHasExcellent holds the string denoting the has_excellent field in the database. 27 | FieldHasExcellent = "has_excellent" 28 | // Table holds the table name of the taskdetail in the database. 29 | Table = "core_task_detail" 30 | ) 31 | 32 | // Columns holds all SQL columns for taskdetail fields. 33 | var Columns = []string{ 34 | FieldID, 35 | FieldCreateTime, 36 | FieldUpdateTime, 37 | FieldDeleteTime, 38 | FieldTaskID, 39 | FieldImageURL, 40 | FieldHasExcellent, 41 | } 42 | 43 | // ValidColumn reports if the column name is valid (part of the table columns). 44 | func ValidColumn(column string) bool { 45 | for i := range Columns { 46 | if column == Columns[i] { 47 | return true 48 | } 49 | } 50 | return false 51 | } 52 | 53 | var ( 54 | // DefaultCreateTime holds the default value on creation for the "create_time" field. 55 | DefaultCreateTime func() time.Time 56 | // DefaultUpdateTime holds the default value on creation for the "update_time" field. 57 | DefaultUpdateTime func() time.Time 58 | // UpdateDefaultUpdateTime holds the default value on update for the "update_time" field. 59 | UpdateDefaultUpdateTime func() time.Time 60 | // ImageURLValidator is a validator for the "image_url" field. It is called by the builders before save. 61 | ImageURLValidator func(string) error 62 | ) 63 | 64 | // OrderOption defines the ordering options for the TaskDetail queries. 65 | type OrderOption func(*sql.Selector) 66 | 67 | // ByID orders the results by the id field. 68 | func ByID(opts ...sql.OrderTermOption) OrderOption { 69 | return sql.OrderByField(FieldID, opts...).ToFunc() 70 | } 71 | 72 | // ByCreateTime orders the results by the create_time field. 73 | func ByCreateTime(opts ...sql.OrderTermOption) OrderOption { 74 | return sql.OrderByField(FieldCreateTime, opts...).ToFunc() 75 | } 76 | 77 | // ByUpdateTime orders the results by the update_time field. 78 | func ByUpdateTime(opts ...sql.OrderTermOption) OrderOption { 79 | return sql.OrderByField(FieldUpdateTime, opts...).ToFunc() 80 | } 81 | 82 | // ByDeleteTime orders the results by the delete_time field. 83 | func ByDeleteTime(opts ...sql.OrderTermOption) OrderOption { 84 | return sql.OrderByField(FieldDeleteTime, opts...).ToFunc() 85 | } 86 | 87 | // ByTaskID orders the results by the task_id field. 88 | func ByTaskID(opts ...sql.OrderTermOption) OrderOption { 89 | return sql.OrderByField(FieldTaskID, opts...).ToFunc() 90 | } 91 | 92 | // ByImageURL orders the results by the image_url field. 93 | func ByImageURL(opts ...sql.OrderTermOption) OrderOption { 94 | return sql.OrderByField(FieldImageURL, opts...).ToFunc() 95 | } 96 | 97 | // ByHasExcellent orders the results by the has_excellent field. 98 | func ByHasExcellent(opts ...sql.OrderTermOption) OrderOption { 99 | return sql.OrderByField(FieldHasExcellent, opts...).ToFunc() 100 | } 101 | -------------------------------------------------------------------------------- /README_zh.md: -------------------------------------------------------------------------------- 1 | # ai-gallery 2 |
3 | 4 | [ [English](README.md) | Chinese ] 5 | 6 | ai-gallery 是一个基于 Go-Zero + SD Plugin + Vite/React + Ant Design 技术的前后端分离系统,用于统一管理 SD 绘画任务。 7 | 8 | - [后端项目](https://github.com/tabelf/ai-gallery)
9 | - [前端项目](https://github.com/tabelf/ai-gallery-ui)
10 | - [SD 插件](https://github.com/tabelf/sd-webui-gen2gallery)
11 | 12 | ## 功能演示 13 |
14 | 15 | https://github.com/user-attachments/assets/db6ac661-84ca-47b8-934b-86f1f61a9578 16 | 17 | [完整视频演示](https://www.bilibili.com/video/BV1mt8ue6E1Y) 18 | 19 | ## ✨ 功能 20 |
21 | 22 | - 管理 SD 文生图、图生图绘画任务记录 23 | - SD 生成图片云端/本地存储 24 | - 多用户提交任务数据汇总 25 | - 用户管理 26 | - 系统设置 27 | 28 | ## 💼 准备工作 29 | 30 | ### 环境准备 31 | ```text 32 | go sdk v1.21.0 33 | node v21.6.2 34 | npm v9.6.7 35 | react v18.2.0 36 | stable diffuison webui v1.9.3 37 | mysql v8.0.28 38 | nginx v1.25.3 39 | ``` 40 | 41 | ### 获取代码 42 | ```bash 43 | # 获取插件代码 44 | git clone https://github.com/tabelf/sd-webui-gen2gallery.git 45 | 46 | # 获取后端代码 47 | git clone https://github.com/tabelf/ai-gallery.git 48 | 49 | # 获取前端代码 50 | git clone https://github.com/tabelf/ai-gallery-ui.git 51 | ``` 52 | 53 | ## 启动说明 54 | 55 | ### 服务端启动 56 | ```bash 57 | # 进入到后端项目目录 58 | cd ./ai-gallery 59 | 60 | # 安装 go 项目依赖 61 | go mod tidy 62 | 63 | # 修改数据库配置 64 | vi ./service/etc/application-dev.yaml 65 | 66 | # root 修改为自己数据库的用户名 67 | # 12345678 为密码 68 | # ai_gallery 为数据库名称 69 | 70 | # db: 71 | # url: root:12345678@(127.0.0.1:3306)/ai_gallery?charset=utf8mb4&parseTime=true&loc=Local&interpolateParams=true 72 | # driver: mysql 73 | # max_open_conns: 100 74 | # max_idle_conns: 30 75 | 76 | # 生成表结构 77 | go run cmd/main.go migrate --env dev 78 | 79 | # 运行项目 80 | go run cmd/main.go start --env dev 81 | ``` 82 | 83 | ### 前端启动 84 | ```bash 85 | # 安装依赖,如果执行慢需要配置镜像源 86 | npm install 87 | 88 | # 启动服务 89 | vite dev 90 | 91 | # 部署成功会显示地址 92 | http://localhost:5173/ 93 | 94 | # 首先要进行登录 95 | # 默认账号:admin 96 | # 密码: 1234567 97 | 98 | # 到系统设置菜单栏中,配置图片要存储的位置 99 | # 如果存储选择本地,需要配置下面的 nginx 100 | # 如果存储选择腾讯云cos,需要配置存储地址,ID,key,记得打开跨域设置 101 | # 如果存储选择阿里云oos,需要配置存储桶名称,存储地址,ID,key,记得打开跨域设置 102 | ``` 103 | 104 | ### 登录账号 105 | ``` 106 | 默认账号:admin 107 | 密码: 1234567 108 | ``` 109 | 110 | ### SD 插件 111 | ``` 112 | # 1. 把插件项目放到 stable diffusion webui 的 extensions 扩展目录下即可 113 | 114 | # 2. 正常启动 webui 115 | ``` 116 | 117 | ### nginx 配置 118 | ``` 119 | # 在 nginx.conf 配置文件中添加 120 | 121 | location /upload/ { 122 | alias /Users/stable-diffusion-webui/; # 修改成自己 stable-diffusion-webui 文件的路径亘路径 123 | autoindex on; 124 | 125 | add_header 'Access-Control-Allow-Origin' '*'; 126 | add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, HEAD, OPTIONS'; 127 | add_header 'Access-Control-Allow-Headers' 'Content-Type, X-CSRF-Token, Authorization, AccessToken, Token, Cache-Control'; 128 | add_header 'Access-Control-Allow-Credentials' 'true'; 129 | 130 | if ($request_method = 'OPTIONS') { 131 | add_header 'Access-Control-Allow-Origin' '*'; 132 | add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, HEAD, OPTIONS'; 133 | add_header 'Access-Control-Allow-Headers' 'Content-Type, X-CSRF-Token, Authorization, AccessToken, Token, Cache-Control'; 134 | add_header 'Access-Control-Allow-Credentials' 'true'; 135 | add_header 'Access-Control-Max-Age' 1728000; 136 | add_header 'Content-Type' 'text/plain charset=UTF-8'; 137 | add_header 'Content-Length' 0; 138 | return 204; 139 | } 140 | } 141 | ``` 142 | 143 | ## 联系 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 |
微信留言
153 | -------------------------------------------------------------------------------- /sql/sql.sql: -------------------------------------------------------------------------------- 1 | create table core_account 2 | ( 3 | id bigint auto_increment comment 'ID' 4 | primary key, 5 | create_time datetime not null comment '创建时间', 6 | update_time datetime not null comment '更新时间', 7 | delete_time datetime null comment '删除时间', 8 | username varchar(255) null comment '用户名', 9 | password varchar(255) null comment '密码', 10 | nickname varchar(30) null comment '昵称', 11 | role varchar(20) null comment '角色: ADMIN, USER', 12 | status int null comment '状态: 0 禁用, 1 可用', 13 | constraint core_account_pk 14 | unique (username) 15 | ) 16 | comment '用户表'; 17 | 18 | create table core_setting 19 | ( 20 | id bigint auto_increment comment 'ID' 21 | primary key, 22 | create_time datetime not null comment '创建时间', 23 | update_time datetime not null comment '更新时间', 24 | delete_time datetime null comment '删除时间', 25 | config_key varchar(30) null comment '配置名', 26 | config_value varchar(255) null comment '配置值', 27 | mark varchar(255) null comment '说明', 28 | operate_id int null comment '操作人ID', 29 | operate_name varchar(30) null comment '操作人名称', 30 | constraint core_setting_config_key_uindex 31 | unique (config_key) 32 | ) 33 | comment '系统配置'; 34 | 35 | create table core_task 36 | ( 37 | id bigint auto_increment comment 'ID' 38 | primary key, 39 | create_time datetime not null comment '创建时间', 40 | update_time datetime not null comment '更新时间', 41 | delete_time datetime null comment '删除时间', 42 | category varchar(20) null comment '类型: txt2img, img2img', 43 | prompt text null comment '提示词', 44 | negative_prompt text null comment '反向提示词', 45 | weight float null comment '长度', 46 | height float null comment '宽度', 47 | img_size varchar(20) null comment '尺寸', 48 | seed varchar(20) null comment '随机数', 49 | sampler_name varchar(50) null comment '采样器', 50 | steps int null comment '采样步数', 51 | cfg_scale int null comment '引导系数', 52 | batch_size int null comment '批次', 53 | total int null comment '总量', 54 | sd_model_name varchar(100) null comment '模型名称', 55 | sd_model_hash varchar(50) null comment '模型hash值', 56 | sd_vae_name varchar(100) null comment 'VAE名称', 57 | sd_vae_hash varchar(50) null comment 'VAE hash值', 58 | job_timestamp datetime null comment '任务时间', 59 | version varchar(20) null comment 'SD 版本号', 60 | grid_image_url varchar(255) null comment '网格图片地址', 61 | status varchar(20) null comment '状态:INIT, PROGRESS, COMPLETE, INTERRUPT', 62 | count int default 0 null comment '实际作品数量', 63 | has_excellent tinyint default 0 null comment '是否存在优秀作品', 64 | ref_images json null comment '参考图片', 65 | store varchar(20) null comment '服务存储名称', 66 | author_id int null comment '作者ID', 67 | author_name varchar(30) null comment '作者名称', 68 | extra text null comment '扩展信息' 69 | ) 70 | comment 'ai任务表'; 71 | 72 | create index core_task_author_id_index 73 | on core_task (author_id); 74 | 75 | create table core_task_detail 76 | ( 77 | id bigint auto_increment comment 'ID' 78 | primary key, 79 | create_time datetime not null comment '创建时间', 80 | update_time datetime not null comment '更新时间', 81 | delete_time datetime null comment '删除时间', 82 | task_id bigint null comment '任务ID', 83 | image_url varchar(255) null comment '图片地址', 84 | has_excellent tinyint null comment '是否优秀作品' 85 | ) 86 | comment 'ai任务详情'; 87 | 88 | create index core_task_detail_task_id_index 89 | on core_task_detail (task_id); 90 | -------------------------------------------------------------------------------- /ent/baseschema.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | import ( 6 | "ai-gallery/ent/baseschema" 7 | "fmt" 8 | "strings" 9 | "time" 10 | 11 | "entgo.io/ent" 12 | "entgo.io/ent/dialect/sql" 13 | ) 14 | 15 | // BaseSchema is the model entity for the BaseSchema schema. 16 | type BaseSchema struct { 17 | config `json:"-"` 18 | // ID of the ent. 19 | ID int `json:"id,omitempty"` 20 | // 创建时间 21 | CreateTime time.Time `json:"create_time,omitempty"` 22 | // 更新时间 23 | UpdateTime time.Time `json:"update_time,omitempty"` 24 | // 删除时间 25 | DeleteTime *time.Time `json:"delete_time,omitempty"` 26 | selectValues sql.SelectValues 27 | } 28 | 29 | // scanValues returns the types for scanning values from sql.Rows. 30 | func (*BaseSchema) scanValues(columns []string) ([]any, error) { 31 | values := make([]any, len(columns)) 32 | for i := range columns { 33 | switch columns[i] { 34 | case baseschema.FieldID: 35 | values[i] = new(sql.NullInt64) 36 | case baseschema.FieldCreateTime, baseschema.FieldUpdateTime, baseschema.FieldDeleteTime: 37 | values[i] = new(sql.NullTime) 38 | default: 39 | values[i] = new(sql.UnknownType) 40 | } 41 | } 42 | return values, nil 43 | } 44 | 45 | // assignValues assigns the values that were returned from sql.Rows (after scanning) 46 | // to the BaseSchema fields. 47 | func (bs *BaseSchema) assignValues(columns []string, values []any) error { 48 | if m, n := len(values), len(columns); m < n { 49 | return fmt.Errorf("mismatch number of scan values: %d != %d", m, n) 50 | } 51 | for i := range columns { 52 | switch columns[i] { 53 | case baseschema.FieldID: 54 | value, ok := values[i].(*sql.NullInt64) 55 | if !ok { 56 | return fmt.Errorf("unexpected type %T for field id", value) 57 | } 58 | bs.ID = int(value.Int64) 59 | case baseschema.FieldCreateTime: 60 | if value, ok := values[i].(*sql.NullTime); !ok { 61 | return fmt.Errorf("unexpected type %T for field create_time", values[i]) 62 | } else if value.Valid { 63 | bs.CreateTime = value.Time 64 | } 65 | case baseschema.FieldUpdateTime: 66 | if value, ok := values[i].(*sql.NullTime); !ok { 67 | return fmt.Errorf("unexpected type %T for field update_time", values[i]) 68 | } else if value.Valid { 69 | bs.UpdateTime = value.Time 70 | } 71 | case baseschema.FieldDeleteTime: 72 | if value, ok := values[i].(*sql.NullTime); !ok { 73 | return fmt.Errorf("unexpected type %T for field delete_time", values[i]) 74 | } else if value.Valid { 75 | bs.DeleteTime = new(time.Time) 76 | *bs.DeleteTime = value.Time 77 | } 78 | default: 79 | bs.selectValues.Set(columns[i], values[i]) 80 | } 81 | } 82 | return nil 83 | } 84 | 85 | // Value returns the ent.Value that was dynamically selected and assigned to the BaseSchema. 86 | // This includes values selected through modifiers, order, etc. 87 | func (bs *BaseSchema) Value(name string) (ent.Value, error) { 88 | return bs.selectValues.Get(name) 89 | } 90 | 91 | // Update returns a builder for updating this BaseSchema. 92 | // Note that you need to call BaseSchema.Unwrap() before calling this method if this BaseSchema 93 | // was returned from a transaction, and the transaction was committed or rolled back. 94 | func (bs *BaseSchema) Update() *BaseSchemaUpdateOne { 95 | return NewBaseSchemaClient(bs.config).UpdateOne(bs) 96 | } 97 | 98 | // Unwrap unwraps the BaseSchema entity that was returned from a transaction after it was closed, 99 | // so that all future queries will be executed through the driver which created the transaction. 100 | func (bs *BaseSchema) Unwrap() *BaseSchema { 101 | _tx, ok := bs.config.driver.(*txDriver) 102 | if !ok { 103 | panic("ent: BaseSchema is not a transactional entity") 104 | } 105 | bs.config.driver = _tx.drv 106 | return bs 107 | } 108 | 109 | // String implements the fmt.Stringer. 110 | func (bs *BaseSchema) String() string { 111 | var builder strings.Builder 112 | builder.WriteString("BaseSchema(") 113 | builder.WriteString(fmt.Sprintf("id=%v, ", bs.ID)) 114 | builder.WriteString("create_time=") 115 | builder.WriteString(bs.CreateTime.Format(time.ANSIC)) 116 | builder.WriteString(", ") 117 | builder.WriteString("update_time=") 118 | builder.WriteString(bs.UpdateTime.Format(time.ANSIC)) 119 | builder.WriteString(", ") 120 | if v := bs.DeleteTime; v != nil { 121 | builder.WriteString("delete_time=") 122 | builder.WriteString(v.Format(time.ANSIC)) 123 | } 124 | builder.WriteByte(')') 125 | return builder.String() 126 | } 127 | 128 | // BaseSchemas is a parsable slice of BaseSchema. 129 | type BaseSchemas []*BaseSchema 130 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ai-gallery 2 |
3 | 4 | [ English | [Chinese](README_zh.md) ] 5 | 6 | ai-gallery is a front-end and back-end separation system based on Go-Zero + SD Plugin + Vite/React + Ant Design technology, which is used to uniformly manage SD painting tasks. 7 | 8 | - [Backend Project](https://github.com/tabelf/ai-gallery)
9 | - [Front-end Project](https://github.com/tabelf/ai-gallery-ui)
10 | - [SD Plugin](https://github.com/tabelf/sd-webui-gen2gallery)
11 | 12 | ## Demo 13 |
14 | 15 | https://github.com/user-attachments/assets/db6ac661-84ca-47b8-934b-86f1f61a9578 16 | 17 | 18 | [Full video demonstration](https://www.bilibili.com/video/BV1mt8ue6E1Y) 19 | 20 | ## ✨ Feature 21 |
22 | 23 | - Manage SD txt2img and img2img drawing task tecord 24 | - SD generate image cloud/local storage 25 | - Aggregation of task data submitted by multiple users 26 | - User management 27 | - System settings 28 | 29 | ## 💼 Preparation 30 | 31 | ### Environment Preparation 32 | ```text 33 | go sdk v1.21.0 34 | node v21.6.2 35 | npm v9.6.7 36 | react v18.2.0 37 | stable diffuison webui v1.9.3 38 | mysql v8.0.28 39 | nginx v1.25.3 40 | ``` 41 | 42 | ### Get the code 43 | ```bash 44 | # get the plugin project code 45 | git clone https://github.com/tabelf/sd-webui-gen2gallery.git 46 | 47 | # get the backend project code 48 | git clone https://github.com/tabelf/ai-gallery.git 49 | 50 | # get front-end project code 51 | git clone https://github.com/tabelf/ai-gallery-ui.git 52 | ``` 53 | 54 | ## Startup 55 | 56 | ### Server startup 57 | ```bash 58 | # enter the backend project directory 59 | cd ./ai-gallery 60 | 61 | # install go dependencies 62 | go mod tidy 63 | 64 | # modify database config 65 | vi ./service/etc/application-dev.yaml 66 | 67 | # root: database username 68 | # 12345678: database password 69 | # ai_gallery: database name 70 | 71 | # db: 72 | # url: root:12345678@(127.0.0.1:3306)/ai_gallery?charset=utf8mb4&parseTime=true&loc=Local&interpolateParams=true 73 | # driver: mysql 74 | # max_open_conns: 100 75 | # max_idle_conns: 30 76 | 77 | # generate database tables 78 | go run cmd/main.go migrate --env dev 79 | 80 | # run 81 | go run cmd/main.go start --env dev 82 | ``` 83 | 84 | ### Front-end startup 85 | ```bash 86 | # install dependencies. 87 | npm install 88 | 89 | # start the service 90 | vite dev 91 | 92 | # the address will be displayed if the deployment is successful 93 | http://localhost:5173/ 94 | 95 | # login 96 | # username:admin 97 | # password: 1234567 98 | 99 | # Go to the system settings menu bar and configure the location where the pictures are to be stored 100 | # If you choose local storage, you need to configure the following nginx 101 | # If you choose Tencent Cloud cos for storage, you need to configure the storage address, ID, key, and remember to turn on cross-domain settings 102 | # If you choose Alibaba Cloud OOS for storage, you need to configure the bucket name, storage address, ID, key, and remember to enable cross-domain settings. 103 | ``` 104 | 105 | ### Login Account 106 | ``` 107 | username:admin 108 | password:1234567 109 | ``` 110 | 111 | ### SD Plugin 112 | ``` 113 | # 1. Put the plug-in project in the extensions directory of stable diffusion webui 114 | 115 | # 2. Normal start ./webui 116 | ``` 117 | 118 | ### Nginx config 119 | ``` 120 | # Add in the nginx.conf configuration file 121 | 122 | location /upload/ { 123 | alias /Users/stable-diffusion-webui/; # 修改成自己 stable-diffusion-webui 文件的路径亘路径 124 | autoindex on; 125 | 126 | add_header 'Access-Control-Allow-Origin' '*'; 127 | add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, HEAD, OPTIONS'; 128 | add_header 'Access-Control-Allow-Headers' 'Content-Type, X-CSRF-Token, Authorization, AccessToken, Token, Cache-Control'; 129 | add_header 'Access-Control-Allow-Credentials' 'true'; 130 | 131 | if ($request_method = 'OPTIONS') { 132 | add_header 'Access-Control-Allow-Origin' '*'; 133 | add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, HEAD, OPTIONS'; 134 | add_header 'Access-Control-Allow-Headers' 'Content-Type, X-CSRF-Token, Authorization, AccessToken, Token, Cache-Control'; 135 | add_header 'Access-Control-Allow-Credentials' 'true'; 136 | add_header 'Access-Control-Max-Age' 1728000; 137 | add_header 'Content-Type' 'text/plain charset=UTF-8'; 138 | add_header 'Content-Length' 0; 139 | return 204; 140 | } 141 | } 142 | ``` 143 | 144 | ## 联系 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 |
wechat
154 | -------------------------------------------------------------------------------- /ent/account/account.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package account 4 | 5 | import ( 6 | "time" 7 | 8 | "entgo.io/ent/dialect/sql" 9 | ) 10 | 11 | const ( 12 | // Label holds the string label denoting the account type in the database. 13 | Label = "account" 14 | // FieldID holds the string denoting the id field in the database. 15 | FieldID = "id" 16 | // FieldCreateTime holds the string denoting the create_time field in the database. 17 | FieldCreateTime = "create_time" 18 | // FieldUpdateTime holds the string denoting the update_time field in the database. 19 | FieldUpdateTime = "update_time" 20 | // FieldDeleteTime holds the string denoting the delete_time field in the database. 21 | FieldDeleteTime = "delete_time" 22 | // FieldUsername holds the string denoting the username field in the database. 23 | FieldUsername = "username" 24 | // FieldPassword holds the string denoting the password field in the database. 25 | FieldPassword = "password" 26 | // FieldNickname holds the string denoting the nickname field in the database. 27 | FieldNickname = "nickname" 28 | // FieldRole holds the string denoting the role field in the database. 29 | FieldRole = "role" 30 | // FieldStatus holds the string denoting the status field in the database. 31 | FieldStatus = "status" 32 | // Table holds the table name of the account in the database. 33 | Table = "core_account" 34 | ) 35 | 36 | // Columns holds all SQL columns for account fields. 37 | var Columns = []string{ 38 | FieldID, 39 | FieldCreateTime, 40 | FieldUpdateTime, 41 | FieldDeleteTime, 42 | FieldUsername, 43 | FieldPassword, 44 | FieldNickname, 45 | FieldRole, 46 | FieldStatus, 47 | } 48 | 49 | // ValidColumn reports if the column name is valid (part of the table columns). 50 | func ValidColumn(column string) bool { 51 | for i := range Columns { 52 | if column == Columns[i] { 53 | return true 54 | } 55 | } 56 | return false 57 | } 58 | 59 | var ( 60 | // DefaultCreateTime holds the default value on creation for the "create_time" field. 61 | DefaultCreateTime func() time.Time 62 | // DefaultUpdateTime holds the default value on creation for the "update_time" field. 63 | DefaultUpdateTime func() time.Time 64 | // UpdateDefaultUpdateTime holds the default value on update for the "update_time" field. 65 | UpdateDefaultUpdateTime func() time.Time 66 | // UsernameValidator is a validator for the "username" field. It is called by the builders before save. 67 | UsernameValidator func(string) error 68 | // PasswordValidator is a validator for the "password" field. It is called by the builders before save. 69 | PasswordValidator func(string) error 70 | // NicknameValidator is a validator for the "nickname" field. It is called by the builders before save. 71 | NicknameValidator func(string) error 72 | // RoleValidator is a validator for the "role" field. It is called by the builders before save. 73 | RoleValidator func(string) error 74 | ) 75 | 76 | // OrderOption defines the ordering options for the Account queries. 77 | type OrderOption func(*sql.Selector) 78 | 79 | // ByID orders the results by the id field. 80 | func ByID(opts ...sql.OrderTermOption) OrderOption { 81 | return sql.OrderByField(FieldID, opts...).ToFunc() 82 | } 83 | 84 | // ByCreateTime orders the results by the create_time field. 85 | func ByCreateTime(opts ...sql.OrderTermOption) OrderOption { 86 | return sql.OrderByField(FieldCreateTime, opts...).ToFunc() 87 | } 88 | 89 | // ByUpdateTime orders the results by the update_time field. 90 | func ByUpdateTime(opts ...sql.OrderTermOption) OrderOption { 91 | return sql.OrderByField(FieldUpdateTime, opts...).ToFunc() 92 | } 93 | 94 | // ByDeleteTime orders the results by the delete_time field. 95 | func ByDeleteTime(opts ...sql.OrderTermOption) OrderOption { 96 | return sql.OrderByField(FieldDeleteTime, opts...).ToFunc() 97 | } 98 | 99 | // ByUsername orders the results by the username field. 100 | func ByUsername(opts ...sql.OrderTermOption) OrderOption { 101 | return sql.OrderByField(FieldUsername, opts...).ToFunc() 102 | } 103 | 104 | // ByPassword orders the results by the password field. 105 | func ByPassword(opts ...sql.OrderTermOption) OrderOption { 106 | return sql.OrderByField(FieldPassword, opts...).ToFunc() 107 | } 108 | 109 | // ByNickname orders the results by the nickname field. 110 | func ByNickname(opts ...sql.OrderTermOption) OrderOption { 111 | return sql.OrderByField(FieldNickname, opts...).ToFunc() 112 | } 113 | 114 | // ByRole orders the results by the role field. 115 | func ByRole(opts ...sql.OrderTermOption) OrderOption { 116 | return sql.OrderByField(FieldRole, opts...).ToFunc() 117 | } 118 | 119 | // ByStatus orders the results by the status field. 120 | func ByStatus(opts ...sql.OrderTermOption) OrderOption { 121 | return sql.OrderByField(FieldStatus, opts...).ToFunc() 122 | } 123 | -------------------------------------------------------------------------------- /ent/setting/setting.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package setting 4 | 5 | import ( 6 | "time" 7 | 8 | "entgo.io/ent/dialect/sql" 9 | ) 10 | 11 | const ( 12 | // Label holds the string label denoting the setting type in the database. 13 | Label = "setting" 14 | // FieldID holds the string denoting the id field in the database. 15 | FieldID = "id" 16 | // FieldCreateTime holds the string denoting the create_time field in the database. 17 | FieldCreateTime = "create_time" 18 | // FieldUpdateTime holds the string denoting the update_time field in the database. 19 | FieldUpdateTime = "update_time" 20 | // FieldDeleteTime holds the string denoting the delete_time field in the database. 21 | FieldDeleteTime = "delete_time" 22 | // FieldConfigKey holds the string denoting the config_key field in the database. 23 | FieldConfigKey = "config_key" 24 | // FieldConfigValue holds the string denoting the config_value field in the database. 25 | FieldConfigValue = "config_value" 26 | // FieldMark holds the string denoting the mark field in the database. 27 | FieldMark = "mark" 28 | // FieldOperateID holds the string denoting the operate_id field in the database. 29 | FieldOperateID = "operate_id" 30 | // FieldOperateName holds the string denoting the operate_name field in the database. 31 | FieldOperateName = "operate_name" 32 | // Table holds the table name of the setting in the database. 33 | Table = "core_setting" 34 | ) 35 | 36 | // Columns holds all SQL columns for setting fields. 37 | var Columns = []string{ 38 | FieldID, 39 | FieldCreateTime, 40 | FieldUpdateTime, 41 | FieldDeleteTime, 42 | FieldConfigKey, 43 | FieldConfigValue, 44 | FieldMark, 45 | FieldOperateID, 46 | FieldOperateName, 47 | } 48 | 49 | // ValidColumn reports if the column name is valid (part of the table columns). 50 | func ValidColumn(column string) bool { 51 | for i := range Columns { 52 | if column == Columns[i] { 53 | return true 54 | } 55 | } 56 | return false 57 | } 58 | 59 | var ( 60 | // DefaultCreateTime holds the default value on creation for the "create_time" field. 61 | DefaultCreateTime func() time.Time 62 | // DefaultUpdateTime holds the default value on creation for the "update_time" field. 63 | DefaultUpdateTime func() time.Time 64 | // UpdateDefaultUpdateTime holds the default value on update for the "update_time" field. 65 | UpdateDefaultUpdateTime func() time.Time 66 | // ConfigKeyValidator is a validator for the "config_key" field. It is called by the builders before save. 67 | ConfigKeyValidator func(string) error 68 | // ConfigValueValidator is a validator for the "config_value" field. It is called by the builders before save. 69 | ConfigValueValidator func(string) error 70 | // MarkValidator is a validator for the "mark" field. It is called by the builders before save. 71 | MarkValidator func(string) error 72 | // OperateNameValidator is a validator for the "operate_name" field. It is called by the builders before save. 73 | OperateNameValidator func(string) error 74 | ) 75 | 76 | // OrderOption defines the ordering options for the Setting queries. 77 | type OrderOption func(*sql.Selector) 78 | 79 | // ByID orders the results by the id field. 80 | func ByID(opts ...sql.OrderTermOption) OrderOption { 81 | return sql.OrderByField(FieldID, opts...).ToFunc() 82 | } 83 | 84 | // ByCreateTime orders the results by the create_time field. 85 | func ByCreateTime(opts ...sql.OrderTermOption) OrderOption { 86 | return sql.OrderByField(FieldCreateTime, opts...).ToFunc() 87 | } 88 | 89 | // ByUpdateTime orders the results by the update_time field. 90 | func ByUpdateTime(opts ...sql.OrderTermOption) OrderOption { 91 | return sql.OrderByField(FieldUpdateTime, opts...).ToFunc() 92 | } 93 | 94 | // ByDeleteTime orders the results by the delete_time field. 95 | func ByDeleteTime(opts ...sql.OrderTermOption) OrderOption { 96 | return sql.OrderByField(FieldDeleteTime, opts...).ToFunc() 97 | } 98 | 99 | // ByConfigKey orders the results by the config_key field. 100 | func ByConfigKey(opts ...sql.OrderTermOption) OrderOption { 101 | return sql.OrderByField(FieldConfigKey, opts...).ToFunc() 102 | } 103 | 104 | // ByConfigValue orders the results by the config_value field. 105 | func ByConfigValue(opts ...sql.OrderTermOption) OrderOption { 106 | return sql.OrderByField(FieldConfigValue, opts...).ToFunc() 107 | } 108 | 109 | // ByMark orders the results by the mark field. 110 | func ByMark(opts ...sql.OrderTermOption) OrderOption { 111 | return sql.OrderByField(FieldMark, opts...).ToFunc() 112 | } 113 | 114 | // ByOperateID orders the results by the operate_id field. 115 | func ByOperateID(opts ...sql.OrderTermOption) OrderOption { 116 | return sql.OrderByField(FieldOperateID, opts...).ToFunc() 117 | } 118 | 119 | // ByOperateName orders the results by the operate_name field. 120 | func ByOperateName(opts ...sql.OrderTermOption) OrderOption { 121 | return sql.OrderByField(FieldOperateName, opts...).ToFunc() 122 | } 123 | -------------------------------------------------------------------------------- /api/work.api: -------------------------------------------------------------------------------- 1 | syntax = "v1" 2 | 3 | info ( 4 | title: "作品接口" 5 | version: "v1.0" 6 | ) 7 | 8 | @server ( 9 | group: work 10 | middleware: JWT 11 | ) 12 | service gallery-api { 13 | @doc ( 14 | summary: "获取作品列表" 15 | ) 16 | @handler GetWork 17 | get /api/v1/manage/work (GetWorkRequest) returns (GetWorkResponse) 18 | 19 | @doc ( 20 | summary: "获取作品详情" 21 | ) 22 | @handler GetWorkDetail 23 | get /api/v1/manage/work/:task_id (GetWorkDetailRequest) returns (GetWorkDetailResponse) 24 | 25 | @doc ( 26 | summary: "获取任务列表" 27 | ) 28 | @handler GetTask 29 | get /api/v1/manage/task (GetTaskRequest) returns (GetTaskResponse) 30 | 31 | @doc ( 32 | summary: "获取上传人列表" 33 | ) 34 | @handler GetTaskAuthor 35 | get /api/v1/manage/task/author returns (GetTaskAuthorResponse) 36 | 37 | @doc ( 38 | summary: "获取上传模型列表" 39 | ) 40 | @handler GetTaskModel 41 | get /api/v1/manage/task/model returns (GetTaskModelResponse) 42 | 43 | @doc ( 44 | summary: "获取上传此尺寸列表" 45 | ) 46 | @handler GetTaskSize 47 | get /api/v1/manage/task/size returns (GetTaskSizeResponse) 48 | 49 | @doc ( 50 | summary: "标记作品为优秀" 51 | ) 52 | @handler MarkWorkExcellent 53 | put /api/v1/manage/work/excellent (MarkWorkExcellentRequest) 54 | } 55 | 56 | type MarkWorkExcellentRequest { 57 | TaskID int `json:"task_id"` 58 | SubTaskID int `json:"sub_task_id"` 59 | HasExcellent bool `json:"has_excellent"` 60 | } 61 | 62 | type GetWorkRequest { 63 | Offset int `form:"offset,default=0"` 64 | Limit int `form:"limit,default=10"` 65 | Sorted string `form:"sorted,default=asc,optional"` 66 | Size string `form:"size,optional"` 67 | SdModelName string `json:"sd_model_name,optional"` 68 | HasExcellent *int `form:"has_excellent,default=-1,optional"` 69 | HasRefImage *int `form:"has_ref_image,default=-1,optional"` 70 | } 71 | 72 | type GetWorkResponse { 73 | Total int `json:"total"` 74 | Data []*WorkBo `json:"data"` 75 | } 76 | 77 | type WorkBo { 78 | TaskID int `json:"task_id"` 79 | Category string `json:"category"` 80 | Prompt string `json:"prompt"` 81 | Size string `json:"size"` 82 | AuthorID int `json:"author_id"` 83 | AuthorName string `json:"author_name"` 84 | Count int `json:"count"` 85 | HeadImage string `json:"head_image"` 86 | } 87 | 88 | type TaskAuthorBo { 89 | AuthorID int `json:"author_id"` 90 | AuthorName string `json:"author_name"` 91 | } 92 | 93 | type GetTaskAuthorResponse { 94 | TaskAuthorBo []*TaskAuthorBo `json:"data"` 95 | } 96 | 97 | type GetTaskModelResponse { 98 | Models []string `json:"models"` 99 | } 100 | 101 | type GetTaskSizeResponse { 102 | Sizes []string `json:"sizes"` 103 | } 104 | 105 | type GetWorkDetailRequest { 106 | TaskID int `path:"task_id"` 107 | } 108 | 109 | type GetWorkDetailResponse { 110 | TaskID int `json:"task_id"` 111 | Category string `json:"category"` 112 | Prompt string `json:"prompt"` 113 | NegativePrompt string `json:"negative_prompt"` 114 | Width float32 `json:"width"` 115 | Height float32 `json:"height"` 116 | Size string `json:"size"` 117 | Seed string `json:"seed"` 118 | SamplerName string `json:"sampler_name"` 119 | Steps int `json:"steps"` // 采样步数 120 | CfgScale int `json:"cfg_scale"` 121 | BatchSize int `json:"batch_size"` 122 | Total int `json:"total"` 123 | SdModelName string `json:"sd_model_name"` 124 | SdModelHash string `json:"sd_model_hash"` 125 | SdVaeName string `json:"sd_vae_name"` 126 | SdVaeHash string `json:"sd_vae_hash"` 127 | JobTimestamp string `json:"job_timestamp"` 128 | Version string `json:"version"` 129 | AuthorID int `json:"author_id"` 130 | AuthorName string `json:"author_name"` 131 | RefImages []string `json:"ref_images"` 132 | WorkDetailBos []*WorkDetailBo `json:"details"` 133 | } 134 | 135 | type WorkDetailBo { 136 | SubTaskID int `json:"sub_task_id"` 137 | ImageURL string `json:"image_url"` 138 | HasExcellent bool `json:"has_excellent"` 139 | } 140 | 141 | type GetTaskRequest { 142 | Offset int `form:"offset,default=0"` 143 | Limit int `form:"limit,default=10"` 144 | StartTime string `form:"start_time,optional"` 145 | EndTime string `form:"end_time,optional"` 146 | AuthorIDs []int `form:"author_ids,optional"` 147 | Category string `form:"category,optional"` 148 | Status string `form:"status,optional"` 149 | } 150 | 151 | type TaskBo { 152 | TaskID int `json:"task_id"` 153 | Category string `json:"category"` 154 | Prompt string `json:"prompt"` 155 | Size string `json:"size"` 156 | AuthorID int `json:"author_id"` 157 | AuthorName string `json:"author_name"` 158 | Total int `json:"total"` 159 | JobTimestamp string `json:"job_timestamp"` 160 | Status string `json:"status"` 161 | Count int `json:"count"` 162 | ImageUrls []string `json:"image_urls"` 163 | } 164 | 165 | type GetTaskResponse { 166 | Total int `json:"total"` 167 | Data []*TaskBo `json:"data"` 168 | } 169 | 170 | -------------------------------------------------------------------------------- /service/internal/handler/routes.go: -------------------------------------------------------------------------------- 1 | // Code generated by goctl. DO NOT EDIT. 2 | package handler 3 | 4 | import ( 5 | "net/http" 6 | 7 | account "ai-gallery/service/internal/handler/account" 8 | analysis "ai-gallery/service/internal/handler/analysis" 9 | anonymous "ai-gallery/service/internal/handler/anonymous" 10 | base "ai-gallery/service/internal/handler/base" 11 | setting "ai-gallery/service/internal/handler/setting" 12 | task "ai-gallery/service/internal/handler/task" 13 | work "ai-gallery/service/internal/handler/work" 14 | "ai-gallery/service/internal/svc" 15 | 16 | "github.com/zeromicro/go-zero/rest" 17 | ) 18 | 19 | func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { 20 | server.AddRoutes( 21 | rest.WithMiddlewares( 22 | []rest.Middleware{serverCtx.JWT}, 23 | []rest.Route{ 24 | { 25 | Method: http.MethodGet, 26 | Path: "/api/v1/manage/user/detail", 27 | Handler: account.GetUserDetailHandler(serverCtx), 28 | }, 29 | { 30 | Method: http.MethodPut, 31 | Path: "/api/v1/manage/user/detail", 32 | Handler: account.UpdateUserDetailHandler(serverCtx), 33 | }, 34 | }..., 35 | ), 36 | ) 37 | 38 | server.AddRoutes( 39 | rest.WithMiddlewares( 40 | []rest.Middleware{serverCtx.ManageJWT}, 41 | []rest.Route{ 42 | { 43 | Method: http.MethodPost, 44 | Path: "/api/v1/manage/user", 45 | Handler: account.AddUserHandler(serverCtx), 46 | }, 47 | { 48 | Method: http.MethodGet, 49 | Path: "/api/v1/manage/user", 50 | Handler: account.GetUserHandler(serverCtx), 51 | }, 52 | { 53 | Method: http.MethodPut, 54 | Path: "/api/v1/manage/user/:user_id", 55 | Handler: account.UpdateUserHandler(serverCtx), 56 | }, 57 | { 58 | Method: http.MethodDelete, 59 | Path: "/api/v1/manage/user/:user_id", 60 | Handler: account.DeleteUserHandler(serverCtx), 61 | }, 62 | { 63 | Method: http.MethodPut, 64 | Path: "/api/v1/manage/user/:user_id/reset", 65 | Handler: account.ResetPwdHandler(serverCtx), 66 | }, 67 | }..., 68 | ), 69 | ) 70 | 71 | server.AddRoutes( 72 | rest.WithMiddlewares( 73 | []rest.Middleware{serverCtx.ManageJWT}, 74 | []rest.Route{ 75 | { 76 | Method: http.MethodGet, 77 | Path: "/api/v1/manage/analysis/base", 78 | Handler: analysis.GetAnalysisBaseHandler(serverCtx), 79 | }, 80 | { 81 | Method: http.MethodGet, 82 | Path: "/api/v1/manage/analysis/task", 83 | Handler: analysis.GetAnalysisTaskHandler(serverCtx), 84 | }, 85 | { 86 | Method: http.MethodGet, 87 | Path: "/api/v1/manage/analysis/user", 88 | Handler: analysis.GetAnalysisUserHandler(serverCtx), 89 | }, 90 | }..., 91 | ), 92 | ) 93 | 94 | server.AddRoutes( 95 | []rest.Route{ 96 | { 97 | Method: http.MethodPost, 98 | Path: "/api/v1/anonymous/login", 99 | Handler: anonymous.AuthLoginHandler(serverCtx), 100 | }, 101 | }, 102 | ) 103 | 104 | server.AddRoutes( 105 | []rest.Route{ 106 | { 107 | Method: http.MethodGet, 108 | Path: "/api/base/ping", 109 | Handler: base.PingHandler(serverCtx), 110 | }, 111 | }, 112 | ) 113 | 114 | server.AddRoutes( 115 | rest.WithMiddlewares( 116 | []rest.Middleware{serverCtx.ManageJWT}, 117 | []rest.Route{ 118 | { 119 | Method: http.MethodGet, 120 | Path: "/api/v1/manage/setting", 121 | Handler: setting.GetSettingHandler(serverCtx), 122 | }, 123 | { 124 | Method: http.MethodPut, 125 | Path: "/api/v1/manage/setting", 126 | Handler: setting.UpdateSettingHandler(serverCtx), 127 | }, 128 | }..., 129 | ), 130 | ) 131 | 132 | server.AddRoutes( 133 | rest.WithMiddlewares( 134 | []rest.Middleware{serverCtx.Headers}, 135 | []rest.Route{ 136 | { 137 | Method: http.MethodPost, 138 | Path: "/api/v1/sub_task", 139 | Handler: task.CreateSubTaskHandler(serverCtx), 140 | }, 141 | { 142 | Method: http.MethodPost, 143 | Path: "/api/v1/task", 144 | Handler: task.CreateTaskHandler(serverCtx), 145 | }, 146 | { 147 | Method: http.MethodPut, 148 | Path: "/api/v1/task/:task_id", 149 | Handler: task.UpdateTaskHandler(serverCtx), 150 | }, 151 | }..., 152 | ), 153 | ) 154 | 155 | server.AddRoutes( 156 | rest.WithMiddlewares( 157 | []rest.Middleware{serverCtx.JWT}, 158 | []rest.Route{ 159 | { 160 | Method: http.MethodGet, 161 | Path: "/api/v1/manage/task", 162 | Handler: work.GetTaskHandler(serverCtx), 163 | }, 164 | { 165 | Method: http.MethodGet, 166 | Path: "/api/v1/manage/task/author", 167 | Handler: work.GetTaskAuthorHandler(serverCtx), 168 | }, 169 | { 170 | Method: http.MethodGet, 171 | Path: "/api/v1/manage/task/model", 172 | Handler: work.GetTaskModelHandler(serverCtx), 173 | }, 174 | { 175 | Method: http.MethodGet, 176 | Path: "/api/v1/manage/task/size", 177 | Handler: work.GetTaskSizeHandler(serverCtx), 178 | }, 179 | { 180 | Method: http.MethodGet, 181 | Path: "/api/v1/manage/work", 182 | Handler: work.GetWorkHandler(serverCtx), 183 | }, 184 | { 185 | Method: http.MethodGet, 186 | Path: "/api/v1/manage/work/:task_id", 187 | Handler: work.GetWorkDetailHandler(serverCtx), 188 | }, 189 | { 190 | Method: http.MethodPut, 191 | Path: "/api/v1/manage/work/excellent", 192 | Handler: work.MarkWorkExcellentHandler(serverCtx), 193 | }, 194 | }..., 195 | ), 196 | ) 197 | } 198 | -------------------------------------------------------------------------------- /ent/taskdetail.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | import ( 6 | "ai-gallery/ent/taskdetail" 7 | "fmt" 8 | "strings" 9 | "time" 10 | 11 | "entgo.io/ent" 12 | "entgo.io/ent/dialect/sql" 13 | ) 14 | 15 | // TaskDetail is the model entity for the TaskDetail schema. 16 | type TaskDetail struct { 17 | config `json:"-"` 18 | // ID of the ent. 19 | ID int `json:"id,omitempty"` 20 | // 创建时间 21 | CreateTime time.Time `json:"create_time,omitempty"` 22 | // 更新时间 23 | UpdateTime time.Time `json:"update_time,omitempty"` 24 | // 删除时间 25 | DeleteTime *time.Time `json:"delete_time,omitempty"` 26 | // 任务ID 27 | TaskID int `json:"task_id,omitempty"` 28 | // 图片地址 29 | ImageURL string `json:"image_url,omitempty"` 30 | // 是否为优秀作品 31 | HasExcellent bool `json:"has_excellent,omitempty"` 32 | selectValues sql.SelectValues 33 | } 34 | 35 | // scanValues returns the types for scanning values from sql.Rows. 36 | func (*TaskDetail) scanValues(columns []string) ([]any, error) { 37 | values := make([]any, len(columns)) 38 | for i := range columns { 39 | switch columns[i] { 40 | case taskdetail.FieldHasExcellent: 41 | values[i] = new(sql.NullBool) 42 | case taskdetail.FieldID, taskdetail.FieldTaskID: 43 | values[i] = new(sql.NullInt64) 44 | case taskdetail.FieldImageURL: 45 | values[i] = new(sql.NullString) 46 | case taskdetail.FieldCreateTime, taskdetail.FieldUpdateTime, taskdetail.FieldDeleteTime: 47 | values[i] = new(sql.NullTime) 48 | default: 49 | values[i] = new(sql.UnknownType) 50 | } 51 | } 52 | return values, nil 53 | } 54 | 55 | // assignValues assigns the values that were returned from sql.Rows (after scanning) 56 | // to the TaskDetail fields. 57 | func (td *TaskDetail) assignValues(columns []string, values []any) error { 58 | if m, n := len(values), len(columns); m < n { 59 | return fmt.Errorf("mismatch number of scan values: %d != %d", m, n) 60 | } 61 | for i := range columns { 62 | switch columns[i] { 63 | case taskdetail.FieldID: 64 | value, ok := values[i].(*sql.NullInt64) 65 | if !ok { 66 | return fmt.Errorf("unexpected type %T for field id", value) 67 | } 68 | td.ID = int(value.Int64) 69 | case taskdetail.FieldCreateTime: 70 | if value, ok := values[i].(*sql.NullTime); !ok { 71 | return fmt.Errorf("unexpected type %T for field create_time", values[i]) 72 | } else if value.Valid { 73 | td.CreateTime = value.Time 74 | } 75 | case taskdetail.FieldUpdateTime: 76 | if value, ok := values[i].(*sql.NullTime); !ok { 77 | return fmt.Errorf("unexpected type %T for field update_time", values[i]) 78 | } else if value.Valid { 79 | td.UpdateTime = value.Time 80 | } 81 | case taskdetail.FieldDeleteTime: 82 | if value, ok := values[i].(*sql.NullTime); !ok { 83 | return fmt.Errorf("unexpected type %T for field delete_time", values[i]) 84 | } else if value.Valid { 85 | td.DeleteTime = new(time.Time) 86 | *td.DeleteTime = value.Time 87 | } 88 | case taskdetail.FieldTaskID: 89 | if value, ok := values[i].(*sql.NullInt64); !ok { 90 | return fmt.Errorf("unexpected type %T for field task_id", values[i]) 91 | } else if value.Valid { 92 | td.TaskID = int(value.Int64) 93 | } 94 | case taskdetail.FieldImageURL: 95 | if value, ok := values[i].(*sql.NullString); !ok { 96 | return fmt.Errorf("unexpected type %T for field image_url", values[i]) 97 | } else if value.Valid { 98 | td.ImageURL = value.String 99 | } 100 | case taskdetail.FieldHasExcellent: 101 | if value, ok := values[i].(*sql.NullBool); !ok { 102 | return fmt.Errorf("unexpected type %T for field has_excellent", values[i]) 103 | } else if value.Valid { 104 | td.HasExcellent = value.Bool 105 | } 106 | default: 107 | td.selectValues.Set(columns[i], values[i]) 108 | } 109 | } 110 | return nil 111 | } 112 | 113 | // Value returns the ent.Value that was dynamically selected and assigned to the TaskDetail. 114 | // This includes values selected through modifiers, order, etc. 115 | func (td *TaskDetail) Value(name string) (ent.Value, error) { 116 | return td.selectValues.Get(name) 117 | } 118 | 119 | // Update returns a builder for updating this TaskDetail. 120 | // Note that you need to call TaskDetail.Unwrap() before calling this method if this TaskDetail 121 | // was returned from a transaction, and the transaction was committed or rolled back. 122 | func (td *TaskDetail) Update() *TaskDetailUpdateOne { 123 | return NewTaskDetailClient(td.config).UpdateOne(td) 124 | } 125 | 126 | // Unwrap unwraps the TaskDetail entity that was returned from a transaction after it was closed, 127 | // so that all future queries will be executed through the driver which created the transaction. 128 | func (td *TaskDetail) Unwrap() *TaskDetail { 129 | _tx, ok := td.config.driver.(*txDriver) 130 | if !ok { 131 | panic("ent: TaskDetail is not a transactional entity") 132 | } 133 | td.config.driver = _tx.drv 134 | return td 135 | } 136 | 137 | // String implements the fmt.Stringer. 138 | func (td *TaskDetail) String() string { 139 | var builder strings.Builder 140 | builder.WriteString("TaskDetail(") 141 | builder.WriteString(fmt.Sprintf("id=%v, ", td.ID)) 142 | builder.WriteString("create_time=") 143 | builder.WriteString(td.CreateTime.Format(time.ANSIC)) 144 | builder.WriteString(", ") 145 | builder.WriteString("update_time=") 146 | builder.WriteString(td.UpdateTime.Format(time.ANSIC)) 147 | builder.WriteString(", ") 148 | if v := td.DeleteTime; v != nil { 149 | builder.WriteString("delete_time=") 150 | builder.WriteString(v.Format(time.ANSIC)) 151 | } 152 | builder.WriteString(", ") 153 | builder.WriteString("task_id=") 154 | builder.WriteString(fmt.Sprintf("%v", td.TaskID)) 155 | builder.WriteString(", ") 156 | builder.WriteString("image_url=") 157 | builder.WriteString(td.ImageURL) 158 | builder.WriteString(", ") 159 | builder.WriteString("has_excellent=") 160 | builder.WriteString(fmt.Sprintf("%v", td.HasExcellent)) 161 | builder.WriteByte(')') 162 | return builder.String() 163 | } 164 | 165 | // TaskDetails is a parsable slice of TaskDetail. 166 | type TaskDetails []*TaskDetail 167 | -------------------------------------------------------------------------------- /service/internal/dao/setting/setting.go: -------------------------------------------------------------------------------- 1 | package setting 2 | 3 | import ( 4 | "ai-gallery/service/internal/dao" 5 | "context" 6 | "time" 7 | 8 | "ai-gallery/ent" 9 | entsetting "ai-gallery/ent/setting" 10 | "ai-gallery/pkg/errgroup" 11 | "ai-gallery/service/internal/model" 12 | ) 13 | 14 | type PO struct { 15 | StoreName string `json:"store_name"` 16 | StoreAddress string `json:"store_address"` 17 | SecureID string `json:"secure_id"` 18 | SecureKey string `json:"secure_key"` 19 | StoreBucket string `json:"store_bucket"` 20 | InitPwd string `json:"init_pwd"` 21 | OperateID int `json:"operate_id"` 22 | OperateName string `json:"operate_name"` 23 | } 24 | 25 | func GetPO(ctx context.Context) (*PO, error) { 26 | var ( 27 | storeName = "" 28 | storeAddress = "" 29 | secureID = "" 30 | secureKey = "" 31 | storeBucket = "" 32 | initPwd = "" 33 | g = errgroup.WithContext(ctx) 34 | ) 35 | g.Go(func(ctx context.Context) (err error) { 36 | storeName, err = GetByConfigKey(ctx, model.SettingEnums.StoreName.Code) 37 | return err 38 | }) 39 | g.Go(func(ctx context.Context) (err error) { 40 | storeAddress, err = GetByConfigKey(ctx, model.SettingEnums.StoreAddress.Code) 41 | return err 42 | }) 43 | g.Go(func(ctx context.Context) (err error) { 44 | secureID, err = GetByConfigKey(ctx, model.SettingEnums.SecureID.Code) 45 | return err 46 | }) 47 | g.Go(func(ctx context.Context) (err error) { 48 | secureKey, err = GetByConfigKey(ctx, model.SettingEnums.SecureKey.Code) 49 | return err 50 | }) 51 | g.Go(func(ctx context.Context) (err error) { 52 | storeBucket, err = GetByConfigKey(ctx, model.SettingEnums.StoreBucket.Code) 53 | return err 54 | }) 55 | g.Go(func(ctx context.Context) (err error) { 56 | initPwd, err = GetByConfigKey(ctx, model.SettingEnums.InitPwd.Code) 57 | return err 58 | }) 59 | if err := g.Wait(); err != nil { 60 | return nil, err 61 | } 62 | return &PO{ 63 | StoreName: storeName, 64 | StoreAddress: storeAddress, 65 | SecureID: secureID, 66 | SecureKey: secureKey, 67 | StoreBucket: storeBucket, 68 | InitPwd: initPwd, 69 | }, nil 70 | } 71 | 72 | func GetByConfigKey(ctx context.Context, configKey string) (string, error) { 73 | setting, err := dao.EntClient.Setting.Query(). 74 | Where(entsetting.ConfigKey(configKey)). 75 | First(ctx) 76 | if err != nil { 77 | return "", err 78 | } 79 | return setting.ConfigValue, nil 80 | } 81 | 82 | func GetInitPwd(ctx context.Context) (string, error) { 83 | initPwd, err := GetByConfigKey(ctx, model.SettingEnums.InitPwd.Code) 84 | if err != nil { 85 | return "", err 86 | } 87 | return initPwd, err 88 | } 89 | 90 | func Create(ctx context.Context, po *PO) error { 91 | return dao.WithTx(ctx, dao.EntClient, func(tx *ent.Tx) error { 92 | if err := create(ctx, tx, model.SettingEnums.StoreName, po.StoreName); err != nil { 93 | return err 94 | } 95 | if err := create(ctx, tx, model.SettingEnums.StoreAddress, po.StoreAddress); err != nil { 96 | return err 97 | } 98 | if err := create(ctx, tx, model.SettingEnums.SecureID, po.SecureID); err != nil { 99 | return err 100 | } 101 | if err := create(ctx, tx, model.SettingEnums.SecureKey, po.SecureKey); err != nil { 102 | return err 103 | } 104 | if err := create(ctx, tx, model.SettingEnums.StoreBucket, po.StoreBucket); err != nil { 105 | return err 106 | } 107 | if err := create(ctx, tx, model.SettingEnums.InitPwd, po.InitPwd); err != nil { 108 | return err 109 | } 110 | return nil 111 | }) 112 | } 113 | 114 | func create(ctx context.Context, tx *ent.Tx, enum *model.Enum, value string) error { 115 | exist, err := tx.Setting.Query(). 116 | Where(entsetting.ConfigKey(enum.Code)). 117 | Exist(ctx) 118 | if err != nil { 119 | return err 120 | } 121 | if !exist { 122 | if err = tx.Setting.Create(). 123 | SetCreateTime(time.Now()). 124 | SetUpdateTime(time.Now()). 125 | SetConfigKey(enum.Code). 126 | SetConfigValue(value). 127 | SetMark(enum.Name). 128 | SetOperateID(-1). 129 | SetOperateName("system"). 130 | Exec(ctx); err != nil { 131 | return err 132 | } 133 | } 134 | return nil 135 | } 136 | 137 | func Update(ctx context.Context, po *PO) error { 138 | return dao.WithTx(ctx, dao.EntClient, func(tx *ent.Tx) error { 139 | if err := tx.Setting.Update(). 140 | SetConfigValue(po.StoreName). 141 | SetOperateID(po.OperateID). 142 | SetOperateName(po.OperateName). 143 | SetUpdateTime(time.Now()). 144 | Where(entsetting.ConfigKey(model.SettingEnums.StoreName.Code)). 145 | Exec(ctx); err != nil { 146 | return err 147 | } 148 | if err := tx.Setting.Update(). 149 | SetConfigValue(po.StoreAddress). 150 | SetOperateID(po.OperateID). 151 | SetOperateName(po.OperateName). 152 | SetUpdateTime(time.Now()). 153 | Where(entsetting.ConfigKey(model.SettingEnums.StoreAddress.Code)). 154 | Exec(ctx); err != nil { 155 | return err 156 | } 157 | if err := tx.Setting.Update(). 158 | SetConfigValue(po.SecureID). 159 | SetOperateID(po.OperateID). 160 | SetOperateName(po.OperateName). 161 | SetUpdateTime(time.Now()). 162 | Where(entsetting.ConfigKey(model.SettingEnums.SecureID.Code)). 163 | Exec(ctx); err != nil { 164 | return err 165 | } 166 | if err := tx.Setting.Update(). 167 | SetConfigValue(po.SecureKey). 168 | SetOperateID(po.OperateID). 169 | SetOperateName(po.OperateName). 170 | SetUpdateTime(time.Now()). 171 | Where(entsetting.ConfigKey(model.SettingEnums.SecureKey.Code)). 172 | Exec(ctx); err != nil { 173 | return err 174 | } 175 | if err := tx.Setting.Update(). 176 | SetConfigValue(po.StoreBucket). 177 | SetOperateID(po.OperateID). 178 | SetOperateName(po.OperateName). 179 | SetUpdateTime(time.Now()). 180 | Where(entsetting.ConfigKey(model.SettingEnums.StoreBucket.Code)). 181 | Exec(ctx); err != nil { 182 | return err 183 | } 184 | if err := tx.Setting.Update(). 185 | SetConfigValue(po.InitPwd). 186 | SetOperateID(po.OperateID). 187 | SetOperateName(po.OperateName). 188 | SetUpdateTime(time.Now()). 189 | Where(entsetting.ConfigKey(model.SettingEnums.InitPwd.Code)). 190 | Exec(ctx); err != nil { 191 | return err 192 | } 193 | return nil 194 | }) 195 | } 196 | -------------------------------------------------------------------------------- /ent/account.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | import ( 6 | "ai-gallery/ent/account" 7 | "fmt" 8 | "strings" 9 | "time" 10 | 11 | "entgo.io/ent" 12 | "entgo.io/ent/dialect/sql" 13 | ) 14 | 15 | // Account is the model entity for the Account schema. 16 | type Account struct { 17 | config `json:"-"` 18 | // ID of the ent. 19 | ID int `json:"id,omitempty"` 20 | // 创建时间 21 | CreateTime time.Time `json:"create_time,omitempty"` 22 | // 更新时间 23 | UpdateTime time.Time `json:"update_time,omitempty"` 24 | // 删除时间 25 | DeleteTime *time.Time `json:"delete_time,omitempty"` 26 | // 用户名 27 | Username string `json:"username,omitempty"` 28 | // 密码 29 | Password string `json:"password,omitempty"` 30 | // 昵称 31 | Nickname string `json:"nickname,omitempty"` 32 | // 角色: ADMIN, USER 33 | Role string `json:"role,omitempty"` 34 | // 状态: 0 禁用, 1 可用 35 | Status int `json:"status,omitempty"` 36 | selectValues sql.SelectValues 37 | } 38 | 39 | // scanValues returns the types for scanning values from sql.Rows. 40 | func (*Account) scanValues(columns []string) ([]any, error) { 41 | values := make([]any, len(columns)) 42 | for i := range columns { 43 | switch columns[i] { 44 | case account.FieldID, account.FieldStatus: 45 | values[i] = new(sql.NullInt64) 46 | case account.FieldUsername, account.FieldPassword, account.FieldNickname, account.FieldRole: 47 | values[i] = new(sql.NullString) 48 | case account.FieldCreateTime, account.FieldUpdateTime, account.FieldDeleteTime: 49 | values[i] = new(sql.NullTime) 50 | default: 51 | values[i] = new(sql.UnknownType) 52 | } 53 | } 54 | return values, nil 55 | } 56 | 57 | // assignValues assigns the values that were returned from sql.Rows (after scanning) 58 | // to the Account fields. 59 | func (a *Account) assignValues(columns []string, values []any) error { 60 | if m, n := len(values), len(columns); m < n { 61 | return fmt.Errorf("mismatch number of scan values: %d != %d", m, n) 62 | } 63 | for i := range columns { 64 | switch columns[i] { 65 | case account.FieldID: 66 | value, ok := values[i].(*sql.NullInt64) 67 | if !ok { 68 | return fmt.Errorf("unexpected type %T for field id", value) 69 | } 70 | a.ID = int(value.Int64) 71 | case account.FieldCreateTime: 72 | if value, ok := values[i].(*sql.NullTime); !ok { 73 | return fmt.Errorf("unexpected type %T for field create_time", values[i]) 74 | } else if value.Valid { 75 | a.CreateTime = value.Time 76 | } 77 | case account.FieldUpdateTime: 78 | if value, ok := values[i].(*sql.NullTime); !ok { 79 | return fmt.Errorf("unexpected type %T for field update_time", values[i]) 80 | } else if value.Valid { 81 | a.UpdateTime = value.Time 82 | } 83 | case account.FieldDeleteTime: 84 | if value, ok := values[i].(*sql.NullTime); !ok { 85 | return fmt.Errorf("unexpected type %T for field delete_time", values[i]) 86 | } else if value.Valid { 87 | a.DeleteTime = new(time.Time) 88 | *a.DeleteTime = value.Time 89 | } 90 | case account.FieldUsername: 91 | if value, ok := values[i].(*sql.NullString); !ok { 92 | return fmt.Errorf("unexpected type %T for field username", values[i]) 93 | } else if value.Valid { 94 | a.Username = value.String 95 | } 96 | case account.FieldPassword: 97 | if value, ok := values[i].(*sql.NullString); !ok { 98 | return fmt.Errorf("unexpected type %T for field password", values[i]) 99 | } else if value.Valid { 100 | a.Password = value.String 101 | } 102 | case account.FieldNickname: 103 | if value, ok := values[i].(*sql.NullString); !ok { 104 | return fmt.Errorf("unexpected type %T for field nickname", values[i]) 105 | } else if value.Valid { 106 | a.Nickname = value.String 107 | } 108 | case account.FieldRole: 109 | if value, ok := values[i].(*sql.NullString); !ok { 110 | return fmt.Errorf("unexpected type %T for field role", values[i]) 111 | } else if value.Valid { 112 | a.Role = value.String 113 | } 114 | case account.FieldStatus: 115 | if value, ok := values[i].(*sql.NullInt64); !ok { 116 | return fmt.Errorf("unexpected type %T for field status", values[i]) 117 | } else if value.Valid { 118 | a.Status = int(value.Int64) 119 | } 120 | default: 121 | a.selectValues.Set(columns[i], values[i]) 122 | } 123 | } 124 | return nil 125 | } 126 | 127 | // Value returns the ent.Value that was dynamically selected and assigned to the Account. 128 | // This includes values selected through modifiers, order, etc. 129 | func (a *Account) Value(name string) (ent.Value, error) { 130 | return a.selectValues.Get(name) 131 | } 132 | 133 | // Update returns a builder for updating this Account. 134 | // Note that you need to call Account.Unwrap() before calling this method if this Account 135 | // was returned from a transaction, and the transaction was committed or rolled back. 136 | func (a *Account) Update() *AccountUpdateOne { 137 | return NewAccountClient(a.config).UpdateOne(a) 138 | } 139 | 140 | // Unwrap unwraps the Account entity that was returned from a transaction after it was closed, 141 | // so that all future queries will be executed through the driver which created the transaction. 142 | func (a *Account) Unwrap() *Account { 143 | _tx, ok := a.config.driver.(*txDriver) 144 | if !ok { 145 | panic("ent: Account is not a transactional entity") 146 | } 147 | a.config.driver = _tx.drv 148 | return a 149 | } 150 | 151 | // String implements the fmt.Stringer. 152 | func (a *Account) String() string { 153 | var builder strings.Builder 154 | builder.WriteString("Account(") 155 | builder.WriteString(fmt.Sprintf("id=%v, ", a.ID)) 156 | builder.WriteString("create_time=") 157 | builder.WriteString(a.CreateTime.Format(time.ANSIC)) 158 | builder.WriteString(", ") 159 | builder.WriteString("update_time=") 160 | builder.WriteString(a.UpdateTime.Format(time.ANSIC)) 161 | builder.WriteString(", ") 162 | if v := a.DeleteTime; v != nil { 163 | builder.WriteString("delete_time=") 164 | builder.WriteString(v.Format(time.ANSIC)) 165 | } 166 | builder.WriteString(", ") 167 | builder.WriteString("username=") 168 | builder.WriteString(a.Username) 169 | builder.WriteString(", ") 170 | builder.WriteString("password=") 171 | builder.WriteString(a.Password) 172 | builder.WriteString(", ") 173 | builder.WriteString("nickname=") 174 | builder.WriteString(a.Nickname) 175 | builder.WriteString(", ") 176 | builder.WriteString("role=") 177 | builder.WriteString(a.Role) 178 | builder.WriteString(", ") 179 | builder.WriteString("status=") 180 | builder.WriteString(fmt.Sprintf("%v", a.Status)) 181 | builder.WriteByte(')') 182 | return builder.String() 183 | } 184 | 185 | // Accounts is a parsable slice of Account. 186 | type Accounts []*Account 187 | -------------------------------------------------------------------------------- /ent/setting.go: -------------------------------------------------------------------------------- 1 | // Code generated by ent, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | import ( 6 | "ai-gallery/ent/setting" 7 | "fmt" 8 | "strings" 9 | "time" 10 | 11 | "entgo.io/ent" 12 | "entgo.io/ent/dialect/sql" 13 | ) 14 | 15 | // Setting is the model entity for the Setting schema. 16 | type Setting struct { 17 | config `json:"-"` 18 | // ID of the ent. 19 | ID int `json:"id,omitempty"` 20 | // 创建时间 21 | CreateTime time.Time `json:"create_time,omitempty"` 22 | // 更新时间 23 | UpdateTime time.Time `json:"update_time,omitempty"` 24 | // 删除时间 25 | DeleteTime *time.Time `json:"delete_time,omitempty"` 26 | // 配置名 27 | ConfigKey string `json:"config_key,omitempty"` 28 | // 配置值 29 | ConfigValue string `json:"config_value,omitempty"` 30 | // 说明 31 | Mark string `json:"mark,omitempty"` 32 | // 操作人ID 33 | OperateID int `json:"operate_id,omitempty"` 34 | // 操作人名称 35 | OperateName string `json:"operate_name,omitempty"` 36 | selectValues sql.SelectValues 37 | } 38 | 39 | // scanValues returns the types for scanning values from sql.Rows. 40 | func (*Setting) scanValues(columns []string) ([]any, error) { 41 | values := make([]any, len(columns)) 42 | for i := range columns { 43 | switch columns[i] { 44 | case setting.FieldID, setting.FieldOperateID: 45 | values[i] = new(sql.NullInt64) 46 | case setting.FieldConfigKey, setting.FieldConfigValue, setting.FieldMark, setting.FieldOperateName: 47 | values[i] = new(sql.NullString) 48 | case setting.FieldCreateTime, setting.FieldUpdateTime, setting.FieldDeleteTime: 49 | values[i] = new(sql.NullTime) 50 | default: 51 | values[i] = new(sql.UnknownType) 52 | } 53 | } 54 | return values, nil 55 | } 56 | 57 | // assignValues assigns the values that were returned from sql.Rows (after scanning) 58 | // to the Setting fields. 59 | func (s *Setting) assignValues(columns []string, values []any) error { 60 | if m, n := len(values), len(columns); m < n { 61 | return fmt.Errorf("mismatch number of scan values: %d != %d", m, n) 62 | } 63 | for i := range columns { 64 | switch columns[i] { 65 | case setting.FieldID: 66 | value, ok := values[i].(*sql.NullInt64) 67 | if !ok { 68 | return fmt.Errorf("unexpected type %T for field id", value) 69 | } 70 | s.ID = int(value.Int64) 71 | case setting.FieldCreateTime: 72 | if value, ok := values[i].(*sql.NullTime); !ok { 73 | return fmt.Errorf("unexpected type %T for field create_time", values[i]) 74 | } else if value.Valid { 75 | s.CreateTime = value.Time 76 | } 77 | case setting.FieldUpdateTime: 78 | if value, ok := values[i].(*sql.NullTime); !ok { 79 | return fmt.Errorf("unexpected type %T for field update_time", values[i]) 80 | } else if value.Valid { 81 | s.UpdateTime = value.Time 82 | } 83 | case setting.FieldDeleteTime: 84 | if value, ok := values[i].(*sql.NullTime); !ok { 85 | return fmt.Errorf("unexpected type %T for field delete_time", values[i]) 86 | } else if value.Valid { 87 | s.DeleteTime = new(time.Time) 88 | *s.DeleteTime = value.Time 89 | } 90 | case setting.FieldConfigKey: 91 | if value, ok := values[i].(*sql.NullString); !ok { 92 | return fmt.Errorf("unexpected type %T for field config_key", values[i]) 93 | } else if value.Valid { 94 | s.ConfigKey = value.String 95 | } 96 | case setting.FieldConfigValue: 97 | if value, ok := values[i].(*sql.NullString); !ok { 98 | return fmt.Errorf("unexpected type %T for field config_value", values[i]) 99 | } else if value.Valid { 100 | s.ConfigValue = value.String 101 | } 102 | case setting.FieldMark: 103 | if value, ok := values[i].(*sql.NullString); !ok { 104 | return fmt.Errorf("unexpected type %T for field mark", values[i]) 105 | } else if value.Valid { 106 | s.Mark = value.String 107 | } 108 | case setting.FieldOperateID: 109 | if value, ok := values[i].(*sql.NullInt64); !ok { 110 | return fmt.Errorf("unexpected type %T for field operate_id", values[i]) 111 | } else if value.Valid { 112 | s.OperateID = int(value.Int64) 113 | } 114 | case setting.FieldOperateName: 115 | if value, ok := values[i].(*sql.NullString); !ok { 116 | return fmt.Errorf("unexpected type %T for field operate_name", values[i]) 117 | } else if value.Valid { 118 | s.OperateName = value.String 119 | } 120 | default: 121 | s.selectValues.Set(columns[i], values[i]) 122 | } 123 | } 124 | return nil 125 | } 126 | 127 | // Value returns the ent.Value that was dynamically selected and assigned to the Setting. 128 | // This includes values selected through modifiers, order, etc. 129 | func (s *Setting) Value(name string) (ent.Value, error) { 130 | return s.selectValues.Get(name) 131 | } 132 | 133 | // Update returns a builder for updating this Setting. 134 | // Note that you need to call Setting.Unwrap() before calling this method if this Setting 135 | // was returned from a transaction, and the transaction was committed or rolled back. 136 | func (s *Setting) Update() *SettingUpdateOne { 137 | return NewSettingClient(s.config).UpdateOne(s) 138 | } 139 | 140 | // Unwrap unwraps the Setting entity that was returned from a transaction after it was closed, 141 | // so that all future queries will be executed through the driver which created the transaction. 142 | func (s *Setting) Unwrap() *Setting { 143 | _tx, ok := s.config.driver.(*txDriver) 144 | if !ok { 145 | panic("ent: Setting is not a transactional entity") 146 | } 147 | s.config.driver = _tx.drv 148 | return s 149 | } 150 | 151 | // String implements the fmt.Stringer. 152 | func (s *Setting) String() string { 153 | var builder strings.Builder 154 | builder.WriteString("Setting(") 155 | builder.WriteString(fmt.Sprintf("id=%v, ", s.ID)) 156 | builder.WriteString("create_time=") 157 | builder.WriteString(s.CreateTime.Format(time.ANSIC)) 158 | builder.WriteString(", ") 159 | builder.WriteString("update_time=") 160 | builder.WriteString(s.UpdateTime.Format(time.ANSIC)) 161 | builder.WriteString(", ") 162 | if v := s.DeleteTime; v != nil { 163 | builder.WriteString("delete_time=") 164 | builder.WriteString(v.Format(time.ANSIC)) 165 | } 166 | builder.WriteString(", ") 167 | builder.WriteString("config_key=") 168 | builder.WriteString(s.ConfigKey) 169 | builder.WriteString(", ") 170 | builder.WriteString("config_value=") 171 | builder.WriteString(s.ConfigValue) 172 | builder.WriteString(", ") 173 | builder.WriteString("mark=") 174 | builder.WriteString(s.Mark) 175 | builder.WriteString(", ") 176 | builder.WriteString("operate_id=") 177 | builder.WriteString(fmt.Sprintf("%v", s.OperateID)) 178 | builder.WriteString(", ") 179 | builder.WriteString("operate_name=") 180 | builder.WriteString(s.OperateName) 181 | builder.WriteByte(')') 182 | return builder.String() 183 | } 184 | 185 | // Settings is a parsable slice of Setting. 186 | type Settings []*Setting 187 | --------------------------------------------------------------------------------