Add feature: Batch operation #58

Former-commit-id: 792aa661ff4e089944a552909a093268fd0f76f2
This commit is contained in:
Physton
2023-05-28 22:31:13 +08:00
parent af6627d538
commit ecbf81c9e4
11 changed files with 1210 additions and 12 deletions

View File

@@ -91,6 +91,10 @@ the UI interfaces of other countries are displayed in English. and the translati
![](https://raw.githubusercontent.com/Physton/sd-webui-prompt-all-in-one-assets/main/images/demo.prompt_format.gif)
- Batch operation / *批量操作*
![](https://raw.githubusercontent.com/Physton/sd-webui-prompt-all-in-one-assets/main/images/demo.batch_operation.gif)
- Custom Theme / Extension styles / *自定义主题/扩展风格*
![](https://raw.githubusercontent.com/Physton/sd-webui-prompt-all-in-one-assets/main/images/demo.custom_theme.gif)

View File

@@ -1 +1 @@
0b686e9244451b855dd8a6b719b2a2d6a16b3940
8e33ccb55b5e8dcd68b5dd6b7f593719c69d0526

View File

@@ -1 +1 @@
6fb84a2d581529f45296b396531085a528fd15f6
54f604e47456799e8881c08bb0c4c1ae15af9fdc

View File

@@ -1 +1 @@
d4978bd9ec94c09075906f6454c76429c0eeaeaf
5cc0da2c0ffd50a46bbcfa80b6ca3fe5cb88c9c2

View File

@@ -1 +1 @@
51b407f391734ad99a88a7f29abe359c0528455a
b302541632aad8707d8cf6c6faff352c6270089c

View File

@@ -0,0 +1,177 @@
export default {
data() {
return {
// 鼠标框选功能
dropStartX: 0,
dropStartY: 0,
dropEndX: 0,
dropEndY: 0,
dropOffsetX: 0,
dropOffsetY: 0,
dropIsSelecting: false,
dropIsStart: false,
dropIsEnd: false,
dropArea: {
top: 0,
left: 0,
width: 0,
height: 0,
},
dropTags: [],
dropTimeId: 0,
}
},
methods: {
_dropOver() {
this.dropIsSelecting = false
this.dropIsStart = false
this.dropIsEnd = false
this.dropTags = []
for (let i = 0; i < this.$refs.promptTagsList.children.length; i++) {
let tag = this.$refs.promptTagsList.children[i]
if (tag.style.display === 'none') {
// 删除display:none属性
tag.style.display = ''
}
tag.classList.remove('drop-selected')
}
},
onDropMouseDown(e) {
if (this.droping) return
this._dropOver()
this.dropOffsetX = e.clientX - e.layerX
this.dropOffsetY = e.clientY - e.layerY
this.dropStartX = e.clientX - this.dropOffsetX
this.dropStartY = e.clientY - this.dropOffsetY
this.dropEndX = e.clientX - this.dropOffsetX
this.dropEndY = e.clientY - this.dropOffsetY
this.dropIsStart = true
},
onDropMouseMove(e) {
if (this.dropIsStart) {
this.dropIsSelecting = true
this.dropEndX = e.clientX - this.dropOffsetX
this.dropEndY = e.clientY - this.dropOffsetY
let left = Math.min(this.dropStartX, this.dropEndX)
let top = Math.min(this.dropStartY, this.dropEndY)
let width = Math.abs(this.dropStartX - this.dropEndX)
let height = Math.abs(this.dropStartY - this.dropEndY)
// 设置不超过 this.$refs.promptTags 范围
left = Math.max(left, 0)
top = Math.max(top, 0)
width = Math.min(width, this.$refs.promptTags.clientWidth - left)
height = Math.min(height, this.$refs.promptTags.clientHeight - top)
this.dropArea.top = top
this.dropArea.left = left
this.dropArea.width = width
this.dropArea.height = height
if (this.dropTimeId) clearTimeout(this.dropTimeId)
this.dropTimeId = setTimeout(this.dropSelectItems, 10)
}
},
dropSelectItems() {
if (this.dropTimeId) clearTimeout(this.dropTimeId)
let selectIds = []
for (let i = 0; i < this.$refs.promptTagsList.children.length; i++) {
let tag = this.$refs.promptTagsList.children[i]
if (!tag.classList.contains('prompt-tag')) continue
let tagLeft = tag.offsetLeft
let tagTop = tag.offsetTop
let tagWidth = tag.clientWidth
let tagHeight = tag.clientHeight
let tagRight = tagLeft + tagWidth
let tagBottom = tagTop + tagHeight
let isSelect = !(tagRight < this.dropArea.left || tagBottom < this.dropArea.top || tagLeft > this.dropArea.left + this.dropArea.width || tagTop > this.dropArea.top + this.dropArea.height)
if (isSelect) {
selectIds.push(tag.getAttribute('data-id'))
tag.classList.add('drop-selected')
} else {
tag.classList.remove('drop-selected')
}
this.dropTags = selectIds
}
},
onDropMouseUp(e) {
this.dropIsSelecting = false
this.dropIsStart = false
this.dropIsEnd = true
this.$refs.dropSelectBtns.style.left = this.$refs.dropSelectBox.style.left
this.$refs.dropSelectBtns.style.top = this.$refs.dropSelectBox.style.top
},
_getDropTags() {
let tags = []
this.dropTags.forEach(id => {
let tag = this.tags.find(tag => tag.id === id)
if (!tag) return
tags.push(tag)
})
return tags
},
_getDropIndexes() {
let indexes = []
this.dropTags.forEach(id => {
let index = this.tags.findIndex(tag => tag.id === id)
if (index === -1) return
indexes.push(index)
})
return indexes
},
_getDropTagsEle() {
let elements = []
this.dropTags.forEach(id => {
let tag = this.$refs.promptTagsList.querySelector(`.prompt-tag[data-id="${id}"]`)
if (!tag) return
elements.push(tag)
})
return elements
},
onDropCopy() {
let tags = this._getDropTags()
this._dropOver()
let prompt = this.genPrompt(tags, true)
this.copy(prompt)
},
onDropFavorite() {
let tags = this._getDropTags()
this._dropOver()
let prompt = this.genPrompt(tags, true)
this.gradioAPI.pushFavorite(this.favoriteKey, tags, prompt, '').then(res => {
if (res) {
this.$toastr.success(this.getLang('success'))
this.$emit('refreshFavorites', this.favoriteKey)
} else {
this.$toastr.error(this.getLang('failed'))
}
}).catch(error => {
this.$toastr.error(this.getLang('failed'))
})
},
onDropDisable() {
let tags = this._getDropTags()
this._dropOver()
tags.forEach(tag => {
tag.disabled = true
})
this.updateTags()
},
onDropEnable() {
let tags = this._getDropTags()
this._dropOver()
tags.forEach(tag => {
tag.disabled = false
})
this.updateTags()
},
onDropDelete() {
let indexes = this._getDropIndexes()
this._dropOver()
indexes.sort((a, b) => b - a)
indexes.forEach(index => {
this.tags.splice(index, 1)
})
this.updateTags()
},
}
}

View File

@@ -0,0 +1,510 @@
import common from "@/utils/common";
export default {
data() {
return {
autocompleteResults: null,
showAppendList: false,
appendListStyle: {
top: 0,
left: 0,
},
appendListSelected: null,
appendListChildSelected: null,
appendList: [
{
"type": "wrap",
"name": "line_break_character",
"icon": "wrap",
"children": []
},
/*{
"type": "lora",
"name": "Lora",
"children": []
},*/
/*{
"type": "favorite",
"name": "favorite",
"icon": "favorite",
"children": []
},
{
"type": "history",
"name": "history",
"icon": "history",
"children": []
}*/
],
}
},
computed: {
appendListChildItemTags() {
if (this.appendListSelected === null) return []
if (this.appendListChildSelected === null) return []
if (this.appendList[this.appendListSelected].type !== 'favorite' && this.appendList[this.appendListSelected].type !== 'history') return []
return this.appendList[this.appendListSelected].children[this.appendListChildSelected].tags
}
},
mounted() {
let temp = [
{
'name': 'txt2img',
'type': 'prompt',
'key': 'txt2img',
'neg': false,
},
{
'name': 'txt2img',
'type': 'negative_prompt',
'key': 'txt2img_neg',
'neg': true,
},
{
'name': 'img2img',
'type': 'prompt',
'key': 'img2img',
'neg': false,
},
{
'name': 'img2img',
'type': 'negative_prompt',
'key': 'img2img_neg',
'neg': true,
},
]
/*for (let i = 0; i < temp.length; i++) {
if (temp[i].key === this.favoriteKey) {
// 排到第一位
let item = temp[i]
temp.splice(i, 1)
temp.unshift(item)
break
}
}*/
temp.forEach(item => {
if (item.neg !== this.neg) return
this.appendList.push({
'type': "favorite",
'name': ["favorite", item.name/*, item.type*/],
"icon": "favorite",
"key": item.key,
'dataKey': 'favorite.' + item.key,
"children": [],
})
})
/*temp.forEach(item => {
this.appendList.push({
'type': "history",
'name': ["history", item.name, item.type],
"icon": "history",
"key": item.key,
'dataKey': 'history.' + item.key,
"children": [],
})
})*/
},
methods: {
onUnfoldClick() {
if (this.hidePanel) {
this.$nextTick(() => {
this.onResize()
})
}
this.$emit("update:hidePanel", !this.hidePanel)
},
onTranslatesToLocalClick() {
if (this.tags.length === 0) return // 没有关键词需要翻译
if (this.loading['all_local']) {
// 正在翻译中,取消翻译
this.cancelMultiTranslate = true
this.loading['all_local'] = false
return
}
this.loading['all_local'] = true
let tagIndexes = []
for (const index in this.tags) {
if (this.tags[index].type && this.tags[index].type !== 'text') continue
tagIndexes.push(index)
}
return this.translates(tagIndexes, true, true).finally(() => {
this.loading['all_local'] = false
this.updateTags()
})
},
onTranslatesToEnglishClick() {
if (this.tags.length === 0) return // 没有关键词需要翻译
if (this.loading['all_en']) {
// 正在翻译中,取消翻译
this.cancelMultiTranslate = true
this.loading['all_en'] = false
return
}
this.loading['all_en'] = true
let tagIndexes = []
for (const index in this.tags) {
if (this.tags[index].type && this.tags[index].type !== 'text') continue
tagIndexes.push(index)
}
this.translates(tagIndexes, false, true).finally(() => {
this.loading['all_en'] = false
this.updateTags()
})
},
onCopyAllTagsClick() {
this.copy(this.prompt)
},
onDeleteAllTagsClick() {
if (!confirm(this.getLang('delete_all_keywords_confirm'))) return
this.tags = []
this.updateTags()
},
appendListItemName(item) {
let names = []
if (typeof item.name === "object") {
for (let name of item.name) {
names.push(this.getLang(name))
}
} else {
names = [this.getLang(item.name)]
}
return names.join(' / ')
},
onAppendTagFocus(e) {
if (e.target.value === '' || e.target.value.trim() === '') {
this.appendListStyle = {
top: e.target.offsetTop + e.target.offsetHeight + 'px',
left: e.target.offsetLeft + 'px',
}
this.appendListSelected = null
this.appendListChildSelected = null
this.showAppendList = true
let dataKeys = []
this.appendList.forEach(item => {
if (typeof item['dataKey'] === 'string') {
dataKeys.push(item['dataKey'])
}
})
this.gradioAPI.getDatas(dataKeys).then(res => {
this.appendList.forEach(item => {
if (typeof item['dataKey'] !== 'string') return
item.children = res[item['dataKey']] || []
// 反转
item.children.reverse()
})
})
/*this.gradioAPI.getFavorites(this.favoriteKey).then(res => {
this.appendList.forEach(item => {
if (item.type !== 'favorite') return
item.children = res
})
})
this.gradioAPI.getHistories(this.historyKey).then(res => {
this.appendList.forEach(item => {
if (item.type !== 'history') return
item.children = res
})
})*/
}
this._setTextareaFocus()
},
onAppendTagBlur(e) {
setTimeout(() => {
this.showAppendList = false
}, 300)
},
selectAppendList(down = true) {
if (this.appendList.length === 0) return
if (this.appendListSelected === null) {
this.appendListSelected = 0
} else {
if (down) {
this.appendListSelected++
if (this.appendListSelected >= this.appendList.length) {
this.appendListSelected = 0
}
} else {
this.appendListSelected--
if (this.appendListSelected < 0) {
this.appendListSelected = this.appendList.length - 1
}
}
}
this.appendListChildSelected = null
},
selectAppendListChild(down = true) {
if (this.appendList.length === 0) return
if (this.appendListSelected === null) return
if (this.appendList[this.appendListSelected].children.length === 0) return
if (this.appendListChildSelected === null) {
this.appendListChildSelected = 0
} else {
if (down) {
this.appendListChildSelected++
if (this.appendListChildSelected >= this.appendList[this.appendListSelected].children.length) {
this.appendListChildSelected = 0
}
} else {
this.appendListChildSelected--
if (this.appendListChildSelected < 0) {
this.appendListChildSelected = this.appendList[this.appendListSelected].children.length - 1
}
}
}
this.scrollAppendListChild()
},
scrollAppendListChild() {
if (this.appendListSelected === null) return
if (this.appendListChildSelected === 0 || this.appendListChildSelected === null) {
this.$refs.promptAppendListChildren[this.appendListSelected].scrollTop = 0
} else {
this.$refs.promptAppendListChild[this.appendListChildSelected].scrollIntoView({
behavior: 'smooth',
block: 'center'
})
}
},
onAppendTagKeyDown(e, localValue = null) {
if (e.keyCode === 38 || e.keyCode === 40) {
} else if (e.keyCode === 13) {
if (this.getAutocompleteResults() && this.autocompleteResults.style.display === 'block' && this.getAutocompleteResultsSelected()) {
let text = this.getAutocompleteResultsSelectedText()
setTimeout(() => {
localValue = e.target.value
if (text) {
localValue = text
} else {
text = this.getAutocompleteResultsSelectedText()
if (text) localValue = text
}
this.onAppendTagKeyDown(e, localValue)
}, 300)
return
}
let tags = e.target.value
e.target.value = ''
this.showAppendList = true
// [night light:magical forest: 5, 15]
if (localValue) {
// 去除末尾的逗号
tags = tags.replace(/,\s*$/, '')
if (common.hasBrackets(tags)) {
tags = common.replaceBrackets(tags)
}
this._appendTag(tags, localValue)
this.updateTags()
} else {
if (common.hasBrackets(tags)) {
// 如果已经被英文括号括起来,那么就不需要再分词了
tags = common.replaceBrackets(tags)
tags = [tags]
} else {
tags = common.splitTags(tags)
}
let indexes = []
tags.forEach(tag => {
if (tag === "\n") {
indexes.push(this._appendTag("\n", "\n", false, -1, 'wrap'))
} else {
indexes.push(this._appendTag(tag))
}
})
this.updatePrompt() // 先更新再翻译
if (this.autoTranslateToEnglish || this.autoTranslateToLocal) {
this.$nextTick(() => {
let useNetwork = !(this.tagCompleteFile && this.onlyCsvOnAuto)
if (this.autoTranslateToEnglish) {
// 如果开启了自动翻译到英语,那么就自动翻译
this.translates(indexes, false, useNetwork).finally(() => {
this.updateTags()
})
} else if (this.autoTranslateToLocal) {
// 如果开启了自动翻译到本地语言,那么就自动翻译
this.translates(indexes, true, useNetwork).finally(() => {
this.updateTags()
})
}
})
} else {
this.updateTags()
}
}
} else {
// 不是上下键,也不是回车
this.removeAutocompleteResultsSelected()
}
},
onAppendTagKeyUp(e) {
if (e.target.value === '' || e.target.value.trim() === '') {
e.target.value = ''
this.showAppendList = true
if (e.keyCode === 38 || e.keyCode === 40) {
// 如果是上下键
if (this.appendListChildSelected === null) {
this.selectAppendList(e.keyCode === 40)
} else {
this.selectAppendListChild(e.keyCode === 40)
}
} else if (e.keyCode === 37 || e.keyCode === 39) {
// 如果是左右键
if (this.appendListSelected !== null) {
if (e.keyCode === 37) {
this.appendListChildSelected = null
this.scrollAppendListChild()
} else {
if (this.appendList[this.appendListSelected].children.length === 0) {
this.appendListChildSelected = null
} else {
this.appendListChildSelected = 0
this.scrollAppendListChild()
}
}
}
} else if (e.keyCode === 13) {
// 如果是回车键
this._appendTagByList()
this.scrollAppendListChild()
this.appendListSelected = null
this.appendListChildSelected = null
}
} else {
this.showAppendList = false
}
},
onAppendGroupClick(index, childIndex, e) {
if (index === null) return
this.appendListSelected = index
if (childIndex === null) {
// 如果是点击的是父级
if (this.appendList[this.appendListSelected].children.length > 0) return
} else {
this.appendListChildSelected = childIndex
}
this._appendTagByList()
},
onAppendListChildMouseLeave(index, childIndex, e) {
this.appendListSelected = null
this.appendListChildSelected = null
},
onAppendListChildMouseEnter(index, childIndex, e) {
this.appendListSelected = index
this.appendListChildSelected = childIndex
},
_appendTagByList() {
if (this.appendListSelected === null) return
const appendItem = this.appendList[this.appendListSelected]
let appendChildItem = null
if (appendItem.children.length > 0) {
if (this.appendListChildSelected !== null) {
// 有子项并且选中了子项
appendChildItem = appendItem.children[this.appendListChildSelected]
}
} else {
// 没有子项
}
let appendTags = []
switch (appendItem.type) {
case 'wrap':
appendTags.push({
value: "\n",
localValue: "\n",
disabled: false,
type: 'wrap'
})
break
case 'lora':
break
case 'favorite':
case 'history':
if (appendChildItem) {
appendChildItem.tags.forEach(tag => {
appendTags.push({
value: tag.value,
localValue: tag.localValue,
disabled: tag.disabled,
type: tag.type || 'text'
})
})
}
break
}
if (appendTags.length <= 0) return
appendTags.forEach(tag => {
this._appendTag(tag.value, tag.localValue, tag.disabled, -1, tag.type)
})
this.updateTags()
},
getAutocompleteResults() {
if (!this.autocompleteResults) {
const autocompleteResults = this.$refs.promptTagAppend.parentElement.querySelector('.autocompleteResults')
if (autocompleteResults) {
this.autocompleteResults = autocompleteResults
// 增加mousemove事件
if (this.autocompleteResults.getAttribute('data-mousemove') !== 'true') {
this.autocompleteResults.setAttribute('data-mousemove', 'true')
this.autocompleteResults.addEventListener('mousemove', (e) => {
this.bindAutocompleteResultsClick()
})
}
}
}
return this.autocompleteResults
},
removeAutocompleteResultsSelected() {
const autocompleteResults = this.getAutocompleteResults()
if (!autocompleteResults) return false
autocompleteResults.querySelectorAll('li').forEach(li => {
li.classList.remove('selected')
})
return true
},
getAutocompleteResultsSelected() {
const autocompleteResults = this.getAutocompleteResults()
if (!autocompleteResults) return null
const el = autocompleteResults.querySelector('li.selected')
if (!el) return null
return el
},
getAutocompleteResultsSelectedText(el = null) {
if (!el) {
el = this.getAutocompleteResultsSelected()
if (!el) return null
}
const $acListItem = el.querySelector('.acListItem')
const text = $acListItem.innerText
const match = text.match(/\[(.+?)\]/)
if (!match) return null
return match[1]
},
bindAutocompleteResultsClick() {
this.getAutocompleteResults()
if (!this.autocompleteResults) return
// 获取列表
let lis = this.autocompleteResults.querySelectorAll('li')
// 给每个li绑定点击事件
lis.forEach(li => {
// 判断是否已经绑定过
if (li.getAttribute('physton-on-clicked') === 'true') return
li.setAttribute('physton-on-clicked', 'true')
li.addEventListener('click', () => {
this.onAutocompleteResultsClicked(li)
})
})
},
onAutocompleteResultsClicked(li) {
const text = this.getAutocompleteResultsSelectedText(li)
setTimeout(() => {
let tags = this.$refs.promptTagAppend.value.replace(/,\s*$/, '')
this.$refs.promptTagAppend.value = ''
if (common.hasBrackets(tags)) {
tags = common.replaceBrackets(tags)
}
this._appendTag(tags, text)
this.updateTags()
}, 300)
},
}
}

View File

@@ -0,0 +1,394 @@
import common from "@/utils/common";
import autoSizeInput from "autosize-input";
export default {
data() {
return {
tagClickTimeId: 0,
}
},
mounted() {
},
methods: {
_setTag(tag) {
if (typeof tag['type'] === 'string' && tag.type === 'wrap') {
tag.weightNum = 1
tag.incWeight = 0
tag.decWeight = 0
} else {
tag.weightNum = common.getTagWeightNum(tag.value)
tag.weightNum = tag.weightNum <= 0 ? 1 : tag.weightNum
tag.incWeight = common.getTagIncWeight(tag.value)
tag.decWeight = common.getTagDecWeight(tag.value)
// const bracket = common.hasBrackets(tag.value)
}
this._setTagClass(tag)
this.$nextTick(() => {
this._setTagHeight(tag)
})
},
_setTagHeight(tag) {
setTimeout(() => {
let $tag = this.$refs['promptTagValue-' + tag.id][0]
let height = $tag.offsetHeight
$tag.parentNode.style.height = height + 'px'
if (this.$refs['promptTagEdit-' + tag.id]) {
this.$refs['promptTagEdit-' + tag.id][0].style.height = height + 'px'
}
if (this.$refs['promptTagDelete-' + tag.id]) {
this.$refs['promptTagDelete-' + tag.id][0].style.height = height + 'px'
}
}, 300)
},
_setTagClass(tag) {
tag.isLora = false
tag.loraExists = false
tag.isLyco = false
tag.lycoExists = false
tag.isEmbedding = false
if (typeof tag['type'] === 'string' && tag.type === 'wrap') {
} else {
// 判断是否lora
const match = tag.value.match(common.loraRegex)
if (match) {
tag.isLora = true
const loraName = this.loraExists(match[1])
if (loraName !== false) {
tag.loraExists = true
tag.loraName = loraName
}
}
if (!tag.isLora) {
// 判断是否lyco
const match = tag.value.match(common.lycoRegex)
if (match) {
tag.isLyco = true
const lycoName = this.lycoExists(match[1])
if (lycoName !== false) {
tag.lycoExists = true
tag.lycoName = lycoName
}
}
}
if (!tag.isLora && !tag.isLyco) {
// 判断是否embedding
const embeddingName = this.embeddingExists(tag.value)
if (embeddingName !== false) {
tag.isEmbedding = true
tag.value = embeddingName
}
}
}
let classes = ['prompt-tag-value']
if (tag.isLora) {
classes.push('lora-tag')
if (!tag.loraExists) {
classes.push('lora-not-exists')
}
} else if (tag.isLyco) {
classes.push('lyco-tag')
if (!tag.lycoExists) {
classes.push('lyco-not-exists')
}
} else if (tag.isEmbedding) {
classes.push('embedding-tag')
} else if (this.neg) {
classes.push('neg-tag')
}
tag.classes = classes
return classes
},
_setTagById(id, value = null, localValue = null) {
let tag = this.tags.find(tag => tag.id === id)
if (!tag) return false
if (value !== null) tag.value = value
if (localValue !== null) tag.localValue = localValue
return tag
},
_appendTag(value, localValue = '', disabled = false, index = -1, type = 'text') {
// 唯一数:当前时间戳+随机数
const id = Date.now() + (Math.random() * 1000000).toFixed(0)
let tag = {
id,
value,
localValue,
disabled,
type
}
this._setTag(tag)
// value = common.setLayers(value, 0, '(', ')')
// value = common.setLayers(value, 0, '[', ']')
if (index >= 0) {
// 插入到指定位置
this.tags.splice(index, 0, tag)
} else {
index = this.tags.push(tag)
}
this.$nextTick(() => {
if (this.$refs['promptTagEdit-' + id]) autoSizeInput(this.$refs['promptTagEdit-' + id][0])
})
return index - 1
},
renderTag(id) {
let tag = this.tags.find(tag => tag.id === id)
if (!tag) return ''
let value = tag.value
value = common.escapeHtml(value)
if (tag.incWeight > 0) {
value = common.setLayers(value, 0, '(', ')')
value = '<div class="character">' + value + '</div>'
let start = '<div class="weight-character">' + '('.repeat(tag.incWeight) + '</div>'
let end = '<div class="weight-character">' + ')'.repeat(tag.incWeight) + '</div>'
value = start + value + end
} else if (tag.decWeight > 0) {
value = common.setLayers(value, 0, '[', ']')
value = '<div class="character">' + value + '</div>'
let start = '<div class="weight-character">' + '['.repeat(tag.decWeight) + '</div>'
let end = '<div class="weight-character">' + ']'.repeat(tag.decWeight) + '</div>'
value = start + value + end
} else {
value = '<div class="character">' + value + '</div>'
}
return value
},
isFavorite(id) {
let tag = this.tags.find(tag => tag.id === id)
if (!tag) return false
if (typeof window.phystonPromptfavorites === 'object') {
for (const group of window.phystonPromptfavorites) {
if (group.key !== this.favoriteKey) continue
for (const favorite of group.list) {
if (favorite.tags.length !== 1) continue
if (favorite.tags[0].value === tag.value) return favorite.id
}
}
}
return false
},
onTagMouseEnter(id) {
let tag = this.tags.find(tag => tag.id === id)
if (!tag) return false
tag.isFavorite = this.isFavorite(tag.id)
},
onTagClick(id) {
let tag = this.tags.find(tag => tag.id === id)
if (!tag) return false
if (this.tagClickTimeId) clearTimeout(this.tagClickTimeId)
this.tagClickTimeId = setTimeout(() => {
this.editing = {}
this.editing[tag.id] = true
this.$forceUpdate()
this.$nextTick(() => {
const input = this.$refs['promptTagEdit-' + tag.id][0]
input.focus()
input.dispatchEvent(new Event('input'))
// input.select()
})
clearTimeout(this.tagClickTimeId)
}, 250)
},
onTagDblclick(id) {
let tag = this.tags.find(tag => tag.id === id)
if (!tag) return false
clearTimeout(this.tagClickTimeId)
this.onDisabledTagClick(tag.id)
},
onTagInputBlur(id) {
let tag = this.tags.find(tag => tag.id === id)
if (!tag) return false
this.editing[tag.id] = false
},
onTagInputKeyDown(id, e) {
if (e.keyCode === 13) {
let tag = this.tags.find(tag => tag.id === id)
if (!tag) return false
this.editing[tag.id] = false
if (tag.value !== e.target.value) {
tag.value = e.target.value
this._setTag(tag)
this.updateTags()
}
}
},
onTagInputChange(id, e) {
let tag = this.tags.find(tag => tag.id === id)
if (!tag) return false
if (tag.value === e.target.value) return
tag.value = e.target.value
this._setTag(tag)
this.updateTags()
},
onTagWeightNumChange(id, e) {
let tag = this.tags.find(tag => tag.id === id)
if (!tag) return false
e = typeof e === "number" || typeof a === "string" ? e : e.target.value
if (tag.weightNum == e) return
let weightNum = e
let value = tag.value
let localValue = tag.localValue
if (weightNum > 0) {
if (weightNum === 1) {
// 如果权重数是1那么就去掉权重数
const bracket = common.hasBrackets(value)
if (bracket[0] === '(' && bracket[1] === ')') {
// 移除括号
value = common.setLayers(value, 0, bracket[0], bracket[1])
if (localValue !== '') localValue = common.setLayers(localValue, 0, bracket[0], bracket[1])
} else {
// 不移除括号
}
// 移除权重数
value = value.replace(common.weightNumRegex, '$1')
if (localValue !== '') localValue = localValue.replace(common.weightNumRegex, '$1')
} else {
// 如果原来没有权重数,那么就加上权重数
if (!common.weightNumRegex.test(value)) {
// 如果原来有括号,就要加到括号内
let bracket = common.hasBrackets(value)
if (bracket) {
value = common.setLayers(value, 1, bracket[0], bracket[1], ':' + weightNum)
if (localValue !== '') localValue = common.setLayers(localValue, 1, bracket[0], bracket[1], ':' + weightNum)
} else {
value = value + ':' + weightNum
if (localValue !== '') localValue = localValue + ':' + weightNum
}
}
// 如果原来没有括号() [] {} <>,那么就加上括号
if (!common.hasBrackets(value)) {
value = common.setLayers(value, 1, '(', ')')
if (localValue !== '') localValue = common.setLayers(localValue, 1, '(', ')')
}
}
if (value !== tag.value) {
tag.value = value
if (localValue !== '') tag.localValue = localValue
this._setTag(tag)
}
} else {
// 如果原来的括号是<>那么最小权重数只能是0.1
const bracket = common.hasBrackets(value)
if (bracket[0] === '<' && bracket[1] === '>') {
weightNum = 0.1
} else {
if (this.autoKeepWeightZero) {
// 保留权重数
tag.value = value.replace(common.weightNumRegex, '$1:0')
if (localValue !== '') tag.localValue = tag.localValue.replace(common.weightNumRegex, '$1:0')
} else {
// 移除权重数
tag.value = value.replace(common.weightNumRegex, '$1')
if (localValue !== '') tag.localValue = tag.localValue.replace(common.weightNumRegex, '$1')
}
}
}
tag.weightNum = weightNum
this.updateTags()
},
onDeleteTagClick(id) {
let tag = this.tags.find(tag => tag.id === id)
if (!tag) return false
let index = this.tags.indexOf(tag)
this.tags.splice(index, 1)
this.updateTags()
},
onFavoriteTagClick(id) {
let tag = this.tags.find(tag => tag.id === id)
if (!tag) return false
let favoriteId = this.isFavorite(tag.id)
if (!favoriteId) {
// 收藏
this.gradioAPI.pushFavorite(this.favoriteKey, [tag], tag.value, tag.localValue === '' ? tag.value : tag.localValue).then(res => {
if (res) {
tag.isFavorite = true
this.$emit('refreshFavorites', this.favoriteKey)
}
})
} else {
// 取消收藏
this.gradioAPI.unFavorite(this.favoriteKey, favoriteId).then(res => {
if (res) {
tag.isFavorite = false
this.$emit('refreshFavorites', this.favoriteKey)
}
})
}
},
onDisabledTagClick(id) {
let tag = this.tags.find(tag => tag.id === id)
if (!tag) return
tag.disabled = !tag.disabled
this.updateTags()
},
onIncWeightClick(id, num) {
let tag = this.tags.find(tag => tag.id === id)
if (!tag) return
let value = tag.value
let localValue = tag.localValue
value = common.setLayers(value, 0, '[', ']')
if (localValue !== '') localValue = common.setLayers(localValue, 0, '[', ']')
let incWeight = tag.incWeight
incWeight += num
if (incWeight < 0) incWeight = 0
tag.incWeight = incWeight
tag.decWeight = 0
value = common.setLayers(value, incWeight, '(', ')')
if (localValue !== '') localValue = common.setLayers(localValue, incWeight, '(', ')')
tag.value = value
if (localValue !== '') tag.localValue = localValue
this.updateTags()
},
onDecWeightClick(id, num) {
let tag = this.tags.find(tag => tag.id === id)
if (!tag) return
let value = tag.value
let localValue = tag.localValue
value = common.setLayers(value, 0, '(', ')')
if (localValue !== '') localValue = common.setLayers(localValue, 0, '(', ')')
let decWeight = tag.decWeight
decWeight += num
if (decWeight < 0) decWeight = 0
tag.incWeight = 0
tag.decWeight = decWeight
value = common.setLayers(value, decWeight, '[', ']')
if (localValue !== '') localValue = common.setLayers(localValue, decWeight, '[', ']')
tag.value = value
if (localValue !== '') tag.localValue = localValue
this.updateTags()
},
onWrapTagClick(id) {
let tag = this.tags.find(tag => tag.id === id)
if (!tag) return
let index = this.tags.indexOf(tag)
let wrapIndex = this._appendTag("\n", "\n", false, -1, 'wrap')
let wrapTag = this.tags[wrapIndex]
// 移动到当前标签的下面
this.tags.splice(wrapIndex, 1);
// 然后将 'c' 插入到 'e' 后面
this.tags.splice(index + 1, 0, wrapTag);
this.updateTags()
},
onTranslateToLocalClick(id) {
let tag = this.tags.find(tag => tag.id === id)
if (!tag) return
let index = this.tags.indexOf(tag)
if (this.loading[tag.id + '_local']) return
this.translates([index], true, true).finally(() => {
this.updateTags()
})
},
onTranslateToEnglishClick(id) {
let tag = this.tags.find(tag => tag.id === id)
if (!tag) return
let index = this.tags.indexOf(tag)
if (this.loading[tag.id + '_en']) return
this.translates([index], false, true).finally(() => {
this.updateTags()
})
},
}
}

View File

@@ -495,4 +495,16 @@ export default {
parent1.insertBefore(ele2, next1)
parent2.insertBefore(ele1, next2)
},
insertBefore(newNode, referenceNode) {
referenceNode.parentNode.insertBefore(newNode, referenceNode);
},
insertAfter(newNode, referenceNode) {
if (referenceNode.nextSibling) {
referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
} else {
referenceNode.parentNode.appendChild(newNode);
}
},
}

View File

@@ -152,7 +152,7 @@
.physton-prompt {
border: 1px solid var(--input-border-color);
padding: 0 10px;
padding: 0;
margin: 5px 0;
div {
@@ -184,12 +184,11 @@
}
.prompt-header {
margin: 5px 0;
margin: 0;
padding: 5px 10px;
display: flex;
justify-content: flex-start;
align-items: center;
padding-bottom: 10px;
margin-bottom: 10px;
border-bottom: 1px dashed var(--input-border-color);
flex-wrap: wrap;
@@ -445,13 +444,24 @@
flex-wrap: wrap;
justify-content: flex-start;
align-items: flex-start;
position: relative;
padding: 5px 10px 0;
&.droping {
&.droping, &.selecting {
.btn-tag-extend {
display: none !important;
}
}
&.selecting {
* {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
}
.prompt-tag-edit {
.set-icon-svg(16px, 16px, #02b7fd, icon-svg-wrap);
}
@@ -480,6 +490,85 @@
.set-icon-svg(16px, 16px, none, icon-svg-loading);
}
.drop-select-bg {
position: fixed;
display: none;
left: 0;
top: 0;
width: 100%;
height: 100%;
z-index: 999;
}
.drop-select-box {
position: absolute;
display: none;
left: 0;
top: 0;
width: 0;
height: 0;
box-sizing: border-box;
background: rgba(0, 175, 255, 0.2);
border: 1px solid rgba(0, 175, 255, 0.8);
z-index: 1000;
}
.drop-select-btns {
position: absolute;
display: none;
left: 0;
top: 0;
width: auto;
height: auto;
z-index: 1000;
justify-content: flex-start;
align-items: center;
padding: 0;
box-sizing: border-box;
box-shadow: 0 0 3px #4a54ff;
background: #0c0c0c;
border-radius: 4px;
overflow: hidden;
.set-icon-svg(20px, 20px, #c5c5c5, icon-svg-copy);
.set-icon-svg(20px, 20px, #ff472f, icon-svg-disabled);
.set-icon-svg(20px, 20px, #2fff53, icon-svg-enable);
.set-icon-svg(20px, 20px, none, icon-svg-favorite-no);
.set-icon-svg(20px, 20px, none, icon-svg-favorite-yes);
.set-icon-svg(20px, 20px, #ff472f, icon-svg-remove);
.btns-title {
color: #fff;
padding: 0 5px;
border-right: 1px solid rgba(255, 255, 255, 0.2);
height: 32px;
line-height: 32px;
}
> button {
height: 32px;
width: 32px;
border: 0;
border-radius: 0;
padding: 5px;
min-width: auto;
font-size: 0.9rem;
min-height: auto;
background: transparent;
color: #fff;
border-right: 1px solid rgba(255, 255, 255, 0.2);
&:last-child {
border-right: 0;
}
&:hover {
background: rgba(255, 255, 255, 0.2);
}
}
}
.prompt-tags-list {
display: flex;
flex-wrap: wrap;
@@ -507,8 +596,15 @@
}
&.disabled {
opacity: 0.7;
z-index: 100;
.prompt-tag-edit {
opacity: .7;
}
}
&.sortable-selected, &.drop-selected {
.prompt-tag-value {
background: rgba(0, 175, 255, 0.4) !important;
}
}
.prompt-tag-main {
@@ -553,6 +649,10 @@
border: var(--button-border-width) solid var(--button-secondary-border-color);
height: auto;
color: var(--green-9);
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
&.neg-tag {
color: var(--magenta-9);
@@ -733,6 +833,7 @@
font-size: .8rem;
color: var(--body-text-color-subdued);
margin-left: 2px;
pointer-events: none;
}
}
}

View File

@@ -1 +1 @@
03fb7625efb04879d48421dbc3ca9362e4417cf2
d4b733cb747e60aaf8e3708761dc0271c9b397d6