[油猴脚本] 网页版 AI 聊天增强(支持 DeepSeek 和 QwenChat 等)

无法访问 greasyfork 的用户可以访问这个国内镜像 https://gf.qytechs.cn/zh-CN

加宽聊天界面

占满网页剩余空间

支持 deepseek/ChatGPT/Claude/Kimi/通义/智谱 GLM/天工/Deepseek/Gemini/腾讯元宝/grok

https://greasyfork.org/zh-CN/scripts/499377-wider-ai-chat 安装这个油猴脚本即可

聊天问题列表

显示聊天会话中,你已经提的问题列表,点击跳转到对应的聊天处

image.png

改造自 https://greasyfork.org/zh-CN/scripts/528739

支持 deepseek、 QwenChat、Grok、GitHub Copilot、通义千问等)

// ==UserScript== // @name webAI聊天问题列表导航 // @namespace http://tampermonkey.net/ // @version 2.10 // @description 通过点击按钮显示用户问题列表,支持导航到特定问题、分页功能、正序/倒序切换,优化性能并美化UI,适配CSP限制 // @author yutao // @match https://grok.com/chat/* // @match https://github.com/copilot/* // @match https://yuanbao.tencent.com/chat/* // @match https://chat.qwenlm.ai/* // @match https://chat.qwen.ai/* // @match https://copilot.microsoft.com/chats/* // @match https://chatgpt.com/c/* // @match https://chat.deepseek.com/* // @grant none // MIT License // // Copyright (c) [2025] [yutao] // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE.@license // ==/UserScript== (function () { 'use strict'; // 配置对象,定义不同网站的聊天消息选择器和条件 const config = { 'grok.com': { messageSelector: 'div.message-bubble', textSelector: 'span.whitespace-pre-wrap', userCondition: (element) => element.classList.contains('bg-foreground') && window.getComputedStyle(element).backgroundColor !== 'rgb(224, 247, 250)' }, 'github.com': { messageSelector: 'div.UserMessage-module__container--cAvvK.ChatMessage-module__userMessage--xvIFp', textSelector: null, userCondition: (element) => element.classList.contains('ChatMessage-module__userMessage--xvIFp') }, 'yuanbao.tencent.com': { messageSelector: 'div.agent-chat__bubble__content', textSelector: 'div.hyc-content-text', userCondition: (element) => true }, 'chat.qwenlm.ai': { messageSelector: 'div.rounded-3xl.bg-gray-50.dark\\:bg-gray-850', textSelector: 'p', userCondition: (element) => true }, 'chat.qwen.ai': { //messageSelector: 'div.rounded-3xl.bg-gray-50.dark\\:bg-gray-850', messageSelector: '.user-message div:has(> p)', textSelector: '', userCondition: (element) => true }, 'copilot.microsoft.com': { messageSelector: 'div.self-end.rounded-2xl', textSelector: null, userCondition: (element) => element.classList.contains('self-end') }, 'chatgpt.com': { messageSelector: 'div.rounded-3xl.bg-token-message-surface', textSelector: 'div.whitespace-pre-wrap', userCondition: (element) => true }, 'chat.deepseek.com': { messageSelector: 'div.fbb737a4', textSelector: null, userCondition: (element) => true } }; // 获取当前域名并选择配置 const hostname = window.location.hostname; const currentConfig = config[hostname] || { messageSelector: 'div[class*=message], div[class*=chat], div[class*=user]', textSelector: null, userCondition: (element) => true }; // 创建美化后的浮动按钮 const button = document.createElement('button'); button.textContent = '问题'; button.style.position = 'fixed'; button.style.bottom = '120px'; button.style.right = '20px'; button.style.zIndex = '1000'; button.style.padding = '4px 8px'; button.style.background = 'linear-gradient(135deg, #007BFF, #00C4FF)'; button.style.color = '#fff'; button.style.border = 'none'; button.style.borderRadius = '8px'; button.style.boxShadow = '0 2px 4px rgba(0,0,0,0.2)'; button.style.cursor = 'pointer'; button.style.fontFamily = 'Arial, sans-serif'; button.style.fontSize = '14px'; button.style.transition = 'transform 0.2s, box-shadow 0.2s'; button.addEventListener('mouseover', () => { button.style.transform = 'scale(1.05)'; button.style.boxShadow = '0 4px 8px rgba(0,0,0,0.3)'; }); button.addEventListener('mouseout', () => { button.style.transform = 'scale(1)'; button.style.boxShadow = '0 2px 4px rgba(0,0,0,0.2)'; }); document.body.appendChild(button); moveableDialog(button, button); // 创建美化后的悬浮窗 const floatWindow = document.createElement('div'); floatWindow.style.position = 'fixed'; floatWindow.style.bottom = '70px'; floatWindow.style.right = '20px'; floatWindow.style.width = '820px'; floatWindow.style.maxHeight = '420px'; floatWindow.style.background = '#ffffff'; floatWindow.style.border = '1px solid #e0e0e0'; floatWindow.style.borderRadius = '10px'; floatWindow.style.boxShadow = '0 4px 12px rgba(0,0,0,0.15)'; floatWindow.style.padding = '15px'; floatWindow.style.overflowY = 'auto'; floatWindow.style.display = 'none'; floatWindow.style.zIndex = '1000'; floatWindow.style.fontFamily = 'Arial, sans-serif'; floatWindow.style.transition = 'opacity 0.2s'; floatWindow.className = 'chat-float-window'; document.body.appendChild(floatWindow); // 监听body被点击 document.body.addEventListener('click', (event) => { // 挡在floatWindow内或分页按钮或问题列表按钮时跳过 if(event.target.closest('.chat-float-window')||event.target===button||event.target.matches('.chat-float-window-page')){ return; } if(floatWindow.style.opacity==='1') { floatWindow.style.opacity = '0'; setTimeout(() => { floatWindow.style.display = 'none'; button.textContent = '问题'; }, 200); } }); // 分页相关变量 let questions = []; const pageSize = 10; let currentPage = 1; let isReversed = false; // 创建排序切换按钮 const sortButton = document.createElement('button'); sortButton.textContent = '正序'; sortButton.style.marginBottom = '10px'; sortButton.style.padding = '5px 10px'; sortButton.style.background = '#007BFF'; sortButton.style.color = '#fff'; sortButton.style.border = 'none'; sortButton.style.borderRadius = '4px'; sortButton.style.cursor = 'pointer'; sortButton.style.fontSize = '12px'; sortButton.addEventListener('click', () => { isReversed = !isReversed; sortButton.textContent = isReversed ? '倒序' : '正序'; findAllQuestions(); }); floatWindow.appendChild(sortButton); // 创建关闭按钮 const closeButton = document.createElement('button'); closeButton.textContent = '关闭'; closeButton.style.float = 'right'; closeButton.style.marginBottom = '10px'; closeButton.style.padding = '5px 10px'; closeButton.style.background = '#007BFF'; closeButton.style.color = '#fff'; closeButton.style.border = 'none'; closeButton.style.borderRadius = '4px'; closeButton.style.cursor = 'pointer'; closeButton.style.fontSize = '12px'; closeButton.addEventListener('click', () => { floatWindow.style.opacity = '0'; setTimeout(() => { floatWindow.style.display = 'none'; button.textContent = '问题'; }, 200); }); floatWindow.appendChild(closeButton); // 创建分页控件 const paginationContainer = document.createElement('div'); paginationContainer.style.display = 'flex'; paginationContainer.style.justifyContent = 'center'; paginationContainer.style.marginTop = '10px'; paginationContainer.style.gap = '5px'; // 问题列表容器 const listContainer = document.createElement('ul'); listContainer.style.listStyle = 'none'; listContainer.style.padding = '0'; listContainer.style.margin = '0'; floatWindow.appendChild(listContainer); floatWindow.appendChild(paginationContainer); // 获取文本内容的辅助函数 function getTextContent(element) { return element ? element.textContent.trim() : ''; } // 查找所有用户问题的函数 function findAllQuestions() { const chatContainer = document.querySelector('.chat-container, #chat, main, article') || document.body; const potentialMessages = chatContainer.querySelectorAll(currentConfig.messageSelector); questions = []; for (let i = 0; i < potentialMessages.length; i++) { const element = potentialMessages[i]; const textElement = currentConfig.textSelector ? element.querySelector(currentConfig.textSelector) : element; const text = getTextContent(textElement); if (text && currentConfig.userCondition(element)) { questions.push({ element, text }); } } if (isReversed) { questions.reverse(); } renderPage(currentPage); updatePagination(); } // 渲染指定页的问题(使用 DOM 操作替代 innerHTML) function renderPage(page) { // 清空列表容器 while (listContainer.firstChild) { listContainer.removeChild(listContainer.firstChild); } const start = (page - 1) * pageSize; const end = page * pageSize; const pageQuestions = questions.slice(start, end); pageQuestions.forEach((q, idx) => { const listItem = document.createElement('li'); const shortText = q.text.substring(0, 150) + (q.text.length > 150 ? '...' : ''); listItem.textContent = `${isReversed ? questions.length - start - idx : start + idx + 1}: ${shortText}`; listItem.style.padding = '8px 12px'; listItem.style.cursor = 'pointer'; listItem.style.fontSize = '13px'; listItem.style.color = '#333'; listItem.style.whiteSpace = 'nowrap'; listItem.style.overflow = 'hidden'; listItem.style.textOverflow = 'ellipsis'; listItem.style.borderBottom = '1px solid #f0f0f0'; listItem.style.transition = 'background 0.2s'; listItem.title = q.text; listItem.addEventListener('mouseover', () => { listItem.style.background = '#f5f5f5'; }); listItem.addEventListener('mouseout', () => { listItem.style.background = 'none'; }); listItem.addEventListener('click', () => { q.element.scrollIntoView({ behavior: 'smooth', block: 'start' }); floatWindow.style.opacity = '0'; setTimeout(() => { floatWindow.style.display = 'none'; button.textContent = '问题'; }, 200); //console.log(`${questions.indexOf(q) + 1}: ${q.text.substring(0, 150)}...`); }); listContainer.appendChild(listItem); }); } // 更新分页控件 function updatePagination() { // 清空分页容器 while (paginationContainer.firstChild) { paginationContainer.removeChild(paginationContainer.firstChild); } const totalPages = Math.ceil(questions.length / pageSize); if (totalPages) { const prevButton = document.createElement('button'); prevButton.textContent = '上一页'; prevButton.style.padding = '5px 10px'; prevButton.style.border = 'none'; prevButton.style.background = currentPage === 1 ? '#f0f0f0' : '#007BFF'; prevButton.style.color = currentPage === 1 ? '#aaa' : '#fff'; prevButton.style.cursor = currentPage === 1 ? 'not-allowed' : 'pointer'; prevButton.style.borderRadius = '4px'; prevButton.disabled = currentPage === 1; prevButton.className= 'chat-float-window-page'; prevButton.addEventListener('click', () => { if (currentPage > 1) { currentPage--; renderPage(currentPage); updatePagination(); } }); paginationContainer.appendChild(prevButton); for (let i = 1; i <= totalPages; i++) { const pageButton = document.createElement('button'); pageButton.textContent = i; pageButton.style.padding = '5px 10px'; pageButton.style.border = 'none'; pageButton.style.background = currentPage === i ? '#007BFF' : '#f0f0f0'; pageButton.style.color = currentPage === i ? '#fff' : '#333'; pageButton.style.cursor = 'pointer'; pageButton.style.borderRadius = '4px'; pageButton.className= 'chat-float-window-page'; pageButton.addEventListener('click', () => { currentPage = i; renderPage(currentPage); updatePagination(); }); paginationContainer.appendChild(pageButton); } const nextButton = document.createElement('button'); nextButton.textContent = '下一页'; nextButton.style.padding = '5px 10px'; nextButton.style.border = 'none'; nextButton.style.background = currentPage === totalPages ? '#f0f0f0' : '#007BFF'; nextButton.style.color = currentPage === totalPages ? '#aaa' : '#fff'; nextButton.style.cursor = currentPage === totalPages ? 'not-allowed' : 'pointer'; nextButton.style.borderRadius = '4px'; nextButton.disabled = currentPage === totalPages; nextButton.className= 'chat-float-window-page'; nextButton.addEventListener('click', () => { if (currentPage < totalPages) { currentPage++; renderPage(currentPage); updatePagination(); } }); paginationContainer.appendChild(nextButton); } } // 点击切换悬浮窗显示状态 button.addEventListener('click', () => { if(isGlobalDragging) return; if (floatWindow.style.display === 'none' || floatWindow.style.display === '') { findAllQuestions(); if (questions.length === 0) { alert('未找到任何问题!'); return; } floatWindow.style.display = 'block'; floatWindow.style.opacity = '1'; button.textContent = '隐藏'; } else { floatWindow.style.opacity = '0'; setTimeout(() => { floatWindow.style.display = 'none'; button.textContent = '问题'; }, 200); } }); // 监听用户输入新问题后触发查找 function setupInputListener() { const input = document.querySelector('textarea, input[type="text"], [contenteditable]'); if (input) { input.addEventListener('keypress', (e) => { if (e.key === 'Enter') { setTimeout(findAllQuestions, 1000); } }); } } let isGlobalDragging = false; function moveableDialog(dialog, dragEl) { let isDragging = false; let offsetX, offsetY; let dialogRect = dialog.getBoundingClientRect(); const dragHandler = (e) => { let clientX, clientY; // 处理触摸事件 if (e.type.startsWith('touch')) { if (e.touches.length > 0) { clientX = e.touches[0].clientX; clientY = e.touches[0].clientY; } else { return; // 如果没有触摸点,直接返回 } } else { clientX = e.clientX; clientY = e.clientY; } if (e.type === 'mousedown' || e.type === 'touchstart') { // 开始拖动 isDragging = true; document.removeEventListener('mousemove', dragHandler); document.removeEventListener('mouseup', dragHandler); document.removeEventListener('touchmove', dragHandler); document.removeEventListener('touchend', dragHandler); document.addEventListener('mousemove', dragHandler); document.addEventListener('mouseup', dragHandler); document.addEventListener('touchmove', dragHandler); document.addEventListener('touchend', dragHandler); offsetX = clientX - dialog.offsetLeft; offsetY = clientY - dialog.offsetTop; setTimeout(() => { if (!isNaN(parseFloat(dialog.style.left)) && !isNaN(parseFloat(dialog.style.top))) { dialog.style.right = 'auto'; dialog.style.bottom = 'auto'; } }, 100); } else if ((e.type === 'mousemove' || e.type === 'touchmove') && isDragging) { // 拖动中 isGlobalDragging = true; const x = clientX - offsetX; const y = clientY - offsetY; // 限制不超过窗口大小 const maxX = window.innerWidth - dialogRect.width; const maxY = window.innerHeight - dialogRect.height; const clampedX = Math.max(0, Math.min(x, maxX)); const clampedY = Math.max(0, Math.min(y, maxY)); dialog.style.left = clampedX + 'px'; dialog.style.top = clampedY + 'px'; } else if (e.type === 'mouseup' || e.type === 'touchend') { // 拖动结束 isDragging = false; setTimeout(()=>{isGlobalDragging = false;}, 300); document.removeEventListener('mousemove', dragHandler); document.removeEventListener('mouseup', dragHandler); document.removeEventListener('touchmove', dragHandler); document.removeEventListener('touchend', dragHandler); } e.preventDefault(); }; // 注册拖动句柄 dragEl.removeEventListener('mousedown', dragHandler); dragEl.removeEventListener('touchstart', dragHandler); dragEl.addEventListener('mousedown', dragHandler); dragEl.addEventListener('touchstart', dragHandler); // 改变窗口大小事件 window.addEventListener("resize", (event) => { if (!isNaN(parseFloat(dialog.style.left)) && !isNaN(parseFloat(dialog.style.top))) { if (parseFloat(dialog.style.left) > window.innerWidth) { dialog.style.left = (window.innerWidth - dialogRect.width) + 'px'; } if (parseFloat(dialog.style.top) > window.innerHeight) { dialog.style.top = (window.innerHeight - dialogRect.height) + 'px'; } } }); } // 页面加载后初始化 window.addEventListener('load', () => { setTimeout(() => { findAllQuestions(); setupInputListener(); }, 2000); }); })();

保存聊天内容

把本会话的所有聊天内容保存为 html 文件

image.png

支持 ChatGPT,deepseek 和 QwenChat

改造自 https://greasyfork.org/zh-CN/scripts/461763

// ==UserScript== // @name AI对话保存 // @namespace http://tampermonkey.net/ // @version 0.2 // @description AI对话保存,兼容ChatGPT和DeepSeek,安装后右下角出现一个悬浮窗按钮,点击即可保存当前对话,自动询问文件名,自动添加时间戳,保存为html格式 // @author thunder-sword // @match https://chat.openai.com/* // @match https://chat.qwen.ai/* // @match https://chat.deepseek.com/* // @icon https://www.google.com/s2/favicons?sz=64&domain=openai.com // @license MIT // @grant none // ==/UserScript== /* 作用:根据指定的html字符串下载html文件,可指定文件名,自动获取当前页面中的css,自动添加时间戳 */ function downloadHtml(html, fileName='page.html', getCSS=true, addTimeSuffix=true){ var result=`<head></head>`; if(getCSS){ /* 获取当前页面 css */ const css = Array.from(document.styleSheets) .filter(styleSheet => { try { return styleSheet.cssRules; // 尝试访问 cssRules,如果不抛出错误则说明不是跨域的 } catch (e) { return false; // 跨域样式表,跳过 } }) .map(styleSheet => Array.from(styleSheet.cssRules).map(rule => rule.cssText)) .flat() .join("\n"); result=`<head><style>\n${css}\n</style></head>`; } result+='<body>'+html+'</body>'; const file = new File([result], "page.html", { type: "text/html" }); const a = document.createElement("a"); a.href = URL.createObjectURL(file); fileName = fileName.endsWith(".html") ? fileName : fileName + ".html"; if(addTimeSuffix){ var currentTime = new Date(); fileName=fileName.slice(0,-5)+`-${currentTime.getFullYear()}${(currentTime.getMonth()+1).toString().padStart(2, "0")}${currentTime.getDate().toString().padStart(2, "0")}.html`; } a.download = fileName; document.body.appendChild(a); a.click(); } var copyScript =`var cs = document.querySelectorAll('.bg-black > div > button'); for (let i = 0; i < cs.length; i++) { /* 为按钮元素添加点击事件监听器 */ cs[i].addEventListener('click', function() { /* 获取需要复制的文本内容 */ let text = cs[i].parentNode.parentNode.querySelector('div.p-4 > code').innerText; /* 将文本内容复制到剪贴板 */ navigator.clipboard.writeText(text).then(function() { /* 复制成功 */ /* alert('文本已复制到剪贴板!'); */ /* 更新按钮文字,提示复制成功 */ cs[i].innerHTML = '<svg stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round" class="w-4 h-4" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><polyline points="20 6 9 17 4 12"></polyline></svg>Copied!'; /* 设置定时器,延迟两秒钟恢复按钮的原状 */ setTimeout(function() { cs[i].innerHTML = '<svg stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round" class="w-4 h-4" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"></path><rect x="8" y="2" width="8" height="4" rx="1" ry="1"></rect></svg>Copy code'; }, 2000); }, function() { /* 复制失败 */ /* alert('文本复制失败!'); */ }); }); }`; /* 作用:保存ai对话记录,可弹窗询问要保存的文件名,默认为false */ function savaAiRecording(fileName='page.html', askFileName=false){ let defaultName = ''; if (location.href.indexOf("chat.qwen.ai")!==-1) { defaultName = document.querySelector('#sidebar a[aria-label="chat-item"]:not([class*=group-hover]) .text-left')?.textContent || document.title.split('|')[0].trim() || ''; } if (location.href.indexOf("chat.deepseek.com")!==-1) { defaultName = document.querySelector('div[style="outline: none;"]')?.textContent || ''; } if (location.href.indexOf("chatgpt.com")!==-1) { defaultName = document.title || ''; } /* askFileName为true时弹窗询问文件名 */ fileName=askFileName?prompt('输入要保存的文件名:', defaultName):fileName; var body=document.createElement('body'); if (location.href.indexOf("chat.qwen.ai")!==-1) { const messagesContainer = document.querySelector("#messages-container"); messagesContainer.style.height = '100vh'; body.innerHTML = messagesContainer.outerHTML; } else { body.innerHTML=document.body.innerHTML; } /* 删除所有script标签 */ var ps = body.querySelectorAll('script'); for (var i = 0; i < ps.length; i++) { ps[i].parentNode.removeChild(ps[i]); } /* 删除所有style标签,因为downloadHtml会自动再获取一次 */ ps = body.querySelectorAll('style'); for (var i = 0; i < ps.length; i++) { ps[i].parentNode.removeChild(ps[i]); } /* 删除下边框 */ var element=body.querySelector('#__next > div > div > main > div.absolute'); element && element.remove(); /* 删除DeepSeek侧边框 */ element=body.querySelector('div#root > div:nth-child(1) > div:nth-child(2) > div:nth-child(1) > div:nth-child(1)'); element && element.remove(); /* 删除侧边框 */ element=body.querySelector('#__next > div > div.hidden'); element && element.remove(); /* 删除侧边框间隔 */ element=body.querySelector('#__next > div > div'); if(element){element.className='';} /* 添加script标签,用于修复一键复制 */ var script=document.createElement('script'); script.innerHTML=copyScript; body.appendChild(script); if (location.href.indexOf("chat.qwen.ai")!==-1) { const style = `<style> ::-webkit-scrollbar { width: 10px; } ::-webkit-scrollbar-track { background: #fafafa; border-radius: 5px; box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.1); } ::-webkit-scrollbar-thumb { background: #c1c1c1; border-radius: 5px; border: 2px solid #fafafa; } ::-webkit-scrollbar-thumb:hover { background: #a8a8a8; } /* Firefox */ body { scrollbar-width: thin; scrollbar-color: #c1c1c1 #fafafa; } </style>`; body.insertAdjacentHTML('afterbegin', style); } downloadHtml(body.innerHTML, fileName); } //版本号:v0.0.2 //作用:创建一个在右下角出现的悬浮窗按钮,多个按钮会自动排序,点击即可执行对应函数 // 保存按钮 function createFloatButton(name, func){ //没有容器则生成容器 let box=document.querySelector("body > div#ths_button_container"); if(!box){ box=document.createElement('div'); box.id="ths_button_container"; box.style.cssText = ` position: fixed; bottom: 86px; right: 18px; min-height: 30px; /* 设置一个最小高度,确保容器有一定高度 */ display: flex; z-index: 999; flex-direction: column; user-select: none; `; document.body.appendChild(box); } // 创建一个 div 元素 var floatWindow = document.createElement('div'); // 设置 div 的内容 //floatWindow.innerHTML = '点我执行代码'; floatWindow.innerHTML = name; // 设置 div 的样式 floatWindow.style.cssText = ` /*padding: 5px; background-color: #333; color: #fff; border-radius: 5px; font-size: 16px; text-align: center; opacity: 1; z-index: 999; margin: 5px; cursor: pointer;*/ /* 鼠标可以选中 */ padding: 4px 8px; background-color: rgb(2 170 255); color: rgb(255, 255, 255); border-radius: 8px; font-size: 14px; text-align: center; opacity: 1; z-index: 99999; margin: 0; cursor: pointer; `; if (location.href.indexOf("chat.deepseek.com")!==-1) { floatWindow.style.cssText += 'padding: 2px 8px;'; } // 将悬浮窗的优先级提高 floatWindow.style.zIndex = "99999"; var isDragging = false; var currentX; var currentY; var initialX; var initialY; var xOffset = 0; var yOffset = 0; var cursorX; var cursorY; floatWindow.addEventListener("mousedown", function(e) { if (!isDragging) { cursorX = e.clientX; cursorY = e.clientY; initialX = cursorX - xOffset; initialY = cursorY - yOffset; isDragging = true; } }); floatWindow.addEventListener("mousemove", function(e) { if (isDragging) { e.preventDefault(); currentX = e.clientX - initialX; currentY = e.clientY - initialY; xOffset = currentX; yOffset = currentY; setTranslate(currentX, currentY, floatWindow); } }); floatWindow.addEventListener("mouseup", async function(e) { initialX = currentX; initialY = currentY; isDragging = false; // 如果点击时鼠标的位置没有改变,就认为是真正的点击 if (cursorX === e.clientX && cursorY === e.clientY) { await func(); } }); // 为悬浮窗添加事件处理程序,用来监听触摸开始和触摸移动事件 // 这些事件处理程序的实现方式与上面的鼠标事件处理程序类似 floatWindow.addEventListener('touchstart', (event) => { if (!isDragging) { cursorX = event.touches[0].clientX; cursorY = event.touches[0].clientY; initialX = cursorX - xOffset; initialY = cursorY - yOffset; isDragging = true; } }); floatWindow.addEventListener('touchmove', (event) => { if (isDragging) { currentX = event.touches[0].clientX - initialX; currentY = event.touches[0].clientY - initialY; xOffset = currentX; yOffset = currentY; setTranslate(currentX, currentY, floatWindow); } }); // 为悬浮窗添加事件处理程序,用来监听触摸结束事件 // 这个事件处理程序的实现方式与上面的鼠标事件处理程序类似 floatWindow.addEventListener('touchend', async () => { initialX = currentX; initialY = currentY; isDragging = false; // 如果点击时鼠标的位置没有改变,就认为是真正的点击 if (cursorX === event.touches[0].clientX && cursorY === event.touches[0].clientY) { await func(); } }); function setTranslate(xPos, yPos, el) { el.style.transform = "translate3d(" + xPos + "px, " + yPos + "px, 0)"; } //将悬浮窗添加到box元素中 box.appendChild(floatWindow); } // AI对话保存 createFloatButton("保存", ()=>{ savaAiRecording('',true); });

可通过 url 参数搜索

网页版增加 query string 的搜索功能,q 是 keyword , r=true 是否开启深度思考,s=true 是开启联网搜索

可配合这个使用,非常方便 [js] 工作栏增加搜索选中文本或访问选中链接,支持 ai 搜索和翻译

支持 deepseek,QwenChat 和通义千问

改造自 https://greasyfork.org/zh-CN/scripts/527071

deepseek 油猴脚本

// ==UserScript== // @name DeepSeek 网页版 URL 增加 query 搜索 // @namespace http://tampermonkey.net/ // @version 1.2 // @description 为 DeepSeek 网页版增加 query string 的搜索功能,q 是 keyword , r=true 是否开启深度思考,s=true 是开启联网搜索 // @author 阿依帝 with DeepSeek R1 (https://space.bilibili.com/103021226) // @match https://chat.deepseek.com/* // @icon https://www.google.com/s2/favicons?sz=64&domain=deepseek.com // @license MIT // @grant none // @run-at document-end // ==/UserScript== (function() { 'use strict'; // 解析URL参数 function getQueryParam(name) { const params = new URLSearchParams(window.location.search); return params.get(name); } // 查找包含指定文本的按钮 function findButtonByText(text) { const xpath = `//div[@role='button']//span[contains(text(), '${text}')]`; const result = document.evaluate(xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null); return result.singleNodeValue?.closest('div[role="button"]'); } // 检查按钮是否激活 function isButtonActive(button) { return getComputedStyle(button).getPropertyValue('--ds-button-color').includes('#DBEAFE'); //77, 107, 254 } // 触发React的输入事件 function setReactInputValue(element, value) { const inputEvent = new Event('input', { bubbles: true, composed: true }); const nativeInputValueSetter = Object.getOwnPropertyDescriptor( window.HTMLTextAreaElement.prototype, 'value' ).set; nativeInputValueSetter.call(element, value); element.dispatchEvent(inputEvent); } // 处理模式切换 async function toggleMode(button, shouldEnable) { if (!button) return; await new Promise(r => setTimeout(r, 100)); const isActive = isButtonActive(button); if (shouldEnable && !isActive) { button.click(); await new Promise(r => setTimeout(r, 200)); } if (!shouldEnable && isActive) { button.click(); await new Promise(r => setTimeout(r, 200)); } } // 主处理函数 async function processQueryParams() { // 获取参数(已修复括号问题) const qParam = getQueryParam('q'); const query = qParam ? decodeURIComponent(qParam) : ''; const needDeepThinking = getQueryParam('r') === 'true'; const search = getQueryParam('s') === 'true'; if (!query) return; // 等待必要元素加载 const maxWaitTime = 5000; const startTime = Date.now(); // 等待输入框加载 let textarea; while (!(textarea = document.getElementById('chat-input')) && Date.now() - startTime < maxWaitTime) { await new Promise(r => setTimeout(r, 100)); } if (!textarea) { console.error('找不到输入框'); return; } // 填充查询内容 setReactInputValue(textarea, query); // 强制开启联网搜索 const webSearchBtn = findButtonByText('联网搜索'); await toggleMode(webSearchBtn, search); // 处理深度思考模式 const deepThinkBtn = findButtonByText('深度思考'); await toggleMode(deepThinkBtn, needDeepThinking); // 点击发送按钮 const sendBtn = document.querySelector('div[role="button"][aria-disabled="false"]'); if (sendBtn) { sendBtn.click(); } else { const observer = new MutationObserver(() => { const activeSendBtn = document.querySelector('div[role="button"][aria-disabled="false"]'); if (activeSendBtn) { observer.disconnect(); activeSendBtn.click(); } }); observer.observe(document.body, { childList: true, subtree: true }); } } // 页面加载完成后执行 window.addEventListener('load', () => { setTimeout(processQueryParams, 1000); }); })();

QwenChat 油猴脚本

// ==UserScript== // @name QWen Chat 网页版 URL 增加 query 搜索 // @namespace http://tampermonkey.net/ // @version 1.2 // @description 为 QWen Chat 网页版增加 query string 的搜索功能,q 是 keyword , r=true 是否开启深度思考,s=true 是开启联网搜索,temporary-chat=true是开启临时对话 // @author Wilson 改自 阿依帝 with DeepSeek R1 (https://space.bilibili.com/103021226) // @match https://chat.qwen.ai/* // @icon https://www.google.com/s2/favicons?sz=64&domain=qwen.ai // @license MIT // @grant none // @run-at document-end // ==/UserScript== (function() { 'use strict'; // 解析URL参数 function getQueryParam(name) { const params = new URLSearchParams(window.location.search); return params.get(name); } // 查找包含指定文本的按钮 function findButtonByText(text) { const xpath = `//button//span[contains(text(), '${text}')]`; const result = document.evaluate(xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null); return result.singleNodeValue?.closest('button'); } // 检查按钮是否激活 function isButtonActive(button) { return getComputedStyle(button).getPropertyValue('backgroundColor').includes('rgb(224, 223, 255)'); } // 触发React的输入事件 function setReactInputValue(element, value) { const inputEvent = new Event('input', { bubbles: true, composed: true }); const nativeInputValueSetter = Object.getOwnPropertyDescriptor( window.HTMLTextAreaElement.prototype, 'value' ).set; nativeInputValueSetter.call(element, value); element.dispatchEvent(inputEvent); } // 处理模式切换 async function toggleMode(button, shouldEnable) { if (!button) return; await new Promise(r => setTimeout(r, 100)); const isActive = isButtonActive(button); if (shouldEnable && !isActive) { button.click(); await new Promise(r => setTimeout(r, 200)); } if (!shouldEnable && isActive) { button.click(); await new Promise(r => setTimeout(r, 200)); } } // 主处理函数 async function processQueryParams() { // 获取参数(已修复括号问题) const qParam = getQueryParam('q'); const query = qParam ? decodeURIComponent(qParam) : ''; const needDeepThinking = getQueryParam('r') === 'true'; const search = getQueryParam('s') === 'true'; //alert(query+'|'+needDeepThinking+'|'+search); if (!query) return; // 等待必要元素加载 const maxWaitTime = 5000; const startTime = Date.now(); // 等待输入框加载 let textarea; while (!(textarea = document.getElementById('chat-input')) && Date.now() - startTime < maxWaitTime) { await new Promise(r => setTimeout(r, 100)); } if (!textarea) { console.error('找不到输入框'); return; } // 填充查询内容 setReactInputValue(textarea, query); // 强制开启联网搜索 const webSearchBtn = findButtonByText('搜索'); await toggleMode(webSearchBtn, search); // 处理深度思考模式 const deepThinkBtn = findButtonByText('深度思考'); await toggleMode(deepThinkBtn, needDeepThinking); // 点击发送按钮 const sendBtn = document.querySelector('#send-message-button'); if (sendBtn) { sendBtn.click(); } else { const observer = new MutationObserver(() => { const activeSendBtn = document.querySelector('#send-message-button'); if (activeSendBtn) { observer.disconnect(); activeSendBtn.click(); } }); observer.observe(document.body, { childList: true, subtree: true }); } } // 页面加载完成后执行 window.addEventListener('load', () => { setTimeout(processQueryParams, 1000); }); })();

通义千问油猴脚本

// ==UserScript== // @name 通义千问 网页版 URL 增加 query 搜索 // @namespace http://tampermonkey.net/ // @version 1.2 // @description 为通义千问网页版增加 query string 的搜索功能,q 是 keyword // @author Wilson 改自 阿依帝 with DeepSeek R1 (https://space.bilibili.com/103021226) // @match https://tongyi.aliyun.com/* // @icon https://www.google.com/s2/favicons?sz=64&domain=tongyi.aliyun.com // @license MIT // @grant none // @run-at document-end // ==/UserScript== (function() { 'use strict'; // 解析URL参数 function getQueryParam(name) { const params = new URLSearchParams(window.location.search); return params.get(name); } // 触发React的输入事件 function setReactInputValue(element, value) { const inputEvent = new Event('input', { bubbles: true, composed: true }); const nativeInputValueSetter = Object.getOwnPropertyDescriptor( window.HTMLTextAreaElement.prototype, 'value' ).set; nativeInputValueSetter.call(element, value); element.dispatchEvent(inputEvent); } // 主处理函数 async function processQueryParams() { // 获取参数(已修复括号问题) const qParam = getQueryParam('q'); const query = qParam ? decodeURIComponent(qParam) : ''; if (!query) return; // 等待必要元素加载 const maxWaitTime = 5000; const startTime = Date.now(); // 等待输入框加载 let textarea; while (!(textarea = document.querySelector('.ant-input')) && Date.now() - startTime < maxWaitTime) { await new Promise(r => setTimeout(r, 100)); } if (!textarea) { console.error('找不到输入框'); return; } // 填充查询内容 setReactInputValue(textarea, query); // 点击发送按钮 const sendBtn = Array.from(document.querySelectorAll('use')).find(node => node.getAttribute('xlink:href') === '#icon-fasong_default')?.closest('div'); if (sendBtn) { sendBtn.click(); } else { const observer = new MutationObserver(() => { const activeSendBtn = Array.from(document.querySelectorAll('use')).find(node => node.getAttribute('xlink:href') === '#icon-fasong_default')?.closest('div'); if (activeSendBtn) { observer.disconnect(); activeSendBtn.click(); } }); observer.observe(document.body, { childList: true, subtree: true }); } } // 页面加载完成后执行 window.addEventListener('load', () => { setTimeout(processQueryParams, 1000); }); })();

AI 划词搜索

兼容所有网页

image.png

// ==UserScript== // @name AI搜索 // @namespace http://tampermonkey.net/ // @version 2025-03-13 // @description AI搜索 // @author Wilson // @match http*://*/* // @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== // @grant GM_addStyle // ==/UserScript== (function() { 'use strict'; // AI搜索引擎, %s% 是搜索关键词 // https://chat.qwen.ai/?q=%s% const AISearch = 'https://chat.baidu.com/search?word=%s%'; GM_addStyle(` /* 提示框样式 */ #search-tip { position: absolute; display: none; padding: 5px 10px; background-color: #007bff; color: white; border-radius: 4px; cursor: pointer; box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); z-index: 1000; white-space: nowrap; /* 防止文本换行 */ } `); document.body.insertAdjacentHTML('beforeend', ` <!-- 搜索提示框 --> <div id="search-tip">AI搜<span id="selected-text"></span></div> `); // 获取相关 DOM 元素 const searchTip = document.getElementById('search-tip'); const selectedTextSpan = document.getElementById('selected-text'); // 监听鼠标松开事件 document.addEventListener('mouseup', (event) => { // 获取选中的文本 const selection = window.getSelection().toString().trim(); // 如果没有选中文本,则隐藏提示框并退出 if (!selection) { searchTip.style.display = 'none'; return; } // 更新提示框内容 //selectedTextSpan.textContent = selection; // 获取鼠标位置(基于文档坐标) const { pageX, pageY } = event; // 设置提示框的位置(略微偏移鼠标位置) searchTip.style.left = `${pageX + 10}px`; // 向右偏移 10px searchTip.style.top = `${pageY + 10}px`; // 向下偏移 10px // 显示提示框 searchTip.style.display = 'block'; // 点击提示框时跳转到百度搜索 searchTip.onclick = () => { const encodedQuery = encodeURIComponent(selection); // 对选中文本进行编码 window.open(AISearch.replace('%s%', encodedQuery), '_blank'); // 跳转到百度搜索 }; }); // 点击页面其他地方时隐藏提示框 document.addEventListener('mousedown', (event) => { if (!searchTip.contains(event.target)) { searchTip.style.display = 'none'; } }); })();

UI 美化

目前仅支持 QwenChat。

主要对问题的背景色进行了调整,方便滚动浏览时分清每条问答,之前的颜色太浅,不容易区分。

还让对聊天页面的滚动条显示出来,原来是不显示的,只能滚轮滚动,不能用鼠标拖动。

// ==UserScript== // @name AI美化 // @namespace http://tampermonkey.net/ai // @version 2025-03-12 // @description AI UI美化 // @author Wilson // @match https://chat.qwen.ai/* // @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== // @grant GM_addStyle // ==/UserScript== (function() { 'use strict'; if (location.href.indexOf("chat.qwen.ai")!==-1) { GM_addStyle(` /* 用户问题 */ .user-message div:has(> p){background-color: #E0E0FD;} ::-webkit-scrollbar { width: 10px; } ::-webkit-scrollbar-track { background: #fafafa; border-radius: 5px; box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.1); } ::-webkit-scrollbar-thumb { background: #c1c1c1; border-radius: 5px; border: 2px solid #fafafa; } ::-webkit-scrollbar-thumb:hover { background: #a8a8a8; } /* Firefox */ body { scrollbar-width: thin; scrollbar-color: #c1c1c1 #fafafa; } `); } })();

更多 AI 的支持

更多 AI 的支持,感兴趣的小伙伴可以根据上面的脚本继续改造。

补充

这里的 QwenChat 是指 https://chat.qwen.ai/ 不是指 https://tongyi.aliyun.com/qianwen/

感觉比国内版的通义千问强大和好用。

  • 思源笔记

    思源笔记是一款隐私优先的个人知识管理系统,支持完全离线使用,同时也支持端到端加密同步。

    融合块、大纲和双向链接,重构你的思维。

    25222 引用 • 104018 回帖 • 1 关注
  • 油猴
    8 引用 • 34 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...