mirror of
https://github.com/yangjian102621/geekai.git
synced 2025-09-17 16:56:38 +08:00
feat: support midjourney --cref and --sref for role consistency
This commit is contained in:
parent
56c225bf20
commit
3f1ad4b7dc
@ -1,7 +1,10 @@
|
|||||||
# 更新日志
|
# 更新日志
|
||||||
## 4.0.2
|
## 4.0.2
|
||||||
* 功能新增:支持前端菜单可以配置
|
* 功能新增:支持前端菜单可以配置
|
||||||
|
* 功能优化:在登录和注册界面标题显示软件版本号
|
||||||
|
* 功能优化:MJ 绘画支持 --sref 和 --cref 图片一致性参数
|
||||||
* 功能优化:手机端支持免登录预览功能
|
* 功能优化:手机端支持免登录预览功能
|
||||||
|
* Bug修复:解决因为图片上传使用相对路径而导致融图失败的问题。
|
||||||
* 功能新增:手机端支持 Stable-Diffusion 绘画
|
* 功能新增:手机端支持 Stable-Diffusion 绘画
|
||||||
* 功能新增:管理后台登录页面增加行为验证码,防止爆破
|
* 功能新增:管理后台登录页面增加行为验证码,防止爆破
|
||||||
|
|
||||||
|
@ -91,7 +91,7 @@ KEY。
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
另外,如果您目前还没有 OpenAI 的 API KEY的,推荐您去 https://gpt.bemore.lol 购买,**无需魔法,高速稳定,且价格还远低于 OpenAI
|
另外,如果您目前还没有 OpenAI 的 API KEY的,推荐您去 https://api.chat-plus.net 购买,**无需魔法,高速稳定,且价格还远低于 OpenAI
|
||||||
官方**。
|
官方**。
|
||||||
|
|
||||||
## 使用须知
|
## 使用须知
|
||||||
|
@ -25,6 +25,7 @@ type MjTask struct {
|
|||||||
Type TaskType `json:"type"`
|
Type TaskType `json:"type"`
|
||||||
UserId int `json:"user_id"`
|
UserId int `json:"user_id"`
|
||||||
Prompt string `json:"prompt,omitempty"`
|
Prompt string `json:"prompt,omitempty"`
|
||||||
|
Params string `json:"full_prompt"`
|
||||||
Index int `json:"index,omitempty"`
|
Index int `json:"index,omitempty"`
|
||||||
MessageId string `json:"message_id,omitempty"`
|
MessageId string `json:"message_id,omitempty"`
|
||||||
MessageHash string `json:"message_hash,omitempty"`
|
MessageHash string `json:"message_hash,omitempty"`
|
||||||
|
@ -98,7 +98,10 @@ func (h *MidJourneyHandler) Image(c *gin.Context) {
|
|||||||
ImgArr []string `json:"img_arr"`
|
ImgArr []string `json:"img_arr"`
|
||||||
Tile bool `json:"tile"`
|
Tile bool `json:"tile"`
|
||||||
Quality float32 `json:"quality"`
|
Quality float32 `json:"quality"`
|
||||||
Weight float32 `json:"weight"`
|
Iw float32 `json:"iw"`
|
||||||
|
CRef string `json:"cref"` //生成角色一致的图像
|
||||||
|
SRef string `json:"sref"` //生成风格一致的图像
|
||||||
|
Cw int `json:"cw"` // 参考程度
|
||||||
}
|
}
|
||||||
if err := c.ShouldBindJSON(&data); err != nil {
|
if err := c.ShouldBindJSON(&data); err != nil {
|
||||||
resp.ERROR(c, types.InvalidArgs)
|
resp.ERROR(c, types.InvalidArgs)
|
||||||
@ -108,41 +111,53 @@ func (h *MidJourneyHandler) Image(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var prompt = data.Prompt
|
var params = ""
|
||||||
if data.Rate != "" && !strings.Contains(prompt, "--ar") {
|
if data.Rate != "" && !strings.Contains(params, "--ar") {
|
||||||
prompt += " --ar " + data.Rate
|
params += " --ar " + data.Rate
|
||||||
}
|
}
|
||||||
if data.Seed > 0 && !strings.Contains(prompt, "--seed") {
|
if data.Seed > 0 && !strings.Contains(params, "--seed") {
|
||||||
prompt += fmt.Sprintf(" --seed %d", data.Seed)
|
params += fmt.Sprintf(" --seed %d", data.Seed)
|
||||||
}
|
}
|
||||||
if data.Stylize > 0 && !strings.Contains(prompt, "--s") && !strings.Contains(prompt, "--stylize") {
|
if data.Stylize > 0 && !strings.Contains(params, "--s") && !strings.Contains(params, "--stylize") {
|
||||||
prompt += fmt.Sprintf(" --s %d", data.Stylize)
|
params += fmt.Sprintf(" --s %d", data.Stylize)
|
||||||
}
|
}
|
||||||
if data.Chaos > 0 && !strings.Contains(prompt, "--c") && !strings.Contains(prompt, "--chaos") {
|
if data.Chaos > 0 && !strings.Contains(params, "--c") && !strings.Contains(params, "--chaos") {
|
||||||
prompt += fmt.Sprintf(" --c %d", data.Chaos)
|
params += fmt.Sprintf(" --c %d", data.Chaos)
|
||||||
}
|
}
|
||||||
if data.Weight > 0 {
|
if len(data.ImgArr) > 0 && data.Iw > 0 {
|
||||||
prompt += fmt.Sprintf(" --iw %f", data.Weight)
|
params += fmt.Sprintf(" --iw %f", data.Iw)
|
||||||
}
|
}
|
||||||
if data.Raw {
|
if data.Raw {
|
||||||
prompt += " --style raw"
|
params += " --style raw"
|
||||||
}
|
}
|
||||||
if data.Quality > 0 {
|
if data.Quality > 0 {
|
||||||
prompt += fmt.Sprintf(" --q %.2f", data.Quality)
|
params += fmt.Sprintf(" --q %.2f", data.Quality)
|
||||||
}
|
}
|
||||||
if data.NegPrompt != "" {
|
if data.NegPrompt != "" {
|
||||||
prompt += fmt.Sprintf(" --no %s", data.NegPrompt)
|
params += fmt.Sprintf(" --no %s", data.NegPrompt)
|
||||||
}
|
}
|
||||||
if data.Tile {
|
if data.Tile {
|
||||||
prompt += " --tile "
|
params += " --tile "
|
||||||
}
|
}
|
||||||
if data.Model != "" && !strings.Contains(prompt, "--v") && !strings.Contains(prompt, "--niji") {
|
if data.CRef != "" {
|
||||||
prompt += fmt.Sprintf(" %s", data.Model)
|
params += fmt.Sprintf(" --cref %s", data.CRef)
|
||||||
|
if data.Cw > 0 {
|
||||||
|
params += fmt.Sprintf(" --cw %d", data.Cw)
|
||||||
|
} else {
|
||||||
|
params += " --cw 100"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if data.SRef != "" {
|
||||||
|
params += fmt.Sprintf(" --sref %s", data.CRef)
|
||||||
|
}
|
||||||
|
if data.Model != "" && !strings.Contains(params, "--v") && !strings.Contains(params, "--niji") {
|
||||||
|
params += fmt.Sprintf(" %s", data.Model)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理融图和换脸的提示词
|
// 处理融图和换脸的提示词
|
||||||
if data.TaskType == types.TaskSwapFace.String() || data.TaskType == types.TaskBlend.String() {
|
if data.TaskType == types.TaskSwapFace.String() || data.TaskType == types.TaskBlend.String() {
|
||||||
prompt = fmt.Sprintf("%s:%s", data.TaskType, strings.Join(data.ImgArr, ","))
|
params = fmt.Sprintf("%s:%s", data.TaskType, strings.Join(data.ImgArr, ","))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果本地图片上传的是相对地址,处理成绝对地址
|
// 如果本地图片上传的是相对地址,处理成绝对地址
|
||||||
@ -165,7 +180,7 @@ func (h *MidJourneyHandler) Image(c *gin.Context) {
|
|||||||
UserId: userId,
|
UserId: userId,
|
||||||
TaskId: taskId,
|
TaskId: taskId,
|
||||||
Progress: 0,
|
Progress: 0,
|
||||||
Prompt: prompt,
|
Prompt: fmt.Sprintf("%s %s", data.Prompt, params),
|
||||||
Power: h.App.SysConfig.MjPower,
|
Power: h.App.SysConfig.MjPower,
|
||||||
CreatedAt: time.Now(),
|
CreatedAt: time.Now(),
|
||||||
}
|
}
|
||||||
@ -188,7 +203,8 @@ func (h *MidJourneyHandler) Image(c *gin.Context) {
|
|||||||
TaskId: taskId,
|
TaskId: taskId,
|
||||||
SessionId: data.SessionId,
|
SessionId: data.SessionId,
|
||||||
Type: types.TaskType(data.TaskType),
|
Type: types.TaskType(data.TaskType),
|
||||||
Prompt: prompt,
|
Prompt: data.Prompt,
|
||||||
|
Params: params,
|
||||||
UserId: userId,
|
UserId: userId,
|
||||||
ImgArr: data.ImgArr,
|
ImgArr: data.ImgArr,
|
||||||
})
|
})
|
||||||
|
@ -53,6 +53,10 @@ func (l *AppLifecycle) OnStop(context.Context) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewAppLifeCycle() *AppLifecycle {
|
||||||
|
return &AppLifecycle{}
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
configFile := os.Getenv("CONFIG_FILE")
|
configFile := os.Getenv("CONFIG_FILE")
|
||||||
if configFile == "" {
|
if configFile == "" {
|
||||||
@ -432,11 +436,14 @@ func main() {
|
|||||||
group.GET("list", h.List)
|
group.GET("list", h.List)
|
||||||
}),
|
}),
|
||||||
fx.Invoke(func(s *core.AppServer, db *gorm.DB) {
|
fx.Invoke(func(s *core.AppServer, db *gorm.DB) {
|
||||||
|
go func() {
|
||||||
err := s.Run(db)
|
err := s.Run(db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
}()
|
||||||
}),
|
}),
|
||||||
|
fx.Provide(NewAppLifeCycle),
|
||||||
// 注册生命周期回调函数
|
// 注册生命周期回调函数
|
||||||
fx.Invoke(func(lifecycle fx.Lifecycle, lc *AppLifecycle) {
|
fx.Invoke(func(lifecycle fx.Lifecycle, lc *AppLifecycle) {
|
||||||
lifecycle.Append(fx.Hook{
|
lifecycle.Append(fx.Hook{
|
||||||
|
@ -26,7 +26,7 @@ func (c *PlusClient) Imagine(task types.MjTask) (ImageRes, error) {
|
|||||||
apiURL := fmt.Sprintf("%s/mj-%s/mj/submit/imagine", c.apiURL, c.Config.Mode)
|
apiURL := fmt.Sprintf("%s/mj-%s/mj/submit/imagine", c.apiURL, c.Config.Mode)
|
||||||
body := ImageReq{
|
body := ImageReq{
|
||||||
BotType: "MID_JOURNEY",
|
BotType: "MID_JOURNEY",
|
||||||
Prompt: task.Prompt,
|
Prompt: fmt.Sprintf("%s %s", task.Prompt, task.Params),
|
||||||
Base64Array: make([]string, 0),
|
Base64Array: make([]string, 0),
|
||||||
}
|
}
|
||||||
// 生成图片 Base64 编码
|
// 生成图片 Base64 编码
|
||||||
|
@ -23,7 +23,7 @@ func NewProxyClient(config types.MjProxyConfig) *ProxyClient {
|
|||||||
func (c *ProxyClient) Imagine(task types.MjTask) (ImageRes, error) {
|
func (c *ProxyClient) Imagine(task types.MjTask) (ImageRes, error) {
|
||||||
apiURL := fmt.Sprintf("%s/mj/submit/imagine", c.apiURL)
|
apiURL := fmt.Sprintf("%s/mj/submit/imagine", c.apiURL)
|
||||||
body := ImageReq{
|
body := ImageReq{
|
||||||
Prompt: task.Prompt,
|
Prompt: fmt.Sprintf("%s %s", task.Prompt, task.Params),
|
||||||
Base64Array: make([]string, 0),
|
Base64Array: make([]string, 0),
|
||||||
}
|
}
|
||||||
// 生成图片 Base64 编码
|
// 生成图片 Base64 编码
|
||||||
@ -46,8 +46,6 @@ func (c *ProxyClient) Imagine(task types.MjTask) (ImageRes, error) {
|
|||||||
SetErrorResult(&errRes).
|
SetErrorResult(&errRes).
|
||||||
Post(apiURL)
|
Post(apiURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
all, err := io.ReadAll(r.Body)
|
|
||||||
logger.Info(string(all))
|
|
||||||
return ImageRes{}, fmt.Errorf("请求 API %s 出错:%v", apiURL, err)
|
return ImageRes{}, fmt.Errorf("请求 API %s 出错:%v", apiURL, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,7 +68,7 @@ func (s *Service) Run() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 如果是 mj-proxy 则自动翻译提示词
|
// 如果是 mj-proxy 则自动翻译提示词
|
||||||
if utils.HasChinese(task.Prompt) && strings.HasPrefix(s.Name, "mj-proxy-service") {
|
if utils.HasChinese(task.Prompt) {
|
||||||
content, err := utils.OpenAIRequest(s.db, fmt.Sprintf(service.TranslatePromptTemplate, task.Prompt))
|
content, err := utils.OpenAIRequest(s.db, fmt.Sprintf(service.TranslatePromptTemplate, task.Prompt))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
task.Prompt = content
|
task.Prompt = content
|
||||||
|
@ -168,7 +168,48 @@
|
|||||||
<div class="extra-params">
|
<div class="extra-params">
|
||||||
<el-form>
|
<el-form>
|
||||||
<el-tabs v-model="activeName" class="title-tabs" @tabChange="tabChange">
|
<el-tabs v-model="activeName" class="title-tabs" @tabChange="tabChange">
|
||||||
<el-tab-pane label="文生图(可选)" name="image">
|
<el-tab-pane label="文生图" name="txt2img">
|
||||||
|
<div class="prompt-box">
|
||||||
|
<div class="param-line pt">
|
||||||
|
<div class="flex-row justify-between items-center">
|
||||||
|
<div class="flex-row justify-start items-center">
|
||||||
|
<span>提示词:</span>
|
||||||
|
<el-tooltip effect="light" content="输入你想要的内容,用逗号分割" placement="right">
|
||||||
|
<el-icon>
|
||||||
|
<InfoFilled/>
|
||||||
|
</el-icon>
|
||||||
|
</el-tooltip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="param-line pt">
|
||||||
|
<el-input v-model="params.prompt" :autosize="{ minRows: 4, maxRows: 6 }" type="textarea"
|
||||||
|
ref="promptRef"
|
||||||
|
placeholder="请在此输入绘画提示词,系统会自动翻译中文提示词,高手请直接输入英文提示词"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="param-line pt">
|
||||||
|
<div class="flex-row justify-between items-center">
|
||||||
|
<div class="flex-row justify-start items-center">
|
||||||
|
<span>不希望出现的内容:(可选)</span>
|
||||||
|
<el-tooltip effect="light" content="不想出现在图片上的元素(例如:树,建筑)" placement="right">
|
||||||
|
<el-icon>
|
||||||
|
<InfoFilled/>
|
||||||
|
</el-icon>
|
||||||
|
</el-tooltip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="param-line pt">
|
||||||
|
<el-input v-model="params.neg_prompt" :autosize="{ minRows: 4, maxRows: 6 }" type="textarea"
|
||||||
|
ref="promptRef"
|
||||||
|
placeholder="请在此输入你不希望出现在图片上的内容,系统会自动翻译中文提示词"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane label="图生图" name="img2img">
|
||||||
<div class="text">图生图:以某张图片为底稿参考来创作绘画,生成类似风格或类型图像,支持 PNG 和 JPG 格式图片;
|
<div class="text">图生图:以某张图片为底稿参考来创作绘画,生成类似风格或类型图像,支持 PNG 和 JPG 格式图片;
|
||||||
</div>
|
</div>
|
||||||
<div class="param-line">
|
<div class="param-line">
|
||||||
@ -190,15 +231,15 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="param-line" style="padding-top: 10px">
|
<div class="param-line" style="padding-top: 10px">
|
||||||
<el-form-item label="图像权重:">
|
<el-form-item label="参考权重:">
|
||||||
<template #default>
|
<template #default>
|
||||||
<div class="form-item-inner">
|
<div class="form-item-inner">
|
||||||
<el-slider v-model.number="params.weight" :max="1" :step="0.01"
|
<el-slider v-model.number="params.iw" :max="1" :step="0.01"
|
||||||
style="width: 180px;--el-slider-main-bg-color:#47fff1"/>
|
style="width: 180px;--el-slider-main-bg-color:#47fff1"/>
|
||||||
<el-tooltip effect="light"
|
<el-tooltip effect="light"
|
||||||
content="使用图像权重参数--iw来调整图像 URL 与文本的重要性 <br/>权重较高时意味着图像提示将对完成的作业产生更大的影响"
|
content="使用图像权重参数--iw来调整图像 URL 与文本的重要性 <br/>权重较高时意味着图像提示将对完成的作业产生更大的影响"
|
||||||
raw-content placement="right">
|
raw-content placement="right">
|
||||||
<el-icon style="margin-top: 9px">
|
<el-icon>
|
||||||
<InfoFilled/>
|
<InfoFilled/>
|
||||||
</el-icon>
|
</el-icon>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
@ -248,7 +289,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
|
|
||||||
<el-tab-pane label="融图(可选)" name="blend">
|
<el-tab-pane label="融图" name="blend">
|
||||||
<div class="text">请上传两张以上的图片,最多不超过五张,超过五张图片请使用文生图功能</div>
|
<div class="text">请上传两张以上的图片,最多不超过五张,超过五张图片请使用文生图功能</div>
|
||||||
<div class="img-inline">
|
<div class="img-inline">
|
||||||
<div class="img-list-box">
|
<div class="img-list-box">
|
||||||
@ -267,7 +308,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
|
|
||||||
<el-tab-pane label="换脸(可选)" name="swapFace">
|
<el-tab-pane label="换脸" name="swapFace">
|
||||||
<div class="text">请上传两张有脸部的图片,用右边图片的脸替换左边图片的脸</div>
|
<div class="text">请上传两张有脸部的图片,用右边图片的脸替换左边图片的脸</div>
|
||||||
<div class="img-inline">
|
<div class="img-inline">
|
||||||
<div class="img-list-box">
|
<div class="img-list-box">
|
||||||
@ -285,6 +326,115 @@
|
|||||||
</el-upload>
|
</el-upload>
|
||||||
</div>
|
</div>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
|
|
||||||
|
<el-tab-pane name="cref">
|
||||||
|
<template #label>
|
||||||
|
<el-badge value="New">
|
||||||
|
<span>一致性</span>
|
||||||
|
</el-badge>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<div class="text">注意:只有于 niji6 和 v6 模型支持一致性功能,如果选择其他模型此功能将不起作用。</div>
|
||||||
|
<div class="param-line">
|
||||||
|
<el-form-item label="角色一致性:" prop="cref">
|
||||||
|
<el-input v-model="params.cref" placeholder="请输入图片URL或者上传图片"
|
||||||
|
style="--el-input-focus-border-color:#47fff1;--el-input-text-color:#ffffff; max-width: 500px; width: 100%"
|
||||||
|
size="small">
|
||||||
|
<template #append>
|
||||||
|
<el-upload
|
||||||
|
:auto-upload="true"
|
||||||
|
:show-file-list="false"
|
||||||
|
@click="beforeUpload('cref')"
|
||||||
|
:http-request="uploadImg"
|
||||||
|
>
|
||||||
|
<el-icon class="uploader-icon">
|
||||||
|
<UploadFilled/>
|
||||||
|
</el-icon>
|
||||||
|
</el-upload>
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="param-line">
|
||||||
|
<el-form-item label="风格一致性:" prop="sref">
|
||||||
|
<el-input v-model="params.sref" placeholder="请输入图片URL或者上传图片"
|
||||||
|
style="--el-input-focus-border-color:#47fff1; --el-input-text-color:#ffffff; max-width: 500px; width: 100%"
|
||||||
|
size="small">
|
||||||
|
<template #append>
|
||||||
|
<el-upload
|
||||||
|
:auto-upload="true"
|
||||||
|
:show-file-list="false"
|
||||||
|
@click="beforeUpload('sref')"
|
||||||
|
:http-request="uploadImg"
|
||||||
|
>
|
||||||
|
<el-icon class="uploader-icon">
|
||||||
|
<UploadFilled/>
|
||||||
|
</el-icon>
|
||||||
|
</el-upload>
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="param-line" style="padding-top: 10px">
|
||||||
|
<el-form-item label="参考权重:">
|
||||||
|
<template #default>
|
||||||
|
<div class="form-item-inner">
|
||||||
|
<el-slider v-model.number="params.cw" :max="100" :step="1"
|
||||||
|
style="width: 180px;--el-slider-main-bg-color:#47fff1"/>
|
||||||
|
<el-tooltip effect="light"
|
||||||
|
content="取值范围 0-100 <br/>默认值100参考原图的脸部、头发和衣服<br/>0则表示只换脸"
|
||||||
|
raw-content placement="right">
|
||||||
|
<el-icon>
|
||||||
|
<InfoFilled/>
|
||||||
|
</el-icon>
|
||||||
|
</el-tooltip>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="prompt-box">
|
||||||
|
<div class="param-line pt">
|
||||||
|
<div class="flex-row justify-between items-center">
|
||||||
|
<div class="flex-row justify-start items-center">
|
||||||
|
<span>提示词:</span>
|
||||||
|
<el-tooltip effect="light" content="输入你想要的内容,用逗号分割" placement="right">
|
||||||
|
<el-icon>
|
||||||
|
<InfoFilled/>
|
||||||
|
</el-icon>
|
||||||
|
</el-tooltip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="param-line pt">
|
||||||
|
<el-input v-model="params.prompt" :autosize="{ minRows: 4, maxRows: 6 }" type="textarea"
|
||||||
|
ref="promptRef"
|
||||||
|
placeholder="请在此输入绘画提示词,系统会自动翻译中文提示词,高手请直接输入英文提示词"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="param-line pt">
|
||||||
|
<div class="flex-row justify-between items-center">
|
||||||
|
<div class="flex-row justify-start items-center">
|
||||||
|
<span>不希望出现的内容:(可选)</span>
|
||||||
|
<el-tooltip effect="light" content="不想出现在图片上的元素(例如:树,建筑)" placement="right">
|
||||||
|
<el-icon>
|
||||||
|
<InfoFilled/>
|
||||||
|
</el-icon>
|
||||||
|
</el-tooltip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="param-line pt">
|
||||||
|
<el-input v-model="params.neg_prompt" :autosize="{ minRows: 4, maxRows: 6 }" type="textarea"
|
||||||
|
ref="promptRef"
|
||||||
|
placeholder="请在此输入你不希望出现在图片上的内容,系统会自动翻译中文提示词"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-tab-pane>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
|
|
||||||
<el-row class="text-info">
|
<el-row class="text-info">
|
||||||
@ -343,7 +493,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h2>创作记录</h2>
|
<h2>创作记录</h2>
|
||||||
<div class="finish-job-list" v-loading="loading" element-loading-background="rgba(255, 255, 255, 0.5)">
|
<div class="finish-job-list" v-loading="loading" element-loading-background="rgba(0, 0, 0, 0.5)">
|
||||||
<div v-if="finishedJobs.length > 0">
|
<div v-if="finishedJobs.length > 0">
|
||||||
<ItemList :items="finishedJobs" :width="240" :gap="16">
|
<ItemList :items="finishedJobs" :width="240" :gap="16">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
@ -508,7 +658,7 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import {nextTick, onMounted, onUnmounted, ref} from "vue"
|
import {nextTick, onMounted, onUnmounted, ref} from "vue"
|
||||||
import {ChromeFilled, Delete, DocumentCopy, InfoFilled, Picture, Plus} from "@element-plus/icons-vue";
|
import {ChromeFilled, Delete, DocumentCopy, InfoFilled, Picture, Plus, UploadFilled} from "@element-plus/icons-vue";
|
||||||
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";
|
||||||
@ -517,7 +667,7 @@ import Clipboard from "clipboard";
|
|||||||
import {checkSession} from "@/action/session";
|
import {checkSession} from "@/action/session";
|
||||||
import {useRouter} from "vue-router";
|
import {useRouter} from "vue-router";
|
||||||
import {getSessionId} from "@/store/session";
|
import {getSessionId} from "@/store/session";
|
||||||
import {removeArrayItem} from "@/utils/libs";
|
import {copyObj, removeArrayItem} from "@/utils/libs";
|
||||||
import LoginDialog from "@/components/LoginDialog.vue";
|
import LoginDialog from "@/components/LoginDialog.vue";
|
||||||
|
|
||||||
const listBoxHeight = ref(window.innerHeight - 40)
|
const listBoxHeight = ref(window.innerHeight - 40)
|
||||||
@ -545,11 +695,12 @@ const models = [
|
|||||||
{text: "优质模式MJ-5.1", value: " --v 5.1", img: "/images/mj/mj-v5.1.jpg"},
|
{text: "优质模式MJ-5.1", value: " --v 5.1", img: "/images/mj/mj-v5.1.jpg"},
|
||||||
{text: "虚幻模式MJ-5", value: " --v 5", img: "/images/mj/mj-v5.jpg"},
|
{text: "虚幻模式MJ-5", value: " --v 5", img: "/images/mj/mj-v5.jpg"},
|
||||||
{text: "真实模式MJ-4", value: " --v 4", img: "/images/mj/mj-v4.jpg"},
|
{text: "真实模式MJ-4", value: " --v 4", img: "/images/mj/mj-v4.jpg"},
|
||||||
{text: "动漫风niji5 原始", value: " --niji 5", img: "/images/mj/mj-niji.png"},
|
{text: "动漫风-niji4", value: " --niji 4", img: "/images/mj/nj4.jpg"},
|
||||||
{text: "动漫风niji5 可爱", value: " --niji 5 --style cute", img: "/images/mj/nj1.jpg"},
|
{text: "动漫风-niji5", value: " --niji 5", img: "/images/mj/mj-niji.png"},
|
||||||
{text: "动漫风niji5 风景", value: " --niji 5 --style scenic", img: "/images/mj/nj2.jpg"},
|
{text: "动漫风-niji5 可爱", value: " --niji 5 --style cute", img: "/images/mj/nj1.jpg"},
|
||||||
{text: "动漫风niji5 表现力", value: " --niji 5 --style expressive", img: "/images/mj/nj3.jpg"},
|
{text: "动漫风-niji5 风景", value: " --niji 5 --style scenic", img: "/images/mj/nj2.jpg"},
|
||||||
{text: "动漫风niji4", value: " --niji 4", img: "/images/mj/nj4.jpg"},
|
{text: "动漫风-niji6", value: " --niji 6", img: "/images/mj/nj3.jpg"},
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
const options = [
|
const options = [
|
||||||
@ -581,17 +732,20 @@ const initParams = {
|
|||||||
seed: 0,
|
seed: 0,
|
||||||
img_arr: [],
|
img_arr: [],
|
||||||
raw: false,
|
raw: false,
|
||||||
weight: 0.25,
|
iw: 0,
|
||||||
prompt: router.currentRoute.value.params["prompt"] ?? "",
|
prompt: router.currentRoute.value.params["prompt"] ?? "",
|
||||||
neg_prompt: "",
|
neg_prompt: "",
|
||||||
tile: false,
|
tile: false,
|
||||||
quality: 0
|
quality: 0,
|
||||||
|
cref: "",
|
||||||
|
sref: "",
|
||||||
|
cw: 0,
|
||||||
}
|
}
|
||||||
const params = ref(initParams)
|
const params = ref(copyObj(initParams))
|
||||||
|
|
||||||
const imgList = ref([])
|
const imgList = ref([])
|
||||||
|
|
||||||
const activeName = ref('image')
|
const activeName = ref('txt2img')
|
||||||
|
|
||||||
const runningJobs = ref([])
|
const runningJobs = ref([])
|
||||||
const finishedJobs = ref([])
|
const finishedJobs = ref([])
|
||||||
@ -780,6 +934,11 @@ const changeModel = (item) => {
|
|||||||
params.value.model = item.value
|
params.value.model = item.value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const imgKey = ref("")
|
||||||
|
const beforeUpload = (key) => {
|
||||||
|
imgKey.value = key
|
||||||
|
}
|
||||||
|
|
||||||
// 图片上传
|
// 图片上传
|
||||||
const uploadImg = (file) => {
|
const uploadImg = (file) => {
|
||||||
if (!isLogin.value) {
|
if (!isLogin.value) {
|
||||||
@ -795,7 +954,12 @@ const uploadImg = (file) => {
|
|||||||
formData.append('file', result, result.name);
|
formData.append('file', result, result.name);
|
||||||
// 执行上传操作
|
// 执行上传操作
|
||||||
httpPost('/api/upload', formData).then((res) => {
|
httpPost('/api/upload', formData).then((res) => {
|
||||||
|
if (imgKey.value === '') {
|
||||||
imgList.value.push(res.data.url)
|
imgList.value.push(res.data.url)
|
||||||
|
} else { // 单张图片上传
|
||||||
|
params.value[imgKey.value] = res.data.url
|
||||||
|
imgKey.value = ''
|
||||||
|
}
|
||||||
ElMessage.success('上传成功')
|
ElMessage.success('上传成功')
|
||||||
}).catch((e) => {
|
}).catch((e) => {
|
||||||
ElMessage.error('上传失败:' + e.message)
|
ElMessage.error('上传失败:' + e.message)
|
||||||
@ -830,7 +994,8 @@ const generate = () => {
|
|||||||
httpPost("/api/mj/image", params.value).then(() => {
|
httpPost("/api/mj/image", params.value).then(() => {
|
||||||
ElMessage.success("绘画任务推送成功,请耐心等待任务执行...")
|
ElMessage.success("绘画任务推送成功,请耐心等待任务执行...")
|
||||||
power.value -= mjPower.value
|
power.value -= mjPower.value
|
||||||
params.value = initParams
|
params.value = copyObj(initParams)
|
||||||
|
imgList.value = []
|
||||||
}).catch(e => {
|
}).catch(e => {
|
||||||
ElMessage.error("任务推送失败:" + e.message)
|
ElMessage.error("任务推送失败:" + e.message)
|
||||||
})
|
})
|
||||||
@ -897,7 +1062,11 @@ const publishImage = (item, action) => {
|
|||||||
|
|
||||||
// 切换菜单
|
// 切换菜单
|
||||||
const tabChange = (tab) => {
|
const tabChange = (tab) => {
|
||||||
|
if (tab === "txt2img" || tab === "img2img" || tab === "cref") {
|
||||||
|
params.value.task_type = "image"
|
||||||
|
} else {
|
||||||
params.value.task_type = tab
|
params.value.task_type = tab
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除已上传图片
|
// 删除已上传图片
|
||||||
|
@ -222,7 +222,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="param-line" v-loading="translating" element-loading-background="rgba(122, 122, 122, 0.8)">
|
<div class="param-line" v-loading="translating" element-loading-background="rgba(0, 0, 0, 0.5)">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="params.prompt"
|
v-model="params.prompt"
|
||||||
:autosize="{ minRows: 4, maxRows: 6 }"
|
:autosize="{ minRows: 4, maxRows: 6 }"
|
||||||
|
Loading…
Reference in New Issue
Block a user