sleepdeep/llm-deploy
0
1let main_parent = document.getElementById("chat-tab").parentNode;2let extensions = document.getElementById("extensions");3 4main_parent.childNodes[0].classList.add("header_bar");5main_parent.style = "padding: 0; margin: 0";6main_parent.parentNode.style = "gap: 0";7main_parent.parentNode.parentNode.style = "padding: 0";8 9document.querySelector(".header_bar").addEventListener("click", function(event) {10 if (event.target.tagName === "BUTTON") {11 const buttonText = event.target.textContent.trim();12 13 let chat_visible = (buttonText == "Chat");14 let default_visible = (buttonText == "Default");15 let notebook_visible = (buttonText == "Notebook");16 17 // Check if one of the generation tabs is visible18 if (chat_visible || notebook_visible || default_visible) {19 extensions && (extensions.style.display = "flex");20 21 if (chat_visible) {22 this.style.marginBottom = "0px";23 extensions && (extensions.style.maxWidth = "880px");24 extensions && (extensions.style.padding = "0px");25 } else {26 this.style.marginBottom = "19px";27 extensions && (extensions.style.maxWidth = "none");28 extensions && (extensions.style.padding = "15px");29 }30 } else {31 this.style.marginBottom = "19px";32 extensions && (extensions.style.display = "none");33 }34 }35});36 37//------------------------------------------------38// Keyboard shortcuts39//------------------------------------------------40let previousTabId = "chat-tab-button";41document.addEventListener("keydown", function(event) {42 43 // Stop generation on Esc pressed44 if (event.key === "Escape") {45 // Find the element with id 'stop' and click it46 var stopButton = document.getElementById("stop");47 if (stopButton) {48 stopButton.click();49 }50 }51 52 // Show chat controls on Ctrl + S53 else if (event.ctrlKey && event.key == "s") {54 event.preventDefault();55 56 var showControlsElement = document.getElementById("show-controls");57 if (showControlsElement && showControlsElement.childNodes.length >= 4) {58 showControlsElement.childNodes[3].click();59 60 var arr = document.getElementById("chat-input").childNodes[2].childNodes;61 arr[arr.length - 1].focus();62 }63 }64 65 // Regenerate on Ctrl + Enter66 else if (event.ctrlKey && event.key === "Enter") {67 event.preventDefault();68 document.getElementById("Regenerate").click();69 }70 71 // Continue on Alt + Enter72 else if (event.altKey && event.key === "Enter") {73 event.preventDefault();74 document.getElementById("Continue").click();75 }76 77 // Remove last on Ctrl + Shift + Backspace78 else if (event.ctrlKey && event.shiftKey && event.key === "Backspace") {79 event.preventDefault();80 document.getElementById("Remove-last").click();81 }82 83 // Copy last on Ctrl + Shift + K84 else if (event.ctrlKey && event.shiftKey && event.key === "K") {85 event.preventDefault();86 document.getElementById("Copy-last").click();87 }88 89 // Replace last on Ctrl + Shift + L90 else if (event.ctrlKey && event.shiftKey && event.key === "L") {91 event.preventDefault();92 document.getElementById("Replace-last").click();93 }94 95 // Impersonate on Ctrl + Shift + M96 else if (event.ctrlKey && event.shiftKey && event.key === "M") {97 event.preventDefault();98 document.getElementById("Impersonate").click();99 }100 101 // Switch between tabs on Tab102 else if (!event.ctrlKey && !event.shiftKey && !event.altKey && !event.metaKey && event.key === "Tab") {103 event.preventDefault();104 var parametersButton = document.getElementById("parameters-button");105 var parentContainer = parametersButton.parentNode;106 var selectedChild = parentContainer.querySelector(".selected");107 108 if (selectedChild.id == "parameters-button") {109 document.getElementById(previousTabId).click();110 } else {111 previousTabId = selectedChild.id;112 parametersButton.click();113 }114 }115});116 117//------------------------------------------------118// Position the chat typing dots119//------------------------------------------------120typing = document.getElementById("typing-container");121typingParent = typing.parentNode;122typingSibling = typing.previousElementSibling;123typingSibling.insertBefore(typing, typingSibling.childNodes[2]);124 125//------------------------------------------------126// Chat scrolling127//------------------------------------------------128const targetElement = document.getElementById("chat").parentNode.parentNode.parentNode;129targetElement.classList.add("pretty_scrollbar");130targetElement.classList.add("chat-parent");131let isScrolled = false;132 133targetElement.addEventListener("scroll", function() {134 let diff = targetElement.scrollHeight - targetElement.clientHeight;135 if(Math.abs(targetElement.scrollTop - diff) <= 10 || diff == 0) {136 isScrolled = false;137 } else {138 isScrolled = true;139 }140});141 142// Create a MutationObserver instance143const observer = new MutationObserver(function(mutations) {144 mutations.forEach(function(mutation) {145 updateCssProperties();146 147 if(!isScrolled) {148 targetElement.scrollTop = targetElement.scrollHeight;149 }150 151 const firstChild = targetElement.children[0];152 if (firstChild.classList.contains("generating")) {153 typing.parentNode.classList.add("visible-dots");154 document.getElementById("stop").style.display = "flex";155 document.getElementById("Generate").style.display = "none";156 } else {157 typing.parentNode.classList.remove("visible-dots");158 document.getElementById("stop").style.display = "none";159 document.getElementById("Generate").style.display = "flex";160 }161 162 });163});164 165// Configure the observer to watch for changes in the subtree and attributes166const config = {167 childList: true,168 subtree: true,169 characterData: true,170 attributeOldValue: true,171 characterDataOldValue: true172};173 174// Start observing the target element175observer.observe(targetElement, config);176 177//------------------------------------------------178// Add some scrollbars179//------------------------------------------------180const textareaElements = document.querySelectorAll(".add_scrollbar textarea");181for(i = 0; i < textareaElements.length; i++) {182 textareaElements[i].classList.remove("scroll-hide");183 textareaElements[i].classList.add("pretty_scrollbar");184 textareaElements[i].style.resize = "none";185}186 187//------------------------------------------------188// Remove some backgrounds189//------------------------------------------------190const noBackgroundelements = document.querySelectorAll(".no-background");191for(i = 0; i < noBackgroundelements.length; i++) {192 noBackgroundelements[i].parentNode.style.border = "none";193 noBackgroundelements[i].parentNode.parentNode.parentNode.style.alignItems = "center";194}195 196const slimDropdownElements = document.querySelectorAll(".slim-dropdown");197for (i = 0; i < slimDropdownElements.length; i++) {198 const parentNode = slimDropdownElements[i].parentNode;199 parentNode.style.background = "transparent";200 parentNode.style.border = "0";201}202 203//------------------------------------------------204// Create the hover menu in the chat tab205// The show/hide events were adapted from:206// https://github.com/SillyTavern/SillyTavern/blob/6c8bd06308c69d51e2eb174541792a870a83d2d6/public/script.js207//------------------------------------------------208var buttonsInChat = document.querySelectorAll("#chat-tab:not(.old-ui) #chat-buttons button");209var button = document.getElementById("hover-element-button");210var menu = document.getElementById("hover-menu");211var istouchscreen = (navigator.maxTouchPoints > 0) || "ontouchstart" in document.documentElement;212 213function showMenu() {214 menu.style.display = "flex"; // Show the menu215}216 217function hideMenu() {218 menu.style.display = "none"; // Hide the menu219 if (!istouchscreen) {220 document.querySelector("#chat-input textarea").focus(); // Focus on the chat input221 }222}223 224if (buttonsInChat.length > 0) {225 for (let i = buttonsInChat.length - 1; i >= 0; i--) {226 const thisButton = buttonsInChat[i];227 menu.appendChild(thisButton);228 229 thisButton.addEventListener("click", () => {230 hideMenu();231 });232 233 const buttonText = thisButton.textContent;234 const matches = buttonText.match(/(\(.*?\))/);235 236 if (matches && matches.length > 1) {237 // Apply the transparent-substring class to the matched substring238 const substring = matches[1];239 const newText = buttonText.replace(substring, ` <span class="transparent-substring">${substring.slice(1, -1)}</span>`);240 thisButton.innerHTML = newText;241 }242 }243} else {244 buttonsInChat = document.querySelectorAll("#chat-tab.old-ui #chat-buttons button");245 for (let i = 0; i < buttonsInChat.length; i++) {246 buttonsInChat[i].textContent = buttonsInChat[i].textContent.replace(/ \(.*?\)/, "");247 }248 document.getElementById("gr-hover-container").style.display = "none";249}250 251function isMouseOverButtonOrMenu() {252 return menu.matches(":hover") || button.matches(":hover");253}254 255button.addEventListener("mouseenter", function () {256 if (!istouchscreen) {257 showMenu();258 }259});260 261button.addEventListener("click", function () {262 if (menu.style.display === "flex") {263 hideMenu();264 }265 else {266 showMenu();267 }268});269 270// Add event listener for mouseleave on the button271button.addEventListener("mouseleave", function () {272 // Delay to prevent menu hiding when the mouse leaves the button into the menu273 setTimeout(function () {274 if (!isMouseOverButtonOrMenu()) {275 hideMenu();276 }277 }, 100);278});279 280// Add event listener for mouseleave on the menu281menu.addEventListener("mouseleave", function () {282 // Delay to prevent menu hide when the mouse leaves the menu into the button283 setTimeout(function () {284 if (!isMouseOverButtonOrMenu()) {285 hideMenu();286 }287 }, 100);288});289 290// Add event listener for click anywhere in the document291document.addEventListener("click", function (event) {292 // Check if the click is outside the button/menu and the menu is visible293 if (!isMouseOverButtonOrMenu() && menu.style.display === "flex") {294 hideMenu();295 }296 297 if (event.target.classList.contains("pfp_character")) {298 toggleBigPicture();299 }300});301 302//------------------------------------------------303// Relocate the "Show controls" checkbox304//------------------------------------------------305var elementToMove = document.getElementById("show-controls");306var parent = elementToMove.parentNode;307for (var i = 0; i < 2; i++) {308 parent = parent.parentNode;309}310 311parent.insertBefore(elementToMove, parent.firstChild);312 313//------------------------------------------------314// Make the chat input grow upwards instead of downwards315//------------------------------------------------316document.getElementById("show-controls").parentNode.style.position = "absolute";317document.getElementById("show-controls").parentNode.style.bottom = "0px";318 319//------------------------------------------------320// Focus on the chat input321//------------------------------------------------322const chatTextArea = document.getElementById("chat-input").querySelector("textarea");323 324function respondToChatInputVisibility(element, callback) {325 var options = {326 root: document.documentElement,327 };328 329 var observer = new IntersectionObserver((entries, observer) => {330 entries.forEach(entry => {331 callback(entry.intersectionRatio > 0);332 });333 }, options);334 335 observer.observe(element);336}337 338function handleChatInputVisibilityChange(isVisible) {339 if (isVisible) {340 chatTextArea.focus();341 }342}343 344respondToChatInputVisibility(chatTextArea, handleChatInputVisibilityChange);345 346//------------------------------------------------347// Show enlarged character picture when the profile348// picture is clicked on349//------------------------------------------------350let bigPictureVisible = false;351 352function addBigPicture() {353 var imgElement = document.createElement("img");354 var timestamp = new Date().getTime();355 imgElement.src = "/file/cache/pfp_character.png?time=" + timestamp;356 imgElement.classList.add("bigProfilePicture");357 358 var imgElementParent = document.getElementById("chat").parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode;359 imgElementParent.appendChild(imgElement);360}361 362function deleteBigPicture() {363 var bigProfilePictures = document.querySelectorAll(".bigProfilePicture");364 bigProfilePictures.forEach(function (element) {365 element.parentNode.removeChild(element);366 });367}368 369function toggleBigPicture() {370 if(bigPictureVisible) {371 deleteBigPicture();372 bigPictureVisible = false;373 } else {374 addBigPicture();375 bigPictureVisible = true;376 }377}378 379//------------------------------------------------380// Define global CSS properties for resizing and381// positioning certain elements382//------------------------------------------------383let currentChatInputHeight = 0;384 385function updateCssProperties() {386 // Set the height of the chat area387 const chatContainer = document.getElementById("chat").parentNode.parentNode.parentNode;388 const chatInputHeight = document.querySelector("#chat-input textarea").clientHeight;389 if (chatContainer.clientHeight > 0) {390 const newChatHeight = `${chatContainer.clientHeight - chatInputHeight + 40}px`;391 document.documentElement.style.setProperty("--chat-height", newChatHeight);392 document.documentElement.style.setProperty("--input-delta", `${chatInputHeight - 40}px`);393 394 // Set the position offset of the chat input box395 const header = document.querySelector(".header_bar");396 const headerHeight = `${header.clientHeight}px`;397 document.documentElement.style.setProperty("--header-height", headerHeight);398 399 // Offset the scroll position of the chat area400 if (chatInputHeight !== currentChatInputHeight) {401 chatContainer.scrollTop += chatInputHeight > currentChatInputHeight ? chatInputHeight : -chatInputHeight;402 currentChatInputHeight = chatInputHeight;403 }404 }405}406 407new ResizeObserver(updateCssProperties)408 .observe(document.querySelector("#chat-input textarea"));409 410window.addEventListener("resize", updateCssProperties);411 412//------------------------------------------------413// Keep track of the display width to position the past414// chats dropdown on desktop415//------------------------------------------------416function updateDocumentWidth() {417 var updatedWidth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;418 document.documentElement.style.setProperty("--document-width", updatedWidth + "px");419}420 421updateDocumentWidth();422window.addEventListener("resize", updateDocumentWidth);423 424//------------------------------------------------425// Focus on the rename text area when it becomes visible426//------------------------------------------------427const renameTextArea = document.getElementById("rename-row").querySelector("textarea");428 429function respondToRenameVisibility(element, callback) {430 var options = {431 root: document.documentElement,432 };433 434 var observer = new IntersectionObserver((entries, observer) => {435 entries.forEach(entry => {436 callback(entry.intersectionRatio > 0);437 });438 }, options);439 440 observer.observe(element);441}442 443 444function handleVisibilityChange(isVisible) {445 if (isVisible) {446 renameTextArea.focus();447 }448}449 450respondToRenameVisibility(renameTextArea, handleVisibilityChange);451 