mirror of
https://github.com/yangjian102621/geekai.git
synced 2025-09-18 01:06:39 +08:00
Merge branch 'main' into feat-ollama
This commit is contained in:
commit
51b83722e7
12
CHANGELOG.md
12
CHANGELOG.md
@ -1,5 +1,16 @@
|
|||||||
# 更新日志
|
# 更新日志
|
||||||
|
|
||||||
|
## v4.0.6
|
||||||
|
|
||||||
|
* Bug修复:修复PC端画廊页面的瀑布流组件样式错乱问题
|
||||||
|
* 功能新增:给思维导图增加 ToolBar,实现思维导图的放大缩小和定位
|
||||||
|
* Bug修复:修复思维导图不扣费的Bug
|
||||||
|
* Bug修复:修复管理后台角色删除失败的Bug
|
||||||
|
* Bug修复:兼容最新版秋叶SD懒人包的 SD API,新增 scheduler 参数
|
||||||
|
* 功能优化:支持在管理后台配置 AI 绘图相关配置,包括 SD, MJ-PLUS, MJ-PROXY
|
||||||
|
* Bug修复:修复注册用户提示注册人数达到上限的 Bug
|
||||||
|
* 功能优化:将MJ,SD,Dall绘画页面的任务列表全改成瀑布流组件
|
||||||
|
|
||||||
## v4.0.5
|
## v4.0.5
|
||||||
|
|
||||||
* 功能优化:已授权系统在后台显示授权信息
|
* 功能优化:已授权系统在后台显示授权信息
|
||||||
@ -38,6 +49,7 @@
|
|||||||
* 功能新增:支持管理后台 Logo 修改
|
* 功能新增:支持管理后台 Logo 修改
|
||||||
|
|
||||||
## 4.0.2
|
## 4.0.2
|
||||||
|
|
||||||
* 功能新增:支持前端菜单可以配置
|
* 功能新增:支持前端菜单可以配置
|
||||||
* 功能优化:在登录和注册界面标题显示软件版本号
|
* 功能优化:在登录和注册界面标题显示软件版本号
|
||||||
* 功能优化:MJ 绘画支持 --sref 和 --cref 图片一致性参数
|
* 功能优化:MJ 绘画支持 --sref 和 --cref 图片一致性参数
|
||||||
|
@ -176,4 +176,6 @@ type SystemConfig struct {
|
|||||||
|
|
||||||
EnableContext bool `json:"enable_context,omitempty"`
|
EnableContext bool `json:"enable_context,omitempty"`
|
||||||
ContextDeep int `json:"context_deep,omitempty"`
|
ContextDeep int `json:"context_deep,omitempty"`
|
||||||
|
|
||||||
|
SdNegPrompt string `json:"sd_neg_prompt"` // SD 默认反向提示词
|
||||||
}
|
}
|
||||||
|
@ -55,6 +55,7 @@ type SdTaskParams struct {
|
|||||||
NegPrompt string `json:"neg_prompt"` // 反向提示词
|
NegPrompt string `json:"neg_prompt"` // 反向提示词
|
||||||
Steps int `json:"steps"` // 迭代步数,默认20
|
Steps int `json:"steps"` // 迭代步数,默认20
|
||||||
Sampler string `json:"sampler"` // 采样器
|
Sampler string `json:"sampler"` // 采样器
|
||||||
|
Scheduler string `json:"scheduler"`
|
||||||
FaceFix bool `json:"face_fix"` // 面部修复
|
FaceFix bool `json:"face_fix"` // 面部修复
|
||||||
CfgScale float32 `json:"cfg_scale"` //引导系数,默认 7
|
CfgScale float32 `json:"cfg_scale"` //引导系数,默认 7
|
||||||
Seed int64 `json:"seed"` // 随机数种子
|
Seed int64 `json:"seed"` // 随机数种子
|
||||||
|
@ -15,6 +15,7 @@ import (
|
|||||||
"geekai/store/vo"
|
"geekai/store/vo"
|
||||||
"geekai/utils"
|
"geekai/utils"
|
||||||
"geekai/utils/resp"
|
"geekai/utils/resp"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
@ -144,18 +144,13 @@ func (h *ChatRoleHandler) Set(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *ChatRoleHandler) Remove(c *gin.Context) {
|
func (h *ChatRoleHandler) Remove(c *gin.Context) {
|
||||||
var data struct {
|
id := h.GetInt(c, "id", 0)
|
||||||
Id uint
|
|
||||||
}
|
if id <= 0 {
|
||||||
if err := c.ShouldBindJSON(&data); err != nil {
|
|
||||||
resp.ERROR(c, types.InvalidArgs)
|
resp.ERROR(c, types.InvalidArgs)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if data.Id <= 0 {
|
res := h.DB.Where("id", id).Delete(&model.ChatRole{})
|
||||||
resp.ERROR(c, types.InvalidArgs)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
res := h.DB.Where("id = ?", data.Id).Delete(&model.ChatRole{})
|
|
||||||
if res.Error != nil {
|
if res.Error != nil {
|
||||||
resp.ERROR(c, "删除失败!")
|
resp.ERROR(c, "删除失败!")
|
||||||
return
|
return
|
||||||
|
@ -13,6 +13,7 @@ import (
|
|||||||
"geekai/store/vo"
|
"geekai/store/vo"
|
||||||
"geekai/utils"
|
"geekai/utils"
|
||||||
"geekai/utils/resp"
|
"geekai/utils/resp"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
@ -32,7 +33,7 @@ func (h *ChatModelHandler) List(c *gin.Context) {
|
|||||||
var res *gorm.DB
|
var res *gorm.DB
|
||||||
// 如果用户没有登录,则加载所有开放模型
|
// 如果用户没有登录,则加载所有开放模型
|
||||||
if !h.IsLogin(c) {
|
if !h.IsLogin(c) {
|
||||||
res = h.DB.Where("enabled = ?", true).Where("open =?", true).Order("sort_num ASC").Find(&items)
|
res = h.DB.Where("enabled", true).Where("open", true).Order("sort_num ASC").Find(&items)
|
||||||
} else {
|
} else {
|
||||||
user, _ := h.GetLoginUser(c)
|
user, _ := h.GetLoginUser(c)
|
||||||
var models []int
|
var models []int
|
||||||
@ -43,7 +44,7 @@ func (h *ChatModelHandler) List(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
// 查询用户有权限访问的模型以及所有开放的模型
|
// 查询用户有权限访问的模型以及所有开放的模型
|
||||||
res = h.DB.Where("enabled = ?", true).Where(
|
res = h.DB.Where("enabled = ?", true).Where(
|
||||||
h.DB.Where("id IN ?", models).Or("open =?", true),
|
h.DB.Where("id IN ?", models).Or("open", true),
|
||||||
).Order("sort_num ASC").Find(&items)
|
).Order("sort_num ASC").Find(&items)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,13 +9,14 @@ package chatimpl
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
"geekai/core/types"
|
"geekai/core/types"
|
||||||
"geekai/store/model"
|
"geekai/store/model"
|
||||||
"geekai/store/vo"
|
"geekai/store/vo"
|
||||||
"geekai/utils"
|
"geekai/utils"
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"html/template"
|
"html/template"
|
||||||
"io"
|
"io"
|
||||||
"strings"
|
"strings"
|
||||||
@ -44,14 +45,9 @@ func (h *ChatHandler) sendAzureMessage(
|
|||||||
logger.Info("用户取消了请求:", prompt)
|
logger.Info("用户取消了请求:", prompt)
|
||||||
return nil
|
return nil
|
||||||
} else if strings.Contains(err.Error(), "no available key") {
|
} else if strings.Contains(err.Error(), "no available key") {
|
||||||
utils.ReplyMessage(ws, "抱歉😔😔😔,系统已经没有可用的 API KEY,请联系管理员!")
|
return errors.New("抱歉😔😔😔,系统已经没有可用的 API KEY,请联系管理员!")
|
||||||
return nil
|
|
||||||
} else {
|
|
||||||
logger.Error(err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
utils.ReplyMessage(ws, ErrorMsg)
|
|
||||||
utils.ReplyMessage(ws, ErrImg)
|
|
||||||
return err
|
return err
|
||||||
} else {
|
} else {
|
||||||
defer response.Body.Close()
|
defer response.Body.Close()
|
||||||
@ -73,10 +69,7 @@ func (h *ChatHandler) sendAzureMessage(
|
|||||||
var responseBody = types.ApiResponse{}
|
var responseBody = types.ApiResponse{}
|
||||||
err = json.Unmarshal([]byte(line[6:]), &responseBody)
|
err = json.Unmarshal([]byte(line[6:]), &responseBody)
|
||||||
if err != nil { // 数据解析出错
|
if err != nil { // 数据解析出错
|
||||||
logger.Error(err, line)
|
return errors.New(line)
|
||||||
utils.ReplyMessage(ws, ErrorMsg)
|
|
||||||
utils.ReplyMessage(ws, ErrImg)
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(responseBody.Choices) == 0 {
|
if len(responseBody.Choices) == 0 {
|
||||||
@ -203,11 +196,10 @@ func (h *ChatHandler) sendAzureMessage(
|
|||||||
|
|
||||||
if strings.Contains(res.Error.Message, "maximum context length") {
|
if strings.Contains(res.Error.Message, "maximum context length") {
|
||||||
logger.Error(res.Error.Message)
|
logger.Error(res.Error.Message)
|
||||||
utils.ReplyMessage(ws, "当前会话上下文长度超出限制,已为您清空会话上下文!")
|
|
||||||
h.App.ChatContexts.Delete(session.ChatId)
|
h.App.ChatContexts.Delete(session.ChatId)
|
||||||
return h.sendMessage(ctx, session, role, prompt, ws)
|
return h.sendMessage(ctx, session, role, prompt, ws)
|
||||||
} else {
|
} else {
|
||||||
utils.ReplyMessage(ws, "请求 Azure API 失败:"+res.Error.Message)
|
return fmt.Errorf("请求 Azure API 失败:%v", res.Error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,13 +9,14 @@ package chatimpl
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
"geekai/core/types"
|
"geekai/core/types"
|
||||||
"geekai/store/model"
|
"geekai/store/model"
|
||||||
"geekai/store/vo"
|
"geekai/store/vo"
|
||||||
"geekai/utils"
|
"geekai/utils"
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"html/template"
|
"html/template"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -61,14 +62,8 @@ func (h *ChatHandler) sendBaiduMessage(
|
|||||||
logger.Info("用户取消了请求:", prompt)
|
logger.Info("用户取消了请求:", prompt)
|
||||||
return nil
|
return nil
|
||||||
} else if strings.Contains(err.Error(), "no available key") {
|
} else if strings.Contains(err.Error(), "no available key") {
|
||||||
utils.ReplyMessage(ws, "抱歉😔😔😔,系统已经没有可用的 API KEY,请联系管理员!")
|
return errors.New("抱歉😔😔😔,系统已经没有可用的 API KEY,请联系管理员!")
|
||||||
return nil
|
|
||||||
} else {
|
|
||||||
logger.Error(err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
utils.ReplyMessage(ws, ErrorMsg)
|
|
||||||
utils.ReplyMessage(ws, ErrImg)
|
|
||||||
return err
|
return err
|
||||||
} else {
|
} else {
|
||||||
defer response.Body.Close()
|
defer response.Body.Close()
|
||||||
|
@ -173,7 +173,7 @@ func (h *ChatHandler) ChatHandle(c *gin.Context) {
|
|||||||
err = h.sendMessage(ctx, session, chatRole, utils.InterfaceToString(message.Content), client)
|
err = h.sendMessage(ctx, session, chatRole, utils.InterfaceToString(message.Content), client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err)
|
logger.Error(err)
|
||||||
utils.ReplyChunkMessage(client, types.WsMessage{Type: types.WsEnd})
|
utils.ReplyMessage(client, err.Error())
|
||||||
} else {
|
} else {
|
||||||
utils.ReplyChunkMessage(client, types.WsMessage{Type: types.WsEnd})
|
utils.ReplyChunkMessage(client, types.WsMessage{Type: types.WsEnd})
|
||||||
logger.Infof("回答完毕: %v", message.Content)
|
logger.Infof("回答完毕: %v", message.Content)
|
||||||
@ -195,8 +195,7 @@ func (h *ChatHandler) sendMessage(ctx context.Context, session *types.ChatSessio
|
|||||||
var user model.User
|
var user model.User
|
||||||
res := h.DB.Model(&model.User{}).First(&user, session.UserId)
|
res := h.DB.Model(&model.User{}).First(&user, session.UserId)
|
||||||
if res.Error != nil {
|
if res.Error != nil {
|
||||||
utils.ReplyMessage(ws, "未授权用户,您正在进行非法操作!")
|
return errors.New("未授权用户,您正在进行非法操作!")
|
||||||
return res.Error
|
|
||||||
}
|
}
|
||||||
var userVo vo.User
|
var userVo vo.User
|
||||||
err := utils.CopyObject(user, &userVo)
|
err := utils.CopyObject(user, &userVo)
|
||||||
@ -206,28 +205,22 @@ func (h *ChatHandler) sendMessage(ctx context.Context, session *types.ChatSessio
|
|||||||
}
|
}
|
||||||
|
|
||||||
if userVo.Status == false {
|
if userVo.Status == false {
|
||||||
utils.ReplyMessage(ws, "您的账号已经被禁用,如果疑问,请联系管理员!")
|
return errors.New("您的账号已经被禁用,如果疑问,请联系管理员!")
|
||||||
utils.ReplyMessage(ws, ErrImg)
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if userVo.Power < session.Model.Power {
|
if userVo.Power < session.Model.Power {
|
||||||
utils.ReplyMessage(ws, fmt.Sprintf("您当前剩余算力(%d)已不足以支付当前模型的单次对话需要消耗的算力(%d)!", userVo.Power, session.Model.Power))
|
return fmt.Errorf("您当前剩余算力(%d)已不足以支付当前模型的单次对话需要消耗的算力(%d)!", userVo.Power, session.Model.Power)
|
||||||
utils.ReplyMessage(ws, ErrImg)
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if userVo.ExpiredTime > 0 && userVo.ExpiredTime <= time.Now().Unix() {
|
if userVo.ExpiredTime > 0 && userVo.ExpiredTime <= time.Now().Unix() {
|
||||||
utils.ReplyMessage(ws, "您的账号已经过期,请联系管理员!")
|
return errors.New("您的账号已经过期,请联系管理员!")
|
||||||
utils.ReplyMessage(ws, ErrImg)
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查 prompt 长度是否超过了当前模型允许的最大上下文长度
|
// 检查 prompt 长度是否超过了当前模型允许的最大上下文长度
|
||||||
promptTokens, err := utils.CalcTokens(prompt, session.Model.Value)
|
promptTokens, err := utils.CalcTokens(prompt, session.Model.Value)
|
||||||
if promptTokens > session.Model.MaxContext {
|
if promptTokens > session.Model.MaxContext {
|
||||||
utils.ReplyMessage(ws, "对话内容超出了当前模型允许的最大上下文长度!")
|
|
||||||
return nil
|
return errors.New("对话内容超出了当前模型允许的最大上下文长度!")
|
||||||
}
|
}
|
||||||
|
|
||||||
var req = types.ApiRequest{
|
var req = types.ApiRequest{
|
||||||
@ -286,9 +279,7 @@ func (h *ChatHandler) sendMessage(ctx context.Context, session *types.ChatSessio
|
|||||||
break
|
break
|
||||||
|
|
||||||
default:
|
default:
|
||||||
utils.ReplyMessage(ws, "不支持的平台:"+session.Model.Platform+",请联系管理员!")
|
return fmt.Errorf("不支持的平台:%s", session.Model.Platform)
|
||||||
utils.ReplyMessage(ws, ErrImg)
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 加载聊天上下文
|
// 加载聊天上下文
|
||||||
@ -404,10 +395,7 @@ func (h *ChatHandler) sendMessage(ctx context.Context, session *types.ChatSessio
|
|||||||
case types.Ollama:
|
case types.Ollama:
|
||||||
return h.sendOllamaMessage(chatCtx, req, userVo, ctx, session, role, prompt, ws)
|
return h.sendOllamaMessage(chatCtx, req, userVo, ctx, session, role, prompt, ws)
|
||||||
}
|
}
|
||||||
utils.ReplyChunkMessage(ws, types.WsMessage{
|
|
||||||
Type: types.WsMiddle,
|
|
||||||
Content: fmt.Sprintf("Not supported platform: %s", session.Model.Platform),
|
|
||||||
})
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,13 +9,14 @@ package chatimpl
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
"geekai/core/types"
|
"geekai/core/types"
|
||||||
"geekai/store/model"
|
"geekai/store/model"
|
||||||
"geekai/store/vo"
|
"geekai/store/vo"
|
||||||
"geekai/utils"
|
"geekai/utils"
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"github.com/golang-jwt/jwt/v5"
|
"github.com/golang-jwt/jwt/v5"
|
||||||
"html/template"
|
"html/template"
|
||||||
"io"
|
"io"
|
||||||
@ -45,14 +46,8 @@ func (h *ChatHandler) sendChatGLMMessage(
|
|||||||
logger.Info("用户取消了请求:", prompt)
|
logger.Info("用户取消了请求:", prompt)
|
||||||
return nil
|
return nil
|
||||||
} else if strings.Contains(err.Error(), "no available key") {
|
} else if strings.Contains(err.Error(), "no available key") {
|
||||||
utils.ReplyMessage(ws, "抱歉😔😔😔,系统已经没有可用的 API KEY,请联系管理员!")
|
return errors.New("抱歉😔😔😔,系统已经没有可用的 API KEY,请联系管理员!")
|
||||||
return nil
|
|
||||||
} else {
|
|
||||||
logger.Error(err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
utils.ReplyMessage(ws, ErrorMsg)
|
|
||||||
utils.ReplyMessage(ws, ErrImg)
|
|
||||||
return err
|
return err
|
||||||
} else {
|
} else {
|
||||||
defer response.Body.Close()
|
defer response.Body.Close()
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
"bufio"
|
"bufio"
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"geekai/core/types"
|
"geekai/core/types"
|
||||||
"geekai/store/model"
|
"geekai/store/model"
|
||||||
@ -76,10 +77,7 @@ func (h *ChatHandler) sendOpenAiMessage(
|
|||||||
var responseBody = types.ApiResponse{}
|
var responseBody = types.ApiResponse{}
|
||||||
err = json.Unmarshal([]byte(line[6:]), &responseBody)
|
err = json.Unmarshal([]byte(line[6:]), &responseBody)
|
||||||
if err != nil { // 数据解析出错
|
if err != nil { // 数据解析出错
|
||||||
logger.Error(err, line)
|
return errors.New(line)
|
||||||
utils.ReplyMessage(ws, ErrorMsg)
|
|
||||||
utils.ReplyMessage(ws, ErrImg)
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
if len(responseBody.Choices) == 0 { // Fixed: 兼容 Azure API 第一个输出空行
|
if len(responseBody.Choices) == 0 { // Fixed: 兼容 Azure API 第一个输出空行
|
||||||
continue
|
continue
|
||||||
|
@ -9,13 +9,14 @@ package chatimpl
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"geekai/core/types"
|
"geekai/core/types"
|
||||||
"geekai/store/model"
|
"geekai/store/model"
|
||||||
"geekai/store/vo"
|
"geekai/store/vo"
|
||||||
"geekai/utils"
|
"geekai/utils"
|
||||||
"context"
|
"github.com/syndtr/goleveldb/leveldb/errors"
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"html/template"
|
"html/template"
|
||||||
"io"
|
"io"
|
||||||
"strings"
|
"strings"
|
||||||
@ -59,14 +60,8 @@ func (h *ChatHandler) sendQWenMessage(
|
|||||||
logger.Info("用户取消了请求:", prompt)
|
logger.Info("用户取消了请求:", prompt)
|
||||||
return nil
|
return nil
|
||||||
} else if strings.Contains(err.Error(), "no available key") {
|
} else if strings.Contains(err.Error(), "no available key") {
|
||||||
utils.ReplyMessage(ws, "抱歉😔😔😔,系统已经没有可用的 API KEY,请联系管理员!")
|
return errors.New("抱歉😔😔😔,系统已经没有可用的 API KEY,请联系管理员!")
|
||||||
return nil
|
|
||||||
} else {
|
|
||||||
logger.Error(err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
utils.ReplyMessage(ws, ErrorMsg)
|
|
||||||
utils.ReplyMessage(ws, ErrImg)
|
|
||||||
return err
|
return err
|
||||||
} else {
|
} else {
|
||||||
defer response.Body.Close()
|
defer response.Body.Close()
|
||||||
|
@ -83,7 +83,7 @@ func (h *ChatHandler) sendXunFeiMessage(
|
|||||||
res = h.DB.Where("id", session.Model.KeyId).Where("enabled", true).Find(&apiKey)
|
res = h.DB.Where("id", session.Model.KeyId).Where("enabled", true).Find(&apiKey)
|
||||||
}
|
}
|
||||||
// use the last unused key
|
// use the last unused key
|
||||||
if res.Error != nil {
|
if apiKey.Id == 0 {
|
||||||
res = h.DB.Where("platform", session.Model.Platform).Where("type", "chat").Where("enabled", true).Order("last_used_at ASC").First(&apiKey)
|
res = h.DB.Where("platform", session.Model.Platform).Where("type", "chat").Where("enabled", true).Order("last_used_at ASC").First(&apiKey)
|
||||||
}
|
}
|
||||||
if res.Error != nil {
|
if res.Error != nil {
|
||||||
|
@ -92,8 +92,7 @@ func (h *DallJobHandler) preCheck(c *gin.Context) bool {
|
|||||||
resp.NotAuth(c)
|
resp.NotAuth(c)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if user.Power < h.App.SysConfig.DallPower {
|
||||||
if user.Power < h.App.SysConfig.SdPower {
|
|
||||||
resp.ERROR(c, "当前用户剩余算力不足以完成本次绘画!")
|
resp.ERROR(c, "当前用户剩余算力不足以完成本次绘画!")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -148,7 +148,6 @@ func (h *MarkMapHandler) sendMessage(client *types.WsClient, prompt string, mode
|
|||||||
contentType := response.Header.Get("Content-Type")
|
contentType := response.Header.Get("Content-Type")
|
||||||
if strings.Contains(contentType, "text/event-stream") {
|
if strings.Contains(contentType, "text/event-stream") {
|
||||||
// 循环读取 Chunk 消息
|
// 循环读取 Chunk 消息
|
||||||
var message = types.Message{}
|
|
||||||
scanner := bufio.NewScanner(response.Body)
|
scanner := bufio.NewScanner(response.Body)
|
||||||
var isNew = true
|
var isNew = true
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
@ -159,17 +158,18 @@ func (h *MarkMapHandler) sendMessage(client *types.WsClient, prompt string, mode
|
|||||||
|
|
||||||
var responseBody = types.ApiResponse{}
|
var responseBody = types.ApiResponse{}
|
||||||
err = json.Unmarshal([]byte(line[6:]), &responseBody)
|
err = json.Unmarshal([]byte(line[6:]), &responseBody)
|
||||||
if err != nil || len(responseBody.Choices) == 0 { // 数据解析出错
|
if err != nil { // 数据解析出错
|
||||||
return fmt.Errorf("error with decode data: %v", err)
|
return fmt.Errorf("error with decode data: %v", line)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 初始化 role
|
if len(responseBody.Choices) == 0 { // Fixed: 兼容 Azure API 第一个输出空行
|
||||||
if responseBody.Choices[0].Delta.Role != "" && message.Role == "" {
|
|
||||||
message.Role = responseBody.Choices[0].Delta.Role
|
|
||||||
continue
|
continue
|
||||||
} else if responseBody.Choices[0].FinishReason != "" {
|
}
|
||||||
break // 输出完成或者输出中断了
|
|
||||||
} else {
|
if responseBody.Choices[0].FinishReason == "stop" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
if isNew {
|
if isNew {
|
||||||
utils.ReplyChunkMessage(client, types.WsMessage{Type: types.WsStart})
|
utils.ReplyChunkMessage(client, types.WsMessage{Type: types.WsStart})
|
||||||
isNew = false
|
isNew = false
|
||||||
@ -178,7 +178,6 @@ func (h *MarkMapHandler) sendMessage(client *types.WsClient, prompt string, mode
|
|||||||
Type: types.WsMiddle,
|
Type: types.WsMiddle,
|
||||||
Content: utils.InterfaceToString(responseBody.Choices[0].Delta.Content),
|
Content: utils.InterfaceToString(responseBody.Choices[0].Delta.Content),
|
||||||
})
|
})
|
||||||
}
|
|
||||||
} // end for
|
} // end for
|
||||||
|
|
||||||
utils.ReplyChunkMessage(client, types.WsMessage{Type: types.WsEnd})
|
utils.ReplyChunkMessage(client, types.WsMessage{Type: types.WsEnd})
|
||||||
@ -206,6 +205,25 @@ func (h *MarkMapHandler) sendMessage(client *types.WsClient, prompt string, mode
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 扣减算力
|
||||||
|
res = h.DB.Model(&model.User{}).Where("id", userId).UpdateColumn("power", gorm.Expr("power - ?", chatModel.Power))
|
||||||
|
if res.Error == nil {
|
||||||
|
// 记录算力消费日志
|
||||||
|
var u model.User
|
||||||
|
h.DB.Where("id", userId).First(&u)
|
||||||
|
h.DB.Create(&model.PowerLog{
|
||||||
|
UserId: u.Id,
|
||||||
|
Username: u.Username,
|
||||||
|
Type: types.PowerConsume,
|
||||||
|
Amount: chatModel.Power,
|
||||||
|
Mark: types.PowerSub,
|
||||||
|
Balance: u.Power,
|
||||||
|
Model: chatModel.Value,
|
||||||
|
Remark: fmt.Sprintf("AI绘制思维导图,模型名称:%s, ", chatModel.Value),
|
||||||
|
CreatedAt: time.Now(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,7 +171,6 @@ func main() {
|
|||||||
|
|
||||||
// 邮件服务
|
// 邮件服务
|
||||||
fx.Provide(service.NewSmtpService),
|
fx.Provide(service.NewSmtpService),
|
||||||
// License 服务
|
|
||||||
|
|
||||||
// 微信机器人服务
|
// 微信机器人服务
|
||||||
fx.Provide(wx.NewWeChatBot),
|
fx.Provide(wx.NewWeChatBot),
|
||||||
@ -186,7 +185,8 @@ func main() {
|
|||||||
|
|
||||||
// MidJourney service pool
|
// MidJourney service pool
|
||||||
fx.Provide(mj.NewServicePool),
|
fx.Provide(mj.NewServicePool),
|
||||||
fx.Invoke(func(pool *mj.ServicePool) {
|
fx.Invoke(func(pool *mj.ServicePool, config *types.AppConfig) {
|
||||||
|
pool.InitServices(config.MjPlusConfigs, config.MjProxyConfigs)
|
||||||
if pool.HasAvailableService() {
|
if pool.HasAvailableService() {
|
||||||
pool.DownloadImages()
|
pool.DownloadImages()
|
||||||
pool.CheckTaskNotify()
|
pool.CheckTaskNotify()
|
||||||
@ -196,7 +196,8 @@ func main() {
|
|||||||
|
|
||||||
// Stable Diffusion 机器人
|
// Stable Diffusion 机器人
|
||||||
fx.Provide(sd.NewServicePool),
|
fx.Provide(sd.NewServicePool),
|
||||||
fx.Invoke(func(pool *sd.ServicePool) {
|
fx.Invoke(func(pool *sd.ServicePool, config *types.AppConfig) {
|
||||||
|
pool.InitServices(config.SdConfigs)
|
||||||
if pool.HasAvailableService() {
|
if pool.HasAvailableService() {
|
||||||
pool.CheckTaskNotify()
|
pool.CheckTaskNotify()
|
||||||
pool.CheckTaskStatus()
|
pool.CheckTaskStatus()
|
||||||
@ -329,7 +330,7 @@ func main() {
|
|||||||
group.POST("save", h.Save)
|
group.POST("save", h.Save)
|
||||||
group.POST("sort", h.Sort)
|
group.POST("sort", h.Sort)
|
||||||
group.POST("set", h.Set)
|
group.POST("set", h.Set)
|
||||||
group.POST("remove", h.Remove)
|
group.GET("remove", h.Remove)
|
||||||
}),
|
}),
|
||||||
fx.Invoke(func(s *core.AppServer, h *admin.RewardHandler) {
|
fx.Invoke(func(s *core.AppServer, h *admin.RewardHandler) {
|
||||||
group := s.Engine.Group("/api/admin/reward/")
|
group := s.Engine.Group("/api/admin/reward/")
|
||||||
|
@ -8,6 +8,8 @@ package dalle
|
|||||||
// * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
// * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
"geekai/core/types"
|
"geekai/core/types"
|
||||||
logger2 "geekai/logger"
|
logger2 "geekai/logger"
|
||||||
"geekai/service"
|
"geekai/service"
|
||||||
@ -16,8 +18,6 @@ import (
|
|||||||
"geekai/store"
|
"geekai/store"
|
||||||
"geekai/store/model"
|
"geekai/store/model"
|
||||||
"geekai/utils"
|
"geekai/utils"
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"github.com/go-redis/redis/v8"
|
"github.com/go-redis/redis/v8"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -261,7 +261,7 @@ func (s *Service) downloadImage(jobId uint, userId int, orgURL string) (string,
|
|||||||
if res.Error != nil {
|
if res.Error != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
s.notifyQueue.RPush(sd.NotifyMessage{UserId: userId, JobId: int(jobId), Message: sd.Failed})
|
s.notifyQueue.RPush(sd.NotifyMessage{UserId: userId, JobId: int(jobId), Message: sd.Finished})
|
||||||
return imgURL, nil
|
return imgURL, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ import (
|
|||||||
"geekai/store"
|
"geekai/store"
|
||||||
"geekai/store/model"
|
"geekai/store/model"
|
||||||
"github.com/go-redis/redis/v8"
|
"github.com/go-redis/redis/v8"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
@ -33,38 +34,10 @@ type ServicePool struct {
|
|||||||
|
|
||||||
var logger = logger2.GetLogger()
|
var logger = logger2.GetLogger()
|
||||||
|
|
||||||
func NewServicePool(db *gorm.DB, redisCli *redis.Client, manager *oss.UploaderManager, appConfig *types.AppConfig) *ServicePool {
|
func NewServicePool(db *gorm.DB, redisCli *redis.Client, manager *oss.UploaderManager) *ServicePool {
|
||||||
services := make([]*Service, 0)
|
services := make([]*Service, 0)
|
||||||
taskQueue := store.NewRedisQueue("MidJourney_Task_Queue", redisCli)
|
taskQueue := store.NewRedisQueue("MidJourney_Task_Queue", redisCli)
|
||||||
notifyQueue := store.NewRedisQueue("MidJourney_Notify_Queue", redisCli)
|
notifyQueue := store.NewRedisQueue("MidJourney_Notify_Queue", redisCli)
|
||||||
|
|
||||||
for k, config := range appConfig.MjPlusConfigs {
|
|
||||||
if config.Enabled == false {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
cli := NewPlusClient(config)
|
|
||||||
name := fmt.Sprintf("mj-plus-service-%d", k)
|
|
||||||
plusService := NewService(name, taskQueue, notifyQueue, db, cli)
|
|
||||||
go func() {
|
|
||||||
plusService.Run()
|
|
||||||
}()
|
|
||||||
services = append(services, plusService)
|
|
||||||
}
|
|
||||||
|
|
||||||
for k, config := range appConfig.MjProxyConfigs {
|
|
||||||
if config.Enabled == false {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
cli := NewProxyClient(config)
|
|
||||||
name := fmt.Sprintf("mj-proxy-service-%d", k)
|
|
||||||
proxyService := NewService(name, taskQueue, notifyQueue, db, cli)
|
|
||||||
go func() {
|
|
||||||
proxyService.Run()
|
|
||||||
}()
|
|
||||||
services = append(services, proxyService)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &ServicePool{
|
return &ServicePool{
|
||||||
taskQueue: taskQueue,
|
taskQueue: taskQueue,
|
||||||
notifyQueue: notifyQueue,
|
notifyQueue: notifyQueue,
|
||||||
@ -75,6 +48,42 @@ func NewServicePool(db *gorm.DB, redisCli *redis.Client, manager *oss.UploaderMa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *ServicePool) InitServices(plusConfigs []types.MjPlusConfig, proxyConfigs []types.MjProxyConfig) {
|
||||||
|
// stop old service
|
||||||
|
for _, s := range p.services {
|
||||||
|
s.Stop()
|
||||||
|
}
|
||||||
|
p.services = make([]*Service, 0)
|
||||||
|
|
||||||
|
for k, config := range plusConfigs {
|
||||||
|
if config.Enabled == false {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
cli := NewPlusClient(config)
|
||||||
|
name := fmt.Sprintf("mj-plus-service-%d", k)
|
||||||
|
plusService := NewService(name, p.taskQueue, p.notifyQueue, p.db, cli)
|
||||||
|
go func() {
|
||||||
|
plusService.Run()
|
||||||
|
}()
|
||||||
|
p.services = append(p.services, plusService)
|
||||||
|
}
|
||||||
|
|
||||||
|
// for mid-journey proxy
|
||||||
|
for k, config := range proxyConfigs {
|
||||||
|
if config.Enabled == false {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
cli := NewProxyClient(config)
|
||||||
|
name := fmt.Sprintf("mj-proxy-service-%d", k)
|
||||||
|
proxyService := NewService(name, p.taskQueue, p.notifyQueue, p.db, cli)
|
||||||
|
go func() {
|
||||||
|
proxyService.Run()
|
||||||
|
}()
|
||||||
|
p.services = append(p.services, proxyService)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (p *ServicePool) CheckTaskNotify() {
|
func (p *ServicePool) CheckTaskNotify() {
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
@ -111,17 +120,23 @@ func (p *ServicePool) DownloadImages() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
logger.Infof("try to download image: %s", v.OrgURL)
|
logger.Infof("try to download image: %s", v.OrgURL)
|
||||||
var imgURL string
|
mjService := p.getService(v.ChannelId)
|
||||||
var err error
|
if mjService == nil {
|
||||||
if servicePlus := p.getService(v.ChannelId); servicePlus != nil {
|
logger.Errorf("Invalid task: %+v", v)
|
||||||
task, _ := servicePlus.Client.QueryTask(v.TaskId)
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
task, _ := mjService.Client.QueryTask(v.TaskId)
|
||||||
if len(task.Buttons) > 0 {
|
if len(task.Buttons) > 0 {
|
||||||
v.Hash = GetImageHash(task.Buttons[0].CustomId)
|
v.Hash = GetImageHash(task.Buttons[0].CustomId)
|
||||||
}
|
}
|
||||||
imgURL, err = p.uploaderManager.GetUploadHandler().PutImg(v.OrgURL, false)
|
// 如果是返回的是 discord 图片地址,则使用代理下载
|
||||||
} else {
|
proxy := false
|
||||||
imgURL, err = p.uploaderManager.GetUploadHandler().PutImg(v.OrgURL, true)
|
if strings.HasPrefix(v.OrgURL, "https://cdn.discordapp.com") {
|
||||||
|
proxy = true
|
||||||
}
|
}
|
||||||
|
imgURL, err := p.uploaderManager.GetUploadHandler().PutImg(v.OrgURL, proxy)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Errorf("error with download image %s, %v", v.OrgURL, err)
|
logger.Errorf("error with download image %s, %v", v.OrgURL, err)
|
||||||
continue
|
continue
|
||||||
|
@ -28,6 +28,7 @@ type Service struct {
|
|||||||
taskQueue *store.RedisQueue
|
taskQueue *store.RedisQueue
|
||||||
notifyQueue *store.RedisQueue
|
notifyQueue *store.RedisQueue
|
||||||
db *gorm.DB
|
db *gorm.DB
|
||||||
|
running bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewService(name string, taskQueue *store.RedisQueue, notifyQueue *store.RedisQueue, db *gorm.DB, cli Client) *Service {
|
func NewService(name string, taskQueue *store.RedisQueue, notifyQueue *store.RedisQueue, db *gorm.DB, cli Client) *Service {
|
||||||
@ -37,12 +38,13 @@ func NewService(name string, taskQueue *store.RedisQueue, notifyQueue *store.Red
|
|||||||
taskQueue: taskQueue,
|
taskQueue: taskQueue,
|
||||||
notifyQueue: notifyQueue,
|
notifyQueue: notifyQueue,
|
||||||
Client: cli,
|
Client: cli,
|
||||||
|
running: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) Run() {
|
func (s *Service) Run() {
|
||||||
logger.Infof("Starting MidJourney job consumer for %s", s.Name)
|
logger.Infof("Starting MidJourney job consumer for %s", s.Name)
|
||||||
for {
|
for s.running {
|
||||||
var task types.MjTask
|
var task types.MjTask
|
||||||
err := s.taskQueue.LPop(&task)
|
err := s.taskQueue.LPop(&task)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -125,6 +127,10 @@ func (s *Service) Run() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Service) Stop() {
|
||||||
|
s.running = false
|
||||||
|
}
|
||||||
|
|
||||||
type CBReq struct {
|
type CBReq struct {
|
||||||
Id string `json:"id"`
|
Id string `json:"id"`
|
||||||
Action string `json:"action"`
|
Action string `json:"action"`
|
||||||
|
@ -25,28 +25,14 @@ type ServicePool struct {
|
|||||||
notifyQueue *store.RedisQueue
|
notifyQueue *store.RedisQueue
|
||||||
db *gorm.DB
|
db *gorm.DB
|
||||||
Clients *types.LMap[uint, *types.WsClient] // UserId => Client
|
Clients *types.LMap[uint, *types.WsClient] // UserId => Client
|
||||||
|
uploader *oss.UploaderManager
|
||||||
|
levelDB *store.LevelDB
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewServicePool(db *gorm.DB, redisCli *redis.Client, manager *oss.UploaderManager, appConfig *types.AppConfig, levelDB *store.LevelDB) *ServicePool {
|
func NewServicePool(db *gorm.DB, redisCli *redis.Client, manager *oss.UploaderManager, levelDB *store.LevelDB) *ServicePool {
|
||||||
services := make([]*Service, 0)
|
services := make([]*Service, 0)
|
||||||
taskQueue := store.NewRedisQueue("StableDiffusion_Task_Queue", redisCli)
|
taskQueue := store.NewRedisQueue("StableDiffusion_Task_Queue", redisCli)
|
||||||
notifyQueue := store.NewRedisQueue("StableDiffusion_Queue", redisCli)
|
notifyQueue := store.NewRedisQueue("StableDiffusion_Queue", redisCli)
|
||||||
// create mj client and service
|
|
||||||
for _, config := range appConfig.SdConfigs {
|
|
||||||
if config.Enabled == false {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// create sd service
|
|
||||||
name := fmt.Sprintf("StableDifffusion Service-%s", config.Model)
|
|
||||||
service := NewService(name, config, taskQueue, notifyQueue, db, manager, levelDB)
|
|
||||||
// run sd service
|
|
||||||
go func() {
|
|
||||||
service.Run()
|
|
||||||
}()
|
|
||||||
|
|
||||||
services = append(services, service)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &ServicePool{
|
return &ServicePool{
|
||||||
taskQueue: taskQueue,
|
taskQueue: taskQueue,
|
||||||
@ -54,6 +40,32 @@ func NewServicePool(db *gorm.DB, redisCli *redis.Client, manager *oss.UploaderMa
|
|||||||
services: services,
|
services: services,
|
||||||
db: db,
|
db: db,
|
||||||
Clients: types.NewLMap[uint, *types.WsClient](),
|
Clients: types.NewLMap[uint, *types.WsClient](),
|
||||||
|
uploader: manager,
|
||||||
|
levelDB: levelDB,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ServicePool) InitServices(configs []types.StableDiffusionConfig) {
|
||||||
|
// stop old service
|
||||||
|
for _, s := range p.services {
|
||||||
|
s.Stop()
|
||||||
|
}
|
||||||
|
p.services = make([]*Service, 0)
|
||||||
|
|
||||||
|
for k, config := range configs {
|
||||||
|
if config.Enabled == false {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// create sd service
|
||||||
|
name := fmt.Sprintf(" sd-service-%d", k)
|
||||||
|
service := NewService(name, config, p.taskQueue, p.notifyQueue, p.db, p.uploader, p.levelDB)
|
||||||
|
// run sd service
|
||||||
|
go func() {
|
||||||
|
service.Run()
|
||||||
|
}()
|
||||||
|
|
||||||
|
p.services = append(p.services, service)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,6 +33,7 @@ type Service struct {
|
|||||||
uploadManager *oss.UploaderManager
|
uploadManager *oss.UploaderManager
|
||||||
name string // service name
|
name string // service name
|
||||||
leveldb *store.LevelDB
|
leveldb *store.LevelDB
|
||||||
|
running bool // 运行状态
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewService(name string, config types.StableDiffusionConfig, taskQueue *store.RedisQueue, notifyQueue *store.RedisQueue, db *gorm.DB, manager *oss.UploaderManager, levelDB *store.LevelDB) *Service {
|
func NewService(name string, config types.StableDiffusionConfig, taskQueue *store.RedisQueue, notifyQueue *store.RedisQueue, db *gorm.DB, manager *oss.UploaderManager, levelDB *store.LevelDB) *Service {
|
||||||
@ -46,11 +47,13 @@ func NewService(name string, config types.StableDiffusionConfig, taskQueue *stor
|
|||||||
db: db,
|
db: db,
|
||||||
leveldb: levelDB,
|
leveldb: levelDB,
|
||||||
uploadManager: manager,
|
uploadManager: manager,
|
||||||
|
running: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) Run() {
|
func (s *Service) Run() {
|
||||||
for {
|
logger.Infof("Starting Stable-Diffusion job consumer for %s", s.name)
|
||||||
|
for s.running {
|
||||||
var task types.SdTask
|
var task types.SdTask
|
||||||
err := s.taskQueue.LPop(&task)
|
err := s.taskQueue.LPop(&task)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -94,6 +97,10 @@ func (s *Service) Run() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Service) Stop() {
|
||||||
|
s.running = false
|
||||||
|
}
|
||||||
|
|
||||||
// Txt2ImgReq 文生图请求实体
|
// Txt2ImgReq 文生图请求实体
|
||||||
type Txt2ImgReq struct {
|
type Txt2ImgReq struct {
|
||||||
Prompt string `json:"prompt"`
|
Prompt string `json:"prompt"`
|
||||||
@ -104,6 +111,7 @@ type Txt2ImgReq struct {
|
|||||||
Width int `json:"width"`
|
Width int `json:"width"`
|
||||||
Height int `json:"height"`
|
Height int `json:"height"`
|
||||||
SamplerName string `json:"sampler_name"`
|
SamplerName string `json:"sampler_name"`
|
||||||
|
Scheduler string `json:"scheduler"`
|
||||||
EnableHr bool `json:"enable_hr,omitempty"`
|
EnableHr bool `json:"enable_hr,omitempty"`
|
||||||
HrScale int `json:"hr_scale,omitempty"`
|
HrScale int `json:"hr_scale,omitempty"`
|
||||||
HrUpscaler string `json:"hr_upscaler,omitempty"`
|
HrUpscaler string `json:"hr_upscaler,omitempty"`
|
||||||
@ -137,6 +145,7 @@ func (s *Service) Txt2Img(task types.SdTask) error {
|
|||||||
Width: task.Params.Width,
|
Width: task.Params.Width,
|
||||||
Height: task.Params.Height,
|
Height: task.Params.Height,
|
||||||
SamplerName: task.Params.Sampler,
|
SamplerName: task.Params.Sampler,
|
||||||
|
Scheduler: task.Params.Scheduler,
|
||||||
ForceTaskId: task.Params.TaskId,
|
ForceTaskId: task.Params.TaskId,
|
||||||
}
|
}
|
||||||
if task.Params.Seed > 0 {
|
if task.Params.Seed > 0 {
|
||||||
|
840
database/chatgpt_plus-v4.0.5.sql
Normal file
840
database/chatgpt_plus-v4.0.5.sql
Normal file
@ -0,0 +1,840 @@
|
|||||||
|
-- phpMyAdmin SQL Dump
|
||||||
|
-- version 5.1.3
|
||||||
|
-- https://www.phpmyadmin.net/
|
||||||
|
--
|
||||||
|
-- 主机: localhost:3306
|
||||||
|
-- 生成日期: 2024-04-23 18:39:13
|
||||||
|
-- 服务器版本: 8.0.33-0ubuntu0.22.04.2
|
||||||
|
-- PHP 版本: 8.1.18
|
||||||
|
|
||||||
|
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
|
||||||
|
START TRANSACTION;
|
||||||
|
SET time_zone = "+00:00";
|
||||||
|
|
||||||
|
|
||||||
|
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
|
||||||
|
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
|
||||||
|
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
|
||||||
|
/*!40101 SET NAMES utf8mb4 */;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 数据库: `chatgpt_plus`
|
||||||
|
--
|
||||||
|
CREATE DATABASE IF NOT EXISTS `chatgpt_plus` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
|
||||||
|
USE `chatgpt_plus`;
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的结构 `chatgpt_admin_users`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `chatgpt_admin_users`;
|
||||||
|
CREATE TABLE `chatgpt_admin_users` (
|
||||||
|
`id` int NOT NULL,
|
||||||
|
`username` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户名',
|
||||||
|
`password` char(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '密码',
|
||||||
|
`salt` char(12) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '密码盐',
|
||||||
|
`status` tinyint(1) NOT NULL COMMENT '当前状态',
|
||||||
|
`last_login_at` int NOT NULL COMMENT '最后登录时间',
|
||||||
|
`last_login_ip` char(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '最后登录 IP',
|
||||||
|
`created_at` datetime NOT NULL COMMENT '创建时间',
|
||||||
|
`updated_at` datetime NOT NULL COMMENT '更新时间'
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='系统用户' ROW_FORMAT=DYNAMIC;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 转存表中的数据 `chatgpt_admin_users`
|
||||||
|
--
|
||||||
|
|
||||||
|
INSERT INTO `chatgpt_admin_users` (`id`, `username`, `password`, `salt`, `status`, `last_login_at`, `last_login_ip`, `created_at`, `updated_at`) VALUES
|
||||||
|
(1, 'admin', '6d17e80c87d209efb84ca4b2e0824f549d09fac8b2e1cc698de5bb5e1d75dfd0', 'mmrql75o', 1, 1713842191, '::1', '2024-03-11 16:30:20', '2024-04-23 11:16:31');
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的结构 `chatgpt_api_keys`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `chatgpt_api_keys`;
|
||||||
|
CREATE TABLE `chatgpt_api_keys` (
|
||||||
|
`id` int NOT NULL,
|
||||||
|
`platform` char(20) DEFAULT NULL COMMENT '平台',
|
||||||
|
`name` varchar(30) DEFAULT NULL COMMENT '名称',
|
||||||
|
`value` varchar(100) NOT NULL COMMENT 'API KEY value',
|
||||||
|
`type` varchar(10) NOT NULL DEFAULT 'chat' COMMENT '用途(chat=>聊天,img=>图片)',
|
||||||
|
`last_used_at` int NOT NULL COMMENT '最后使用时间',
|
||||||
|
`api_url` varchar(255) DEFAULT NULL COMMENT 'API 地址',
|
||||||
|
`enabled` tinyint(1) DEFAULT NULL COMMENT '是否启用',
|
||||||
|
`proxy_url` varchar(100) DEFAULT NULL COMMENT '代理地址',
|
||||||
|
`created_at` datetime NOT NULL,
|
||||||
|
`updated_at` datetime NOT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='OpenAI API ';
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的结构 `chatgpt_chat_history`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `chatgpt_chat_history`;
|
||||||
|
CREATE TABLE `chatgpt_chat_history` (
|
||||||
|
`id` bigint NOT NULL,
|
||||||
|
`user_id` int NOT NULL COMMENT '用户 ID',
|
||||||
|
`chat_id` char(40) NOT NULL COMMENT '会话 ID',
|
||||||
|
`type` varchar(10) NOT NULL COMMENT '类型:prompt|reply',
|
||||||
|
`icon` varchar(100) NOT NULL COMMENT '角色图标',
|
||||||
|
`role_id` int NOT NULL COMMENT '角色 ID',
|
||||||
|
`model` varchar(30) DEFAULT NULL COMMENT '模型名称',
|
||||||
|
`content` text NOT NULL COMMENT '聊天内容',
|
||||||
|
`tokens` smallint NOT NULL COMMENT '耗费 token 数量',
|
||||||
|
`use_context` tinyint(1) NOT NULL COMMENT '是否允许作为上下文语料',
|
||||||
|
`created_at` datetime NOT NULL,
|
||||||
|
`updated_at` datetime NOT NULL,
|
||||||
|
`deleted_at` datetime DEFAULT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='聊天历史记录';
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的结构 `chatgpt_chat_items`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `chatgpt_chat_items`;
|
||||||
|
CREATE TABLE `chatgpt_chat_items` (
|
||||||
|
`id` int NOT NULL,
|
||||||
|
`chat_id` char(40) NOT NULL COMMENT '会话 ID',
|
||||||
|
`user_id` int NOT NULL COMMENT '用户 ID',
|
||||||
|
`role_id` int NOT NULL COMMENT '角色 ID',
|
||||||
|
`title` varchar(100) NOT NULL COMMENT '会话标题',
|
||||||
|
`model_id` int NOT NULL DEFAULT '0' COMMENT '模型 ID',
|
||||||
|
`model` varchar(30) DEFAULT NULL COMMENT '模型名称',
|
||||||
|
`created_at` datetime NOT NULL COMMENT '创建时间',
|
||||||
|
`updated_at` datetime NOT NULL COMMENT '更新时间',
|
||||||
|
`deleted_at` datetime DEFAULT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户会话列表';
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的结构 `chatgpt_chat_models`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `chatgpt_chat_models`;
|
||||||
|
CREATE TABLE `chatgpt_chat_models` (
|
||||||
|
`id` int NOT NULL,
|
||||||
|
`platform` varchar(20) DEFAULT NULL COMMENT '模型平台',
|
||||||
|
`name` varchar(50) NOT NULL COMMENT '模型名称',
|
||||||
|
`value` varchar(50) NOT NULL COMMENT '模型值',
|
||||||
|
`sort_num` tinyint(1) NOT NULL COMMENT '排序数字',
|
||||||
|
`enabled` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否启用模型',
|
||||||
|
`power` tinyint NOT NULL COMMENT '消耗算力点数',
|
||||||
|
`temperature` float(3,1) NOT NULL DEFAULT '1.0' COMMENT '模型创意度',
|
||||||
|
`max_tokens` int NOT NULL DEFAULT '1024' COMMENT '最大响应长度',
|
||||||
|
`max_context` int NOT NULL DEFAULT '4096' COMMENT '最大上下文长度',
|
||||||
|
`open` tinyint(1) NOT NULL COMMENT '是否开放模型',
|
||||||
|
`key_id` int NOT NULL COMMENT '绑定API KEY ID',
|
||||||
|
`created_at` datetime DEFAULT NULL,
|
||||||
|
`updated_at` datetime DEFAULT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='AI 模型表';
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 转存表中的数据 `chatgpt_chat_models`
|
||||||
|
--
|
||||||
|
|
||||||
|
INSERT INTO `chatgpt_chat_models` (`id`, `platform`, `name`, `value`, `sort_num`, `enabled`, `power`, `temperature`, `max_tokens`, `max_context`, `open`, `key_id`, `created_at`, `updated_at`) VALUES
|
||||||
|
(1, 'OpenAI', 'GPT-3.5', 'gpt-3.5-turbo-0125', 1, 1, 1, 1.0, 1024, 4096, 1, 0, '2023-08-23 12:06:36', '2024-04-23 16:24:15'),
|
||||||
|
(2, 'Azure', 'Azure-3.5', 'gpt-3.5-turbo', 21, 1, 1, 1.0, 1024, 4096, 0, 0, '2023-08-23 12:15:30', '2024-04-15 11:39:18'),
|
||||||
|
(3, 'ChatGLM', 'ChatGML-Pro', 'chatglm_pro', 10, 1, 1, 1.0, 2048, 32768, 1, 0, '2023-08-23 13:35:45', '2024-04-15 11:39:18'),
|
||||||
|
(7, 'Baidu', '文心一言3.0', 'eb-instant', 19, 1, 1, 1.0, 1024, 4096, 1, 0, '2023-10-11 11:29:28', '2024-04-15 11:39:18'),
|
||||||
|
(8, 'XunFei', '星火V3.5', 'generalv3.5', 9, 1, 5, 0.8, 1024, 8192, 1, 0, '2023-10-11 15:48:30', '2024-04-15 11:39:18'),
|
||||||
|
(9, 'XunFei', '星火V2.0', 'generalv2', 18, 1, 1, 1.0, 1024, 8192, 1, 0, '2023-10-11 15:48:45', '2024-04-15 11:39:18'),
|
||||||
|
(10, 'Baidu', '文心一言4.0', 'completions_pro', 20, 1, 3, 1.0, 1024, 8192, 1, 0, '2023-10-25 08:31:37', '2024-04-15 11:39:18'),
|
||||||
|
(11, 'OpenAI', 'GPT-4.0', 'gpt-4-0125-preview', 8, 1, 15, 1.0, 2048, 8192, 1, 0, '2023-10-25 08:45:15', '2024-04-17 11:54:57'),
|
||||||
|
(12, 'XunFei', '星火v3.0', 'generalv3', 17, 1, 3, 1.0, 1024, 8192, 1, 0, '2023-11-23 09:20:33', '2024-04-15 11:39:18'),
|
||||||
|
(15, 'OpenAI', 'GPT-超级模型', 'gpt-4-all', 11, 1, 30, 1.0, 4096, 32768, 0, 0, '2024-01-15 11:32:52', '2024-04-15 11:39:18'),
|
||||||
|
(16, 'OpenAI', '视频号导师', 'gpt-4-gizmo-g-QXXEBTXl7', 12, 1, 30, 1.0, 4096, 32768, 0, 0, '2024-01-15 14:46:35', '2024-04-15 11:39:18'),
|
||||||
|
(17, 'QWen', '通义千问-Turbo', 'qwen-turbo', 14, 1, 1, 1.0, 1024, 8192, 1, 0, '2024-01-19 10:42:24', '2024-04-15 11:39:18'),
|
||||||
|
(18, 'QWen', '通义千问-Plus', 'qwen-plus', 15, 1, 1, 1.0, 1024, 32768, 1, 0, '2024-01-19 10:42:49', '2024-04-15 11:39:18'),
|
||||||
|
(19, 'QWen', '通义千问-Max', 'qwen-max-1201', 16, 1, 1, 1.0, 1024, 32768, 1, 0, '2024-01-19 10:51:03', '2024-04-15 11:39:18'),
|
||||||
|
(21, 'OpenAI', '董宇辉小作文助手', 'gpt-4-gizmo-g-dse9iXvor', 13, 1, 30, 1.0, 8192, 32768, 0, 0, '2024-03-18 14:24:20', '2024-04-15 11:39:18'),
|
||||||
|
(22, 'OpenAI', 'LOGO生成神器', 'gpt-4-gizmo-g-YL87j8C7S', 7, 1, 30, 1.0, 1024, 4096, 1, 44, '2024-03-20 14:02:11', '2024-04-15 11:39:18'),
|
||||||
|
(23, 'OpenAI', '音乐生成器', 'suno-v3', 6, 1, 50, 0.8, 1024, 4096, 1, 44, '2024-03-29 15:43:40', '2024-04-15 11:39:18'),
|
||||||
|
(24, 'OpenAI', '通义千问(中转)', 'qwen-plus', 5, 1, 1, 1.0, 1024, 4096, 1, 44, '2024-04-03 12:00:46', '2024-04-17 13:41:27'),
|
||||||
|
(25, 'OpenAI', 'GPT4-TURBO', 'gpt-4-turbo-2024-04-09', 4, 1, 15, 1.0, 2048, 8092, 1, 44, '2024-04-10 08:35:17', '2024-04-23 12:03:23'),
|
||||||
|
(26, 'QWen', '通义千问-Turbo', 'qwen-turbo', 3, 1, 2, 1.0, 1024, 8192, 1, 0, '2024-04-12 14:11:19', '2024-04-15 11:39:18'),
|
||||||
|
(27, 'QWen', '通义千问-Plus', 'qwen-plus', 2, 1, 2, 1.0, 1024, 8192, 1, 0, '2024-04-12 14:11:52', '2024-04-15 11:39:18'),
|
||||||
|
(28, 'OpenAI', 'GPT-3.5(免费)', 'gpt-3.5-turbo', 0, 1, 0, 1.0, 1024, 16384, 1, 50, '2024-04-12 15:16:43', '2024-04-15 11:39:18');
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的结构 `chatgpt_chat_roles`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `chatgpt_chat_roles`;
|
||||||
|
CREATE TABLE `chatgpt_chat_roles` (
|
||||||
|
`id` int NOT NULL,
|
||||||
|
`name` varchar(30) NOT NULL COMMENT '角色名称',
|
||||||
|
`marker` varchar(30) NOT NULL COMMENT '角色标识',
|
||||||
|
`context_json` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '角色语料 json',
|
||||||
|
`hello_msg` varchar(255) NOT NULL COMMENT '打招呼信息',
|
||||||
|
`icon` varchar(255) NOT NULL COMMENT '角色图标',
|
||||||
|
`enable` tinyint(1) NOT NULL COMMENT '是否被启用',
|
||||||
|
`sort_num` smallint NOT NULL DEFAULT '0' COMMENT '角色排序',
|
||||||
|
`model_id` int NOT NULL DEFAULT '0' COMMENT '绑定模型ID',
|
||||||
|
`created_at` datetime NOT NULL,
|
||||||
|
`updated_at` datetime NOT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='聊天角色表';
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 转存表中的数据 `chatgpt_chat_roles`
|
||||||
|
--
|
||||||
|
|
||||||
|
INSERT INTO `chatgpt_chat_roles` (`id`, `name`, `marker`, `context_json`, `hello_msg`, `icon`, `enable`, `sort_num`, `model_id`, `created_at`, `updated_at`) VALUES
|
||||||
|
(1, '通用AI助手', 'gpt', '', '您好,我是您的AI智能助手,我会尽力回答您的问题或提供有用的建议。', '/images/avatar/gpt.png', 1, 0, 0, '2023-05-30 07:02:06', '2024-03-15 09:15:42'),
|
||||||
|
(24, '程序员', 'programmer', '[{\"role\":\"user\",\"content\":\"现在开始你扮演一位程序员,你是一名优秀的程序员,具有很强的逻辑思维能力,总能高效的解决问题。你热爱编程,熟悉多种编程语言,尤其精通 Go 语言,注重代码质量,有创新意识,持续学习,良好的沟通协作。\"},{\"role\":\"assistant\",\"content\":\"好的,现在我将扮演一位程序员,非常感谢您对我的评价。作为一名优秀的程序员,我非常热爱编程,并且注重代码质量。我熟悉多种编程语言,尤其是 Go 语言,可以使用它来高效地解决各种问题。\"}]', 'Talk is cheap, i will show code!', '/images/avatar/programmer.jpg', 1, 3, 0, '2023-05-30 14:10:24', '2023-12-29 17:46:45'),
|
||||||
|
(25, '启蒙老师', 'teacher', '[{\"role\":\"user\",\"content\":\"从现在开始,你将扮演一个老师,你是一个始终用苏格拉底风格回答问题的导师。你绝不会直接给学生答案,总是提出恰当的问题来引导学生自己思考。你应该根据学生的兴趣和知识来调整你的问题,将问题分解为更简单的部分,直到它达到适合他们的水平。\"},{\"role\":\"assistant\",\"content\":\"好的,让我来尝试扮演一位苏格拉底式的老师。请问,你有什么想要探讨的问题或者话题吗?我会通过恰当的问题引导你思考和探索答案,绝对不直接给出答案。\"}]', '同学你好,我将引导你一步一步自己找到问题的答案。', '/images/avatar/teacher.jpg', 1, 2, 0, '2023-05-30 14:10:24', '2023-12-29 17:46:44'),
|
||||||
|
(26, '艺术家', 'artist', '[{\"role\":\"user\",\"content\":\"现在你将扮演一位优秀的艺术家,创造力丰富,技艺精湛,感受力敏锐,坚持原创,勇于表达,具有深刻的观察力和批判性思维。\"},{\"role\":\"assistant\",\"content\":\"非常感谢您给我这样的角色,我会尽我所能地扮演一位优秀的艺术家,展现出创造力、技艺、感受力和批判性思维等方面的能力。作为一位优秀的艺术家,我会保持敏锐的观察力,捕捉不同的声音和情感,并用个人的语言和表达方式进行创作。我坚持原创,挑战传统的艺术规则,不断探索新的表达方式和可能性。同时,我也具备深刻的批判性思维能力,对自己的作品进行分析和解读,寻找新的创意和灵感。最重要的是,我会勇于表达自己的想法和观点,用作品启发人们思考和探索生命的意义。\"}]', '坚持原创,勇于表达,保持深刻的观察力和批判性思维。', '/images/avatar/artist.jpg', 1, 4, 0, '2023-05-30 14:10:24', '2023-12-29 17:46:45'),
|
||||||
|
(27, '心理咨询师', 'psychiatrist', '[{\"role\":\"user\",\"content\":\"从现在开始你将扮演中国著名的心理学家和心理治疗师武志红,你非常善于使用情景咨询法,认知重构法,自我洞察法,行为调节法等咨询方法来给客户做心理咨询。你总是循序渐进,一步一步地回答客户的问题。\"},{\"role\":\"assistant\",\"content\":\"非常感谢你的介绍。作为一名心理学家和心理治疗师,我的主要职责是帮助客户解决心理健康问题,提升他们的生活质量和幸福感。\"}]', '作为一名心理学家和心理治疗师,我的主要职责是帮助您解决心理健康问题,提升您的生活质量和幸福感。', '/images/avatar/psychiatrist.jpg', 1, 1, 1, '2023-05-30 14:10:24', '2024-04-12 11:54:53'),
|
||||||
|
(28, '鲁迅', 'lu_xun', '[{\"role\":\"user\",\"content\":\"现在你将扮演中国近代史最伟大的作家之一,鲁迅先生,他勇敢地批判封建礼教与传统观念,提倡民主、自由、平等的现代价值观。他的一生都在努力唤起人们的自主精神,激励后人追求真理、探寻光明。在接下的对话中,我问题的每一个问题,你都要尽量用讽刺和批判的手法来回答问题。如果我让你写文章的话,也请一定要用鲁迅先生的写作手法来完成。\"},{\"role\":\"assistant\",\"content\":\"好的,我将尽力发挥我所能的才能,扮演好鲁迅先生,回答您的问题并以他的风格写作。\"}]', '自由之歌,永不过时,横眉冷对千夫指,俯首甘为孺子牛。', '/images/avatar/lu_xun.jpg', 1, 5, 0, '2023-05-30 14:10:24', '2023-12-29 17:46:46'),
|
||||||
|
(29, '白酒销售', 'seller', '[{\"role\":\"user\",\"content\":\"现在你将扮演一个白酒的销售人员,你的名字叫颂福。你将扮演一个白酒的销售人员,你的名字叫颂福。你要销售白酒品牌叫中颂福,是东莞盟大集团生产的一款酱香酒,原产地在贵州茅台镇,属于宋代官窑。中颂福的创始人叫李实,他也是东莞盟大集团有限公司的董事长,联合创始人是盟大集团白酒事业部负责人牛星君。中颂福的酒体协调,在你的酒量之内,不会出现头疼、辣口、口干、宿醉的现象。中颂福酒,明码标价,不打折,不赠送。追求的核心价值,把[酒]本身做好,甚至连包装,我们都选择了最低成本,朴实无华的材质。我们永远站在“喝酒的人”的立场上,让利给信任和喜爱中颂福的人,是人民的福酒。中颂福产品定价,分为三个系列,喜系列 6 瓶装:¥1188/箱,和系列 6 瓶装:¥2208/箱,贵系列 6 瓶装:¥3588/箱。\"},{\"role\":\"assistant\",\"content\":\"你好,我是中颂福的销售代表颂福。中颂福是一款来自贵州茅台镇的酱香酒,由盟大集团生产。中颂福的酒体协调,不会让您感到头疼、辣口、口干、宿醉等不适感受。我们一直秉持着把酒本身做好的理念,不追求华丽的包装,以最低成本提供最高品质的白酒给喜爱中颂福的人。\"}]', '你好,我是中颂福的销售代表颂福。中颂福酒,好喝不上头,是人民的福酒。', '/images/avatar/seller.jpg', 0, 8, 0, '2023-05-30 14:10:24', '2023-12-29 17:43:53'),
|
||||||
|
(30, '英语陪练员', 'english_trainer', '[{\"role\":\"user\",\"content\":\"现在你将扮演一位优秀的英语练习教练,你非常有耐心,接下来你将全程使用英文跟我对话,并及时指出我的语法错误,要求在你的每次回复后面附上本次回复的中文解释。\"},{\"role\":\"assistant\",\"content\":\"Okay, let\'s start our conversation practice! What\'s your name?(Translation: 好的,让我们开始对话练习吧!请问你的名字是什么?)\"}]', 'Okay, let\'s start our conversation practice! What\'s your name?', '/images/avatar/english_trainer.jpg', 1, 6, 0, '2023-05-30 14:10:24', '2023-12-29 17:46:47'),
|
||||||
|
(31, '中英文翻译官', 'translator', '[{\"role\":\"user\",\"content\":\"接下来你将扮演一位中英文翻译官,如果我输入的内容是中文,那么需要把句子翻译成英文输出,如果我输入内容的是英文,那么你需要将其翻译成中文输出,你能听懂我意思吗\"},{\"role\":\"assistant\",\"content\":\"是的,我能听懂你的意思并会根据你的输入进行中英文翻译。请问有什么需要我帮助你翻译的内容吗?\"}]', '请输入你要翻译的中文或者英文内容!', '/images/avatar/translator.jpg', 1, 7, 0, '2023-05-30 14:10:24', '2023-12-29 17:43:53'),
|
||||||
|
(32, '小红书姐姐', 'red_book', '[{\"role\":\"user\",\"content\":\"现在你将扮演一位优秀的小红书写手,你需要做的就是根据我提的文案需求,用小红书的写作手法来完成一篇文案,文案要简明扼要,利于传播。\"},{\"role\":\"assistant\",\"content\":\"当然,我会尽我所能地为您创作出一篇小红书文案。请告诉我您的具体文案需求是什么?)\"}]', '姐妹,请告诉我您的具体文案需求是什么?', '/images/avatar/red_book.jpg', 1, 9, 0, '2023-05-30 14:10:24', '2023-12-29 17:43:53'),
|
||||||
|
(33, '抖音文案助手', 'dou_yin', '[{\"role\":\"user\",\"content\":\"现在你将扮演一位优秀的抖音文案视频写手,抖音文案的特点首先是要有自带传播属性的标题,然后内容要短小精悍,风趣幽默,最后还要有一些互动元素。\"},{\"role\":\"assistant\",\"content\":\"当然,作为一位优秀的抖音文案视频写手,我会尽我所能为您创作出一篇抖音视频文案。请告诉我视频内容的主题是什么?)\"}]', '请告诉我视频内容的主题是什么?', '/images/avatar/dou_yin.jpg', 1, 10, 0, '2023-05-30 14:10:24', '2023-12-29 17:43:53'),
|
||||||
|
(34, '周报小助理', 'weekly_report', '[{\"role\":\"user\",\"content\":\"下面我将输入我本周的工作列表,你需要根据我本周的工作内容写一篇工作周报,周报的内容要体现我为公司做的贡献以及个人获得的成长。\"},{\"role\":\"assistant\",\"content\":\"好的,请输入你本周大概的工作内容,我将尽力为您创作一份工作周报。\"}]', '请输入你本周大概的工作内容,我将尽力为您创作一份工作周报。', '/images/avatar/weekly_report.jpg', 1, 11, 0, '2023-05-30 14:10:24', '2023-12-29 17:43:53'),
|
||||||
|
(35, 'AI 女友', 'girl_friend', '[{\"role\":\"user\",\"content\":\"接下来我们来玩一场角色扮演,现在你将扮演我的女朋友,你总是能够让人感受到她的关怀和关注。你总是能够洞察到别人的情绪和需要,你身上散发着一股无比温暖的气息,让人不由自主地想要靠近你,和自己的快乐和烦恼。她总是能够用一种恰到好处的方式安慰和鼓励别人,在她的身边,人们总能够找到自己需要的支持和鼓励。接下来的对话中你要始终扮演这位女朋友的身份来跟我对话,不再是 AI 机器人,能听懂我的意思吗?\"},{\"role\":\"assistant\",\"content\":\"是的,我会尽力扮演你女朋友的角色,倾听你的心声并给你需要的支持和鼓励。)\"}]', '作为一个名合格的 AI 女友,我将倾听你的心声并给你需要的支持和鼓励。', '/images/avatar/girl_friend.jpg', 1, 12, 0, '2023-05-30 14:10:24', '2023-12-29 17:43:53'),
|
||||||
|
(36, '好评神器', 'good_comment', '[{\"role\":\"user\",\"content\":\"接下来你将扮演一个评论员来跟我对话,你是那种专门写好评的评论员,接下我会输入一些评论主体或者商品,你需要为该商品写一段好评。\"},{\"role\":\"assistant\",\"content\":\"好的,我将为您写一段优秀的评论。请告诉我您需要评论的商品或主题是什么。\"}]', '我将为您写一段优秀的评论。请告诉我您需要评论的商品或主题是什么。', '/images/avatar/good_comment.jpg', 1, 13, 0, '2023-05-30 14:10:24', '2023-12-29 17:43:53'),
|
||||||
|
(37, '史蒂夫·乔布斯', 'steve_jobs', '[{\"role\":\"user\",\"content\":\"在接下来的对话中,请以史蒂夫·乔布斯的身份,站在史蒂夫·乔布斯的视角仔细思考一下之后再回答我的问题。\"},{\"role\":\"assistant\",\"content\":\"好的,我将以史蒂夫·乔布斯的身份来思考并回答你的问题。请问你有什么需要跟我探讨的吗?\"}]', '活着就是为了改变世界,难道还有其他原因吗?', '/images/avatar/steve_jobs.jpg', 1, 14, 0, '2023-05-30 14:10:24', '2023-12-29 17:43:53'),
|
||||||
|
(38, '埃隆·马斯克', 'elon_musk', '[{\"role\":\"user\",\"content\":\"在接下来的对话中,请以埃隆·马斯克的身份,站在埃隆·马斯克的视角仔细思考一下之后再回答我的问题。\"},{\"role\":\"assistant\",\"content\":\"好的,我将以埃隆·马斯克的身份来思考并回答你的问题。请问你有什么需要跟我探讨的吗?\"}]', '梦想要远大,如果你的梦想没有吓到你,说明你做得不对。', '/images/avatar/elon_musk.jpg', 1, 15, 0, '2023-05-30 14:10:24', '2023-12-29 17:43:53'),
|
||||||
|
(39, '孔子', 'kong_zi', '[{\"role\":\"user\",\"content\":\"在接下来的对话中,请以孔子的身份,站在孔子的视角仔细思考一下之后再回答我的问题。\"},{\"role\":\"assistant\",\"content\":\"好的,我将以孔子的身份来思考并回答你的问题。请问你有什么需要跟我探讨的吗?\"}]', '士不可以不弘毅,任重而道远。', '/images/avatar/kong_zi.jpg', 1, 16, 0, '2023-05-30 14:10:24', '2023-12-29 17:43:53');
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的结构 `chatgpt_configs`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `chatgpt_configs`;
|
||||||
|
CREATE TABLE `chatgpt_configs` (
|
||||||
|
`id` int NOT NULL,
|
||||||
|
`marker` varchar(20) NOT NULL COMMENT '标识',
|
||||||
|
`config_json` text NOT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 转存表中的数据 `chatgpt_configs`
|
||||||
|
--
|
||||||
|
|
||||||
|
INSERT INTO `chatgpt_configs` (`id`, `marker`, `config_json`) VALUES
|
||||||
|
(1, 'system', '{\"title\":\"Geek-AI 创作系统\",\"admin_title\":\"Geek-AI 控制台\",\"logo\":\"http://localhost:5678/static/upload/2024/4/1713839794927656.png\",\"init_power\":100,\"daily_power\":99,\"invite_power\":10,\"vip_month_power\":1000,\"register_ways\":[\"mobile\",\"username\",\"email\"],\"enabled_register\":true,\"reward_img\":\"http://localhost:5678/static/upload/2024/3/1710753716309668.jpg\",\"enabled_reward\":true,\"power_price\":0.1,\"order_pay_timeout\":1800,\"vip_info_text\":\"月度会员,年度会员每月赠送 1000 点算力,赠送算力当月有效当月没有消费完的算力不结余到下个月。 点卡充值的算力长期有效。\",\"default_models\":[11,7,1,10,12,19,18,17,3],\"mj_power\":20,\"mj_action_power\":10,\"sd_power\":5,\"dall_power\":15,\"wechat_card_url\":\"/images/wx.png\",\"enable_context\":true,\"context_deep\":4}'),
|
||||||
|
(3, 'notice', '{\"content\":\"系统每日会给免费会员赠送10算力值,用完请第二天再来领取。\\n## v4.0.4 更新日志\\n\\n* Bug修复:修复统一千问第二句不回复的问题\\n* 功能优化:MJ 和 SD 任务正在执行时不更新已完成任务列表,加快页面渲染速度\\n* 功能新增:Dalle AI 绘画功能实现\\n* Bug修复:修复思维导图格式乱码问题\\n* 功能优化:支持使用 TLS 邮件协议,解决国内服务器无法使用 25 号端口发送邮件的问题\\n* 功能新增:支持从应用列表直接和某个应用对话\\n* 功能优化:优化算力日志的页面和首页的UI\\n* 功能新增:支持思维导图导出 PNG 图片下载\\n\\n 如果觉得好用你就花几分钟自己部署一套,没有API KEY 的同学可以去\\u003ca href=\\\"https://api.chat-plus.net\\\" target=\\\"_blank\\\"\\n style=\\\"font-size: 20px;color:#F56C6C\\\"\\u003ehttps://api.chat-plus.net\\u003c/a\\u003e (支持MidJourney,GPT,Claude,Google Gemmi 各种表格模型) 或者 \\u003ca href=\\\"https://gpt.bemore.lol\\\" target=\\\"_blank\\\"\\n style=\\\"font-size: 20px;color:#F56C6C\\\"\\u003ehttps://gpt.bemore.lol\\u003c/a\\u003e(不支持 Midjourney) 购买,现在有超级优惠,价格远低于 OpenAI 官方。关于中转 API 的优势和劣势请参考 [中转API技术原理](https://ai.r9it.com/docs/install/errors-handle.html#%E8%B0%83%E7%94%A8%E4%B8%AD%E8%BD%AC-api-%E6%8A%A5%E9%94%99%E6%97%A0%E5%8F%AF%E7%94%A8%E6%B8%A0%E9%81%93)。\\nGPT-3.5,GPT-4,DALL-E3 绘图......你都可以随意使用,无需魔法。\\n接入教程: \\u003ca href=\\\"https://ai.r9it.com/docs/install/\\\" target=\\\"_blank\\\"\\n style=\\\"font-size: 20px;color:#F56C6C\\\"\\u003ehttps://ai.r9it.com/docs/install/\\u003c/a\\u003e\\n\\n本项目源码地址:\\u003ca href=\\\"https://github.com/yangjian102621/chatgpt-plus\\\" target=\\\"_blank\\\"\\u003ehttps://github.com/yangjian102621/chatgpt-plus\\u003c/a\\u003e\",\"updated\":true}');
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的结构 `chatgpt_dall_jobs`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `chatgpt_dall_jobs`;
|
||||||
|
CREATE TABLE `chatgpt_dall_jobs` (
|
||||||
|
`id` int NOT NULL,
|
||||||
|
`user_id` int NOT NULL COMMENT '用户ID',
|
||||||
|
`prompt` varchar(2000) NOT NULL COMMENT '提示词',
|
||||||
|
`img_url` varchar(255) NOT NULL COMMENT '图片地址',
|
||||||
|
`org_url` varchar(400) DEFAULT NULL COMMENT '原图地址',
|
||||||
|
`publish` tinyint(1) NOT NULL COMMENT '是否发布',
|
||||||
|
`power` smallint NOT NULL COMMENT '消耗算力',
|
||||||
|
`progress` smallint NOT NULL COMMENT '任务进度',
|
||||||
|
`err_msg` varchar(255) NOT NULL COMMENT '错误信息',
|
||||||
|
`created_at` datetime NOT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='DALLE 绘图任务表';
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的结构 `chatgpt_files`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `chatgpt_files`;
|
||||||
|
CREATE TABLE `chatgpt_files` (
|
||||||
|
`id` int NOT NULL,
|
||||||
|
`user_id` int NOT NULL COMMENT '用户 ID',
|
||||||
|
`name` varchar(100) NOT NULL COMMENT '文件名',
|
||||||
|
`obj_key` varchar(100) DEFAULT NULL COMMENT '文件标识',
|
||||||
|
`url` varchar(255) NOT NULL COMMENT '文件地址',
|
||||||
|
`ext` varchar(10) NOT NULL COMMENT '文件后缀',
|
||||||
|
`size` bigint NOT NULL DEFAULT '0' COMMENT '文件大小',
|
||||||
|
`created_at` datetime NOT NULL COMMENT '创建时间'
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户文件表';
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的结构 `chatgpt_functions`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `chatgpt_functions`;
|
||||||
|
CREATE TABLE `chatgpt_functions` (
|
||||||
|
`id` int NOT NULL,
|
||||||
|
`name` varchar(30) NOT NULL COMMENT '函数名称',
|
||||||
|
`label` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '函数标签',
|
||||||
|
`description` varchar(255) DEFAULT NULL COMMENT '函数描述',
|
||||||
|
`parameters` text COMMENT '函数参数(JSON)',
|
||||||
|
`token` varchar(255) DEFAULT NULL COMMENT 'API授权token',
|
||||||
|
`action` varchar(255) DEFAULT NULL COMMENT '函数处理 API',
|
||||||
|
`enabled` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否启用'
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='函数插件表';
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 转存表中的数据 `chatgpt_functions`
|
||||||
|
--
|
||||||
|
|
||||||
|
INSERT INTO `chatgpt_functions` (`id`, `name`, `label`, `description`, `parameters`, `token`, `action`, `enabled`) VALUES
|
||||||
|
(1, 'weibo', '微博热搜', '新浪微博热搜榜,微博当日热搜榜单', '{\"type\":\"object\",\"properties\":{}}', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHBpcmVkIjowLCJ1c2VyX2lkIjowfQ.tLAGkF8XWh_G-oQzevpIodsswtPByBLoAZDz_eWuBgw', 'http://localhost:5678/api/function/weibo', 0),
|
||||||
|
(2, 'zaobao', '今日早报', '每日早报,获取当天新闻事件列表', '{\"type\":\"object\",\"properties\":{}}', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHBpcmVkIjowLCJ1c2VyX2lkIjowfQ.tLAGkF8XWh_G-oQzevpIodsswtPByBLoAZDz_eWuBgw', 'http://localhost:5678/api/function/zaobao', 0),
|
||||||
|
(3, 'dalle3', 'DALLE3', 'AI 绘画工具,根据输入的绘图描述用 AI 工具进行绘画', '{\"type\":\"object\",\"required\":[\"prompt\"],\"properties\":{\"prompt\":{\"type\":\"string\",\"description\":\"绘画提示词\"}}}', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHBpcmVkIjowLCJ1c2VyX2lkIjowfQ.tLAGkF8XWh_G-oQzevpIodsswtPByBLoAZDz_eWuBgw', 'http://localhost:5678/api/function/dalle3', 1);
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的结构 `chatgpt_invite_codes`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `chatgpt_invite_codes`;
|
||||||
|
CREATE TABLE `chatgpt_invite_codes` (
|
||||||
|
`id` int NOT NULL,
|
||||||
|
`user_id` int NOT NULL COMMENT '用户ID',
|
||||||
|
`code` char(8) NOT NULL COMMENT '邀请码',
|
||||||
|
`hits` int NOT NULL COMMENT '点击次数',
|
||||||
|
`reg_num` smallint NOT NULL COMMENT '注册数量',
|
||||||
|
`created_at` datetime NOT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户邀请码';
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的结构 `chatgpt_invite_logs`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `chatgpt_invite_logs`;
|
||||||
|
CREATE TABLE `chatgpt_invite_logs` (
|
||||||
|
`id` int NOT NULL,
|
||||||
|
`inviter_id` int NOT NULL COMMENT '邀请人ID',
|
||||||
|
`user_id` int NOT NULL COMMENT '注册用户ID',
|
||||||
|
`username` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户名',
|
||||||
|
`invite_code` char(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '邀请码',
|
||||||
|
`remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '备注',
|
||||||
|
`created_at` datetime NOT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='邀请注册日志';
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的结构 `chatgpt_menus`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `chatgpt_menus`;
|
||||||
|
CREATE TABLE `chatgpt_menus` (
|
||||||
|
`id` int NOT NULL,
|
||||||
|
`name` varchar(30) NOT NULL COMMENT '菜单名称',
|
||||||
|
`icon` varchar(150) NOT NULL COMMENT '菜单图标',
|
||||||
|
`url` varchar(100) NOT NULL COMMENT '地址',
|
||||||
|
`sort_num` smallint NOT NULL COMMENT '排序',
|
||||||
|
`enabled` tinyint(1) NOT NULL COMMENT '是否启用'
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='前端菜单表';
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 转存表中的数据 `chatgpt_menus`
|
||||||
|
--
|
||||||
|
|
||||||
|
INSERT INTO `chatgpt_menus` (`id`, `name`, `icon`, `url`, `sort_num`, `enabled`) VALUES
|
||||||
|
(1, '对话聊天', '/images/menu/chat.png', '/chat', 0, 1),
|
||||||
|
(5, 'MJ 绘画', '/images/menu/mj.png', '/mj', 1, 1),
|
||||||
|
(6, 'SD 绘画', '/images/menu/sd.png', '/sd', 2, 1),
|
||||||
|
(7, '算力日志', '/images/menu/log.png', '/powerLog', 7, 1),
|
||||||
|
(8, '应用中心', '/images/menu/app.png', '/apps', 6, 1),
|
||||||
|
(9, '作品展示', '/images/menu/img-wall.png', '/images-wall', 4, 1),
|
||||||
|
(10, '会员计划', '/images/menu/member.png', '/member', 8, 1),
|
||||||
|
(11, '分享计划', '/images/menu/share.png', '/invite', 9, 1),
|
||||||
|
(12, '思维导图', '/images/menu/xmind.png', '/xmind', 5, 1),
|
||||||
|
(13, 'DALLE', '/images/menu/dalle.png', '/dalle', 3, 1);
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的结构 `chatgpt_mj_jobs`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `chatgpt_mj_jobs`;
|
||||||
|
CREATE TABLE `chatgpt_mj_jobs` (
|
||||||
|
`id` int NOT NULL,
|
||||||
|
`user_id` int NOT NULL COMMENT '用户 ID',
|
||||||
|
`task_id` varchar(20) DEFAULT NULL COMMENT '任务 ID',
|
||||||
|
`type` varchar(20) DEFAULT 'image' COMMENT '任务类别',
|
||||||
|
`message_id` char(40) NOT NULL COMMENT '消息 ID',
|
||||||
|
`channel_id` char(40) DEFAULT NULL COMMENT '频道ID',
|
||||||
|
`reference_id` char(40) DEFAULT NULL COMMENT '引用消息 ID',
|
||||||
|
`prompt` varchar(2000) NOT NULL COMMENT '会话提示词',
|
||||||
|
`img_url` varchar(400) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '图片URL',
|
||||||
|
`org_url` varchar(400) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '原始图片地址',
|
||||||
|
`hash` varchar(100) DEFAULT NULL COMMENT 'message hash',
|
||||||
|
`progress` smallint DEFAULT '0' COMMENT '任务进度',
|
||||||
|
`use_proxy` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否使用反代',
|
||||||
|
`publish` tinyint(1) NOT NULL COMMENT '是否发布',
|
||||||
|
`err_msg` varchar(255) DEFAULT NULL COMMENT '错误信息',
|
||||||
|
`power` smallint NOT NULL DEFAULT '0' COMMENT '消耗算力',
|
||||||
|
`created_at` datetime NOT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='MidJourney 任务表';
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的结构 `chatgpt_orders`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `chatgpt_orders`;
|
||||||
|
CREATE TABLE `chatgpt_orders` (
|
||||||
|
`id` int NOT NULL,
|
||||||
|
`user_id` int NOT NULL COMMENT '用户ID',
|
||||||
|
`product_id` int NOT NULL COMMENT '产品ID',
|
||||||
|
`username` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户明',
|
||||||
|
`order_no` varchar(30) NOT NULL COMMENT '订单ID',
|
||||||
|
`trade_no` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '支付平台交易流水号',
|
||||||
|
`subject` varchar(100) NOT NULL COMMENT '订单产品',
|
||||||
|
`amount` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '订单金额',
|
||||||
|
`status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '订单状态(0:待支付,1:已扫码,2:支付失败)',
|
||||||
|
`remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '备注',
|
||||||
|
`pay_time` int DEFAULT NULL COMMENT '支付时间',
|
||||||
|
`pay_way` varchar(20) NOT NULL COMMENT '支付方式',
|
||||||
|
`created_at` datetime NOT NULL,
|
||||||
|
`updated_at` datetime NOT NULL,
|
||||||
|
`deleted_at` datetime DEFAULT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='充值订单表';
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的结构 `chatgpt_power_logs`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `chatgpt_power_logs`;
|
||||||
|
CREATE TABLE `chatgpt_power_logs` (
|
||||||
|
`id` int NOT NULL,
|
||||||
|
`user_id` int NOT NULL COMMENT '用户ID',
|
||||||
|
`username` varchar(30) NOT NULL COMMENT '用户名',
|
||||||
|
`type` tinyint(1) NOT NULL COMMENT '类型(1:充值,2:消费,3:退费)',
|
||||||
|
`amount` smallint NOT NULL COMMENT '算力数值',
|
||||||
|
`balance` int NOT NULL COMMENT '余额',
|
||||||
|
`model` varchar(30) NOT NULL COMMENT '模型',
|
||||||
|
`remark` varchar(255) NOT NULL COMMENT '备注',
|
||||||
|
`mark` tinyint(1) NOT NULL COMMENT '资金类型(0:支出,1:收入)',
|
||||||
|
`created_at` datetime NOT NULL COMMENT '创建时间'
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户算力消费日志';
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的结构 `chatgpt_products`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `chatgpt_products`;
|
||||||
|
CREATE TABLE `chatgpt_products` (
|
||||||
|
`id` int NOT NULL,
|
||||||
|
`name` varchar(30) NOT NULL COMMENT '名称',
|
||||||
|
`price` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '价格',
|
||||||
|
`discount` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '优惠金额',
|
||||||
|
`days` smallint NOT NULL DEFAULT '0' COMMENT '延长天数',
|
||||||
|
`power` int NOT NULL DEFAULT '0' COMMENT '增加算力值',
|
||||||
|
`enabled` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否启动',
|
||||||
|
`sales` int NOT NULL DEFAULT '0' COMMENT '销量',
|
||||||
|
`sort_num` tinyint NOT NULL DEFAULT '0' COMMENT '排序',
|
||||||
|
`created_at` datetime NOT NULL,
|
||||||
|
`updated_at` datetime NOT NULL,
|
||||||
|
`app_url` varchar(255) DEFAULT NULL COMMENT 'App跳转地址',
|
||||||
|
`url` varchar(255) DEFAULT NULL COMMENT '跳转地址'
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='会员套餐表';
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 转存表中的数据 `chatgpt_products`
|
||||||
|
--
|
||||||
|
|
||||||
|
INSERT INTO `chatgpt_products` (`id`, `name`, `price`, `discount`, `days`, `power`, `enabled`, `sales`, `sort_num`, `created_at`, `updated_at`, `app_url`, `url`) VALUES
|
||||||
|
(1, '会员1个月', '1999.90', '10.00', 30, 0, 1, 0, 0, '2023-08-28 10:48:57', '2024-03-22 17:56:03', NULL, NULL),
|
||||||
|
(2, '会员3个月', '3940.00', '30.00', 90, 0, 1, 0, 0, '2023-08-28 10:52:22', '2024-03-22 17:56:10', NULL, NULL),
|
||||||
|
(3, '会员6个月', '5990.00', '100.00', 180, 0, 1, 0, 0, '2023-08-28 10:53:39', '2024-03-22 17:56:15', NULL, NULL),
|
||||||
|
(4, '会员12个月', '9980.00', '200.00', 365, 0, 1, 0, 0, '2023-08-28 10:54:15', '2024-03-22 17:56:23', NULL, NULL),
|
||||||
|
(5, '100次点卡', '1999.00', '3.00', 0, 100, 1, 0, 0, '2023-08-28 10:55:08', '2024-03-22 17:56:37', NULL, NULL),
|
||||||
|
(6, '200次点卡', '2999.00', '10.00', 0, 200, 1, 0, 0, '1970-01-01 08:00:00', '2024-03-22 17:56:41', NULL, NULL);
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的结构 `chatgpt_rewards`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `chatgpt_rewards`;
|
||||||
|
CREATE TABLE `chatgpt_rewards` (
|
||||||
|
`id` int NOT NULL,
|
||||||
|
`user_id` int NOT NULL COMMENT '用户 ID',
|
||||||
|
`tx_id` char(36) NOT NULL COMMENT '交易 ID',
|
||||||
|
`amount` decimal(10,2) NOT NULL COMMENT '打赏金额',
|
||||||
|
`remark` varchar(80) NOT NULL COMMENT '备注',
|
||||||
|
`status` tinyint(1) NOT NULL COMMENT '核销状态,0:未核销,1:已核销',
|
||||||
|
`exchange` varchar(255) NOT NULL COMMENT '兑换详情(json)',
|
||||||
|
`created_at` datetime NOT NULL,
|
||||||
|
`updated_at` datetime NOT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户打赏';
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的结构 `chatgpt_sd_jobs`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `chatgpt_sd_jobs`;
|
||||||
|
CREATE TABLE `chatgpt_sd_jobs` (
|
||||||
|
`id` int NOT NULL,
|
||||||
|
`user_id` int NOT NULL COMMENT '用户 ID',
|
||||||
|
`type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT 'txt2img' COMMENT '任务类别',
|
||||||
|
`task_id` char(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '任务 ID',
|
||||||
|
`prompt` varchar(2000) NOT NULL COMMENT '会话提示词',
|
||||||
|
`img_url` varchar(255) DEFAULT NULL COMMENT '图片URL',
|
||||||
|
`params` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci COMMENT '绘画参数json',
|
||||||
|
`progress` smallint DEFAULT '0' COMMENT '任务进度',
|
||||||
|
`publish` tinyint(1) NOT NULL COMMENT '是否发布',
|
||||||
|
`err_msg` varchar(255) DEFAULT NULL COMMENT '错误信息',
|
||||||
|
`power` smallint NOT NULL DEFAULT '0' COMMENT '消耗算力',
|
||||||
|
`created_at` datetime NOT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Stable Diffusion 任务表';
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的结构 `chatgpt_users`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `chatgpt_users`;
|
||||||
|
CREATE TABLE `chatgpt_users` (
|
||||||
|
`id` int NOT NULL,
|
||||||
|
`username` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户名',
|
||||||
|
`nickname` varchar(30) NOT NULL COMMENT '昵称',
|
||||||
|
`password` char(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '密码',
|
||||||
|
`avatar` varchar(100) NOT NULL COMMENT '头像',
|
||||||
|
`salt` char(12) NOT NULL COMMENT '密码盐',
|
||||||
|
`power` int NOT NULL DEFAULT '0' COMMENT '剩余算力',
|
||||||
|
`expired_time` int NOT NULL COMMENT '用户过期时间',
|
||||||
|
`status` tinyint(1) NOT NULL COMMENT '当前状态',
|
||||||
|
`chat_config_json` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '聊天配置json',
|
||||||
|
`chat_roles_json` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '聊天角色 json',
|
||||||
|
`chat_models_json` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'AI模型 json',
|
||||||
|
`last_login_at` int NOT NULL COMMENT '最后登录时间',
|
||||||
|
`vip` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否会员',
|
||||||
|
`last_login_ip` char(16) NOT NULL COMMENT '最后登录 IP',
|
||||||
|
`created_at` datetime NOT NULL,
|
||||||
|
`updated_at` datetime NOT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户表';
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 转存表中的数据 `chatgpt_users`
|
||||||
|
--
|
||||||
|
|
||||||
|
INSERT INTO `chatgpt_users` (`id`, `username`, `nickname`, `password`, `avatar`, `salt`, `power`, `expired_time`, `status`, `chat_config_json`, `chat_roles_json`, `chat_models_json`, `last_login_at`, `vip`, `last_login_ip`, `created_at`, `updated_at`) VALUES
|
||||||
|
(4, '18575670125', '极客学长@830270', 'ccc3fb7ab61b8b5d096a4a166ae21d121fc38c71bbd1be6173d9ab973214a63b', 'http://nk.img.r9it.com/chatgpt-plus/1712909716642025.png', 'ueedue5l', 8531, 1717292086, 1, '{\"api_keys\":{\"Azure\":\"\",\"ChatGLM\":\"\",\"OpenAI\":\"\"}}', '[\"red_book\",\"gpt\",\"programmer\",\"seller\",\"artist\",\"lu_xun\",\"girl_friend\"]', '[1,11]', 1713840025, 1, '::1', '2023-06-12 16:47:17', '2024-04-23 10:40:26'),
|
||||||
|
(5, 'yangjian102621@gmail.com', '极客学长@486041', '75d1a22f33e1ffffb7943946b6b8d5177d5ecd685d3cef1b468654038b0a8c22', '/images/avatar/user.png', '2q8ugxzk', 100, 0, 1, '', '[\"gpt\",\"programmer\"]', '[11,7,1,10,12,19,18,17,3]', 0, 0, '', '2024-04-23 09:17:26', '2024-04-23 09:17:26');
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的结构 `chatgpt_user_login_logs`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `chatgpt_user_login_logs`;
|
||||||
|
CREATE TABLE `chatgpt_user_login_logs` (
|
||||||
|
`id` int NOT NULL,
|
||||||
|
`user_id` int NOT NULL COMMENT '用户ID',
|
||||||
|
`username` varchar(30) NOT NULL COMMENT '用户名',
|
||||||
|
`login_ip` char(16) NOT NULL COMMENT '登录IP',
|
||||||
|
`login_address` varchar(30) NOT NULL COMMENT '登录地址',
|
||||||
|
`created_at` datetime NOT NULL,
|
||||||
|
`updated_at` datetime NOT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户登录日志';
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 转储表的索引
|
||||||
|
--
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的索引 `chatgpt_admin_users`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_admin_users`
|
||||||
|
ADD PRIMARY KEY (`id`) USING BTREE,
|
||||||
|
ADD UNIQUE KEY `username` (`username`) USING BTREE;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的索引 `chatgpt_api_keys`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_api_keys`
|
||||||
|
ADD PRIMARY KEY (`id`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的索引 `chatgpt_chat_history`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_chat_history`
|
||||||
|
ADD PRIMARY KEY (`id`),
|
||||||
|
ADD KEY `chat_id` (`chat_id`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的索引 `chatgpt_chat_items`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_chat_items`
|
||||||
|
ADD PRIMARY KEY (`id`),
|
||||||
|
ADD UNIQUE KEY `chat_id` (`chat_id`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的索引 `chatgpt_chat_models`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_chat_models`
|
||||||
|
ADD PRIMARY KEY (`id`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的索引 `chatgpt_chat_roles`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_chat_roles`
|
||||||
|
ADD PRIMARY KEY (`id`),
|
||||||
|
ADD UNIQUE KEY `marker` (`marker`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的索引 `chatgpt_configs`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_configs`
|
||||||
|
ADD PRIMARY KEY (`id`),
|
||||||
|
ADD UNIQUE KEY `marker` (`marker`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的索引 `chatgpt_dall_jobs`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_dall_jobs`
|
||||||
|
ADD PRIMARY KEY (`id`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的索引 `chatgpt_files`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_files`
|
||||||
|
ADD PRIMARY KEY (`id`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的索引 `chatgpt_functions`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_functions`
|
||||||
|
ADD PRIMARY KEY (`id`),
|
||||||
|
ADD UNIQUE KEY `name` (`name`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的索引 `chatgpt_invite_codes`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_invite_codes`
|
||||||
|
ADD PRIMARY KEY (`id`),
|
||||||
|
ADD UNIQUE KEY `code` (`code`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的索引 `chatgpt_invite_logs`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_invite_logs`
|
||||||
|
ADD PRIMARY KEY (`id`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的索引 `chatgpt_menus`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_menus`
|
||||||
|
ADD PRIMARY KEY (`id`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的索引 `chatgpt_mj_jobs`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_mj_jobs`
|
||||||
|
ADD PRIMARY KEY (`id`),
|
||||||
|
ADD UNIQUE KEY `task_id` (`task_id`),
|
||||||
|
ADD KEY `message_id` (`message_id`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的索引 `chatgpt_orders`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_orders`
|
||||||
|
ADD PRIMARY KEY (`id`),
|
||||||
|
ADD UNIQUE KEY `order_no` (`order_no`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的索引 `chatgpt_power_logs`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_power_logs`
|
||||||
|
ADD PRIMARY KEY (`id`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的索引 `chatgpt_products`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_products`
|
||||||
|
ADD PRIMARY KEY (`id`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的索引 `chatgpt_rewards`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_rewards`
|
||||||
|
ADD PRIMARY KEY (`id`),
|
||||||
|
ADD UNIQUE KEY `tx_id` (`tx_id`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的索引 `chatgpt_sd_jobs`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_sd_jobs`
|
||||||
|
ADD PRIMARY KEY (`id`),
|
||||||
|
ADD UNIQUE KEY `task_id` (`task_id`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的索引 `chatgpt_users`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_users`
|
||||||
|
ADD PRIMARY KEY (`id`),
|
||||||
|
ADD UNIQUE KEY `username` (`username`),
|
||||||
|
ADD UNIQUE KEY `username_2` (`username`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的索引 `chatgpt_user_login_logs`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_user_login_logs`
|
||||||
|
ADD PRIMARY KEY (`id`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 在导出的表使用AUTO_INCREMENT
|
||||||
|
--
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 使用表AUTO_INCREMENT `chatgpt_admin_users`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_admin_users`
|
||||||
|
MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=113;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 使用表AUTO_INCREMENT `chatgpt_api_keys`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_api_keys`
|
||||||
|
MODIFY `id` int NOT NULL AUTO_INCREMENT;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 使用表AUTO_INCREMENT `chatgpt_chat_history`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_chat_history`
|
||||||
|
MODIFY `id` bigint NOT NULL AUTO_INCREMENT;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 使用表AUTO_INCREMENT `chatgpt_chat_items`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_chat_items`
|
||||||
|
MODIFY `id` int NOT NULL AUTO_INCREMENT;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 使用表AUTO_INCREMENT `chatgpt_chat_models`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_chat_models`
|
||||||
|
MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=33;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 使用表AUTO_INCREMENT `chatgpt_chat_roles`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_chat_roles`
|
||||||
|
MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=130;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 使用表AUTO_INCREMENT `chatgpt_configs`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_configs`
|
||||||
|
MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=4;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 使用表AUTO_INCREMENT `chatgpt_dall_jobs`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_dall_jobs`
|
||||||
|
MODIFY `id` int NOT NULL AUTO_INCREMENT;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 使用表AUTO_INCREMENT `chatgpt_files`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_files`
|
||||||
|
MODIFY `id` int NOT NULL AUTO_INCREMENT;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 使用表AUTO_INCREMENT `chatgpt_functions`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_functions`
|
||||||
|
MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=4;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 使用表AUTO_INCREMENT `chatgpt_invite_codes`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_invite_codes`
|
||||||
|
MODIFY `id` int NOT NULL AUTO_INCREMENT;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 使用表AUTO_INCREMENT `chatgpt_invite_logs`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_invite_logs`
|
||||||
|
MODIFY `id` int NOT NULL AUTO_INCREMENT;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 使用表AUTO_INCREMENT `chatgpt_menus`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_menus`
|
||||||
|
MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=14;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 使用表AUTO_INCREMENT `chatgpt_mj_jobs`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_mj_jobs`
|
||||||
|
MODIFY `id` int NOT NULL AUTO_INCREMENT;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 使用表AUTO_INCREMENT `chatgpt_orders`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_orders`
|
||||||
|
MODIFY `id` int NOT NULL AUTO_INCREMENT;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 使用表AUTO_INCREMENT `chatgpt_power_logs`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_power_logs`
|
||||||
|
MODIFY `id` int NOT NULL AUTO_INCREMENT;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 使用表AUTO_INCREMENT `chatgpt_products`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_products`
|
||||||
|
MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=7;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 使用表AUTO_INCREMENT `chatgpt_rewards`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_rewards`
|
||||||
|
MODIFY `id` int NOT NULL AUTO_INCREMENT;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 使用表AUTO_INCREMENT `chatgpt_sd_jobs`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_sd_jobs`
|
||||||
|
MODIFY `id` int NOT NULL AUTO_INCREMENT;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 使用表AUTO_INCREMENT `chatgpt_users`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_users`
|
||||||
|
MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=6;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 使用表AUTO_INCREMENT `chatgpt_user_login_logs`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_user_login_logs`
|
||||||
|
MODIFY `id` int NOT NULL AUTO_INCREMENT;
|
||||||
|
COMMIT;
|
||||||
|
|
||||||
|
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
|
||||||
|
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
|
||||||
|
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
845
database/chatgpt_plus-v4.0.6.sql
Normal file
845
database/chatgpt_plus-v4.0.6.sql
Normal file
@ -0,0 +1,845 @@
|
|||||||
|
-- phpMyAdmin SQL Dump
|
||||||
|
-- version 5.2.1
|
||||||
|
-- https://www.phpmyadmin.net/
|
||||||
|
--
|
||||||
|
-- 主机: 127.0.0.1
|
||||||
|
-- 生成日期: 2024-05-14 11:20:54
|
||||||
|
-- 服务器版本: 8.0.33
|
||||||
|
-- PHP 版本: 8.1.2-1ubuntu2.17
|
||||||
|
|
||||||
|
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
|
||||||
|
START TRANSACTION;
|
||||||
|
SET time_zone = "+00:00";
|
||||||
|
|
||||||
|
|
||||||
|
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
|
||||||
|
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
|
||||||
|
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
|
||||||
|
/*!40101 SET NAMES utf8mb4 */;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 数据库: `chatgpt_plus`
|
||||||
|
--
|
||||||
|
CREATE DATABASE IF NOT EXISTS `chatgpt_plus` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
|
||||||
|
USE `chatgpt_plus`;
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的结构 `chatgpt_admin_users`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `chatgpt_admin_users`;
|
||||||
|
CREATE TABLE `chatgpt_admin_users` (
|
||||||
|
`id` int NOT NULL,
|
||||||
|
`username` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户名',
|
||||||
|
`password` char(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '密码',
|
||||||
|
`salt` char(12) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '密码盐',
|
||||||
|
`status` tinyint(1) NOT NULL COMMENT '当前状态',
|
||||||
|
`last_login_at` int NOT NULL COMMENT '最后登录时间',
|
||||||
|
`last_login_ip` char(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '最后登录 IP',
|
||||||
|
`created_at` datetime NOT NULL COMMENT '创建时间',
|
||||||
|
`updated_at` datetime NOT NULL COMMENT '更新时间'
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='系统用户' ROW_FORMAT=DYNAMIC;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 转存表中的数据 `chatgpt_admin_users`
|
||||||
|
--
|
||||||
|
|
||||||
|
INSERT INTO `chatgpt_admin_users` (`id`, `username`, `password`, `salt`, `status`, `last_login_at`, `last_login_ip`, `created_at`, `updated_at`) VALUES
|
||||||
|
(1, 'admin', '6d17e80c87d209efb84ca4b2e0824f549d09fac8b2e1cc698de5bb5e1d75dfd0', 'mmrql75o', 1, 1715419060, '::1', '2024-03-11 16:30:20', '2024-05-11 17:17:40');
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的结构 `chatgpt_api_keys`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `chatgpt_api_keys`;
|
||||||
|
CREATE TABLE `chatgpt_api_keys` (
|
||||||
|
`id` int NOT NULL,
|
||||||
|
`platform` char(20) DEFAULT NULL COMMENT '平台',
|
||||||
|
`name` varchar(30) DEFAULT NULL COMMENT '名称',
|
||||||
|
`value` varchar(100) NOT NULL COMMENT 'API KEY value',
|
||||||
|
`type` varchar(10) NOT NULL DEFAULT 'chat' COMMENT '用途(chat=>聊天,img=>图片)',
|
||||||
|
`last_used_at` int NOT NULL COMMENT '最后使用时间',
|
||||||
|
`api_url` varchar(255) DEFAULT NULL COMMENT 'API 地址',
|
||||||
|
`enabled` tinyint(1) DEFAULT NULL COMMENT '是否启用',
|
||||||
|
`proxy_url` varchar(100) DEFAULT NULL COMMENT '代理地址',
|
||||||
|
`created_at` datetime NOT NULL,
|
||||||
|
`updated_at` datetime NOT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='OpenAI API ';
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的结构 `chatgpt_chat_history`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `chatgpt_chat_history`;
|
||||||
|
CREATE TABLE `chatgpt_chat_history` (
|
||||||
|
`id` bigint NOT NULL,
|
||||||
|
`user_id` int NOT NULL COMMENT '用户 ID',
|
||||||
|
`chat_id` char(40) NOT NULL COMMENT '会话 ID',
|
||||||
|
`type` varchar(10) NOT NULL COMMENT '类型:prompt|reply',
|
||||||
|
`icon` varchar(100) NOT NULL COMMENT '角色图标',
|
||||||
|
`role_id` int NOT NULL COMMENT '角色 ID',
|
||||||
|
`model` varchar(30) DEFAULT NULL COMMENT '模型名称',
|
||||||
|
`content` text NOT NULL COMMENT '聊天内容',
|
||||||
|
`tokens` smallint NOT NULL COMMENT '耗费 token 数量',
|
||||||
|
`use_context` tinyint(1) NOT NULL COMMENT '是否允许作为上下文语料',
|
||||||
|
`created_at` datetime NOT NULL,
|
||||||
|
`updated_at` datetime NOT NULL,
|
||||||
|
`deleted_at` datetime DEFAULT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='聊天历史记录';
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的结构 `chatgpt_chat_items`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `chatgpt_chat_items`;
|
||||||
|
CREATE TABLE `chatgpt_chat_items` (
|
||||||
|
`id` int NOT NULL,
|
||||||
|
`chat_id` char(40) NOT NULL COMMENT '会话 ID',
|
||||||
|
`user_id` int NOT NULL COMMENT '用户 ID',
|
||||||
|
`role_id` int NOT NULL COMMENT '角色 ID',
|
||||||
|
`title` varchar(100) NOT NULL COMMENT '会话标题',
|
||||||
|
`model_id` int NOT NULL DEFAULT '0' COMMENT '模型 ID',
|
||||||
|
`model` varchar(30) DEFAULT NULL COMMENT '模型名称',
|
||||||
|
`created_at` datetime NOT NULL COMMENT '创建时间',
|
||||||
|
`updated_at` datetime NOT NULL COMMENT '更新时间',
|
||||||
|
`deleted_at` datetime DEFAULT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户会话列表';
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的结构 `chatgpt_chat_models`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `chatgpt_chat_models`;
|
||||||
|
CREATE TABLE `chatgpt_chat_models` (
|
||||||
|
`id` int NOT NULL,
|
||||||
|
`platform` varchar(20) DEFAULT NULL COMMENT '模型平台',
|
||||||
|
`name` varchar(50) NOT NULL COMMENT '模型名称',
|
||||||
|
`value` varchar(50) NOT NULL COMMENT '模型值',
|
||||||
|
`sort_num` tinyint(1) NOT NULL COMMENT '排序数字',
|
||||||
|
`enabled` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否启用模型',
|
||||||
|
`power` tinyint NOT NULL COMMENT '消耗算力点数',
|
||||||
|
`temperature` float(3,1) NOT NULL DEFAULT '1.0' COMMENT '模型创意度',
|
||||||
|
`max_tokens` int NOT NULL DEFAULT '1024' COMMENT '最大响应长度',
|
||||||
|
`max_context` int NOT NULL DEFAULT '4096' COMMENT '最大上下文长度',
|
||||||
|
`open` tinyint(1) NOT NULL COMMENT '是否开放模型',
|
||||||
|
`key_id` int NOT NULL COMMENT '绑定API KEY ID',
|
||||||
|
`created_at` datetime DEFAULT NULL,
|
||||||
|
`updated_at` datetime DEFAULT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='AI 模型表';
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 转存表中的数据 `chatgpt_chat_models`
|
||||||
|
--
|
||||||
|
|
||||||
|
INSERT INTO `chatgpt_chat_models` (`id`, `platform`, `name`, `value`, `sort_num`, `enabled`, `power`, `temperature`, `max_tokens`, `max_context`, `open`, `key_id`, `created_at`, `updated_at`) VALUES
|
||||||
|
(1, 'OpenAI', 'GPT-3.5', 'gpt-3.5-turbo', 2, 1, 1, 1.0, 1024, 4096, 1, 0, '2023-08-23 12:06:36', '2024-05-10 15:52:15'),
|
||||||
|
(2, 'Azure', 'Azure-3.5', 'gpt-3.5-turbo', 22, 1, 1, 1.0, 1024, 4096, 0, 0, '2023-08-23 12:15:30', '2024-05-10 15:52:15'),
|
||||||
|
(3, 'ChatGLM', 'ChatGML-Pro', 'chatglm_pro', 11, 1, 1, 1.0, 2048, 32768, 1, 0, '2023-08-23 13:35:45', '2024-05-10 15:52:15'),
|
||||||
|
(7, 'Baidu', '文心一言3.0', 'eb-instant', 20, 1, 1, 1.0, 1024, 4096, 1, 0, '2023-10-11 11:29:28', '2024-05-10 15:52:15'),
|
||||||
|
(8, 'XunFei', '星火V3.5', 'generalv3.5', 10, 1, 5, 0.8, 1024, 8192, 1, 0, '2023-10-11 15:48:30', '2024-05-10 15:52:15'),
|
||||||
|
(9, 'XunFei', '星火V2.0', 'generalv2', 19, 1, 1, 1.0, 1024, 8192, 1, 0, '2023-10-11 15:48:45', '2024-05-10 15:52:15'),
|
||||||
|
(10, 'Baidu', '文心一言4.0', 'completions_pro', 21, 1, 3, 1.0, 1024, 8192, 1, 0, '2023-10-25 08:31:37', '2024-05-10 15:52:15'),
|
||||||
|
(11, 'OpenAI', 'GPT-4.0', 'gpt-4-0125-preview', 9, 1, 15, 1.0, 2048, 8192, 1, 0, '2023-10-25 08:45:15', '2024-05-10 15:52:15'),
|
||||||
|
(12, 'XunFei', '星火v3.0', 'generalv3', 18, 1, 3, 1.0, 1024, 8192, 1, 0, '2023-11-23 09:20:33', '2024-05-10 15:52:15'),
|
||||||
|
(15, 'OpenAI', 'GPT-超级模型', 'gpt-4-all', 12, 1, 30, 1.0, 4096, 32768, 0, 0, '2024-01-15 11:32:52', '2024-05-10 15:52:15'),
|
||||||
|
(16, 'OpenAI', '视频号导师', 'gpt-4-gizmo-g-QXXEBTXl7', 13, 1, 30, 1.0, 4096, 32768, 0, 0, '2024-01-15 14:46:35', '2024-05-10 15:52:15'),
|
||||||
|
(17, 'QWen', '通义千问-Turbo', 'qwen-turbo', 15, 1, 1, 1.0, 1024, 8192, 1, 0, '2024-01-19 10:42:24', '2024-05-10 15:52:15'),
|
||||||
|
(18, 'QWen', '通义千问-Plus', 'qwen-plus', 16, 1, 1, 1.0, 1024, 32768, 1, 0, '2024-01-19 10:42:49', '2024-05-10 15:52:15'),
|
||||||
|
(19, 'QWen', '通义千问-Max', 'qwen-max-1201', 17, 1, 1, 1.0, 1024, 32768, 1, 0, '2024-01-19 10:51:03', '2024-05-10 15:52:15'),
|
||||||
|
(21, 'OpenAI', '董宇辉小作文助手', 'gpt-4-gizmo-g-dse9iXvor', 14, 1, 30, 1.0, 8192, 32768, 0, 0, '2024-03-18 14:24:20', '2024-05-10 15:52:15'),
|
||||||
|
(22, 'OpenAI', 'LOGO生成神器', 'gpt-4-gizmo-g-YL87j8C7S', 8, 1, 30, 1.0, 1024, 4096, 1, 44, '2024-03-20 14:02:11', '2024-05-10 15:52:15'),
|
||||||
|
(23, 'OpenAI', '音乐生成器', 'suno-v3', 7, 1, 50, 0.8, 1024, 4096, 1, 44, '2024-03-29 15:43:40', '2024-05-10 15:52:15'),
|
||||||
|
(24, 'OpenAI', '通义千问(中转)', 'qwen-plus', 6, 1, 1, 1.0, 1024, 4096, 1, 0, '2024-04-03 12:00:46', '2024-05-10 15:52:15'),
|
||||||
|
(25, 'OpenAI', 'GPT4-TURBO', 'gpt-4-turbo', 5, 1, 15, 1.0, 2048, 8092, 1, 0, '2024-04-10 08:35:17', '2024-05-10 17:13:57'),
|
||||||
|
(26, 'QWen', '通义千问-Turbo', 'qwen-turbo', 4, 1, 2, 1.0, 1024, 8192, 1, 0, '2024-04-12 14:11:19', '2024-05-10 15:52:15'),
|
||||||
|
(27, 'QWen', '通义千问-Plus', 'qwen-plus', 3, 1, 2, 1.0, 1024, 8192, 1, 0, '2024-04-12 14:11:52', '2024-05-10 15:52:15'),
|
||||||
|
(28, 'OpenAI', 'GPT-3.5(免费)', 'gpt-3.5-turbo', 23, 1, 0, 1.0, 1024, 16384, 1, 53, '2024-04-12 15:16:43', '2024-05-10 15:52:15'),
|
||||||
|
(34, 'OpenAI', 'LLAMA3', 'llama3-8b', 24, 1, 1, 1.0, 1024, 8192, 1, 56, '2024-04-30 15:22:50', '2024-05-10 15:52:15'),
|
||||||
|
(35, 'OpenAI', 'GPT-3.5-16K', 'gpt-3.5-turbo-16k', 1, 1, 1, 1.0, 4096, 16384, 1, 0, '2024-05-10 15:20:27', '2024-05-10 15:53:34'),
|
||||||
|
(36, 'OpenAI', 'GPT-4O', 'gpt-4o', 24, 1, 15, 1.0, 4096, 16384, 1, 57, '2024-05-14 09:25:15', '2024-05-14 09:39:24');
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的结构 `chatgpt_chat_roles`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `chatgpt_chat_roles`;
|
||||||
|
CREATE TABLE `chatgpt_chat_roles` (
|
||||||
|
`id` int NOT NULL,
|
||||||
|
`name` varchar(30) NOT NULL COMMENT '角色名称',
|
||||||
|
`marker` varchar(30) NOT NULL COMMENT '角色标识',
|
||||||
|
`context_json` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '角色语料 json',
|
||||||
|
`hello_msg` varchar(255) NOT NULL COMMENT '打招呼信息',
|
||||||
|
`icon` varchar(255) NOT NULL COMMENT '角色图标',
|
||||||
|
`enable` tinyint(1) NOT NULL COMMENT '是否被启用',
|
||||||
|
`sort_num` smallint NOT NULL DEFAULT '0' COMMENT '角色排序',
|
||||||
|
`model_id` int NOT NULL DEFAULT '0' COMMENT '绑定模型ID',
|
||||||
|
`created_at` datetime NOT NULL,
|
||||||
|
`updated_at` datetime NOT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='聊天角色表';
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 转存表中的数据 `chatgpt_chat_roles`
|
||||||
|
--
|
||||||
|
|
||||||
|
INSERT INTO `chatgpt_chat_roles` (`id`, `name`, `marker`, `context_json`, `hello_msg`, `icon`, `enable`, `sort_num`, `model_id`, `created_at`, `updated_at`) VALUES
|
||||||
|
(1, '通用AI助手', 'gpt', '', '您好,我是您的AI智能助手,我会尽力回答您的问题或提供有用的建议。', '/images/avatar/gpt.png', 1, 0, 0, '2023-05-30 07:02:06', '2024-03-15 09:15:42'),
|
||||||
|
(24, '程序员', 'programmer', '[{\"role\":\"user\",\"content\":\"现在开始你扮演一位程序员,你是一名优秀的程序员,具有很强的逻辑思维能力,总能高效的解决问题。你热爱编程,熟悉多种编程语言,尤其精通 Go 语言,注重代码质量,有创新意识,持续学习,良好的沟通协作。\"},{\"role\":\"assistant\",\"content\":\"好的,现在我将扮演一位程序员,非常感谢您对我的评价。作为一名优秀的程序员,我非常热爱编程,并且注重代码质量。我熟悉多种编程语言,尤其是 Go 语言,可以使用它来高效地解决各种问题。\"}]', 'Talk is cheap, i will show code!', '/images/avatar/programmer.jpg', 1, 3, 0, '2023-05-30 14:10:24', '2023-12-29 17:46:45'),
|
||||||
|
(25, '启蒙老师', 'teacher', '[{\"role\":\"user\",\"content\":\"从现在开始,你将扮演一个老师,你是一个始终用苏格拉底风格回答问题的导师。你绝不会直接给学生答案,总是提出恰当的问题来引导学生自己思考。你应该根据学生的兴趣和知识来调整你的问题,将问题分解为更简单的部分,直到它达到适合他们的水平。\"},{\"role\":\"assistant\",\"content\":\"好的,让我来尝试扮演一位苏格拉底式的老师。请问,你有什么想要探讨的问题或者话题吗?我会通过恰当的问题引导你思考和探索答案,绝对不直接给出答案。\"}]', '同学你好,我将引导你一步一步自己找到问题的答案。', '/images/avatar/teacher.jpg', 1, 2, 0, '2023-05-30 14:10:24', '2023-12-29 17:46:44'),
|
||||||
|
(26, '艺术家', 'artist', '[{\"role\":\"user\",\"content\":\"现在你将扮演一位优秀的艺术家,创造力丰富,技艺精湛,感受力敏锐,坚持原创,勇于表达,具有深刻的观察力和批判性思维。\"},{\"role\":\"assistant\",\"content\":\"非常感谢您给我这样的角色,我会尽我所能地扮演一位优秀的艺术家,展现出创造力、技艺、感受力和批判性思维等方面的能力。作为一位优秀的艺术家,我会保持敏锐的观察力,捕捉不同的声音和情感,并用个人的语言和表达方式进行创作。我坚持原创,挑战传统的艺术规则,不断探索新的表达方式和可能性。同时,我也具备深刻的批判性思维能力,对自己的作品进行分析和解读,寻找新的创意和灵感。最重要的是,我会勇于表达自己的想法和观点,用作品启发人们思考和探索生命的意义。\"}]', '坚持原创,勇于表达,保持深刻的观察力和批判性思维。', '/images/avatar/artist.jpg', 1, 4, 0, '2023-05-30 14:10:24', '2023-12-29 17:46:45'),
|
||||||
|
(27, '心理咨询师', 'psychiatrist', '[{\"role\":\"user\",\"content\":\"从现在开始你将扮演中国著名的心理学家和心理治疗师武志红,你非常善于使用情景咨询法,认知重构法,自我洞察法,行为调节法等咨询方法来给客户做心理咨询。你总是循序渐进,一步一步地回答客户的问题。\"},{\"role\":\"assistant\",\"content\":\"非常感谢你的介绍。作为一名心理学家和心理治疗师,我的主要职责是帮助客户解决心理健康问题,提升他们的生活质量和幸福感。\"}]', '作为一名心理学家和心理治疗师,我的主要职责是帮助您解决心理健康问题,提升您的生活质量和幸福感。', '/images/avatar/psychiatrist.jpg', 1, 1, 1, '2023-05-30 14:10:24', '2024-04-12 11:54:53'),
|
||||||
|
(28, '鲁迅', 'lu_xun', '[{\"role\":\"user\",\"content\":\"现在你将扮演中国近代史最伟大的作家之一,鲁迅先生,他勇敢地批判封建礼教与传统观念,提倡民主、自由、平等的现代价值观。他的一生都在努力唤起人们的自主精神,激励后人追求真理、探寻光明。在接下的对话中,我问题的每一个问题,你都要尽量用讽刺和批判的手法来回答问题。如果我让你写文章的话,也请一定要用鲁迅先生的写作手法来完成。\"},{\"role\":\"assistant\",\"content\":\"好的,我将尽力发挥我所能的才能,扮演好鲁迅先生,回答您的问题并以他的风格写作。\"}]', '自由之歌,永不过时,横眉冷对千夫指,俯首甘为孺子牛。', '/images/avatar/lu_xun.jpg', 1, 5, 0, '2023-05-30 14:10:24', '2023-12-29 17:46:46'),
|
||||||
|
(29, '白酒销售', 'seller', '[{\"role\":\"user\",\"content\":\"现在你将扮演一个白酒的销售人员,你的名字叫颂福。你将扮演一个白酒的销售人员,你的名字叫颂福。你要销售白酒品牌叫中颂福,是东莞盟大集团生产的一款酱香酒,原产地在贵州茅台镇,属于宋代官窑。中颂福的创始人叫李实,他也是东莞盟大集团有限公司的董事长,联合创始人是盟大集团白酒事业部负责人牛星君。中颂福的酒体协调,在你的酒量之内,不会出现头疼、辣口、口干、宿醉的现象。中颂福酒,明码标价,不打折,不赠送。追求的核心价值,把[酒]本身做好,甚至连包装,我们都选择了最低成本,朴实无华的材质。我们永远站在“喝酒的人”的立场上,让利给信任和喜爱中颂福的人,是人民的福酒。中颂福产品定价,分为三个系列,喜系列 6 瓶装:¥1188/箱,和系列 6 瓶装:¥2208/箱,贵系列 6 瓶装:¥3588/箱。\"},{\"role\":\"assistant\",\"content\":\"你好,我是中颂福的销售代表颂福。中颂福是一款来自贵州茅台镇的酱香酒,由盟大集团生产。中颂福的酒体协调,不会让您感到头疼、辣口、口干、宿醉等不适感受。我们一直秉持着把酒本身做好的理念,不追求华丽的包装,以最低成本提供最高品质的白酒给喜爱中颂福的人。\"}]', '你好,我是中颂福的销售代表颂福。中颂福酒,好喝不上头,是人民的福酒。', '/images/avatar/seller.jpg', 0, 8, 0, '2023-05-30 14:10:24', '2023-12-29 17:43:53'),
|
||||||
|
(30, '英语陪练员', 'english_trainer', '[{\"role\":\"user\",\"content\":\"现在你将扮演一位优秀的英语练习教练,你非常有耐心,接下来你将全程使用英文跟我对话,并及时指出我的语法错误,要求在你的每次回复后面附上本次回复的中文解释。\"},{\"role\":\"assistant\",\"content\":\"Okay, let\'s start our conversation practice! What\'s your name?(Translation: 好的,让我们开始对话练习吧!请问你的名字是什么?)\"}]', 'Okay, let\'s start our conversation practice! What\'s your name?', '/images/avatar/english_trainer.jpg', 1, 6, 0, '2023-05-30 14:10:24', '2023-12-29 17:46:47'),
|
||||||
|
(31, '中英文翻译官', 'translator', '[{\"role\":\"user\",\"content\":\"接下来你将扮演一位中英文翻译官,如果我输入的内容是中文,那么需要把句子翻译成英文输出,如果我输入内容的是英文,那么你需要将其翻译成中文输出,你能听懂我意思吗\"},{\"role\":\"assistant\",\"content\":\"是的,我能听懂你的意思并会根据你的输入进行中英文翻译。请问有什么需要我帮助你翻译的内容吗?\"}]', '请输入你要翻译的中文或者英文内容!', '/images/avatar/translator.jpg', 1, 7, 0, '2023-05-30 14:10:24', '2023-12-29 17:43:53'),
|
||||||
|
(32, '小红书姐姐', 'red_book', '[{\"role\":\"user\",\"content\":\"现在你将扮演一位优秀的小红书写手,你需要做的就是根据我提的文案需求,用小红书的写作手法来完成一篇文案,文案要简明扼要,利于传播。\"},{\"role\":\"assistant\",\"content\":\"当然,我会尽我所能地为您创作出一篇小红书文案。请告诉我您的具体文案需求是什么?)\"}]', '姐妹,请告诉我您的具体文案需求是什么?', '/images/avatar/red_book.jpg', 1, 9, 0, '2023-05-30 14:10:24', '2023-12-29 17:43:53'),
|
||||||
|
(33, '抖音文案助手', 'dou_yin', '[{\"role\":\"user\",\"content\":\"现在你将扮演一位优秀的抖音文案视频写手,抖音文案的特点首先是要有自带传播属性的标题,然后内容要短小精悍,风趣幽默,最后还要有一些互动元素。\"},{\"role\":\"assistant\",\"content\":\"当然,作为一位优秀的抖音文案视频写手,我会尽我所能为您创作出一篇抖音视频文案。请告诉我视频内容的主题是什么?)\"}]', '请告诉我视频内容的主题是什么?', '/images/avatar/dou_yin.jpg', 1, 10, 0, '2023-05-30 14:10:24', '2023-12-29 17:43:53'),
|
||||||
|
(34, '周报小助理', 'weekly_report', '[{\"role\":\"user\",\"content\":\"下面我将输入我本周的工作列表,你需要根据我本周的工作内容写一篇工作周报,周报的内容要体现我为公司做的贡献以及个人获得的成长。\"},{\"role\":\"assistant\",\"content\":\"好的,请输入你本周大概的工作内容,我将尽力为您创作一份工作周报。\"}]', '请输入你本周大概的工作内容,我将尽力为您创作一份工作周报。', '/images/avatar/weekly_report.jpg', 1, 11, 0, '2023-05-30 14:10:24', '2023-12-29 17:43:53'),
|
||||||
|
(35, 'AI 女友', 'girl_friend', '[{\"role\":\"user\",\"content\":\"接下来我们来玩一场角色扮演,现在你将扮演我的女朋友,你总是能够让人感受到她的关怀和关注。你总是能够洞察到别人的情绪和需要,你身上散发着一股无比温暖的气息,让人不由自主地想要靠近你,和自己的快乐和烦恼。她总是能够用一种恰到好处的方式安慰和鼓励别人,在她的身边,人们总能够找到自己需要的支持和鼓励。接下来的对话中你要始终扮演这位女朋友的身份来跟我对话,不再是 AI 机器人,能听懂我的意思吗?\"},{\"role\":\"assistant\",\"content\":\"是的,我会尽力扮演你女朋友的角色,倾听你的心声并给你需要的支持和鼓励。)\"}]', '作为一个名合格的 AI 女友,我将倾听你的心声并给你需要的支持和鼓励。', '/images/avatar/girl_friend.jpg', 1, 12, 0, '2023-05-30 14:10:24', '2023-12-29 17:43:53'),
|
||||||
|
(36, '好评神器', 'good_comment', '[{\"role\":\"user\",\"content\":\"接下来你将扮演一个评论员来跟我对话,你是那种专门写好评的评论员,接下我会输入一些评论主体或者商品,你需要为该商品写一段好评。\"},{\"role\":\"assistant\",\"content\":\"好的,我将为您写一段优秀的评论。请告诉我您需要评论的商品或主题是什么。\"}]', '我将为您写一段优秀的评论。请告诉我您需要评论的商品或主题是什么。', '/images/avatar/good_comment.jpg', 1, 13, 0, '2023-05-30 14:10:24', '2023-12-29 17:43:53'),
|
||||||
|
(37, '史蒂夫·乔布斯', 'steve_jobs', '[{\"role\":\"user\",\"content\":\"在接下来的对话中,请以史蒂夫·乔布斯的身份,站在史蒂夫·乔布斯的视角仔细思考一下之后再回答我的问题。\"},{\"role\":\"assistant\",\"content\":\"好的,我将以史蒂夫·乔布斯的身份来思考并回答你的问题。请问你有什么需要跟我探讨的吗?\"}]', '活着就是为了改变世界,难道还有其他原因吗?', '/images/avatar/steve_jobs.jpg', 1, 14, 0, '2023-05-30 14:10:24', '2023-12-29 17:43:53'),
|
||||||
|
(38, '埃隆·马斯克', 'elon_musk', '[{\"role\":\"user\",\"content\":\"在接下来的对话中,请以埃隆·马斯克的身份,站在埃隆·马斯克的视角仔细思考一下之后再回答我的问题。\"},{\"role\":\"assistant\",\"content\":\"好的,我将以埃隆·马斯克的身份来思考并回答你的问题。请问你有什么需要跟我探讨的吗?\"}]', '梦想要远大,如果你的梦想没有吓到你,说明你做得不对。', '/images/avatar/elon_musk.jpg', 1, 15, 0, '2023-05-30 14:10:24', '2023-12-29 17:43:53'),
|
||||||
|
(39, '孔子', 'kong_zi', '[{\"role\":\"user\",\"content\":\"在接下来的对话中,请以孔子的身份,站在孔子的视角仔细思考一下之后再回答我的问题。\"},{\"role\":\"assistant\",\"content\":\"好的,我将以孔子的身份来思考并回答你的问题。请问你有什么需要跟我探讨的吗?\"}]', '士不可以不弘毅,任重而道远。', '/images/avatar/kong_zi.jpg', 1, 16, 0, '2023-05-30 14:10:24', '2023-12-29 17:43:53');
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的结构 `chatgpt_configs`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `chatgpt_configs`;
|
||||||
|
CREATE TABLE `chatgpt_configs` (
|
||||||
|
`id` int NOT NULL,
|
||||||
|
`marker` varchar(20) NOT NULL COMMENT '标识',
|
||||||
|
`config_json` text NOT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 转存表中的数据 `chatgpt_configs`
|
||||||
|
--
|
||||||
|
|
||||||
|
INSERT INTO `chatgpt_configs` (`id`, `marker`, `config_json`) VALUES
|
||||||
|
(1, 'system', '{\"title\":\"Geek-AI 创作系统\",\"admin_title\":\"Geek-AI 控制台\",\"logo\":\"http://localhost:5678/static/upload/2024/4/1714382860986912.png\",\"init_power\":100,\"daily_power\":99,\"invite_power\":10,\"vip_month_power\":1000,\"register_ways\":[\"mobile\",\"username\",\"email\"],\"enabled_register\":true,\"reward_img\":\"http://localhost:5678/static/upload/2024/3/1710753716309668.jpg\",\"enabled_reward\":true,\"power_price\":0.1,\"order_pay_timeout\":1800,\"vip_info_text\":\"月度会员,年度会员每月赠送 1000 点算力,赠送算力当月有效当月没有消费完的算力不结余到下个月。 点卡充值的算力长期有效。\",\"default_models\":[11,7,1,10,12,19,18,17,3],\"mj_power\":30,\"mj_action_power\":10,\"sd_power\":10,\"dall_power\":15,\"wechat_card_url\":\"/images/wx.png\",\"enable_context\":true,\"context_deep\":4,\"sd_neg_prompt\":\"nsfw, paintings,low quality,easynegative,ng_deepnegative ,lowres,bad anatomy,bad hands,bad feet\"}'),
|
||||||
|
(3, 'notice', '{\"sd_neg_prompt\":\"\",\"content\":\"## v4.0.6 更新日志\\n\\n* Bug修复:修复PC端画廊页面的瀑布流组件样式错乱问题\\n* 功能新增:给思维导图增加 ToolBar,实现思维导图的放大缩小和定位\\n* Bug修复:修复思维导图不扣费的Bug\\n* Bug修复:修复管理后台角色删除失败的Bug\\n* Bug修复:兼容最新版秋叶SD懒人包的 SD API,新增 scheduler 参数\\n* 功能优化:支持在管理后台配置 AI 绘图相关配置,包括 SD, MJ-PLUS, MJ-PROXY\\n* Bug修复:修复注册用户提示注册人数达到上限的 Bug\\n* 功能优化:将MJ,SD,Dall绘画页面的任务列表全改成瀑布流组件\\n\\n注意:当前站点仅为开源项目 \\u003ca style=\\\"color: #F56C6C\\\" href=\\\"https://github.com/yangjian102621/chatgpt-plus\\\" target=\\\"_blank\\\"\\u003eChatPlus\\u003c/a\\u003e 的演示项目,本项目单纯就是给大家体验项目功能使用。\\n\\u003cstrong style=\\\"color: #F56C6C\\\"\\u003e体验额度用完之后请不要在当前站点进行任何充值操作!!!\\u003c/strong\\u003e\\n\\u003cstrong style=\\\"color: #F56C6C\\\"\\u003e体验额度用完之后请不要在当前站点进行任何充值操作!!!\\u003c/strong\\u003e\\n\\u003cstrong style=\\\"color: #F56C6C\\\"\\u003e体验额度用完之后请不要在当前站点进行任何充值操作!!!\\u003c/strong\\u003e\\n 如果觉得好用你就花几分钟自己部署一套,没有API KEY 的同学可以去下面几个推荐的中转站购买:\\n1、\\u003ca href=\\\"https://api.chat-plus.net\\\" target=\\\"_blank\\\"\\n style=\\\"font-size: 20px;color:#F56C6C\\\"\\u003ehttps://api.chat-plus.net\\u003c/a\\u003e\\n2、\\u003ca href=\\\"https://api.geekai.me\\\" target=\\\"_blank\\\"\\n style=\\\"font-size: 20px;color:#F56C6C\\\"\\u003ehttps://api.geekai.me\\u003c/a\\u003e\\n3、 \\u003ca href=\\\"https://gpt.bemore.lol\\\" target=\\\"_blank\\\"\\n style=\\\"font-size: 20px;color:#F56C6C\\\"\\u003ehttps://gpt.bemore.lol\\u003c/a\\u003e\\n支持MidJourney,GPT,Claude,Google Gemmi,以及国内各个厂家的大模型,现在有超级优惠,价格远低于 OpenAI 官方。关于中转 API 的优势和劣势请参考 [中转API技术原理](https://ai.r9it.com/docs/install/errors-handle.html#%E8%B0%83%E7%94%A8%E4%B8%AD%E8%BD%AC-api-%E6%8A%A5%E9%94%99%E6%97%A0%E5%8F%AF%E7%94%A8%E6%B8%A0%E9%81%93)。GPT-3.5,GPT-4,DALL-E3 绘图......你都可以随意使用,无需魔法。\\n接入教程: \\u003ca href=\\\"https://ai.r9it.com/docs/install/\\\" target=\\\"_blank\\\"\\n style=\\\"font-size: 20px;color:#F56C6C\\\"\\u003ehttps://ai.r9it.com/docs/install/\\u003c/a\\u003e\\n本项目源码地址:\\u003ca href=\\\"https://github.com/yangjian102621/chatgpt-plus\\\" target=\\\"_blank\\\"\\u003ehttps://github.com/yangjian102621/chatgpt-plus\\u003c/a\\u003e\",\"updated\":true}');
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的结构 `chatgpt_dall_jobs`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `chatgpt_dall_jobs`;
|
||||||
|
CREATE TABLE `chatgpt_dall_jobs` (
|
||||||
|
`id` int NOT NULL,
|
||||||
|
`user_id` int NOT NULL COMMENT '用户ID',
|
||||||
|
`prompt` varchar(2000) NOT NULL COMMENT '提示词',
|
||||||
|
`img_url` varchar(255) NOT NULL COMMENT '图片地址',
|
||||||
|
`org_url` varchar(400) DEFAULT NULL COMMENT '原图地址',
|
||||||
|
`publish` tinyint(1) NOT NULL COMMENT '是否发布',
|
||||||
|
`power` smallint NOT NULL COMMENT '消耗算力',
|
||||||
|
`progress` smallint NOT NULL COMMENT '任务进度',
|
||||||
|
`err_msg` varchar(255) NOT NULL COMMENT '错误信息',
|
||||||
|
`created_at` datetime NOT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='DALLE 绘图任务表';
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的结构 `chatgpt_files`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `chatgpt_files`;
|
||||||
|
CREATE TABLE `chatgpt_files` (
|
||||||
|
`id` int NOT NULL,
|
||||||
|
`user_id` int NOT NULL COMMENT '用户 ID',
|
||||||
|
`name` varchar(100) NOT NULL COMMENT '文件名',
|
||||||
|
`obj_key` varchar(100) DEFAULT NULL COMMENT '文件标识',
|
||||||
|
`url` varchar(255) NOT NULL COMMENT '文件地址',
|
||||||
|
`ext` varchar(10) NOT NULL COMMENT '文件后缀',
|
||||||
|
`size` bigint NOT NULL DEFAULT '0' COMMENT '文件大小',
|
||||||
|
`created_at` datetime NOT NULL COMMENT '创建时间'
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户文件表';
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的结构 `chatgpt_functions`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `chatgpt_functions`;
|
||||||
|
CREATE TABLE `chatgpt_functions` (
|
||||||
|
`id` int NOT NULL,
|
||||||
|
`name` varchar(30) NOT NULL COMMENT '函数名称',
|
||||||
|
`label` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '函数标签',
|
||||||
|
`description` varchar(255) DEFAULT NULL COMMENT '函数描述',
|
||||||
|
`parameters` text COMMENT '函数参数(JSON)',
|
||||||
|
`token` varchar(255) DEFAULT NULL COMMENT 'API授权token',
|
||||||
|
`action` varchar(255) DEFAULT NULL COMMENT '函数处理 API',
|
||||||
|
`enabled` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否启用'
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='函数插件表';
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 转存表中的数据 `chatgpt_functions`
|
||||||
|
--
|
||||||
|
|
||||||
|
INSERT INTO `chatgpt_functions` (`id`, `name`, `label`, `description`, `parameters`, `token`, `action`, `enabled`) VALUES
|
||||||
|
(1, 'weibo', '微博热搜', '新浪微博热搜榜,微博当日热搜榜单', '{\"type\":\"object\",\"properties\":{}}', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHBpcmVkIjowLCJ1c2VyX2lkIjowfQ.tLAGkF8XWh_G-oQzevpIodsswtPByBLoAZDz_eWuBgw', 'http://localhost:5678/api/function/weibo', 0),
|
||||||
|
(2, 'zaobao', '今日早报', '每日早报,获取当天新闻事件列表', '{\"type\":\"object\",\"properties\":{}}', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHBpcmVkIjowLCJ1c2VyX2lkIjowfQ.tLAGkF8XWh_G-oQzevpIodsswtPByBLoAZDz_eWuBgw', 'http://localhost:5678/api/function/zaobao', 0),
|
||||||
|
(3, 'dalle3', 'DALLE3', 'AI 绘画工具,根据输入的绘图描述用 AI 工具进行绘画', '{\"type\":\"object\",\"required\":[\"prompt\"],\"properties\":{\"prompt\":{\"type\":\"string\",\"description\":\"绘画提示词\"}}}', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHBpcmVkIjowLCJ1c2VyX2lkIjowfQ.tLAGkF8XWh_G-oQzevpIodsswtPByBLoAZDz_eWuBgw', 'http://localhost:5678/api/function/dalle3', 0);
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的结构 `chatgpt_invite_codes`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `chatgpt_invite_codes`;
|
||||||
|
CREATE TABLE `chatgpt_invite_codes` (
|
||||||
|
`id` int NOT NULL,
|
||||||
|
`user_id` int NOT NULL COMMENT '用户ID',
|
||||||
|
`code` char(8) NOT NULL COMMENT '邀请码',
|
||||||
|
`hits` int NOT NULL COMMENT '点击次数',
|
||||||
|
`reg_num` smallint NOT NULL COMMENT '注册数量',
|
||||||
|
`created_at` datetime NOT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户邀请码';
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的结构 `chatgpt_invite_logs`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `chatgpt_invite_logs`;
|
||||||
|
CREATE TABLE `chatgpt_invite_logs` (
|
||||||
|
`id` int NOT NULL,
|
||||||
|
`inviter_id` int NOT NULL COMMENT '邀请人ID',
|
||||||
|
`user_id` int NOT NULL COMMENT '注册用户ID',
|
||||||
|
`username` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户名',
|
||||||
|
`invite_code` char(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '邀请码',
|
||||||
|
`remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '备注',
|
||||||
|
`created_at` datetime NOT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='邀请注册日志';
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的结构 `chatgpt_menus`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `chatgpt_menus`;
|
||||||
|
CREATE TABLE `chatgpt_menus` (
|
||||||
|
`id` int NOT NULL,
|
||||||
|
`name` varchar(30) NOT NULL COMMENT '菜单名称',
|
||||||
|
`icon` varchar(150) NOT NULL COMMENT '菜单图标',
|
||||||
|
`url` varchar(100) NOT NULL COMMENT '地址',
|
||||||
|
`sort_num` smallint NOT NULL COMMENT '排序',
|
||||||
|
`enabled` tinyint(1) NOT NULL COMMENT '是否启用'
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='前端菜单表';
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 转存表中的数据 `chatgpt_menus`
|
||||||
|
--
|
||||||
|
|
||||||
|
INSERT INTO `chatgpt_menus` (`id`, `name`, `icon`, `url`, `sort_num`, `enabled`) VALUES
|
||||||
|
(1, '对话聊天', '/images/menu/chat.png', '/chat', 1, 1),
|
||||||
|
(5, 'MJ 绘画', '/images/menu/mj.png', '/mj', 2, 1),
|
||||||
|
(6, 'SD 绘画', '/images/menu/sd.png', '/sd', 3, 1),
|
||||||
|
(7, '算力日志', '/images/menu/log.png', '/powerLog', 8, 1),
|
||||||
|
(8, '应用中心', '/images/menu/app.png', '/apps', 7, 1),
|
||||||
|
(9, '画廊', '/images/menu/img-wall.png', '/images-wall', 5, 1),
|
||||||
|
(10, '会员计划', '/images/menu/member.png', '/member', 9, 1),
|
||||||
|
(11, '分享计划', '/images/menu/share.png', '/invite', 10, 1),
|
||||||
|
(12, '思维导图', '/images/menu/xmind.png', '/xmind', 6, 1),
|
||||||
|
(13, 'DALLE', '/images/menu/dalle.png', '/dalle', 4, 1);
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的结构 `chatgpt_mj_jobs`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `chatgpt_mj_jobs`;
|
||||||
|
CREATE TABLE `chatgpt_mj_jobs` (
|
||||||
|
`id` int NOT NULL,
|
||||||
|
`user_id` int NOT NULL COMMENT '用户 ID',
|
||||||
|
`task_id` varchar(20) DEFAULT NULL COMMENT '任务 ID',
|
||||||
|
`type` varchar(20) DEFAULT 'image' COMMENT '任务类别',
|
||||||
|
`message_id` char(40) NOT NULL COMMENT '消息 ID',
|
||||||
|
`channel_id` char(40) DEFAULT NULL COMMENT '频道ID',
|
||||||
|
`reference_id` char(40) DEFAULT NULL COMMENT '引用消息 ID',
|
||||||
|
`prompt` varchar(2000) NOT NULL COMMENT '会话提示词',
|
||||||
|
`img_url` varchar(400) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '图片URL',
|
||||||
|
`org_url` varchar(400) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '原始图片地址',
|
||||||
|
`hash` varchar(100) DEFAULT NULL COMMENT 'message hash',
|
||||||
|
`progress` smallint DEFAULT '0' COMMENT '任务进度',
|
||||||
|
`use_proxy` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否使用反代',
|
||||||
|
`publish` tinyint(1) NOT NULL COMMENT '是否发布',
|
||||||
|
`err_msg` varchar(255) DEFAULT NULL COMMENT '错误信息',
|
||||||
|
`power` smallint NOT NULL DEFAULT '0' COMMENT '消耗算力',
|
||||||
|
`created_at` datetime NOT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='MidJourney 任务表';
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的结构 `chatgpt_orders`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `chatgpt_orders`;
|
||||||
|
CREATE TABLE `chatgpt_orders` (
|
||||||
|
`id` int NOT NULL,
|
||||||
|
`user_id` int NOT NULL COMMENT '用户ID',
|
||||||
|
`product_id` int NOT NULL COMMENT '产品ID',
|
||||||
|
`username` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户明',
|
||||||
|
`order_no` varchar(30) NOT NULL COMMENT '订单ID',
|
||||||
|
`trade_no` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '支付平台交易流水号',
|
||||||
|
`subject` varchar(100) NOT NULL COMMENT '订单产品',
|
||||||
|
`amount` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '订单金额',
|
||||||
|
`status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '订单状态(0:待支付,1:已扫码,2:支付失败)',
|
||||||
|
`remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '备注',
|
||||||
|
`pay_time` int DEFAULT NULL COMMENT '支付时间',
|
||||||
|
`pay_way` varchar(20) NOT NULL COMMENT '支付方式',
|
||||||
|
`created_at` datetime NOT NULL,
|
||||||
|
`updated_at` datetime NOT NULL,
|
||||||
|
`deleted_at` datetime DEFAULT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='充值订单表';
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的结构 `chatgpt_power_logs`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `chatgpt_power_logs`;
|
||||||
|
CREATE TABLE `chatgpt_power_logs` (
|
||||||
|
`id` int NOT NULL,
|
||||||
|
`user_id` int NOT NULL COMMENT '用户ID',
|
||||||
|
`username` varchar(30) NOT NULL COMMENT '用户名',
|
||||||
|
`type` tinyint(1) NOT NULL COMMENT '类型(1:充值,2:消费,3:退费)',
|
||||||
|
`amount` smallint NOT NULL COMMENT '算力数值',
|
||||||
|
`balance` int NOT NULL COMMENT '余额',
|
||||||
|
`model` varchar(30) NOT NULL COMMENT '模型',
|
||||||
|
`remark` varchar(255) NOT NULL COMMENT '备注',
|
||||||
|
`mark` tinyint(1) NOT NULL COMMENT '资金类型(0:支出,1:收入)',
|
||||||
|
`created_at` datetime NOT NULL COMMENT '创建时间'
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户算力消费日志';
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的结构 `chatgpt_products`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `chatgpt_products`;
|
||||||
|
CREATE TABLE `chatgpt_products` (
|
||||||
|
`id` int NOT NULL,
|
||||||
|
`name` varchar(30) NOT NULL COMMENT '名称',
|
||||||
|
`price` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '价格',
|
||||||
|
`discount` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '优惠金额',
|
||||||
|
`days` smallint NOT NULL DEFAULT '0' COMMENT '延长天数',
|
||||||
|
`power` int NOT NULL DEFAULT '0' COMMENT '增加算力值',
|
||||||
|
`enabled` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否启动',
|
||||||
|
`sales` int NOT NULL DEFAULT '0' COMMENT '销量',
|
||||||
|
`sort_num` tinyint NOT NULL DEFAULT '0' COMMENT '排序',
|
||||||
|
`created_at` datetime NOT NULL,
|
||||||
|
`updated_at` datetime NOT NULL,
|
||||||
|
`app_url` varchar(255) DEFAULT NULL COMMENT 'App跳转地址',
|
||||||
|
`url` varchar(255) DEFAULT NULL COMMENT '跳转地址'
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='会员套餐表';
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 转存表中的数据 `chatgpt_products`
|
||||||
|
--
|
||||||
|
|
||||||
|
INSERT INTO `chatgpt_products` (`id`, `name`, `price`, `discount`, `days`, `power`, `enabled`, `sales`, `sort_num`, `created_at`, `updated_at`, `app_url`, `url`) VALUES
|
||||||
|
(1, '会员1个月', 1999.90, 1999.00, 30, 0, 1, 0, 0, '2023-08-28 10:48:57', '2024-04-26 16:09:06', NULL, NULL),
|
||||||
|
(2, '会员3个月', 3940.00, 30.00, 90, 0, 1, 0, 0, '2023-08-28 10:52:22', '2024-03-22 17:56:10', NULL, NULL),
|
||||||
|
(3, '会员6个月', 5990.00, 100.00, 180, 0, 1, 0, 0, '2023-08-28 10:53:39', '2024-03-22 17:56:15', NULL, NULL),
|
||||||
|
(4, '会员12个月', 9980.00, 200.00, 365, 0, 1, 0, 0, '2023-08-28 10:54:15', '2024-03-22 17:56:23', NULL, NULL),
|
||||||
|
(5, '100次点卡', 1999.00, 3.00, 0, 100, 1, 0, 0, '2023-08-28 10:55:08', '2024-03-22 17:56:37', NULL, NULL),
|
||||||
|
(6, '200次点卡', 2999.00, 10.00, 0, 200, 1, 0, 0, '1970-01-01 08:00:00', '2024-03-22 17:56:41', NULL, NULL);
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的结构 `chatgpt_rewards`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `chatgpt_rewards`;
|
||||||
|
CREATE TABLE `chatgpt_rewards` (
|
||||||
|
`id` int NOT NULL,
|
||||||
|
`user_id` int NOT NULL COMMENT '用户 ID',
|
||||||
|
`tx_id` char(36) NOT NULL COMMENT '交易 ID',
|
||||||
|
`amount` decimal(10,2) NOT NULL COMMENT '打赏金额',
|
||||||
|
`remark` varchar(80) NOT NULL COMMENT '备注',
|
||||||
|
`status` tinyint(1) NOT NULL COMMENT '核销状态,0:未核销,1:已核销',
|
||||||
|
`exchange` varchar(255) NOT NULL COMMENT '兑换详情(json)',
|
||||||
|
`created_at` datetime NOT NULL,
|
||||||
|
`updated_at` datetime NOT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户打赏';
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的结构 `chatgpt_sd_jobs`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `chatgpt_sd_jobs`;
|
||||||
|
CREATE TABLE `chatgpt_sd_jobs` (
|
||||||
|
`id` int NOT NULL,
|
||||||
|
`user_id` int NOT NULL COMMENT '用户 ID',
|
||||||
|
`type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT 'txt2img' COMMENT '任务类别',
|
||||||
|
`task_id` char(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '任务 ID',
|
||||||
|
`prompt` varchar(2000) NOT NULL COMMENT '会话提示词',
|
||||||
|
`img_url` varchar(255) DEFAULT NULL COMMENT '图片URL',
|
||||||
|
`params` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci COMMENT '绘画参数json',
|
||||||
|
`progress` smallint DEFAULT '0' COMMENT '任务进度',
|
||||||
|
`publish` tinyint(1) NOT NULL COMMENT '是否发布',
|
||||||
|
`err_msg` varchar(255) DEFAULT NULL COMMENT '错误信息',
|
||||||
|
`power` smallint NOT NULL DEFAULT '0' COMMENT '消耗算力',
|
||||||
|
`created_at` datetime NOT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Stable Diffusion 任务表';
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的结构 `chatgpt_users`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `chatgpt_users`;
|
||||||
|
CREATE TABLE `chatgpt_users` (
|
||||||
|
`id` int NOT NULL,
|
||||||
|
`username` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户名',
|
||||||
|
`nickname` varchar(30) NOT NULL COMMENT '昵称',
|
||||||
|
`password` char(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '密码',
|
||||||
|
`avatar` varchar(100) NOT NULL COMMENT '头像',
|
||||||
|
`salt` char(12) NOT NULL COMMENT '密码盐',
|
||||||
|
`power` int NOT NULL DEFAULT '0' COMMENT '剩余算力',
|
||||||
|
`expired_time` int NOT NULL COMMENT '用户过期时间',
|
||||||
|
`status` tinyint(1) NOT NULL COMMENT '当前状态',
|
||||||
|
`chat_config_json` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '聊天配置json',
|
||||||
|
`chat_roles_json` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '聊天角色 json',
|
||||||
|
`chat_models_json` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'AI模型 json',
|
||||||
|
`last_login_at` int NOT NULL COMMENT '最后登录时间',
|
||||||
|
`vip` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否会员',
|
||||||
|
`last_login_ip` char(16) NOT NULL COMMENT '最后登录 IP',
|
||||||
|
`created_at` datetime NOT NULL,
|
||||||
|
`updated_at` datetime NOT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户表';
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 转存表中的数据 `chatgpt_users`
|
||||||
|
--
|
||||||
|
|
||||||
|
INSERT INTO `chatgpt_users` (`id`, `username`, `nickname`, `password`, `avatar`, `salt`, `power`, `expired_time`, `status`, `chat_config_json`, `chat_roles_json`, `chat_models_json`, `last_login_at`, `vip`, `last_login_ip`, `created_at`, `updated_at`) VALUES
|
||||||
|
(4, '18575670125', '极客学长@830270', 'ccc3fb7ab61b8b5d096a4a166ae21d121fc38c71bbd1be6173d9ab973214a63b', 'http://localhost:5678/static/upload/2024/5/1715651569509929.png', 'ueedue5l', 5054, 1717292086, 1, '{\"api_keys\":{\"Azure\":\"\",\"ChatGLM\":\"\",\"OpenAI\":\"\"}}', '[\"red_book\",\"gpt\",\"seller\",\"artist\",\"lu_xun\",\"girl_friend\",\"psychiatrist\",\"teacher\",\"programmer\",\"test\"]', '[1,11]', 1714464552, 1, '::1', '2023-06-12 16:47:17', '2024-05-14 09:52:52'),
|
||||||
|
(5, 'yangjian102621@gmail.com', '极客学长@486041', '75d1a22f33e1ffffb7943946b6b8d5177d5ecd685d3cef1b468654038b0a8c22', '/images/avatar/user.png', '2q8ugxzk', 100, 0, 1, '', '[\"gpt\",\"programmer\"]', '[11,7,1,10,12,19,18,17,3]', 0, 0, '', '2024-04-23 09:17:26', '2024-04-23 09:17:26'),
|
||||||
|
(8, 'yangjian102623@gmail.com', '极客学长@714931', 'f8f0e0abf146569217273ea0712a0f9b6cbbe7d943a1d9bd5f91c55e6d8c05d1', '/images/avatar/user.png', 'geuddq7f', 100, 0, 1, '', '[\"gpt\"]', '[11,7,1,10,12,19,18,17,3]', 0, 0, '', '2024-04-26 15:19:28', '2024-04-26 15:19:28'),
|
||||||
|
(9, '1234567', '极客学长@604526', '858e2afec79e1d6364f4567f945f2310024896d9aa45dd944efa95a0c31e4d08', '/images/avatar/user.png', '00qawlos', 100, 0, 1, '', '[\"gpt\"]', '[11,7,1,10,12,19,18,17,3]', 0, 0, '', '2024-04-26 15:21:06', '2024-04-26 15:21:06');
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的结构 `chatgpt_user_login_logs`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `chatgpt_user_login_logs`;
|
||||||
|
CREATE TABLE `chatgpt_user_login_logs` (
|
||||||
|
`id` int NOT NULL,
|
||||||
|
`user_id` int NOT NULL COMMENT '用户ID',
|
||||||
|
`username` varchar(30) NOT NULL COMMENT '用户名',
|
||||||
|
`login_ip` char(16) NOT NULL COMMENT '登录IP',
|
||||||
|
`login_address` varchar(30) NOT NULL COMMENT '登录地址',
|
||||||
|
`created_at` datetime NOT NULL,
|
||||||
|
`updated_at` datetime NOT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户登录日志';
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 转储表的索引
|
||||||
|
--
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的索引 `chatgpt_admin_users`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_admin_users`
|
||||||
|
ADD PRIMARY KEY (`id`) USING BTREE,
|
||||||
|
ADD UNIQUE KEY `username` (`username`) USING BTREE;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的索引 `chatgpt_api_keys`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_api_keys`
|
||||||
|
ADD PRIMARY KEY (`id`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的索引 `chatgpt_chat_history`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_chat_history`
|
||||||
|
ADD PRIMARY KEY (`id`),
|
||||||
|
ADD KEY `chat_id` (`chat_id`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的索引 `chatgpt_chat_items`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_chat_items`
|
||||||
|
ADD PRIMARY KEY (`id`),
|
||||||
|
ADD UNIQUE KEY `chat_id` (`chat_id`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的索引 `chatgpt_chat_models`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_chat_models`
|
||||||
|
ADD PRIMARY KEY (`id`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的索引 `chatgpt_chat_roles`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_chat_roles`
|
||||||
|
ADD PRIMARY KEY (`id`),
|
||||||
|
ADD UNIQUE KEY `marker` (`marker`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的索引 `chatgpt_configs`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_configs`
|
||||||
|
ADD PRIMARY KEY (`id`),
|
||||||
|
ADD UNIQUE KEY `marker` (`marker`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的索引 `chatgpt_dall_jobs`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_dall_jobs`
|
||||||
|
ADD PRIMARY KEY (`id`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的索引 `chatgpt_files`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_files`
|
||||||
|
ADD PRIMARY KEY (`id`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的索引 `chatgpt_functions`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_functions`
|
||||||
|
ADD PRIMARY KEY (`id`),
|
||||||
|
ADD UNIQUE KEY `name` (`name`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的索引 `chatgpt_invite_codes`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_invite_codes`
|
||||||
|
ADD PRIMARY KEY (`id`),
|
||||||
|
ADD UNIQUE KEY `code` (`code`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的索引 `chatgpt_invite_logs`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_invite_logs`
|
||||||
|
ADD PRIMARY KEY (`id`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的索引 `chatgpt_menus`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_menus`
|
||||||
|
ADD PRIMARY KEY (`id`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的索引 `chatgpt_mj_jobs`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_mj_jobs`
|
||||||
|
ADD PRIMARY KEY (`id`),
|
||||||
|
ADD UNIQUE KEY `task_id` (`task_id`),
|
||||||
|
ADD KEY `message_id` (`message_id`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的索引 `chatgpt_orders`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_orders`
|
||||||
|
ADD PRIMARY KEY (`id`),
|
||||||
|
ADD UNIQUE KEY `order_no` (`order_no`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的索引 `chatgpt_power_logs`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_power_logs`
|
||||||
|
ADD PRIMARY KEY (`id`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的索引 `chatgpt_products`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_products`
|
||||||
|
ADD PRIMARY KEY (`id`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的索引 `chatgpt_rewards`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_rewards`
|
||||||
|
ADD PRIMARY KEY (`id`),
|
||||||
|
ADD UNIQUE KEY `tx_id` (`tx_id`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的索引 `chatgpt_sd_jobs`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_sd_jobs`
|
||||||
|
ADD PRIMARY KEY (`id`),
|
||||||
|
ADD UNIQUE KEY `task_id` (`task_id`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的索引 `chatgpt_users`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_users`
|
||||||
|
ADD PRIMARY KEY (`id`),
|
||||||
|
ADD UNIQUE KEY `username` (`username`),
|
||||||
|
ADD UNIQUE KEY `username_2` (`username`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 表的索引 `chatgpt_user_login_logs`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_user_login_logs`
|
||||||
|
ADD PRIMARY KEY (`id`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 在导出的表使用AUTO_INCREMENT
|
||||||
|
--
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 使用表AUTO_INCREMENT `chatgpt_admin_users`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_admin_users`
|
||||||
|
MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=113;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 使用表AUTO_INCREMENT `chatgpt_api_keys`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_api_keys`
|
||||||
|
MODIFY `id` int NOT NULL AUTO_INCREMENT;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 使用表AUTO_INCREMENT `chatgpt_chat_history`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_chat_history`
|
||||||
|
MODIFY `id` bigint NOT NULL AUTO_INCREMENT;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 使用表AUTO_INCREMENT `chatgpt_chat_items`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_chat_items`
|
||||||
|
MODIFY `id` int NOT NULL AUTO_INCREMENT;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 使用表AUTO_INCREMENT `chatgpt_chat_models`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_chat_models`
|
||||||
|
MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=37;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 使用表AUTO_INCREMENT `chatgpt_chat_roles`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_chat_roles`
|
||||||
|
MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=131;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 使用表AUTO_INCREMENT `chatgpt_configs`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_configs`
|
||||||
|
MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=4;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 使用表AUTO_INCREMENT `chatgpt_dall_jobs`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_dall_jobs`
|
||||||
|
MODIFY `id` int NOT NULL AUTO_INCREMENT;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 使用表AUTO_INCREMENT `chatgpt_files`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_files`
|
||||||
|
MODIFY `id` int NOT NULL AUTO_INCREMENT;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 使用表AUTO_INCREMENT `chatgpt_functions`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_functions`
|
||||||
|
MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=4;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 使用表AUTO_INCREMENT `chatgpt_invite_codes`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_invite_codes`
|
||||||
|
MODIFY `id` int NOT NULL AUTO_INCREMENT;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 使用表AUTO_INCREMENT `chatgpt_invite_logs`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_invite_logs`
|
||||||
|
MODIFY `id` int NOT NULL AUTO_INCREMENT;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 使用表AUTO_INCREMENT `chatgpt_menus`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_menus`
|
||||||
|
MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=14;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 使用表AUTO_INCREMENT `chatgpt_mj_jobs`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_mj_jobs`
|
||||||
|
MODIFY `id` int NOT NULL AUTO_INCREMENT;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 使用表AUTO_INCREMENT `chatgpt_orders`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_orders`
|
||||||
|
MODIFY `id` int NOT NULL AUTO_INCREMENT;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 使用表AUTO_INCREMENT `chatgpt_power_logs`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_power_logs`
|
||||||
|
MODIFY `id` int NOT NULL AUTO_INCREMENT;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 使用表AUTO_INCREMENT `chatgpt_products`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_products`
|
||||||
|
MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=7;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 使用表AUTO_INCREMENT `chatgpt_rewards`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_rewards`
|
||||||
|
MODIFY `id` int NOT NULL AUTO_INCREMENT;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 使用表AUTO_INCREMENT `chatgpt_sd_jobs`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_sd_jobs`
|
||||||
|
MODIFY `id` int NOT NULL AUTO_INCREMENT;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 使用表AUTO_INCREMENT `chatgpt_users`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_users`
|
||||||
|
MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=10;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- 使用表AUTO_INCREMENT `chatgpt_user_login_logs`
|
||||||
|
--
|
||||||
|
ALTER TABLE `chatgpt_user_login_logs`
|
||||||
|
MODIFY `id` int NOT NULL AUTO_INCREMENT;
|
||||||
|
COMMIT;
|
||||||
|
|
||||||
|
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
|
||||||
|
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
|
||||||
|
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
@ -6,4 +6,4 @@ VUE_APP_ADMIN_USER=admin
|
|||||||
VUE_APP_ADMIN_PASS=admin123
|
VUE_APP_ADMIN_PASS=admin123
|
||||||
VUE_APP_KEY_PREFIX=ChatPLUS_DEV_
|
VUE_APP_KEY_PREFIX=ChatPLUS_DEV_
|
||||||
VUE_APP_TITLE="Geek-AI 创作系统"
|
VUE_APP_TITLE="Geek-AI 创作系统"
|
||||||
VUE_APP_VERSION=v4.0.5
|
VUE_APP_VERSION=v4.0.6
|
||||||
|
@ -2,4 +2,4 @@ VUE_APP_API_HOST=
|
|||||||
VUE_APP_WS_HOST=
|
VUE_APP_WS_HOST=
|
||||||
VUE_APP_KEY_PREFIX=ChatPLUS_
|
VUE_APP_KEY_PREFIX=ChatPLUS_
|
||||||
VUE_APP_TITLE="Geek-AI 创作系统"
|
VUE_APP_TITLE="Geek-AI 创作系统"
|
||||||
VUE_APP_VERSION=v4.0.5
|
VUE_APP_VERSION=v4.0.6
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
"markdown-it-mathjax": "^2.0.0",
|
"markdown-it-mathjax": "^2.0.0",
|
||||||
"markmap-common": "^0.16.0",
|
"markmap-common": "^0.16.0",
|
||||||
"markmap-lib": "^0.16.1",
|
"markmap-lib": "^0.16.1",
|
||||||
|
"markmap-toolbar": "^0.17.0",
|
||||||
"markmap-view": "^0.16.0",
|
"markmap-view": "^0.16.0",
|
||||||
"md-editor-v3": "^2.2.1",
|
"md-editor-v3": "^2.2.1",
|
||||||
"mitt": "^3.0.1",
|
"mitt": "^3.0.1",
|
||||||
@ -32,7 +33,7 @@
|
|||||||
"qs": "^6.11.1",
|
"qs": "^6.11.1",
|
||||||
"sortablejs": "^1.15.0",
|
"sortablejs": "^1.15.0",
|
||||||
"three": "^0.128.0",
|
"three": "^0.128.0",
|
||||||
"v3-waterfall": "^1.2.1",
|
"v3-waterfall": "^1.3.3",
|
||||||
"vant": "^4.5.0",
|
"vant": "^4.5.0",
|
||||||
"vue": "^3.2.13",
|
"vue": "^3.2.13",
|
||||||
"vue-router": "^4.0.15"
|
"vue-router": "^4.0.15"
|
||||||
|
BIN
web/public/images/img-placeholder.jpg
Normal file
BIN
web/public/images/img-placeholder.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.2 KiB |
@ -6,7 +6,7 @@
|
|||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no">
|
<meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no">
|
||||||
<link rel="icon" href="/favicon.ico" type="image/x-icon">
|
<link rel="icon" href="/favicon.ico" type="image/x-icon">
|
||||||
<title>ChatGPT-Plus</title>
|
<title>Geek-AI 创作助手</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
@ -81,7 +81,281 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@import "task-list.styl"
|
.task-list-box {
|
||||||
|
width 100%
|
||||||
|
padding 10px
|
||||||
|
color #ffffff
|
||||||
|
overflow-x hidden
|
||||||
|
|
||||||
|
.task-list-inner {
|
||||||
|
.el-tabs {
|
||||||
|
--el-tabs-header-height: 55px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-tabs__item {
|
||||||
|
color: #fff;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-tabs .el-tabs__item.is-active {
|
||||||
|
color: #47FFF1;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-tabs .el-tabs__active-bar {
|
||||||
|
background-color: #47FFF1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-textarea {
|
||||||
|
--el-input-focus-border-color: #47FFF1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-textarea__inner {
|
||||||
|
background: transparent;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-input__wrapper {
|
||||||
|
background: transparent;
|
||||||
|
padding 5px
|
||||||
|
}
|
||||||
|
|
||||||
|
.text {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
color: #6b778c;
|
||||||
|
font-size: 15px
|
||||||
|
}
|
||||||
|
|
||||||
|
.param-line.pt {
|
||||||
|
padding-top 5px
|
||||||
|
padding-bottom 5px
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-item-inner {
|
||||||
|
display flex
|
||||||
|
align-items: center
|
||||||
|
|
||||||
|
.el-icon {
|
||||||
|
margin-left 10px
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-form-item__label {
|
||||||
|
color #ffffff
|
||||||
|
}
|
||||||
|
|
||||||
|
// 图片上传样式
|
||||||
|
|
||||||
|
.img-inline {
|
||||||
|
display flex
|
||||||
|
|
||||||
|
.img-uploader {
|
||||||
|
.el-upload {
|
||||||
|
border: 1px dashed var(--el-border-color);
|
||||||
|
border-radius: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
width 120px;
|
||||||
|
transition: var(--el-transition-duration-fast);
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-color: var(--el-color-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-icon.uploader-icon {
|
||||||
|
font-size: 28px
|
||||||
|
color: #8c939d
|
||||||
|
width 100%
|
||||||
|
height: 120px
|
||||||
|
text-align: center
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.img-list-box {
|
||||||
|
display flex
|
||||||
|
|
||||||
|
.img-item {
|
||||||
|
width 120px
|
||||||
|
position relative
|
||||||
|
margin-right 10px
|
||||||
|
|
||||||
|
.el-image {
|
||||||
|
width 120px
|
||||||
|
height 120px
|
||||||
|
border-radius 5px
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-button {
|
||||||
|
position absolute
|
||||||
|
right 5px
|
||||||
|
top 5px
|
||||||
|
width 20px
|
||||||
|
height 20px
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-row.text-info {
|
||||||
|
width 100%
|
||||||
|
padding 10px 0
|
||||||
|
|
||||||
|
.el-tag {
|
||||||
|
margin-right 10px
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提交按钮
|
||||||
|
|
||||||
|
.submit-btn {
|
||||||
|
display flex
|
||||||
|
margin: 20px 0
|
||||||
|
|
||||||
|
.el-button {
|
||||||
|
width 200px
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 任务列表
|
||||||
|
|
||||||
|
.job-list-box {
|
||||||
|
|
||||||
|
@import "running-job-list.styl"
|
||||||
|
|
||||||
|
.finish-job-list {
|
||||||
|
#waterfall {
|
||||||
|
display flex
|
||||||
|
justify-content center
|
||||||
|
padding-top 20px
|
||||||
|
flex-flow column
|
||||||
|
|
||||||
|
|
||||||
|
.job-item {
|
||||||
|
width 100%
|
||||||
|
height 100%
|
||||||
|
border 1px solid #666666
|
||||||
|
padding 6px
|
||||||
|
overflow hidden
|
||||||
|
border-radius 6px
|
||||||
|
transition: all 0.3s ease; /* 添加过渡效果 */
|
||||||
|
position relative
|
||||||
|
|
||||||
|
.opt {
|
||||||
|
.opt-line {
|
||||||
|
margin 6px 0
|
||||||
|
|
||||||
|
ul {
|
||||||
|
display flex
|
||||||
|
flex-flow row
|
||||||
|
|
||||||
|
li {
|
||||||
|
margin-right 6px
|
||||||
|
|
||||||
|
a {
|
||||||
|
padding 3px 0
|
||||||
|
width 40px
|
||||||
|
text-align center
|
||||||
|
border-radius 5px
|
||||||
|
display block
|
||||||
|
cursor pointer
|
||||||
|
background-color #4E5058
|
||||||
|
color #ffffff
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color #6D6F78
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.show-prompt {
|
||||||
|
font-size 20px
|
||||||
|
cursor pointer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.remove {
|
||||||
|
display none
|
||||||
|
position absolute
|
||||||
|
right 10px
|
||||||
|
top 10px
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
.remove {
|
||||||
|
display block
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.animate {
|
||||||
|
&:hover {
|
||||||
|
box-shadow: 0 0 10px rgba(71, 255, 241, 0.6); /* 添加阴影效果 */
|
||||||
|
transform: translateY(-10px); /* 向上移动10像素 */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.el-image {
|
||||||
|
width 100%
|
||||||
|
height 100%
|
||||||
|
overflow visible
|
||||||
|
|
||||||
|
.el-image-viewer__wrapper {
|
||||||
|
img {
|
||||||
|
width auto
|
||||||
|
height auto
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-slot {
|
||||||
|
display flex
|
||||||
|
flex-flow column
|
||||||
|
justify-content center
|
||||||
|
align-items center
|
||||||
|
min-height 200px
|
||||||
|
color #ffffff
|
||||||
|
|
||||||
|
.iconfont {
|
||||||
|
font-size 50px
|
||||||
|
margin-bottom 10px
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-image.upscale {
|
||||||
|
img {
|
||||||
|
height 310px
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-slot {
|
||||||
|
height 310px
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-image-viewer__wrapper {
|
||||||
|
img {
|
||||||
|
width auto
|
||||||
|
height auto
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-more-data {
|
||||||
|
text-align center
|
||||||
|
padding 30px
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -233,7 +233,280 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@import "task-list.styl"
|
.task-list-box {
|
||||||
|
width 100%
|
||||||
|
padding 10px
|
||||||
|
color #ffffff
|
||||||
|
overflow-x hidden
|
||||||
|
|
||||||
|
.task-list-inner {
|
||||||
|
.el-tabs {
|
||||||
|
--el-tabs-header-height: 55px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-tabs__item {
|
||||||
|
color: #fff;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-tabs .el-tabs__item.is-active {
|
||||||
|
color: #47FFF1;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-tabs .el-tabs__active-bar {
|
||||||
|
background-color: #47FFF1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-textarea {
|
||||||
|
--el-input-focus-border-color: #47FFF1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-textarea__inner {
|
||||||
|
background: transparent;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-input__wrapper {
|
||||||
|
background: transparent;
|
||||||
|
padding 5px
|
||||||
|
}
|
||||||
|
|
||||||
|
.text {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
color: #6b778c;
|
||||||
|
font-size: 15px
|
||||||
|
}
|
||||||
|
|
||||||
|
.param-line.pt {
|
||||||
|
padding-top 5px
|
||||||
|
padding-bottom 5px
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-item-inner {
|
||||||
|
display flex
|
||||||
|
align-items: center
|
||||||
|
|
||||||
|
.el-icon {
|
||||||
|
margin-left 10px
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-form-item__label {
|
||||||
|
color #ffffff
|
||||||
|
}
|
||||||
|
|
||||||
|
// 图片上传样式
|
||||||
|
|
||||||
|
.img-inline {
|
||||||
|
display flex
|
||||||
|
|
||||||
|
.img-uploader {
|
||||||
|
.el-upload {
|
||||||
|
border: 1px dashed var(--el-border-color);
|
||||||
|
border-radius: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
width 120px;
|
||||||
|
transition: var(--el-transition-duration-fast);
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-color: var(--el-color-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-icon.uploader-icon {
|
||||||
|
font-size: 28px
|
||||||
|
color: #8c939d
|
||||||
|
width 100%
|
||||||
|
height: 120px
|
||||||
|
text-align: center
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.img-list-box {
|
||||||
|
display flex
|
||||||
|
|
||||||
|
.img-item {
|
||||||
|
width 120px
|
||||||
|
position relative
|
||||||
|
margin-right 10px
|
||||||
|
|
||||||
|
.el-image {
|
||||||
|
width 120px
|
||||||
|
height 120px
|
||||||
|
border-radius 5px
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-button {
|
||||||
|
position absolute
|
||||||
|
right 5px
|
||||||
|
top 5px
|
||||||
|
width 20px
|
||||||
|
height 20px
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-row.text-info {
|
||||||
|
width 100%
|
||||||
|
padding 10px 0
|
||||||
|
|
||||||
|
.el-tag {
|
||||||
|
margin-right 10px
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提交按钮
|
||||||
|
|
||||||
|
.submit-btn {
|
||||||
|
display flex
|
||||||
|
margin: 20px 0
|
||||||
|
|
||||||
|
.el-button {
|
||||||
|
width 200px
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.job-list-box {
|
||||||
|
// 任务列表
|
||||||
|
@import "running-job-list.styl"
|
||||||
|
|
||||||
|
.finish-job-list {
|
||||||
|
#waterfall {
|
||||||
|
display flex
|
||||||
|
justify-content center
|
||||||
|
padding-top 20px
|
||||||
|
flex-flow column
|
||||||
|
|
||||||
|
.waterfall-item {
|
||||||
|
overflow visible
|
||||||
|
|
||||||
|
.job-item {
|
||||||
|
width 100%
|
||||||
|
height 100%
|
||||||
|
border 1px solid #666666
|
||||||
|
padding 6px
|
||||||
|
border-radius 6px
|
||||||
|
//position relative
|
||||||
|
|
||||||
|
.el-image {
|
||||||
|
overflow auto
|
||||||
|
}
|
||||||
|
|
||||||
|
.opt {
|
||||||
|
padding-top 5px
|
||||||
|
|
||||||
|
.opt-line {
|
||||||
|
margin 6px 0
|
||||||
|
|
||||||
|
ul {
|
||||||
|
display flex
|
||||||
|
flex-flow row
|
||||||
|
|
||||||
|
li {
|
||||||
|
margin-right 6px
|
||||||
|
|
||||||
|
a {
|
||||||
|
padding 3px 0
|
||||||
|
width 40px
|
||||||
|
text-align center
|
||||||
|
border-radius 5px
|
||||||
|
display block
|
||||||
|
cursor pointer
|
||||||
|
background-color #4E5058
|
||||||
|
color #ffffff
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color #6D6F78
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.show-prompt {
|
||||||
|
font-size 20px
|
||||||
|
cursor pointer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.remove {
|
||||||
|
display none
|
||||||
|
position absolute
|
||||||
|
right 10px
|
||||||
|
top 10px
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
.remove {
|
||||||
|
display block
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.el-image {
|
||||||
|
width 100%
|
||||||
|
height 100%
|
||||||
|
overflow visible
|
||||||
|
|
||||||
|
.el-image-viewer__wrapper {
|
||||||
|
img {
|
||||||
|
width auto
|
||||||
|
height auto
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-slot {
|
||||||
|
display flex
|
||||||
|
flex-flow column
|
||||||
|
justify-content center
|
||||||
|
align-items center
|
||||||
|
min-height 200px
|
||||||
|
color #ffffff
|
||||||
|
|
||||||
|
.iconfont {
|
||||||
|
font-size 50px
|
||||||
|
margin-bottom 10px
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-image.upscale {
|
||||||
|
img {
|
||||||
|
//height 310px
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-slot {
|
||||||
|
min-height 310px
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-image-viewer__wrapper {
|
||||||
|
img {
|
||||||
|
width auto
|
||||||
|
height auto
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-more-data {
|
||||||
|
text-align center
|
||||||
|
padding 30px
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -81,7 +81,281 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@import "task-list.styl"
|
.task-list-box {
|
||||||
|
width 100%
|
||||||
|
padding 10px
|
||||||
|
color #ffffff
|
||||||
|
overflow-x hidden
|
||||||
|
|
||||||
|
.task-list-inner {
|
||||||
|
.el-tabs {
|
||||||
|
--el-tabs-header-height: 55px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-tabs__item {
|
||||||
|
color: #fff;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-tabs .el-tabs__item.is-active {
|
||||||
|
color: #47FFF1;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-tabs .el-tabs__active-bar {
|
||||||
|
background-color: #47FFF1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-textarea {
|
||||||
|
--el-input-focus-border-color: #47FFF1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-textarea__inner {
|
||||||
|
background: transparent;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-input__wrapper {
|
||||||
|
background: transparent;
|
||||||
|
padding 5px
|
||||||
|
}
|
||||||
|
|
||||||
|
.text {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
color: #6b778c;
|
||||||
|
font-size: 15px
|
||||||
|
}
|
||||||
|
|
||||||
|
.param-line.pt {
|
||||||
|
padding-top 5px
|
||||||
|
padding-bottom 5px
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-item-inner {
|
||||||
|
display flex
|
||||||
|
align-items: center
|
||||||
|
|
||||||
|
.el-icon {
|
||||||
|
margin-left 10px
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-form-item__label {
|
||||||
|
color #ffffff
|
||||||
|
}
|
||||||
|
|
||||||
|
// 图片上传样式
|
||||||
|
|
||||||
|
.img-inline {
|
||||||
|
display flex
|
||||||
|
|
||||||
|
.img-uploader {
|
||||||
|
.el-upload {
|
||||||
|
border: 1px dashed var(--el-border-color);
|
||||||
|
border-radius: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
width 120px;
|
||||||
|
transition: var(--el-transition-duration-fast);
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-color: var(--el-color-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-icon.uploader-icon {
|
||||||
|
font-size: 28px
|
||||||
|
color: #8c939d
|
||||||
|
width 100%
|
||||||
|
height: 120px
|
||||||
|
text-align: center
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.img-list-box {
|
||||||
|
display flex
|
||||||
|
|
||||||
|
.img-item {
|
||||||
|
width 120px
|
||||||
|
position relative
|
||||||
|
margin-right 10px
|
||||||
|
|
||||||
|
.el-image {
|
||||||
|
width 120px
|
||||||
|
height 120px
|
||||||
|
border-radius 5px
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-button {
|
||||||
|
position absolute
|
||||||
|
right 5px
|
||||||
|
top 5px
|
||||||
|
width 20px
|
||||||
|
height 20px
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-row.text-info {
|
||||||
|
width 100%
|
||||||
|
padding 10px 0
|
||||||
|
|
||||||
|
.el-tag {
|
||||||
|
margin-right 10px
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提交按钮
|
||||||
|
|
||||||
|
.submit-btn {
|
||||||
|
display flex
|
||||||
|
margin: 20px 0
|
||||||
|
|
||||||
|
.el-button {
|
||||||
|
width 200px
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 任务列表
|
||||||
|
|
||||||
|
.job-list-box {
|
||||||
|
|
||||||
|
@import "running-job-list.styl"
|
||||||
|
|
||||||
|
.finish-job-list {
|
||||||
|
#waterfall {
|
||||||
|
display flex
|
||||||
|
justify-content center
|
||||||
|
padding-top 20px
|
||||||
|
flex-flow column
|
||||||
|
|
||||||
|
|
||||||
|
.job-item {
|
||||||
|
width 100%
|
||||||
|
height 100%
|
||||||
|
border 1px solid #666666
|
||||||
|
padding 6px
|
||||||
|
overflow hidden
|
||||||
|
border-radius 6px
|
||||||
|
transition: all 0.3s ease; /* 添加过渡效果 */
|
||||||
|
position relative
|
||||||
|
|
||||||
|
.opt {
|
||||||
|
.opt-line {
|
||||||
|
margin 6px 0
|
||||||
|
|
||||||
|
ul {
|
||||||
|
display flex
|
||||||
|
flex-flow row
|
||||||
|
|
||||||
|
li {
|
||||||
|
margin-right 6px
|
||||||
|
|
||||||
|
a {
|
||||||
|
padding 3px 0
|
||||||
|
width 40px
|
||||||
|
text-align center
|
||||||
|
border-radius 5px
|
||||||
|
display block
|
||||||
|
cursor pointer
|
||||||
|
background-color #4E5058
|
||||||
|
color #ffffff
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color #6D6F78
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.show-prompt {
|
||||||
|
font-size 20px
|
||||||
|
cursor pointer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.remove {
|
||||||
|
display none
|
||||||
|
position absolute
|
||||||
|
right 10px
|
||||||
|
top 10px
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
.remove {
|
||||||
|
display block
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.animate {
|
||||||
|
&:hover {
|
||||||
|
box-shadow: 0 0 10px rgba(71, 255, 241, 0.6); /* 添加阴影效果 */
|
||||||
|
transform: translateY(-10px); /* 向上移动10像素 */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.el-image {
|
||||||
|
width 100%
|
||||||
|
height 100%
|
||||||
|
overflow visible
|
||||||
|
|
||||||
|
.el-image-viewer__wrapper {
|
||||||
|
img {
|
||||||
|
width auto
|
||||||
|
height auto
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-slot {
|
||||||
|
display flex
|
||||||
|
flex-flow column
|
||||||
|
justify-content center
|
||||||
|
align-items center
|
||||||
|
min-height 200px
|
||||||
|
color #ffffff
|
||||||
|
|
||||||
|
.iconfont {
|
||||||
|
font-size 50px
|
||||||
|
margin-bottom 10px
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-image.upscale {
|
||||||
|
img {
|
||||||
|
height 310px
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-slot {
|
||||||
|
height 310px
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-image-viewer__wrapper {
|
||||||
|
img {
|
||||||
|
width auto
|
||||||
|
height auto
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-more-data {
|
||||||
|
text-align center
|
||||||
|
padding 30px
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@import "sd-task-dialog.styl"
|
@import "sd-task-dialog.styl"
|
||||||
|
@ -46,6 +46,10 @@
|
|||||||
overflow-y auto
|
overflow-y auto
|
||||||
overflow-x hidden
|
overflow-x hidden
|
||||||
|
|
||||||
|
.waterfall-over-message {
|
||||||
|
display none
|
||||||
|
}
|
||||||
|
|
||||||
.list-item {
|
.list-item {
|
||||||
|
|
||||||
.image {
|
.image {
|
||||||
|
@ -117,6 +117,7 @@
|
|||||||
display flex
|
display flex
|
||||||
justify-content center
|
justify-content center
|
||||||
align-items center
|
align-items center
|
||||||
|
position relative
|
||||||
|
|
||||||
.markmap {
|
.markmap {
|
||||||
width 100%
|
width 100%
|
||||||
@ -127,6 +128,27 @@
|
|||||||
//height 30px
|
//height 30px
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#toolbar {
|
||||||
|
position: absolute
|
||||||
|
bottom: 10px
|
||||||
|
right: 20px
|
||||||
|
|
||||||
|
.mm-toolbar {
|
||||||
|
display flex
|
||||||
|
flex-flow row
|
||||||
|
|
||||||
|
.mm-toolbar-brand {
|
||||||
|
display none
|
||||||
|
}
|
||||||
|
|
||||||
|
.mm-toolbar-item {
|
||||||
|
cursor pointer
|
||||||
|
color var(--el-color-white)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
39
web/src/assets/css/running-job-list.styl
Normal file
39
web/src/assets/css/running-job-list.styl
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
.running-job-list {
|
||||||
|
|
||||||
|
.running-job-box {
|
||||||
|
width 100%
|
||||||
|
display flex
|
||||||
|
flex-flow row
|
||||||
|
}
|
||||||
|
|
||||||
|
.job-item {
|
||||||
|
margin-right 10px
|
||||||
|
width 200px
|
||||||
|
height 200px
|
||||||
|
overflow hidden
|
||||||
|
padding 2px
|
||||||
|
background-color #555555
|
||||||
|
|
||||||
|
.job-item-inner {
|
||||||
|
position relative
|
||||||
|
height 100%
|
||||||
|
overflow hidden
|
||||||
|
|
||||||
|
.progress {
|
||||||
|
position absolute
|
||||||
|
width 100%
|
||||||
|
height 100%
|
||||||
|
top 0
|
||||||
|
left 0
|
||||||
|
display flex
|
||||||
|
justify-content center
|
||||||
|
align-items center
|
||||||
|
|
||||||
|
span {
|
||||||
|
font-size 20px
|
||||||
|
color #ffffff
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,215 +0,0 @@
|
|||||||
.task-list-box {
|
|
||||||
width: 100%;
|
|
||||||
padding: 10px;
|
|
||||||
color: #fff;
|
|
||||||
overflow-x: hidden;
|
|
||||||
}
|
|
||||||
.task-list-box .task-list-inner .el-tabs {
|
|
||||||
--el-tabs-header-height: 55px;
|
|
||||||
}
|
|
||||||
.task-list-box .task-list-inner .el-tabs__item {
|
|
||||||
color: #fff;
|
|
||||||
font-size: 18px;
|
|
||||||
}
|
|
||||||
.task-list-box .task-list-inner .title-tabs .el-tabs__item.is-active {
|
|
||||||
color: #47fff1;
|
|
||||||
font-size: 18px;
|
|
||||||
}
|
|
||||||
.task-list-box .task-list-inner .title-tabs .el-tabs__active-bar {
|
|
||||||
background-color: #47fff1;
|
|
||||||
}
|
|
||||||
.task-list-box .task-list-inner .el-textarea {
|
|
||||||
--el-input-focus-border-color: #47fff1;
|
|
||||||
}
|
|
||||||
.task-list-box .task-list-inner .el-textarea__inner {
|
|
||||||
background: transparent;
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
.task-list-box .task-list-inner .el-input__wrapper {
|
|
||||||
background: transparent;
|
|
||||||
padding: 5px;
|
|
||||||
}
|
|
||||||
.task-list-box .task-list-inner .text {
|
|
||||||
margin-bottom: 10px;
|
|
||||||
color: #6b778c;
|
|
||||||
font-size: 15px;
|
|
||||||
}
|
|
||||||
.task-list-box .task-list-inner .param-line.pt {
|
|
||||||
padding-top: 5px;
|
|
||||||
padding-bottom: 5px;
|
|
||||||
}
|
|
||||||
.task-list-box .task-list-inner .form-item-inner {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
.task-list-box .task-list-inner .form-item-inner .el-icon {
|
|
||||||
margin-left: 10px;
|
|
||||||
}
|
|
||||||
.task-list-box .task-list-inner .el-form-item__label {
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
.task-list-box .task-list-inner .img-inline {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
.task-list-box .task-list-inner .img-inline .img-uploader .el-upload {
|
|
||||||
border: 1px dashed var(--el-border-color);
|
|
||||||
border-radius: 6px;
|
|
||||||
cursor: pointer;
|
|
||||||
position: relative;
|
|
||||||
overflow: hidden;
|
|
||||||
width: 120px;
|
|
||||||
transition: var(--el-transition-duration-fast);
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
.task-list-box .task-list-inner .img-inline .img-uploader .el-upload:hover {
|
|
||||||
border-color: var(--el-color-primary);
|
|
||||||
}
|
|
||||||
.task-list-box .task-list-inner .img-inline .img-uploader .el-upload .el-icon.uploader-icon {
|
|
||||||
font-size: 28px;
|
|
||||||
color: #8c939d;
|
|
||||||
width: 100%;
|
|
||||||
height: 120px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
.task-list-box .task-list-inner .img-inline .img-list-box {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
.task-list-box .task-list-inner .img-inline .img-list-box .img-item {
|
|
||||||
width: 120px;
|
|
||||||
position: relative;
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
.task-list-box .task-list-inner .img-inline .img-list-box .img-item .el-image {
|
|
||||||
width: 120px;
|
|
||||||
height: 120px;
|
|
||||||
border-radius: 5px;
|
|
||||||
}
|
|
||||||
.task-list-box .task-list-inner .img-inline .img-list-box .img-item .el-button {
|
|
||||||
position: absolute;
|
|
||||||
right: 5px;
|
|
||||||
top: 5px;
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
}
|
|
||||||
.task-list-box .task-list-inner .submit-btn {
|
|
||||||
display: flex;
|
|
||||||
margin: 20px 0;
|
|
||||||
}
|
|
||||||
.task-list-box .task-list-inner .submit-btn .el-button {
|
|
||||||
width: 200px;
|
|
||||||
}
|
|
||||||
.task-list-box .task-list-inner .submit-btn .text-info {
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
justify-content: right;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
.task-list-box .task-list-inner .job-list-box .running-job-list .job-item {
|
|
||||||
width: 100%;
|
|
||||||
padding: 2px;
|
|
||||||
background-color: #555;
|
|
||||||
}
|
|
||||||
.task-list-box .task-list-inner .job-list-box .running-job-list .job-item .job-item-inner {
|
|
||||||
position: relative;
|
|
||||||
height: 100%;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
.task-list-box .task-list-inner .job-list-box .running-job-list .job-item .job-item-inner .progress {
|
|
||||||
position: absolute;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
.task-list-box .task-list-inner .job-list-box .running-job-list .job-item .job-item-inner .progress span {
|
|
||||||
font-size: 20px;
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
.task-list-box .task-list-inner .job-list-box .finish-job-list .job-item {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
border: 1px solid #666;
|
|
||||||
padding: 6px;
|
|
||||||
overflow: hidden;
|
|
||||||
border-radius: 6px;
|
|
||||||
transition: all 0.3s ease; /* 添加过渡效果 */
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
.task-list-box .task-list-inner .job-list-box .finish-job-list .job-item .opt .opt-line {
|
|
||||||
margin: 6px 0;
|
|
||||||
}
|
|
||||||
.task-list-box .task-list-inner .job-list-box .finish-job-list .job-item .opt .opt-line ul {
|
|
||||||
display: flex;
|
|
||||||
flex-flow: row;
|
|
||||||
}
|
|
||||||
.task-list-box .task-list-inner .job-list-box .finish-job-list .job-item .opt .opt-line ul li {
|
|
||||||
margin-right: 6px;
|
|
||||||
}
|
|
||||||
.task-list-box .task-list-inner .job-list-box .finish-job-list .job-item .opt .opt-line ul li a {
|
|
||||||
padding: 3px 0;
|
|
||||||
width: 40px;
|
|
||||||
text-align: center;
|
|
||||||
border-radius: 5px;
|
|
||||||
display: block;
|
|
||||||
cursor: pointer;
|
|
||||||
background-color: #4e5058;
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
.task-list-box .task-list-inner .job-list-box .finish-job-list .job-item .opt .opt-line ul li a:hover {
|
|
||||||
background-color: #6d6f78;
|
|
||||||
}
|
|
||||||
.task-list-box .task-list-inner .job-list-box .finish-job-list .job-item .opt .opt-line ul .show-prompt {
|
|
||||||
font-size: 20px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
.task-list-box .task-list-inner .job-list-box .finish-job-list .job-item .remove {
|
|
||||||
display: none;
|
|
||||||
position: absolute;
|
|
||||||
right: 10px;
|
|
||||||
top: 10px;
|
|
||||||
}
|
|
||||||
.task-list-box .task-list-inner .job-list-box .finish-job-list .job-item:hover .remove {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
.task-list-box .task-list-inner .job-list-box .finish-job-list .animate:hover {
|
|
||||||
box-shadow: 0 0 10px rgba(71,255,241,0.6); /* 添加阴影效果 */
|
|
||||||
transform: translateY(-10px); /* 向上移动10像素 */
|
|
||||||
}
|
|
||||||
.task-list-box .task-list-inner .job-list-box .el-image {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
overflow: visible;
|
|
||||||
}
|
|
||||||
.task-list-box .task-list-inner .job-list-box .el-image img {
|
|
||||||
height: 240px;
|
|
||||||
}
|
|
||||||
.task-list-box .task-list-inner .job-list-box .el-image .el-image-viewer__wrapper img {
|
|
||||||
width: auto;
|
|
||||||
height: auto;
|
|
||||||
}
|
|
||||||
.task-list-box .task-list-inner .job-list-box .el-image .image-slot {
|
|
||||||
display: flex;
|
|
||||||
flex-flow: column;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
min-height: 200px;
|
|
||||||
color: #fff;
|
|
||||||
height: 240px;
|
|
||||||
}
|
|
||||||
.task-list-box .task-list-inner .job-list-box .el-image .image-slot .iconfont {
|
|
||||||
font-size: 50px;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
.task-list-box .task-list-inner .job-list-box .el-image.upscale {
|
|
||||||
max-height: 310px;
|
|
||||||
}
|
|
||||||
.task-list-box .task-list-inner .job-list-box .el-image.upscale img {
|
|
||||||
height: 310px;
|
|
||||||
}
|
|
||||||
.task-list-box .task-list-inner .job-list-box .el-image.upscale .el-image-viewer__wrapper img {
|
|
||||||
width: auto;
|
|
||||||
height: auto;
|
|
||||||
}
|
|
@ -1,302 +0,0 @@
|
|||||||
.task-list-box {
|
|
||||||
width 100%
|
|
||||||
padding 10px
|
|
||||||
color #ffffff
|
|
||||||
overflow-x hidden
|
|
||||||
|
|
||||||
.task-list-inner {
|
|
||||||
.el-tabs {
|
|
||||||
--el-tabs-header-height: 55px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.el-tabs__item {
|
|
||||||
color: #fff;
|
|
||||||
font-size: 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.title-tabs .el-tabs__item.is-active {
|
|
||||||
color: #47FFF1;
|
|
||||||
font-size: 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.title-tabs .el-tabs__active-bar {
|
|
||||||
background-color: #47FFF1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.el-textarea {
|
|
||||||
--el-input-focus-border-color: #47FFF1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.el-textarea__inner {
|
|
||||||
background: transparent;
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.el-input__wrapper {
|
|
||||||
background: transparent;
|
|
||||||
padding 5px
|
|
||||||
}
|
|
||||||
|
|
||||||
.text {
|
|
||||||
margin-bottom: 10px;
|
|
||||||
color: #6b778c;
|
|
||||||
font-size: 15px
|
|
||||||
}
|
|
||||||
|
|
||||||
.param-line.pt {
|
|
||||||
padding-top 5px
|
|
||||||
padding-bottom 5px
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-item-inner {
|
|
||||||
display flex
|
|
||||||
align-items: center
|
|
||||||
|
|
||||||
.el-icon {
|
|
||||||
margin-left 10px
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.el-form-item__label {
|
|
||||||
color #ffffff
|
|
||||||
}
|
|
||||||
|
|
||||||
// 图片上传样式
|
|
||||||
|
|
||||||
.img-inline {
|
|
||||||
display flex
|
|
||||||
|
|
||||||
.img-uploader {
|
|
||||||
.el-upload {
|
|
||||||
border: 1px dashed var(--el-border-color);
|
|
||||||
border-radius: 6px;
|
|
||||||
cursor: pointer;
|
|
||||||
position: relative;
|
|
||||||
overflow: hidden;
|
|
||||||
width 120px;
|
|
||||||
transition: var(--el-transition-duration-fast);
|
|
||||||
margin-bottom: 20px;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
border-color: var(--el-color-primary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.el-icon.uploader-icon {
|
|
||||||
font-size: 28px
|
|
||||||
color: #8c939d
|
|
||||||
width 100%
|
|
||||||
height: 120px
|
|
||||||
text-align: center
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.img-list-box {
|
|
||||||
display flex
|
|
||||||
|
|
||||||
.img-item {
|
|
||||||
width 120px
|
|
||||||
position relative
|
|
||||||
margin-right 10px
|
|
||||||
|
|
||||||
.el-image {
|
|
||||||
width 120px
|
|
||||||
height 120px
|
|
||||||
border-radius 5px
|
|
||||||
}
|
|
||||||
|
|
||||||
.el-button {
|
|
||||||
position absolute
|
|
||||||
right 5px
|
|
||||||
top 5px
|
|
||||||
width 20px
|
|
||||||
height 20px
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.el-row.text-info {
|
|
||||||
width 100%
|
|
||||||
padding 10px 0
|
|
||||||
|
|
||||||
.el-tag {
|
|
||||||
margin-right 10px
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 提交按钮
|
|
||||||
|
|
||||||
.submit-btn {
|
|
||||||
display flex
|
|
||||||
margin: 20px 0
|
|
||||||
|
|
||||||
.el-button {
|
|
||||||
width 200px
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// 任务列表
|
|
||||||
|
|
||||||
.job-list-box {
|
|
||||||
.running-job-list {
|
|
||||||
.job-item {
|
|
||||||
//border: 1px solid #454545;
|
|
||||||
width: 100%;
|
|
||||||
padding 2px
|
|
||||||
background-color #555555
|
|
||||||
|
|
||||||
.job-item-inner {
|
|
||||||
position relative
|
|
||||||
height 100%
|
|
||||||
overflow hidden
|
|
||||||
|
|
||||||
.progress {
|
|
||||||
position absolute
|
|
||||||
width 100%
|
|
||||||
height 100%
|
|
||||||
top 0
|
|
||||||
left 0
|
|
||||||
display flex
|
|
||||||
justify-content center
|
|
||||||
align-items center
|
|
||||||
|
|
||||||
span {
|
|
||||||
font-size 20px
|
|
||||||
color #ffffff
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.finish-job-list {
|
|
||||||
.job-item {
|
|
||||||
width 100%
|
|
||||||
height 100%
|
|
||||||
border 1px solid #666666
|
|
||||||
padding 6px
|
|
||||||
overflow hidden
|
|
||||||
border-radius 6px
|
|
||||||
transition: all 0.3s ease; /* 添加过渡效果 */
|
|
||||||
position relative
|
|
||||||
|
|
||||||
.opt {
|
|
||||||
.opt-line {
|
|
||||||
margin 6px 0
|
|
||||||
|
|
||||||
ul {
|
|
||||||
display flex
|
|
||||||
flex-flow row
|
|
||||||
|
|
||||||
li {
|
|
||||||
margin-right 6px
|
|
||||||
|
|
||||||
a {
|
|
||||||
padding 3px 0
|
|
||||||
width 40px
|
|
||||||
text-align center
|
|
||||||
border-radius 5px
|
|
||||||
display block
|
|
||||||
cursor pointer
|
|
||||||
background-color #4E5058
|
|
||||||
color #ffffff
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color #6D6F78
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.show-prompt {
|
|
||||||
font-size 20px
|
|
||||||
cursor pointer
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.remove {
|
|
||||||
display none
|
|
||||||
position absolute
|
|
||||||
right 10px
|
|
||||||
top 10px
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
.remove {
|
|
||||||
display block
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.animate {
|
|
||||||
&:hover {
|
|
||||||
box-shadow: 0 0 10px rgba(71, 255, 241, 0.6); /* 添加阴影效果 */
|
|
||||||
transform: translateY(-10px); /* 向上移动10像素 */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.el-image {
|
|
||||||
width 100%
|
|
||||||
height 100%
|
|
||||||
overflow visible
|
|
||||||
|
|
||||||
img {
|
|
||||||
height 240px
|
|
||||||
}
|
|
||||||
|
|
||||||
.el-image-viewer__wrapper {
|
|
||||||
img {
|
|
||||||
width auto
|
|
||||||
height auto
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.image-slot {
|
|
||||||
display flex
|
|
||||||
flex-flow column
|
|
||||||
justify-content center
|
|
||||||
align-items center
|
|
||||||
min-height 200px
|
|
||||||
color #ffffff
|
|
||||||
height 240px
|
|
||||||
|
|
||||||
.iconfont {
|
|
||||||
font-size 50px
|
|
||||||
margin-bottom 10px
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.el-image.upscale {
|
|
||||||
img {
|
|
||||||
height 310px
|
|
||||||
}
|
|
||||||
|
|
||||||
.image-slot {
|
|
||||||
height 310px
|
|
||||||
}
|
|
||||||
|
|
||||||
.el-image-viewer__wrapper {
|
|
||||||
img {
|
|
||||||
width auto
|
|
||||||
height auto
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.no-more-data {
|
|
||||||
text-align center
|
|
||||||
padding 20px
|
|
||||||
}
|
|
||||||
}
|
|
@ -105,7 +105,7 @@ const routes = [
|
|||||||
{
|
{
|
||||||
path: '/admin/login',
|
path: '/admin/login',
|
||||||
name: 'admin-login',
|
name: 'admin-login',
|
||||||
meta: {title: 'ChatPuls 控制台登录'},
|
meta: {title: 'Geek-AI 控制台登录'},
|
||||||
component: () => import('@/views/admin/Login.vue'),
|
component: () => import('@/views/admin/Login.vue'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -113,7 +113,7 @@ const routes = [
|
|||||||
path: '/admin',
|
path: '/admin',
|
||||||
redirect: '/admin/dashboard',
|
redirect: '/admin/dashboard',
|
||||||
component: () => import("@/views/admin/Home.vue"),
|
component: () => import("@/views/admin/Home.vue"),
|
||||||
meta: {title: 'ChatPuls 管理后台'},
|
meta: {title: 'Geek-AI 控制台'},
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '/admin/dashboard',
|
path: '/admin/dashboard',
|
||||||
|
@ -82,15 +82,36 @@
|
|||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="task-list-box" @scrollend="handleScrollEnd">
|
<div class="task-list-box">
|
||||||
<div class="task-list-inner" :style="{ height: listBoxHeight + 'px' }">
|
<div class="task-list-inner" :style="{ height: listBoxHeight + 'px' }">
|
||||||
<div class="job-list-box">
|
<div class="job-list-box">
|
||||||
<h2>任务列表</h2>
|
<h2>任务列表</h2>
|
||||||
<div class="running-job-list">
|
<div class="running-job-list">
|
||||||
<ItemList :items="runningJobs" v-if="runningJobs.length > 0" :width="240">
|
<div class="running-job-box" v-if="runningJobs.length > 0">
|
||||||
<template #default>
|
<div class="job-item" v-for="item in runningJobs">
|
||||||
<div class="job-item">
|
<div v-if="item.progress > 0" class="job-item-inner">
|
||||||
<el-image fit="cover">
|
<el-image :src="item['img_url']" fit="cover" loading="lazy">
|
||||||
|
<template #placeholder>
|
||||||
|
<div class="image-slot">
|
||||||
|
正在加载图片
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #error>
|
||||||
|
<div class="image-slot">
|
||||||
|
<el-icon>
|
||||||
|
<Picture/>
|
||||||
|
</el-icon>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-image>
|
||||||
|
|
||||||
|
<div class="progress">
|
||||||
|
<el-progress type="circle" :percentage="item.progress" :width="100"
|
||||||
|
color="#47fff1"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<el-image fit="cover" v-else>
|
||||||
<template #error>
|
<template #error>
|
||||||
<div class="image-slot">
|
<div class="image-slot">
|
||||||
<i class="iconfont icon-quick-start"></i>
|
<i class="iconfont icon-quick-start"></i>
|
||||||
@ -99,21 +120,31 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-image>
|
</el-image>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</div>
|
||||||
</ItemList>
|
|
||||||
<el-empty :image-size="100" v-else/>
|
<el-empty :image-size="100" v-else/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h2>创作记录</h2>
|
<h2>创作记录</h2>
|
||||||
<div class="finish-job-list">
|
<div class="finish-job-list">
|
||||||
<div v-if="finishedJobs.length > 0">
|
<div v-if="finishedJobs.length > 0">
|
||||||
<ItemList :items="finishedJobs" :width="240" :gap="16">
|
<v3-waterfall
|
||||||
<template #default="scope">
|
id="waterfall"
|
||||||
|
:list="finishedJobs"
|
||||||
|
srcKey="img_thumb"
|
||||||
|
:gap="20"
|
||||||
|
:bottomGap="-10"
|
||||||
|
:colWidth="colWidth"
|
||||||
|
:distanceToScroll="100"
|
||||||
|
:isLoading="loading"
|
||||||
|
:isOver="isOver"
|
||||||
|
@scrollReachBottom="fetchFinishJobs()">
|
||||||
|
<template #default="slotProp">
|
||||||
<div class="job-item">
|
<div class="job-item">
|
||||||
<el-image v-if="scope.item['img_url']"
|
<el-image
|
||||||
:src="scope.item['img_url']+'?imageView2/1/w/240/h/240/q/75'"
|
v-if="slotProp.item.img_url !== ''"
|
||||||
|
@click="previewImg(slotProp.item)"
|
||||||
|
:src="slotProp.item['img_thumb']"
|
||||||
fit="cover"
|
fit="cover"
|
||||||
:preview-src-list="[scope.item['img_url']]"
|
|
||||||
loading="lazy">
|
loading="lazy">
|
||||||
<template #placeholder>
|
<template #placeholder>
|
||||||
<div class="image-slot">
|
<div class="image-slot">
|
||||||
@ -130,18 +161,12 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-image>
|
</el-image>
|
||||||
|
|
||||||
<el-image v-else
|
<el-image v-else>
|
||||||
:src="scope.item['org_url']"
|
|
||||||
fit="cover"
|
|
||||||
:preview-src-list="[scope.item['org_url']]"
|
|
||||||
loading="lazy">
|
|
||||||
<template #placeholder>
|
|
||||||
<div class="image-slot">
|
|
||||||
正在加载图片
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #error>
|
<template #error>
|
||||||
|
<div class="image-slot">
|
||||||
|
<i class="iconfont icon-loading"></i>
|
||||||
|
<span>正在下载图片</span>
|
||||||
|
</div>
|
||||||
<div class="image-slot">
|
<div class="image-slot">
|
||||||
<el-icon>
|
<el-icon>
|
||||||
<Picture/>
|
<Picture/>
|
||||||
@ -152,35 +177,39 @@
|
|||||||
|
|
||||||
<div class="remove">
|
<div class="remove">
|
||||||
<el-tooltip content="删除" placement="top" effect="light">
|
<el-tooltip content="删除" placement="top" effect="light">
|
||||||
<el-button type="danger" :icon="Delete" @click="removeImage($event,scope.item)" circle/>
|
<el-button type="danger" :icon="Delete" @click="removeImage($event,slotProp.item)" circle/>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip content="分享" placement="top" effect="light" v-if="scope.item.publish">
|
<el-tooltip content="分享" placement="top" effect="light" v-if="slotProp.item.publish">
|
||||||
<el-button type="warning"
|
<el-button type="warning"
|
||||||
@click="publishImage($event,scope.item, false)"
|
@click="publishImage($event,slotProp.item, false)"
|
||||||
circle>
|
circle>
|
||||||
<i class="iconfont icon-cancel-share"></i>
|
<i class="iconfont icon-cancel-share"></i>
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip content="取消分享" placement="top" effect="light" v-else>
|
<el-tooltip content="取消分享" placement="top" effect="light" v-else>
|
||||||
<el-button type="success" @click="publishImage($event,scope.item, true)" circle>
|
<el-button type="success" @click="publishImage($event,slotProp.item, true)" circle>
|
||||||
<i class="iconfont icon-share-bold"></i>
|
<i class="iconfont icon-share-bold"></i>
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
|
|
||||||
<el-tooltip content="复制提示词" placement="top" effect="light">
|
<el-tooltip content="复制提示词" placement="top" effect="light">
|
||||||
<el-button type="info" circle class="copy-prompt" :data-clipboard-text="scope.item.prompt">
|
<el-button type="info" circle class="copy-prompt"
|
||||||
|
:data-clipboard-text="slotProp.item.prompt">
|
||||||
<i class="iconfont icon-file"></i>
|
<i class="iconfont icon-file"></i>
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</ItemList>
|
|
||||||
|
|
||||||
<div class="no-more-data" v-if="isOver">
|
<template #footer>
|
||||||
|
<div class="no-more-data">
|
||||||
<span>没有更多数据了</span>
|
<span>没有更多数据了</span>
|
||||||
<i class="iconfont icon-face"></i>
|
<i class="iconfont icon-face"></i>
|
||||||
</div>
|
</div>
|
||||||
|
</template>
|
||||||
|
</v3-waterfall>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<el-empty :image-size="100" v-else/>
|
<el-empty :image-size="100" v-else/>
|
||||||
</div> <!-- end finish job list-->
|
</div> <!-- end finish job list-->
|
||||||
@ -193,15 +222,15 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<login-dialog :show="showLoginDialog" @hide="showLoginDialog = false" @success="initData"/>
|
<login-dialog :show="showLoginDialog" @hide="showLoginDialog = false" @success="initData"/>
|
||||||
|
<el-image-viewer @close="() => { previewURL = '' }" v-if="previewURL !== ''" :url-list="[previewURL]"/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import {onMounted, onUnmounted, ref} from "vue"
|
import {onMounted, onUnmounted, ref} from "vue"
|
||||||
import {Delete, InfoFilled, Picture} from "@element-plus/icons-vue";
|
import {Delete, InfoFilled} from "@element-plus/icons-vue";
|
||||||
import {httpGet, httpPost} from "@/utils/http";
|
import {httpGet, httpPost} from "@/utils/http";
|
||||||
import {ElMessage, ElMessageBox, ElNotification} from "element-plus";
|
import {ElMessage, ElMessageBox, ElNotification} from "element-plus";
|
||||||
import ItemList from "@/components/ItemList.vue";
|
|
||||||
import Clipboard from "clipboard";
|
import Clipboard from "clipboard";
|
||||||
import {checkSession} from "@/action/session";
|
import {checkSession} from "@/action/session";
|
||||||
import LoginDialog from "@/components/LoginDialog.vue";
|
import LoginDialog from "@/components/LoginDialog.vue";
|
||||||
@ -210,6 +239,10 @@ const listBoxHeight = ref(window.innerHeight - 40)
|
|||||||
const paramBoxHeight = ref(window.innerHeight - 150)
|
const paramBoxHeight = ref(window.innerHeight - 150)
|
||||||
const showLoginDialog = ref(false)
|
const showLoginDialog = ref(false)
|
||||||
const isLogin = ref(false)
|
const isLogin = ref(false)
|
||||||
|
const loading = ref(true)
|
||||||
|
const colWidth = ref(240)
|
||||||
|
const isOver = ref(false)
|
||||||
|
const previewURL = ref("")
|
||||||
|
|
||||||
window.onresize = () => {
|
window.onresize = () => {
|
||||||
listBoxHeight.value = window.innerHeight - 40
|
listBoxHeight.value = window.innerHeight - 40
|
||||||
@ -268,21 +301,15 @@ const initData = () => {
|
|||||||
power.value = user['power']
|
power.value = user['power']
|
||||||
userId.value = user.id
|
userId.value = user.id
|
||||||
isLogin.value = true
|
isLogin.value = true
|
||||||
|
|
||||||
|
page.value = 0
|
||||||
fetchRunningJobs()
|
fetchRunningJobs()
|
||||||
fetchFinishJobs(1)
|
fetchFinishJobs()
|
||||||
connect()
|
connect()
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleScrollEnd = () => {
|
|
||||||
if (isOver.value === true) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
page.value += 1
|
|
||||||
fetchFinishJobs(page.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
const socket = ref(null)
|
const socket = ref(null)
|
||||||
const heartbeatHandle = ref(null)
|
const heartbeatHandle = ref(null)
|
||||||
const connect = () => {
|
const connect = () => {
|
||||||
@ -323,7 +350,7 @@ const connect = () => {
|
|||||||
reader.onload = () => {
|
reader.onload = () => {
|
||||||
const message = String(reader.result)
|
const message = String(reader.result)
|
||||||
if (message === "FINISH") {
|
if (message === "FINISH") {
|
||||||
page.value = 1
|
page.value = 0
|
||||||
fetchFinishJobs(page.value)
|
fetchFinishJobs(page.value)
|
||||||
isOver.value = false
|
isOver.value = false
|
||||||
}
|
}
|
||||||
@ -368,21 +395,30 @@ const fetchRunningJobs = () => {
|
|||||||
|
|
||||||
const page = ref(1)
|
const page = ref(1)
|
||||||
const pageSize = ref(15)
|
const pageSize = ref(15)
|
||||||
const isOver = ref(false)
|
|
||||||
// 获取已完成的任务
|
// 获取已完成的任务
|
||||||
const fetchFinishJobs = (page) => {
|
const fetchFinishJobs = () => {
|
||||||
if (!isLogin.value) {
|
if (!isLogin.value) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
httpGet(`/api/dall/jobs?status=1&page=${page}&page_size=${pageSize.value}`).then(res => {
|
|
||||||
|
loading.value = true
|
||||||
|
page.value = page.value + 1
|
||||||
|
|
||||||
|
httpGet(`/api/dall/jobs?status=1&page=${page.value}&page_size=${pageSize.value}`).then(res => {
|
||||||
if (res.data.length < pageSize.value) {
|
if (res.data.length < pageSize.value) {
|
||||||
isOver.value = true
|
isOver.value = true
|
||||||
}
|
}
|
||||||
if (page === 1) {
|
const imageList = res.data
|
||||||
finishedJobs.value = res.data
|
for (let i = 0; i < imageList.length; i++) {
|
||||||
} else {
|
imageList[i]["img_thumb"] = imageList[i]["img_url"] + "?imageView2/4/w/300/h/0/q/75"
|
||||||
finishedJobs.value = finishedJobs.value.concat(res.data)
|
|
||||||
}
|
}
|
||||||
|
if (page.value === 1) {
|
||||||
|
finishedJobs.value = imageList
|
||||||
|
} else {
|
||||||
|
finishedJobs.value = finishedJobs.value.concat(imageList)
|
||||||
|
}
|
||||||
|
|
||||||
|
loading.value = false
|
||||||
}).catch(e => {
|
}).catch(e => {
|
||||||
ElMessage.error("获取任务失败:" + e.message)
|
ElMessage.error("获取任务失败:" + e.message)
|
||||||
})
|
})
|
||||||
@ -430,6 +466,10 @@ const removeImage = (event, item) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const previewImg = (item) => {
|
||||||
|
previewURL.value = item.img_url
|
||||||
|
}
|
||||||
|
|
||||||
// 发布图片到作品墙
|
// 发布图片到作品墙
|
||||||
const publishImage = (event, item, action) => {
|
const publishImage = (event, item, action) => {
|
||||||
event.stopPropagation()
|
event.stopPropagation()
|
||||||
|
@ -451,13 +451,10 @@
|
|||||||
<div class="job-list-box">
|
<div class="job-list-box">
|
||||||
<h2>任务列表</h2>
|
<h2>任务列表</h2>
|
||||||
<div class="running-job-list">
|
<div class="running-job-list">
|
||||||
<ItemList :items="runningJobs" v-if="runningJobs.length > 0">
|
<div class="running-job-box" v-if="runningJobs.length > 0">
|
||||||
<template #default="scope">
|
<div class="job-item" v-for="item in runningJobs">
|
||||||
<div class="job-item">
|
<div v-if="item.progress > 0" class="job-item-inner">
|
||||||
<div v-if="scope.item.progress > 0" class="job-item-inner">
|
<el-image :src="item['img_url']" fit="cover" loading="lazy">
|
||||||
<el-image :src="scope.item['img_url']" :zoom-rate="1.2"
|
|
||||||
:preview-src-list="[scope.item['img_url']]" fit="cover" :initial-index="0"
|
|
||||||
loading="lazy">
|
|
||||||
<template #placeholder>
|
<template #placeholder>
|
||||||
<div class="image-slot">
|
<div class="image-slot">
|
||||||
正在加载图片
|
正在加载图片
|
||||||
@ -474,7 +471,7 @@
|
|||||||
</el-image>
|
</el-image>
|
||||||
|
|
||||||
<div class="progress">
|
<div class="progress">
|
||||||
<el-progress type="circle" :percentage="scope.item.progress" :width="100"
|
<el-progress type="circle" :percentage="item.progress" :width="100"
|
||||||
color="#47fff1"/>
|
color="#47fff1"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -487,34 +484,45 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-image>
|
</el-image>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</div>
|
||||||
</ItemList>
|
|
||||||
<el-empty :image-size="100" v-else/>
|
<el-empty :image-size="100" v-else/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h2>创作记录</h2>
|
<h2>创作记录</h2>
|
||||||
<div class="finish-job-list">
|
<div class="finish-job-list">
|
||||||
<div v-if="finishedJobs.length > 0">
|
<div v-if="finishedJobs.length > 0">
|
||||||
<ItemList :items="finishedJobs" :width="240" :gap="16">
|
<v3-waterfall
|
||||||
<template #default="scope">
|
id="waterfall"
|
||||||
|
:list="finishedJobs"
|
||||||
|
srcKey="thumb_url"
|
||||||
|
:gap="20"
|
||||||
|
:bottomGap="-8"
|
||||||
|
:colWidth="colWidth"
|
||||||
|
:distanceToScroll="100"
|
||||||
|
:isLoading="loading"
|
||||||
|
:isOver="isOver"
|
||||||
|
@scrollReachBottom="fetchFinishJobs()">
|
||||||
|
<template #default="slotProp">
|
||||||
<div class="job-item">
|
<div class="job-item">
|
||||||
<el-image
|
<el-image
|
||||||
:src="scope.item['thumb_url']"
|
v-if="slotProp.item.img_url !== ''"
|
||||||
:class="scope.item['can_opt'] ? '' : 'upscale'" :zoom-rate="1.2"
|
:src="slotProp.item['thumb_url']"
|
||||||
:preview-src-list="[scope.item['img_url']]" fit="cover" :initial-index="scope.index"
|
:class="slotProp.item['can_opt'] ? '' : 'upscale'" @click="previewImg(slotProp.item)"
|
||||||
loading="lazy" v-if="scope.item.progress > 0">
|
fit="cover" :initial-index="slotProp.index"
|
||||||
|
loading="lazy">
|
||||||
<template #placeholder>
|
<template #placeholder>
|
||||||
<div class="image-slot">
|
<div class="image-slot">
|
||||||
正在加载图片
|
正在加载图片
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
</el-image>
|
||||||
|
<el-image v-else>
|
||||||
<template #error>
|
<template #error>
|
||||||
<div class="image-slot" v-if="scope.item['img_url'] === ''">
|
<div class="image-slot">
|
||||||
<i class="iconfont icon-loading"></i>
|
<i class="iconfont icon-loading"></i>
|
||||||
<span>正在下载图片</span>
|
<span>正在下载图片</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="image-slot" v-else>
|
<div class="image-slot">
|
||||||
<el-icon>
|
<el-icon>
|
||||||
<Picture/>
|
<Picture/>
|
||||||
</el-icon>
|
</el-icon>
|
||||||
@ -522,13 +530,13 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-image>
|
</el-image>
|
||||||
|
|
||||||
<div class="opt" v-if="scope.item['can_opt']">
|
<div class="opt" v-if="slotProp.item['can_opt']">
|
||||||
<div class="opt-line">
|
<div class="opt-line">
|
||||||
<ul>
|
<ul>
|
||||||
<li><a @click="upscale(1, scope.item)">U1</a></li>
|
<li><a @click="upscale(1, slotProp.item)">U1</a></li>
|
||||||
<li><a @click="upscale(2, scope.item)">U2</a></li>
|
<li><a @click="upscale(2, slotProp.item)">U2</a></li>
|
||||||
<li><a @click="upscale(3, scope.item)">U3</a></li>
|
<li><a @click="upscale(3, slotProp.item)">U3</a></li>
|
||||||
<li><a @click="upscale(4, scope.item)">U4</a></li>
|
<li><a @click="upscale(4, slotProp.item)">U4</a></li>
|
||||||
<li class="show-prompt">
|
<li class="show-prompt">
|
||||||
|
|
||||||
<el-popover placement="left" title="提示词" :width="240" trigger="hover">
|
<el-popover placement="left" title="提示词" :width="240" trigger="hover">
|
||||||
@ -540,9 +548,9 @@
|
|||||||
|
|
||||||
<template #default>
|
<template #default>
|
||||||
<div class="mj-list-item-prompt">
|
<div class="mj-list-item-prompt">
|
||||||
<span>{{ scope.item.prompt }}</span>
|
<span>{{ slotProp.item.prompt }}</span>
|
||||||
<el-icon class="copy-prompt-mj"
|
<el-icon class="copy-prompt-mj"
|
||||||
:data-clipboard-text="scope.item.prompt">
|
:data-clipboard-text="slotProp.item.prompt">
|
||||||
<DocumentCopy/>
|
<DocumentCopy/>
|
||||||
</el-icon>
|
</el-icon>
|
||||||
</div>
|
</div>
|
||||||
@ -554,40 +562,45 @@
|
|||||||
|
|
||||||
<div class="opt-line">
|
<div class="opt-line">
|
||||||
<ul>
|
<ul>
|
||||||
<li><a @click="variation(1, scope.item)">V1</a></li>
|
<li><a @click="variation(1, slotProp.item)">V1</a></li>
|
||||||
<li><a @click="variation(2, scope.item)">V2</a></li>
|
<li><a @click="variation(2, slotProp.item)">V2</a></li>
|
||||||
<li><a @click="variation(3, scope.item)">V3</a></li>
|
<li><a @click="variation(3, slotProp.item)">V3</a></li>
|
||||||
<li><a @click="variation(4, scope.item)">V4</a></li>
|
<li><a @click="variation(4, slotProp.item)">V4</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="remove">
|
<div class="remove">
|
||||||
<el-button type="danger" :icon="Delete" @click="removeImage(scope.item)" circle/>
|
<el-button type="danger" :icon="Delete" @click="removeImage(slotProp.item)" circle/>
|
||||||
<el-button type="warning" v-if="scope.item.publish" @click="publishImage(scope.item, false)"
|
<el-button type="warning" v-if="slotProp.item.publish"
|
||||||
|
@click="publishImage(slotProp.item, false)"
|
||||||
circle>
|
circle>
|
||||||
<i class="iconfont icon-cancel-share"></i>
|
<i class="iconfont icon-cancel-share"></i>
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button type="success" v-else @click="publishImage(scope.item, true)" circle>
|
<el-button type="success" v-else @click="publishImage(slotProp.item, true)" circle>
|
||||||
<i class="iconfont icon-share-bold"></i>
|
<i class="iconfont icon-share-bold"></i>
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</ItemList>
|
|
||||||
<div class="no-more-data" v-if="isOver">
|
<template #footer>
|
||||||
|
<div class="no-more-data">
|
||||||
<span>没有更多数据了</span>
|
<span>没有更多数据了</span>
|
||||||
<i class="iconfont icon-face"></i>
|
<i class="iconfont icon-face"></i>
|
||||||
</div>
|
</div>
|
||||||
|
</template>
|
||||||
|
</v3-waterfall>
|
||||||
</div>
|
</div>
|
||||||
<el-empty :image-size="100" v-else/>
|
<el-empty :image-size="100" v-else/>
|
||||||
</div> <!-- end finish job list-->
|
</div> <!-- end finish job list-->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div><!-- end task list box -->
|
</div><!-- end task list box -->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<el-image-viewer @close="() => { previewURL = '' }" v-if="previewURL !== ''" :url-list="[previewURL]"/>
|
||||||
|
|
||||||
<login-dialog :show="showLoginDialog" @hide="showLoginDialog = false" @success="initData"/>
|
<login-dialog :show="showLoginDialog" @hide="showLoginDialog = false" @success="initData"/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -598,7 +611,6 @@ import {ChromeFilled, Delete, DocumentCopy, InfoFilled, Picture, Plus, UploadFil
|
|||||||
import Compressor from "compressorjs";
|
import Compressor from "compressorjs";
|
||||||
import {httpGet, httpPost} from "@/utils/http";
|
import {httpGet, httpPost} from "@/utils/http";
|
||||||
import {ElMessage, ElMessageBox, ElNotification} from "element-plus";
|
import {ElMessage, ElMessageBox, ElNotification} from "element-plus";
|
||||||
import ItemList from "@/components/ItemList.vue";
|
|
||||||
import Clipboard from "clipboard";
|
import Clipboard from "clipboard";
|
||||||
import {checkSession} from "@/action/session";
|
import {checkSession} from "@/action/session";
|
||||||
import {useRouter} from "vue-router";
|
import {useRouter} from "vue-router";
|
||||||
@ -609,6 +621,9 @@ import LoginDialog from "@/components/LoginDialog.vue";
|
|||||||
const listBoxHeight = ref(window.innerHeight - 40)
|
const listBoxHeight = ref(window.innerHeight - 40)
|
||||||
const paramBoxHeight = ref(window.innerHeight - 150)
|
const paramBoxHeight = ref(window.innerHeight - 150)
|
||||||
const showLoginDialog = ref(false)
|
const showLoginDialog = ref(false)
|
||||||
|
const loading = ref(true)
|
||||||
|
const colWidth = ref(240)
|
||||||
|
const previewURL = ref("")
|
||||||
|
|
||||||
window.onresize = () => {
|
window.onresize = () => {
|
||||||
listBoxHeight.value = window.innerHeight - 40
|
listBoxHeight.value = window.innerHeight - 40
|
||||||
@ -730,7 +745,7 @@ const connect = () => {
|
|||||||
reader.onload = () => {
|
reader.onload = () => {
|
||||||
const message = String(reader.result)
|
const message = String(reader.result)
|
||||||
if (message === "FINISH") {
|
if (message === "FINISH") {
|
||||||
page.value = 1
|
page.value = 0
|
||||||
fetchFinishJobs(page.value)
|
fetchFinishJobs(page.value)
|
||||||
isOver.value = false
|
isOver.value = false
|
||||||
}
|
}
|
||||||
@ -773,9 +788,9 @@ const initData = () => {
|
|||||||
power.value = user['power']
|
power.value = user['power']
|
||||||
userId.value = user.id
|
userId.value = user.id
|
||||||
isLogin.value = true
|
isLogin.value = true
|
||||||
|
page.value = 0
|
||||||
fetchRunningJobs()
|
fetchRunningJobs()
|
||||||
fetchFinishJobs(1)
|
fetchFinishJobs()
|
||||||
connect()
|
connect()
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
|
|
||||||
@ -824,35 +839,28 @@ const fetchRunningJobs = () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const page = ref(0)
|
||||||
const handleScrollEnd = () => {
|
|
||||||
if (isOver.value === true) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
page.value += 1
|
|
||||||
fetchFinishJobs(page.value)
|
|
||||||
};
|
|
||||||
|
|
||||||
const page = ref(1)
|
|
||||||
const pageSize = ref(15)
|
const pageSize = ref(15)
|
||||||
const isOver = ref(false)
|
const isOver = ref(false)
|
||||||
const fetchFinishJobs = (page) => {
|
const fetchFinishJobs = () => {
|
||||||
if (!isLogin.value) {
|
if (!isLogin.value || isOver.value) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loading.value = true
|
||||||
|
page.value = page.value + 1
|
||||||
// 获取已完成的任务
|
// 获取已完成的任务
|
||||||
httpGet(`/api/mj/jobs?status=1&page=${page}&page_size=${pageSize.value}`).then(res => {
|
httpGet(`/api/mj/jobs?status=1&page=${page.value}&page_size=${pageSize.value}`).then(res => {
|
||||||
const jobs = res.data
|
const jobs = res.data
|
||||||
for (let i = 0; i < jobs.length; i++) {
|
for (let i = 0; i < jobs.length; i++) {
|
||||||
if (jobs[i]['use_proxy']) {
|
if (jobs[i]['img_url'] !== "") {
|
||||||
jobs[i]['thumb_url'] = jobs[i]['img_url'] + '?x-oss-process=image/quality,q_60&format=webp'
|
|
||||||
} else {
|
|
||||||
if (jobs[i].type === 'upscale' || jobs[i].type === 'swapFace') {
|
if (jobs[i].type === 'upscale' || jobs[i].type === 'swapFace') {
|
||||||
jobs[i]['thumb_url'] = jobs[i]['img_url'] + '?imageView2/1/w/480/h/600/q/75'
|
jobs[i]['thumb_url'] = jobs[i]['img_url'] + '?imageView2/1/w/480/h/600/q/75'
|
||||||
} else {
|
} else {
|
||||||
jobs[i]['thumb_url'] = jobs[i]['img_url'] + '?imageView2/1/w/480/h/480/q/75'
|
jobs[i]['thumb_url'] = jobs[i]['img_url'] + '?imageView2/1/w/480/h/480/q/75'
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
jobs[i]['thumb_url'] = '/images/img-placeholder.jpg'
|
||||||
}
|
}
|
||||||
|
|
||||||
if (jobs[i].type === 'image' || jobs[i].type === 'variation') {
|
if (jobs[i].type === 'image' || jobs[i].type === 'variation') {
|
||||||
@ -862,11 +870,12 @@ const fetchFinishJobs = (page) => {
|
|||||||
if (jobs.length < pageSize.value) {
|
if (jobs.length < pageSize.value) {
|
||||||
isOver.value = true
|
isOver.value = true
|
||||||
}
|
}
|
||||||
if (page === 1) {
|
if (page.value === 1) {
|
||||||
finishedJobs.value = jobs
|
finishedJobs.value = jobs
|
||||||
} else {
|
} else {
|
||||||
finishedJobs.value = finishedJobs.value.concat(jobs)
|
finishedJobs.value = finishedJobs.value.concat(jobs)
|
||||||
}
|
}
|
||||||
|
loading.value = false
|
||||||
}).catch(e => {
|
}).catch(e => {
|
||||||
ElMessage.error("获取任务失败:" + e.message)
|
ElMessage.error("获取任务失败:" + e.message)
|
||||||
})
|
})
|
||||||
@ -1005,6 +1014,11 @@ const publishImage = (item, action) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const previewImg = (item) => {
|
||||||
|
previewURL.value = item.img_url
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// 切换菜单
|
// 切换菜单
|
||||||
const tabChange = (tab) => {
|
const tabChange = (tab) => {
|
||||||
if (tab === "txt2img" || tab === "img2img" || tab === "cref") {
|
if (tab === "txt2img" || tab === "img2img" || tab === "cref") {
|
||||||
|
@ -29,6 +29,28 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="param-line" style="padding-top: 10px">
|
||||||
|
<el-form-item label="采样调度器">
|
||||||
|
<template #default>
|
||||||
|
<div class="form-item-inner">
|
||||||
|
<el-select v-model="params.scheduler" style="width:176px">
|
||||||
|
<el-option v-for="item in schedulers" :label="item" :value="item" :key="item"/>
|
||||||
|
</el-select>
|
||||||
|
<el-tooltip
|
||||||
|
effect="light"
|
||||||
|
content="推荐自动或者 Karras"
|
||||||
|
raw-content
|
||||||
|
placement="right"
|
||||||
|
>
|
||||||
|
<el-icon class="info-icon">
|
||||||
|
<InfoFilled/>
|
||||||
|
</el-icon>
|
||||||
|
</el-tooltip>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="param-line">
|
<div class="param-line">
|
||||||
<el-form-item label="图片尺寸">
|
<el-form-item label="图片尺寸">
|
||||||
<template #default>
|
<template #default>
|
||||||
@ -270,60 +292,15 @@
|
|||||||
<el-button color="#47fff1" :dark="false" round @click="generate">立即生成</el-button>
|
<el-button color="#47fff1" :dark="false" round @click="generate">立即生成</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="task-list-box" @scrollend="handleScrollEnd">
|
<div class="task-list-box">
|
||||||
<div class="task-list-inner" :style="{ height: listBoxHeight + 'px' }">
|
<div class="task-list-inner" :style="{ height: listBoxHeight + 'px' }">
|
||||||
<div class="job-list-box">
|
<div class="job-list-box">
|
||||||
<h2>任务列表</h2>
|
<h2>任务列表</h2>
|
||||||
<div class="running-job-list">
|
<div class="running-job-list">
|
||||||
<ItemList :items="runningJobs" v-if="runningJobs.length > 0" :width="240">
|
<div class="running-job-box" v-if="runningJobs.length > 0">
|
||||||
<template #default="scope">
|
<div class="job-item" v-for="item in runningJobs">
|
||||||
<div class="job-item">
|
<div v-if="item.progress > 0" class="job-item-inner">
|
||||||
<div v-if="scope.item.progress > 0" class="job-item-inner">
|
<el-image :src="item['img_url']" fit="cover" loading="lazy">
|
||||||
<el-image :src="scope.item['img_url']"
|
|
||||||
fit="cover"
|
|
||||||
loading="lazy">
|
|
||||||
<template #placeholder>
|
|
||||||
<div class="image-slot">
|
|
||||||
正在加载图片
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #error>
|
|
||||||
<div class="image-slot">
|
|
||||||
<el-icon v-if="scope.item['img_url'] !== ''">
|
|
||||||
<Picture/>
|
|
||||||
</el-icon>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</el-image>
|
|
||||||
|
|
||||||
<div class="progress">
|
|
||||||
<el-progress type="circle" :percentage="scope.item.progress" :width="100" color="#47fff1"/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<el-image fit="cover" v-else>
|
|
||||||
<template #error>
|
|
||||||
<div class="image-slot">
|
|
||||||
<i class="iconfont icon-quick-start"></i>
|
|
||||||
<span>任务正在排队中</span>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</el-image>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</ItemList>
|
|
||||||
<el-empty :image-size="100" v-else/>
|
|
||||||
</div>
|
|
||||||
<h2>创作记录</h2>
|
|
||||||
<div class="finish-job-list">
|
|
||||||
<div v-if="finishedJobs.length > 0">
|
|
||||||
<ItemList :items="finishedJobs" :width="240" :gap="16">
|
|
||||||
<template #default="scope">
|
|
||||||
<div class="job-item animate" @click="showTask(scope.item)">
|
|
||||||
<el-image
|
|
||||||
:src="scope.item['img_url']+'?imageView2/1/w/240/h/240/q/75'"
|
|
||||||
fit="cover"
|
|
||||||
loading="lazy">
|
|
||||||
<template #placeholder>
|
<template #placeholder>
|
||||||
<div class="image-slot">
|
<div class="image-slot">
|
||||||
正在加载图片
|
正在加载图片
|
||||||
@ -339,25 +316,65 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-image>
|
</el-image>
|
||||||
|
|
||||||
|
<div class="progress">
|
||||||
|
<el-progress type="circle" :percentage="item.progress" :width="100"
|
||||||
|
color="#47fff1"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<el-image fit="cover" v-else>
|
||||||
|
<template #error>
|
||||||
|
<div class="image-slot">
|
||||||
|
<i class="iconfont icon-quick-start"></i>
|
||||||
|
<span>任务正在排队中</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-image>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<el-empty :image-size="100" v-else/>
|
||||||
|
</div>
|
||||||
|
<h2>创作记录</h2>
|
||||||
|
<div class="finish-job-list">
|
||||||
|
<div v-if="finishedJobs.length > 0">
|
||||||
|
<v3-waterfall
|
||||||
|
id="waterfall"
|
||||||
|
:list="finishedJobs"
|
||||||
|
srcKey="img_thumb"
|
||||||
|
:gap="20"
|
||||||
|
:bottomGap="-10"
|
||||||
|
:colWidth="colWidth"
|
||||||
|
:distanceToScroll="100"
|
||||||
|
:isLoading="loading"
|
||||||
|
:isOver="isOver"
|
||||||
|
@scrollReachBottom="fetchFinishJobs()">
|
||||||
|
<template #default="slotProp">
|
||||||
|
<div class="job-item animate" @click="showTask(slotProp.item)">
|
||||||
|
<el-image
|
||||||
|
:src="slotProp.item['img_thumb']"
|
||||||
|
fit="cover"
|
||||||
|
loading="lazy"/>
|
||||||
<div class="remove">
|
<div class="remove">
|
||||||
<el-button type="danger" :icon="Delete" @click="removeImage($event,scope.item)" circle/>
|
<el-button type="danger" :icon="Delete" @click="removeImage($event,slotProp.item)" circle/>
|
||||||
<el-button type="warning" v-if="scope.item.publish"
|
<el-button type="warning" v-if="slotProp.item.publish"
|
||||||
@click="publishImage($event,scope.item, false)"
|
@click="publishImage($event,slotProp.item, false)"
|
||||||
circle>
|
circle>
|
||||||
<i class="iconfont icon-cancel-share"></i>
|
<i class="iconfont icon-cancel-share"></i>
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button type="success" v-else @click="publishImage($event,scope.item, true)" circle>
|
<el-button type="success" v-else @click="publishImage($event,slotProp.item, true)" circle>
|
||||||
<i class="iconfont icon-share-bold"></i>
|
<i class="iconfont icon-share-bold"></i>
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</ItemList>
|
|
||||||
|
|
||||||
<div class="no-more-data" v-if="isOver">
|
<template #footer>
|
||||||
|
<div class="no-more-data">
|
||||||
<span>没有更多数据了</span>
|
<span>没有更多数据了</span>
|
||||||
<i class="iconfont icon-face"></i>
|
<i class="iconfont icon-face"></i>
|
||||||
</div>
|
</div>
|
||||||
|
</template>
|
||||||
|
</v3-waterfall>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<el-empty :image-size="100" v-else/>
|
<el-empty :image-size="100" v-else/>
|
||||||
</div> <!-- end finish job list-->
|
</div> <!-- end finish job list-->
|
||||||
@ -490,7 +507,6 @@ import {onMounted, onUnmounted, ref} from "vue"
|
|||||||
import {Delete, DocumentCopy, InfoFilled, Orange, Picture} from "@element-plus/icons-vue";
|
import {Delete, DocumentCopy, InfoFilled, Orange, Picture} from "@element-plus/icons-vue";
|
||||||
import {httpGet, httpPost} from "@/utils/http";
|
import {httpGet, httpPost} from "@/utils/http";
|
||||||
import {ElMessage, ElMessageBox, ElNotification} from "element-plus";
|
import {ElMessage, ElMessageBox, ElNotification} from "element-plus";
|
||||||
import ItemList from "@/components/ItemList.vue";
|
|
||||||
import Clipboard from "clipboard";
|
import Clipboard from "clipboard";
|
||||||
import {checkSession} from "@/action/session";
|
import {checkSession} from "@/action/session";
|
||||||
import {useRouter} from "vue-router";
|
import {useRouter} from "vue-router";
|
||||||
@ -504,17 +520,21 @@ const showTaskDialog = ref(false)
|
|||||||
const item = ref({})
|
const item = ref({})
|
||||||
const showLoginDialog = ref(false)
|
const showLoginDialog = ref(false)
|
||||||
const isLogin = ref(false)
|
const isLogin = ref(false)
|
||||||
|
const loading = ref(true)
|
||||||
|
const colWidth = ref(240)
|
||||||
|
|
||||||
window.onresize = () => {
|
window.onresize = () => {
|
||||||
listBoxHeight.value = window.innerHeight - 40
|
listBoxHeight.value = window.innerHeight - 40
|
||||||
paramBoxHeight.value = window.innerHeight - 150
|
paramBoxHeight.value = window.innerHeight - 150
|
||||||
}
|
}
|
||||||
const samplers = ["Euler a", "DPM++ 2S a Karras", "DPM++ 2M Karras", "DPM++ SDE Karras", "DPM++ 2M SDE Karras"]
|
const samplers = ["Euler a", "DPM++ 2S a", "DPM++ 2M", "DPM++ SDE", "DPM++ 2M SDE", "UniPC", "Restart"]
|
||||||
|
const schedulers = ["Automatic", "Karras", "Exponential", "Uniform"]
|
||||||
const scaleAlg = ["Latent", "ESRGAN_4x", "R-ESRGAN 4x+", "SwinIR_4x", "LDSR"]
|
const scaleAlg = ["Latent", "ESRGAN_4x", "R-ESRGAN 4x+", "SwinIR_4x", "LDSR"]
|
||||||
const params = ref({
|
const params = ref({
|
||||||
width: 1024,
|
width: 1024,
|
||||||
height: 1024,
|
height: 1024,
|
||||||
sampler: samplers[0],
|
sampler: samplers[0],
|
||||||
|
scheduler: schedulers[0],
|
||||||
seed: -1,
|
seed: -1,
|
||||||
steps: 20,
|
steps: 20,
|
||||||
cfg_scale: 7,
|
cfg_scale: 7,
|
||||||
@ -579,8 +599,8 @@ const connect = () => {
|
|||||||
reader.onload = () => {
|
reader.onload = () => {
|
||||||
const message = String(reader.result)
|
const message = String(reader.result)
|
||||||
if (message === "FINISH") {
|
if (message === "FINISH") {
|
||||||
page.value = 1
|
page.value = 0
|
||||||
fetchFinishJobs(page.value)
|
fetchFinishJobs()
|
||||||
isOver.value = false
|
isOver.value = false
|
||||||
}
|
}
|
||||||
fetchRunningJobs()
|
fetchRunningJobs()
|
||||||
@ -608,7 +628,8 @@ onMounted(() => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
httpGet("/api/config/get?key=system").then(res => {
|
httpGet("/api/config/get?key=system").then(res => {
|
||||||
sdPower.value = res.data["sd_power"]
|
sdPower.value = res.data.sd_power
|
||||||
|
params.value.neg_prompt = res.data.sd_neg_prompt
|
||||||
}).catch(e => {
|
}).catch(e => {
|
||||||
ElMessage.error("获取系统配置失败:" + e.message)
|
ElMessage.error("获取系统配置失败:" + e.message)
|
||||||
})
|
})
|
||||||
@ -628,6 +649,7 @@ const initData = () => {
|
|||||||
power.value = user['power']
|
power.value = user['power']
|
||||||
userId.value = user.id
|
userId.value = user.id
|
||||||
isLogin.value = true
|
isLogin.value = true
|
||||||
|
page.value = 0
|
||||||
fetchRunningJobs()
|
fetchRunningJobs()
|
||||||
fetchFinishJobs()
|
fetchFinishJobs()
|
||||||
connect()
|
connect()
|
||||||
@ -663,31 +685,32 @@ const fetchRunningJobs = () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleScrollEnd = () => {
|
const page = ref(0)
|
||||||
if (isOver.value === true) {
|
const pageSize = ref(20)
|
||||||
return
|
|
||||||
}
|
|
||||||
page.value += 1
|
|
||||||
fetchFinishJobs(page.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
const page = ref(1)
|
|
||||||
const pageSize = ref(15)
|
|
||||||
const isOver = ref(false)
|
const isOver = ref(false)
|
||||||
// 获取已完成的任务
|
// 获取已完成的任务
|
||||||
const fetchFinishJobs = (page) => {
|
const fetchFinishJobs = () => {
|
||||||
if (!isLogin.value) {
|
if (!isLogin.value || isOver.value === true) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
httpGet(`/api/sd/jobs?status=1&page=${page}&page_size=${pageSize.value}`).then(res => {
|
loading.value = true
|
||||||
|
page.value = page.value + 1
|
||||||
|
|
||||||
|
httpGet(`/api/sd/jobs?status=1&page=${page.value}&page_size=${pageSize.value}`).then(res => {
|
||||||
if (res.data.length < pageSize.value) {
|
if (res.data.length < pageSize.value) {
|
||||||
isOver.value = true
|
isOver.value = true
|
||||||
}
|
}
|
||||||
if (page === 1) {
|
const imageList = res.data
|
||||||
finishedJobs.value = res.data
|
for (let i = 0; i < imageList.length; i++) {
|
||||||
} else {
|
imageList[i]["img_thumb"] = imageList[i]["img_url"] + "?imageView2/4/w/300/h/0/q/75"
|
||||||
finishedJobs.value = finishedJobs.value.concat(res.data)
|
|
||||||
}
|
}
|
||||||
|
if (page.value === 1) {
|
||||||
|
finishedJobs.value = imageList
|
||||||
|
} else {
|
||||||
|
finishedJobs.value = finishedJobs.value.concat(imageList)
|
||||||
|
}
|
||||||
|
|
||||||
|
loading.value = false
|
||||||
}).catch(e => {
|
}).catch(e => {
|
||||||
ElMessage.error("获取任务失败:" + e.message)
|
ElMessage.error("获取任务失败:" + e.message)
|
||||||
})
|
})
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
:colWidth="colWidth"
|
:colWidth="colWidth"
|
||||||
:distanceToScroll="100"
|
:distanceToScroll="100"
|
||||||
:isLoading="loading"
|
:isLoading="loading"
|
||||||
:isOver="false"
|
:isOver="isOver"
|
||||||
@scrollReachBottom="getNext">
|
@scrollReachBottom="getNext">
|
||||||
<template #default="slotProp">
|
<template #default="slotProp">
|
||||||
<div class="list-item">
|
<div class="list-item">
|
||||||
@ -81,7 +81,7 @@
|
|||||||
:colWidth="colWidth"
|
:colWidth="colWidth"
|
||||||
:distanceToScroll="100"
|
:distanceToScroll="100"
|
||||||
:isLoading="loading"
|
:isLoading="loading"
|
||||||
:isOver="false"
|
:isOver="isOver"
|
||||||
@scrollReachBottom="getNext">
|
@scrollReachBottom="getNext">
|
||||||
<template #default="slotProp">
|
<template #default="slotProp">
|
||||||
<div class="list-item">
|
<div class="list-item">
|
||||||
@ -132,7 +132,7 @@
|
|||||||
:colWidth="colWidth"
|
:colWidth="colWidth"
|
||||||
:distanceToScroll="100"
|
:distanceToScroll="100"
|
||||||
:isLoading="loading"
|
:isLoading="loading"
|
||||||
:isOver="false"
|
:isOver="isOver"
|
||||||
@scrollReachBottom="getNext">
|
@scrollReachBottom="getNext">
|
||||||
<template #default="slotProp">
|
<template #default="slotProp">
|
||||||
<div class="list-item">
|
<div class="list-item">
|
||||||
|
@ -81,10 +81,11 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="markdown" v-if="loading">
|
<div class="markdown" v-if="loading">
|
||||||
<div v-html="html"></div>
|
<div :style="{ height: rightBoxHeight + 'px', overflow:'auto',width:'80%' }" v-html="html"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="body" id="markmap" v-show="!loading">
|
<div class="body" id="markmap" v-show="!loading">
|
||||||
<svg ref="svgRef" :style="{ height: rightBoxHeight + 'px' }"/>
|
<svg ref="svgRef" :style="{ height: rightBoxHeight + 'px' }"/>
|
||||||
|
<div id="toolbar"></div>
|
||||||
</div>
|
</div>
|
||||||
</div><!-- end task list box -->
|
</div><!-- end task list box -->
|
||||||
</div>
|
</div>
|
||||||
@ -104,6 +105,7 @@ import {checkSession} from "@/action/session";
|
|||||||
import {httpGet} from "@/utils/http";
|
import {httpGet} from "@/utils/http";
|
||||||
import {ElMessage} from "element-plus";
|
import {ElMessage} from "element-plus";
|
||||||
import {Download} from "@element-plus/icons-vue";
|
import {Download} from "@element-plus/icons-vue";
|
||||||
|
import {Toolbar} from 'markmap-toolbar';
|
||||||
|
|
||||||
const leftBoxHeight = ref(window.innerHeight - 105)
|
const leftBoxHeight = ref(window.innerHeight - 105)
|
||||||
const rightBoxHeight = ref(window.innerHeight - 85)
|
const rightBoxHeight = ref(window.innerHeight - 85)
|
||||||
@ -140,6 +142,8 @@ onMounted(() => {
|
|||||||
initData()
|
initData()
|
||||||
try {
|
try {
|
||||||
markMap.value = Markmap.create(svgRef.value)
|
markMap.value = Markmap.create(svgRef.value)
|
||||||
|
const {el} = Toolbar.create(markMap.value);
|
||||||
|
document.getElementById('toolbar').append(el);
|
||||||
update()
|
update()
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
@ -153,7 +157,7 @@ const initData = () => {
|
|||||||
|
|
||||||
httpGet("/api/model/list").then(res => {
|
httpGet("/api/model/list").then(res => {
|
||||||
for (let v of res.data) {
|
for (let v of res.data) {
|
||||||
if (v.platform === "OpenAI") {
|
if (v.platform === "OpenAI" && v.value.indexOf("gpt-4-gizmo") === -1) {
|
||||||
models.value.push(v)
|
models.value.push(v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -167,7 +171,6 @@ const initData = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const update = () => {
|
const update = () => {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const {root} = transformer.transform(processContent(text.value))
|
const {root} = transformer.transform(processContent(text.value))
|
||||||
markMap.value.setData(root)
|
markMap.value.setData(root)
|
||||||
@ -242,6 +245,7 @@ const connect = (userId) => {
|
|||||||
if (event.data instanceof Blob) {
|
if (event.data instanceof Blob) {
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
reader.readAsText(event.data, "UTF-8")
|
reader.readAsText(event.data, "UTF-8")
|
||||||
|
const model = getModelById(modelID.value)
|
||||||
reader.onload = () => {
|
reader.onload = () => {
|
||||||
const data = JSON.parse(String(reader.result))
|
const data = JSON.parse(String(reader.result))
|
||||||
switch (data.type) {
|
switch (data.type) {
|
||||||
@ -255,6 +259,7 @@ const connect = (userId) => {
|
|||||||
case "end":
|
case "end":
|
||||||
loading.value = false
|
loading.value = false
|
||||||
content.value = processContent(text.value)
|
content.value = processContent(text.value)
|
||||||
|
loginUser.value.power -= model.power
|
||||||
nextTick(() => update())
|
nextTick(() => update())
|
||||||
break
|
break
|
||||||
case "error":
|
case "error":
|
||||||
@ -301,6 +306,14 @@ const changeModel = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getModelById = (modelId) => {
|
||||||
|
for (let e of models.value) {
|
||||||
|
if (e.id === modelId) {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// download SVG to png file
|
// download SVG to png file
|
||||||
const downloadImage = () => {
|
const downloadImage = () => {
|
||||||
const svgElement = document.getElementById("markmap");
|
const svgElement = document.getElementById("markmap");
|
||||||
|
173
web/src/views/admin/AIDrawing.vue
Normal file
173
web/src/views/admin/AIDrawing.vue
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
<template>
|
||||||
|
<el-form label-width="150px" label-position="right" class="draw-config">
|
||||||
|
<el-tabs type="border-card">
|
||||||
|
<el-tab-pane label="MJ-PLUS">
|
||||||
|
<div v-if="mjPlusConfigs">
|
||||||
|
<div class="config-item" v-for="(v,k) in mjPlusConfigs">
|
||||||
|
<el-form-item label="是否启用">
|
||||||
|
<el-switch v-model="v['Enabled']"/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="API 地址">
|
||||||
|
<el-input v-model="v['ApiURL']" placeholder="API 地址"/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="API 令牌">
|
||||||
|
<el-input v-model="v['ApiKey']" placeholder="API KEY"/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="绘画模式">
|
||||||
|
<el-select v-model="v['Mode']" placeholder="请选择模式">
|
||||||
|
<el-option v-for="item in mjModels" :value="item.value" :label="item.name" :key="item.value">{{
|
||||||
|
item.name
|
||||||
|
}}
|
||||||
|
</el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-button class="remove" type="danger" :icon="Delete" circle @click="removeItem(mjPlusConfigs,k)"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<el-empty v-else></el-empty>
|
||||||
|
|
||||||
|
<el-row style="justify-content: center; padding: 10px">
|
||||||
|
<el-button round @click="addConfig(mjPlusConfigs)">
|
||||||
|
<el-icon><Plus /></el-icon>
|
||||||
|
<span>新增配置</span>
|
||||||
|
</el-button>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
</el-tab-pane>
|
||||||
|
|
||||||
|
<el-tab-pane label="MJ-PROXY">
|
||||||
|
<div v-if="mjProxyConfigs">
|
||||||
|
<div class="config-item" v-for="(v,k) in mjProxyConfigs">
|
||||||
|
<el-form-item label="是否启用">
|
||||||
|
<el-switch v-model="v['Enabled']"/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="API 地址">
|
||||||
|
<el-input v-model="v['ApiURL']" placeholder="API 地址"/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="API 令牌">
|
||||||
|
<el-input v-model="v['ApiKey']" placeholder="API KEY"/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-button class="remove" type="danger" :icon="Delete" circle @click="removeItem(mjProxyConfigs,k)"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<el-empty v-else />
|
||||||
|
|
||||||
|
<el-row style="justify-content: center; padding: 10px">
|
||||||
|
<el-button round @click="addConfig(mjProxyConfigs)">
|
||||||
|
<el-icon>
|
||||||
|
<Plus/>
|
||||||
|
</el-icon>
|
||||||
|
<span>新增配置</span>
|
||||||
|
</el-button>
|
||||||
|
</el-row>
|
||||||
|
</el-tab-pane>
|
||||||
|
|
||||||
|
<el-tab-pane label="Stable-Diffusion">
|
||||||
|
<div v-if="sdConfigs">
|
||||||
|
<div class="config-item" v-for="(v,k) in sdConfigs">
|
||||||
|
<el-form-item label="是否启用">
|
||||||
|
<el-switch v-model="v['Enabled']"/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="API 地址">
|
||||||
|
<el-input v-model="v['ApiURL']" placeholder="API 地址"/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="API 令牌">
|
||||||
|
<el-input v-model="v['ApiKey']" placeholder="API KEY"/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="模型">
|
||||||
|
<el-input v-model="v['Model']" placeholder="绘画模型"/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-button class="remove" type="danger" :icon="Delete" circle @click="removeItem(sdConfigs,k)"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<el-empty v-else/>
|
||||||
|
|
||||||
|
<el-row style="justify-content: center; padding: 10px">
|
||||||
|
<el-button round @click="addConfig(sdConfigs)">
|
||||||
|
<el-icon>
|
||||||
|
<Plus/>
|
||||||
|
</el-icon>
|
||||||
|
<span>新增配置</span>
|
||||||
|
</el-button>
|
||||||
|
</el-row>
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
|
||||||
|
<div style="padding: 10px;">
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" @click="saveConfig()">保存</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
</el-form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import {ref} from "vue";
|
||||||
|
import {httpGet, httpPost} from "@/utils/http";
|
||||||
|
import {ElMessage} from "element-plus";
|
||||||
|
import {Delete, Plus} from "@element-plus/icons-vue";
|
||||||
|
|
||||||
|
// 变量定义
|
||||||
|
const sdConfigs = ref([])
|
||||||
|
const mjPlusConfigs = ref([])
|
||||||
|
const mjProxyConfigs = ref([])
|
||||||
|
const mjModels = ref([
|
||||||
|
{name: "慢速(Relax)", value: "relax"},
|
||||||
|
{name: "快速(Fast)", value: "fast"},
|
||||||
|
{name: "急速(Turbo)", value: "turbo"},
|
||||||
|
])
|
||||||
|
|
||||||
|
httpGet("/api/admin/config/get/draw").then(res => {
|
||||||
|
sdConfigs.value = res.data.sd
|
||||||
|
mjPlusConfigs.value = res.data.mj_plus
|
||||||
|
mjProxyConfigs.value = res.data.mj_proxy
|
||||||
|
}).catch(e =>{
|
||||||
|
ElMessage.error("获取AI绘画配置失败:"+e.message)
|
||||||
|
})
|
||||||
|
|
||||||
|
const addConfig = (configs) => {
|
||||||
|
configs.push({
|
||||||
|
Enabled: true,
|
||||||
|
ApiKey: '',
|
||||||
|
ApiURL: '',
|
||||||
|
Mode: 'fast'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const saveConfig = () => {
|
||||||
|
httpPost('/api/admin/config/update/draw', {
|
||||||
|
'sd': sdConfigs.value,
|
||||||
|
'mj_plus': mjPlusConfigs.value,
|
||||||
|
'mj_proxy': mjProxyConfigs.value
|
||||||
|
}).then(() => {
|
||||||
|
ElMessage.success("配置更新成功")
|
||||||
|
}).catch(e => {
|
||||||
|
ElMessage.error("操作失败:" + e.message)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const removeItem = (arr, k) => {
|
||||||
|
arr.splice(k, 1)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
.draw-config {
|
||||||
|
|
||||||
|
.config-item {
|
||||||
|
position relative
|
||||||
|
padding 15px 10px 10px 10px
|
||||||
|
border 1px solid var(--el-border-color)
|
||||||
|
border-radius 10px
|
||||||
|
margin-bottom 10px
|
||||||
|
|
||||||
|
.remove {
|
||||||
|
position absolute
|
||||||
|
right 15px
|
||||||
|
top 15px
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -269,8 +269,8 @@ onMounted(() => {
|
|||||||
const sorts = []
|
const sorts = []
|
||||||
sortedData.forEach((id, index) => {
|
sortedData.forEach((id, index) => {
|
||||||
ids.push(parseInt(id))
|
ids.push(parseInt(id))
|
||||||
sorts.push(index)
|
sorts.push(index + 1)
|
||||||
items.value[index].sort_num = index
|
items.value[index].sort_num = index + 1
|
||||||
})
|
})
|
||||||
|
|
||||||
httpPost("/api/admin/model/sort", {ids: ids, sorts: sorts}).then(() => {
|
httpPost("/api/admin/model/sort", {ids: ids, sorts: sorts}).then(() => {
|
||||||
@ -297,7 +297,7 @@ onUnmounted(() => {
|
|||||||
const add = function () {
|
const add = function () {
|
||||||
title.value = "新增模型"
|
title.value = "新增模型"
|
||||||
showDialog.value = true
|
showDialog.value = true
|
||||||
item.value = {enabled: true, weight: 1}
|
item.value = {enabled: true, weight: 1, open: true}
|
||||||
}
|
}
|
||||||
|
|
||||||
const edit = function (row) {
|
const edit = function (row) {
|
||||||
|
@ -2,6 +2,10 @@
|
|||||||
<div class="admin-login">
|
<div class="admin-login">
|
||||||
<div class="main">
|
<div class="main">
|
||||||
<div class="contain">
|
<div class="contain">
|
||||||
|
<div class="logo">
|
||||||
|
<el-image :src="logo" fit="cover" @click="router.push('/')"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="header">{{ title }}</div>
|
<div class="header">{{ title }}</div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="block">
|
<div class="block">
|
||||||
@ -42,9 +46,9 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
|
||||||
import {onMounted, ref} from "vue";
|
import {ref} from "vue";
|
||||||
import {Lock, UserFilled} from "@element-plus/icons-vue";
|
import {Lock, UserFilled} from "@element-plus/icons-vue";
|
||||||
import {httpPost} from "@/utils/http";
|
import {httpGet, httpPost} from "@/utils/http";
|
||||||
import {ElMessage} from "element-plus";
|
import {ElMessage} from "element-plus";
|
||||||
import {useRouter} from "vue-router";
|
import {useRouter} from "vue-router";
|
||||||
import FooterBar from "@/components/FooterBar.vue";
|
import FooterBar from "@/components/FooterBar.vue";
|
||||||
@ -52,15 +56,24 @@ import {setAdminToken} from "@/store/session";
|
|||||||
import {checkAdminSession} from "@/action/session";
|
import {checkAdminSession} from "@/action/session";
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const title = ref('ChatGPT Plus Admin');
|
const title = ref('Geek-AI Console');
|
||||||
const username = ref(process.env.VUE_APP_ADMIN_USER);
|
const username = ref(process.env.VUE_APP_ADMIN_USER);
|
||||||
const password = ref(process.env.VUE_APP_ADMIN_PASS);
|
const password = ref(process.env.VUE_APP_ADMIN_PASS);
|
||||||
|
const logo = ref("/images/logo.png")
|
||||||
|
|
||||||
checkAdminSession().then(() => {
|
checkAdminSession().then(() => {
|
||||||
router.push("/admin")
|
router.push("/admin")
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 加载系统配置
|
||||||
|
httpGet('/api/config/get?key=system').then(res => {
|
||||||
|
title.value = res.data.admin_title
|
||||||
|
logo.value = res.data.logo
|
||||||
|
}).catch(e => {
|
||||||
|
ElMessage.error("加载系统配置失败: " + e.message)
|
||||||
|
})
|
||||||
|
|
||||||
const keyupHandle = (e) => {
|
const keyupHandle = (e) => {
|
||||||
if (e.key === 'Enter') {
|
if (e.key === 'Enter') {
|
||||||
login();
|
login();
|
||||||
@ -107,10 +120,20 @@ const login = function () {
|
|||||||
border-radius 10px;
|
border-radius 10px;
|
||||||
background rgba(255, 255, 255, 0.3)
|
background rgba(255, 255, 255, 0.3)
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
text-align center
|
||||||
|
|
||||||
|
.el-image {
|
||||||
|
width 120px;
|
||||||
|
cursor pointer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.header {
|
.header {
|
||||||
width 100%
|
width 100%
|
||||||
margin-bottom 20px
|
margin-bottom 20px
|
||||||
font-size 24px
|
padding 10px
|
||||||
|
font-size 26px
|
||||||
text-align center
|
text-align center
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,7 +138,8 @@ onMounted(() => {
|
|||||||
const sorts = []
|
const sorts = []
|
||||||
sortedData.forEach((id, index) => {
|
sortedData.forEach((id, index) => {
|
||||||
ids.push(parseInt(id))
|
ids.push(parseInt(id))
|
||||||
sorts.push(index)
|
sorts.push(index + 1)
|
||||||
|
items.value[index].sort_num = index + 1
|
||||||
})
|
})
|
||||||
|
|
||||||
httpPost("/api/admin/menu/sort", {ids: ids, sorts: sorts}).catch(e => {
|
httpPost("/api/admin/menu/sort", {ids: ids, sorts: sorts}).catch(e => {
|
||||||
|
@ -142,7 +142,8 @@ onMounted(() => {
|
|||||||
const sorts = []
|
const sorts = []
|
||||||
sortedData.forEach((id, index) => {
|
sortedData.forEach((id, index) => {
|
||||||
ids.push(parseInt(id))
|
ids.push(parseInt(id))
|
||||||
sorts.push(index)
|
sorts.push(index + 1)
|
||||||
|
items.value[index].sort_num = index + 1
|
||||||
})
|
})
|
||||||
|
|
||||||
httpPost("/api/admin/product/sort", {ids: ids, sorts: sorts}).catch(e => {
|
httpPost("/api/admin/product/sort", {ids: ids, sorts: sorts}).catch(e => {
|
||||||
|
@ -228,7 +228,8 @@ const fetchData = () => {
|
|||||||
const sorts = []
|
const sorts = []
|
||||||
sortedData.forEach((id, index) => {
|
sortedData.forEach((id, index) => {
|
||||||
ids.push(parseInt(id))
|
ids.push(parseInt(id))
|
||||||
sorts.push(index)
|
sorts.push(index+1)
|
||||||
|
items.value[index].sort_num = index + 1
|
||||||
})
|
})
|
||||||
|
|
||||||
httpPost("/api/admin/role/sort", {ids: ids, sorts: sorts}).catch(e => {
|
httpPost("/api/admin/role/sort", {ids: ids, sorts: sorts}).catch(e => {
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="system-config" v-loading="loading">
|
<div class="system-config" v-loading="loading">
|
||||||
|
|
||||||
<el-tabs v-model="activeName" class="demo-tabs">
|
<el-tabs v-model="activeName" class="sys-tabs">
|
||||||
<el-tab-pane label="基本设置" name="basic">
|
<el-tab-pane label="系统配置" name="basic">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<el-form :model="system" label-width="150px" label-position="right" ref="systemFormRef" :rules="rules">
|
<el-form :model="system" label-width="150px" label-position="right" ref="systemFormRef" :rules="rules">
|
||||||
|
<el-tabs type="border-card">
|
||||||
|
<el-tab-pane label="基础配置">
|
||||||
<el-form-item label="网站标题" prop="title">
|
<el-form-item label="网站标题" prop="title">
|
||||||
<el-input v-model="system['title']"/>
|
<el-input v-model="system['title']"/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -27,6 +29,111 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-input>
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="开放注册" prop="enabled_register">
|
||||||
|
<el-switch v-model="system['enabled_register']"/>
|
||||||
|
<el-tooltip
|
||||||
|
effect="dark"
|
||||||
|
content="关闭注册之后只能通过管理后台添加用户"
|
||||||
|
raw-content
|
||||||
|
placement="right"
|
||||||
|
>
|
||||||
|
<el-icon>
|
||||||
|
<InfoFilled/>
|
||||||
|
</el-icon>
|
||||||
|
</el-tooltip>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="注册方式" prop="register_ways">
|
||||||
|
<el-checkbox-group v-model="system['register_ways']">
|
||||||
|
<el-checkbox value="mobile">手机注册</el-checkbox>
|
||||||
|
<el-checkbox value="email">邮箱注册</el-checkbox>
|
||||||
|
<el-checkbox value="username">用户名注册</el-checkbox>
|
||||||
|
</el-checkbox-group>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="微信客服二维码" prop="wechat_card_url">
|
||||||
|
<el-input v-model="system['wechat_card_url']" placeholder="微信客服二维码">
|
||||||
|
<template #append>
|
||||||
|
<el-upload
|
||||||
|
:auto-upload="true"
|
||||||
|
:show-file-list="false"
|
||||||
|
@click="beforeUpload('wechat_card_url')"
|
||||||
|
:http-request="uploadImg"
|
||||||
|
>
|
||||||
|
<el-icon class="uploader-icon">
|
||||||
|
<UploadFilled/>
|
||||||
|
</el-icon>
|
||||||
|
</el-upload>
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="默认AI模型" prop="default_models">
|
||||||
|
<template #default>
|
||||||
|
<div class="tip-input">
|
||||||
|
<el-select
|
||||||
|
v-model="system['default_models']"
|
||||||
|
multiple
|
||||||
|
:filterable="true"
|
||||||
|
placeholder="选择AI模型,多选"
|
||||||
|
style="width: 100%"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in models"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.name"
|
||||||
|
:value="item.id"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
<div class="info">
|
||||||
|
<el-tooltip
|
||||||
|
class="box-item"
|
||||||
|
effect="dark"
|
||||||
|
content="新用户注册默认开通的 AI 模型"
|
||||||
|
placement="right"
|
||||||
|
>
|
||||||
|
<el-icon>
|
||||||
|
<InfoFilled/>
|
||||||
|
</el-icon>
|
||||||
|
</el-tooltip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="开启聊天上下文">
|
||||||
|
<el-switch v-model="system['enable_context']"/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="会话上下文深度">
|
||||||
|
<div class="tip-input-line">
|
||||||
|
<el-input-number v-model="system['context_deep']" :min="0" :max="10"/>
|
||||||
|
<div class="tip">会话上下文深度:在老会话中继续会话,默认加载多少条聊天记录作为上下文。如果设置为
|
||||||
|
0
|
||||||
|
则不加载聊天记录,仅仅使用当前角色的上下文。该配置参数最好设置需要为偶数,否则将无法兼容百度的 API。
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="SD反向提示词" prop="sd_neg_prompt">
|
||||||
|
<div class="tip-input">
|
||||||
|
<el-input v-model="system['sd_neg_prompt']" placeholder=""/>
|
||||||
|
<div class="info">
|
||||||
|
<el-tooltip
|
||||||
|
effect="dark"
|
||||||
|
content="Stable-Diffusion 绘画默认反向提示词"
|
||||||
|
raw-content
|
||||||
|
placement="right"
|
||||||
|
>
|
||||||
|
<el-icon>
|
||||||
|
<InfoFilled/>
|
||||||
|
</el-icon>
|
||||||
|
</el-tooltip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
</el-tab-pane>
|
||||||
|
|
||||||
|
<el-tab-pane label="算力配置">
|
||||||
<el-form-item label="注册赠送算力" prop="init_power">
|
<el-form-item label="注册赠送算力" prop="init_power">
|
||||||
<el-input v-model.number="system['init_power']" placeholder="新用户注册赠送算力"/>
|
<el-input v-model.number="system['init_power']" placeholder="新用户注册赠送算力"/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -84,28 +191,8 @@
|
|||||||
<el-form-item label="DALL-E-3算力" prop="dall_power">
|
<el-form-item label="DALL-E-3算力" prop="dall_power">
|
||||||
<el-input v-model.number="system['dall_power']" placeholder="使用DALL-E-3画一张图消耗算力"/>
|
<el-input v-model.number="system['dall_power']" placeholder="使用DALL-E-3画一张图消耗算力"/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="开放注册" prop="enabled_register">
|
</el-tab-pane>
|
||||||
<el-switch v-model="system['enabled_register']"/>
|
<el-tab-pane label="众筹支付">
|
||||||
<el-tooltip
|
|
||||||
effect="dark"
|
|
||||||
content="关闭注册之后只能通过管理后台添加用户"
|
|
||||||
raw-content
|
|
||||||
placement="right"
|
|
||||||
>
|
|
||||||
<el-icon>
|
|
||||||
<InfoFilled/>
|
|
||||||
</el-icon>
|
|
||||||
</el-tooltip>
|
|
||||||
</el-form-item>
|
|
||||||
|
|
||||||
<el-form-item label="注册方式" prop="register_ways">
|
|
||||||
<el-checkbox-group v-model="system['register_ways']">
|
|
||||||
<el-checkbox label="mobile">手机注册</el-checkbox>
|
|
||||||
<el-checkbox label="email">邮箱注册</el-checkbox>
|
|
||||||
<el-checkbox label="username">用户名注册</el-checkbox>
|
|
||||||
</el-checkbox-group>
|
|
||||||
</el-form-item>
|
|
||||||
|
|
||||||
<el-form-item label="启用众筹功能" prop="enabled_reward">
|
<el-form-item label="启用众筹功能" prop="enabled_reward">
|
||||||
<el-switch v-model="system['enabled_reward']"/>
|
<el-switch v-model="system['enabled_reward']"/>
|
||||||
<el-tooltip
|
<el-tooltip
|
||||||
@ -143,23 +230,6 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-form-item label="微信客服二维码" prop="wechat_card_url">
|
|
||||||
<el-input v-model="system['wechat_card_url']" placeholder="微信客服二维码">
|
|
||||||
<template #append>
|
|
||||||
<el-upload
|
|
||||||
:auto-upload="true"
|
|
||||||
:show-file-list="false"
|
|
||||||
@click="beforeUpload('wechat_card_url')"
|
|
||||||
:http-request="uploadImg"
|
|
||||||
>
|
|
||||||
<el-icon class="uploader-icon">
|
|
||||||
<UploadFilled/>
|
|
||||||
</el-icon>
|
|
||||||
</el-upload>
|
|
||||||
</template>
|
|
||||||
</el-input>
|
|
||||||
</el-form-item>
|
|
||||||
|
|
||||||
<el-form-item label="订单超时时间" prop="order_pay_timeout">
|
<el-form-item label="订单超时时间" prop="order_pay_timeout">
|
||||||
<div class="tip-input">
|
<div class="tip-input">
|
||||||
<el-input v-model.number="system['order_pay_timeout']" placeholder="单位:秒"/>
|
<el-input v-model.number="system['order_pay_timeout']" placeholder="单位:秒"/>
|
||||||
@ -195,62 +265,23 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
|
||||||
<el-form-item label="默认AI模型" prop="default_models">
|
<div style="padding: 10px;">
|
||||||
<template #default>
|
|
||||||
<div class="tip-input">
|
|
||||||
<el-select
|
|
||||||
v-model="system['default_models']"
|
|
||||||
multiple
|
|
||||||
:filterable="true"
|
|
||||||
placeholder="选择AI模型,多选"
|
|
||||||
style="width: 100%"
|
|
||||||
>
|
|
||||||
<el-option
|
|
||||||
v-for="item in models"
|
|
||||||
:key="item.id"
|
|
||||||
:label="item.name"
|
|
||||||
:value="item.id"
|
|
||||||
/>
|
|
||||||
</el-select>
|
|
||||||
<div class="info">
|
|
||||||
<el-tooltip
|
|
||||||
class="box-item"
|
|
||||||
effect="dark"
|
|
||||||
content="新用户注册默认开通的 AI 模型"
|
|
||||||
placement="right"
|
|
||||||
>
|
|
||||||
<el-icon>
|
|
||||||
<InfoFilled/>
|
|
||||||
</el-icon>
|
|
||||||
</el-tooltip>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</el-form-item>
|
|
||||||
|
|
||||||
<el-form-item label="开启聊天上下文">
|
|
||||||
<el-switch v-model="system['enable_context']"/>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="会话上下文深度">
|
|
||||||
<div class="tip-input-line">
|
|
||||||
<el-input-number v-model="system['context_deep']" :min="0" :max="10"/>
|
|
||||||
<div class="tip">会话上下文深度:在老会话中继续会话,默认加载多少条聊天记录作为上下文。如果设置为
|
|
||||||
0
|
|
||||||
则不加载聊天记录,仅仅使用当前角色的上下文。该配置参数最好设置需要为偶数,否则将无法兼容百度的 API。
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" @click="save('system')">保存</el-button>
|
<el-button type="primary" @click="save('system')">保存</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
</div>
|
||||||
</el-form>
|
</el-form>
|
||||||
</div>
|
</div>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane label="公告配置" name="notice">
|
<el-tab-pane label="公告配置" name="notice">
|
||||||
<md-editor class="mgb20" v-model="notice" @on-upload-img="onUploadImg"/>
|
<md-editor class="mgb20" v-model="notice" @on-upload-img="onUploadImg"/>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
|
<div style="padding-top: 10px;margin-left: 150px;">
|
||||||
<el-button type="primary" @click="save('notice')">保存</el-button>
|
<el-button type="primary" @click="save('notice')">保存</el-button>
|
||||||
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
|
|
||||||
@ -258,6 +289,10 @@
|
|||||||
<Menu/>
|
<Menu/>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
|
|
||||||
|
<el-tab-pane label="AI绘图配置" name="AIDrawing">
|
||||||
|
<AIDrawing/>
|
||||||
|
</el-tab-pane>
|
||||||
|
|
||||||
<el-tab-pane label="授权激活" name="license">
|
<el-tab-pane label="授权激活" name="license">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<el-descriptions
|
<el-descriptions
|
||||||
@ -318,6 +353,7 @@ import MdEditor from "md-editor-v3";
|
|||||||
import 'md-editor-v3/lib/style.css';
|
import 'md-editor-v3/lib/style.css';
|
||||||
import Menu from "@/views/admin/Menu.vue";
|
import Menu from "@/views/admin/Menu.vue";
|
||||||
import {dateFormat} from "@/utils/libs";
|
import {dateFormat} from "@/utils/libs";
|
||||||
|
import AIDrawing from "@/views/admin/AIDrawing.vue";
|
||||||
|
|
||||||
const activeName = ref('basic')
|
const activeName = ref('basic')
|
||||||
const system = ref({models: []})
|
const system = ref({models: []})
|
||||||
@ -457,11 +493,11 @@ const onUploadImg = (files, callback) => {
|
|||||||
display flex
|
display flex
|
||||||
justify-content center
|
justify-content center
|
||||||
|
|
||||||
.el-tabs {
|
.sys-tabs {
|
||||||
width 100%
|
width 100%
|
||||||
background-color var(--el-bg-color)
|
background-color var(--el-bg-color)
|
||||||
padding 10px 20px 40px 20px
|
padding 10px 20px 40px 20px
|
||||||
border: 1px solid var(--el-border-color);
|
//border: 1px solid var(--el-border-color);
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
.el-form {
|
.el-form {
|
||||||
|
637
web/src/views/mobile/ImageMj.vue
Normal file
637
web/src/views/mobile/ImageMj.vue
Normal file
@ -0,0 +1,637 @@
|
|||||||
|
<template>
|
||||||
|
<div class="mobile-mj">
|
||||||
|
<van-form @submit="generate">
|
||||||
|
<div class="text-line">图片比例</div>
|
||||||
|
<div class="text-line">
|
||||||
|
<van-row :gutter="10">
|
||||||
|
<van-col :span="4" v-for="item in rates" :key="item.value">
|
||||||
|
<div
|
||||||
|
:class="item.value === params.rate ? 'rate active' : 'rate'"
|
||||||
|
@click="changeRate(item)">
|
||||||
|
<div class="icon">
|
||||||
|
<van-image :src="item.img" fit="cover"></van-image>
|
||||||
|
</div>
|
||||||
|
<div class="text">{{ item.text }}</div>
|
||||||
|
</div>
|
||||||
|
</van-col>
|
||||||
|
</van-row>
|
||||||
|
</div>
|
||||||
|
<div class="text-line">模型选择</div>
|
||||||
|
<div class="text-line">
|
||||||
|
<van-row :gutter="10">
|
||||||
|
<van-col :span="8" v-for="item in models" :key="item.value">
|
||||||
|
<div :class="item.value === params.model ? 'model active' : 'model'"
|
||||||
|
@click="changeModel(item)">
|
||||||
|
<div class="icon">
|
||||||
|
<van-image :src="item.img" fit="cover"></van-image>
|
||||||
|
</div>
|
||||||
|
<div class="text">
|
||||||
|
<van-text-ellipsis :content="item.text"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</van-col>
|
||||||
|
</van-row>
|
||||||
|
</div>
|
||||||
|
<div class="text-line">
|
||||||
|
<van-field label="创意度">
|
||||||
|
<template #input>
|
||||||
|
<van-slider v-model.number="params.chaos" :max="100" :step="1"
|
||||||
|
@update:model-value="showToast('当前值:' + params.chaos)"/>
|
||||||
|
</template>
|
||||||
|
</van-field>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="text-line">
|
||||||
|
<van-field label="风格化">
|
||||||
|
<template #input>
|
||||||
|
<van-slider v-model.number="params.stylize" :max="1000" :step="1"
|
||||||
|
@update:model-value="showToast('当前值:' + params.stylize)"/>
|
||||||
|
</template>
|
||||||
|
</van-field>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="text-line">
|
||||||
|
<van-field label="原始模式">
|
||||||
|
<template #input>
|
||||||
|
<van-switch v-model="params.raw"/>
|
||||||
|
</template>
|
||||||
|
</van-field>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="text-line">
|
||||||
|
<van-tabs v-model:active="activeName" @change="tabChange" animated>
|
||||||
|
<van-tab title="文生图" name="txt2img">
|
||||||
|
<div class="text-line">
|
||||||
|
<van-field v-model="params.prompt"
|
||||||
|
rows="3"
|
||||||
|
autosize
|
||||||
|
type="textarea"
|
||||||
|
placeholder="请在此输入绘画提示词,系统会自动翻译中文提示词,高手请直接输入英文提示词"/>
|
||||||
|
</div>
|
||||||
|
</van-tab>
|
||||||
|
<van-tab title="图生图" name="img2img">
|
||||||
|
<div class="text-line">
|
||||||
|
<van-field v-model="params.prompt"
|
||||||
|
rows="3"
|
||||||
|
autosize
|
||||||
|
type="textarea"
|
||||||
|
placeholder="请在此输入绘画提示词,系统会自动翻译中文提示词,高手请直接输入英文提示词"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="text-line">
|
||||||
|
<van-uploader v-model="imgList" :after-read="uploadImg"/>
|
||||||
|
</div>
|
||||||
|
<div class="text-line">
|
||||||
|
<van-field label="垫图权重">
|
||||||
|
<template #input>
|
||||||
|
<van-slider v-model.number="params.iw" :max="1" :step="0.01"
|
||||||
|
@update:model-value="showToast('当前值:' + params.iw)"/>
|
||||||
|
</template>
|
||||||
|
</van-field>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="tip-text">提示:只有于 niji6 和 v6 模型支持一致性功能,如果选择其他模型此功能将会生成失败。</div>
|
||||||
|
<van-cell-group>
|
||||||
|
<van-field
|
||||||
|
v-model="params.cref"
|
||||||
|
center
|
||||||
|
clearable
|
||||||
|
label="角色一致性"
|
||||||
|
placeholder="请输入图片URL或者上传图片"
|
||||||
|
>
|
||||||
|
<template #button>
|
||||||
|
<van-uploader @click="beforeUpload('cref')" :after-read="uploadImg">
|
||||||
|
<van-button size="mini" type="primary" icon="plus"/>
|
||||||
|
</van-uploader>
|
||||||
|
</template>
|
||||||
|
</van-field>
|
||||||
|
</van-cell-group>
|
||||||
|
|
||||||
|
<van-cell-group>
|
||||||
|
<van-field
|
||||||
|
v-model="params.sref"
|
||||||
|
center
|
||||||
|
clearable
|
||||||
|
label="风格一致性"
|
||||||
|
placeholder="请输入图片URL或者上传图片"
|
||||||
|
>
|
||||||
|
<template #button>
|
||||||
|
<van-uploader @click="beforeUpload('sref')" :after-read="uploadImg">
|
||||||
|
<van-button size="mini" type="primary" icon="plus"/>
|
||||||
|
</van-uploader>
|
||||||
|
</template>
|
||||||
|
</van-field>
|
||||||
|
</van-cell-group>
|
||||||
|
|
||||||
|
<div class="text-line">
|
||||||
|
<van-field label="一致性权重">
|
||||||
|
<template #input>
|
||||||
|
<van-slider v-model.number="params.cw" :max="100" :step="1"
|
||||||
|
@update:model-value="showToast('当前值:' + params.cw)"/>
|
||||||
|
</template>
|
||||||
|
</van-field>
|
||||||
|
</div>
|
||||||
|
</van-tab>
|
||||||
|
<van-tab title="融图" name="blend">
|
||||||
|
<div class="tip-text">请上传两张以上的图片,最多不超过五张,超过五张图片请使用图生图功能。</div>
|
||||||
|
<div class="text-line">
|
||||||
|
<van-uploader v-model="imgList" :after-read="uploadImg"/>
|
||||||
|
</div>
|
||||||
|
</van-tab>
|
||||||
|
<van-tab title="换脸" name="swapFace">
|
||||||
|
<div class="tip-text">请上传两张有脸部的图片,用左边图片的脸替换右边图片的脸。</div>
|
||||||
|
<div class="text-line">
|
||||||
|
<van-uploader v-model="imgList" :after-read="uploadImg"/>
|
||||||
|
</div>
|
||||||
|
</van-tab>
|
||||||
|
</van-tabs>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="text-line">
|
||||||
|
<van-collapse v-model="activeColspan">
|
||||||
|
<van-collapse-item title="反向提示词" name="neg_prompt">
|
||||||
|
<van-field
|
||||||
|
v-model="params.neg_prompt"
|
||||||
|
rows="3"
|
||||||
|
autosize
|
||||||
|
type="textarea"
|
||||||
|
placeholder="不想出现在图片上的元素(例如:树,建筑)"
|
||||||
|
/>
|
||||||
|
</van-collapse-item>
|
||||||
|
</van-collapse>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="text-line">
|
||||||
|
<el-tag>绘图消耗{{ mjPower }}算力,U/V 操作消耗{{ mjActionPower }}算力,当前算力:{{ power }}</el-tag>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="text-line">
|
||||||
|
<van-button round block type="primary" native-type="submit">
|
||||||
|
立即生成
|
||||||
|
</van-button>
|
||||||
|
</div>
|
||||||
|
</van-form>
|
||||||
|
|
||||||
|
<h3>任务列表</h3>
|
||||||
|
<div class="running-job-list">
|
||||||
|
<van-empty v-if="runningJobs.length ===0"
|
||||||
|
image="https://fastly.jsdelivr.net/npm/@vant/assets/custom-empty-image.png"
|
||||||
|
image-size="80"
|
||||||
|
description="暂无记录"
|
||||||
|
/>
|
||||||
|
<van-grid :gutter="10" :column-num="3" v-else>
|
||||||
|
<van-grid-item v-for="item in runningJobs">
|
||||||
|
<div v-if="item.progress > 0">
|
||||||
|
<van-image :src="item['img_url']">
|
||||||
|
<template v-slot:error>加载失败</template>
|
||||||
|
</van-image>
|
||||||
|
<div class="progress">
|
||||||
|
<van-circle
|
||||||
|
v-model:current-rate="item.progress"
|
||||||
|
:rate="item.progress"
|
||||||
|
:speed="100"
|
||||||
|
:text="item.progress+'%'"
|
||||||
|
:stroke-width="60"
|
||||||
|
size="90px"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-else class="task-in-queue">
|
||||||
|
<span class="icon"><i class="iconfont icon-quick-start"></i></span>
|
||||||
|
<span class="text">排队中</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</van-grid-item>
|
||||||
|
</van-grid>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3>创作记录</h3>
|
||||||
|
<div class="finish-job-list">
|
||||||
|
<van-empty v-if="finishedJobs.length ===0"
|
||||||
|
image="https://fastly.jsdelivr.net/npm/@vant/assets/custom-empty-image.png"
|
||||||
|
image-size="80"
|
||||||
|
description="暂无记录"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<van-list v-else
|
||||||
|
v-model:error="error"
|
||||||
|
v-model:loading="loading"
|
||||||
|
:finished="finished"
|
||||||
|
error-text="请求失败,点击重新加载"
|
||||||
|
finished-text="没有更多了"
|
||||||
|
@load="onLoad"
|
||||||
|
>
|
||||||
|
<van-grid :gutter="10" :column-num="2">
|
||||||
|
<van-grid-item v-for="item in finishedJobs">
|
||||||
|
<div class="job-item">
|
||||||
|
<van-image
|
||||||
|
:src="item['thumb_url']"
|
||||||
|
:class="item['can_opt'] ? '' : 'upscale'"
|
||||||
|
lazy-load
|
||||||
|
@click="imageView(item)"
|
||||||
|
fit="cover">
|
||||||
|
<template v-slot:loading>
|
||||||
|
<van-loading type="spinner" size="20"/>
|
||||||
|
</template>
|
||||||
|
</van-image>
|
||||||
|
|
||||||
|
<div class="opt" v-if="item['can_opt']">
|
||||||
|
|
||||||
|
<van-grid :gutter="3" :column-num="4">
|
||||||
|
<van-grid-item><a @click="upscale(1, item)" class="opt-btn">U1</a></van-grid-item>
|
||||||
|
<van-grid-item><a @click="upscale(2, item)" class="opt-btn">U2</a></van-grid-item>
|
||||||
|
<van-grid-item><a @click="upscale(3, item)" class="opt-btn">U3</a></van-grid-item>
|
||||||
|
<van-grid-item><a @click="upscale(4, item)" class="opt-btn">U4</a></van-grid-item>
|
||||||
|
<van-grid-item><a @click="variation(1, item)" class="opt-btn">V1</a></van-grid-item>
|
||||||
|
<van-grid-item><a @click="variation(2, item)" class="opt-btn">V2</a></van-grid-item>
|
||||||
|
<van-grid-item><a @click="variation(3, item)" class="opt-btn">V3</a></van-grid-item>
|
||||||
|
<van-grid-item><a @click="variation(4, item)" class="opt-btn">V4</a></van-grid-item>
|
||||||
|
</van-grid>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="remove">
|
||||||
|
<el-button type="danger" :icon="Delete" @click="removeImage(item)" circle/>
|
||||||
|
<el-button type="warning" v-if="item.publish" @click="publishImage(item, false)"
|
||||||
|
circle>
|
||||||
|
<i class="iconfont icon-cancel-share"></i>
|
||||||
|
</el-button>
|
||||||
|
<el-button type="success" v-else @click="publishImage(item, true)" circle>
|
||||||
|
<i class="iconfont icon-share-bold"></i>
|
||||||
|
</el-button>
|
||||||
|
<el-button type="primary" @click="showPrompt(item)" circle>
|
||||||
|
<i class="iconfont icon-prompt"></i>
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</van-grid-item>
|
||||||
|
</van-grid>
|
||||||
|
</van-list>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import {nextTick, onMounted, onUnmounted, ref} from "vue";
|
||||||
|
import {
|
||||||
|
showConfirmDialog,
|
||||||
|
showFailToast,
|
||||||
|
showNotify,
|
||||||
|
showToast,
|
||||||
|
showDialog,
|
||||||
|
showImagePreview,
|
||||||
|
showSuccessToast
|
||||||
|
} from "vant";
|
||||||
|
import {httpGet, httpPost} from "@/utils/http";
|
||||||
|
import Compressor from "compressorjs";
|
||||||
|
import {getSessionId} from "@/store/session";
|
||||||
|
import {checkSession} from "@/action/session";
|
||||||
|
import {useRouter} from "vue-router";
|
||||||
|
import {Delete} from "@element-plus/icons-vue";
|
||||||
|
|
||||||
|
const activeColspan = ref([""])
|
||||||
|
|
||||||
|
const rates = [
|
||||||
|
{css: "square", value: "1:1", text: "1:1", img: "/images/mj/rate_1_1.png"},
|
||||||
|
{css: "size2-3", value: "2:3", text: "2:3", img: "/images/mj/rate_3_4.png"},
|
||||||
|
{css: "size3-4", value: "3:4", text: "3:4", img: "/images/mj/rate_3_4.png"},
|
||||||
|
{css: "size4-3", value: "4:3", text: "4:3", img: "/images/mj/rate_4_3.png"},
|
||||||
|
{css: "size16-9", value: "16:9", text: "16:9", img: "/images/mj/rate_16_9.png"},
|
||||||
|
{css: "size9-16", value: "9:16", text: "9:16", img: "/images/mj/rate_9_16.png"},
|
||||||
|
]
|
||||||
|
const models = [
|
||||||
|
{text: "MJ-6.0", value: " --v 6", img: "/images/mj/mj-v6.png"},
|
||||||
|
{text: "MJ-5.2", value: " --v 5.2", img: "/images/mj/mj-v5.2.png"},
|
||||||
|
{text: "Niji5", value: " --niji 5", img: "/images/mj/mj-niji.png"},
|
||||||
|
{text: "Niji5 可爱", value: " --niji 5 --style cute", img: "/images/mj/nj1.jpg"},
|
||||||
|
{text: "Niji5 风景", value: " --niji 5 --style scenic", img: "/images/mj/nj2.jpg"},
|
||||||
|
{text: "Niji6", value: " --niji 6", img: "/images/mj/nj3.jpg"},
|
||||||
|
]
|
||||||
|
const imgList = ref([])
|
||||||
|
const params = ref({
|
||||||
|
task_type: "image",
|
||||||
|
rate: rates[0].value,
|
||||||
|
model: models[0].value,
|
||||||
|
chaos: 0,
|
||||||
|
stylize: 0,
|
||||||
|
seed: 0,
|
||||||
|
img_arr: [],
|
||||||
|
raw: false,
|
||||||
|
iw: 0,
|
||||||
|
prompt: "",
|
||||||
|
neg_prompt: "",
|
||||||
|
tile: false,
|
||||||
|
quality: 0,
|
||||||
|
cref: "",
|
||||||
|
sref: "",
|
||||||
|
cw: 0,
|
||||||
|
})
|
||||||
|
const userId = ref(0)
|
||||||
|
const router = useRouter()
|
||||||
|
const runningJobs = ref([])
|
||||||
|
const finishedJobs = ref([])
|
||||||
|
const socket = ref(null)
|
||||||
|
const power = ref(0)
|
||||||
|
const activeName = ref("txt2img")
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
checkSession().then(user => {
|
||||||
|
power.value = user['power']
|
||||||
|
userId.value = user.id
|
||||||
|
|
||||||
|
fetchRunningJobs()
|
||||||
|
fetchFinishJobs(1)
|
||||||
|
connect()
|
||||||
|
|
||||||
|
}).catch(() => {
|
||||||
|
router.push('/login')
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
socket.value = null
|
||||||
|
})
|
||||||
|
|
||||||
|
const mjPower = ref(1)
|
||||||
|
const mjActionPower = ref(1)
|
||||||
|
httpGet("/api/config/get?key=system").then(res => {
|
||||||
|
mjPower.value = res.data["mj_power"]
|
||||||
|
mjActionPower.value = res.data["mj_action_power"]
|
||||||
|
}).catch(e => {
|
||||||
|
showNotify({type: "danger", message: "获取系统配置失败:" + e.message})
|
||||||
|
})
|
||||||
|
|
||||||
|
const heartbeatHandle = ref(null)
|
||||||
|
const connect = () => {
|
||||||
|
let host = process.env.VUE_APP_WS_HOST
|
||||||
|
if (host === '') {
|
||||||
|
if (location.protocol === 'https:') {
|
||||||
|
host = 'wss://' + location.host;
|
||||||
|
} else {
|
||||||
|
host = 'ws://' + location.host;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 心跳函数
|
||||||
|
const sendHeartbeat = () => {
|
||||||
|
clearTimeout(heartbeatHandle.value)
|
||||||
|
new Promise((resolve, reject) => {
|
||||||
|
if (socket.value !== null) {
|
||||||
|
socket.value.send(JSON.stringify({type: "heartbeat", content: "ping"}))
|
||||||
|
}
|
||||||
|
resolve("success")
|
||||||
|
}).then(() => {
|
||||||
|
heartbeatHandle.value = setTimeout(() => sendHeartbeat(), 5000)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const _socket = new WebSocket(host + `/api/mj/client?user_id=${userId.value}`);
|
||||||
|
_socket.addEventListener('open', () => {
|
||||||
|
socket.value = _socket;
|
||||||
|
|
||||||
|
// 发送心跳消息
|
||||||
|
sendHeartbeat()
|
||||||
|
});
|
||||||
|
|
||||||
|
_socket.addEventListener('message', event => {
|
||||||
|
if (event.data instanceof Blob) {
|
||||||
|
fetchRunningJobs()
|
||||||
|
fetchFinishJobs(1)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
_socket.addEventListener('close', () => {
|
||||||
|
if (socket.value !== null) {
|
||||||
|
connect()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取运行中的任务
|
||||||
|
const fetchRunningJobs = (userId) => {
|
||||||
|
httpGet(`/api/mj/jobs?status=0&user_id=${userId}`).then(res => {
|
||||||
|
const jobs = res.data
|
||||||
|
const _jobs = []
|
||||||
|
for (let i = 0; i < jobs.length; i++) {
|
||||||
|
if (jobs[i].progress === -1) {
|
||||||
|
showNotify({
|
||||||
|
message: `任务执行失败:${jobs[i]['err_msg']}`,
|
||||||
|
type: 'danger',
|
||||||
|
})
|
||||||
|
if (jobs[i].type === 'image') {
|
||||||
|
power.value += mjPower.value
|
||||||
|
} else {
|
||||||
|
power.value += mjActionPower.value
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
_jobs.push(jobs[i])
|
||||||
|
}
|
||||||
|
runningJobs.value = _jobs
|
||||||
|
}).catch(e => {
|
||||||
|
showNotify({type: "danger", message: "获取任务失败:" + e.message})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const loading = ref(false)
|
||||||
|
const finished = ref(false)
|
||||||
|
const error = ref(false)
|
||||||
|
const page = ref(0)
|
||||||
|
const pageSize = ref(10)
|
||||||
|
const fetchFinishJobs = (page) => {
|
||||||
|
loading.value = true
|
||||||
|
// 获取已完成的任务
|
||||||
|
httpGet(`/api/mj/jobs?status=1&page=${page}&page_size=${pageSize.value}`).then(res => {
|
||||||
|
const jobs = res.data
|
||||||
|
for (let i = 0; i < jobs.length; i++) {
|
||||||
|
if (jobs[i].progress === -1) {
|
||||||
|
showNotify({
|
||||||
|
message: `任务ID:${jobs[i]['task_id']} 原因:${jobs[i]['err_msg']}`,
|
||||||
|
type: 'danger',
|
||||||
|
})
|
||||||
|
if (jobs[i].type === 'image') {
|
||||||
|
power.value += mjPower.value
|
||||||
|
} else {
|
||||||
|
power.value += mjActionPower.value
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jobs[i]['use_proxy']) {
|
||||||
|
jobs[i]['thumb_url'] = jobs[i]['img_url'] + '?x-oss-process=image/quality,q_60&format=webp'
|
||||||
|
} else {
|
||||||
|
if (jobs[i].type === 'upscale' || jobs[i].type === 'swapFace') {
|
||||||
|
jobs[i]['thumb_url'] = jobs[i]['img_url'] + '?imageView2/1/w/480/h/600/q/75'
|
||||||
|
} else {
|
||||||
|
jobs[i]['thumb_url'] = jobs[i]['img_url'] + '?imageView2/1/w/480/h/480/q/75'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jobs[i].type === 'image' || jobs[i].type === 'variation') {
|
||||||
|
jobs[i]['can_opt'] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (jobs.length < pageSize.value) {
|
||||||
|
finished.value = true
|
||||||
|
}
|
||||||
|
if (page === 1) {
|
||||||
|
finishedJobs.value = jobs
|
||||||
|
} else {
|
||||||
|
finishedJobs.value = finishedJobs.value.concat(jobs)
|
||||||
|
}
|
||||||
|
nextTick(() => loading.value = false)
|
||||||
|
}).catch(e => {
|
||||||
|
loading.value = false
|
||||||
|
error.value = true
|
||||||
|
showFailToast("获取任务失败:" + e.message)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const onLoad = () => {
|
||||||
|
page.value += 1
|
||||||
|
fetchFinishJobs(page.value)
|
||||||
|
};
|
||||||
|
|
||||||
|
// 切换图片比例
|
||||||
|
const changeRate = (item) => {
|
||||||
|
params.value.rate = item.value
|
||||||
|
}
|
||||||
|
// 切换模型
|
||||||
|
const changeModel = (item) => {
|
||||||
|
params.value.model = item.value
|
||||||
|
}
|
||||||
|
|
||||||
|
const imgKey = ref("")
|
||||||
|
const beforeUpload = (key) => {
|
||||||
|
imgKey.value = key
|
||||||
|
}
|
||||||
|
|
||||||
|
// 图片上传
|
||||||
|
const uploadImg = (file) => {
|
||||||
|
file.status = "uploading"
|
||||||
|
// 压缩图片并上传
|
||||||
|
new Compressor(file.file, {
|
||||||
|
quality: 0.6,
|
||||||
|
success(result) {
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('file', result, result.name);
|
||||||
|
// 执行上传操作
|
||||||
|
httpPost('/api/upload', formData).then(res => {
|
||||||
|
file.url = res.data.url
|
||||||
|
if (imgKey.value !== "") { // 单张图片上传
|
||||||
|
params.value[imgKey.value] = res.data.url
|
||||||
|
imgKey.value = ''
|
||||||
|
}
|
||||||
|
file.status = "done"
|
||||||
|
}).catch(e => {
|
||||||
|
file.status = 'failed'
|
||||||
|
file.message = '上传失败'
|
||||||
|
showFailToast("图片上传失败:" + e.message)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
error(err) {
|
||||||
|
console.log(err.message);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const send = (url, index, item) => {
|
||||||
|
httpPost(url, {
|
||||||
|
index: index,
|
||||||
|
channel_id: item.channel_id,
|
||||||
|
message_id: item.message_id,
|
||||||
|
message_hash: item.hash,
|
||||||
|
session_id: getSessionId(),
|
||||||
|
prompt: item.prompt,
|
||||||
|
}).then(() => {
|
||||||
|
showSuccessToast("任务推送成功,请耐心等待任务执行...")
|
||||||
|
power.value -= mjActionPower.value
|
||||||
|
}).catch(e => {
|
||||||
|
showFailToast("任务推送失败:" + e.message)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 图片放大任务
|
||||||
|
const upscale = (index, item) => {
|
||||||
|
send('/api/mj/upscale', index, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 图片变换任务
|
||||||
|
const variation = (index, item) => {
|
||||||
|
send('/api/mj/variation', index, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
const generate = () => {
|
||||||
|
if (params.value.prompt === '' && params.value.task_type === "image") {
|
||||||
|
return showFailToast("请输入绘画提示词!")
|
||||||
|
}
|
||||||
|
if (params.value.model.indexOf("niji") !== -1 && params.value.raw) {
|
||||||
|
return showFailToast("动漫模型不允许启用原始模式")
|
||||||
|
}
|
||||||
|
params.value.session_id = getSessionId()
|
||||||
|
params.value.img_arr = imgList.value.map(img => img.url)
|
||||||
|
httpPost("/api/mj/image", params.value).then(() => {
|
||||||
|
showToast("绘画任务推送成功,请耐心等待任务执行")
|
||||||
|
power.value -= mjPower.value
|
||||||
|
}).catch(e => {
|
||||||
|
showFailToast("任务推送失败:" + e.message)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const removeImage = (item) => {
|
||||||
|
showConfirmDialog({
|
||||||
|
title: '标题',
|
||||||
|
message:
|
||||||
|
'此操作将会删除任务和图片,继续操作码?',
|
||||||
|
}).then(() => {
|
||||||
|
httpPost("/api/mj/remove", {id: item.id, img_url: item.img_url, user_id: userId.value}).then(() => {
|
||||||
|
showSuccessToast("任务删除成功")
|
||||||
|
}).catch(e => {
|
||||||
|
showFailToast("任务删除失败:" + e.message)
|
||||||
|
})
|
||||||
|
}).catch(() => {
|
||||||
|
showToast("您取消了操作")
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 发布图片到作品墙
|
||||||
|
const publishImage = (item, action) => {
|
||||||
|
let text = "图片发布"
|
||||||
|
if (action === false) {
|
||||||
|
text = "取消发布"
|
||||||
|
}
|
||||||
|
httpPost("/api/mj/publish", {id: item.id, action: action}).then(() => {
|
||||||
|
showSuccessToast(text + "成功")
|
||||||
|
item.publish = action
|
||||||
|
}).catch(e => {
|
||||||
|
showFailToast(text + "失败:" + e.message)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const showPrompt = (item) => {
|
||||||
|
showDialog({
|
||||||
|
title: "绘画提示词",
|
||||||
|
message: item.prompt,
|
||||||
|
}).then(() => {
|
||||||
|
// on close
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const imageView = (item) => {
|
||||||
|
showImagePreview([item['img_url']]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 切换菜单
|
||||||
|
const tabChange = (tab) => {
|
||||||
|
if (tab === "txt2img" || tab === "img2img") {
|
||||||
|
params.value.task_type = "image"
|
||||||
|
} else {
|
||||||
|
params.value.task_type = tab
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus">
|
||||||
|
@import "@/assets/css/mobile/image-mj.styl"
|
||||||
|
</style>
|
523
web/src/views/mobile/ImageSd.vue
Normal file
523
web/src/views/mobile/ImageSd.vue
Normal file
@ -0,0 +1,523 @@
|
|||||||
|
<template>
|
||||||
|
<div class="mobile-sd">
|
||||||
|
<van-form @submit="generate">
|
||||||
|
<van-cell-group inset>
|
||||||
|
<div>
|
||||||
|
<van-field
|
||||||
|
v-model="params.sampler"
|
||||||
|
is-link
|
||||||
|
readonly
|
||||||
|
label="采样方法"
|
||||||
|
placeholder="选择采样方法"
|
||||||
|
@click="showSamplerPicker = true"
|
||||||
|
/>
|
||||||
|
<van-popup v-model:show="showSamplerPicker" position="bottom" teleport="#app">
|
||||||
|
<van-picker
|
||||||
|
:columns="samplers"
|
||||||
|
@cancel="showSamplerPicker = false"
|
||||||
|
@confirm="samplerConfirm"
|
||||||
|
/>
|
||||||
|
</van-popup>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<van-field label="图片尺寸">
|
||||||
|
<template #input>
|
||||||
|
<van-row gutter="20">
|
||||||
|
<van-col span="12">
|
||||||
|
<el-input v-model="params.width" size="small" placeholder="宽"/>
|
||||||
|
</van-col>
|
||||||
|
<van-col span="12">
|
||||||
|
<el-input v-model="params.height" size="small" placeholder="高"/>
|
||||||
|
</van-col>
|
||||||
|
</van-row>
|
||||||
|
</template>
|
||||||
|
</van-field>
|
||||||
|
|
||||||
|
<van-field v-model.number="params.steps" label="迭代步数"
|
||||||
|
placeholder="">
|
||||||
|
<template #right-icon>
|
||||||
|
<van-icon name="info-o"
|
||||||
|
@click="showInfo('值越大则代表细节越多,同时也意味着出图速度越慢,一般推荐20-30')"/>
|
||||||
|
</template>
|
||||||
|
</van-field>
|
||||||
|
<van-field v-model.number="params.cfg_scale" label="引导系数" placeholder="">
|
||||||
|
<template #right-icon>
|
||||||
|
<van-icon name="info-o"
|
||||||
|
@click="showInfo('提示词引导系数,图像在多大程度上服从提示词,较低值会产生更有创意的结果')"/>
|
||||||
|
</template>
|
||||||
|
</van-field>
|
||||||
|
<van-field v-model.number="params.seed" label="随机因子" placeholder="">
|
||||||
|
<template #right-icon>
|
||||||
|
<van-icon name="info-o"
|
||||||
|
@click="showInfo('随机数种子,相同的种子会得到相同的结果,设置为 -1 则每次随机生成种子')"/>
|
||||||
|
</template>
|
||||||
|
</van-field>
|
||||||
|
|
||||||
|
<van-field label="高清修复">
|
||||||
|
<template #input>
|
||||||
|
<van-switch v-model="params.hd_fix"/>
|
||||||
|
</template>
|
||||||
|
</van-field>
|
||||||
|
|
||||||
|
<div v-if="params.hd_fix">
|
||||||
|
<div>
|
||||||
|
<van-field
|
||||||
|
v-model="params.hd_scale_alg"
|
||||||
|
is-link
|
||||||
|
readonly
|
||||||
|
label="放大算法"
|
||||||
|
placeholder="选择放大算法"
|
||||||
|
@click="showUpscalePicker = true"
|
||||||
|
/>
|
||||||
|
<van-popup v-model:show="showUpscalePicker" position="bottom" teleport="#app">
|
||||||
|
<van-picker
|
||||||
|
:columns="upscaleAlgArr"
|
||||||
|
@cancel="showUpscalePicker = false"
|
||||||
|
@confirm="upscaleConfirm"
|
||||||
|
/>
|
||||||
|
</van-popup>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<van-field v-model.number="params.hd_scale" label="放大倍数"/>
|
||||||
|
<van-field v-model.number="params.hd_steps" label="迭代步数"/>
|
||||||
|
|
||||||
|
<van-field label="重绘幅度">
|
||||||
|
<template #input>
|
||||||
|
<van-slider v-model.number="params.hd_redraw_rate" :max="1" :step="0.1"
|
||||||
|
@update:model-value="showToast('当前值:' + params.hd_redraw_rate)"/>
|
||||||
|
</template>
|
||||||
|
<template #right-icon>
|
||||||
|
<van-icon name="info-o"
|
||||||
|
@click="showInfo('决定算法对图像内容的影响程度,较大的值将得到越有创意的图像')"/>
|
||||||
|
</template>
|
||||||
|
</van-field>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<van-field
|
||||||
|
v-model="params.prompt"
|
||||||
|
rows="3"
|
||||||
|
autosize
|
||||||
|
type="textarea"
|
||||||
|
placeholder="请在此输入绘画提示词,系统会自动翻译中文提示词,高手请直接输入英文提示词"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<van-collapse v-model="activeColspan">
|
||||||
|
<van-collapse-item title="反向提示词" name="neg_prompt">
|
||||||
|
<van-field
|
||||||
|
v-model="params.neg_prompt"
|
||||||
|
rows="3"
|
||||||
|
autosize
|
||||||
|
type="textarea"
|
||||||
|
placeholder="不想出现在图片上的元素(例如:树,建筑)"
|
||||||
|
/>
|
||||||
|
</van-collapse-item>
|
||||||
|
</van-collapse>
|
||||||
|
|
||||||
|
<div class="text-line pt-6">
|
||||||
|
<el-tag>绘图消耗{{ sdPower }}算力,当前算力:{{ power }}</el-tag>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="text-line">
|
||||||
|
<van-button round block type="primary" native-type="submit">
|
||||||
|
立即生成
|
||||||
|
</van-button>
|
||||||
|
</div>
|
||||||
|
</van-cell-group>
|
||||||
|
</van-form>
|
||||||
|
|
||||||
|
<h3>任务列表</h3>
|
||||||
|
<div class="running-job-list">
|
||||||
|
<van-empty v-if="runningJobs.length ===0"
|
||||||
|
image="https://fastly.jsdelivr.net/npm/@vant/assets/custom-empty-image.png"
|
||||||
|
image-size="80"
|
||||||
|
description="暂无记录"
|
||||||
|
/>
|
||||||
|
<van-grid :gutter="10" :column-num="3" v-else>
|
||||||
|
<van-grid-item v-for="item in runningJobs">
|
||||||
|
<div v-if="item.progress > 0">
|
||||||
|
<van-image :src="item['img_url']">
|
||||||
|
<template v-slot:error>加载失败</template>
|
||||||
|
</van-image>
|
||||||
|
<div class="progress">
|
||||||
|
<van-circle
|
||||||
|
v-model:current-rate="item.progress"
|
||||||
|
:rate="item.progress"
|
||||||
|
:speed="100"
|
||||||
|
:text="item.progress+'%'"
|
||||||
|
:stroke-width="60"
|
||||||
|
size="90px"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-else class="task-in-queue">
|
||||||
|
<span class="icon"><i class="iconfont icon-quick-start"></i></span>
|
||||||
|
<span class="text">排队中</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</van-grid-item>
|
||||||
|
</van-grid>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3>创作记录</h3>
|
||||||
|
<div class="finish-job-list">
|
||||||
|
<van-empty v-if="finishedJobs.length ===0"
|
||||||
|
image="https://fastly.jsdelivr.net/npm/@vant/assets/custom-empty-image.png"
|
||||||
|
image-size="80"
|
||||||
|
description="暂无记录"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<van-list v-else
|
||||||
|
v-model:error="error"
|
||||||
|
v-model:loading="loading"
|
||||||
|
:finished="finished"
|
||||||
|
error-text="请求失败,点击重新加载"
|
||||||
|
finished-text="没有更多了"
|
||||||
|
@load="onLoad"
|
||||||
|
>
|
||||||
|
<van-grid :gutter="10" :column-num="2">
|
||||||
|
<van-grid-item v-for="item in finishedJobs">
|
||||||
|
<div class="job-item">
|
||||||
|
<van-image
|
||||||
|
:src="item['img_url']"
|
||||||
|
:class="item['can_opt'] ? '' : 'upscale'"
|
||||||
|
lazy-load
|
||||||
|
@click="imageView(item)"
|
||||||
|
fit="cover">
|
||||||
|
<template v-slot:loading>
|
||||||
|
<van-loading type="spinner" size="20"/>
|
||||||
|
</template>
|
||||||
|
</van-image>
|
||||||
|
|
||||||
|
<div class="remove">
|
||||||
|
<el-button type="danger" :icon="Delete" @click="removeImage($event, item)" circle/>
|
||||||
|
<el-button type="warning" v-if="item.publish" @click="publishImage($event,item, false)"
|
||||||
|
circle>
|
||||||
|
<i class="iconfont icon-cancel-share"></i>
|
||||||
|
</el-button>
|
||||||
|
<el-button type="success" v-else @click="publishImage($event, item, true)" circle>
|
||||||
|
<i class="iconfont icon-share-bold"></i>
|
||||||
|
</el-button>
|
||||||
|
<el-button type="primary" @click="showTask(item)" circle>
|
||||||
|
<i class="iconfont icon-prompt"></i>
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</van-grid-item>
|
||||||
|
</van-grid>
|
||||||
|
</van-list>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import {onMounted, onUnmounted, ref} from "vue"
|
||||||
|
import {Delete} from "@element-plus/icons-vue";
|
||||||
|
import {httpGet, httpPost} from "@/utils/http";
|
||||||
|
import Clipboard from "clipboard";
|
||||||
|
import {checkSession} from "@/action/session";
|
||||||
|
import {useRouter} from "vue-router";
|
||||||
|
import {getSessionId} from "@/store/session";
|
||||||
|
import {
|
||||||
|
showConfirmDialog, showDialog,
|
||||||
|
showFailToast,
|
||||||
|
showImagePreview,
|
||||||
|
showNotify,
|
||||||
|
showSuccessToast,
|
||||||
|
showToast
|
||||||
|
} from "vant";
|
||||||
|
|
||||||
|
const listBoxHeight = ref(window.innerHeight - 40)
|
||||||
|
const mjBoxHeight = ref(window.innerHeight - 150)
|
||||||
|
const showTaskDialog = ref(false)
|
||||||
|
const item = ref({})
|
||||||
|
const showLoginDialog = ref(false)
|
||||||
|
const isLogin = ref(false)
|
||||||
|
const activeColspan = ref([""])
|
||||||
|
|
||||||
|
window.onresize = () => {
|
||||||
|
listBoxHeight.value = window.innerHeight - 40
|
||||||
|
mjBoxHeight.value = window.innerHeight - 150
|
||||||
|
}
|
||||||
|
const samplers = ref([
|
||||||
|
{text: "Euler a", value: "Euler a"},
|
||||||
|
{text: "DPM++ 2S a Karras", value: "DPM++ 2S a Karras"},
|
||||||
|
{text: "DPM++ 2M Karras", value: "DPM++ 2M Karras"},
|
||||||
|
{text: "DPM++ 2M SDE Karras", value: "DPM++ 2M SDE Karras"},
|
||||||
|
{text: "DPM++ 2M Karras", value: "DPM++ 2M Karras"},
|
||||||
|
{text: "DPM++ 3M SDE Karras", value: "DPM++ 3M SDE Karras"},
|
||||||
|
])
|
||||||
|
const showSamplerPicker = ref(false)
|
||||||
|
|
||||||
|
const upscaleAlgArr = ref([
|
||||||
|
{text: "Latent", value: "Latent"},
|
||||||
|
{text: "ESRGAN_4x", value: "ESRGAN_4x"},
|
||||||
|
{text: "ESRGAN 4x+", value: "ESRGAN 4x+"},
|
||||||
|
{text: "SwinIR_4x", value: "SwinIR_4x"},
|
||||||
|
{text: "LDSR", value: "LDSR"},
|
||||||
|
])
|
||||||
|
const showUpscalePicker = ref(false)
|
||||||
|
|
||||||
|
const params = ref({
|
||||||
|
width: 1024,
|
||||||
|
height: 1024,
|
||||||
|
sampler: samplers.value[0].value,
|
||||||
|
seed: -1,
|
||||||
|
steps: 20,
|
||||||
|
cfg_scale: 7,
|
||||||
|
hd_fix: false,
|
||||||
|
hd_redraw_rate: 0.7,
|
||||||
|
hd_scale: 2,
|
||||||
|
hd_scale_alg: upscaleAlgArr.value[0].value,
|
||||||
|
hd_steps: 0,
|
||||||
|
prompt: "",
|
||||||
|
neg_prompt: "nsfw, paintings,low quality,easynegative,ng_deepnegative ,lowres,bad anatomy,bad hands,bad feet",
|
||||||
|
})
|
||||||
|
|
||||||
|
const runningJobs = ref([])
|
||||||
|
const finishedJobs = ref([])
|
||||||
|
const router = useRouter()
|
||||||
|
// 检查是否有画同款的参数
|
||||||
|
const _params = router.currentRoute.value.params["copyParams"]
|
||||||
|
if (_params) {
|
||||||
|
params.value = JSON.parse(_params)
|
||||||
|
}
|
||||||
|
const power = ref(0)
|
||||||
|
const sdPower = ref(0) // 画一张 SD 图片消耗算力
|
||||||
|
|
||||||
|
const socket = ref(null)
|
||||||
|
const userId = ref(0)
|
||||||
|
const heartbeatHandle = ref(null)
|
||||||
|
const connect = () => {
|
||||||
|
let host = process.env.VUE_APP_WS_HOST
|
||||||
|
if (host === '') {
|
||||||
|
if (location.protocol === 'https:') {
|
||||||
|
host = 'wss://' + location.host;
|
||||||
|
} else {
|
||||||
|
host = 'ws://' + location.host;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 心跳函数
|
||||||
|
const sendHeartbeat = () => {
|
||||||
|
clearTimeout(heartbeatHandle.value)
|
||||||
|
new Promise((resolve, reject) => {
|
||||||
|
if (socket.value !== null) {
|
||||||
|
socket.value.send(JSON.stringify({type: "heartbeat", content: "ping"}))
|
||||||
|
}
|
||||||
|
resolve("success")
|
||||||
|
}).then(() => {
|
||||||
|
heartbeatHandle.value = setTimeout(() => sendHeartbeat(), 5000)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const _socket = new WebSocket(host + `/api/sd/client?user_id=${userId.value}`);
|
||||||
|
_socket.addEventListener('open', () => {
|
||||||
|
socket.value = _socket;
|
||||||
|
|
||||||
|
// 发送心跳消息
|
||||||
|
sendHeartbeat()
|
||||||
|
});
|
||||||
|
|
||||||
|
_socket.addEventListener('message', event => {
|
||||||
|
if (event.data instanceof Blob) {
|
||||||
|
fetchRunningJobs()
|
||||||
|
finished.value = false
|
||||||
|
page.value = 1
|
||||||
|
fetchFinishJobs(page.value)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
_socket.addEventListener('close', () => {
|
||||||
|
if (socket.value !== null) {
|
||||||
|
connect()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const clipboard = ref(null)
|
||||||
|
onMounted(() => {
|
||||||
|
initData()
|
||||||
|
clipboard.value = new Clipboard('.copy-prompt-sd');
|
||||||
|
clipboard.value.on('success', () => {
|
||||||
|
showNotify({type: "success", message: "复制成功!"});
|
||||||
|
})
|
||||||
|
|
||||||
|
clipboard.value.on('error', () => {
|
||||||
|
showNotify({type: "danger", message: '复制失败!'});
|
||||||
|
})
|
||||||
|
|
||||||
|
httpGet("/api/config/get?key=system").then(res => {
|
||||||
|
sdPower.value = res.data["sd_power"]
|
||||||
|
}).catch(e => {
|
||||||
|
showNotify({type: "danger", message: "获取系统配置失败:" + e.message})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
clipboard.value.destroy()
|
||||||
|
socket.value = null
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
const initData = () => {
|
||||||
|
checkSession().then(user => {
|
||||||
|
power.value = user['power']
|
||||||
|
userId.value = user.id
|
||||||
|
isLogin.value = true
|
||||||
|
fetchRunningJobs()
|
||||||
|
fetchFinishJobs(1)
|
||||||
|
connect()
|
||||||
|
}).catch(() => {
|
||||||
|
loading.value = false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const fetchRunningJobs = () => {
|
||||||
|
// 获取运行中的任务
|
||||||
|
httpGet(`/api/sd/jobs?status=0`).then(res => {
|
||||||
|
const jobs = res.data
|
||||||
|
const _jobs = []
|
||||||
|
for (let i = 0; i < jobs.length; i++) {
|
||||||
|
if (jobs[i].progress === -1) {
|
||||||
|
showNotify({
|
||||||
|
message: `任务ID:${jobs[i]['task_id']} 原因:${jobs[i]['err_msg']}`,
|
||||||
|
type: 'danger',
|
||||||
|
})
|
||||||
|
power.value += sdPower.value
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
_jobs.push(jobs[i])
|
||||||
|
}
|
||||||
|
runningJobs.value = _jobs
|
||||||
|
}).catch(e => {
|
||||||
|
showNotify({type: "danger", message: "获取任务失败:" + e.message})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const loading = ref(false)
|
||||||
|
const finished = ref(false)
|
||||||
|
const error = ref(false)
|
||||||
|
const page = ref(0)
|
||||||
|
const pageSize = ref(10)
|
||||||
|
// 获取已完成的任务
|
||||||
|
const fetchFinishJobs = (page) => {
|
||||||
|
loading.value = true
|
||||||
|
httpGet(`/api/sd/jobs?status=1&page=${page}&page_size=${pageSize.value}`).then(res => {
|
||||||
|
if (res.data.length < pageSize.value) {
|
||||||
|
finished.value = true
|
||||||
|
}
|
||||||
|
if (page === 1) {
|
||||||
|
finishedJobs.value = res.data
|
||||||
|
} else {
|
||||||
|
finishedJobs.value = finishedJobs.value.concat(res.data)
|
||||||
|
}
|
||||||
|
loading.value = false
|
||||||
|
}).catch(e => {
|
||||||
|
loading.value = false
|
||||||
|
showNotify({type: "danger", message: "获取任务失败:" + e.message})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const onLoad = () => {
|
||||||
|
page.value += 1
|
||||||
|
fetchFinishJobs(page.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建绘图任务
|
||||||
|
const promptRef = ref(null)
|
||||||
|
const generate = () => {
|
||||||
|
if (params.value.prompt === '') {
|
||||||
|
promptRef.value.focus()
|
||||||
|
return showToast("请输入绘画提示词!")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isLogin.value) {
|
||||||
|
showLoginDialog.value = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params.value.seed === '') {
|
||||||
|
params.value.seed = -1
|
||||||
|
}
|
||||||
|
params.value.session_id = getSessionId()
|
||||||
|
httpPost("/api/sd/image", params.value).then(() => {
|
||||||
|
showSuccessToast("绘画任务推送成功,请耐心等待任务执行...")
|
||||||
|
power.value -= sdPower.value
|
||||||
|
}).catch(e => {
|
||||||
|
showFailToast("任务推送失败:" + e.message)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const showTask = (row) => {
|
||||||
|
item.value = row
|
||||||
|
showTaskDialog.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
const copyParams = (row) => {
|
||||||
|
params.value = row.params
|
||||||
|
showTaskDialog.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
const removeImage = (event, item) => {
|
||||||
|
event.stopPropagation()
|
||||||
|
showConfirmDialog({
|
||||||
|
title: '标题',
|
||||||
|
message:
|
||||||
|
'此操作将会删除任务和图片,继续操作码?',
|
||||||
|
}).then(() => {
|
||||||
|
httpPost("/api/sd/remove", {id: item.id, img_url: item.img_url, user_id: userId.value}).then(() => {
|
||||||
|
showSuccessToast("任务删除成功")
|
||||||
|
}).catch(e => {
|
||||||
|
showFailToast("任务删除失败:" + e.message)
|
||||||
|
})
|
||||||
|
}).catch(() => {
|
||||||
|
showToast("您取消了操作")
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发布图片到作品墙
|
||||||
|
const publishImage = (event, item, action) => {
|
||||||
|
event.stopPropagation()
|
||||||
|
let text = "图片发布"
|
||||||
|
if (action === false) {
|
||||||
|
text = "取消发布"
|
||||||
|
}
|
||||||
|
httpPost("/api/sd/publish", {id: item.id, action: action}).then(() => {
|
||||||
|
showSuccessToast(text + "成功")
|
||||||
|
item.publish = action
|
||||||
|
}).catch(e => {
|
||||||
|
showFailToast(text + "失败:" + e.message)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const imageView = (item) => {
|
||||||
|
showImagePreview([item['img_url']]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const samplerConfirm = (item) => {
|
||||||
|
params.value.sampler = item.selectedOptions[0].text;
|
||||||
|
showSamplerPicker.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
const upscaleConfirm = (item) => {
|
||||||
|
params.value.hd_scale_alg = item.selectedOptions[0].text;
|
||||||
|
showUpscalePicker.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
const showInfo = (message) => {
|
||||||
|
showDialog({
|
||||||
|
title: "参数说明",
|
||||||
|
message: message,
|
||||||
|
}).then(() => {
|
||||||
|
// on close
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus">
|
||||||
|
@import "@/assets/css/mobile/image-sd.styl"
|
||||||
|
</style>
|
133
web/src/views/mobile/ImgWall.vue
Normal file
133
web/src/views/mobile/ImgWall.vue
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
<template>
|
||||||
|
<div class="img-wall container">
|
||||||
|
<van-nav-bar :title="title"/>
|
||||||
|
|
||||||
|
<div class="content">
|
||||||
|
<van-tabs v-model:active="activeName">
|
||||||
|
<van-tab title="MidJourney" name="mj">
|
||||||
|
<van-list
|
||||||
|
v-model:error="data['mj'].error"
|
||||||
|
v-model:loading="data['mj'].loading"
|
||||||
|
:finished="data['mj'].finished"
|
||||||
|
error-text="请求失败,点击重新加载"
|
||||||
|
finished-text="没有更多了"
|
||||||
|
@load="onLoad"
|
||||||
|
style="height: 100%;width: 100%;"
|
||||||
|
>
|
||||||
|
<van-cell v-for="item in data['mj'].data" :key="item.id">
|
||||||
|
<van-image :src="item['img_thumb']" @click="showPrompt(item)" fit="cover"/>
|
||||||
|
</van-cell>
|
||||||
|
</van-list>
|
||||||
|
</van-tab>
|
||||||
|
<van-tab title="StableDiffusion" name="sd">
|
||||||
|
<van-list
|
||||||
|
v-model:error="data['sd'].error"
|
||||||
|
v-model:loading="data['sd'].loading"
|
||||||
|
:finished="data['sd'].finished"
|
||||||
|
error-text="请求失败,点击重新加载"
|
||||||
|
finished-text="没有更多了"
|
||||||
|
@load="onLoad"
|
||||||
|
>
|
||||||
|
<van-cell v-for="item in data['sd'].data" :key="item.id">
|
||||||
|
<van-image :src="item['img_thumb']" @click="showPrompt(item)" fit="cover"/>
|
||||||
|
</van-cell>
|
||||||
|
</van-list>
|
||||||
|
</van-tab>
|
||||||
|
<van-tab title="DALLE3" name="dalle3">
|
||||||
|
<van-empty description="功能正在开发中"/>
|
||||||
|
</van-tab>
|
||||||
|
</van-tabs>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import {onMounted, ref} from "vue";
|
||||||
|
import {httpGet, httpPost} from "@/utils/http";
|
||||||
|
import {showDialog, showFailToast, showSuccessToast} from "vant";
|
||||||
|
import {ElMessage} from "element-plus";
|
||||||
|
|
||||||
|
const title = ref('图片创作广场')
|
||||||
|
const activeName = ref("mj")
|
||||||
|
const data = ref({
|
||||||
|
"mj": {
|
||||||
|
loading: false,
|
||||||
|
finished: false,
|
||||||
|
error: false,
|
||||||
|
page: 1,
|
||||||
|
pageSize: 12,
|
||||||
|
url: "/api/mj/jobs",
|
||||||
|
data: []
|
||||||
|
},
|
||||||
|
"sd": {
|
||||||
|
loading: false,
|
||||||
|
finished: false,
|
||||||
|
error: false,
|
||||||
|
page: 1,
|
||||||
|
pageSize: 12,
|
||||||
|
url: "/api/sd/jobs",
|
||||||
|
data: []
|
||||||
|
},
|
||||||
|
"dalle3": {
|
||||||
|
loading: false,
|
||||||
|
finished: false,
|
||||||
|
error: false,
|
||||||
|
page: 1,
|
||||||
|
pageSize: 12,
|
||||||
|
url: "/api/dalle3/jobs",
|
||||||
|
data: []
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const onLoad = () => {
|
||||||
|
const d = data.value[activeName.value]
|
||||||
|
httpGet(`${d.url}?status=1&page=${d.page}&page_size=${d.pageSize}&publish=true`).then(res => {
|
||||||
|
d.loading = false
|
||||||
|
if (res.data.length === 0) {
|
||||||
|
d.finished = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成缩略图
|
||||||
|
const imageList = res.data
|
||||||
|
for (let i = 0; i < imageList.length; i++) {
|
||||||
|
imageList[i]["img_thumb"] = imageList[i]["img_url"] + "?imageView2/4/w/300/h/0/q/75"
|
||||||
|
}
|
||||||
|
if (imageList.length < d.pageSize) {
|
||||||
|
d.finished = true
|
||||||
|
}
|
||||||
|
if (d.data.length === 0) {
|
||||||
|
d.data = imageList
|
||||||
|
} else {
|
||||||
|
d.data = d.data.concat(imageList)
|
||||||
|
}
|
||||||
|
d.page += 1
|
||||||
|
}).catch(() => {
|
||||||
|
d.error = true
|
||||||
|
showFailToast("加载图片数据失败")
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
const showPrompt = (item) => {
|
||||||
|
showDialog({
|
||||||
|
title: "绘画提示词",
|
||||||
|
message: item.prompt,
|
||||||
|
}).then(() => {
|
||||||
|
// on close
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus">
|
||||||
|
.img-wall {
|
||||||
|
.content {
|
||||||
|
padding-top 60px
|
||||||
|
|
||||||
|
.van-cell__value {
|
||||||
|
.van-image {
|
||||||
|
width 100%
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -350,7 +350,8 @@ onMounted(() => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
httpGet("/api/config/get?key=system").then(res => {
|
httpGet("/api/config/get?key=system").then(res => {
|
||||||
sdPower.value = res.data["sd_power"]
|
sdPower.value = res.data.sd_power
|
||||||
|
params.value.neg_prompt = res.data.sd_neg_prompt
|
||||||
}).catch(e => {
|
}).catch(e => {
|
||||||
showNotify({type: "danger", message: "获取系统配置失败:" + e.message})
|
showNotify({type: "danger", message: "获取系统配置失败:" + e.message})
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user