Save Unsent AI Prompts

Auto-save unsent AI prompts as drafts

// ==UserScript==
// @name         Save Unsent AI Prompts
// @namespace    Violent Monkey Scripts
// @version      1.0
// @description  Auto-save unsent AI prompts as drafts
// @match        https://chatgpt.com/*
// @grant        none
// @license      MIT
// ==/UserScript==

/*
Doesn't it suck that chatgpt saves all your history unless you don't send it. There is no draft system in chatgpt.

This userscript will make it so you can dig for it in localStorage if you really need it.

Continued discussion about this userscript can be found here: https://goatmatrix.net/c/Userscripts/9sBaPCiRRE
*/

;(async function(){
 for await (let newTarget of targetDivs()) {
  applyHandler(newTarget);
 }
})();

function timeout(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
 }

 // Continuously looks for new #prompt-textarea divs
 async function* targetDivs() {
  let found = new Set();
  while(true) {
   let divs = document.querySelectorAll('#prompt-textarea');
   for(let div of divs) {
    if(!found.has(div)) {
     found.add(div);
     yield div;
    }
   }
   await timeout(500);
  }
 }

function shouldSaveDraft(oldVal, newVal) {
  // Save if text was added or replaced (not pure deletion).
  if (newVal.length > oldVal.length) return true;
  if (newVal.length === oldVal.length && newVal !== oldVal) return true;
  return false;
}

function saveDraft(id, text) {
 localStorage.setItem('draft-'+id, text);
}

function applyHandler(div) {
 let currentId = null;
 let oldValue = '';

 // Called whenever mutations occur
 function onDivMutate() {
  let newValue = div.innerHTML.trim();
  if (!newValue) {
   // If there's nothing left, reset
   currentId = null;
   oldValue = '';
   return;
  }
  // If we had no oldValue, this is the first time we're typing => new ID
  if (!oldValue || !currentId) {
   currentId = Date.now();
  }
  // Only save if something was added (newValue got longer than oldValue)
  if(shouldSaveDraft(oldValue,newValue)) {
   saveDraft(currentId,newValue);
  }
  // Update the known current content
  oldValue = newValue;
 }

 // Observe changes in the div (childList & characterData changes)
 let observer = new MutationObserver(onDivMutate);
 observer.observe(div, {childList: true, characterData: true, subtree: true});
}

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址