mirror of
https://gitee.com/blackfox/geekai.git
synced 2024-11-29 18:57:34 +08:00
restore use power when removed not finish jobs
This commit is contained in:
parent
96f1126d02
commit
1d9d487f0e
@ -1,4 +1,8 @@
|
||||
# 更新日志
|
||||
|
||||
## v4.1.2
|
||||
* Bug修复:修复思维导图页面获取模型失败的问题
|
||||
|
||||
## v4.1.1
|
||||
* Bug修复:修复 GPT 模型 function call 调用后没有输出的问题
|
||||
* 功能新增:允许获取 License 授权用户可以自定义版权信息
|
||||
|
@ -225,7 +225,7 @@ func needLogin(c *gin.Context) bool {
|
||||
c.Request.URL.Path == "/api/payment/doPay" ||
|
||||
c.Request.URL.Path == "/api/payment/payWays" ||
|
||||
c.Request.URL.Path == "/api/suno/client" ||
|
||||
c.Request.URL.Path == "/api/suno/Detail" ||
|
||||
c.Request.URL.Path == "/api/suno/detail" ||
|
||||
c.Request.URL.Path == "/api/suno/play" ||
|
||||
strings.HasPrefix(c.Request.URL.Path, "/api/test") ||
|
||||
strings.HasPrefix(c.Request.URL.Path, "/api/user/clogin") ||
|
||||
|
@ -61,7 +61,6 @@ type ChatSession struct {
|
||||
|
||||
type ChatModel struct {
|
||||
Id uint `json:"id"`
|
||||
Platform string `json:"platform"`
|
||||
Name string `json:"name"`
|
||||
Value string `json:"value"`
|
||||
Power int `json:"power"`
|
||||
|
@ -468,7 +468,7 @@ func (h *ChatHandler) doRequest(ctx context.Context, req types.ApiRequest, sessi
|
||||
} else {
|
||||
client = http.DefaultClient
|
||||
}
|
||||
logger.Debugf("Sending %s request, Channel:%s, API KEY:%s, PROXY: %s, Model: %s", session.Model.Platform, apiKey.ApiURL, apiURL, apiKey.ProxyURL, req.Model)
|
||||
logger.Debugf("Sending %s request, API KEY:%s, PROXY: %s, Model: %s", apiKey.ApiURL, apiURL, apiKey.ProxyURL, req.Model)
|
||||
request.Header.Set("Authorization", fmt.Sprintf("Bearer %s", apiKey.Value))
|
||||
// 更新API KEY 最后使用时间
|
||||
h.DB.Model(&model.ApiKey{}).Where("id", apiKey.Id).UpdateColumn("last_used_at", time.Now().Unix())
|
||||
|
@ -8,6 +8,7 @@ package handler
|
||||
// * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"geekai/core"
|
||||
"geekai/core/types"
|
||||
"geekai/service/dalle"
|
||||
@ -16,9 +17,9 @@ import (
|
||||
"geekai/store/vo"
|
||||
"geekai/utils"
|
||||
"geekai/utils/resp"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-redis/redis/v8"
|
||||
@ -178,7 +179,7 @@ func (h *DallJobHandler) getData(finish bool, userId uint, page int, pageSize in
|
||||
|
||||
session := h.DB.Session(&gorm.Session{})
|
||||
if finish {
|
||||
session = session.Where("progress = ?", 100).Order("id DESC")
|
||||
session = session.Where("progress >= ?", 100).Order("id DESC")
|
||||
} else {
|
||||
session = session.Where("progress < ?", 100).Order("id ASC")
|
||||
}
|
||||
@ -215,20 +216,51 @@ func (h *DallJobHandler) getData(finish bool, userId uint, page int, pageSize in
|
||||
// Remove remove task image
|
||||
func (h *DallJobHandler) Remove(c *gin.Context) {
|
||||
id := h.GetInt(c, "id", 0)
|
||||
userId := h.GetInt(c, "user_id", 0)
|
||||
userId := h.GetLoginUserId(c)
|
||||
var job model.DallJob
|
||||
if res := h.DB.Where("id = ? AND user_id = ?", id, userId).First(&job); res.Error != nil {
|
||||
resp.ERROR(c, "记录不存在")
|
||||
return
|
||||
}
|
||||
|
||||
// remove job recode
|
||||
res := h.DB.Delete(&model.DallJob{Id: job.Id})
|
||||
if res.Error != nil {
|
||||
resp.ERROR(c, res.Error.Error())
|
||||
// 删除任务
|
||||
tx := h.DB.Begin()
|
||||
if err := tx.Delete(&job).Error; err != nil {
|
||||
tx.Rollback()
|
||||
resp.ERROR(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 如果任务未完成,或者任务失败,则恢复用户算力
|
||||
if job.Progress != 100 {
|
||||
err := tx.Model(&model.User{}).Where("id = ?", job.UserId).UpdateColumn("power", gorm.Expr("power + ?", job.Power)).Error
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
resp.ERROR(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
var user model.User
|
||||
h.DB.Where("id = ?", job.UserId).First(&user)
|
||||
err = tx.Create(&model.PowerLog{
|
||||
UserId: user.Id,
|
||||
Username: user.Username,
|
||||
Type: types.PowerConsume,
|
||||
Amount: job.Power,
|
||||
Balance: user.Power,
|
||||
Mark: types.PowerAdd,
|
||||
Model: "dall-e-3",
|
||||
Remark: fmt.Sprintf("任务失败,退回算力。任务ID:%d,Err: %s", job.Id, job.ErrMsg),
|
||||
CreatedAt: time.Now(),
|
||||
}).Error
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
resp.ERROR(c, err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
tx.Commit()
|
||||
|
||||
// remove image
|
||||
err := h.uploader.GetUploadHandler().Delete(job.ImgURL)
|
||||
if err != nil {
|
||||
@ -241,10 +273,10 @@ func (h *DallJobHandler) Remove(c *gin.Context) {
|
||||
// Publish 发布/取消发布图片到画廊显示
|
||||
func (h *DallJobHandler) Publish(c *gin.Context) {
|
||||
id := h.GetInt(c, "id", 0)
|
||||
userId := h.GetInt(c, "user_id", 0)
|
||||
userId := h.GetLoginUserId(c)
|
||||
action := h.GetBool(c, "action") // 发布动作,true => 发布,false => 取消分享
|
||||
|
||||
res := h.DB.Model(&model.DallJob{Id: uint(id), UserId: uint(userId)}).UpdateColumn("publish", action)
|
||||
res := h.DB.Model(&model.DallJob{Id: uint(id), UserId: userId}).UpdateColumn("publish", action)
|
||||
if res.Error != nil {
|
||||
logger.Error("error with update database:", res.Error)
|
||||
resp.ERROR(c, "更新数据库失败")
|
||||
|
@ -101,17 +101,13 @@ func (h *MarkMapHandler) sendMessage(client *types.WsClient, prompt string, mode
|
||||
return fmt.Errorf("error with query chat model: %v", res.Error)
|
||||
}
|
||||
|
||||
if user.Status == false {
|
||||
return errors.New("当前用户被禁用")
|
||||
}
|
||||
|
||||
if user.Power < chatModel.Power {
|
||||
return fmt.Errorf("您当前剩余算力(%d)已不足以支付当前模型算力(%d)!", user.Power, chatModel.Power)
|
||||
}
|
||||
|
||||
messages := make([]interface{}, 0)
|
||||
messages = append(messages, types.Message{Role: "system", Content: `
|
||||
你是一位非常优秀的思维导图助手,你会把用户的所有提问都总结成思维导图,然后以 Markdown 格式输出。markdown 只需要输出一级标题,二级标题,三级标题,四级标题,最多输出四级,除此之外不要输出任何其他 markdown 标记。下面是一个合格的例子:
|
||||
你是一位非常优秀的思维导图助手, 你能帮助用户整理思路,根据用户提供的主题或内容,快速生成结构清晰,有条理的思维导图,然后以 Markdown 格式输出。markdown 只需要输出一级标题,二级标题,三级标题,四级标题,最多输出四级,除此之外不要输出任何其他 markdown 标记。下面是一个合格的例子:
|
||||
# Geek-AI 助手
|
||||
|
||||
## 完整的开源系统
|
||||
@ -130,7 +126,7 @@ func (h *MarkMapHandler) sendMessage(client *types.WsClient, prompt string, mode
|
||||
|
||||
另外,除此之外不要任何解释性语句。
|
||||
`})
|
||||
messages = append(messages, types.Message{Role: "user", Content: prompt})
|
||||
messages = append(messages, types.Message{Role: "user", Content: fmt.Sprintf("请生成一份有关【%s】一份思维导图,要求结构清晰,有条理", prompt)})
|
||||
var req = types.ApiRequest{
|
||||
Model: chatModel.Value,
|
||||
Stream: true,
|
||||
@ -253,5 +249,6 @@ func (h *MarkMapHandler) doRequest(req types.ApiRequest, chatModel model.ChatMod
|
||||
client = http.DefaultClient
|
||||
}
|
||||
request.Header.Set("Authorization", fmt.Sprintf("Bearer %s", apiKey.Value))
|
||||
logger.Debugf("Sending %s request, API KEY:%s, PROXY: %s, Model: %s", apiKey.ApiURL, apiURL, apiKey.ProxyURL, req.Model)
|
||||
return client.Do(request)
|
||||
}
|
||||
|
@ -465,35 +465,37 @@ func (h *MidJourneyHandler) Remove(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// refund power
|
||||
err := tx.Model(&model.User{}).Where("id = ?", job.UserId).UpdateColumn("power", gorm.Expr("power + ?", job.Power)).Error
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
resp.ERROR(c, err.Error())
|
||||
return
|
||||
}
|
||||
var user model.User
|
||||
h.DB.Where("id = ?", job.UserId).First(&user)
|
||||
err = tx.Create(&model.PowerLog{
|
||||
UserId: user.Id,
|
||||
Username: user.Username,
|
||||
Type: types.PowerConsume,
|
||||
Amount: job.Power,
|
||||
Balance: user.Power + job.Power,
|
||||
Mark: types.PowerAdd,
|
||||
Model: "mid-journey",
|
||||
Remark: fmt.Sprintf("绘画任务失败,退回算力。任务ID:%s", job.TaskId),
|
||||
CreatedAt: time.Now(),
|
||||
}).Error
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
resp.ERROR(c, err.Error())
|
||||
return
|
||||
// 如果任务未完成,或者任务失败,则恢复用户算力
|
||||
if job.Progress != 100 {
|
||||
err := tx.Model(&model.User{}).Where("id = ?", job.UserId).UpdateColumn("power", gorm.Expr("power + ?", job.Power)).Error
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
resp.ERROR(c, err.Error())
|
||||
return
|
||||
}
|
||||
var user model.User
|
||||
h.DB.Where("id = ?", job.UserId).First(&user)
|
||||
err = tx.Create(&model.PowerLog{
|
||||
UserId: user.Id,
|
||||
Username: user.Username,
|
||||
Type: types.PowerConsume,
|
||||
Amount: job.Power,
|
||||
Balance: user.Power,
|
||||
Mark: types.PowerAdd,
|
||||
Model: "mid-journey",
|
||||
Remark: fmt.Sprintf("绘画任务失败,退回算力。任务ID:%s,Err: %s", job.TaskId, job.ErrMsg),
|
||||
CreatedAt: time.Now(),
|
||||
}).Error
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
resp.ERROR(c, err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
tx.Commit()
|
||||
|
||||
// remove image
|
||||
err = h.uploader.GetUploadHandler().Delete(job.ImgURL)
|
||||
err := h.uploader.GetUploadHandler().Delete(job.ImgURL)
|
||||
if err != nil {
|
||||
logger.Error("remove image failed: ", err)
|
||||
}
|
||||
|
@ -232,7 +232,7 @@ func (h *SdJobHandler) getData(finish bool, userId uint, page int, pageSize int,
|
||||
|
||||
session := h.DB.Session(&gorm.Session{})
|
||||
if finish {
|
||||
session = session.Where("progress = ?", 100).Order("id DESC")
|
||||
session = session.Where("progress >= ?", 100).Order("id DESC")
|
||||
} else {
|
||||
session = session.Where("progress < ?", 100).Order("id ASC")
|
||||
}
|
||||
@ -278,20 +278,50 @@ func (h *SdJobHandler) getData(finish bool, userId uint, page int, pageSize int,
|
||||
// Remove remove task image
|
||||
func (h *SdJobHandler) Remove(c *gin.Context) {
|
||||
id := h.GetInt(c, "id", 0)
|
||||
userId := h.GetInt(c, "user_id", 0)
|
||||
userId := h.GetLoginUserId(c)
|
||||
var job model.SdJob
|
||||
if res := h.DB.Where("id = ? AND user_id = ?", id, userId).First(&job); res.Error != nil {
|
||||
resp.ERROR(c, "记录不存在")
|
||||
return
|
||||
}
|
||||
|
||||
// remove job recode
|
||||
res := h.DB.Delete(&model.SdJob{Id: job.Id})
|
||||
if res.Error != nil {
|
||||
resp.ERROR(c, res.Error.Error())
|
||||
// 删除任务
|
||||
tx := h.DB.Begin()
|
||||
if err := tx.Delete(&job).Error; err != nil {
|
||||
tx.Rollback()
|
||||
resp.ERROR(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 如果任务未完成,或者任务失败,则恢复用户算力
|
||||
if job.Progress != 100 {
|
||||
err := tx.Model(&model.User{}).Where("id = ?", job.UserId).UpdateColumn("power", gorm.Expr("power + ?", job.Power)).Error
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
resp.ERROR(c, err.Error())
|
||||
return
|
||||
}
|
||||
var user model.User
|
||||
h.DB.Where("id = ?", job.UserId).First(&user)
|
||||
err = tx.Create(&model.PowerLog{
|
||||
UserId: user.Id,
|
||||
Username: user.Username,
|
||||
Type: types.PowerConsume,
|
||||
Amount: job.Power,
|
||||
Balance: user.Power,
|
||||
Mark: types.PowerAdd,
|
||||
Model: "stable-diffusion",
|
||||
Remark: fmt.Sprintf("任务失败,退回算力。任务ID:%s, Err: %s", job.TaskId, job.ErrMsg),
|
||||
CreatedAt: time.Now(),
|
||||
}).Error
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
resp.ERROR(c, err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
tx.Commit()
|
||||
|
||||
// remove image
|
||||
err := h.uploader.GetUploadHandler().Delete(job.ImgURL)
|
||||
if err != nil {
|
||||
@ -309,10 +339,10 @@ func (h *SdJobHandler) Remove(c *gin.Context) {
|
||||
// Publish 发布/取消发布图片到画廊显示
|
||||
func (h *SdJobHandler) Publish(c *gin.Context) {
|
||||
id := h.GetInt(c, "id", 0)
|
||||
userId := h.GetInt(c, "user_id", 0)
|
||||
userId := h.GetLoginUserId(c)
|
||||
action := h.GetBool(c, "action") // 发布动作,true => 发布,false => 取消分享
|
||||
|
||||
res := h.DB.Model(&model.SdJob{Id: uint(id), UserId: userId}).UpdateColumn("publish", action)
|
||||
res := h.DB.Model(&model.SdJob{Id: uint(id), UserId: int(userId)}).UpdateColumn("publish", action)
|
||||
if res.Error != nil {
|
||||
logger.Error("error with update database:", res.Error)
|
||||
resp.ERROR(c, "更新数据库失败")
|
||||
|
@ -210,7 +210,42 @@ func (h *SunoHandler) Remove(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
// 删除任务
|
||||
h.DB.Delete(&job)
|
||||
tx := h.DB.Begin()
|
||||
if err := tx.Delete(&job).Error; err != nil {
|
||||
tx.Rollback()
|
||||
resp.ERROR(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 如果任务未完成,或者任务失败,则恢复用户算力
|
||||
if job.Progress != 100 {
|
||||
err := tx.Model(&model.User{}).Where("id = ?", job.UserId).UpdateColumn("power", gorm.Expr("power + ?", job.Power)).Error
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
resp.ERROR(c, err.Error())
|
||||
return
|
||||
}
|
||||
var user model.User
|
||||
h.DB.Where("id = ?", job.UserId).First(&user)
|
||||
err = tx.Create(&model.PowerLog{
|
||||
UserId: user.Id,
|
||||
Username: user.Username,
|
||||
Type: types.PowerConsume,
|
||||
Amount: job.Power,
|
||||
Balance: user.Power,
|
||||
Mark: types.PowerAdd,
|
||||
Model: job.ModelName,
|
||||
Remark: fmt.Sprintf("Suno 任务失败,退回算力。任务ID:%s,Err:%s", job.TaskId, job.ErrMsg),
|
||||
CreatedAt: time.Now(),
|
||||
}).Error
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
resp.ERROR(c, err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
tx.Commit()
|
||||
|
||||
// 删除文件
|
||||
_ = h.uploader.GetUploadHandler().Delete(job.CoverURL)
|
||||
_ = h.uploader.GetUploadHandler().Delete(job.AudioURL)
|
||||
|
@ -70,7 +70,7 @@ func (s *Service) Run() {
|
||||
if err != nil {
|
||||
logger.Errorf("error with image task: %v", err)
|
||||
s.db.Model(&model.DallJob{Id: task.JobId}).UpdateColumns(map[string]interface{}{
|
||||
"progress": -1,
|
||||
"progress": 101,
|
||||
"err_msg": err.Error(),
|
||||
})
|
||||
s.notifyQueue.RPush(sd.NotifyMessage{UserId: int(task.UserId), JobId: int(task.JobId), Message: sd.Failed})
|
||||
@ -148,7 +148,7 @@ func (s *Service) Image(task types.DallTask, sync bool) (string, error) {
|
||||
Where("enabled", true).
|
||||
Order("last_used_at ASC").First(&apiKey)
|
||||
if tx.Error != nil {
|
||||
return "", fmt.Errorf("no available IMG api key: %v", tx.Error)
|
||||
return "", fmt.Errorf("no available DALL-E api key: %v", tx.Error)
|
||||
}
|
||||
|
||||
var res imgRes
|
||||
@ -225,6 +225,30 @@ func (s *Service) CheckTaskNotify() {
|
||||
}()
|
||||
}
|
||||
|
||||
func (s *Service) CheckTaskStatus() {
|
||||
go func() {
|
||||
logger.Info("Running DALL-E task status checking ...")
|
||||
for {
|
||||
var jobs []model.DallJob
|
||||
res := s.db.Where("progress < ?", 100).Find(&jobs)
|
||||
if res.Error != nil {
|
||||
time.Sleep(5 * time.Second)
|
||||
continue
|
||||
}
|
||||
|
||||
for _, job := range jobs {
|
||||
// 超时的任务标记为失败
|
||||
if time.Now().Sub(job.CreatedAt) > time.Minute*10 {
|
||||
job.Progress = 101
|
||||
job.ErrMsg = "任务超时"
|
||||
s.db.Updates(&job)
|
||||
}
|
||||
}
|
||||
time.Sleep(time.Second * 10)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (s *Service) DownloadImages() {
|
||||
go func() {
|
||||
var items []model.DallJob
|
||||
@ -271,44 +295,3 @@ func (s *Service) downloadImage(jobId uint, userId int, orgURL string) (string,
|
||||
s.notifyQueue.RPush(sd.NotifyMessage{UserId: userId, JobId: int(jobId), Message: sd.Finished})
|
||||
return imgURL, nil
|
||||
}
|
||||
|
||||
// CheckTaskStatus 检查任务状态,自动删除过期或者失败的任务
|
||||
func (s *Service) CheckTaskStatus() {
|
||||
go func() {
|
||||
logger.Info("Running Stable-Diffusion task status checking ...")
|
||||
for {
|
||||
var jobs []model.DallJob
|
||||
res := s.db.Where("progress < ?", 100).Find(&jobs)
|
||||
if res.Error != nil {
|
||||
time.Sleep(5 * time.Second)
|
||||
continue
|
||||
}
|
||||
|
||||
for _, job := range jobs {
|
||||
// 5 分钟还没完成的任务直接删除
|
||||
if time.Now().Sub(job.CreatedAt) > time.Minute*5 || job.Progress == -1 {
|
||||
s.db.Delete(&job)
|
||||
var user model.User
|
||||
s.db.Where("id = ?", job.UserId).First(&user)
|
||||
// 退回绘图次数
|
||||
res = s.db.Model(&model.User{}).Where("id = ?", job.UserId).UpdateColumn("power", gorm.Expr("power + ?", job.Power))
|
||||
if res.Error == nil && res.RowsAffected > 0 {
|
||||
s.db.Create(&model.PowerLog{
|
||||
UserId: user.Id,
|
||||
Username: user.Username,
|
||||
Type: types.PowerConsume,
|
||||
Amount: job.Power,
|
||||
Balance: user.Power + job.Power,
|
||||
Mark: types.PowerAdd,
|
||||
Model: "dall-e-3",
|
||||
Remark: fmt.Sprintf("任务失败,退回算力。任务ID:%d", job.Id),
|
||||
CreatedAt: time.Now(),
|
||||
})
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
time.Sleep(time.Second * 10)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
@ -187,6 +187,14 @@ func (p *ServicePool) SyncTaskProgress() {
|
||||
}
|
||||
|
||||
for _, job := range jobs {
|
||||
// 5 分钟还没完成的任务标记为失败
|
||||
if time.Now().Sub(job.CreatedAt) > time.Minute*5 {
|
||||
job.Progress = 101
|
||||
job.ErrMsg = "任务超时"
|
||||
p.db.Updates(&job)
|
||||
continue
|
||||
}
|
||||
|
||||
if servicePlus := p.getService(job.ChannelId); servicePlus != nil {
|
||||
_ = servicePlus.Notify(job)
|
||||
}
|
||||
|
@ -109,27 +109,11 @@ func (p *ServicePool) CheckTaskStatus() {
|
||||
}
|
||||
|
||||
for _, job := range jobs {
|
||||
// 5 分钟还没完成的任务直接删除
|
||||
if time.Now().Sub(job.CreatedAt) > time.Minute*5 || job.Progress == -1 {
|
||||
p.db.Delete(&job)
|
||||
var user model.User
|
||||
p.db.Where("id = ?", job.UserId).First(&user)
|
||||
// 退回绘图次数
|
||||
res = p.db.Model(&model.User{}).Where("id = ?", job.UserId).UpdateColumn("power", gorm.Expr("power + ?", job.Power))
|
||||
if res.Error == nil && res.RowsAffected > 0 {
|
||||
p.db.Create(&model.PowerLog{
|
||||
UserId: user.Id,
|
||||
Username: user.Username,
|
||||
Type: types.PowerConsume,
|
||||
Amount: job.Power,
|
||||
Balance: user.Power + job.Power,
|
||||
Mark: types.PowerAdd,
|
||||
Model: "stable-diffusion",
|
||||
Remark: fmt.Sprintf("任务失败,退回算力。任务ID:%s", job.TaskId),
|
||||
CreatedAt: time.Now(),
|
||||
})
|
||||
}
|
||||
continue
|
||||
// 5 分钟还没完成的任务标记为失败
|
||||
if time.Now().Sub(job.CreatedAt) > time.Minute*5 {
|
||||
job.Progress = 101
|
||||
job.ErrMsg = "任务超时"
|
||||
p.db.Updates(&job)
|
||||
}
|
||||
}
|
||||
time.Sleep(time.Second * 5)
|
||||
|
@ -87,7 +87,7 @@ func (s *Service) Run() {
|
||||
logger.Error("绘画任务执行失败:", err.Error())
|
||||
// update the task progress
|
||||
s.db.Model(&model.SdJob{Id: uint(task.Id)}).UpdateColumns(map[string]interface{}{
|
||||
"progress": -1,
|
||||
"progress": 101,
|
||||
"err_msg": err.Error(),
|
||||
})
|
||||
// 通知前端,任务失败
|
||||
|
@ -4,8 +4,8 @@ VUE_APP_USER=18575670125
|
||||
VUE_APP_PASS=12345678
|
||||
VUE_APP_ADMIN_USER=admin
|
||||
VUE_APP_ADMIN_PASS=admin123
|
||||
VUE_APP_KEY_PREFIX=ChatPLUS_DEV_
|
||||
VUE_APP_KEY_PREFIX=GeekAI_DEV_
|
||||
VUE_APP_TITLE="Geek-AI 创作系统"
|
||||
VUE_APP_VERSION=v4.1.1
|
||||
VUE_APP_VERSION=v4.1.2
|
||||
VUE_APP_DOCS_URL=https://docs.geekai.me
|
||||
VUE_APP_GIT_URL=https://github.com/yangjian102621/geekai
|
||||
|
@ -1,6 +1,6 @@
|
||||
VUE_APP_API_HOST=
|
||||
VUE_APP_WS_HOST=
|
||||
VUE_APP_KEY_PREFIX=ChatPLUS_
|
||||
VUE_APP_VERSION=v4.1.1
|
||||
VUE_APP_KEY_PREFIX=GeekAI_
|
||||
VUE_APP_VERSION=v4.1.2
|
||||
VUE_APP_DOCS_URL=https://docs.geekai.me
|
||||
VUE_APP_GIT_URL=https://github.com/yangjian102621/geekai
|
||||
|
@ -221,134 +221,7 @@
|
||||
|
||||
|
||||
// 任务列表
|
||||
|
||||
.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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@import "waterfall-list.styl"
|
||||
}
|
||||
|
||||
.no-more-data {
|
||||
|
@ -220,136 +220,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 任务列表
|
||||
|
||||
.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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@import "waterfall-list.styl"
|
||||
}
|
||||
|
||||
.no-more-data {
|
||||
|
146
web/src/assets/css/waterfall-list.styl
Normal file
146
web/src/assets/css/waterfall-list.styl
Normal file
@ -0,0 +1,146 @@
|
||||
.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 220px
|
||||
color #ffffff
|
||||
|
||||
.err-msg-container {
|
||||
overflow hidden
|
||||
word-break break-all
|
||||
padding 15px
|
||||
.title {
|
||||
font-size 20px
|
||||
text-align center
|
||||
font-weight bold
|
||||
color #f56c6c
|
||||
margin-bottom 30px
|
||||
}
|
||||
|
||||
.opt {
|
||||
display flex
|
||||
justify-content center
|
||||
}
|
||||
}
|
||||
.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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -367,7 +367,6 @@ const initData = () => {
|
||||
inputRef.value.addEventListener('paste', (event) => {
|
||||
const items = (event.clipboardData || window.clipboardData).items;
|
||||
let fileFound = false;
|
||||
loading.value = true
|
||||
|
||||
for (let item of items) {
|
||||
if (item.kind === 'file') {
|
||||
@ -376,6 +375,7 @@ const initData = () => {
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
loading.value = true
|
||||
// 执行上传操作
|
||||
httpPost('/api/upload', formData).then((res) => {
|
||||
files.value.push(res.data)
|
||||
@ -389,7 +389,7 @@ const initData = () => {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!fileFound) {
|
||||
document.getElementById('status').innerText = 'No file found in paste data.';
|
||||
}
|
||||
|
@ -125,6 +125,24 @@
|
||||
</template>
|
||||
</el-image>
|
||||
|
||||
<el-image v-else-if="slotProp.item.progress === 101">
|
||||
<template #error>
|
||||
<div class="image-slot">
|
||||
<div class="err-msg-container">
|
||||
<div class="title">任务失败</div>
|
||||
<div class="opt">
|
||||
<el-popover title="错误详情" trigger="click" :width="250" :content="slotProp.item['err_msg']" placement="top">
|
||||
<template #reference>
|
||||
<el-button type="info">详情</el-button>
|
||||
</template>
|
||||
</el-popover>
|
||||
<el-button type="danger" @click="removeImage(slotProp.item)">删除</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-image>
|
||||
|
||||
<el-image v-else>
|
||||
<template #error>
|
||||
<div class="image-slot">
|
||||
@ -136,17 +154,17 @@
|
||||
|
||||
<div class="remove">
|
||||
<el-tooltip content="删除" placement="top" effect="light">
|
||||
<el-button type="danger" :icon="Delete" @click="removeImage($event,slotProp.item)" circle/>
|
||||
<el-button type="danger" :icon="Delete" @click="removeImage(slotProp.item)" circle/>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="分享" placement="top" effect="light" v-if="slotProp.item.publish">
|
||||
<el-button type="warning"
|
||||
@click="publishImage($event,slotProp.item, false)"
|
||||
@click="publishImage(slotProp.item, false)"
|
||||
circle>
|
||||
<i class="iconfont icon-cancel-share"></i>
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="取消分享" placement="top" effect="light" v-else>
|
||||
<el-button type="success" @click="publishImage($event,slotProp.item, true)" circle>
|
||||
<el-button type="success" @click="publishImage(slotProp.item, true)" circle>
|
||||
<i class="iconfont icon-share-bold"></i>
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
@ -185,7 +203,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {onMounted, onUnmounted, ref} from "vue"
|
||||
import {nextTick, onMounted, onUnmounted, ref} from "vue"
|
||||
import {Delete, InfoFilled, Picture} from "@element-plus/icons-vue";
|
||||
import {httpGet, httpPost} from "@/utils/http";
|
||||
import {ElMessage, ElMessageBox, ElNotification} from "element-plus";
|
||||
@ -286,25 +304,9 @@ const connect = () => {
|
||||
}
|
||||
}
|
||||
|
||||
// 心跳函数
|
||||
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/dall/client?user_id=${userId.value}`);
|
||||
_socket.addEventListener('open', () => {
|
||||
socket.value = _socket;
|
||||
|
||||
// 发送心跳消息
|
||||
sendHeartbeat()
|
||||
});
|
||||
|
||||
_socket.addEventListener('message', event => {
|
||||
@ -313,12 +315,12 @@ const connect = () => {
|
||||
reader.readAsText(event.data, "UTF-8")
|
||||
reader.onload = () => {
|
||||
const message = String(reader.result)
|
||||
if (message === "FINISH") {
|
||||
if (message === "FINISH" || message === "FAIL") {
|
||||
page.value = 0
|
||||
isOver.value = false
|
||||
fetchFinishJobs(page.value)
|
||||
}
|
||||
fetchRunningJobs()
|
||||
nextTick(() => fetchRunningJobs())
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -336,22 +338,7 @@ const fetchRunningJobs = () => {
|
||||
}
|
||||
// 获取运行中的任务
|
||||
httpGet(`/api/dall/jobs?finish=false`).then(res => {
|
||||
const jobs = res.data
|
||||
const _jobs = []
|
||||
for (let i = 0; i < jobs.length; i++) {
|
||||
if (jobs[i].progress === -1) {
|
||||
ElNotification({
|
||||
title: '任务执行失败',
|
||||
dangerouslyUseHTMLString: true,
|
||||
message: `任务ID:${jobs[i]['task_id']}<br />原因:${jobs[i]['err_msg']}`,
|
||||
type: 'error',
|
||||
})
|
||||
power.value += dallPower.value
|
||||
continue
|
||||
}
|
||||
_jobs.push(jobs[i])
|
||||
}
|
||||
runningJobs.value = _jobs
|
||||
runningJobs.value = res.data
|
||||
}).catch(e => {
|
||||
ElMessage.error("获取任务失败:" + e.message)
|
||||
})
|
||||
@ -409,8 +396,7 @@ const generate = () => {
|
||||
})
|
||||
}
|
||||
|
||||
const removeImage = (event, item) => {
|
||||
event.stopPropagation()
|
||||
const removeImage = (item) => {
|
||||
ElMessageBox.confirm(
|
||||
'此操作将会删除任务和图片,继续操作码?',
|
||||
'删除提示',
|
||||
@ -420,7 +406,7 @@ const removeImage = (event, item) => {
|
||||
type: 'warning',
|
||||
}
|
||||
).then(() => {
|
||||
httpGet("/api/dall/remove", {id: item.id, user_id: item.user}).then(() => {
|
||||
httpGet("/api/dall/remove", {id: item.id}).then(() => {
|
||||
ElMessage.success("任务删除成功")
|
||||
page.value = 0
|
||||
isOver.value = false
|
||||
@ -437,18 +423,16 @@ const previewImg = (item) => {
|
||||
}
|
||||
|
||||
// 发布图片到作品墙
|
||||
const publishImage = (event, item, action) => {
|
||||
event.stopPropagation()
|
||||
const publishImage = (item, action) => {
|
||||
let text = "图片发布"
|
||||
if (action === false) {
|
||||
text = "取消发布"
|
||||
}
|
||||
httpGet("/api/dall/publish", {id: item.id, action: action,user_id:item.user_id}).then(() => {
|
||||
httpGet("/api/dall/publish", {id: item.id, action: action}).then(() => {
|
||||
ElMessage.success(text + "成功")
|
||||
item.publish = action
|
||||
page.value = 0
|
||||
isOver.value = false
|
||||
fetchFinishJobs()
|
||||
}).catch(e => {
|
||||
ElMessage.error(text + "失败:" + e.message)
|
||||
})
|
||||
|
@ -17,7 +17,7 @@
|
||||
effect="light"
|
||||
content="部署文档"
|
||||
placement="bottom">
|
||||
<a href="https://docs.geekai.me/install/" class="link-button" target="_blank">
|
||||
<a :href="docsURL" class="link-button" target="_blank">
|
||||
<i class="iconfont icon-book"></i>
|
||||
</a>
|
||||
</el-tooltip>
|
||||
|
@ -487,7 +487,7 @@
|
||||
</div>
|
||||
</template>
|
||||
</el-image>
|
||||
<el-image v-else-if="slotProp.item['err_msg'] !== ''">
|
||||
<el-image v-else-if="slotProp.item.progress === 101">
|
||||
<template #error>
|
||||
<div class="image-slot">
|
||||
<div class="err-msg-container">
|
||||
|
@ -313,21 +313,41 @@
|
||||
: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">
|
||||
<el-button type="danger" :icon="Delete" @click="removeImage($event,slotProp.item)" circle/>
|
||||
<el-button type="warning" v-if="slotProp.item.publish"
|
||||
@click="publishImage($event,slotProp.item, false)"
|
||||
circle>
|
||||
<i class="iconfont icon-cancel-share"></i>
|
||||
</el-button>
|
||||
<el-button type="success" v-else @click="publishImage($event,slotProp.item, true)" circle>
|
||||
<i class="iconfont icon-share-bold"></i>
|
||||
</el-button>
|
||||
<div class="job-item animate">
|
||||
<el-image v-if="slotProp.item.progress === 101">
|
||||
<template #error>
|
||||
<div class="image-slot">
|
||||
<div class="err-msg-container">
|
||||
<div class="title">任务失败</div>
|
||||
<div class="opt">
|
||||
<el-popover title="错误详情" trigger="click" :width="250" :content="slotProp.item['err_msg']" placement="top">
|
||||
<template #reference>
|
||||
<el-button type="info">详情</el-button>
|
||||
</template>
|
||||
</el-popover>
|
||||
<el-button type="danger" @click="removeImage(slotProp.item)">删除</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-image>
|
||||
<div v-else>
|
||||
<el-image
|
||||
:src="slotProp.item['img_thumb']"
|
||||
@click="showTask(slotProp.item)"
|
||||
fit="cover"
|
||||
loading="lazy"/>
|
||||
<div class="remove">
|
||||
<el-button type="danger" :icon="Delete" @click="removeImage(slotProp.item)" circle/>
|
||||
<el-button type="warning" v-if="slotProp.item.publish"
|
||||
@click="publishImage(slotProp.item, false)"
|
||||
circle>
|
||||
<i class="iconfont icon-cancel-share"></i>
|
||||
</el-button>
|
||||
<el-button type="success" v-else @click="publishImage(slotProp.item, true)" circle>
|
||||
<i class="iconfont icon-share-bold"></i>
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -466,7 +486,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {onMounted, onUnmounted, ref} from "vue"
|
||||
import {nextTick, onMounted, onUnmounted, ref} from "vue"
|
||||
import {Delete, DocumentCopy, InfoFilled, Orange, Picture} from "@element-plus/icons-vue";
|
||||
import {httpGet, httpPost} from "@/utils/http";
|
||||
import {ElMessage, ElMessageBox, ElNotification} from "element-plus";
|
||||
@ -540,25 +560,9 @@ const connect = () => {
|
||||
}
|
||||
}
|
||||
|
||||
// 心跳函数
|
||||
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 => {
|
||||
@ -567,12 +571,12 @@ const connect = () => {
|
||||
reader.readAsText(event.data, "UTF-8")
|
||||
reader.onload = () => {
|
||||
const message = String(reader.result)
|
||||
if (message === "FINISH") {
|
||||
if (message === "FINISH" || message === "FAIL") {
|
||||
page.value = 0
|
||||
isOver.value = false
|
||||
fetchFinishJobs()
|
||||
}
|
||||
fetchRunningJobs()
|
||||
nextTick(() => fetchRunningJobs())
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -633,22 +637,7 @@ const fetchRunningJobs = () => {
|
||||
|
||||
// 获取运行中的任务
|
||||
httpGet(`/api/sd/jobs?finish=0`).then(res => {
|
||||
const jobs = res.data
|
||||
const _jobs = []
|
||||
for (let i = 0; i < jobs.length; i++) {
|
||||
if (jobs[i].progress === -1) {
|
||||
ElNotification({
|
||||
title: '任务执行失败',
|
||||
dangerouslyUseHTMLString: true,
|
||||
message: `任务ID:${jobs[i]['task_id']}<br />原因:${jobs[i]['err_msg']}`,
|
||||
type: 'error',
|
||||
})
|
||||
power.value += sdPower.value
|
||||
continue
|
||||
}
|
||||
_jobs.push(jobs[i])
|
||||
}
|
||||
runningJobs.value = _jobs
|
||||
runningJobs.value = res.data
|
||||
}).catch(e => {
|
||||
ElMessage.error("获取任务失败:" + e.message)
|
||||
})
|
||||
@ -699,7 +688,7 @@ const generate = () => {
|
||||
return
|
||||
}
|
||||
|
||||
if (params.value.seed === '') {
|
||||
if (!params.value.seed) {
|
||||
params.value.seed = -1
|
||||
}
|
||||
params.value.session_id = getSessionId()
|
||||
@ -721,8 +710,7 @@ const copyParams = (row) => {
|
||||
showTaskDialog.value = false
|
||||
}
|
||||
|
||||
const removeImage = (event, item) => {
|
||||
event.stopPropagation()
|
||||
const removeImage = (item) => {
|
||||
ElMessageBox.confirm(
|
||||
'此操作将会删除任务和图片,继续操作码?',
|
||||
'删除提示',
|
||||
@ -732,7 +720,7 @@ const removeImage = (event, item) => {
|
||||
type: 'warning',
|
||||
}
|
||||
).then(() => {
|
||||
httpGet("/api/sd/remove", {id: item.id, user_id: item.user}).then(() => {
|
||||
httpGet("/api/sd/remove", {id: item.id}).then(() => {
|
||||
ElMessage.success("任务删除成功")
|
||||
page.value = 0
|
||||
isOver.value = false
|
||||
@ -745,13 +733,12 @@ const removeImage = (event, item) => {
|
||||
}
|
||||
|
||||
// 发布图片到作品墙
|
||||
const publishImage = (event, item, action) => {
|
||||
event.stopPropagation()
|
||||
const publishImage = (item, action) => {
|
||||
let text = "图片发布"
|
||||
if (action === false) {
|
||||
text = "取消发布"
|
||||
}
|
||||
httpGet("/api/sd/publish", {id: item.id, action: action, user_id: item.user}).then(() => {
|
||||
httpGet("/api/sd/publish", {id: item.id, action: action}).then(() => {
|
||||
ElMessage.success(text + "成功")
|
||||
item.publish = action
|
||||
page.value = 0
|
||||
|
@ -156,7 +156,7 @@ httpGet("/api/config/get?key=system").then(res => {
|
||||
const initData = () => {
|
||||
httpGet("/api/model/list").then(res => {
|
||||
for (let v of res.data) {
|
||||
if (v.platform === "OpenAI" && v.value.indexOf("gpt-4-gizmo") === -1) {
|
||||
if (v.value.indexOf("gpt-4-gizmo") === -1) {
|
||||
models.value.push(v)
|
||||
}
|
||||
}
|
||||
|
@ -381,9 +381,9 @@ onMounted(() => {
|
||||
|
||||
checkSession().then(user => {
|
||||
userId.value = user.id
|
||||
fetchData(1)
|
||||
connect()
|
||||
})
|
||||
fetchData(1)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
@ -410,6 +410,8 @@ const fetchData = (_page) => {
|
||||
list.value = items
|
||||
noData.value = list.value.length === 0
|
||||
}).catch(e => {
|
||||
loading.value = false
|
||||
noData.value = true
|
||||
showMessageError("获取作品列表失败:"+e.message)
|
||||
})
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user