feat: auto translate and rewrite prompt for midjourney and stable-diffusion

This commit is contained in:
RockYang
2024-03-27 13:45:52 +08:00
parent 342b76f666
commit b5947545cb
18 changed files with 162 additions and 355 deletions

View File

@@ -244,7 +244,7 @@
</template>
<script setup>
import {nextTick, onMounted, ref} from 'vue'
import {nextTick, onMounted, onUnmounted, ref} from 'vue'
import ChatPrompt from "@/components/ChatPrompt.vue";
import ChatReply from "@/components/ChatReply.vue";
import {
@@ -339,6 +339,10 @@ onMounted(() => {
window.onresize = () => resizeElement();
});
onUnmounted(() => {
socket.value = null
})
// 初始化数据
const initData = () => {
// 检查会话
@@ -699,12 +703,11 @@ const connect = function (chat_id, role_id) {
});
_socket.addEventListener('close', () => {
if (activelyClose.value) { // 忽略主动关闭
if (activelyClose.value || socket.value === null) { // 忽略主动关闭
return;
}
// 停止发送消息
disableInput(true)
socket.value = null;
loading.value = true;
checkSession().then(() => {
connect(chat_id, role_id)

View File

@@ -218,36 +218,13 @@
</el-icon>
</el-tooltip>
</div>
<div>
<el-button type="primary" @click="translatePrompt(false)" :disabled="translating">
<el-icon style="margin-right: 6px;font-size: 18px;">
<Refresh/>
</el-icon>
翻译
</el-button>
<el-tooltip
class="box-item"
effect="light"
raw-content
content="使用 AI 翻译并重写提示词,<br/>增加更多细节,风格等描述"
placement="top-end"
>
<el-button type="success" @click="rewritePrompt" :disabled="translating">
<el-icon style="margin-right: 6px;font-size: 18px;">
<Refresh/>
</el-icon>
翻译并重写
</el-button>
</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="这里输入你的英文咒语例如A chinese girl walking in the middle of a cobblestone street"/>
placeholder="请在此输入绘画提示词,系统会自动翻译中文提示词,高手请直接输入英文提示词"/>
</div>
<div class="param-line pt">
@@ -260,19 +237,13 @@
</el-icon>
</el-tooltip>
</div>
<el-button type="primary" @click="translatePrompt(true)" :disabled="translating">
<el-icon style="margin-right: 6px;font-size: 18px;">
<Refresh/>
</el-icon>
翻译
</el-button>
</div>
</div>
<div class="param-line pt">
<el-input v-model="params.neg_prompt" :autosize="{ minRows: 4, maxRows: 6 }" type="textarea"
ref="promptRef"
placeholder="这里输入你不希望出现在图片上的内容,元素"/>
placeholder="请在此输入你不希望出现在图片上的内容,系统会自动翻译中文提示词"/>
</div>
</div>
</el-tab-pane>
@@ -471,7 +442,7 @@
<script setup>
import {nextTick, onMounted, onUnmounted, ref} from "vue"
import {ChromeFilled, Delete, DocumentCopy, InfoFilled, Picture, Plus, Refresh} from "@element-plus/icons-vue";
import {ChromeFilled, Delete, DocumentCopy, InfoFilled, Picture, Plus} from "@element-plus/icons-vue";
import Compressor from "compressorjs";
import {httpGet, httpPost} from "@/utils/http";
import {ElMessage, ElMessageBox, ElNotification} from "element-plus";
@@ -560,50 +531,9 @@ const finishedJobs = ref([])
const socket = ref(null)
const power = ref(0)
const translating = ref(false)
const userId = ref(0)
const isLogin = ref(false)
const rewritePrompt = () => {
if (!isLogin.value) {
showLoginDialog.value = true
return
}
translating.value = true
httpPost("/api/prompt/rewrite", {"prompt": params.value.prompt}).then(res => {
params.value.prompt = res.data
translating.value = false
}).catch(e => {
translating.value = false
ElMessage.error("翻译失败:" + e.message)
})
}
const translatePrompt = (negative) => {
if (!isLogin.value) {
showLoginDialog.value = true
return
}
translating.value = true
let prompt = params.value.prompt
if (negative) {
prompt = params.value.neg_prompt
}
httpPost("/api/prompt/translate", {"prompt": prompt}).then(res => {
if (negative) {
params.value.neg_prompt = res.data
} else {
params.value.prompt = res.data
}
translating.value = false
}).catch(e => {
translating.value = false
ElMessage.error("翻译失败:" + e.message)
})
}
const heartbeatHandle = ref(null)
const connect = () => {
let host = process.env.VUE_APP_WS_HOST
@@ -646,7 +576,9 @@ const connect = () => {
});
_socket.addEventListener('close', () => {
connect()
if (socket.value !== null) {
connect()
}
});
}
@@ -663,6 +595,10 @@ onMounted(() => {
})
})
onUnmounted(() => {
socket.value = null
})
// 初始化数据
const initData = () => {
checkSession().then(user => {

View File

@@ -117,26 +117,6 @@
</el-form-item>
</div>
<div class="param-line">
<el-form-item label="面部修复">
<template #default>
<div class="form-item-inner">
<el-switch v-model="params.face_fix" style="--el-switch-on-color: #47fff1;"/>
<el-tooltip
effect="light"
content="仅对绘制人物图像有效果。"
raw-content
placement="right"
>
<el-icon style="margin-top: 6px">
<InfoFilled/>
</el-icon>
</el-tooltip>
</div>
</template>
</el-form-item>
</div>
<div class="param-line">
<el-form-item label="高清修复">
<template #default>
@@ -248,34 +228,10 @@
:autosize="{ minRows: 4, maxRows: 6 }"
type="textarea"
ref="promptRef"
placeholder="正向提示词例如A chinese girl walking in the middle of a cobblestone street"
placeholder="请在此输入绘画提示词,系统会自动翻译中文提示词,高手请直接输入英文提示词"
/>
</div>
<div style="padding: 10px">
<el-button type="primary" @click="translatePrompt" size="small">
<el-icon style="margin-right: 6px;font-size: 18px;">
<Refresh/>
</el-icon>
翻译
</el-button>
<el-tooltip
class="box-item"
effect="dark"
raw-content
content="使用 AI 翻译并重写提示词,<br/>增加更多细节,风格等描述"
placement="top-end"
>
<el-button type="success" @click="rewritePrompt" size="small">
<el-icon style="margin-right: 6px;font-size: 18px;">
<Refresh/>
</el-icon>
翻译并重写
</el-button>
</el-tooltip>
</div>
<div class="param-line pt">
<span>反向提示词</span>
<el-tooltip
@@ -516,7 +472,7 @@
</el-dialog>
</div>
<login-dialog :show="showLoginDialog" @hide="showLoginDialog = false" @success="initData"/>
</div>
</template>
@@ -553,14 +509,13 @@ const params = ref({
height: 1024,
sampler: samplers[0],
seed: -1,
steps: 30,
steps: 20,
cfg_scale: 7,
face_fix: false,
hd_fix: false,
hd_redraw_rate: 0.5,
hd_redraw_rate: 0.7,
hd_scale: 2,
hd_scale_alg: scaleAlg[0],
hd_steps: 15,
hd_steps: 0,
prompt: "",
negative_prompt: "nsfw, paintings,low quality,easynegative,ng_deepnegative ,lowres,bad anatomy,bad hands,bad feet",
})
@@ -574,38 +529,7 @@ if (_params) {
params.value = JSON.parse(_params)
}
const power = ref(0)
const rewritePrompt = () => {
if (!isLogin.value) {
showLoginDialog.value = true
return
}
translating.value = true
httpPost("/api/prompt/rewrite", {"prompt": params.value.prompt}).then(res => {
params.value.prompt = res.data
translating.value = false
}).catch(e => {
translating.value = false
ElMessage.error("翻译失败:" + e.message)
})
}
const translatePrompt = () => {
if (!isLogin.value) {
showLoginDialog.value = true
return
}
translating.value = true
httpPost("/api/prompt/translate", {"prompt": params.value.prompt}).then(res => {
params.value.prompt = res.data
translating.value = false
}).catch(e => {
translating.value = false
ElMessage.error("翻译失败:" + e.message)
})
}
const sdPower = ref(0) // 画一张 SD 图片消耗算力
const socket = ref(null)
const userId = ref(0)
@@ -651,7 +575,9 @@ const connect = () => {
});
_socket.addEventListener('close', () => {
connect()
if (socket.value !== null) {
connect()
}
});
}
@@ -666,10 +592,17 @@ onMounted(() => {
clipboard.value.on('error', () => {
ElMessage.error('复制失败!');
})
httpGet("/api/config/get?key=system").then(res => {
sdPower.value = res.data["sd_power"]
}).catch(e => {
ElMessage.error("获取系统配置失败:" + e.message)
})
})
onUnmounted(() => {
clipboard.value.destroy()
socket.value = null
})
@@ -699,7 +632,7 @@ const fetchRunningJobs = (userId) => {
message: `任务ID${jobs[i]['task_id']}<br />原因:${jobs[i]['err_msg']}`,
type: 'error',
})
power.value += 1
power.value += sdPower.value
continue
}
_jobs.push(jobs[i])
@@ -761,7 +694,7 @@ const generate = () => {
params.value.session_id = getSessionId()
httpPost("/api/sd/image", params.value).then(() => {
ElMessage.success("绘画任务推送成功,请耐心等待任务执行...")
power.value -= 1
power.value -= sdPower.value
}).catch(e => {
ElMessage.error("任务推送失败:" + e.message)
})

View File

@@ -103,7 +103,7 @@
</template>
<script setup>
import {nextTick, onMounted, ref} from "vue";
import {nextTick, onMounted, onUnmounted, ref} from "vue";
import {showImagePreview, showNotify, showToast} from "vant";
import {onBeforeRouteLeave, useRouter} from "vue-router";
import {dateFormat, processContent, randString, renderInputText, UUID} from "@/utils/libs";
@@ -147,6 +147,10 @@ onMounted(() => {
})
})
onUnmounted(() => {
socket.value = null
})
const chatData = ref([])
const loading = ref(false)
const finished = ref(false)
@@ -347,12 +351,11 @@ const connect = function (chat_id, role_id) {
});
_socket.addEventListener('close', () => {
if (activelyClose.value) { // 忽略主动关闭
if (activelyClose.value || socket.value === null) { // 忽略主动关闭
return;
}
// 停止发送消息
canSend.value = true;
socket.value = null;
// 重连
checkSession().then(() => {
connect(chat_id, role_id)

View File

@@ -67,13 +67,7 @@
label="提示词"
autosize
type="textarea"
placeholder="如:一个美丽的中国女孩站在电影院门口,手上拿着爆米花,微笑,写实风格,电影灯光效果,半身像">
<template #button>
<van-button v-if="translating" disabled loading type="primary"/>
<van-button v-else size="small" type="primary" @click="translatePrompt">翻译</van-button>
</template>
</van-field>
placeholder="请在此输入绘画提示词,系统会自动翻译中文提示词,高手请直接输入英文提示词"/>
</div>
<van-collapse v-model="activeColspan">
@@ -206,7 +200,7 @@
</template>
<script setup>
import {nextTick, onMounted, ref} from "vue";
import {nextTick, onMounted, onUnmounted, ref} from "vue";
import {
showConfirmDialog,
showFailToast,
@@ -221,9 +215,8 @@ import Compressor from "compressorjs";
import {ElMessage} from "element-plus";
import {getSessionId} from "@/store/session";
import {checkSession} from "@/action/session";
import Clipboard from "clipboard";
import {useRouter} from "vue-router";
import {Delete, Picture} from "@element-plus/icons-vue";
import {Delete} from "@element-plus/icons-vue";
const title = ref('MidJourney 绘画')
const activeColspan = ref([""])
@@ -281,6 +274,10 @@ onMounted(() => {
});
})
onUnmounted(() => {
socket.value = null
})
const heartbeatHandle = ref(null)
const connect = () => {
let host = process.env.VUE_APP_WS_HOST
@@ -315,13 +312,15 @@ const connect = () => {
_socket.addEventListener('message', event => {
if (event.data instanceof Blob) {
fetchRunningJobs(userId.value)
fetchFinishJobs(userId.value)
fetchRunningJobs()
fetchFinishJobs(1)
}
});
_socket.addEventListener('close', () => {
connect()
if (socket.value !== null) {
connect()
}
});
}
@@ -512,24 +511,6 @@ const showPrompt = (item) => {
const imageView = (item) => {
showImagePreview([item['img_url']]);
}
const translating = ref(false)
const translatePrompt = () => {
if (params.value.prompt === '') {
return showToast("请输入中文提示词!")
}
translating.value = true
const prompt = params.value.prompt
httpPost("/api/prompt/translate", {"prompt": prompt}).then(res => {
params.value.prompt = res.data
translating.value = false
}).catch(e => {
translating.value = false
showFailToast("翻译失败:" + e.message)
})
}
</script>
<style lang="stylus">