keep my ai conversations with formulas

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

Dovrai installare un'estensione come Tampermonkey, Greasemonkey o Violentmonkey per installare questo script.

Dovrai installare un'estensione come Tampermonkey o Violentmonkey per installare questo script.

Dovrai installare un'estensione come Tampermonkey o Violentmonkey per installare questo script.

Dovrai installare un'estensione come Tampermonkey o Userscripts per installare questo script.

Dovrai installare un'estensione come ad esempio Tampermonkey per installare questo script.

Dovrai installare un gestore di script utente per installare questo script.

(Ho già un gestore di script utente, lasciamelo installare!)

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

(Ho già un gestore di stile utente, lasciamelo installare!)

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