keep my ai conversations with formulas

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

K instalaci tototo skriptu si budete muset nainstalovat rozšíření jako Tampermonkey, Greasemonkey nebo Violentmonkey.

K instalaci tohoto skriptu si budete muset nainstalovat rozšíření jako Tampermonkey nebo Violentmonkey.

K instalaci tohoto skriptu si budete muset nainstalovat rozšíření jako Tampermonkey nebo Violentmonkey.

K instalaci tohoto skriptu si budete muset nainstalovat rozšíření jako Tampermonkey nebo Userscripts.

You will need to install an extension such as Tampermonkey to install this script.

K instalaci tohoto skriptu si budete muset nainstalovat manažer uživatelských skriptů.

(Už mám manažer uživatelských skriptů, nechte mě ho nainstalovat!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(Už mám manažer uživatelských stylů, nechte mě ho nainstalovat!)

// ==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);
})();