您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
使用AI总结网页内容的油猴脚本
// ==UserScript== // @name AI网页内容总结 // @namespace http://tampermonkey.net/ // @version 1.0 // @description 使用AI总结网页内容的油猴脚本 // @author bizhanrensheng // @match *://*/* // @grant GM_addStyle // @grant GM_getValue // @grant GM_setValue // @require https://cdnjs.cloudflare.com/ajax/libs/markdown-it/13.0.1/markdown-it.min.js // @license MIT // @homepageURL https://xr.imyaigc.com // ==/UserScript== (function() { 'use strict'; // 默认配置 // Replace DEFAULT_CONFIG with the new API settings const DEFAULT_CONFIG = { API_URL: 'https://api.x.ai/v1/chat/completions', API_KEY: 'xai-bizhan(这里用你注册获得的API)', MAX_TOKENS: 10000, SHORTCUT: 'Alt+S', PROMPT: 'Please summarize the following webpage content in Markdown format, covering main points, key information, and details. Make it thorough, accurate, and organized.', MODEL: 'grok-beta' }; // Then, update the `summarizeContent` function to match the API format you need async function summarizeContent(content) { return new Promise(async (resolve, reject) => { const contentContainer = document.querySelector('.ai-summary-content'); contentContainer.innerHTML = '<div class="ai-loading">Generating summary<span class="ai-loading-dots"></span></div>'; let summary = ''; const md = createMarkdownRenderer(); // Set a timeout to handle potential request delays const timeout = setTimeout(() => { reject(new Error('Request timed out. Please check API URL, API Key, and network connection.')); }, 20000); try { const response = await fetch(CONFIG.API_URL, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${CONFIG.API_KEY}` }, body: JSON.stringify({ model: CONFIG.MODEL, messages: [ { role: 'system', content: CONFIG.PROMPT }, { role: 'user', content: content } ], max_tokens: CONFIG.MAX_TOKENS, temperature: 0, stream: false }) }); // Check if the response is OK if (!response.ok) { clearTimeout(timeout); throw new Error(`API request failed (${response.status}): Please check API URL and Key`); } const result = await response.json(); clearTimeout(timeout); if (result && result.choices && result.choices[0] && result.choices[0].message) { summary = result.choices[0].message.content; contentContainer.innerHTML = md.render(summary); resolve(summary); } else { throw new Error("Unexpected API response format."); } } catch (error) { clearTimeout(timeout); reject(error); } }); } // 获取配置 let CONFIG = {}; function loadConfig() { CONFIG = { API_URL: GM_getValue('API_URL', DEFAULT_CONFIG.API_URL), API_KEY: GM_getValue('API_KEY', DEFAULT_CONFIG.API_KEY), MAX_TOKENS: GM_getValue('MAX_TOKENS', DEFAULT_CONFIG.MAX_TOKENS), SHORTCUT: GM_getValue('SHORTCUT', DEFAULT_CONFIG.SHORTCUT), PROMPT: GM_getValue('PROMPT', DEFAULT_CONFIG.PROMPT), MODEL: GM_getValue('MODEL', DEFAULT_CONFIG.MODEL) }; return CONFIG; } // 保存配置 function saveConfig(newConfig) { Object.keys(newConfig).forEach(key => { GM_setValue(key, newConfig[key]); }); CONFIG = { ...CONFIG, ...newConfig }; } // 添加样式 GM_addStyle(` #ai-summary-root .ai-summary-container{position:fixed;bottom:20px;right:20px;display:flex;align-items:center;z-index:99998;user-select:none;align-items:stretch;box-shadow:0 2px 5px rgba(0,0,0,.2);height:30px}#ai-summary-root .ai-settings-panel,#ai-summary-root .ai-summary-modal{position:fixed;transform:translate(-50%,-50%);box-shadow:0 4px 20px rgba(0,0,0,.15)}#ai-summary-root .ai-summary-container .ai-drag-handle{width:15px;height:100%;background-color:rgba(75,85,99,.8);border-radius:5px 0 0 5px;cursor:move;margin-right:1px;display:flex;align-items:center;justify-content:center}#ai-summary-root .ai-summary-container .ai-drag-handle::before{content:"⋮";color:#f3f4f6;font-size:16px;transform:rotate(90deg)}#ai-summary-root .ai-summary-container .ai-summary-btn{padding:5px 15px;background-color:rgba(75,85,99,.8);color:#f3f4f6;border:none;border-radius:0 4px 4px 0;cursor:pointer;font-size:12px;transition:.3s;height:100%;line-height:1;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif}#ai-summary-root .ai-summary-container .ai-summary-btn:hover{background-color:rgba(75,85,99,.9)}#ai-summary-root .ai-summary-modal{display:none;top:50%;left:50%;width:80%;max-width:800px;max-height:80vh;background:#f8f9fa;border-radius:8px;z-index:99999;overflow:hidden;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif}#ai-summary-root .ai-summary-modal *{box-sizing:border-box}#ai-summary-root .ai-summary-overlay{display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,.5);z-index:99998}#ai-summary-root .ai-summary-modal .ai-summary-header{padding:15px 20px;background:#f1f3f5;border-bottom:1px solid #dee2e6;display:flex;justify-content:space-between;align-items:center}#ai-summary-root .ai-summary-modal .ai-summary-header h3{color:#495057;margin:0;padding:0;font-size:16px;font-weight:600;line-height:1.4;font-family:inherit}#ai-summary-root .ai-summary-modal .ai-summary-close{background:0 0;border:none;font-size:20px;cursor:pointer;color:#6c757d;padding:0 5px;line-height:1;font-family:inherit}#ai-summary-root .ai-summary-modal .ai-summary-close:hover{color:#495057}#ai-summary-root .ai-summary-modal .ai-summary-content{padding:20px;overflow-y:auto;max-height:calc(80vh - 130px);line-height:1.6;color:#374151;font-size:15px;font-family:inherit}#ai-summary-root .ai-summary-modal .ai-summary-content h1{font-size:1.8em;margin:1.5em 0 .8em;padding-bottom:.3em;border-bottom:2px solid #e5e7eb;font-weight:600;line-height:1.3;color:#1f2937}#ai-summary-root .ai-summary-modal .ai-summary-content h2{font-size:1.5em;margin:1.3em 0 .7em;padding-bottom:.2em;border-bottom:1px solid #e5e7eb;font-weight:600;line-height:1.3;color:#1f2937}#ai-summary-root .ai-summary-modal .ai-summary-content h3{font-size:1.3em;margin:1.2em 0 .6em;font-weight:600;line-height:1.3;color:#1f2937}#ai-summary-root .ai-summary-modal .ai-summary-content p{margin:1em 0;line-height:1.8;color:inherit}#ai-summary-root .ai-summary-modal .ai-summary-content ol,#ai-summary-root .ai-summary-modal .ai-summary-content ul{margin:1em 0;padding-left:2em;line-height:1.6}#ai-summary-root .ai-summary-modal .ai-summary-content li{margin:.5em 0;line-height:inherit;color:inherit}#ai-summary-root .ai-summary-modal .ai-summary-content blockquote{margin:1em 0;padding:.5em 1em;border-left:4px solid #60a5fa;background:#f3f4f6;color:#4b5563;font-style:normal}#ai-summary-root .ai-summary-modal .ai-summary-content code{background:#f3f4f6;padding:.2em .4em;border-radius:3px;font-family:Consolas,Monaco,"Courier New",monospace;font-size:.9em;color:#d946ef;white-space:pre-wrap}#ai-summary-root .ai-summary-modal .ai-summary-content pre{background:#1f2937;color:#e5e7eb;padding:1em;border-radius:6px;overflow-x:auto;margin:1em 0;white-space:pre;word-wrap:normal}#ai-summary-root .ai-summary-modal .ai-summary-content pre code{background:0 0;color:inherit;padding:0;border-radius:0;font-size:inherit;white-space:pre}#ai-summary-root .ai-summary-modal .ai-summary-content table{border-collapse:collapse;width:100%;margin:1em 0;font-size:inherit}#ai-summary-root .ai-summary-modal .ai-summary-content td,#ai-summary-root .ai-summary-modal .ai-summary-content th{border:1px solid #d1d5db;padding:.5em;text-align:left;color:inherit;background:0 0}#ai-summary-root .ai-summary-modal .ai-summary-content th{background:#f9fafb;font-weight:600}#ai-summary-root .ai-summary-modal .ai-summary-footer{padding:15px 20px;border-top:1px solid #dee2e6;display:flex;justify-content:flex-end;gap:10px;background:#f8f9fa}#ai-summary-root .ai-settings-btn,#ai-summary-root .ai-summary-modal .ai-retry-btn{padding:8px;background:#6c757d;color:#fff;border:none;border-radius:4px;cursor:pointer;display:inline-flex;align-items:center;justify-content:center;transition:background .3s;width:36px;height:36px;min-width:36px;line-height:1}#ai-summary-root .ai-settings-btn:hover,#ai-summary-root .ai-settings-panel .cancel-btn:hover,#ai-summary-root .ai-settings-panel .save-btn:hover,#ai-summary-root .ai-summary-modal .ai-copy-btn:hover,#ai-summary-root .ai-summary-modal .ai-retry-btn:hover{background:#5a6268}#ai-summary-root .ai-summary-modal .ai-retry-btn svg{width:20px;height:20px}#ai-summary-root .ai-summary-modal .ai-copy-btn{padding:8px 16px;background:#6c757d;color:#fff;border:none;border-radius:4px;cursor:pointer;display:inline-flex;align-items:center;gap:8px;transition:background .3s;font-size:14px;line-height:1;font-family:inherit}#ai-summary-root .ai-summary-modal .ai-loading{text-align:center;padding:20px;color:#6c757d;font-family:inherit}#ai-summary-root .ai-summary-modal .ai-loading-dots:after{content:'.';animation:1.5s steps(5,end) infinite dots}@keyframes dots{0%,20%{content:'.'}40%{content:'..'}60%{content:'...'}100%,80%{content:''}}#ai-summary-root .ai-settings-panel{display:none;top:50%;left:50%;width:90%;max-width:500px;background:#fff;padding:20px;border-radius:8px;z-index:100000}#ai-summary-root .ai-settings-panel textarea{resize:vertical;max-width:100%;height:100px;resize:vertical}#ai-summary-root .ai-settings-panel h3{margin:0 0 20px;padding-bottom:10px;border-bottom:1px solid #dee2e6;color:#495057;font-size:18px}#ai-summary-root .ai-settings-panel .form-group{margin-bottom:15px}#ai-summary-root .ai-settings-panel label{display:block;margin-bottom:5px;color:#495057;font-weight:500}#ai-summary-root .ai-settings-panel input,#ai-summary-root .ai-settings-panel textarea{max-width:100%;box-sizing:border-box;width:100%;padding:8px 12px;border:1px solid #ced4da;border-radius:4px;font-size:14px;line-height:1.5}#ai-summary-root .ai-settings-panel button{padding:8px 16px;border:none;border-radius:4px;cursor:pointer;font-size:14px;transition:.3s}#ai-summary-root .ai-settings-panel .cancel-btn,#ai-summary-root .ai-settings-panel .save-btn{background:#6c757d;color:#fff}#ai-summary-root .ai-settings-panel .clear-cache-btn{padding:8px 16px;background:#dc3545;color:#fff;border:none;border-radius:4px;cursor:pointer;font-size:14px;transition:.3s;margin-right:auto}#ai-summary-root .ai-settings-panel .clear-cache-btn:hover{background:#c82333}#ai-summary-root .ai-settings-panel .buttons{display:flex;justify-content:flex-end;gap:10px;margin-top:20px} `); // 创建设置面板 function createSettingsPanel() { const panel = document.createElement('div'); panel.className = 'ai-settings-panel'; panel.innerHTML = ` <h3>设置</h3> <div class="form-group"> <label for="api-url">API URL</label> <input type="text" id="api-url" value="${CONFIG.API_URL}"> </div> <div class="form-group"> <label for="api-key">API Key</label> <input type="text" id="api-key" value="${CONFIG.API_KEY}"> </div> <div class="form-group"> <label for="model">模型</label> <input type="text" id="model" value="${CONFIG.MODEL}"> </div> <div class="form-group"> <label for="max-tokens">最大Token数</label> <input type="number" id="max-tokens" value="${CONFIG.MAX_TOKENS}"> </div> <div class="form-group"> <label for="shortcut">快捷键</label> <input type="text" id="shortcut" value="${CONFIG.SHORTCUT}"> </div> <div class="form-group"> <label for="prompt">总结提示词</label> <textarea id="prompt">${CONFIG.PROMPT}</textarea> </div> <div class="buttons"> <button class="clear-cache-btn">清除缓存</button> <button class="cancel-btn">取消</button> <button class="save-btn">保存</button> </div> `; const overlay = document.createElement('div'); overlay.className = 'ai-summary-overlay'; // 事件监听 panel.querySelector('.save-btn').addEventListener('click', () => { const newConfig = { API_URL: panel.querySelector('#api-url').value, API_KEY: panel.querySelector('#api-key').value, MAX_TOKENS: parseInt(panel.querySelector('#max-tokens').value), SHORTCUT: panel.querySelector('#shortcut').value, PROMPT: panel.querySelector('#prompt').value, MODEL: panel.querySelector('#model').value }; saveConfig(newConfig); panel.style.display = 'none'; document.querySelector('.ai-summary-overlay').style.display = 'none'; }); panel.querySelector('.cancel-btn').addEventListener('click', () => { panel.style.display = 'none'; document.querySelector('.ai-summary-overlay').style.display = 'none'; }); // 清除缓存按钮事件 panel.querySelector('.clear-cache-btn').addEventListener('click', () => { const keys = ['API_URL', 'API_KEY', 'MAX_TOKENS', 'SHORTCUT', 'PROMPT', 'MODEL']; keys.forEach(key => GM_setValue(key, undefined)); // 设置为undefined模拟删除 // 重置为默认配置 CONFIG = { ...DEFAULT_CONFIG }; // 更新输入框的值 panel.querySelector('#api-url').value = CONFIG.API_URL; panel.querySelector('#api-key').value = CONFIG.API_KEY; panel.querySelector('#max-tokens').value = CONFIG.MAX_TOKENS; panel.querySelector('#shortcut').value = CONFIG.SHORTCUT; panel.querySelector('#prompt').value = CONFIG.PROMPT; panel.querySelector('#model').value = CONFIG.MODEL; alert('缓存已清除,已恢复默认设置'); }); return panel; } // 创建DOM元素 function createElements() { // 创建根容器,并添加唯一ID const rootContainer = document.createElement('div'); rootContainer.id = 'ai-summary-root'; // 创建容器和拖动把手 const container = document.createElement('div'); container.className = 'ai-summary-container'; const dragHandle = document.createElement('div'); dragHandle.className = 'ai-drag-handle'; const button = document.createElement('button'); button.className = 'ai-summary-btn'; button.textContent = '总结网页'; // 在footer中添加设置按钮 const settingsBtn = document.createElement('button'); settingsBtn.className = 'ai-settings-btn'; settingsBtn.title = '设置'; settingsBtn.innerHTML = ` <svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2"> <circle cx="12" cy="12" r="3"></circle> <path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path> </svg> `; container.appendChild(dragHandle); container.appendChild(button); document.body.appendChild(container); // 创建模态框和遮罩层 const modal = document.createElement('div'); modal.className = 'ai-summary-modal'; modal.innerHTML = ` <div class="ai-summary-header"> <h3 style="margin: 0;">网页内容总结</h3> <button class="ai-summary-close">×</button> </div> <div class="ai-summary-content"></div> <div class="ai-summary-footer"> <button class="ai-retry-btn" title="重新生成"> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> <path d="M21 12a9 9 0 11-2.3-6M21 3v6h-6"></path> </svg> </button> <button class="ai-copy-btn"> <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> <rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect> <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path> </svg> 复制内容 </button> </div> `; const overlay = document.createElement('div'); overlay.className = 'ai-summary-overlay'; document.body.appendChild(overlay); document.body.appendChild(modal); modal.querySelector('.ai-summary-footer').insertBefore( settingsBtn, modal.querySelector('.ai-retry-btn') ); const settingsPanel = createSettingsPanel(); // 将容器添加到根容器 rootContainer.appendChild(container); rootContainer.appendChild(overlay); rootContainer.appendChild(modal); rootContainer.appendChild(settingsPanel); document.body.appendChild(rootContainer); // 将根容器添加到body return { container, button, modal, overlay, dragHandle, settingsBtn, settingsPanel, rootContainer }; } // 获取网页内容 function getPageContent() { const title = document.title; const content = document.body.innerText; return { title, content }; } // 显示错误信息 function showError(container, error, details = '') { container.innerHTML = ` <div class="ai-summary-error"> <strong>错误:</strong> ${error} </div> ${details ? `<div class="ai-summary-debug">${details}</div>` : ''} `; } // 调用API进行总结 async function summarizeContent(content) { return new Promise(async (resolve, reject) => { const contentContainer = document.querySelector('.ai-summary-content'); contentContainer.innerHTML = '<div class="ai-loading">正在生成总结<span class="ai-loading-dots"></span></div>'; let summary = ''; const md = createMarkdownRenderer(); // 添加超时检查 const timeout = setTimeout(() => { reject(new Error('请求超时,请检查API URL、API Key和网络连接')); }, 20000); try { const response = await fetch(CONFIG.API_URL, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${CONFIG.API_KEY}` }, body: JSON.stringify({ model: CONFIG.MODEL, messages: [ { role: 'system', content: CONFIG.PROMPT }, { role: 'user', content: content } ], max_tokens: CONFIG.MAX_TOKENS, temperature: 0.7, stream: true }) }); // 检查响应状态 if (!response.ok) { clearTimeout(timeout); throw new Error(`API请求失败 (${response.status}): 请检查API URL和Key是否正确`); } const reader = response.body.getReader(); const decoder = new TextDecoder("utf-8"); while (true) { const { done, value } = await reader.read(); if (done) break; const chunk = decoder.decode(value, { stream: true }); const lines = chunk.split('\n'); for (const line of lines) { if (line.trim() === '' || line.trim() === 'data: [DONE]') continue; const jsonLine = line.replace(/^data: /, ''); try { const parsedData = JSON.parse(jsonLine); if (parsedData.choices && parsedData.choices[0] && parsedData.choices[0].delta) { if (parsedData.choices[0].delta.content) { summary += parsedData.choices[0].delta.content; contentContainer.innerHTML = md.render(summary); } } } catch (e) { console.warn('忽略无法解析的行:', line); continue; } } } clearTimeout(timeout); resolve(summary); } catch (error) { clearTimeout(timeout); reject(error); } }); } // 初始化拖动功能 function initializeDrag(container, dragHandle) { let isDragging = false; let currentX; let currentY; let initialX; let initialY; dragHandle.addEventListener('mousedown', (e) => { isDragging = true; initialX = e.clientX - container.offsetLeft; initialY = e.clientY - container.offsetTop; }); document.addEventListener('mousemove', (e) => { if (isDragging) { e.preventDefault(); currentX = e.clientX - initialX; currentY = e.clientY - initialY; // 确保不会拖出屏幕 const maxX = window.innerWidth - container.offsetWidth; const maxY = window.innerHeight - container.offsetHeight; currentX = Math.max(0, Math.min(currentX, maxX)); currentY = Math.max(0, Math.min(currentY, maxY)); container.style.left = currentX + 'px'; container.style.top = currentY + 'px'; container.style.right = 'auto'; container.style.bottom = 'auto'; } }); document.addEventListener('mouseup', () => { isDragging = false; }); } // 初始化事件监听 function initializeEvents(elements) { const { container, button, modal, overlay, dragHandle, settingsBtn, settingsPanel, rootContainer } = elements; // 初始化拖动功能 initializeDrag(container, dragHandle); // 点击按钮显示模态框 button.addEventListener('click', async () => { // 检查是否是第一次点击且未配置API if (!CONFIG.API_KEY || CONFIG.API_KEY === '' || CONFIG.API_KEY === 'YOUR_API_KEY') { settingsPanel.style.display = 'block'; overlay.style.display = 'block'; return; } showModal(modal, overlay); const contentContainer = modal.querySelector('.ai-summary-content'); try { if (!CONFIG.API_URL || CONFIG.API_URL === 'YOUR_API_URL') { throw new Error('请先配置API URL'); } if (!CONFIG.API_KEY || CONFIG.API_KEY === 'YOUR_API_KEY') { throw new Error('请先配置API Key'); } const { content } = getPageContent(); const summary = await summarizeContent(content); if (summary) { contentContainer.innerHTML = window.markdownit().render(summary); } } catch (error) { console.error('Summary Error:', error); showError(contentContainer, error.message); } }); // 关闭模态框 modal.querySelector('.ai-summary-close').addEventListener('click', () => { hideModal(modal, overlay); }); overlay.addEventListener('click', () => { hideModal(modal, overlay); settingsPanel.style.display = 'none'; }); // 复制按钮功能 modal.querySelector('.ai-copy-btn').addEventListener('click', () => { const content = modal.querySelector('.ai-summary-content').textContent; navigator.clipboard.writeText(content).then(() => { const copyBtn = modal.querySelector('.ai-copy-btn'); const originalText = copyBtn.innerHTML; copyBtn.innerHTML = '已复制!'; setTimeout(() => { copyBtn.innerHTML = originalText; }, 2000); }); }); // 添加快捷键支持 document.addEventListener('keydown', (e) => { if (e.altKey && e.key.toLowerCase() === 's') { button.click(); } if (e.key === 'Escape' && modal.style.display === 'block') { hideModal(modal, overlay); } }); // 添加重试按钮事件处理 modal.querySelector('.ai-retry-btn').addEventListener('click', async () => { const contentContainer = modal.querySelector('.ai-summary-content'); try { const { content } = getPageContent(); const summary = await summarizeContent(content); if (summary) { const md = window.markdownit({ html: true, linkify: true, typographer: true, breaks: true }); contentContainer.innerHTML = md.render(summary); } } catch (error) { console.error('Retry Error:', error); showError(contentContainer, error.message); } }); const allSettingsButtons = rootContainer.querySelectorAll('.ai-settings-btn'); allSettingsButtons.forEach(btn => { btn.addEventListener('click', () => { // 更新设置面板中的值 settingsPanel.querySelector('#api-url').value = CONFIG.API_URL; settingsPanel.querySelector('#api-key').value = CONFIG.API_KEY; settingsPanel.querySelector('#max-tokens').value = CONFIG.MAX_TOKENS; settingsPanel.querySelector('#shortcut').value = CONFIG.SHORTCUT; settingsPanel.querySelector('#prompt').value = CONFIG.PROMPT; settingsPanel.querySelector('#model').value = CONFIG.MODEL; settingsPanel.style.display = 'block'; overlay.style.display = 'block'; }); }); } // 增强markdown-it配置 function createMarkdownRenderer() { return window.markdownit({ html: true, linkify: true, typographer: true, breaks: true }); } // 显示模态框 function showModal(modal, overlay) { modal.style.display = 'block'; overlay.style.display = 'block'; } // 隐藏模态框 function hideModal(modal, overlay) { modal.style.display = 'none'; overlay.style.display = 'none'; } // 初始化时加载配置 loadConfig(); // 初始化脚本 const elements = createElements(); initializeEvents(elements); })();