Save Conversation

Save the conversation as a .txt file

当前为 2025-05-30 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Save Conversation
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.81
  5. // @description Save the conversation as a .txt file
  6. // @match *chatgpt.com/*
  7. // @match *.deepseek.com/*
  8. // @grant none
  9. // ==/UserScript==
  10.  
  11. (function() {
  12. 'use strict';
  13.  
  14. function capitalizeRole(role) {
  15. if (role === 'user') return 'User';
  16. if (role === 'assistant') return 'Assistant';
  17. return role.charAt(0).toUpperCase() + role.slice(1);}
  18.  
  19. function generateFileName(messages) {
  20. let raw = (document.querySelector('title') || {}).textContent;
  21. if (raw) {
  22. let name = raw.trim()
  23. .slice(0, 40);
  24. return name || 'conversation';}
  25. let firstWords = messages[0].text.split(/\s+/).slice(0, 5).join(' ');
  26. let snippet = firstWords.toLowerCase()
  27. .replace(/[^a-z0-9 ]/g, '')
  28. .replace(/\s+/g, '_')
  29. .slice(0, 30);
  30. return snippet || 'conversation';}
  31.  
  32. function saveConversation() {
  33. const containers = document.querySelectorAll('[data-message-id]');
  34. const messages = [];
  35. containers.forEach(el => {
  36. const role = el.getAttribute('data-message-author-role');
  37. let content = el.querySelector('.whitespace-pre-wrap') || el.querySelector('.markdown');
  38. if (role && content) {
  39. let text = content.innerText.trim();
  40. messages.push({ role: capitalizeRole(role), text });}
  41. });
  42. if (!messages.length) {
  43. alert('No conversation found to save.');
  44. return;}
  45. const body = messages.map(m => `${m.role}:\n${m.text}`).join('\n\n---\n\n');
  46. const blob = new Blob([body], { type: 'text/plain' });
  47. const url = URL.createObjectURL(blob);
  48. const a = document.createElement('a');
  49. a.href = url;
  50. a.download = generateFileName(messages) + '.txt';
  51. document.body.appendChild(a);
  52. a.click();
  53. document.body.removeChild(a);
  54. URL.revokeObjectURL(url);
  55. }
  56.  
  57. function createDownloadButton() {
  58. if (document.getElementById('save-convo-button')) return;
  59. const btn = document.createElement('button');
  60. btn.id = 'save-convo-button';
  61. btn.title = 'Save conversation';
  62. btn.style.position = 'fixed';
  63. btn.style.top = '0';
  64. btn.style.left = '0';
  65. btn.style.width = '12px';
  66. btn.style.height = '30px';
  67. btn.style.backgroundColor = '#ececec';
  68. btn.style.borderRadius = '4px';
  69. btn.style.zIndex = 9999;
  70. btn.style.cursor = 'pointer';
  71. btn.addEventListener('click', saveConversation);
  72. document.body.appendChild(btn);
  73. }
  74.  
  75. const waitForBody = setInterval(() => {
  76. if (document.body && document.querySelector('[data-message-id]')) {
  77. clearInterval(waitForBody);
  78. createDownloadButton();}
  79. }, 500);
  80. })();