keep my ai conversations with formulas

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

Você precisará instalar uma extensão como Tampermonkey, Greasemonkey ou Violentmonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey ou Violentmonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey ou Violentmonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey ou Userscripts para instalar este script.

Você precisará instalar uma extensão como o Tampermonkey para instalar este script.

Você precisará instalar um gerenciador de scripts de usuário para instalar este script.

(Eu já tenho um gerenciador de scripts de usuário, me deixe instalá-lo!)

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

(Eu já possuo um gerenciador de estilos de usuário, me deixar fazer a instalação!)

// ==UserScript==
// @name         keep my ai conversations with formulas
// @name:fr      conserver mes conversations ia avec formules
// @description  keep conversations with formulas , generated by deepseek, chatgpt , mistral or claude
// @description:fr  conserver mes conversations ia avec formules , générées par deepseek, chatgpt , mistral ou claude
// @license MIT
// @namespace    http://tampermonkey.net/
// @version      2025-09-03
// @author       Guerard F
// @match        https://*/*
// @icon         data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
// @grant        none
// ==/UserScript==

(function() {
    'use strict';
    function processNode(node) {
        if (node.nodeType === Node.TEXT_NODE) {
            return node.textContent;
        }
        if (node.nodeType === Node.ELEMENT_NODE) {

            return node.outerHTML;
        }
        return '';
    }
    function extractMessages() {
        let htmlContent = `
<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document avec KaTeX</title>
    <!-- KaTeX CSS -->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.css">
    <!-- KaTeX JavaScript -->
    <script defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.js"></script>
    <!-- Auto-render Extension -->
    <script defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/contrib/auto-render.min.js"
        onload="renderMathInElement(document.body);"></script>
    <style>
    body {
      font-family: Arial, sans-serif;
      line-height: 1.6;
      padding: 20px;
    }
    .message {
      margin-bottom: 20px;
      padding: 10px;
      border-radius: 5px;
    }
    .question {
      background-color: #e0f7fa;
    }
    .reponse {
      background-color: #f1f8e9;
    }
    .role {
      font-weight: bold;
      margin-bottom: 5px;
    }
    </style>
</head>
<body>
        `;
        let clonedbody=document.body.cloneNode(true);
        clonedbody.querySelectorAll('svg').forEach(svg => svg.remove());
        if (ia=="deepseek" || ia=="gpt" || ia=="mistral" || ia=="claude") {
            if (ia=="deepseek" || ia=="gpt" || ia=="mistral") {
                clonedbody.querySelectorAll('span.katex').forEach(katexspan => {
                    const annotations = katexspan.querySelectorAll('annotation');
                    if (annotations.length === 1) {
                        const annotcontexttext = annotations[0].textContent;
                        const newSpan = document.createElement('span');
                        newSpan.textContent = `\\( ${annotcontexttext} \\)`;
                        katexspan.replaceWith(newSpan);
                    } else {
                        anomalies +='annotations non 1 trouvée;';
                    }
                });
            }

            switch (ia) {
                case "deepseek": {
                    //20250903 div.ds-markdown:not(.ds-think-content div.ds-markdown) pour écarter le texte thinking
                    let messages = clonedbody.querySelectorAll("div.fbb737a4, div.ds-markdown:not(.ds-think-content div.ds-markdown)");
                    for (let i = 0; i < messages.length; i++) {
                        if (messages[i].classList.contains("fbb737a4")) {
                            const question = messages[i].textContent.trim();
                            let answer = "";
                            if (messages[i + 1] && messages[i + 1].classList.contains("ds-markdown")) {
                                //20250903 ds-markdown--block > ds-markdown
                                answer = processNode(messages[i + 1]).trim();
                                i++;
                            }
                            htmlContent += `\n<div class="message question"><p><strong>Question:</strong></p>${question}</div>`;
                            htmlContent += `\n<div class="message reponse"><p><strong>Answer:</strong></p>${answer}</div>`;
                        }
                    }
                    break;
                }
                case "gpt": {
                    let messages = clonedbody.querySelectorAll("article.w-full");
                    for (let i = 0; i < messages.length; i++) {
                        const question = messages[i].textContent.trim();
                        const answer = processNode(messages[i + 1]).trim();
                        htmlContent += `\n<div class="message question"><p><strong>Question:</strong></p>${question}</div>`;
                        htmlContent += `\n<div class="message reponse"><p><strong>Answer:</strong></p>${answer}</div>`;
                        i++;
                    }
                    break;
                }
                case "mistral": {
                    let messages = clonedbody.querySelectorAll("div.group.gap-3");
                    for (let i = 0; i < messages.length; i++) {
                        const question = messages[i].textContent.trim();
                        const answer = processNode(messages[i + 1]).trim();
                        htmlContent += `\n<div class="message question"><p><strong>Question:</strong></p>${question}</div>`;
                        htmlContent += `\n<div class="message reponse"><p><strong>Answer:</strong></p>${answer}</div>`;
                        i++;
                    }
                    break;
                }
                case "claude": {
                    let messages = clonedbody.querySelectorAll("div[data-test-render-count]");
                    for (let i = 0; i < messages.length; i++) {
                        const question = messages[i].textContent.trim();
                        const answer = messages[i+1].outerHTML;
                        htmlContent += `\n<div class="message question"><p><strong>Question:</strong></p>${question}</div>`;
                        htmlContent += `\n<div class="message reponse"><p><strong>Answer:</strong></p>${answer}</div>`;
                        i++;
                    }
                    break;
                }
            }

            htmlContent += '\n</body></html>';
            const blob = new Blob([htmlContent], {type: 'text/html'});
            const url = URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            a.download = `export(${ia}).html`;
            a.click();
        }
    }
    let anomalies="anomalies?";
    var currentUrl = window.location.href;
    let ia="";
    switch (true) {
        case currentUrl.startsWith("https://chat.deepseek.com/"):
            ia="deepseek";
            break;
        case currentUrl.startsWith("https://chatgpt.com/"):
            ia="gpt";
            break;
        case currentUrl.startsWith("https://chat.mistral.ai/"):
            ia="mistral";
            break;
        case currentUrl.startsWith("https://claude.ai/"):
            ia="claude";
            break;
    }
    document.addEventListener('contextmenu', function(event) {
        const btn = document.createElement('button');
        btn.textContent = 'Export HTML';
        btn.style.zIndex = '9999';
        btn.style.position = 'fixed';
        btn.onclick = extractMessages;
        if (ia!="") {
            document.body.insertBefore(btn, document.body.firstChild);
        }
    }, true);
})();