您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
1) Real-Time Local Disk Storage: ChatGPTHelper automatically saves all your chat history and predefined prompts on your local disk as you go. 2) No Official History Required: You won't need to fine-tune it with official history data. Your information remains confidential, never used to train the model. 3) Offline Functionality: ChatGPTHelper makes the histtory still available when offline.
当前为
- // ==UserScript==
- // @name ChatGPTHelper
- // @namespace http://tampermonkey.net/
- // @version 0.4
- // @description 1) Real-Time Local Disk Storage: ChatGPTHelper automatically saves all your chat history and predefined prompts on your local disk as you go. 2) No Official History Required: You won't need to fine-tune it with official history data. Your information remains confidential, never used to train the model. 3) Offline Functionality: ChatGPTHelper makes the histtory still available when offline.
- // @author maple
- // @match https://chat.openai.com/*
- // @grant GM_xmlhttpRequest
- // @license GPL-3.0-or-later
- // ==/UserScript==
- (function() {
- 'use strict';
- const WEBREDIS_ENDPOINT = "http://127.0.0.1:7379";
- var thisInHistory = false;
- var HistoryPrefix = "HISTORY";
- var PromptPrefix = "USERPROMPT";
- /*---------------------------------History-------------------------------------*/
- function load(key, callback) {
- key = encodeURIComponent(key);
- GM_xmlhttpRequest({
- method: "GET",
- url: `${WEBREDIS_ENDPOINT}/GET/${key}`,
- onload: function(response) {
- callback(null, JSON.parse(response.responseText));
- },
- onerror: function(error) {
- callback(error, null);
- }
- });
- }
- function save(nameprefix, data, callback) {
- var strdata;
- var dname;
- var currentTimestamp = "";
- if (Array.isArray(data)) {// history
- strdata = JSON.stringify(data.map(function(element) {
- return element.innerHTML;
- }));
- dname = data[0].innerText.substring(0, 50).trim();
- var date = new Date();
- currentTimestamp = date.toLocaleString().substring(0, 19);
- } else {//prompt
- strdata = JSON.stringify(data);
- dname = data.substring(0, 50).trim();
- }
- if (strdata && strdata.length < 3){
- return;
- }
- var redisname = encodeURIComponent(nameprefix + currentTimestamp + "\n" + dname);
- console.log(redisname);
- GM_xmlhttpRequest({
- method: "GET",
- url: `${WEBREDIS_ENDPOINT}/SET/${redisname}/${encodeURIComponent(strdata)}`,
- onload: function(response) {
- console.log(response);
- callback(null, response.responseText);
- },
- onerror: function(error) {
- console.log(error);
- callback(error, null);
- }
- });
- }
- function remove(key, callback) {
- key = encodeURIComponent(key);
- GM_xmlhttpRequest({
- method: "GET",
- url: `${WEBREDIS_ENDPOINT}/DEL/${key}`,
- onload: function(response) {
- callback(null, JSON.parse(response.responseText));
- },
- onerror: function(error) {
- callback(error, null);
- }
- });
- }
- function getAllRedisKeys(callback) {
- GM_xmlhttpRequest({
- method: "GET",
- url: `${WEBREDIS_ENDPOINT}/KEYS/*`, // Update this to your actual endpoint
- onload: function(response) {
- if (response.responseText == undefined){
- redisError();
- return;
- }
- callback(null, JSON.parse(response.responseText));
- },
- onerror: function(error) {
- callback(error, null);
- }
- });
- }
- function getCurrentDialogContent() {
- // Get all div elements with the specified class
- const divsWithSpecificClass = document.querySelectorAll('div.flex.flex-grow.flex-col.gap-3.max-w-full');
- // Create an array to store the text content of each div
- const divTexts = [];
- // Loop through the NodeList and get the text content of each div
- divsWithSpecificClass.forEach(div => {
- var textContent = [];
- divTexts.push(div);
- });
- // Return the array of text contents
- return divTexts;
- }
- function sleep(ms) {
- return new Promise(resolve => setTimeout(resolve, ms));
- }
- function showHistory(dataList) {
- var targetDiv = document.querySelector('div.flex-1.overflow-hidden > div > div > div');
- /*while(targetDiv.firstChild) {
- targetDiv.removeChild(targetDiv.firstChild);
- }*/
- dataList.forEach(data => {
- var newDiv = document.createElement('div');
- newDiv.textContent = data;
- targetDiv.appendChild(newDiv);
- });
- }
- function makeAGroup(name, keys, elementfilter, clickcallback){
- const ul = document.createElement('ul');
- ul.style.overflowY = 'auto';
- ul.style.maxHeight = '500px';
- var eid = "myUl" + name
- ul.id = eid; // Setting an ID to the ul element
- var h2 = document.createElement('h2');
- h2.innerText = name;
- h2.style.color = 'white';
- h2.style.textAlign = "center";
- ul.append(h2);
- for (let i = 0; i < keys.length; i++) {
- const li = document.createElement('li');
- if(!keys[i].startsWith(elementfilter)){
- continue;
- }
- li.innerHTML = keys[i].substring(elementfilter.length, keys[i].length).replace(/\n/g, '<br>');;
- li.style.color = 'white';
- // Apply CSS styles for the rounded rectangle
- li.style.border = '1px solid white'; // Add a border
- li.style.borderRadius = '10px'; // Adjust the horizontal and vertical radii to create rounded corners
- li.style.padding = '5px'; // Add some padding to make it visually appealing
- li.style.position = 'relative';
- li.addEventListener('mouseenter', function() {
- li.style.backgroundColor = 'grey'; // Change to your desired background color
- });
- li.addEventListener('mouseleave', function() {
- li.style.backgroundColor = ''; // Reset to the original background color
- });
- li.addEventListener('click', (event) => {clickcallback(event, keys[i]);});
- // add close
- // Create close button
- const closeButton = document.createElement('span');
- closeButton.textContent = '✖';
- closeButton.style.position = 'absolute';
- closeButton.style.top = '5px';
- closeButton.style.right = '5px';
- closeButton.style.color = 'white';
- closeButton.style.cursor = 'pointer'; // Set cursor to pointer to indicate it's clickable
- // Add event listener for the close button
- closeButton.addEventListener('click', async (event) => {
- // Your callback function here
- event.stopPropagation();
- remove(keys[i], function (){});
- await sleep(500);
- InitPanel();
- });
- // Add close button to li
- li.appendChild(closeButton);
- ul.appendChild(li);
- }
- return ul;
- }
- async function InitPanel() {
- getAllRedisKeys(function(error, data) {
- if (error) {
- redisError();
- console.error('An error occurred:', error);
- return;
- }
- const ol = document.querySelectorAll('ol')[2];
- var div = document.querySelectorAll('div.flex-shrink-0.overflow-x-hidden')[0];
- const ulExisting = document.getElementById('myUlHistory');
- if (ulExisting) {
- div.removeChild(ulExisting, function (){});
- }
- if (data.KEYS.length == 0){
- redisError();
- }
- var ul = makeAGroup("History", data.KEYS.sort().reverse(), HistoryPrefix, function(event, key) {
- //console.log('Item clicked:', data.KEYS[i]);
- // Load data after saving
- load(key, function(err, data) {
- if (err) return console.error(err);
- var myList = JSON.parse(data.GET);
- if (Array.isArray(myList)){
- for (let i = 0; i < myList.length; i++) {
- if (i % 2 == 0) {
- myList[i] = "👨: " + myList[i].replace(/\n/g, '<br>');
- } else {
- myList[i] = "🤖: " + myList[i].replace(/\n/g, '<br>');
- }
- }
- showHistoryLog(myList.join("<br>"));
- }
- });
- });
- div.prepend(ul);
- /*---Prompt---*/
- var ulPrompt = document.getElementById('myUlPrompt');
- if (ulPrompt) {
- div.removeChild(ulPrompt);
- }
- var prompt = makeAGroup("Prompt", data.KEYS.sort().reverse(), PromptPrefix, function(event, key) {
- //console.log('Item clicked:', data.KEYS[i]);
- // Load data after saving
- load(key, function(err, data) {
- if (err) return console.error(err);
- var prompt = JSON.parse(data.GET);
- var textarea = document.getElementById('prompt-textarea');
- textarea.value = prompt;
- });
- });
- div.prepend(prompt);
- if (!ulPrompt) {
- var button = document.createElement('button');
- button.innerText = 'Save Message As Prompt';
- button.style.color = 'white';
- button.style.position = 'relative';
- button.style.textAlign = 'center';
- button.style.border = '1px solid white';
- button.style.backgroundColor = '#268BD2';
- var bottomdiv = document.querySelectorAll('div.relative.pb-3.pt-2.text-center.text-xs.text-gray-600')[0];
- bottomdiv.appendChild(button);
- button.addEventListener('click', function() {
- var textarea = document.getElementById('prompt-textarea');
- save(PromptPrefix, textarea.textContent, function(err, response) {
- if (err) return console.error(err);
- });
- InitPanel();
- });
- }
- });
- /*Remote Offical*/
- await sleep(2000);
- const olElements = document.querySelectorAll('ol');
- olElements.forEach(ol => {
- // First remove all existing children
- while (ol.firstChild) {
- ol.removeChild(ol.firstChild);
- }
- });
- }
- function redisError(){
- var div = document.querySelectorAll('div.flex-shrink-0.overflow-x-hidden')[0];
- const ul = document.createElement('ul');
- div.prepend(ul);
- const li = document.createElement('li');
- li.textContent = "There is no record. Please verify if webdis AND redis-server has been started! Just run `webdis.sh start` to start.";
- li.style.color = 'white';
- ul.appendChild(li);
- }
- function showHistoryLog(text) {
- // Check if the div with a specific id already exists
- var existingDiv = document.getElementById('historyLog');
- if (existingDiv) {
- // If the div exists, update the messageSpan's HTML content
- var messageSpan = existingDiv.querySelector('.message-span');
- if (messageSpan) {
- messageSpan.innerHTML = text;
- }
- existingDiv.style.display = '';
- } else {
- // If the div doesn't exist, create a new div and append it to the body
- var hoverBox = document.createElement('div');
- hoverBox.id = 'historyLog'; // Set a unique id for the div
- hoverBox.style.position = 'fixed';
- hoverBox.style.top = '50%';
- hoverBox.style.left = '50%';
- hoverBox.style.transform = 'translate(-50%, -50%)';
- hoverBox.style.zIndex = '10000';
- hoverBox.style.padding = '10px';
- hoverBox.style.width = '1000px';
- hoverBox.style.height = '800px';
- hoverBox.style.backgroundColor = 'white';
- hoverBox.style.border = '1px solid black';
- hoverBox.style.borderRadius = '5px';
- hoverBox.style.boxShadow = '0px 0px 10px rgba(0, 0, 0, 0.5)';
- hoverBox.style.overflow = 'hidden'; // Hide content overflow
- // Create a container div for the content and close button
- var contentContainer = document.createElement('div');
- contentContainer.style.overflowY = 'auto'; // Make content scrollable
- //contentContainer.style.resize = 'both'; // Enable resizing
- contentContainer.style.height = 'calc(100% - 40px)'; // Adjust height for close button
- // Create a span element to hold the message
- var messageSpan = document.createElement('span');
- messageSpan.innerHTML = text;
- messageSpan.className = 'message-span'; // Add a class for easy selection
- messageSpan.style.display = 'block';
- messageSpan.style.marginTop = '20px';
- // Create a button element to close the hover box
- var closeButton = document.createElement('button');
- closeButton.textContent = '✖';
- closeButton.style.position = 'absolute';
- closeButton.style.top = '10px';
- closeButton.style.right = '10px';
- closeButton.addEventListener('click', function () {
- hoverBox.style.display = 'none';
- });
- // Add the message span and close button to the content container
- contentContainer.appendChild(messageSpan);
- contentContainer.appendChild(closeButton);
- // Add the content container to the hover box
- hoverBox.appendChild(contentContainer);
- document.addEventListener('click', function (event) {
- if (!hoverBox.contains(event.target) && event.target !== hoverBox) {
- hoverBox.style.display = 'none';
- }
- });
- // Add the hover box to the body of the document
- document.body.appendChild(hoverBox);
- }
- }
- InitPanel();
- document.addEventListener('keydown', async function(event) {
- if (event.key === 'Enter' || (event.metaKey && event.key === 'r')) {
- // Usage examples
- while(true){
- var thisdialog = getCurrentDialogContent();
- save(HistoryPrefix, thisdialog, function(err, response) {
- if (err) return console.error(err);
- console.log('Save response:', response);
- if(!thisInHistory){
- InitPanel();
- thisInHistory = true;
- }
- });
- const divElement = document.querySelector('div.flex.items-center.md\\:items-end');
- if (divElement == undefined || divElement.textContent == undefined || divElement.textContent != 'Stop generating'){
- break;
- }
- await sleep(2000);
- }
- }
- if (event.key === 'Escape') {
- var existingDiv = document.getElementById('historyLog');
- if (existingDiv) {
- existingDiv.style.display = 'none';
- }
- }
- });
- })();