Mattthew commited on
Commit
42b75a8
1 Parent(s): 214046a

adding prompt builder feature

Browse files
Files changed (3) hide show
  1. index.css +379 -6
  2. index.html +96 -37
  3. index.js +473 -41
index.css CHANGED
@@ -23,6 +23,7 @@ h4 {
23
  display: flex;
24
  flex-direction: column;
25
  height: 100%;
 
26
  }
27
 
28
  #rows {
@@ -37,14 +38,14 @@ h4 {
37
  top: 0;
38
  left: 0;
39
  width: calc(40% + 20px);
40
- height: 100%;
41
  display: flex;
42
  flex-direction: column;
43
  flex-wrap: wrap;
44
  opacity: 1;
45
  line-height: 140%;
46
  box-sizing: border-box;
47
- padding: 20px;
48
  overflow: auto;
49
  transition: opacity 50ms 100ms linear;
50
  }
@@ -272,10 +273,11 @@ label.no_matches {
272
  }
273
 
274
  label.category {
 
275
  color: #00d5c0;
276
  font-weight: bold;
277
  padding-bottom: 5px;
278
- margin: 10px 40px 0 0;
279
  border-bottom: 1px solid #333;
280
  opacity: 1;
281
  }
@@ -576,12 +578,11 @@ input[type="checkbox"]:checked::before {
576
  color: #ffe300;
577
  font-size: 12px;
578
  font-weight: bold;
579
- transition: opacity 100ms 200ms linear;
580
  }
581
 
582
  .information_section .buttons div:hover {
583
  opacity: 1;
584
- transition: opacity 100ms 0ms linear;
585
  }
586
 
587
  #info_search_input {
@@ -1023,6 +1024,378 @@ input[type="checkbox"]:checked::before {
1023
  display: none;
1024
  }
1025
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1026
  #layout.edit_mode #edit_most_used {
1027
  font-weight: bold;
1028
  color: #ff0000;
@@ -1072,4 +1445,4 @@ input[type="checkbox"]:checked::before {
1072
 
1073
  #layout.edit_mode #favorite_label {
1074
  cursor: default;
1075
- }
 
23
  display: flex;
24
  flex-direction: column;
25
  height: 100%;
26
+ overflow: hidden;
27
  }
28
 
29
  #rows {
 
38
  top: 0;
39
  left: 0;
40
  width: calc(40% + 20px);
41
+ height: calc(100% - 55px);
42
  display: flex;
43
  flex-direction: column;
44
  flex-wrap: wrap;
45
  opacity: 1;
46
  line-height: 140%;
47
  box-sizing: border-box;
48
+ padding: 20px 20px 60px 20px;
49
  overflow: auto;
50
  transition: opacity 50ms 100ms linear;
51
  }
 
273
  }
274
 
275
  label.category {
276
+ height: initial;
277
  color: #00d5c0;
278
  font-weight: bold;
279
  padding-bottom: 5px;
280
+ margin: 10px 40px 5px 0;
281
  border-bottom: 1px solid #333;
282
  opacity: 1;
283
  }
 
578
  color: #ffe300;
579
  font-size: 12px;
580
  font-weight: bold;
 
581
  }
582
 
583
  .information_section .buttons div:hover {
584
  opacity: 1;
585
+ transition: opacity 100ms linear;
586
  }
587
 
588
  #info_search_input {
 
1024
  display: none;
1025
  }
1026
 
1027
+ #prompt_builder {
1028
+ display: flex;
1029
+ flex-direction: column;
1030
+ gap: 10px;
1031
+ position: relative;
1032
+ z-index: 2;
1033
+ height: 54px;
1034
+ padding: 10px;
1035
+ border-top: 1px solid #333;
1036
+ box-sizing: border-box;
1037
+ background-color: #000;
1038
+ transition: height 100ms 0ms ease-out;
1039
+ }
1040
+
1041
+ #prompt_builder.show {
1042
+ height: 97px;
1043
+ transition: height 200ms 200ms ease-out;
1044
+ }
1045
+
1046
+ #prompt_selector {
1047
+ display: flex;
1048
+ flex-direction: row;
1049
+ align-items: center;
1050
+ cursor: pointer;
1051
+ }
1052
+
1053
+ #prompt_selector > div {
1054
+ display: flex;
1055
+ flex-direction: row;
1056
+ gap: 10px;
1057
+ align-items: center;
1058
+ flex-grow: 1;
1059
+ font-size: 12px;
1060
+ overflow: scroll;
1061
+ -ms-overflow-style: none; /* IE and Edge */
1062
+ scrollbar-width: none; /* Firefox */
1063
+ }
1064
+
1065
+ #prompt_selector div::-webkit-scrollbar {
1066
+ display: none; /* Chrome, Safari and Opera */
1067
+ }
1068
+
1069
+ #prompt_builder_title {
1070
+ padding-left: 9px;
1071
+ color: #777;
1072
+ white-space: nowrap;
1073
+ cursor: default;
1074
+ }
1075
+
1076
+ .prompt_artist {
1077
+ display: flex;
1078
+ gap: 5px;
1079
+ align-items: center;
1080
+ flex-direction: row;
1081
+ padding: 5px 5px;
1082
+ border-radius: 50px;
1083
+ border: 1px solid #333;
1084
+ background-color: #222;
1085
+ }
1086
+
1087
+ .prompt_artist_count {
1088
+ width: 20px;
1089
+ text-align: center;
1090
+ border-radius: 50px;
1091
+ white-space: nowrap;
1092
+ color: #ffe300;
1093
+ font-weight: bold;
1094
+ cursor: default;
1095
+ }
1096
+
1097
+ .prompt_artist_left,
1098
+ .prompt_artist_right,
1099
+ .prompt_artist_remove {
1100
+ padding: 0px 6px;
1101
+ opacity: 0.8;
1102
+ border: 1px solid rgba(0, 255, 230, 0.5);
1103
+ border-radius: 50px;
1104
+ cursor: pointer;
1105
+ white-space: nowrap;
1106
+ background-color: black;
1107
+ color: #00ffe6;
1108
+ font-weight: bold;
1109
+ }
1110
+
1111
+ .prompt_artist_left:hover,
1112
+ .prompt_artist_right:hover,
1113
+ .prompt_artist_remove:hover {
1114
+ opacity: 1;
1115
+ transition: opacity 100ms linear;
1116
+ }
1117
+
1118
+ #prompt_artist_add {
1119
+ display: flex;
1120
+ align-items: center;
1121
+ cursor: pointer;
1122
+ }
1123
+ #prompt_artist_add div {
1124
+ padding: 0px 10px;
1125
+ border: 2px solid rgba(0, 255, 230, 0.5);
1126
+ border-radius: 50px;
1127
+ color: #00ffe6;
1128
+ white-space: nowrap;
1129
+ opacity: 0.7;
1130
+ }
1131
+ #prompt_artist_add:hover div {
1132
+ opacity: 1;
1133
+ }
1134
+
1135
+ .prompt_artist_remove {
1136
+ border-color: rgba(222, 0, 0, 0.5);
1137
+ color: #f00;
1138
+ }
1139
+
1140
+ .prompt_artist_remove span {
1141
+ display: block;
1142
+ }
1143
+
1144
+ .prompt_artist_intensity,
1145
+ .prompt_artist_combine {
1146
+ display: flex;
1147
+ align-items: center;
1148
+ gap: 5px;
1149
+ height: 21px;
1150
+ position: relative;
1151
+ border: 1px solid #00ffe6;
1152
+ border-radius: 50px;
1153
+ box-sizing: border-box;
1154
+ padding: 0px 10px;
1155
+ cursor: pointer;
1156
+ background-color: rgba(0, 255, 230, 0.2);
1157
+ opacity: 0.8;
1158
+ }
1159
+
1160
+ .prompt_artist_intensity:hover,
1161
+ .prompt_artist_combine:hover {
1162
+ opacity: 1;
1163
+ }
1164
+
1165
+ .prompt_artist_intensity::after,
1166
+ .prompt_artist_combine::after {
1167
+ content: '';
1168
+ min-width: 10px;
1169
+ height: 6px;
1170
+ background-color: #00ffe6;
1171
+ clip-path: polygon(5% 0, 95% 0, 100% 15%, 55% 100%, 45% 100%, 0 15%);
1172
+ position: relative;
1173
+ z-index: 0;
1174
+ left: -15px;
1175
+ margin-right: -15px;
1176
+ /* the arrow isn't clickable, so we position it over the select */
1177
+ /* and the selects' min-widths proves extra space for it */
1178
+ }
1179
+
1180
+ .prompt_artist select {
1181
+ appearance: none;
1182
+ position: relative;
1183
+ z-index: 1;
1184
+ width: 100%;
1185
+ height: 21px;
1186
+ margin: 0;
1187
+ padding: 0 1px 0 0;
1188
+ border: none;
1189
+ outline: none;
1190
+ background-color: transparent;
1191
+ color: #00d5c0;
1192
+ font-family: inherit;
1193
+ font-size: inherit;
1194
+ cursor: inherit;
1195
+ }
1196
+
1197
+ .prompt_artist select::-ms-expand {
1198
+ display: none;
1199
+ }
1200
+
1201
+ .prompt_artist_intensity select {
1202
+ min-width: 4ch;
1203
+ }
1204
+
1205
+ .prompt_artist_combine select {
1206
+ min-width: 7ch;
1207
+ }
1208
+
1209
+ .prompt_artist input {
1210
+ width: 150px;
1211
+ height: 21px;
1212
+ border: 1px solid #ffe300;
1213
+ border-radius: 50px;
1214
+ box-sizing: border-box;
1215
+ padding: 0px 10px;
1216
+ background-color: rgba(255, 227, 0, 0.2);
1217
+ color: #ffe300;
1218
+ font-family: inherit;
1219
+ font-size: inherit;
1220
+ opacity: 0.8;
1221
+ }
1222
+
1223
+ .prompt_artist input:focus{
1224
+ outline: none;
1225
+ border-width: 2px;
1226
+ opacity: 1;
1227
+ }
1228
+
1229
+ .prompt_artist input:hover {
1230
+ opacity: 1;
1231
+ }
1232
+
1233
+ .prompt_artist input:valid {
1234
+ border-color: #00ffe6;
1235
+ background-color: #00ffe62e;
1236
+ color: #00ffe6;
1237
+ }
1238
+
1239
+ #prompt_artist_search {
1240
+ display: none;
1241
+ width: 180px;
1242
+ max-height: 100px;
1243
+ overflow-y: scroll;
1244
+ position: absolute;
1245
+ left: 0;
1246
+ bottom: 91px;
1247
+ border-radius: 10px;
1248
+ border: 1px solid #333;
1249
+ box-sizing: border-box;
1250
+ padding: 10px;
1251
+ background-color: #222;
1252
+ box-shadow: 0 5px 10px #00000090;
1253
+ font-size: 12px;
1254
+ opacity: 0;
1255
+ transition: left 200ms ease-out;
1256
+ }
1257
+
1258
+ #prompt_artist_search.show {
1259
+ display: block;
1260
+ opacity: 1;
1261
+ }
1262
+
1263
+ #prompt_artist_search div {
1264
+ opacity: 0.5;
1265
+ cursor: pointer;
1266
+ }
1267
+
1268
+ #prompt_artist_search div:hover {
1269
+ opacity: 0.8;
1270
+ }
1271
+
1272
+ #prompt_builder #prompt_builder_hide {
1273
+ visibility: hidden;
1274
+ flex-grow: 0;
1275
+ width: 33px;
1276
+ height: 33px;
1277
+ padding: 0 9px;
1278
+ box-sizing: border-box;
1279
+ cursor: pointer;
1280
+ color: #00ffe6;
1281
+ overflow: hidden;
1282
+ box-shadow: -5px 0 5px #000000;
1283
+ transition: visibility 0ms 500ms;
1284
+ }
1285
+
1286
+ #prompt_builder #prompt_builder_hide::after {
1287
+ content: '';
1288
+ max-width: 14px;
1289
+ height: 8px;
1290
+ clip-path: polygon(5% 0, 95% 0, 100% 15%, 55% 100%, 45% 100%, 0 15%);
1291
+ background-color: #00ffe6;
1292
+ padding: 0 9px;
1293
+ }
1294
+
1295
+ #prompt_builder.show #prompt_builder_hide {
1296
+ visibility: visible;
1297
+ opacity: 0.8;
1298
+ }
1299
+
1300
+ #prompt_builder.show #prompt_builder_hide:hover {
1301
+ opacity: 1;
1302
+ }
1303
+
1304
+ #prompt_result {
1305
+ display: flex;
1306
+ flex-direction: row;
1307
+ gap: 10px;
1308
+ font-size: 12px;
1309
+ }
1310
+
1311
+ #prompt_result > div {
1312
+ display: flex;
1313
+ position: relative;
1314
+ flex-grow: 1;
1315
+ align-items: center;
1316
+ height: 33px;
1317
+ max-width: calc(100% - 135px);
1318
+ overflow-x: scroll;
1319
+ padding: 0 5px;
1320
+ border-radius: 50px;
1321
+ box-sizing: border-box;
1322
+ border: 1px solid #333;
1323
+ background-color: #222;
1324
+ color: rgb(160,160,160);
1325
+ white-space: nowrap;
1326
+ opacity: 1;
1327
+ -ms-overflow-style: none; /* IE and Edge */
1328
+ scrollbar-width: none; /* Firefox */
1329
+ }
1330
+
1331
+ #prompt_result div::-webkit-scrollbar {
1332
+ display: none; /* Chrome, Safari and Opera */
1333
+ }
1334
+
1335
+ #prompt_result > div::after {
1336
+ content: 'press the / key for more info about this prompt';
1337
+ opacity: 0;
1338
+ display: block;
1339
+ visibility: hidden;
1340
+ position: absolute;
1341
+ bottom: 5px;
1342
+ right: 15px;
1343
+ padding: 2px 10px;
1344
+ border-radius: 50px;
1345
+ background-color: #222;
1346
+ box-shadow: 0 0 10px #222;
1347
+ color: #777;
1348
+ }
1349
+
1350
+ #prompt_result > div:first-child:hover::after {
1351
+ visibility: visible;
1352
+ opacity: 1;
1353
+ transition: opacity 50ms 1000ms linear;
1354
+ }
1355
+
1356
+ #prompt_result b {
1357
+ font-style: normal;
1358
+ font-weight: bold;
1359
+ color: #00ffe6;
1360
+ margin: 0 4px;
1361
+ }
1362
+
1363
+ #prompt_result i {
1364
+ font-style: normal;
1365
+ font-weight: bold;
1366
+ color: #ffe300;
1367
+ margin: 0 4px;
1368
+ }
1369
+
1370
+ #prompt_result #prompt_result_editable {
1371
+ font-style: normal;
1372
+ font-weight: bold;
1373
+ margin: 0 4px;
1374
+ }
1375
+
1376
+ #prompt_result:hover #prompt_result_editable {
1377
+ color: rgb(255,255,255);
1378
+ }
1379
+
1380
+ #prompt_result #prompt_result_copy {
1381
+ flex-grow: 0;
1382
+ display: flex;
1383
+ align-items: center;
1384
+ padding: 0 8px;
1385
+ border-radius: 4px;
1386
+ cursor: pointer;
1387
+ white-space: nowrap;
1388
+ background-color: #ffe300;
1389
+ color: #000;
1390
+ font-weight: bold;
1391
+ opacity: 0.8;
1392
+ }
1393
+
1394
+ #prompt_result #prompt_result_copy:hover {
1395
+ opacity: 1;
1396
+ transition: opacity 100ms linear;
1397
+ }
1398
+
1399
  #layout.edit_mode #edit_most_used {
1400
  font-weight: bold;
1401
  color: #ff0000;
 
1445
 
1446
  #layout.edit_mode #favorite_label {
1447
  cursor: default;
1448
+ }
index.html CHANGED
@@ -94,12 +94,71 @@
94
  -->
95
  </div>
96
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97
  </div>
98
  <div id="information">
99
  <div id="info_switcher">
100
  <h2 id="info_actions" class="selected">🔍&nbsp;&nbsp;&nbsp;actions</h2>
101
  <h2 id="info_help">📓&nbsp;&nbsp;&nbsp;manual</h2>
102
- <h2 id="info_tips">📸&nbsp;&nbsp;&nbsp;tips</h2>
103
  <h2 id="info_about">💫&nbsp;&nbsp;&nbsp;about</h2>
104
  <h2 id="info_export">📤&nbsp;&nbsp;&nbsp;export</h2>
105
  <h2 id="info_closer">ESC</h2>
@@ -110,7 +169,7 @@
110
  <div id="random-tags">see some random tags</div>
111
  <div id="copy-all-names">copy visible artist names</div>
112
  </div>
113
- <input type="text" id="info_search_input" name="info_search_input" value="" data-match="" placeholder="search for tags" autocomplete="off">
114
  <div id="info_search_output"></div>
115
  </div>
116
  <div id="information_help" class="information_section">
@@ -143,35 +202,54 @@
143
  <ul>
144
  <li>Click <strong>edit</strong> under the important category to add or remove tags</li>
145
  </ul>
 
 
 
 
 
 
146
  <h3>✍️ Offline tag-editing</h3>
147
  <ul>
148
  <li>If you are viewing this from Hugging Face, your tag edits won't be applied. They'll be saved and applied if you've downloaded the repository and are viewing your local file. In both cases, your edits will be available for export 📥 as text. If you want to suggest tag improvements for everyone's benefit, edit tags, copy the text from 📥, and post it as a comment to Hugging Face. I will incorporate accurate edits ASAP. Thank you for contributing!</li>
149
  </ul>
 
 
 
 
150
  </div>
151
  </div>
152
  <div id="information_tips" class="information_section">
153
  <div>
154
- <h3>Prompting artist styles with SDXL</h3>
155
  <ul>
156
- <li>I recommend this 3-section prompt (auto1111 syntax):
 
 
157
  <ul>
158
- <li><b>(</b><i>style stuff</i><b>:1.5)</b>, <b>(</b>an image<b>:0.5)</b>, <b>(</b><i>content stuff</i><b>:1.0)</b></li>
159
- </ul>
160
- </li>
161
- <li>For example:
162
- <ul>
163
- <li>safest bet, needed for photographers:</li>
164
- <li><b>(</b>by <i>artist full name</i><b>:1.5)</b>, <b>(</b>an image<b>:0.5)</b>, <b>(</b>a landscape, water under a bridge<b>:1.0)</b></li>
165
- <li>stronger style, not for photographers:</li>
166
- <li><b>(</b>artwork in the style of <i>artist full name</i><b>:1.5)</b>, <b>(</b>an image<b>:0.5)</b>, <b>(</b>a landscape, water under a bridge<b>:1.0)</b></li>
 
 
 
 
 
 
 
167
  </ul>
168
  </li>
169
  </ul>
170
- <h3>Explanation of the 3-section prompt</h3>
171
  <ul>
172
- <li>The reason for this 3-section prompt is that it's very easy for common words to erase the style. For example, for some artists that never made portraits, using the word "portrait" in your prompt can erase their style, making the image style generic.</li>
173
- <li>To overcome this, we add weight to the <i>style stuff</i> and to remove weight from the <i>content stuff</i>. I recommend starting with 1.5 and 1.0 respectively, which gives slightly more weight to the style. As you edit the <i>content stuff</i>, if the style disappears, try other weights, e.g 2.0 and 0.5.</li>
174
- <li>The part in the middle "<b>(</b>an image<b>:0.5)</b>" doesn't change the output, but it's sometimes needed when the <i>content stuff</i> weight is less than 1.0. You can try removing it, and if your output looks garbled, try putting it back in.</li>
175
  </ul>
176
  <h3>An artist's style includes much more than their medium</h3>
177
  <ul>
@@ -185,32 +263,13 @@
185
  <li>This helps especially when the artist is famous for multiple mediums. But sometimes it reduces the artist's specific style and more matches the generic style of the medium.</li>
186
  <li>Also try adding the <strong>opposite</strong> medium/style to the <strong>negative</strong> prompt. For example, if the artist you want is a photographer, try "painting, illustration" in the negative prompt.</li>
187
  </ul>
188
- <h3>Combining the styles of multiple artists</h3>
189
- <ul>
190
- <li>I recommend either of these patterns (auto1111 syntax):
191
- <ul>
192
- <li><b>(</b>by <i>artist A</i>, by <i>artist B</i><b>:2.0)</b>, <i>the rest of the prompt</i></li>
193
- <li><b>(</b>by <b>[</b><i>artist A</i><b>|</b><i>artist B</i><b>]</b><b>:2.0)</b>, <i>the rest of the prompt</i></li>
194
- <li>Which is best depends on the artists. Try both!</li>
195
- </ul>
196
- </li>
197
- <li>To make one of the artists styles more dominant, make it first in the prompt. If it's still not strong enough repeat the artist's name. For example:<br>
198
- <b>[</b><i>artist A</i><b>|</b><i>artist A</i><b>|</b><i>artist B</i><b>]</b></li>
199
- <li>I've found that adding weight to one of the artists doesn't work, but your mileage may vary.
200
- </ul>
201
  <h3>Making non-photographic mediums look more photographic</h3>
202
  <ul>
203
- <li>It's worth trying "photograph by <i>illustration artist</i>" along with "illustration" in the negative prompt. But that often won't work.
204
  <li>It's also worth trying "<b>[</b><i>by artist A</i><b>:</b><i>style of photograph</i><b>:0.5]</b>". This will start with the artist style and switch to photograph style after 50% of the steps. Adjust the decimal as needed.</li>
205
  <li>I've had best results by sending the output to img2img, then replacing the artist's name in the prompt with "photograph", and setting the de-noise very low. Then feed the result back to img2img, and slowly nudge it towards photographic. That will at least maintain the composition.</li>
206
  <li>If Reference Controlnet for SDXL has been released, that should work well.</li>
207
  </ul>
208
- <h3>Why does the 🎨 prompt sometimes match the 🧑 or 🏞️ prompt?</h3>
209
- <ul>
210
- <li>
211
- The prompt used for the 🎨 images is the intentionally generic, "an image". If that results in a portrait, that's useful to know. It indicates that, for that artist, SDXL is more strongly trained to output portraits. Anything in your prompt that's not related to a person will harder to prompt for in that artist's style.
212
- </li>
213
- </ul>
214
  </div>
215
  </div>
216
  <div id="information_about" class="information_section">
 
94
  -->
95
  </div>
96
  </div>
97
+ <div id="prompt_builder">
98
+ <div id="prompt_artist_search"></div>
99
+ <div id="prompt_selector">
100
+ <div>
101
+ <div id="prompt_builder_title">build-a-prompt:</div>
102
+ <div class="prompt_artist">
103
+ <div class="prompt_artist_count">
104
+ <div>1</div>
105
+ </div>
106
+ <div class="prompt_artist_name">
107
+ <input type="text" value="" placeholder="search by name" autocomplete="off" required pattern=".+" title="you can also click an artist name to add them here" />
108
+ </div>
109
+ <div class="prompt_artist_intensity" title="the weight of this artist">
110
+ <select autocomplete="off">
111
+ <option value="1">✖ 1</option>
112
+ <option value="2">✖ 2</option>
113
+ <option value="3">✖ 3</option>
114
+ </select>
115
+ </div>
116
+ <div class="prompt_artist_combine" title="the method of combining, type / for more info">
117
+ <select autocomplete="off">
118
+ <option value="add">add</option>
119
+ <option value="loop">loop</option>
120
+ <option value="swap">swap</option>
121
+ </select>
122
+ </div>
123
+ <div class="prompt_artist_left" title="move an artist left to give them more weight">
124
+ <div><</div>
125
+ </div>
126
+ <div class="prompt_artist_right" title="move an artist right to give them less weight">
127
+ <div>></div>
128
+ </div>
129
+ <div class="prompt_artist_remove" title="remove this artist from the prompt">
130
+ <span>X</span>
131
+ </div>
132
+ </div>
133
+ <div id="prompt_artist_add">
134
+ <div>
135
+ <span>add another</span>
136
+ </div>
137
+ </div>
138
+ </div>
139
+ <div id="prompt_builder_hide"></div>
140
+ </div>
141
+ <div id="prompt_result">
142
+ <div>
143
+ <span>
144
+ <b>(</b>artwork in the style of <i>[</i>name<i>|</i>name<i>]</i><b>:1.5)</b>,
145
+ </span>
146
+ <span>
147
+ <b>(</b>an image<b>:0.5)</b>,
148
+ </span>
149
+ <span>
150
+ <b>(</b><span id="prompt_result_editable" contenteditable="true"></span><b>:1.0)</b>
151
+ </span>
152
+ </div>
153
+ <div id="prompt_result_copy">copy this prompt</div>
154
+ </div>
155
+ </div>
156
  </div>
157
  <div id="information">
158
  <div id="info_switcher">
159
  <h2 id="info_actions" class="selected">🔍&nbsp;&nbsp;&nbsp;actions</h2>
160
  <h2 id="info_help">📓&nbsp;&nbsp;&nbsp;manual</h2>
161
+ <h2 id="info_tips">📸&nbsp;&nbsp;&nbsp;prompts</h2>
162
  <h2 id="info_about">💫&nbsp;&nbsp;&nbsp;about</h2>
163
  <h2 id="info_export">📤&nbsp;&nbsp;&nbsp;export</h2>
164
  <h2 id="info_closer">ESC</h2>
 
169
  <div id="random-tags">see some random tags</div>
170
  <div id="copy-all-names">copy visible artist names</div>
171
  </div>
172
+ <input type="text" id="info_search_input" name="info_search_input" value="" placeholder="search for tags" autocomplete="off">
173
  <div id="info_search_output"></div>
174
  </div>
175
  <div id="information_help" class="information_section">
 
202
  <ul>
203
  <li>Click <strong>edit</strong> under the important category to add or remove tags</li>
204
  </ul>
205
+ <h3>Why does the 🎨 prompt sometimes match the 🧑 or 🏞️ prompt?</h3>
206
+ <ul>
207
+ <li>
208
+ The prompt used for the 🎨 images is the intentionally generic, "an image". If that results in a portrait, that's useful to know. It indicates that, for that artist, SDXL is more strongly trained to output portraits. Anything in your prompt that's not related to a person will harder to prompt for in that artist's style.
209
+ </li>
210
+ </ul>
211
  <h3>✍️ Offline tag-editing</h3>
212
  <ul>
213
  <li>If you are viewing this from Hugging Face, your tag edits won't be applied. They'll be saved and applied if you've downloaded the repository and are viewing your local file. In both cases, your edits will be available for export 📥 as text. If you want to suggest tag improvements for everyone's benefit, edit tags, copy the text from 📥, and post it as a comment to Hugging Face. I will incorporate accurate edits ASAP. Thank you for contributing!</li>
214
  </ul>
215
+ <h3>Build a prompt</h3>
216
+ <ul>
217
+ <li>See 📸 prompts</li>
218
+ </ul>
219
  </div>
220
  </div>
221
  <div id="information_tips" class="information_section">
222
  <div>
223
+ <h3>Building prompts from artist styles</h3>
224
  <ul>
225
+ <li>Build-a-prompt uses auto1111 syntax, and it creates a 3-section prompt:</li>
226
+ <li><b>(</b><i>artist stuff</i><b>:1.5)</b>, <b>(</b>an image<b>:0.5)</b>, <b>(</b><i>your prompt words</i><b>:1.0)</b></li>
227
+ <li>Options:
228
  <ul>
229
+ <li><strong>Intensity:</strong>
230
+ <ul>
231
+ <li>i.e. ✖1, ✖2, ✖3, gives more weight to a style by repeating the artist's name. This works better than using prompt weighting</li>
232
+ </ul>
233
+ </li>
234
+ <li><strong>Mixing method:</strong>
235
+ <ul>
236
+ <li><strong>Add:</strong> puts all the artists' names in the prompt separated by a comma. Usually the best choice. Try 'add' and 'loop' and see which works better.</li>
237
+ <li><strong>Loop:</strong> uses a1111 syntax for alternating the prompt at each step. This alternates which artist's name appears in the prompt. If an artist's name is repeated, then it's repeat for multiple steps.</li>
238
+ <li><strong>Swap:</strong> uses a1111 syntax to swap the prompt after a fraction of the total steps. This swaps the artist's name after 50% of steps by default. You can change this fraction. For example, <b>[</b>A<b>:</b>B<b>:</b>0.1<b>]</b> switches to B after 10% of all steps.</li>
239
+ </ul>
240
+ <li><strong>Move left and right:</strong>
241
+ <ul>
242
+ <li>tokens closest to the start of the prompt always have more influence. Therefore, moving an artist's name to the left adds weight to that style.</li>
243
+ </ul>
244
+ </li>
245
  </ul>
246
  </li>
247
  </ul>
248
+ <h3>Why this prompting method?</h3>
249
  <ul>
250
+ <li>The reason why build-a-prompt uses 3-sections is that it's very easy for common words in a prompt to erase an artist's style. For example, for some artists that never made any portraits, using the word "portrait" in your prompt can erase their style entirely.</li>
251
+ <li>To overcome this, we add weight to the <i>artist stuff</i> and to remove weight from the <i>rest of the prompt</i>. Built a prompt weights this at <b>1.5</b> and <b>1.0</b> respectively. This gives slightly more weight to the <i>artist stuff</i>. As you edit the <i>rest of the promt</i>, if the style disappears, adjust both numbers, e.g. try <b>2.0</b> and <b>0.5</b>.</li>
252
+ <li>The middle section, "<b>(</b>an image<b>:0.5)</b>" doesn't change the output at all. However, it's sometimes needed when the weight of the <i>rest of the prompt</i> weight is less than 1.</li>
253
  </ul>
254
  <h3>An artist's style includes much more than their medium</h3>
255
  <ul>
 
263
  <li>This helps especially when the artist is famous for multiple mediums. But sometimes it reduces the artist's specific style and more matches the generic style of the medium.</li>
264
  <li>Also try adding the <strong>opposite</strong> medium/style to the <strong>negative</strong> prompt. For example, if the artist you want is a photographer, try "painting, illustration" in the negative prompt.</li>
265
  </ul>
 
 
 
 
 
 
 
 
 
 
 
 
 
266
  <h3>Making non-photographic mediums look more photographic</h3>
267
  <ul>
268
+ <li>It's worth trying "photograph by <i>illustration artist</i>" along with "illustration" in the negative prompt. But that often won't work.</li>
269
  <li>It's also worth trying "<b>[</b><i>by artist A</i><b>:</b><i>style of photograph</i><b>:0.5]</b>". This will start with the artist style and switch to photograph style after 50% of the steps. Adjust the decimal as needed.</li>
270
  <li>I've had best results by sending the output to img2img, then replacing the artist's name in the prompt with "photograph", and setting the de-noise very low. Then feed the result back to img2img, and slowly nudge it towards photographic. That will at least maintain the composition.</li>
271
  <li>If Reference Controlnet for SDXL has been released, that should work well.</li>
272
  </ul>
 
 
 
 
 
 
273
  </div>
274
  </div>
275
  <div id="information_about" class="information_section">
index.js CHANGED
@@ -17,6 +17,8 @@ var startUpTime;
17
  var tagsConcatenated = new Set();
18
  var editedArtists = new Set();
19
  var storingAccessType = 'none';
 
 
20
  var start = performance.now();
21
  const lowCountThreshold = 3;
22
  //
@@ -52,6 +54,8 @@ async function startUp() {
52
  showHideLowCountTags();
53
  makeStyleRuleForDrag();
54
  teasePartition();
 
 
55
  addAllListeners();
56
  }
57
 
@@ -982,52 +986,43 @@ function showInformation(tab) {
982
 
983
  function searchForTagsInfo(event) {
984
  let input = document.getElementById('info_search_input');
985
- if(input.dataset.match != '') {
986
  event.preventDefault();
987
  if(event.key === 'Backspace' || event.keyCode === 8) {
988
  input.value = '';
989
- input.dataset.match = '';
990
  } else {
991
  input.value = input.dataset.match;
992
  }
993
- return;
994
- }
995
- let output = document.getElementById('info_search_output');
996
- output.innerHTML = '';
997
- let matches = 0;
998
- let match = '';
999
- let range = 'start'
1000
- let tags = document.querySelectorAll('#toggles label:not(.top_control):not(.category):not([data-is-in-category="other"]');
1001
- tags.forEach(function(tag) {
1002
- let tagName = tag.querySelector('input').name;
1003
- if(tagName.toLowerCase().indexOf(input.value.toLowerCase()) > -1) {
1004
- range = 'continue';
1005
- let label = tag.cloneNode(true);
1006
- label.addEventListener('change', function(e) {
1007
- toggleMatchingTag(this);
1008
- });
1009
- output.appendChild(label);
1010
- match = tagName;
1011
- matches++;
1012
- } else {
1013
- if(range != 'start') {
1014
- range = 'stop';
1015
  }
 
 
 
 
 
 
 
 
 
 
 
1016
  }
1017
- if(range == 'stop') {
1018
- return;
1019
- }
1020
- });
1021
- if(matches == 0) {
1022
- let noneFound = document.createElement('label');
1023
- noneFound.textContent = 'no matching tags';
1024
- output.appendChild(noneFound);
1025
- } else if(matches == 1) {
1026
- input.value = match;
1027
- event.preventDefault();
1028
- input.dataset.match = match;
1029
- } else {
1030
- sortInfoSearchTags(output);
1031
  }
1032
  }
1033
 
@@ -1499,7 +1494,7 @@ function enterExitEditMostUsedMode(doExit) {
1499
  // clean up classes added to track moved tags during edit mode
1500
  label.classList.remove('was_moved');
1501
  });
1502
- document.getElementById('toggles').style.width = 'calc(' + gutterEndPercentX + '% - 20px)';
1503
  document.getElementById('gutter').style.left = gutterEndPercentX + '%';
1504
  document.getElementById('image-container').style.marginLeft = 'calc(' + gutterEndPercentX + '% + 50px)';
1505
  updateArtistsCountPerCategory();
@@ -1699,6 +1694,17 @@ function copyStuffToClipboard(item,stuff) {
1699
  } else {
1700
  doAlert('No artists are visible!',1);
1701
  }
 
 
 
 
 
 
 
 
 
 
 
1702
  }
1703
  }
1704
 
@@ -1774,7 +1780,7 @@ function hideLowCountSingle(checkbox) {
1774
  // only present if the tag is below the hide threshhold but not hidden because the checkbox was checked
1775
  checkbox.parentNode.classList.add('hidden');
1776
  checkbox.parentNode.dataset.hideDeferred = false;
1777
- doAlert('low-use tag hidden',0);
1778
  }
1779
  }
1780
 
@@ -1869,7 +1875,7 @@ function movePartition(e) {
1869
  newPos = window.innerWidth - 350;
1870
  }
1871
  let gutterEndPercentX = (newPos / window.innerWidth) * 100;
1872
- document.getElementById('toggles').style.width = 'calc(' + gutterEndPercentX + '% - 20px)';
1873
  document.getElementById('gutter').style.left = gutterEndPercentX + '%';
1874
  document.getElementById('image-container').style.marginLeft = 'calc(' + gutterEndPercentX + '% + 50px)';
1875
  imgHoverRule.style.width = gutterEndPercentX + '%';
@@ -2185,6 +2191,409 @@ function deleteAllEdits() {
2185
  }
2186
  }
2187
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2188
  function addAllListeners() {
2189
  // global
2190
  document.addEventListener('keydown', function(event) {
@@ -2436,6 +2845,7 @@ function addAllListeners() {
2436
  });
2437
  imageItem.getElementsByTagName('h3')[0].addEventListener('click', function(e) {
2438
  copyStuffToClipboard(this,'name');
 
2439
  });
2440
  imageItem.getElementsByTagName('h4')[0].addEventListener('click', function(e) {
2441
  if(!this.classList.contains('edit_mode')) {
@@ -2455,4 +2865,26 @@ function addAllListeners() {
2455
  gutter.removeEventListener('mousemove', movePartition, false);
2456
  }, false);
2457
  }, false);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2458
  }
 
17
  var tagsConcatenated = new Set();
18
  var editedArtists = new Set();
19
  var storingAccessType = 'none';
20
+ // the longer prompt is better for non-photographers
21
+ var promptStyleWords = ['artwork in the style of','by|||']
22
  var start = performance.now();
23
  const lowCountThreshold = 3;
24
  //
 
54
  showHideLowCountTags();
55
  makeStyleRuleForDrag();
56
  teasePartition();
57
+ promptBuilderAddArtist(true);
58
+ updatePromptBuilderParts();
59
  addAllListeners();
60
  }
61
 
 
986
 
987
  function searchForTagsInfo(event) {
988
  let input = document.getElementById('info_search_input');
989
+ if(input.dataset.match !== undefined) {
990
  event.preventDefault();
991
  if(event.key === 'Backspace' || event.keyCode === 8) {
992
  input.value = '';
993
+ delete input.dataset.match;
994
  } else {
995
  input.value = input.dataset.match;
996
  }
997
+ } else {
998
+ let matches = 0;
999
+ let output = document.getElementById('info_search_output');
1000
+ output.innerHTML = '';
1001
+ let match = '';
1002
+ let tags = document.querySelectorAll('#toggles label:not(.top_control):not(.category):not([data-is-in-category="other"]');
1003
+ tags.forEach(function(tag) {
1004
+ let tagName = tag.querySelector('input').name;
1005
+ if(tagName.toLowerCase().indexOf(input.value.toLowerCase()) > -1) {
1006
+ let label = tag.cloneNode(true);
1007
+ label.addEventListener('change', function(e) {
1008
+ toggleMatchingTag(this);
1009
+ });
1010
+ output.appendChild(label);
1011
+ match = tagName;
1012
+ matches++;
 
 
 
 
 
 
1013
  }
1014
+ });
1015
+ if(matches == 0) {
1016
+ let noneFound = document.createElement('label');
1017
+ noneFound.textContent = 'no matching tags';
1018
+ output.appendChild(noneFound);
1019
+ } else if(matches == 1) {
1020
+ input.value = match;
1021
+ event.preventDefault();
1022
+ input.dataset.match = match;
1023
+ } else {
1024
+ // sortInfoSearchTags(output);
1025
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1026
  }
1027
  }
1028
 
 
1494
  // clean up classes added to track moved tags during edit mode
1495
  label.classList.remove('was_moved');
1496
  });
1497
+ document.getElementById('toggles').style.width = 'calc(' + gutterEndPercentX + '% + 20px)';
1498
  document.getElementById('gutter').style.left = gutterEndPercentX + '%';
1499
  document.getElementById('image-container').style.marginLeft = 'calc(' + gutterEndPercentX + '% + 50px)';
1500
  updateArtistsCountPerCategory();
 
1694
  } else {
1695
  doAlert('No artists are visible!',1);
1696
  }
1697
+ } else if(stuff == 'prompt') {
1698
+ let prompt_result = document.getElementById('prompt_result').querySelector('div');
1699
+ let prompt = prompt_result.innerText.trim();
1700
+ prompt = prompt.replace(/(\r\n|\n|\r)/gm, '');
1701
+ navigator.clipboard.writeText(prompt)
1702
+ .then(() => {
1703
+ doAlert('Copied prompt to clipboard!',1);
1704
+ })
1705
+ .catch(() => {
1706
+ doAlert('😭😭 Can\'t access clipboard',1);
1707
+ });
1708
  }
1709
  }
1710
 
 
1780
  // only present if the tag is below the hide threshhold but not hidden because the checkbox was checked
1781
  checkbox.parentNode.classList.add('hidden');
1782
  checkbox.parentNode.dataset.hideDeferred = false;
1783
+ doAlert('Low-use tag hidden',0);
1784
  }
1785
  }
1786
 
 
1875
  newPos = window.innerWidth - 350;
1876
  }
1877
  let gutterEndPercentX = (newPos / window.innerWidth) * 100;
1878
+ document.getElementById('toggles').style.width = 'calc(' + gutterEndPercentX + '% + 20px)';
1879
  document.getElementById('gutter').style.left = gutterEndPercentX + '%';
1880
  document.getElementById('image-container').style.marginLeft = 'calc(' + gutterEndPercentX + '% + 50px)';
1881
  imgHoverRule.style.width = gutterEndPercentX + '%';
 
2191
  }
2192
  }
2193
 
2194
+ function promptBuilderAddArtist(isStart) {
2195
+ let ogPart = document.querySelector('.prompt_artist');
2196
+ let part = ogPart.cloneNode(true);
2197
+ document.querySelector('#prompt_artist_add').before(part);
2198
+ let input = part.querySelector('.prompt_artist_name input');
2199
+ input.value = '';
2200
+ delete input.dataset.match;
2201
+ delete input.dataset.isPhoto;
2202
+ input.addEventListener('focus', function(e) {
2203
+ this.dataset.hasFocus = 'yes';
2204
+ setXPosOfSearchOutput();
2205
+ });
2206
+ input.addEventListener('keyup', function(e) {
2207
+ promptBuilderSearch(this,e);
2208
+ });
2209
+ input.addEventListener('blur', function(e) {
2210
+ // need to give time for search result row click event
2211
+ timer = setTimeout(promptBuilderBlur.bind(this, this), 100);
2212
+ if(this.dataset.match === undefined) {
2213
+ this.value = '';
2214
+ }
2215
+ });
2216
+ let intensity = part.querySelector('.prompt_artist_intensity select');
2217
+ intensity.selectedIndex = 'x1';
2218
+ intensity.addEventListener('change', function(e) {
2219
+ writePrompt();
2220
+ });
2221
+ let combine = part.querySelector('.prompt_artist_combine select');
2222
+ combine.selectedIndex = 'mix';
2223
+ combine.addEventListener('change', function(e) {
2224
+ writePrompt();
2225
+ });
2226
+ let remove = part.querySelector('.prompt_artist_remove');
2227
+ remove.addEventListener('click', function(e) {
2228
+ promptBuilderRemoveArtist(this);
2229
+ writePrompt();
2230
+ });
2231
+ let left = part.querySelector('.prompt_artist_left');
2232
+ left.addEventListener('click', function(e) {
2233
+ promptBuilderMove(this.parentNode,'left');
2234
+ writePrompt();
2235
+ });
2236
+ let right = part.querySelector('.prompt_artist_right');
2237
+ right.addEventListener('click', function(e) {
2238
+ promptBuilderMove(this.parentNode,'right');
2239
+ writePrompt();
2240
+ });
2241
+ if(isStart) {
2242
+ // start copies then removes the HTML part so that
2243
+ // the event listeners don't need defined twice in the code
2244
+ ogPart.remove();
2245
+ }
2246
+ updatePromptBuilderParts();
2247
+ writePrompt();
2248
+ }
2249
+
2250
+ function promptBuilderBlur(input) {
2251
+ delete input.dataset.hasFocus;
2252
+ document.getElementById('prompt_artist_search').classList.remove('show');
2253
+ writePrompt();
2254
+ }
2255
+
2256
+ function updatePromptBuilderParts() {
2257
+ let count = 1;
2258
+ let parts = Array.from(document.querySelectorAll('.prompt_artist'));
2259
+ if(parts.length == 1) {
2260
+ let part = parts[0];
2261
+ let intensity = part.querySelector('.prompt_artist_intensity');
2262
+ let combine = part.querySelector('.prompt_artist_combine');
2263
+ let left = part.querySelector('.prompt_artist_left');
2264
+ let right = part.querySelector('.prompt_artist_right');
2265
+ let remove = part.querySelector('.prompt_artist_remove');
2266
+ intensity.style.display = 'none';
2267
+ combine.style.display = 'none';
2268
+ left.style.display = 'none';
2269
+ right.style.display = 'none';
2270
+ remove.style.display = 'none';
2271
+ } else {
2272
+ for(i=0,il=parts.length; i<il; i++) {
2273
+ let part = parts[i];
2274
+ let countEl = part.querySelector('.prompt_artist_count div');
2275
+ let intensity = part.querySelector('.prompt_artist_intensity');
2276
+ let combine = part.querySelector('.prompt_artist_combine');
2277
+ let left = part.querySelector('.prompt_artist_left');
2278
+ let right = part.querySelector('.prompt_artist_right');
2279
+ let remove = part.querySelector('.prompt_artist_remove');
2280
+ countEl.textContent = count;
2281
+ count++;
2282
+ intensity.style.display = '';
2283
+ combine.style.display = '';
2284
+ left.style.display = '';
2285
+ right.style.display = '';
2286
+ remove.style.display = '';
2287
+ if(i==0) {
2288
+ left.style.display = 'none';
2289
+ combine.style.display = 'none';
2290
+ if(il==1) {
2291
+ right.style.display = 'none';
2292
+ }
2293
+ } else if(i==il-1) {
2294
+ right.style.display = 'none';
2295
+ }
2296
+ }
2297
+ }
2298
+ }
2299
+
2300
+ function promptBuilderMove(part,direction) {
2301
+ if(direction == 'left') {
2302
+ part.previousElementSibling.before(part);
2303
+ } else if(direction == 'right') {
2304
+ part.nextElementSibling.after(part);
2305
+ }
2306
+ updatePromptBuilderParts();
2307
+ }
2308
+
2309
+ function promptBuilderRemoveArtist(removeButton) {
2310
+ if(removeButton.textContent.trim() == 'X') {
2311
+ removeButton.textContent = 'again';
2312
+ timer = setTimeout(cleanupRemoveButton.bind(this, removeButton), 1000);
2313
+ } else {
2314
+ removeButton.parentNode.remove();
2315
+ updatePromptBuilderParts();
2316
+ }
2317
+ }
2318
+
2319
+ function cleanupRemoveButton(removeButton) {
2320
+ removeButton.textContent = 'X';
2321
+ }
2322
+
2323
+ function promptBuilderFillArtist(item,e) {
2324
+ var name = item.closest('.image-item').getElementsByClassName('firstN')[0].textContent +
2325
+ ' ' + item.closest('.image-item').getElementsByClassName('lastN')[0].textContent;
2326
+ let inputs = Array.from(document.querySelectorAll('.prompt_artist_name input'));
2327
+ for(i=0,il=inputs.length; i<il; i++) {
2328
+ if(inputs[i].value == '') {
2329
+ inputs[i].value = name;
2330
+ promptBuilderSearch(inputs[i],e);
2331
+ break;
2332
+ }
2333
+ }
2334
+ }
2335
+
2336
+ function promptBuilderHide() {
2337
+ document.querySelector('#prompt_builder').classList.remove('show');
2338
+ }
2339
+
2340
+ function promptBuilderShow() {
2341
+ document.querySelector('#prompt_builder').classList.add('show');
2342
+ }
2343
+
2344
+ function promptBuilderSearch(input,event) {
2345
+ if(input.dataset.match !== undefined) {
2346
+ event.preventDefault();
2347
+ if(event.key === 'Backspace' || event.keyCode === 8) {
2348
+ input.value = '';
2349
+ delete input.dataset.match;
2350
+ delete input.dataset.isPhoto;
2351
+ } else {
2352
+ input.value = input.dataset.match;
2353
+ }
2354
+ } else {
2355
+ let matches = 0;
2356
+ let output = document.getElementById('prompt_artist_search');
2357
+ output.innerHTML = '';
2358
+ let match = '';
2359
+ let isPhoto = false;
2360
+ for(i=0,il=artistsData.length; i<il; i++) {
2361
+ let artistName = artistsData[i][1] + ' ' + artistsData[i][0];
2362
+ if(artistName.toLowerCase().indexOf(input.value.toLowerCase()) > -1) {
2363
+ let outputRow = document.createElement('div');
2364
+ outputRow.textContent = artistName;
2365
+ outputRow.addEventListener('click', function(e) {
2366
+ let input = document.querySelector('input[data-has-focus="yes"]');
2367
+ input.value = this.textContent;
2368
+ promptBuilderSearch(input,e);
2369
+ input.focus();
2370
+ });
2371
+ output.appendChild(outputRow);
2372
+ matches++;
2373
+ match = artistName;
2374
+ if(artistsData[i][2].toLowerCase().indexOf('photography') > -1) {
2375
+ isPhoto = true;
2376
+ }
2377
+ }
2378
+ }
2379
+ if(matches == 0) {
2380
+ let noneFound = document.createElement('div');
2381
+ noneFound.textContent = 'no matching names';
2382
+ output.appendChild(noneFound);
2383
+ } else if(matches == 1) {
2384
+ input.value = match;
2385
+ event.preventDefault();
2386
+ input.dataset.match = match;
2387
+ if(isPhoto) {
2388
+ input.dataset.isPhoto = 'yes';
2389
+ } else {
2390
+ input.dataset.isPhoto = 'no';
2391
+ }
2392
+ output.classList.remove('show');
2393
+ writePrompt();
2394
+ } else {
2395
+ output.classList.add('show');
2396
+ promptBuilderSearchSortOutput(output);
2397
+ }
2398
+ }
2399
+ }
2400
+
2401
+ function debounceSetXPosOfSearchOutput(func, delay) {
2402
+ let debounceTimer;
2403
+ return function() {
2404
+ const context = this;
2405
+ const args = arguments;
2406
+ clearTimeout(debounceTimer);
2407
+ debounceTimer = setTimeout(() => func.apply(context, args), delay);
2408
+ };
2409
+ }
2410
+
2411
+ function setXPosOfSearchOutput() {
2412
+ let input = document.querySelector('.prompt_artist input:focus');
2413
+ if(input) {
2414
+ let output = document.getElementById('prompt_artist_search');
2415
+ let xPos = input.getBoundingClientRect().left;
2416
+ output.style.left = xPos + 'px';
2417
+ }
2418
+ }
2419
+
2420
+ function promptBuilderSearchSortOutput(output) {
2421
+ let rows = Array.from(output.querySelectorAll('div'));
2422
+ rows.sort(function(a, b) {
2423
+ var aValue = a.textContent;
2424
+ var bValue = b.textContent;
2425
+ return aValue.localeCompare(bValue);
2426
+ });
2427
+ rows.forEach(function(row) {
2428
+ output.appendChild(row);
2429
+ });
2430
+ }
2431
+
2432
+
2433
+ function writePrompt() {
2434
+ let prompt = '';
2435
+ let edited = true;
2436
+ let editable = document.querySelector('#prompt_result_editable').textContent.trim();
2437
+ let editMe = ['you can edit me','pick an artist, then edit me',''];
2438
+ if(editable == editMe[0] || editable == editMe[1] || editable == editMe[2]) {
2439
+ edited = false;
2440
+ }
2441
+ let parts = Array.from(document.querySelectorAll('.prompt_artist'));
2442
+ let nextCombine = 'start';
2443
+ let startAt = 0;
2444
+ let missingName = false;
2445
+ if(parts.length == 1) {
2446
+ let part = parts[0];
2447
+ let name = part.querySelector('input').value;
2448
+ if(name == '') {
2449
+ missingName = true;
2450
+ }
2451
+ let style = promptStyleWords[0];
2452
+ let isPhoto = part.querySelector('input').dataset.isPhoto;
2453
+ if(isPhoto == 'yes') {
2454
+ style = promptStyleWords[1];
2455
+ }
2456
+ if(name != '') {
2457
+ prompt = style + ' ' + name;
2458
+ }
2459
+ } else {
2460
+ for(pCount=1,pLength=parts.length; pCount<pLength; pCount++) {
2461
+ // i starts at 1 because first part's combine value is ignored
2462
+ let part = parts[pCount];
2463
+ let thisCombine = part.querySelector('.prompt_artist_combine select').value;
2464
+ if(parts[pCount+1]) {
2465
+ if(nextCombine == 'start') {
2466
+ nextCombine = parts[pCount+1].querySelector('.prompt_artist_combine select').value;
2467
+ }
2468
+ } else {
2469
+ nextCombine = 'end';
2470
+ }
2471
+ if(thisCombine != nextCombine || nextCombine == 'end' || thisCombine == 'swap') {
2472
+ if(thisCombine == 'loop') {
2473
+ prompt = '[' + prompt;
2474
+ } else if(thisCombine == 'swap') {
2475
+ prompt = '[' + prompt;
2476
+ }
2477
+ // loop through artists with matching combine
2478
+ for(j=startAt,jl=pCount+1; j<jl; j++) {
2479
+ part = parts[j];
2480
+ let name = part.querySelector('input').value;
2481
+ if(name == '') {
2482
+ missingName = true;
2483
+ break;
2484
+ }
2485
+ let style = promptStyleWords[0];
2486
+ let isPhoto = part.querySelector('input').dataset.isPhoto;
2487
+ if(isPhoto == 'yes') {
2488
+ style = promptStyleWords[1];
2489
+ }
2490
+ let intensityNum = parseInt(part.querySelector('.prompt_artist_intensity select').value);
2491
+ // repeat based on intensity
2492
+ for(k=0,kl=intensityNum; k<kl; k++) {
2493
+ if(thisCombine == 'add') {
2494
+ prompt += style + ' ' + name + ',';
2495
+ } else if(thisCombine == 'loop') {
2496
+ prompt += style + ' ' + name + '|';
2497
+ } else if(thisCombine == 'swap') {
2498
+ prompt += style + ' ' + name + ',';
2499
+ }
2500
+ }
2501
+ if(thisCombine == 'swap') {
2502
+ prompt = prompt.substring(0,prompt.length-1);
2503
+ prompt += ':';
2504
+ }
2505
+ }
2506
+ prompt = prompt.substring(0,prompt.length-1);
2507
+ if(thisCombine == 'loop') {
2508
+ prompt += ']'
2509
+ } else if(thisCombine == 'swap') {
2510
+ prompt += ':0.5]'
2511
+ }
2512
+ startAt = pCount;
2513
+ }
2514
+ }
2515
+ }
2516
+ if(missingName) {
2517
+ // no artists are selected
2518
+ if(!edited) {
2519
+ editable = editMe[1];
2520
+ }
2521
+ prompt = '<span id="prompt_result_editable" contenteditable="true">' + editable + '</span>';
2522
+ } else {
2523
+ // 1 or more artists selected
2524
+ if(!edited) {
2525
+ editable = editMe[0];
2526
+ }
2527
+ prompt = formatPrompt(prompt);
2528
+ prompt = '<span><b>(</b>' + prompt + '<b>:1.5)</b></span>, ' +
2529
+ '<span><b>(</b>an image<b>:0.5)</b>, </span>' +
2530
+ '<span><b>(</b><span id="prompt_result_editable" contenteditable="true">' + editable + '</span><b>:1.0)</b></span>';
2531
+ }
2532
+ document.querySelector('#prompt_result div').innerHTML = prompt;
2533
+ document.getElementById('prompt_result_editable').addEventListener('blur', function(e) {
2534
+ let str = this.innerText;
2535
+ this.innerHTML = str;
2536
+ });
2537
+
2538
+ }
2539
+
2540
+ function formatPrompt(prompt) {
2541
+ let promptArr = [];
2542
+ let style = promptStyleWords[0];
2543
+ if(prompt.indexOf(promptStyleWords[0]) > -1 && prompt.indexOf(promptStyleWords[1]) < 0) {
2544
+ // prompt contains only non-photographers
2545
+ // so use the style words for st
2546
+ promptArr = prompt.split(promptStyleWords[0]);
2547
+ /*
2548
+ } else if(prompt.indexOf(promptStyleWords[0]) < 0 && prompt.indexOf(promptStyleWords[1]) > -1) {
2549
+ // prompt contains only photographers
2550
+ promptArr = prompt.split(promptStyleWords[1]);
2551
+ style = promptStyleWords[1];
2552
+ */
2553
+ } else {
2554
+ // prompt contains only both photographers and non
2555
+ // using the shorter prompt event though it makes the style weaker
2556
+ // because it uses for fewer tokens for multiple artists
2557
+ let regStr = new RegExp(promptStyleWords[0],'g');
2558
+ prompt = prompt.replace(regStr,promptStyleWords[1]);
2559
+ promptArr = prompt.split(promptStyleWords[1]);
2560
+ style = promptStyleWords[1];
2561
+
2562
+ }
2563
+ if(promptArr.length > 0) {
2564
+ prompt = style + ' ';
2565
+ for(i=0,il=promptArr.length; i<il; i++) {
2566
+ prompt += promptArr[i];
2567
+ }
2568
+ }
2569
+ prompt = prompt.replace('|||','');
2570
+ prompt = prompt.replace(/\[ |\[/g,'<i>[</i>');
2571
+ prompt = prompt.replace(/\| |\|/g,'<i>|</i>');
2572
+ prompt = prompt.replace(/: |:/g,'<i>:</i>');
2573
+ prompt = prompt.replace(/]/g,'<i>]</i>');
2574
+ return prompt;
2575
+ }
2576
+
2577
+ /*
2578
+ **
2579
+ **
2580
+ **
2581
+ **
2582
+ **
2583
+ **
2584
+ **
2585
+ **
2586
+ **
2587
+ **
2588
+ **
2589
+ **
2590
+ **
2591
+ **
2592
+ **
2593
+ **
2594
+ **
2595
+ */
2596
+
2597
  function addAllListeners() {
2598
  // global
2599
  document.addEventListener('keydown', function(event) {
 
2845
  });
2846
  imageItem.getElementsByTagName('h3')[0].addEventListener('click', function(e) {
2847
  copyStuffToClipboard(this,'name');
2848
+ promptBuilderFillArtist(this,e);
2849
  });
2850
  imageItem.getElementsByTagName('h4')[0].addEventListener('click', function(e) {
2851
  if(!this.classList.contains('edit_mode')) {
 
2865
  gutter.removeEventListener('mousemove', movePartition, false);
2866
  }, false);
2867
  }, false);
2868
+ // prompt builder
2869
+ var prompt_builder = document.getElementById('prompt_builder');
2870
+ prompt_builder.addEventListener('click', function(e) {
2871
+ promptBuilderShow();
2872
+ });
2873
+ var prompt_builder_hide = document.getElementById('prompt_builder_hide');
2874
+ prompt_builder_hide.addEventListener('click', function(e) {
2875
+ promptBuilderHide();
2876
+ e.stopPropagation();
2877
+ });
2878
+ var prompt_result_copy = document.getElementById('prompt_result_copy');
2879
+ prompt_result_copy.addEventListener('click', function(e) {
2880
+ copyStuffToClipboard(null,'prompt');
2881
+ });
2882
+ var prompt_artist_add = document.getElementById('prompt_artist_add');
2883
+ prompt_artist_add.addEventListener('click', function(e) {
2884
+ promptBuilderAddArtist();
2885
+ });
2886
+ var prompt_selector_div = document.querySelector('#prompt_selector > div');
2887
+ prompt_selector_div.addEventListener('scroll', debounceSetXPosOfSearchOutput(function() {
2888
+ setXPosOfSearchOutput();
2889
+ }, 100));
2890
  }