├── 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 | | wechat |
152 |
153 |
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 |
--------------------------------------------------------------------------------