From a0f3bc8ccb9ad567999e5ca70cad32457d1efbce Mon Sep 17 00:00:00 2001 From: RockYang Date: Fri, 26 Jan 2024 11:57:08 +0800 Subject: [PATCH] feat: blend and swap face function for midjourney-plus is ready --- api/handler/mj_handler.go | 7 +- api/service/mj/plus/client.go | 4 +- api/service/mj/pool.go | 9 +- web/src/assets/css/image-mj.css | 74 ++-- web/src/assets/css/image-sd.css | 74 ++-- web/src/assets/css/task-list.styl | 323 +++++++++-------- web/src/views/ImageMj.vue | 581 +++++++++++++++--------------- 7 files changed, 568 insertions(+), 504 deletions(-) diff --git a/api/handler/mj_handler.go b/api/handler/mj_handler.go index 89995d98..b1c78756 100644 --- a/api/handler/mj_handler.go +++ b/api/handler/mj_handler.go @@ -157,6 +157,11 @@ func (h *MidJourneyHandler) Image(c *gin.Context) { Prompt: prompt, CreatedAt: time.Now(), } + if data.TaskType == types.TaskBlend.String() { + data.Prompt = "融图:" + strings.Join(data.ImgArr, ",") + } else if data.TaskType == types.TaskSwapFace.String() { + data.Prompt = "换脸:" + strings.Join(data.ImgArr, ",") + } if res := h.db.Create(&job); res.Error != nil || res.RowsAffected == 0 { resp.ERROR(c, "添加任务失败:"+res.Error.Error()) return @@ -166,7 +171,7 @@ func (h *MidJourneyHandler) Image(c *gin.Context) { Id: int(job.Id), TaskId: taskId, SessionId: data.SessionId, - Type: types.TaskImage, + Type: types.TaskType(data.TaskType), Prompt: prompt, UserId: userId, ImgArr: data.ImgArr, diff --git a/api/service/mj/plus/client.go b/api/service/mj/plus/client.go index 45ba1481..b79afa24 100644 --- a/api/service/mj/plus/client.go +++ b/api/service/mj/plus/client.go @@ -98,7 +98,7 @@ func (c *Client) Blend(task types.MjTask) (ImageRes, error) { BotType: "MID_JOURNEY", Dimensions: "SQUARE", NotifyHook: c.Config.NotifyURL, - Base64Array: make([]string, 1), + Base64Array: make([]string, 0), } // 生成图片 Base64 编码 if len(task.ImgArr) > 0 { @@ -107,7 +107,7 @@ func (c *Client) Blend(task types.MjTask) (ImageRes, error) { if err != nil { logger.Error("error with download image: ", err) } else { - body.Base64Array[0] = "data:image/png;base64," + base64.StdEncoding.EncodeToString(imageData) + body.Base64Array = append(body.Base64Array, "data:image/png;base64,"+base64.StdEncoding.EncodeToString(imageData)) } } } diff --git a/api/service/mj/pool.go b/api/service/mj/pool.go index 8aee04a6..2e406407 100644 --- a/api/service/mj/pool.go +++ b/api/service/mj/pool.go @@ -167,7 +167,7 @@ func (p *ServicePool) HasAvailableService() bool { } func (p *ServicePool) Notify(data plus.CBReq) error { - logger.Infof("收到任务回调:%+v", data) + logger.Debugf("收到任务回调:%+v", data) var job model.MidJourneyJob res := p.db.Where("task_id = ?", data.Id).First(&job) if res.Error != nil { @@ -190,7 +190,7 @@ func (p *ServicePool) SyncTaskProgress() { go func() { var items []model.MidJourneyJob for { - res := p.db.Where("progress < ?", 100).Find(&items) + res := p.db.Where("progress >= ? AND progress < ?", 0, 100).Find(&items) if res.Error != nil { continue } @@ -215,6 +215,11 @@ func (p *ServicePool) SyncTaskProgress() { if err != nil { continue } + // 任务失败了 + if task.FailReason != "" { + p.db.Model(&model.MidJourneyJob{Id: v.Id}).UpdateColumn("progress", -1) + continue + } if len(task.Buttons) > 0 { v.Hash = getImageHash(task.Buttons[0].CustomId) } diff --git a/web/src/assets/css/image-mj.css b/web/src/assets/css/image-mj.css index cdb9197e..4bc3c538 100644 --- a/web/src/assets/css/image-mj.css +++ b/web/src/assets/css/image-mj.css @@ -231,32 +231,49 @@ .page-mj .inner .task-list-box .task-list-inner .el-form-item__label { color: #fff; } -.page-mj .inner .task-list-box .task-list-inner .img-uploader .el-upload { +.page-mj .inner .task-list-box .task-list-inner .img-inline { + display: flex; +} +.page-mj .inner .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: 300px; + width: 120px; transition: var(--el-transition-duration-fast); margin-bottom: 20px; } -.page-mj .inner .task-list-box .task-list-inner .img-uploader .el-upload:hover { +.page-mj .inner .task-list-box .task-list-inner .img-inline .img-uploader .el-upload:hover { border-color: var(--el-color-primary); } -.page-mj .inner .task-list-box .task-list-inner .img-uploader .el-upload .el-icon.uploader-icon { +.page-mj .inner .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; } -.page-mj .inner .task-list-box .task-list-inner .img-inline { +.page-mj .inner .task-list-box .task-list-inner .img-inline .img-list-box { display: flex; } -.page-mj .inner .task-list-box .task-list-inner .img-inline .img-uploader { +.page-mj .inner .task-list-box .task-list-inner .img-inline .img-list-box .img-item { + width: 120px; + position: relative; margin-right: 10px; } +.page-mj .inner .task-list-box .task-list-inner .img-inline .img-list-box .img-item .el-image { + width: 120px; + height: 120px; + border-radius: 5px; +} +.page-mj .inner .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; +} .page-mj .inner .task-list-box .task-list-inner .submit-btn { display: flex; margin: 20px 0; @@ -270,17 +287,17 @@ justify-content: right; align-items: center; } -.page-mj .inner .task-list-box .running-job-list .job-item { +.page-mj .inner .task-list-box .task-list-inner .job-list-box .running-job-list .job-item { width: 100%; padding: 2px; background-color: #555; } -.page-mj .inner .task-list-box .running-job-list .job-item .job-item-inner { +.page-mj .inner .task-list-box .task-list-inner .job-list-box .running-job-list .job-item .job-item-inner { position: relative; height: 100%; overflow: hidden; } -.page-mj .inner .task-list-box .running-job-list .job-item .job-item-inner .progress { +.page-mj .inner .task-list-box .task-list-inner .job-list-box .running-job-list .job-item .job-item-inner .progress { position: absolute; width: 100%; height: 100%; @@ -290,11 +307,11 @@ justify-content: center; align-items: center; } -.page-mj .inner .task-list-box .running-job-list .job-item .job-item-inner .progress span { +.page-mj .inner .task-list-box .task-list-inner .job-list-box .running-job-list .job-item .job-item-inner .progress span { font-size: 20px; color: #fff; } -.page-mj .inner .task-list-box .finish-job-list .job-item { +.page-mj .inner .task-list-box .task-list-inner .job-list-box .finish-job-list .job-item { width: 100%; height: 100%; border: 1px solid #666; @@ -304,17 +321,17 @@ transition: all 0.3s ease; /* 添加过渡效果 */ position: relative; } -.page-mj .inner .task-list-box .finish-job-list .job-item .opt .opt-line { +.page-mj .inner .task-list-box .task-list-inner .job-list-box .finish-job-list .job-item .opt .opt-line { margin: 6px 0; } -.page-mj .inner .task-list-box .finish-job-list .job-item .opt .opt-line ul { +.page-mj .inner .task-list-box .task-list-inner .job-list-box .finish-job-list .job-item .opt .opt-line ul { display: flex; flex-flow: row; } -.page-mj .inner .task-list-box .finish-job-list .job-item .opt .opt-line ul li { +.page-mj .inner .task-list-box .task-list-inner .job-list-box .finish-job-list .job-item .opt .opt-line ul li { margin-right: 6px; } -.page-mj .inner .task-list-box .finish-job-list .job-item .opt .opt-line ul li a { +.page-mj .inner .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; @@ -324,59 +341,58 @@ background-color: #4e5058; color: #fff; } -.page-mj .inner .task-list-box .finish-job-list .job-item .opt .opt-line ul li a:hover { +.page-mj .inner .task-list-box .task-list-inner .job-list-box .finish-job-list .job-item .opt .opt-line ul li a:hover { background-color: #6d6f78; } -.page-mj .inner .task-list-box .finish-job-list .job-item .opt .opt-line ul .show-prompt { +.page-mj .inner .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; } -.page-mj .inner .task-list-box .finish-job-list .job-item .remove { +.page-mj .inner .task-list-box .task-list-inner .job-list-box .finish-job-list .job-item .remove { display: none; position: absolute; right: 10px; top: 10px; } -.page-mj .inner .task-list-box .finish-job-list .job-item:hover .remove { +.page-mj .inner .task-list-box .task-list-inner .job-list-box .finish-job-list .job-item:hover .remove { display: block; } -.page-mj .inner .task-list-box .finish-job-list .animate:hover { +.page-mj .inner .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像素 */ } -.page-mj .inner .task-list-box .el-image { +.page-mj .inner .task-list-box .task-list-inner .job-list-box .el-image { width: 100%; height: 100%; overflow: visible; } -.page-mj .inner .task-list-box .el-image img { +.page-mj .inner .task-list-box .task-list-inner .job-list-box .el-image img { height: 240px; } -.page-mj .inner .task-list-box .el-image .el-image-viewer__wrapper img { +.page-mj .inner .task-list-box .task-list-inner .job-list-box .el-image .el-image-viewer__wrapper img { width: auto; height: auto; } -.page-mj .inner .task-list-box .el-image .image-slot { +.page-mj .inner .task-list-box .task-list-inner .job-list-box .el-image .image-slot { display: flex; flex-flow: column; justify-content: center; align-items: center; - height: 100%; min-height: 200px; color: #fff; height: 240px; } -.page-mj .inner .task-list-box .el-image .image-slot .iconfont { +.page-mj .inner .task-list-box .task-list-inner .job-list-box .el-image .image-slot .iconfont { font-size: 50px; margin-bottom: 10px; } -.page-mj .inner .task-list-box .el-image.upscale { +.page-mj .inner .task-list-box .task-list-inner .job-list-box .el-image.upscale { max-height: 310px; } -.page-mj .inner .task-list-box .el-image.upscale img { +.page-mj .inner .task-list-box .task-list-inner .job-list-box .el-image.upscale img { height: 310px; } -.page-mj .inner .task-list-box .el-image.upscale .el-image-viewer__wrapper img { +.page-mj .inner .task-list-box .task-list-inner .job-list-box .el-image.upscale .el-image-viewer__wrapper img { width: auto; height: auto; } diff --git a/web/src/assets/css/image-sd.css b/web/src/assets/css/image-sd.css index 15251961..3504fcd0 100644 --- a/web/src/assets/css/image-sd.css +++ b/web/src/assets/css/image-sd.css @@ -116,32 +116,49 @@ .page-sd .inner .task-list-box .task-list-inner .el-form-item__label { color: #fff; } -.page-sd .inner .task-list-box .task-list-inner .img-uploader .el-upload { +.page-sd .inner .task-list-box .task-list-inner .img-inline { + display: flex; +} +.page-sd .inner .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: 300px; + width: 120px; transition: var(--el-transition-duration-fast); margin-bottom: 20px; } -.page-sd .inner .task-list-box .task-list-inner .img-uploader .el-upload:hover { +.page-sd .inner .task-list-box .task-list-inner .img-inline .img-uploader .el-upload:hover { border-color: var(--el-color-primary); } -.page-sd .inner .task-list-box .task-list-inner .img-uploader .el-upload .el-icon.uploader-icon { +.page-sd .inner .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; } -.page-sd .inner .task-list-box .task-list-inner .img-inline { +.page-sd .inner .task-list-box .task-list-inner .img-inline .img-list-box { display: flex; } -.page-sd .inner .task-list-box .task-list-inner .img-inline .img-uploader { +.page-sd .inner .task-list-box .task-list-inner .img-inline .img-list-box .img-item { + width: 120px; + position: relative; margin-right: 10px; } +.page-sd .inner .task-list-box .task-list-inner .img-inline .img-list-box .img-item .el-image { + width: 120px; + height: 120px; + border-radius: 5px; +} +.page-sd .inner .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; +} .page-sd .inner .task-list-box .task-list-inner .submit-btn { display: flex; margin: 20px 0; @@ -155,17 +172,17 @@ justify-content: right; align-items: center; } -.page-sd .inner .task-list-box .running-job-list .job-item { +.page-sd .inner .task-list-box .task-list-inner .job-list-box .running-job-list .job-item { width: 100%; padding: 2px; background-color: #555; } -.page-sd .inner .task-list-box .running-job-list .job-item .job-item-inner { +.page-sd .inner .task-list-box .task-list-inner .job-list-box .running-job-list .job-item .job-item-inner { position: relative; height: 100%; overflow: hidden; } -.page-sd .inner .task-list-box .running-job-list .job-item .job-item-inner .progress { +.page-sd .inner .task-list-box .task-list-inner .job-list-box .running-job-list .job-item .job-item-inner .progress { position: absolute; width: 100%; height: 100%; @@ -175,11 +192,11 @@ justify-content: center; align-items: center; } -.page-sd .inner .task-list-box .running-job-list .job-item .job-item-inner .progress span { +.page-sd .inner .task-list-box .task-list-inner .job-list-box .running-job-list .job-item .job-item-inner .progress span { font-size: 20px; color: #fff; } -.page-sd .inner .task-list-box .finish-job-list .job-item { +.page-sd .inner .task-list-box .task-list-inner .job-list-box .finish-job-list .job-item { width: 100%; height: 100%; border: 1px solid #666; @@ -189,17 +206,17 @@ transition: all 0.3s ease; /* 添加过渡效果 */ position: relative; } -.page-sd .inner .task-list-box .finish-job-list .job-item .opt .opt-line { +.page-sd .inner .task-list-box .task-list-inner .job-list-box .finish-job-list .job-item .opt .opt-line { margin: 6px 0; } -.page-sd .inner .task-list-box .finish-job-list .job-item .opt .opt-line ul { +.page-sd .inner .task-list-box .task-list-inner .job-list-box .finish-job-list .job-item .opt .opt-line ul { display: flex; flex-flow: row; } -.page-sd .inner .task-list-box .finish-job-list .job-item .opt .opt-line ul li { +.page-sd .inner .task-list-box .task-list-inner .job-list-box .finish-job-list .job-item .opt .opt-line ul li { margin-right: 6px; } -.page-sd .inner .task-list-box .finish-job-list .job-item .opt .opt-line ul li a { +.page-sd .inner .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; @@ -209,59 +226,58 @@ background-color: #4e5058; color: #fff; } -.page-sd .inner .task-list-box .finish-job-list .job-item .opt .opt-line ul li a:hover { +.page-sd .inner .task-list-box .task-list-inner .job-list-box .finish-job-list .job-item .opt .opt-line ul li a:hover { background-color: #6d6f78; } -.page-sd .inner .task-list-box .finish-job-list .job-item .opt .opt-line ul .show-prompt { +.page-sd .inner .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; } -.page-sd .inner .task-list-box .finish-job-list .job-item .remove { +.page-sd .inner .task-list-box .task-list-inner .job-list-box .finish-job-list .job-item .remove { display: none; position: absolute; right: 10px; top: 10px; } -.page-sd .inner .task-list-box .finish-job-list .job-item:hover .remove { +.page-sd .inner .task-list-box .task-list-inner .job-list-box .finish-job-list .job-item:hover .remove { display: block; } -.page-sd .inner .task-list-box .finish-job-list .animate:hover { +.page-sd .inner .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像素 */ } -.page-sd .inner .task-list-box .el-image { +.page-sd .inner .task-list-box .task-list-inner .job-list-box .el-image { width: 100%; height: 100%; overflow: visible; } -.page-sd .inner .task-list-box .el-image img { +.page-sd .inner .task-list-box .task-list-inner .job-list-box .el-image img { height: 240px; } -.page-sd .inner .task-list-box .el-image .el-image-viewer__wrapper img { +.page-sd .inner .task-list-box .task-list-inner .job-list-box .el-image .el-image-viewer__wrapper img { width: auto; height: auto; } -.page-sd .inner .task-list-box .el-image .image-slot { +.page-sd .inner .task-list-box .task-list-inner .job-list-box .el-image .image-slot { display: flex; flex-flow: column; justify-content: center; align-items: center; - height: 100%; min-height: 200px; color: #fff; height: 240px; } -.page-sd .inner .task-list-box .el-image .image-slot .iconfont { +.page-sd .inner .task-list-box .task-list-inner .job-list-box .el-image .image-slot .iconfont { font-size: 50px; margin-bottom: 10px; } -.page-sd .inner .task-list-box .el-image.upscale { +.page-sd .inner .task-list-box .task-list-inner .job-list-box .el-image.upscale { max-height: 310px; } -.page-sd .inner .task-list-box .el-image.upscale img { +.page-sd .inner .task-list-box .task-list-inner .job-list-box .el-image.upscale img { height: 310px; } -.page-sd .inner .task-list-box .el-image.upscale .el-image-viewer__wrapper img { +.page-sd .inner .task-list-box .task-list-inner .job-list-box .el-image.upscale .el-image-viewer__wrapper img { width: auto; height: auto; } diff --git a/web/src/assets/css/task-list.styl b/web/src/assets/css/task-list.styl index 9717c90b..7d046fa5 100644 --- a/web/src/assets/css/task-list.styl +++ b/web/src/assets/css/task-list.styl @@ -61,39 +61,63 @@ color #ffffff } - .img-uploader { - .el-upload { - border: 1px dashed var(--el-border-color); - border-radius: 6px; - cursor: pointer; - position: relative; - overflow: hidden; - width 300px; - 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-inline { display flex .img-uploader { - margin-right 10px + .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 + } + } } } + // 提交按钮 + .submit-btn { display flex margin: 20px 0 @@ -109,154 +133,159 @@ align-items center } } - } - .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 + .job-list-box { + .running-job-list { + .job-item { + //border: 1px solid #454545; + width: 100%; + padding 2px + background-color #555555 - span { - font-size 20px - color #ffffff + .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 + .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 + .opt { + .opt-line { + margin 6px 0 - ul { - display flex - flex-flow row + ul { + display flex + flex-flow row - li { - margin-right 6px + 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 + 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 + &:hover { + background-color #6D6F78 + } + } + } + + .show-prompt { + font-size 20px + cursor pointer } } } + } - .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 + } + } } - .remove { - display none - position absolute - right 10px - top 10px - } + .el-image.upscale { + max-height 310px - &:hover { - .remove { - display block + img { + height 310px } - } - } - - .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 - height 100% - min-height 200px - color #ffffff - height 240px - - .iconfont { - font-size 50px - margin-bottom 10px - } - } - } - - .el-image.upscale { - max-height 310px - - img { - height 310px - } - - .el-image-viewer__wrapper { - img { - width auto - height auto + .el-image-viewer__wrapper { + img { + width auto + height auto + } + } } } } diff --git a/web/src/views/ImageMj.vue b/web/src/views/ImageMj.vue index b8209755..72fb31e4 100644 --- a/web/src/views/ImageMj.vue +++ b/web/src/views/ImageMj.vue @@ -165,191 +165,241 @@
-

AI绘画

- - - -
图生图:以某张图片为底稿参考来创作绘画,生成类似风格或类型图像,支持 PNG 和 JPG 格式图片; -
-
- - - -
- -
- - - - - - -
- -
- - - -
- -
+
+ + + +
图生图:以某张图片为底稿参考来创作绘画,生成类似风格或类型图像,支持 PNG 和 JPG 格式图片; +
-
-
- 提示词: - - - + + + +
+ +
+
+
+
+ + +
+
-
- + + + + + +
+
+ +
+ + + +
+ +
+
+
+
+ 提示词: + + + + + +
+
+ + + + + 翻译 + + + + + + + + 翻译并重写 + + +
+
+
+ +
+ +
+ +
+
+
+ 不希望出现的内容:(可选) + + + + + +
+ 翻译 - - - - - - - 翻译并重写 - -
-
-
- -
- -
-
-
- 不希望出现的内容:(可选) - - - - - -
- - - - - 翻译 - +
+
+ -
- + +
请上传两张以上的图片,最多不超过五张,超过五张图片请使用文生图功能
+
+
+
+ + +
+ +
+ + + + +
+
+ + +
请上传两张有脸部的图片,用右边图片的脸替换左边图片的脸
+
+
+
+ + +
+ +
+ + + + + +
+
+ + +
+ 立即生成 +
+ 绘图可用额度:{{ imgCalls }}
- - - -
请上传两张以上的图片
-
- - - - - - - - - - - - - -
-
- - -
请上传两张有脸部的图片,用右边图片的脸替换左边图片的脸
-
- - - - - - - - - - - - - -
-
- - -
- 立即生成 -
- 绘图可用额度:{{ imgCalls }}
-
- + +
-

任务列表

-
- - - - - -
+ +
+
@@ -496,6 +504,7 @@ import Clipboard from "clipboard"; import {checkSession} from "@/action/session"; import {useRouter} from "vue-router"; import {getSessionId} from "@/store/session"; +import {removeArrayItem} from "@/utils/libs"; const listBoxHeight = ref(window.innerHeight - 40) const mjBoxHeight = ref(window.innerHeight - 150) @@ -553,10 +562,8 @@ const params = ref({ chaos: 0, stylize: 100, seed: 0, - raw: false, - img: "", - img2: "", img_arr: [], + raw: false, weight: 0.25, prompt: "", neg_prompt: "", @@ -564,6 +571,8 @@ const params = ref({ quality: 0 }) +const imgList = ref([]) + const activeName = ref('image') const runningJobs = ref([]) @@ -735,27 +744,7 @@ const uploadImg = (file) => { formData.append('file', result, result.name); // 执行上传操作 httpPost('/api/upload', formData).then((res) => { - params.value.img = res.data.url - ElMessage.success('上传成功') - }).catch((e) => { - ElMessage.error('上传失败:' + e.message) - }) - }, - error(err) { - console.log(err.message); - }, - }); -}; -const uploadImg2 = (file) => { - // 压缩图片并上传 - 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) => { - params.value.img2 = res.data.url + imgList.value.push(res.data.url) ElMessage.success('上传成功') }).catch((e) => { ElMessage.error('上传失败:' + e.message) @@ -766,6 +755,7 @@ const uploadImg2 = (file) => { }, }); }; + // 创建绘图任务 const promptRef = ref(null) const generate = () => { @@ -776,13 +766,11 @@ const generate = () => { if (params.value.model.indexOf("niji") !== -1 && params.value.raw) { return ElMessage.error("动漫模型不允许启用原始模式") } + if (imgList.value.length !== 2 && params.value.task_type === "swapFace") { + return ElMessage.error("换脸操作需要上传两张图片") + } params.value.session_id = getSessionId() - if (params.value.img !== "") { - params.value.img_arr.push(params.value.img) - } - if (params.value.img2 !== "") { - params.value.img_arr.push(params.value.img2) - } + params.value.img_arr = imgList.value httpPost("/api/mj/image", params.value).then(() => { ElMessage.success("绘画任务推送成功,请耐心等待任务执行...") imgCalls.value -= 1 @@ -855,6 +843,11 @@ const tabChange = (tab) => { params.value.task_type = tab } +// 删除已上传图片 +const removeUploadImage = (url) => { + imgList.value = removeArrayItem(imgList.value, url) +} +