Greasy Fork

适用AI的LaTeX公式格式转换工具

将LaTeX公式格式转换为Markdown格式

// ==UserScript==
// @name         适用AI的LaTeX公式格式转换工具
// @namespace    http://tampermonkey.net/
// @version      2.0
// @description  将LaTeX公式格式转换为Markdown格式
// @author       榛铭
// @match        https://tongyi.aliyun.com/qianwen/*
// @match        https://chat.openai.com/*
// @match        https://kimi.moonshot.cn/*
// @match        https://chatgpt.com/**
// @grant        GM_addStyle
// @license      MIT
// ==/UserScript==
 
 
(function() {
    'use strict';
    
    // 添加 Font Awesome
    document.head.appendChild(Object.assign(document.createElement('link'), {
        rel: 'stylesheet',
        href: 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css'
    }));
 
    // 添加基础样式
    GM_addStyle(`
        #formula-converter {
            position: fixed;
            top: 20vh;
            right: 0;
            background: white;
            border: 1px solid #ccc;
            border-radius: 8px;
            padding: 15px;
            width: 500px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
            z-index: 9999;
            font-family: Arial, sans-serif;
            max-height: 90vh;
            display: flex;
            flex-direction: column;
            transition: width 0.3s ease, height 0.3s ease, padding 0.3s ease;
        }
        #formula-converter textarea {
            width: 100%;
            height: 150px;
            margin: 10px 0;
            padding: 8px;
            border: 1px solid #ddd;
            border-radius: 4px;
            resize: vertical;
        }
        #formula-converter button {
            background: #4CAF50;
            color: white;
            border: none;
            padding: 8px 15px;
            border-radius: 4px;
            cursor: pointer;
            margin: 5px;
            display: inline-flex;
            align-items: center;
            gap: 5px;
        }
        #formula-converter button:hover {
            background: #45a049;
        }
        #formula-converter .header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 10px;
        }
        #formula-converter .minimize-btn {
            background: none;
            border: none;
            color: #666;
            padding: 8px;
            margin: 0;
            border-radius: 50%;
            width: 32px;
            height: 32px;
            display: flex;
            align-items: center;
            justify-content: center;
        }
        #formula-converter .minimize-btn:hover {
            background: #f0f0f0;
            color: #333;
        }
        #formula-converter .output {
            margin-top: 10px;
            padding: 8px;
            background: #f5f5f5;
            border-radius: 4px;
            white-space: pre-wrap;
            max-height: 200px;
            overflow-y: auto;
        }
        #formula-converter.minimized {
            width: 48px;
            height: 48px;
            padding: 0;
            border-radius: 50%;
            border: none;
        }
        #formula-converter.minimized .converter-content,
        #formula-converter.minimized .header span { 
            display: none; 
        }
        #formula-converter.minimized .minimize-btn {
            width: 100%;
            height: 100%;
            display: flex;
            align-items: center;
            justify-content: center;
            background: none;
            border-radius: 50%;
        }
        .toast {
            position: fixed;
            bottom: 80px;
            right: 20px;
            padding: 10px 20px;
            background: rgba(0,0,0,0.8);
            color: white;
            border-radius: 4px;
            display: none;
            z-index: 10000;
        }
    `);
 
    // 创建转换器界面
    const converterHTML = `
        <div id="formula-converter">
            <div class="header">
                <span>公式转换工具</span>
                <button class="minimize-btn" title="最小化/展开">
                    <i class="fas fa-minus"></i>
                </button>
            </div>
            <div class="converter-content">
                <textarea placeholder="在此输入带有公式的文本..."></textarea>
                <div class="button-group">
                    <button class="convert-btn" title="转换LaTeX公式">
                        <i class="fas fa-exchange-alt"></i>
                        转换
                    </button>
                    <button class="copy-btn" title="复制转换结果">
                        <i class="fas fa-copy"></i>
                        复制结果
                    </button>
                    <button class="clear-btn" title="清空入">
                        <i class="fas fa-trash"></i>
                        清空
                    </button>
                </div>
                <div class="output"></div>
            </div>
            <div class="toast">已复制到剪贴板!</div>
        </div>
    `;
 
    // 添加到页面
    document.body.insertAdjacentHTML('beforeend', converterHTML);
 
    // 获取元素
    const elements = {
        converter: document.getElementById('formula-converter'),
        minimizeBtn: document.querySelector('#formula-converter .minimize-btn'),
        textarea: document.querySelector('#formula-converter textarea'),
        convertBtn: document.querySelector('#formula-converter .convert-btn'),
        copyBtn: document.querySelector('#formula-converter .copy-btn'),
        output: document.querySelector('#formula-converter .output'),
        toast: document.querySelector('#formula-converter .toast'),
        clearBtn: document.querySelector('#formula-converter .clear-btn')
    };
 
    // 初始化为最小化状态
    elements.converter.classList.add('minimized');
    elements.minimizeBtn.innerHTML = `
        <svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 512 512" width="24" height="24">
            <g>
                <g>
                    <path style="fill:#5596FB;" d="M441,61H341c-5.522,0-10,4.478-10,10s4.478,10,10,10h100c5.514,0,10,4.486,10,10v220     c0,5.514-4.486,10-10,10H71c-5.514,0-10-4.486-10-10V91c0-5.514,4.486-10,10-10h100c5.522,0,10-4.478,10-10s-4.478-10-10-10H71     c-16.542,0-30,13.458-30,30v220c0,16.542,13.458,30,30,30h370c16.542,0,30-13.458,30-30V91C471,74.458,457.542,61,441,61z"/>
                    <path style="fill:#5596FB;" d="M181,246h-20c-5.522,0-10,4.478-10,10s4.478,10,10,10h20c5.522,0,10-4.478,10-10     S186.522,246,181,246z"/>
                    <path style="fill:#5596FB;" d="M161,206c-5.522,0-10,4.478-10,10s4.478,10,10,10h20c5.522,0,10-4.478,10-10s-4.478-10-10-10H161z"/>
                    <path style="fill:#5596FB;" d="M121,206c5.522,0,10-4.478,10-10s-4.478-10-10-10H91c-5.522,0-10,4.478-10,10v80     c0,5.522,4.478,10,10,10h30c5.522,0,10-4.478,10-10s-4.478-10-10-10h-20v-20h20c5.522,0,10-4.478,10-10s-4.478-10-10-10h-20v-20     H121z"/>
                    <path style="fill:#5596FB;" d="M221,286c5.522,0,10-4.478,10-10v-35c0-8.271,6.729-15,15-15s15,6.729,15,15v35     c0,5.522,4.478,10,10,10s10-4.478,10-10v-35c0-8.271,6.729-15,15-15s15,6.729,15,15v35c0,5.522,4.478,10,10,10s10-4.478,10-10     v-35c0-19.299-15.701-35-35-35c-9.786,0-18.642,4.042-25,10.539c-10.807-11.043-26.954-13.371-40-7.159V206     c0-5.522-4.478-10-10-10s-10,4.478-10,10v70C211,281.522,215.478,286,221,286z"/>
                    <path style="fill:#5596FB;" d="M358.574,275.749c13.646,13.646,35.849,13.646,49.497,0c3.905-3.905,3.905-10.237,0-14.143     c-3.906-3.904-10.236-3.904-14.143,0c-5.846,5.85-15.363,5.849-21.213,0c-5.849-5.849-5.849-15.364-0.001-21.213     c5.85-5.849,15.366-5.848,21.214,0c3.906,3.904,10.236,3.904,14.143,0c3.905-3.905,3.905-10.237,0-14.143     c-13.647-13.646-35.851-13.646-49.498,0C344.927,239.897,344.927,262.103,358.574,275.749z"/>
                    <path style="fill:#5596FB;" d="M407,154l-32,24c-3.443,2.583-4.848,7.079-3.487,11.162c1.361,4.084,5.183,6.838,9.487,6.838h40     c5.522,0,10-4.478,10-10s-4.478-10-10-10h-10l8-6c7.514-5.636,12-14.607,12-24c0-16.542-13.458-30-30-30s-30,13.458-30,30     c0,5.522,4.478,10,10,10s10-4.478,10-10c0-5.514,4.486-10,10-10s10,4.486,10,10C411,149.131,409.505,152.121,407,154z"/>
                </g>
                <g>
                    <path style="fill:#283954;" d="M461,21H349.28C345.152,9.361,334.036,1,321,1H191c-13.036,0-24.152,8.361-28.28,20H51     C23.43,21,1,43.43,1,71v260c0,27.57,22.43,50,50,50h61.461l-28.055,91.178C78.466,491.485,92.875,511,113.079,511h18.149     c13.253,0,24.775-8.511,28.673-21.178L165.693,471h180.614l5.792,18.822c3.897,12.667,15.42,21.178,28.673,21.178h18.149     c20.199,0,34.614-19.511,28.673-38.822L399.539,381H461c27.57,0,50-22.43,50-50V71C511,43.43,488.57,21,461,21z M191,21h130     c5.514,0,10,4.486,10,10v40c0,5.514-4.486,10-10,10H191c-5.514,0-10-4.486-10-10V31C181,25.486,185.486,21,191,21z M131.229,491     h-18.149c-6.734,0-11.537-6.504-9.558-12.941L133.386,381h39.074c-3.407,11.073-28.244,91.793-31.674,102.941     C139.487,488.163,135.646,491,131.229,491z M318.615,381l9.231,30H184.155l9.231-30H318.615z M171.847,451l6.154-20h155.999     l6.154,20H171.847z M408.479,478.059c1.979,6.436-2.822,12.941-9.558,12.941h-18.149c-4.417,0-8.259-2.837-9.558-7.059     c-3.43-11.148-28.267-91.868-31.674-102.941h39.074L408.479,478.059z M491,331c0,16.542-13.458,30-30,30     c-49.548,0-84.553,0-135,0c-17.513,0-263.04,0-275,0c-16.542,0-30-13.458-30-30V71c0-16.542,13.458-30,30-30h110v30     c0,16.542,13.458,30,30,30h130c16.542,0,30-13.458,30-30V41h110c16.542,0,30,13.458,30,30V331z"/>
                </g>
            </g>
        </svg>
    `;
 
    // 转换函数
    function convertFormula(text) {
        return text
            .replace(/\\\((.+?)\\\)/g, '$$$1$')
            .replace(/(\s*)\\\[([\s\S]*?)\\\]/g, (_, indent, formula) => 
                `${indent}$$${formula.trim()}$$`
            );
    }
 
    // 显示提示
    const showToast = () => {
        elements.toast.style.display = 'block';
        setTimeout(() => elements.toast.style.display = 'none', 2000);
    };
 
    // 事件监听
    elements.minimizeBtn.addEventListener('click', () => {
        const isMinimized = elements.converter.classList.toggle('minimized');
        elements.minimizeBtn.innerHTML = isMinimized 
            ? `<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 512 512" width="24" height="24">
                <g>
                    <g>
                        <path style="fill:#5596FB;" d="M441,61H341c-5.522,0-10,4.478-10,10s4.478,10,10,10h100c5.514,0,10,4.486,10,10v220     c0,5.514-4.486,10-10,10H71c-5.514,0-10-4.486-10-10V91c0-5.514,4.486-10,10-10h100c5.522,0,10-4.478,10-10s-4.478-10-10-10H71     c-16.542,0-30,13.458-30,30v220c0,16.542,13.458,30,30,30h370c16.542,0,30-13.458,30-30V91C471,74.458,457.542,61,441,61z"/>
                        <path style="fill:#5596FB;" d="M181,246h-20c-5.522,0-10,4.478-10,10s4.478,10,10,10h20c5.522,0,10-4.478,10-10     S186.522,246,181,246z"/>
                        <path style="fill:#5596FB;" d="M161,206c-5.522,0-10,4.478-10,10s4.478,10,10,10h20c5.522,0,10-4.478,10-10s-4.478-10-10-10H161z"/>
                        <path style="fill:#5596FB;" d="M121,206c5.522,0,10-4.478,10-10s-4.478-10-10-10H91c-5.522,0-10,4.478-10,10v80     c0,5.522,4.478,10,10,10h30c5.522,0,10-4.478,10-10s-4.478-10-10-10h-20v-20h20c5.522,0,10-4.478,10-10s-4.478-10-10-10h-20v-20     H121z"/>
                        <path style="fill:#5596FB;" d="M221,286c5.522,0,10-4.478,10-10v-35c0-8.271,6.729-15,15-15s15,6.729,15,15v35     c0,5.522,4.478,10,10,10s10-4.478,10-10v-35c0-8.271,6.729-15,15-15s15,6.729,15,15v35c0,5.522,4.478,10,10,10s10-4.478,10-10     v-35c0-19.299-15.701-35-35-35c-9.786,0-18.642,4.042-25,10.539c-10.807-11.043-26.954-13.371-40-7.159V206     c0-5.522-4.478-10-10-10s-10,4.478-10,10v70C211,281.522,215.478,286,221,286z"/>
                        <path style="fill:#5596FB;" d="M358.574,275.749c13.646,13.646,35.849,13.646,49.497,0c3.905-3.905,3.905-10.237,0-14.143     c-3.906-3.904-10.236-3.904-14.143,0c-5.846,5.85-15.363,5.849-21.213,0c-5.849-5.849-5.849-15.364-0.001-21.213     c5.85-5.849,15.366-5.848,21.214,0c3.906,3.904,10.236,3.904,14.143,0c3.905-3.905,3.905-10.237,0-14.143     c-13.647-13.646-35.851-13.646-49.498,0C344.927,239.897,344.927,262.103,358.574,275.749z"/>
                        <path style="fill:#5596FB;" d="M407,154l-32,24c-3.443,2.583-4.848,7.079-3.487,11.162c1.361,4.084,5.183,6.838,9.487,6.838h40     c5.522,0,10-4.478,10-10s-4.478-10-10-10h-10l8-6c7.514-5.636,12-14.607,12-24c0-16.542-13.458-30-30-30s-30,13.458-30,30     c0,5.522,4.478,10,10,10s10-4.478,10-10c0-5.514,4.486-10,10-10s10,4.486,10,10C411,149.131,409.505,152.121,407,154z"/>
                    </g>
                    <g>
                        <path style="fill:#283954;" d="M461,21H349.28C345.152,9.361,334.036,1,321,1H191c-13.036,0-24.152,8.361-28.28,20H51     C23.43,21,1,43.43,1,71v260c0,27.57,22.43,50,50,50h61.461l-28.055,91.178C78.466,491.485,92.875,511,113.079,511h18.149     c13.253,0,24.775-8.511,28.673-21.178L165.693,471h180.614l5.792,18.822c3.897,12.667,15.42,21.178,28.673,21.178h18.149     c20.199,0,34.614-19.511,28.673-38.822L399.539,381H461c27.57,0,50-22.43,50-50V71C511,43.43,488.57,21,461,21z M191,21h130     c5.514,0,10,4.486,10,10v40c0,5.514-4.486,10-10,10H191c-5.514,0-10-4.486-10-10V31C181,25.486,185.486,21,191,21z M131.229,491     h-18.149c-6.734,0-11.537-6.504-9.558-12.941L133.386,381h39.074c-3.407,11.073-28.244,91.793-31.674,102.941     C139.487,488.163,135.646,491,131.229,491z M318.615,381l9.231,30H184.155l9.231-30H318.615z M171.847,451l6.154-20h155.999     l6.154,20H171.847z M408.479,478.059c1.979,6.436-2.822,12.941-9.558,12.941h-18.149c-4.417,0-8.259-2.837-9.558-7.059     c-3.43-11.148-28.267-91.868-31.674-102.941h39.074L408.479,478.059z M491,331c0,16.542-13.458,30-30,30     c-49.548,0-84.553,0-135,0c-17.513,0-263.04,0-275,0c-16.542,0-30-13.458-30-30V71c0-16.542,13.458-30,30-30h110v30     c0,16.542,13.458,30,30,30h130c16.542,0,30-13.458,30-30V41h110c16.542,0,30,13.458,30,30V331z"/>
                    </g>
                </g>
            </svg>`
            : `<svg xmlns="http://www.w3.org/2000/svg" height="16" width="14" viewBox="0 0 448 512">
                <path fill="currentColor" d="M432 256c0 17.7-14.3 32-32 32L48 288c-17.7 0-32-14.3-32-32s14.3-32 32-32l352 0c17.7 0 32 14.3 32 32z"/>
               </svg>`;
    });
 
    elements.convertBtn.addEventListener('click', () => {
        elements.output.textContent = convertFormula(elements.textarea.value);
    });
 
    elements.copyBtn.addEventListener('click', () => {
        navigator.clipboard.writeText(elements.output.textContent)
            .then(showToast)
            .catch(() => alert('复制失败,请手动复制'));
    });
 
    elements.clearBtn.addEventListener('click', () => {
        elements.textarea.value = '';
    });
})();