mirror of
https://github.com/DominikDoom/a1111-sd-webui-tagcomplete.git
synced 2026-01-27 03:29:55 +00:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a782f951a6 | ||
|
|
fd0d05101a | ||
|
|
6fa1d1d041 | ||
|
|
00a12b4e41 | ||
|
|
d88ab906d7 | ||
|
|
4243ebe645 |
@@ -9,6 +9,8 @@ I created this script as a convenience tool since it reduces the need of switchi
|
||||
|
||||
You can either download the files manually as described below, or use a pre-packaged version from [Releases](https://github.com/DominikDoom/a1111-sd-webui-tagcomplete/releases).
|
||||
|
||||
(Note: e621 tags aren't added to the releases yet since coloring is broken for them at the moment).
|
||||
|
||||
### Disclaimer:
|
||||
This script is definitely not optimized, and it's not very intelligent. The tags are simply recommended based on their natural order in the CSV, which is their respective image count for the default Danbooru tag list. Also, at least for now, neither keyboard selection for tags nor completion for negative or img2img prompt textboxes is supported, and there's no way to turn the feature off from the ui, but I plan to get around to those features eventually.
|
||||
|
||||
|
||||
@@ -118,6 +118,13 @@ const debounce = (func, wait = 300) => {
|
||||
|
||||
// Difference function to fix duplicates not being seen as changes in normal filter
|
||||
function difference(a, b) {
|
||||
if (a.length == 0) {
|
||||
return b;
|
||||
}
|
||||
if (b.length == 0) {
|
||||
return a;
|
||||
}
|
||||
|
||||
return [...b.reduce( (acc, v) => acc.set(v, (acc.get(v) || 0) - 1),
|
||||
a.reduce( (acc, v) => acc.set(v, (acc.get(v) || 0) + 1), new Map() )
|
||||
)].reduce( (acc, [v, count]) => acc.concat(Array(Math.abs(count)).fill(v)), [] );
|
||||
@@ -157,11 +164,17 @@ function insertTextAtCursor(text, tagword) {
|
||||
let promptTextbox = gradioApp().querySelector('#txt2img_prompt > label > textarea');
|
||||
let cursorPos = promptTextbox.selectionStart;
|
||||
let sanitizedText = acConfig.replaceUnderscores ? text.replaceAll("_", " ") : text;
|
||||
let optionalComma = (promptTextbox.value[cursorPos] == ",") ? "" : ", ";
|
||||
|
||||
var prompt = promptTextbox.value;
|
||||
let optionalComma = (prompt[cursorPos] === "," || prompt[cursorPos + tagword.length] === ",") ? "" : ", ";
|
||||
|
||||
// Edit prompt text
|
||||
var prompt = promptTextbox.value;
|
||||
promptTextbox.value = prompt.substring(0, cursorPos - tagword.length) + sanitizedText + optionalComma + prompt.substring(cursorPos);
|
||||
let direction = prompt.substring(cursorPos, cursorPos + tagword.length) === tagword ? 1 : -1;
|
||||
if (direction === 1) {
|
||||
promptTextbox.value = prompt.substring(0, cursorPos) + sanitizedText + optionalComma + prompt.substring(cursorPos + tagword.length)
|
||||
} else {
|
||||
promptTextbox.value = prompt.substring(0, cursorPos - tagword.length) + sanitizedText + optionalComma + prompt.substring(cursorPos)
|
||||
}
|
||||
prompt = promptTextbox.value;
|
||||
|
||||
// Update cursor position to after the inserted text
|
||||
@@ -176,20 +189,29 @@ function insertTextAtCursor(text, tagword) {
|
||||
previousTags = tags;
|
||||
}
|
||||
|
||||
const colors_dark = ["lightblue", "indianred", "unused", "violet", "lightgreen", "orange"];
|
||||
const colors_light = ["dodgerblue", "firebrick", "unused", "darkorchid", "darkgreen", "darkorange" ]
|
||||
function addResultsToList(results, tagword) {
|
||||
let resultsList = gradioApp().querySelector('#autocompleteResultsList');
|
||||
resultsList.innerHTML = "";
|
||||
|
||||
let colors = gradioApp().querySelector('.dark') ? colors_dark : colors_light;
|
||||
// Find right colors from config
|
||||
let tagFileName = acConfig.tagFile.split(".")[0];
|
||||
let tagColors = acConfig.colors;
|
||||
//let colorIndex = Object.keys(tagColors).findIndex(key => key === tagFileName);
|
||||
//let colorValues = Object.values(tagColors)[colorIndex];
|
||||
|
||||
let mode = gradioApp().querySelector('.dark') ? 0 : 1;
|
||||
|
||||
for (let i = 0; i < results.length; i++) {
|
||||
let result = results[i];
|
||||
let li = document.createElement("li");
|
||||
li.innerHTML = result[0];
|
||||
li.style = `color: ${colors[result[1]]};`;
|
||||
|
||||
// Set the color of the tag
|
||||
let tagType = result[1];
|
||||
li.style = `color: ${tagColors[tagFileName][tagType][mode]};`;
|
||||
// Add listener
|
||||
li.addEventListener("click", function() { insertTextAtCursor(result[0], tagword); });
|
||||
// Add element to list
|
||||
resultsList.appendChild(li);
|
||||
}
|
||||
}
|
||||
@@ -212,7 +234,7 @@ tagword = "";
|
||||
resultCount = 0;
|
||||
function autocomplete(prompt) {
|
||||
// Guard for empty prompt
|
||||
if (prompt.length == 0) {
|
||||
if (prompt.length === 0) {
|
||||
hideResults();
|
||||
return;
|
||||
}
|
||||
@@ -223,7 +245,7 @@ function autocomplete(prompt) {
|
||||
previousTags = tags;
|
||||
|
||||
// Guard for no difference / only whitespace remaining
|
||||
if (diff == undefined || diff.length == 0) {
|
||||
if (diff === undefined || diff.length === 0) {
|
||||
hideResults();
|
||||
return;
|
||||
}
|
||||
@@ -231,7 +253,7 @@ function autocomplete(prompt) {
|
||||
tagword = diff[0]
|
||||
|
||||
// Guard for empty tagword
|
||||
if (tagword == undefined || tagword.length == 0) {
|
||||
if (tagword === undefined || tagword.length === 0) {
|
||||
hideResults();
|
||||
return;
|
||||
}
|
||||
@@ -240,7 +262,7 @@ function autocomplete(prompt) {
|
||||
resultCount = results.length;
|
||||
|
||||
// Guard for empty results
|
||||
if (resultCount == 0) {
|
||||
if (resultCount === 0) {
|
||||
hideResults();
|
||||
return;
|
||||
}
|
||||
@@ -257,14 +279,14 @@ function navigateInList(event) {
|
||||
|
||||
switch (event.key) {
|
||||
case "ArrowUp":
|
||||
if (selectedTag == null) {
|
||||
if (selectedTag === null) {
|
||||
selectedTag = resultCount - 1;
|
||||
} else {
|
||||
selectedTag = (selectedTag - 1 + resultCount) % resultCount;
|
||||
}
|
||||
break;
|
||||
case "ArrowDown":
|
||||
if (selectedTag == null) {
|
||||
if (selectedTag === null) {
|
||||
selectedTag = 0;
|
||||
} else {
|
||||
selectedTag = (selectedTag + 1) % resultCount;
|
||||
@@ -277,7 +299,7 @@ function navigateInList(event) {
|
||||
selectedTag = resultCount - 1;
|
||||
break;
|
||||
case "Enter":
|
||||
if (selectedTag != null) {
|
||||
if (selectedTag !== null) {
|
||||
insertTextAtCursor(results[selectedTag][0], tagword);
|
||||
}
|
||||
break;
|
||||
@@ -286,7 +308,7 @@ function navigateInList(event) {
|
||||
break;
|
||||
}
|
||||
// Update highlighting
|
||||
if (selectedTag != null)
|
||||
if (selectedTag !== null)
|
||||
updateSelectionStyle(selectedTag);
|
||||
|
||||
// Prevent default behavior
|
||||
@@ -296,12 +318,12 @@ function navigateInList(event) {
|
||||
|
||||
onUiUpdate(function(){
|
||||
// One-time CSV setup
|
||||
if (acConfig == null) acConfig = JSON.parse(readFile("file/tags/config.json"));
|
||||
if (allTags.length == 0) allTags = loadCSV();
|
||||
if (acConfig === null) acConfig = JSON.parse(readFile("file/tags/config.json"));
|
||||
if (allTags.length === 0) allTags = loadCSV();
|
||||
|
||||
let promptTextbox = gradioApp().querySelector('#txt2img_prompt > label > textarea');
|
||||
|
||||
if (promptTextbox == null) return;
|
||||
if (promptTextbox === null) return;
|
||||
if (gradioApp().querySelector('#autocompleteResults') != null) return;
|
||||
|
||||
// Only add listeners once
|
||||
@@ -317,7 +339,7 @@ onUiUpdate(function(){
|
||||
// Add focusout event listener
|
||||
promptTextbox.addEventListener('focusout', debounce(() => hideResults(), 400));
|
||||
// Add up and down arrow event listener
|
||||
promptTextbox.addEventListener('keydown', function(e) { navigateInList(e); });
|
||||
promptTextbox.addEventListener('keydown', (e) => navigateInList(e));
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,25 @@
|
||||
{
|
||||
"tagFile": "danbooru.csv",
|
||||
"maxResults": 5,
|
||||
"replaceUnderscores": true
|
||||
}
|
||||
"replaceUnderscores": true,
|
||||
"colors": {
|
||||
"danbooru": {
|
||||
"0": ["lightblue", "dodgerblue"],
|
||||
"1": ["indianred", "firebrick"],
|
||||
"3": ["violet", "darkorchid"],
|
||||
"4": ["lightgreen", "darkgreen"],
|
||||
"5": ["orange", "darkorange"]
|
||||
},
|
||||
"e621": {
|
||||
"-1": ["red", "maroon"],
|
||||
"0": ["lightblue", "dodgerblue"],
|
||||
"1": ["gold", "goldenrod"],
|
||||
"3": ["violet", "darkorchid"],
|
||||
"4": ["lightgreen", "darkgreen"],
|
||||
"5": ["tomato", "darksalmon"],
|
||||
"6": ["red", "maroon"],
|
||||
"7": ["whitesmoke", "black"],
|
||||
"8": ["seagreen", "darkseagreen"]
|
||||
}
|
||||
}
|
||||
}
|
||||
66094
tags/e621.csv
Normal file
66094
tags/e621.csv
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user