| onUiLoaded(() => { |
| addFormatButton('txt2img'); |
| addFormatButton('img2img'); |
| }); |
|
|
| function addFormatButton(type) { |
| let formatButton = gradioApp().querySelector(`#${type}_format_prompt`); |
| const lastButton = gradioApp().querySelector(`#${type}_clear_prompt`); |
| if (formatButton || !lastButton || !lastButton.parentNode) |
| return; |
| formatButton = createFormatButton(`${type}_format_prompt`, type); |
| lastButton.parentNode.append(formatButton); |
| } |
|
|
| function createFormatButton(id, type) { |
| const button = document.createElement('button'); |
| button.id = id; |
| button.type = 'button'; |
| button.innerHTML = '🪄'; |
| button.title = 'Format prompt~🪄' |
| button.className = 'lg secondary gradio-button tool svelte-cmf5ev'; |
| button.addEventListener('click', () => formatPrompts(type)); |
| return button; |
| } |
|
|
| function formatPrompts(type) { |
| for (let kind of ['_prompt', '_neg_prompt']) { |
| const prompt = gradioApp().querySelector(`#${type + kind} > label > textarea`); |
| const result = formatPrompt(prompt.value); |
| prompt.value = result; |
| dispatchInputEvent(prompt); |
| } |
| } |
|
|
| function dispatchInputEvent(target) { |
| let inputEvent = new Event('input'); |
| Object.defineProperty(inputEvent, 'target', { value: target }); |
| target.dispatchEvent(inputEvent); |
| } |
|
|
| function round(value) { |
| return Math.round(value * 10000) / 10000 |
| } |
|
|
| function convertStr(str) { |
| return str.replace(/:/g, ':').replace(/(/g, '(').replace(/)/g, ')') |
| } |
|
|
| function convertStr2Array(str) { |
| const bracketRegex = /([()<>[\]])/g |
|
|
| const splitByBracket = str => { |
| const arr = [] |
| let start = 0 |
| let depth = 0 |
| let match |
| while ((match = bracketRegex.exec(str)) !== null) { |
| if (depth === 0 && match.index > start) { |
| arr.push(str.substring(start, match.index)) |
| start = match.index |
| } |
| if (match[0] === '(' || match[0] === '<' || match[0] === '[') { |
| depth++ |
| } else if (match[0] === ')' || match[0] === '>' || match[0] === ']') { |
| depth-- |
| } |
| if (depth === 0) { |
| arr.push(str.substring(start, match.index + 1)) |
| start = match.index + 1 |
| } |
| } |
| if (start < str.length) { |
| arr.push(str.substring(start)) |
| } |
| return arr |
| } |
|
|
| const splitByComma = str => { |
| const arr = [] |
| let start = 0 |
| let inBracket = false |
| for (let i = 0; i < str.length; i++) { |
| if (str[i] === ',' && !inBracket) { |
| arr.push(str.substring(start, i).trim()) |
| start = i + 1 |
| } else if (str[i].match(bracketRegex)) { |
| inBracket = !inBracket |
| } |
| } |
| arr.push(str.substring(start).trim()) |
| return arr |
| } |
|
|
| const cleanStr = str => { |
| let arr = splitByBracket(str) |
| arr = arr.flatMap((s) => splitByComma(s)) |
| return arr.filter((s) => s !== '') |
| } |
|
|
| return cleanStr(str) |
| .filter((item) => { |
| const pattern = /^[,\s, ]+$/ |
| return !pattern.test(item) |
| }) |
| .filter(Boolean) |
| .sort((a, b) => { |
| return a.includes('<') && !b.includes('<') ? 1 : b.includes('<') && !a.includes('<') ? -1 : 0 |
| }) |
| } |
|
|
| function convertArray2Str(array) { |
| const newArray = array.map((item) => { |
| if (item.includes('<')) return item |
| const newItem = item |
| .replace(/\s+/g, ' ') |
| .replace(/,|\.\|。/g, ',') |
| .replace(/“|‘|”|"|\/'/g, '') |
| .replace(/, /g, ',') |
| .replace(/,,/g, ',') |
| .replace(/,/g, ', ') |
| return convertStr2Array(newItem).join(', ') |
| }) |
| return newArray.join(', ') |
| } |
|
|
| function formatPrompt(input) { |
| const re_attention = /\{|\[|\}|\]|[^{}[\]]+/gmu |
|
|
| let text = convertStr(input) |
| const textArray = convertStr2Array(text) |
| text = convertArray2Str(textArray) |
|
|
| let res = [] |
|
|
| const curly_bracket_multiplier = 1.05 |
| const square_bracket_multiplier = 1 / 1.05 |
|
|
| const brackets = { |
| '{': { stack: [], multiplier: curly_bracket_multiplier }, |
| '[': { stack: [], multiplier: square_bracket_multiplier }, |
| } |
|
|
| function multiply_range(start_position, multiplier) { |
| for (let pos = start_position; pos < res.length; pos++) { |
| res[pos][1] = round(res[pos][1] * multiplier) |
| } |
| } |
|
|
| for (const match of text.matchAll(re_attention)) { |
| let word = match[0] |
|
|
| if (word in brackets) { |
| brackets[word].stack.push(res.length) |
| } else if (word === '}' || word === ']') { |
| const bracket = brackets[word === '}' ? '{' : '['] |
| if (bracket.stack.length > 0) { |
| multiply_range(bracket.stack.pop(), bracket.multiplier) |
| } |
| } else { |
| res.push([word, 1.0]) |
| } |
| } |
|
|
| Object.keys(brackets).forEach((bracketType) => { |
| brackets[bracketType].stack.forEach((pos) => { |
| multiply_range(pos, brackets[bracketType].multiplier) |
| }) |
| }) |
|
|
| if (res.length === 0) { |
| res = [['', 1.0]] |
| } |
|
|
| let i = 0 |
| while (i + 1 < res.length) { |
| if (res[i][1] === res[i + 1][1]) { |
| res[i][0] += res[i + 1][0] |
| res.splice(i + 1, 1) |
| } else { |
| i += 1 |
| } |
| } |
|
|
| let result = '' |
| for (const [word, value] of res) { |
| result += value === 1.0 ? word : `(${word}:${value.toString()})` |
| } |
| return result |
| } |
|
|