mirror of
https://github.com/DominikDoom/a1111-sd-webui-tagcomplete.git
synced 2026-02-19 06:30:11 +00:00
Ruby Text live translation feature (WIP)
This commit is contained in:
@@ -8,6 +8,9 @@
|
||||
"--meta-text-color": ["#6b6f7b", "#a2a9b4"],
|
||||
"--embedding-v1-color": ["lightsteelblue", "#2b5797"],
|
||||
"--embedding-v2-color": ["skyblue", "#2d89ef"],
|
||||
"--live-translation-color-1": ["lightskyblue", "#2d89ef"],
|
||||
"--live-translation-color-2": ["palegoldenrod", "#eb5700"],
|
||||
"--live-translation-color-3": ["darkseagreen", "darkgreen"],
|
||||
}
|
||||
const browserVars = {
|
||||
"--results-overflow-y": {
|
||||
@@ -78,6 +81,26 @@ const autocompleteCSS = `
|
||||
.acListItem.acEmbeddingV2 {
|
||||
color: var(--embedding-v2-color);
|
||||
}
|
||||
.acRuby {
|
||||
margin-top: 0.5rem;
|
||||
padding: var(--input-padding);
|
||||
color: #888;
|
||||
}
|
||||
.acRuby > :nth-child(3n+1) {
|
||||
color: var(--live-translation-color-1);
|
||||
}
|
||||
.acRuby > :nth-child(3n+2) {
|
||||
color: var(--live-translation-color-2);
|
||||
}
|
||||
.acRuby > :nth-child(3n+3) {
|
||||
color: var(--live-translation-color-3);
|
||||
}
|
||||
.acRuby > ruby > rt {
|
||||
overflow: hidden;
|
||||
padding: 0px 5px;
|
||||
text-align: center;
|
||||
font-size: 0.8em;
|
||||
}
|
||||
`;
|
||||
|
||||
async function loadTags(c) {
|
||||
@@ -217,7 +240,7 @@ function createResultsDiv(textArea) {
|
||||
let typeClass = textAreaId.replaceAll(".", " ");
|
||||
|
||||
resultsDiv.style.maxHeight = `${CFG.maxResults * 50}px`;
|
||||
resultsDiv.setAttribute("class", `autocompleteResults ${typeClass} notranslate`);
|
||||
resultsDiv.setAttribute("class", `autocompleteResults${typeClass} notranslate`);
|
||||
resultsDiv.setAttribute("translate", "no");
|
||||
resultsList.setAttribute("class", "autocompleteResultsList");
|
||||
resultsDiv.appendChild(resultsList);
|
||||
@@ -286,6 +309,7 @@ const WEIGHT_REGEX = /[([]([^()[\]:|]+)(?::(?:\d+(?:\.\d+)?|\.\d+))?[)\]]/g;
|
||||
const POINTY_REGEX = /<[^\s,<](?:[^\t\n\r,<>]*>|[^\t\n\r,> ]*)/g;
|
||||
const COMPLETED_WILDCARD_REGEX = /__[^\s,_][^\t\n\r,_]*[^\s,_]__[^\s,_]*/g;
|
||||
const NORMAL_TAG_REGEX = /[^\s,|<>)\]]+|</g;
|
||||
const RUBY_TAG_REGEX = /(?<![<:])[\w\d(][\w\d' \-()?!/\\]{2,}/g;
|
||||
const TAG_REGEX = new RegExp(`${POINTY_REGEX.source}|${COMPLETED_WILDCARD_REGEX.source}|${NORMAL_TAG_REGEX.source}`, "g");
|
||||
|
||||
// On click, insert the tag into the prompt textbox with respect to the cursor position
|
||||
@@ -548,6 +572,50 @@ function updateSelectionStyle(textArea, newIndex, oldIndex) {
|
||||
}
|
||||
}
|
||||
|
||||
async function updateRuby(textArea, prompt) {
|
||||
let ruby = gradioApp().querySelector('.acRuby' + getTextAreaIdentifier(textArea));
|
||||
if (!ruby) {
|
||||
let textAreaId = getTextAreaIdentifier(textArea);
|
||||
let typeClass = textAreaId.replaceAll(".", " ");
|
||||
ruby = document.createElement("div");
|
||||
ruby.setAttribute("class", `acRuby${typeClass} notranslate`);
|
||||
textArea.parentNode.appendChild(ruby);
|
||||
}
|
||||
|
||||
ruby.innerText = prompt;
|
||||
|
||||
let rubyTags = prompt.match(RUBY_TAG_REGEX);
|
||||
if (!rubyTags) return;
|
||||
|
||||
rubyTags = new Set(rubyTags);
|
||||
rubyTags.forEach(tag => {
|
||||
tag = tag.trim();
|
||||
// Cut off opening bracket for weighted tags
|
||||
if (tag.startsWith("(")) {
|
||||
tag = tag.substring(1);
|
||||
// Cut off closing bracket if left over from a single word weighted tag
|
||||
if (tag.endsWith(")"))
|
||||
tag = tag.substring(0, tag.length - 1);
|
||||
}
|
||||
|
||||
let unsanitizedTag = tag
|
||||
.replaceAll(" ", "_")
|
||||
.replaceAll("\\(", "(")
|
||||
.replaceAll("\\)", ")");
|
||||
|
||||
const translation = translations?.get(tag) || translations?.get(unsanitizedTag);
|
||||
|
||||
let escapedTag = tag;
|
||||
if (tag.endsWith("\\)")) {
|
||||
escapedTag = escapedTag.substring(0, escapedTag.length - 1);
|
||||
}
|
||||
escapedTag = escapeRegExp(escapedTag);
|
||||
|
||||
if (translation)
|
||||
ruby.innerHTML = ruby.innerHTML.replaceAll(new RegExp(`${escapedTag}(?:\\)|\\b)`, "g"), `<ruby>${translation}<rt>${tag}</rt></ruby>`);
|
||||
});
|
||||
}
|
||||
|
||||
async function autocomplete(textArea, prompt, fixedTag = null) {
|
||||
// Return if the function is deactivated in the UI
|
||||
if (!isEnabled()) return;
|
||||
@@ -875,7 +943,10 @@ async function setup() {
|
||||
hideResults(area);
|
||||
|
||||
// Add autocomplete event listener
|
||||
area.addEventListener('input', debounce(() => autocomplete(area, area.value), CFG.delayTime));
|
||||
area.addEventListener('input', debounce(() => {
|
||||
autocomplete(area, area.value);
|
||||
updateRuby(area, area.value);
|
||||
}, CFG.delayTime));
|
||||
// Add focusout event listener
|
||||
area.addEventListener('focusout', debounce(() => hideResults(area), 400));
|
||||
// Add up and down arrow event listener
|
||||
@@ -903,10 +974,10 @@ async function setup() {
|
||||
let css = autocompleteCSS;
|
||||
// Replace vars with actual values (can't use actual css vars because of the way we inject the css)
|
||||
Object.keys(styleColors).forEach((key) => {
|
||||
css = css.replace(`var(${key})`, styleColors[key][mode]);
|
||||
css = css.replaceAll(`var(${key})`, styleColors[key][mode]);
|
||||
})
|
||||
Object.keys(browserVars).forEach((key) => {
|
||||
css = css.replace(`var(${key})`, browserVars[key][browser]);
|
||||
css = css.replaceAll(`var(${key})`, browserVars[key][browser]);
|
||||
})
|
||||
|
||||
if (acStyle.styleSheet) {
|
||||
|
||||
Reference in New Issue
Block a user