您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
A toggleable panel that lets you delete any turn. You need c.ai Neo Panel as well in order to use this
// ==UserScript== // @name c.ai Neo Panel Delete // @namespace c.ai Neo Panel Delete // @version 1.0 // @description A toggleable panel that lets you delete any turn. You need c.ai Neo Panel as well in order to use this // @author vishanka // @license MIT // @match https://*.character.ai/chat* // @icon https://i.imgur.com/iH2r80g.png // @grant none // ==/UserScript== (function() { 'use strict'; // WebSocket handling const socket = new WebSocket('wss://neo.character.ai/ws/'); socket.addEventListener('open', () => { console.log('Socket connection opened.'); }); socket.addEventListener('error', (error) => { console.error('Socket error:', error); }); socket.addEventListener('close', () => { console.log('Socket connection closed.'); }); function sendSocketMessage(socket, message, reload) { socket.send(JSON.stringify(message)); if (reload) { location.reload(); } } var original_prototype_open = XMLHttpRequest.prototype.open; const intercepted_data_object_delete = {}; XMLHttpRequest.prototype.open = function(method, url, async) { if ( url.startsWith('https://plus.character.ai/chat/history/continue/') || url.startsWith('https://plus.character.ai/chat/character/info') || url.startsWith('https://beta.character.ai/chat/history/continue/') || url.startsWith('https://beta.character.ai/chat/character/info') ) { this.addEventListener('load', function() { let info1_delete = JSON.parse(this.responseText); intercepted_data_object_delete.external_id = info1_delete.character.external_id; intercepted_data_object_delete.name = info1_delete.character.name; console.log("character_id:",intercepted_data_object_delete.external_id); // Only create the toggle button and the panel once if (!document.getElementById('NeoPanelDelete')) { // createToggleButton_NeoPanelDelete(); createNeoPanelDelete(); } }); } else if (url.startsWith(`https://neo.character.ai/chats/recent/${intercepted_data_object_delete.external_id}`)) { this.addEventListener('load', function() { let info2_delete = JSON.parse(this.responseText); intercepted_data_object_delete.chat_id = info2_delete.chats[0].chat_id; console.log("chat_id:",intercepted_data_object_delete.chat_id); }); // ---------------------------------- Ab hier kann ich turns extracten ---------------------------------------- } else if (url.startsWith(`https://neo.character.ai/turns/${intercepted_data_object_delete.chat_id}`)) { this.addEventListener('load', function() { let info3_delete = JSON.parse(this.responseText); intercepted_data_object_delete.total_turns = info3_delete.turns.length; console.log("total_turns:", intercepted_data_object_delete.total_turns); const delete_list = document.createElement('div'); delete_list.style.textAlign = 'left'; delete_list.style.marginTop = '10px'; delete_list.style.overflowY = 'auto'; // Iterate through the turns array in reverse for (let i = 0; i < info3_delete.turns.length; i++) { let turn = info3_delete.turns[i]; let turn_id = turn.turn_key.turn_id; let candidates = turn.candidates; let name = turn.author.name; if (candidates.length > 0) { let raw_content = candidates[0].raw_content; // Create a container for each raw_content const contentContainer = document.createElement('div'); contentContainer.style.cursor = 'pointer'; // Make it appear clickable contentContainer.style.alignItems = 'center'; // Center-align vertically contentContainer.style.direction = 'ltr'; contentContainer.style.transform = 'rotate(180deg)'; // Function to toggle the red color function toggleRedColor() { if (contentContainer.style.backgroundColor === 'red') { contentContainer.style.backgroundColor = ''; } else { contentContainer.style.backgroundColor = 'red'; } } // Add click event to toggle red color contentContainer.addEventListener('click', toggleRedColor); // Create a div element for the name const nameDiv = document.createElement('div'); nameDiv.style.fontWeight = 'bold'; // Make the name bold nameDiv.textContent = name; // Use the "name" variable contentContainer.appendChild(nameDiv); // Create a div element for the raw_content const div = document.createElement('div'); div.style.textAlign = 'left'; div.style.overflowWrap = 'break-word'; div.style.whiteSpace = 'pre-wrap'; div.style.color = '#958C7F'; // Changes the color of the text const formattedContent = raw_content.replace(/(["“”«»].*?["“”«»])/g, '<span style="color: #FFFFFF">$1</span>'); const finalContent1 = formattedContent.replace(/\*\*(.*?)\*\*/g, '<span style="font-weight: bold;">$1</span>'); const finalContent = finalContent1.replace(/\*(.*?)\*/g, '<span style="font-style: italic; color: #E0DF7F;">$1</span>'); // Use regular expressions to find text within backticks and apply formatting const formattedBackticks_3 = finalContent.replace(/```([^`]*)```/g, '<div style="display: inline-block; margin: 0px 10px; vertical-align: middle;"><div style="color: white; font-family: Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace; text-align: left; white-space: pre; word-spacing: normal; word-break: normal; overflow-wrap: normal; line-height: 1.5; font-size: 13px; tab-size: 4; hyphens: none; padding: 5px; margin: 0px; overflow: auto; background: rgb(1, 22, 39);"><code style="color: rgb(214, 222, 235); font-family: Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace; text-align: left; white-space: pre-wrap; word-spacing: normal; word-break: normal; overflow-wrap: normal; line-height: 1.5; font-size: 1em; tab-size: 4; hyphens: none;">$1</code></div></div>'); const formattedBackticks_tilde = formattedBackticks_3.replace(/~~~([^`]*)~~~/g, '<div style="display: inline-block; margin: 0px 10px; vertical-align: middle;"><div style="color: white; font-family: Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace; text-align: left; white-space: pre; word-spacing: normal; word-break: normal; overflow-wrap: normal; line-height: 1.5; font-size: 13px; tab-size: 4; hyphens: none; padding: 5px; margin: 0px; overflow: auto; background: rgb(1, 22, 39);"><code style="color: rgb(214, 222, 235); font-family: Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace; text-align: left; white-space: pre-wrap; word-spacing: normal; word-break: normal; overflow-wrap: normal; line-height: 1.5; font-size: 1em; tab-size: 4; hyphens: none;">$1</code></div></div>'); const formattedBackticks_1 = formattedBackticks_tilde.replace(/`(?!`)(.*?)`/g, '<div style="display: inline-block; margin: 0px 10px; vertical-align: middle;"><div style="color: white; font-family: Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace; text-align: left; white-space: pre; word-spacing: normal; word-break: normal; overflow-wrap: normal; line-height: 1.5; font-size: 13px; tab-size: 4; hyphens: none; padding: 5px; margin: 0px; overflow: auto; background: rgb(1, 22, 39);"><code style="color: rgb(214, 222, 235); font-family: Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace; text-align: left; white-space: pre-wrap; word-spacing: normal; word-break: normal; overflow-wrap: normal; line-height: 1.5; font-size: 1em; tab-size: 4; hyphens: none;">$1</code></div></div>'); // Set the final formatted content as innerHTML div.innerHTML = formattedBackticks_1; contentContainer.appendChild(div); // Add a horizontal line const hr = document.createElement('hr'); contentContainer.appendChild(hr); // Add a click event listener contentContainer.addEventListener('click', () => { // Create a custom modal const modal = document.createElement('div'); modal.style.position = 'fixed'; modal.style.top = '0'; modal.style.left = '0'; modal.style.width = '100%'; modal.style.height = '100%'; modal.style.backgroundColor = 'rgba(0, 0, 0, 0.5)'; modal.style.display = 'flex'; modal.style.justifyContent = 'center'; modal.style.alignItems = 'center'; modal.style.zIndex = '9999'; // Create modal content const modalContent = document.createElement('div'); modalContent.style.backgroundColor = 'white'; modalContent.style.padding = '20px'; modalContent.style.borderRadius = '5px'; modalContent.style.textAlign = 'center'; modal.appendChild(modalContent); // Create message element const messageElement = document.createElement('p'); messageElement.textContent = 'The selected message will be deleted. Proceed?'; messageElement.style.marginBottom = '20px'; modalContent.appendChild(messageElement); // Create "Yes" button const yesButton = document.createElement('button'); yesButton.textContent = 'Confirm'; yesButton.style.marginRight = '10px'; yesButton.style.backgroundColor = 'red'; // Example button color yesButton.style.color = 'white'; // Example text color yesButton.style.border = 'none'; yesButton.style.borderRadius = '3px'; yesButton.style.padding = '5px 15px'; yesButton.addEventListener('click', () => { // Remove the modal document.body.removeChild(modal); // Your existing code for deletion const delete_commandJson = `{ "command": "remove_turns", "request_id": "", "payload": { "chat_id": "${intercepted_data_object_delete.chat_id}", "turn_ids": ["${turn_id}"] }, "origin_id": "" }`; const deleteCommand = JSON.parse(delete_commandJson); sendSocketMessage(socket, deleteCommand, true); // Pass `true` for reload argument }); modalContent.appendChild(yesButton); // Create "No" button const noButton = document.createElement('button'); noButton.textContent = 'Cancel'; noButton.style.backgroundColor = 'gray'; // Example button color noButton.style.color = 'white'; // Example text color noButton.style.border = 'none'; noButton.style.borderRadius = '3px'; noButton.style.padding = '5px 15px'; noButton.addEventListener('click', () => { // Remove the modal document.body.removeChild(modal); // Reset red color on "No" button click toggleRedColor(); }); modalContent.appendChild(noButton); // Append the modal to the body document.body.appendChild(modal); }); delete_list.appendChild(contentContainer); } } // Append the delete_list to NeoPanelDelete NeoPanelDelete.appendChild(delete_list); const lastContentContainer = delete_list.lastElementChild; lastContentContainer.scrollIntoView({ behavior: 'smooth', block: 'end' }); XHR_interception_resolve(intercepted_data_object_delete); }); } original_prototype_open.apply(this, [method, url, async]); }; let XHR_interception_resolve; const XHR_interception_promise = new Promise(function(resolve, reject) { XHR_interception_resolve = resolve; }); XHR_interception_promise.then(function() { console.log("Intercepted Data:", intercepted_data_object_delete); // Add a horizontal line (divider) const divider_Delete1 = document.createElement('hr'); divider_Delete1.style.marginTop = '-5px'; NeoPanelDelete.appendChild(divider_Delete1); // Add greeting header to the panel const Delete_headline = document.createElement('h5'); Delete_headline.textContent = 'Greeting'; Delete_headline.style.marginTop = '0px'; Delete_headline.style.textAlign = 'center'; // Center-align the text Delete_headline.style.transform = 'rotate(180deg)'; NeoPanelDelete.appendChild(Delete_headline); }); /*function createToggleButton_NeoPanelDelete() { const toggleButton_NeoPanelDelete = document.createElement('button'); toggleButton_NeoPanelDelete.textContent = 'Swipe List'; toggleButton_NeoPanelDelete.style.position = 'fixed'; toggleButton_NeoPanelDelete.style.bottom = '0px'; toggleButton_NeoPanelDelete.style.right = '0%'; toggleButton_NeoPanelDelete.style.backgroundColor = '#3E4040'; toggleButton_NeoPanelDelete.style.color = 'white'; toggleButton_NeoPanelDelete.style.fontWeight = 'bold'; toggleButton_NeoPanelDelete.style.padding = '4px'; toggleButton_NeoPanelDelete.style.margin = '0px'; toggleButton_NeoPanelDelete.style.width = '15%'; toggleButton_NeoPanelDelete.style.border = 'none'; toggleButton_NeoPanelDelete.style.borderRadius = '0px'; toggleButton_NeoPanelDelete.style.cursor = 'pointer'; toggleButton_NeoPanelDelete.style.userSelect = 'none'; toggleButton_NeoPanelDelete.style.zIndex = '101'; toggleButton_NeoPanelDelete.addEventListener('click', toggleNeoPanelDelete); document.body.appendChild(toggleButton_NeoPanelDelete); }*/ function createNeoPanelDelete() { const NeoPanelDelete = document.createElement('div'); NeoPanelDelete.id = 'NeoPanelDelete'; NeoPanelDelete.style.position = 'fixed'; NeoPanelDelete.style.bottom = '0px'; NeoPanelDelete.style.left = '15%'; NeoPanelDelete.style.width = '15%'; NeoPanelDelete.style.height = '100%'; NeoPanelDelete.style.backgroundColor = 'white'; NeoPanelDelete.style.borderLeft = '1px solid #ccc'; NeoPanelDelete.style.padding = '10px'; NeoPanelDelete.style.zIndex = '100'; NeoPanelDelete.style.resize = 'none'; NeoPanelDelete.style.direction = 'rtl'; NeoPanelDelete.style.overflow = 'auto'; // Set the initial display state to 'none' NeoPanelDelete.style.display = 'none'; NeoPanelDelete.style.transform = 'rotate(180deg)'; // Add a wheel event listener to reverse the scroll direction NeoPanelDelete.addEventListener('wheel', (event) => { // Reverse the wheel event's deltaY to reverse the scroll direction const scrollAmount = event.deltaY * -1; // Scroll the panel content by the reversed amount NeoPanelDelete.scrollTop += scrollAmount; // Prevent the default scroll behavior event.preventDefault(); }); document.body.appendChild(NeoPanelDelete); } /* function toggleNeoPanelDelete() { const NeoPanelDelete = document.getElementById('NeoPanelDelete'); if (NeoPanelDelete.style.display === 'block') { NeoPanelDelete.style.display = 'none'; } else { NeoPanelDelete.style.display = 'block'; } } */ })();