您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Optimize your experience on the chat.lmsys.org with the `lmsys-enhancer` Tampermonkey script.
// ==UserScript== // @name lmsys-enhancer // @namespace http://tampermonkey.net/ // @version 0.7 // @description Optimize your experience on the chat.lmsys.org with the `lmsys-enhancer` Tampermonkey script. // @author joshlee // @match https://chat.lmsys.org/ // @icon https://www.google.com/s2/favicons?sz=64&domain=lmsys.org // @grant none // @license MIT // ==/UserScript== const scriptConfig = { model: "gpt-4-turbo", loadLatestSession: true, firstMeetSessionHash: true, firstSend: true, currentSessionHash: "", dataKey: "session_hash_history", mainColor: "#DE6B2F", drawerWidth: 250, position: { main: "#component-1", changeModel: "#model_selector_row label", directChat: ".tab-nav.scroll-hide button:nth-child(3)", maxOutputTokenInput: "//span[text()='Max output tokens']/../../input", maxOutputTokenBar: "//span[text()='Max output tokens']/../../../../input", sendBtn: '//button[text()="Send"]', unnecessaryList: ["#component-93", "#component-83"], }, }; const originalSend = WebSocket.prototype.send; var itemList; function $x(xpathToExecute) { var result = []; var nodesSnapshot = document.evaluate( xpathToExecute, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null ); for (var i = 0; i < nodesSnapshot.snapshotLength; i++) { result.push(nodesSnapshot.snapshotItem(i)); } return result; } function removeUselessElements() { // Remove unnecessary notices and components document .querySelectorAll("#notice_markdown") .forEach((elem) => elem.remove()); scriptConfig.position.unnecessaryList.forEach((v) => { const componentToRemove = document.querySelector(v); if (componentToRemove) componentToRemove.remove(); }); } function setMaxOutputToken(maxValue = 4096) { // Set the maximum token output to the desired value const [, , input] = $x(scriptConfig.position.maxOutputTokenInput); const [, , bar] = $x(scriptConfig.position.maxOutputTokenBar); if (!input || !bar) { console.error("Set max output token failure!"); return; } input.value = String(maxValue); bar.max = String(maxValue); bar.value = String(maxValue); const changeEvent = new Event("change", { bubbles: true, cancelable: true }); bar.dispatchEvent(changeEvent); } function changeModel(model) { document.querySelector(scriptConfig.position.changeModel).click(); document.querySelector(`li[data-value=${model}]`).dispatchEvent( new MouseEvent("mousedown", { view: window, bubbles: true, cancelable: true, }) ); } function hackWsSend(data) { let d = JSON.parse(data); // get session_hash if (d.session_hash) { // first create session if (scriptConfig.firstMeetSessionHash) { scriptConfig.currentSessionHash = d.session_hash; scriptConfig.firstMeetSessionHash = false; } if ( scriptConfig.loadLatestSession && d.fn_index === 38 && getLastestSessionToggleBtn() ) { // skip creat new session d.fn_index = 41; d.data = [null, scriptConfig.model, ""]; originalSend.call(this, data); toggleLastestSession(); return; } // first send message if (scriptConfig.firstSend && d.fn_index === 39) { saveCurrentSession(); scriptConfig.firstSend = false; } // modify session_hash if (scriptConfig.currentSessionHash) { d.session_hash = scriptConfig.currentSessionHash; data = JSON.stringify(d); } } originalSend.call(this, data); } function createSessionItem(text, sessionHash) { var itemContainer = document.createElement("div"); itemContainer.style.display = "flex"; itemContainer.style.justifyContent = "space-between"; itemContainer.style.alignItems = "center"; itemContainer.style.padding = "10px"; itemContainer.style.borderBottom = "1px solid #ccc"; itemContainer.className = "session-item-container"; itemContainer.setAttribute("data-session-hash", sessionHash); var itemText = document.createElement("div"); itemText.textContent = text; itemContainer.appendChild(itemText); // Create toggle session button var toggleButton = document.createElement("button"); toggleButton.textContent = "⇢"; toggleButton.style.marginLeft = "5px"; toggleButton.style.padding = "5px 10px"; toggleButton.style.border = "none"; toggleButton.style.borderRadius = "4px"; toggleButton.style.backgroundColor = "#4CAF50"; toggleButton.style.color = "white"; toggleButton.style.cursor = "pointer"; // Button hover effect toggleButton.addEventListener("mouseover", function () { this.style.backgroundColor = "#45a049"; }); toggleButton.addEventListener("mouseout", function () { this.style.backgroundColor = "#4CAF50"; }); toggleButton.addEventListener("click", function () { scriptConfig.currentSessionHash = sessionHash; clickSendBtn(); }); itemContainer.appendChild(toggleButton); // Create Delete button var deleteButton = document.createElement("button"); deleteButton.textContent = "✖"; deleteButton.style.marginLeft = "5px"; deleteButton.style.padding = "5px 10px"; deleteButton.style.border = "none"; deleteButton.style.borderRadius = "4px"; deleteButton.style.backgroundColor = "#f44336"; deleteButton.style.color = "white"; deleteButton.style.cursor = "pointer"; // Button hover effect deleteButton.addEventListener("mouseover", function () { this.style.backgroundColor = "#e53935"; }); deleteButton.addEventListener("mouseout", function () { this.style.backgroundColor = "#f44336"; }); deleteButton.addEventListener("click", function () { removeSessionHash(sessionHash); itemContainer.remove(); }); itemContainer.appendChild(deleteButton); itemContainer.highlight = function () { itemContainer.classList.add("highlighted-session"); toggleButton.classList.add("disabled-button"); deleteButton.classList.add("disabled-button"); }; itemContainer.unhighlight = function () { itemContainer.classList.remove("highlighted-session"); toggleButton.classList.remove("disabled-button"); deleteButton.classList.remove("disabled-button"); }; if (sessionHash === scriptConfig.currentSessionHash) { itemContainer.highlight(); } itemList.appendChild(itemContainer); updateHighlightedSessions(); } function createHistorySessionElement() { // Create Float Button var floatButton = document.createElement("button"); floatButton.textContent = "☰"; floatButton.style.position = "fixed"; floatButton.style.left = "20px"; floatButton.style.top = "50%"; floatButton.style.transform = "translateY(-50%)"; floatButton.style.zIndex = "9999"; floatButton.style.padding = "15px"; floatButton.style.borderRadius = "100%"; floatButton.style.backgroundColor = "#212936"; floatButton.style.color = "white"; floatButton.style.border = "none"; floatButton.style.boxShadow = "0 2px 5px rgba(0,0,0,0.3)"; floatButton.style.transition = "left 0.3s ease"; floatButton.style.cursor = "pointer"; floatButton.addEventListener("click", function () { if (drawer.style.left === `-${scriptConfig.drawerWidth}px`) { drawer.style.left = "0"; floatButton.style.left = `${scriptConfig.drawerWidth}px`; } else { drawer.style.left = `-${scriptConfig.drawerWidth}px`; floatButton.style.left = "20px"; } }); document.body.appendChild(floatButton); // Create drawer container var drawer = document.createElement("div"); drawer.style.position = "fixed"; drawer.style.left = "-250px"; drawer.style.top = "0"; drawer.style.width = `${scriptConfig.drawerWidth}px`; drawer.style.height = "100%"; drawer.style.backgroundColor = "#212936"; drawer.style.transition = "0.3s"; drawer.style.zIndex = "9998"; drawer.style.padding = "15px"; drawer.style.boxSizing = "border-box"; drawer.style.color = "white"; drawer.style.overflowY = "auto"; document.body.appendChild(drawer); // Create Deawer Title var drawerTitle = document.createElement("h2"); drawerTitle.textContent = "History Session"; drawerTitle.style.padding = "10px"; drawerTitle.style.marginTop = "0"; drawerTitle.style.color = "white"; drawerTitle.style.backgroundColor = "#2c3e50"; drawerTitle.style.borderBottom = "1px solid #ccc"; drawer.appendChild(drawerTitle); // Create session item container itemList = document.createElement("div"); drawer.appendChild(itemList); // Click outside the drawer to turn off the drawer's function document.addEventListener("click", function (event) { // Check if the click is happening outside of the drawer or floating button if (!drawer.contains(event.target) && !floatButton.contains(event.target)) { updateHighlightedSessions(); // Opened if (drawer.style.left === "0px") { drawer.style.left = `-${scriptConfig.drawerWidth}px`; // hidden floatButton.style.left = "20px"; // restore } } }); // Create New Chat Button const newChatButton = document.createElement("button"); newChatButton.textContent = "New Chat"; newChatButton.style.position = "absolute"; newChatButton.style.bottom = "20px"; newChatButton.style.left = "50%"; newChatButton.style.transform = "translateX(-50%)"; newChatButton.style.padding = "10px 30px"; newChatButton.style.border = "none"; newChatButton.style.borderRadius = "5px"; newChatButton.style.backgroundColor = scriptConfig.mainColor; newChatButton.style.color = "white"; newChatButton.style.cursor = "pointer"; newChatButton.addEventListener("click", function () { handleNewChatClick(); }); drawer.appendChild(newChatButton); loadSessionHashHistory(); } function handleNewChatClick() { scriptConfig.currentSessionHash = Math.random().toString(36).substring(2); scriptConfig.firstMeetSessionHash = true; scriptConfig.firstSend = true; scriptConfig.loadLatestSession = false; clickSendBtn(); } // Update the highlighted state of the session list function updateHighlightedSessions() { const sessionItems = itemList.getElementsByClassName( "session-item-container" ); for (const item of sessionItems) { item.unhighlight(); // remove all highlight state } const newItem = itemList.querySelector( `[data-session-hash="${scriptConfig.currentSessionHash}"]` ); if (newItem) { newItem.highlight(); return; } } function getLastestSessionToggleBtn() { const gotoBtn = document.querySelectorAll( ".session-item-container button" )[0]; return gotoBtn; } function toggleLastestSession() { scriptConfig.firstSend = false; scriptConfig.firstMeetSessionHash = false; getLastestSessionToggleBtn().click(); } function loadSessionHashHistory() { itemList.innerHTML = ""; const list = JSON.parse(localStorage.getItem(scriptConfig.dataKey)) || []; for (let i = list.length - 1; i >= 0; i--) { let e = list[i]; createSessionItem(e.time, e.session_hash); } updateHighlightedSessions(); } function getCurrentFormattedTime() { const now = new Date(); const year = now.getFullYear().toString(); // year const month = (now.getMonth() + 1).toString().padStart(2, "0"); // month const date = now.getDate().toString().padStart(2, "0"); // day const hours = now.getHours().toString().padStart(2, "0"); // hout const minutes = now.getMinutes().toString().padStart(2, "0"); return `${year}-${month}-${date} ${hours}:${minutes}`; } function removeSessionHash(targetSessionHash) { const list = JSON.parse(localStorage.getItem(scriptConfig.dataKey)); let filteredList = list.filter( (item) => item.session_hash !== targetSessionHash ); localStorage.setItem(scriptConfig.dataKey, JSON.stringify(filteredList)); } function clickSendBtn() { $x(scriptConfig.position.sendBtn)[2].click(); } function saveCurrentSession() { const value = localStorage.getItem(scriptConfig.dataKey); let list = []; if (value) { list = JSON.parse(value); } list.push({ time: getCurrentFormattedTime(), session_hash: scriptConfig.currentSessionHash, }); localStorage.setItem(scriptConfig.dataKey, JSON.stringify(list)); loadSessionHashHistory(); } function initialize() { window.alert = null; WebSocket.prototype.send = hackWsSend; document.querySelector(scriptConfig.position.directChat).click(); removeUselessElements(); setMaxOutputToken(); changeModel(scriptConfig.model); } (function main() { // Add a style to highlight the current session const style = document.createElement("style"); style.type = "text/css"; style.innerHTML = ` .highlighted-session { background-color: #e0e0e0; color: #333; border-left: 3px solid #ffeb3b; } .disabled-button { pointer-events: none; opacity: 0.6; } `; document.head.appendChild(style); createHistorySessionElement(); // Create a MutationObserver instance and pass the callback function const observer = new MutationObserver((mutations, observer) => { // Find the target element using its ID (you may adjust the selector according to your needs) const targetElement = document.querySelector(scriptConfig.position.main); if (targetElement) { // If the target element exists, execute the optimize function and stop observing initialize(); observer.disconnect(); // Stop observing } }); // Configuration for the observer: const observerConfig = { childList: true, subtree: true }; // Select the node that will be observed for mutations const targetNode = document.body; // You may specify a more specific parent node to reduce the scope of observation // Call the observer's observe method to start observing the target node observer.observe(targetNode, observerConfig); })();