FashGate commited on
Commit
3a20d16
·
1 Parent(s): 9975f02

Upload easy_prompt_selector.js

Browse files
Files changed (1) hide show
  1. easy_prompt_selector.js +342 -0
easy_prompt_selector.js ADDED
@@ -0,0 +1,342 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ class EPSElementBuilder {
2
+ // Templates
3
+ static baseButton(text, { size = 'sm', color = 'primary' }) {
4
+ const button = gradioApp().getElementById('txt2img_generate').cloneNode()
5
+ button.id = ''
6
+ button.classList.remove('gr-button-lg', 'gr-button-primary', 'lg', 'primary')
7
+ button.classList.add(
8
+ // gradio 3.16
9
+ `gr-button-${size}`,
10
+ `gr-button-${color}`,
11
+ // gradio 3.22
12
+ size,
13
+ color
14
+ )
15
+ button.textContent = text
16
+
17
+ return button
18
+ }
19
+
20
+ static tagFields() {
21
+ const fields = document.createElement('div')
22
+ fields.style.display = 'flex'
23
+ fields.style.flexDirection = 'row'
24
+ fields.style.flexWrap = 'wrap'
25
+ fields.style.minWidth = 'min(320px, 100%)'
26
+ fields.style.maxWidth = '100%'
27
+ fields.style.flex = '1 calc(50% - 20px)'
28
+ fields.style.borderWidth = '1px'
29
+ fields.style.borderColor = 'var(--block-border-color,#374151)'
30
+ fields.style.borderRadius = 'var(--block-radius,8px)'
31
+ fields.style.padding = '8px'
32
+ fields.style.height = 'fit-content'
33
+
34
+ return fields
35
+ }
36
+
37
+ // Elements
38
+ static openButton({ onClick }) {
39
+ const button = EPSElementBuilder.baseButton('🔯提示词', { size: 'sm', color: 'secondary' })
40
+ button.classList.add('easy_prompt_selector_button')
41
+ button.addEventListener('click', onClick)
42
+
43
+ return button
44
+ }
45
+
46
+ static areaContainer(id = undefined) {
47
+ const container = gradioApp().getElementById('txt2img_results').cloneNode()
48
+ container.id = id
49
+ container.style.gap = 0
50
+ container.style.display = 'none'
51
+
52
+ return container
53
+ }
54
+
55
+ static tagButton({ title, onClick, onRightClick, color = 'primary' }) {
56
+ const button = EPSElementBuilder.baseButton(title, { color })
57
+ button.style.height = '2rem'
58
+ button.style.flexGrow = '0'
59
+ button.style.margin = '2px'
60
+
61
+ button.addEventListener('click', onClick)
62
+ button.addEventListener('contextmenu', onRightClick)
63
+
64
+ return button
65
+ }
66
+
67
+ static dropDown(id, options, { onChange }) {
68
+ const select = document.createElement('select')
69
+ select.id = id
70
+
71
+ // gradio 3.16
72
+ select.classList.add('gr-box', 'gr-input')
73
+
74
+ // gradio 3.22
75
+ select.style.color = 'var(--body-text-color)'
76
+ select.style.backgroundColor = 'var(--body-background-fill)'
77
+ select.style.borderColor = 'var(--block-border-color)'
78
+ select.style.borderRadius = 'var(--block-radius)'
79
+ select.style.margin = '2px'
80
+ select.addEventListener('change', (event) => { onChange(event.target.value) })
81
+
82
+ const none = ['空']
83
+ none.concat(options).forEach((key) => {
84
+ const option = document.createElement('option')
85
+ option.value = key
86
+ option.textContent = key
87
+ select.appendChild(option)
88
+ })
89
+
90
+ return select
91
+ }
92
+
93
+ static checkbox(text, { onChange }) {
94
+ const label = document.createElement('label')
95
+ label.style.display = 'flex'
96
+ label.style.alignItems = 'center'
97
+
98
+ const checkbox = gradioApp().querySelector('input[type=checkbox]').cloneNode()
99
+ checkbox.checked = false
100
+ checkbox.addEventListener('change', (event) => {
101
+ onChange(event.target.checked)
102
+ })
103
+
104
+ const span = document.createElement('span')
105
+ span.style.marginLeft = 'var(--size-2, 8px)'
106
+ span.textContent = text
107
+
108
+ label.appendChild(checkbox)
109
+ label.appendChild(span)
110
+
111
+ return label
112
+ }
113
+ }
114
+
115
+ class EasyPromptSelector {
116
+ PATH_FILE = 'tmp/easyPromptSelector.txt'
117
+ AREA_ID = 'easy-prompt-selector'
118
+ SELECT_ID = 'easy-prompt-selector-select'
119
+ CONTENT_ID = 'easy-prompt-selector-content'
120
+ TO_NEGATIVE_PROMPT_ID = 'easy-prompt-selector-to-negative-prompt'
121
+
122
+ constructor(yaml, gradioApp) {
123
+ this.yaml = yaml
124
+ this.gradioApp = gradioApp
125
+ this.visible = false
126
+ this.toNegative = false
127
+ this.tags = undefined
128
+ }
129
+
130
+ async init() {
131
+ this.tags = await this.parseFiles()
132
+
133
+ const tagArea = gradioApp().querySelector(`#${this.AREA_ID}`)
134
+ if (tagArea != null) {
135
+ this.visible = false
136
+ this.changeVisibility(tagArea, this.visible)
137
+ tagArea.remove()
138
+ }
139
+
140
+ gradioApp()
141
+ .getElementById('txt2img_toprow')
142
+ .after(this.render())
143
+ }
144
+
145
+ async readFile(filepath) {
146
+ const response = await fetch(`file=${filepath}?${new Date().getTime()}`);
147
+
148
+ return await response.text();
149
+ }
150
+
151
+ async parseFiles() {
152
+ const text = await this.readFile(this.PATH_FILE);
153
+ if (text === '') { return {} }
154
+
155
+ const paths = text.split(/\r\n|\n/)
156
+
157
+ const tags = {}
158
+ for (const path of paths) {
159
+ const filename = path.split('/').pop().split('.').slice(0, -1).join('.')
160
+ const data = await this.readFile(path)
161
+ yaml.loadAll(data, function (doc) {
162
+ tags[filename] = doc
163
+ })
164
+ }
165
+
166
+ return tags
167
+ }
168
+
169
+ // Render
170
+ render() {
171
+ const row = document.createElement('div')
172
+ row.style.display = 'flex'
173
+ row.style.alignItems = 'center'
174
+ row.style.gap = '10px'
175
+
176
+ const dropDown = this.renderDropdown()
177
+ dropDown.style.flex = '1'
178
+ dropDown.style.minWidth = '1'
179
+ row.appendChild(dropDown)
180
+
181
+ const settings = document.createElement('div')
182
+ const checkbox = EPSElementBuilder.checkbox('负面', {
183
+ onChange: (checked) => { this.toNegative = checked }
184
+ })
185
+ settings.style.flex = '1'
186
+ settings.appendChild(checkbox)
187
+
188
+ row.appendChild(settings)
189
+
190
+ const container = EPSElementBuilder.areaContainer(this.AREA_ID)
191
+
192
+ container.appendChild(row)
193
+ container.appendChild(this.renderContent())
194
+
195
+ return container
196
+ }
197
+
198
+ renderDropdown() {
199
+ const dropDown = EPSElementBuilder.dropDown(
200
+ this.SELECT_ID,
201
+ Object.keys(this.tags), {
202
+ onChange: (selected) => {
203
+ const content = gradioApp().getElementById(this.CONTENT_ID)
204
+ Array.from(content.childNodes).forEach((node) => {
205
+ const visible = node.id === `easy-prompt-selector-container-${selected}`
206
+ this.changeVisibility(node, visible)
207
+ })
208
+ }
209
+ }
210
+ )
211
+
212
+ return dropDown
213
+ }
214
+
215
+ renderContent() {
216
+ const content = document.createElement('div')
217
+ content.id = this.CONTENT_ID
218
+
219
+ Object.keys(this.tags).forEach((key) => {
220
+ const values = this.tags[key]
221
+
222
+ const fields = EPSElementBuilder.tagFields()
223
+ fields.id = `easy-prompt-selector-container-${key}`
224
+ fields.style.display = 'none'
225
+ fields.style.flexDirection = 'row'
226
+ fields.style.marginTop = '10px'
227
+
228
+ this.renderTagButtons(values, key).forEach((group) => {
229
+ fields.appendChild(group)
230
+ })
231
+
232
+ content.appendChild(fields)
233
+ })
234
+
235
+ return content
236
+ }
237
+
238
+ renderTagButtons(tags, prefix = '') {
239
+ if (Array.isArray(tags)) {
240
+ return tags.map((tag) => this.renderTagButton(tag, tag, 'secondary'))
241
+ } else {
242
+ return Object.keys(tags).map((key) => {
243
+ const values = tags[key]
244
+ const randomKey = `${prefix}:${key}`
245
+
246
+ if (typeof values === 'string') { return this.renderTagButton(key, values, 'secondary') }
247
+
248
+ const fields = EPSElementBuilder.tagFields()
249
+ fields.style.flexDirection = 'column'
250
+
251
+ fields.append(this.renderTagButton(key, `@${randomKey}@`))
252
+
253
+ const buttons = EPSElementBuilder.tagFields()
254
+ buttons.id = 'buttons'
255
+ fields.append(buttons)
256
+ this.renderTagButtons(values, randomKey).forEach((button) => {
257
+ buttons.appendChild(button)
258
+ })
259
+
260
+ return fields
261
+ })
262
+ }
263
+ }
264
+
265
+ renderTagButton(title, value, color = 'primary') {
266
+ return EPSElementBuilder.tagButton({
267
+ title,
268
+ onClick: (e) => {
269
+ e.preventDefault();
270
+
271
+ this.addTag(value, this.toNegative || e.metaKey || e.ctrlKey)
272
+ },
273
+ onRightClick: (e) => {
274
+ e.preventDefault();
275
+
276
+ this.removeTag(value, this.toNegative || e.metaKey || e.ctrlKey)
277
+ },
278
+ color
279
+ })
280
+ }
281
+
282
+ // Util
283
+ changeVisibility(node, visible) {
284
+ node.style.display = visible ? 'flex' : 'none'
285
+ }
286
+
287
+ addTag(tag, toNegative = false) {
288
+ const id = toNegative ? 'txt2img_neg_prompt' : 'txt2img_prompt'
289
+ const textarea = gradioApp().getElementById(id).querySelector('textarea')
290
+
291
+ if (textarea.value.trim() === '') {
292
+ textarea.value = tag
293
+ } else if (textarea.value.trim().endsWith(',')) {
294
+ textarea.value += ' ' + tag
295
+ } else {
296
+ textarea.value += ', ' + tag
297
+ }
298
+
299
+ updateInput(textarea)
300
+ }
301
+
302
+ removeTag(tag, toNegative = false) {
303
+ const id = toNegative ? 'txt2img_neg_prompt' : 'txt2img_prompt'
304
+ const textarea = gradioApp().getElementById(id).querySelector('textarea')
305
+
306
+ if (textarea.value.trimStart().startsWith(tag)) {
307
+ const matched = textarea.value.match(new RegExp(`${tag.replace(/[-\/\\^$*+?.()|\[\]{}]/g, '\\$&') },*`))
308
+ textarea.value = textarea.value.replace(matched[0], '').trimStart()
309
+ } else {
310
+ textarea.value = textarea.value.replace(`, ${tag}`, '')
311
+ }
312
+
313
+ updateInput(textarea)
314
+ }
315
+ }
316
+
317
+ onUiLoaded(async () => {
318
+ yaml = window.jsyaml
319
+ const easyPromptSelector = new EasyPromptSelector(yaml, gradioApp())
320
+
321
+ const button = EPSElementBuilder.openButton({
322
+ onClick: () => {
323
+ const tagArea = gradioApp().querySelector(`#${easyPromptSelector.AREA_ID}`)
324
+ easyPromptSelector.changeVisibility(tagArea, easyPromptSelector.visible = !easyPromptSelector.visible)
325
+ }
326
+ })
327
+
328
+ const reloadButton = gradioApp().getElementById('easy_prompt_selector_reload_button')
329
+ reloadButton.addEventListener('click', async () => {
330
+ await easyPromptSelector.init()
331
+ })
332
+
333
+ const txt2imgActionColumn = gradioApp().getElementById('txt2img_actions_column')
334
+ const container = document.createElement('div')
335
+ container.classList.add('easy_prompt_selector_container')
336
+ container.appendChild(button)
337
+ container.appendChild(reloadButton)
338
+
339
+ txt2imgActionColumn.appendChild(container)
340
+
341
+ await easyPromptSelector.init()
342
+ })