keep my ai conversations with formulas

keep conversations with formulas , generated by deepseek, chatgpt , mistral or claude

  1. // ==UserScript==
  2. // @name keep my ai conversations with formulas
  3. // @name:fr conserver mes conversations ia avec formules
  4. // @description keep conversations with formulas , generated by deepseek, chatgpt , mistral or claude
  5. // @description:fr conserver mes conversations ia avec formules , générées par deepseek, chatgpt , mistral ou claude
  6. // @license MIT
  7. // @namespace http://tampermonkey.net/
  8. // @version 2025-04-04
  9. // @author Guerard F
  10. // @match https://*/*
  11. // @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
  12. // @grant none
  13. // ==/UserScript==
  14.  
  15. (function() {
  16. 'use strict';
  17. function processNode(node) {
  18. if (node.nodeType === Node.TEXT_NODE) {
  19. return node.textContent;
  20. }
  21. if (node.nodeType === Node.ELEMENT_NODE) {
  22.  
  23. return node.outerHTML;
  24. }
  25. return '';
  26. }
  27. function extractMessages() {
  28. let htmlContent = `
  29. <!DOCTYPE html>
  30. <html lang="fr">
  31. <head>
  32. <meta charset="UTF-8">
  33. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  34. <title>Document avec KaTeX</title>
  35. <!-- KaTeX CSS -->
  36. <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.0/dist/katex.min.css">
  37. <!-- KaTeX JavaScript -->
  38. <script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.0/dist/katex.min.js"></script>
  39. <!-- Auto-render Extension -->
  40. <script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.0/dist/contrib/auto-render.min.js"
  41. onload="renderMathInElement(document.body);"></script>
  42. <style>
  43. body {
  44. font-family: Arial, sans-serif;
  45. line-height: 1.6;
  46. padding: 20px;
  47. }
  48. .message {
  49. margin-bottom: 20px;
  50. padding: 10px;
  51. border-radius: 5px;
  52. }
  53. .question {
  54. background-color: #e0f7fa;
  55. }
  56. .reponse {
  57. background-color: #f1f8e9;
  58. }
  59. .role {
  60. font-weight: bold;
  61. margin-bottom: 5px;
  62. }
  63. </style>
  64. </head>
  65. <body>
  66. `;
  67. let clonedbody=document.body.cloneNode(true);
  68. clonedbody.querySelectorAll('svg').forEach(svg => svg.remove());
  69. if (ia=="deepseek" || ia=="gpt" || ia=="mistral" || ia=="claude") {
  70. if (ia=="deepseek" || ia=="gpt" || ia=="mistral") {
  71. clonedbody.querySelectorAll('span.katex').forEach(katexspan => {
  72. const annotations = katexspan.querySelectorAll('annotation');
  73. if (annotations.length === 1) {
  74. const annotcontexttext = annotations[0].textContent;
  75. const newSpan = document.createElement('span');
  76. newSpan.textContent = `\\( ${annotcontexttext} \\)`;
  77. katexspan.replaceWith(newSpan);
  78. } else {
  79. anomalies +='annotations non 1 trouvée;';
  80. }
  81. });
  82. }
  83.  
  84. switch (ia) {
  85. case "deepseek": {
  86. let messages = clonedbody.querySelectorAll("div.fbb737a4, div.ds-markdown--block");
  87. for (let i = 0; i < messages.length; i++) {
  88. if (messages[i].classList.contains("fbb737a4")) {
  89. const question = messages[i].textContent.trim();
  90. let answer = "";
  91. if (messages[i + 1] && messages[i + 1].classList.contains("ds-markdown--block")) {
  92. answer = processNode(messages[i + 1]).trim();
  93. i++;
  94. }
  95. htmlContent += `\n<div class="message question"><p><strong>Question:</strong></p>${question}</div>`;
  96. htmlContent += `\n<div class="message reponse"><p><strong>Answer:</strong></p>${answer}</div>`;
  97. }
  98. }
  99. break;
  100. }
  101. case "gpt": {
  102. let messages = clonedbody.querySelectorAll("article.w-full");
  103. for (let i = 0; i < messages.length; i++) {
  104. const question = messages[i].textContent.trim();
  105. const answer = processNode(messages[i + 1]).trim();
  106. htmlContent += `\n<div class="message question"><p><strong>Question:</strong></p>${question}</div>`;
  107. htmlContent += `\n<div class="message reponse"><p><strong>Answer:</strong></p>${answer}</div>`;
  108. i++;
  109. }
  110. break;
  111. }
  112. case "mistral": {
  113. let messages = clonedbody.querySelectorAll("div.group.gap-3");
  114. for (let i = 0; i < messages.length; i++) {
  115. const question = messages[i].textContent.trim();
  116. const answer = processNode(messages[i + 1]).trim();
  117. htmlContent += `\n<div class="message question"><p><strong>Question:</strong></p>${question}</div>`;
  118. htmlContent += `\n<div class="message reponse"><p><strong>Answer:</strong></p>${answer}</div>`;
  119. i++;
  120. }
  121. break;
  122. }
  123. case "claude": {
  124. let messages = clonedbody.querySelectorAll("div[data-test-render-count]");
  125. for (let i = 0; i < messages.length; i++) {
  126. const question = messages[i].textContent.trim();
  127. const answer = messages[i+1].outerHTML;
  128. htmlContent += `\n<div class="message question"><p><strong>Question:</strong></p>${question}</div>`;
  129. htmlContent += `\n<div class="message reponse"><p><strong>Answer:</strong></p>${answer}</div>`;
  130. i++;
  131. }
  132. break;
  133. }
  134. }
  135.  
  136. htmlContent += '\n</body></html>';
  137. const blob = new Blob([htmlContent], {type: 'text/html'});
  138. const url = URL.createObjectURL(blob);
  139. const a = document.createElement('a');
  140. a.href = url;
  141. a.download = `export(${ia}).html`;
  142. a.click();
  143. }
  144. }
  145. let anomalies="anomalies?";
  146. var currentUrl = window.location.href;
  147. let ia="";
  148. switch (true) {
  149. case currentUrl.startsWith("https://chat.deepseek.com/"):
  150. ia="deepseek";
  151. break;
  152. case currentUrl.startsWith("https://chatgpt.com/"):
  153. ia="gpt";
  154. break;
  155. case currentUrl.startsWith("https://chat.mistral.ai/"):
  156. ia="mistral";
  157. break;
  158. case currentUrl.startsWith("https://claude.ai/"):
  159. ia="claude";
  160. break;
  161. }
  162. document.addEventListener('contextmenu', function(event) {
  163. const btn = document.createElement('button');
  164. btn.textContent = 'Export HTML';
  165. btn.style.zIndex = '9999';
  166. btn.style.position = 'fixed';
  167. btn.onclick = extractMessages;
  168. if (ia!="") {
  169. document.body.insertBefore(btn, document.body.firstChild);
  170. }
  171. }, true);
  172. })();
  173.  
  174.  
  175.