无法访问 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 安装这个油猴脚本即可
聊天问题列表
显示聊天会话中,你已经提的问题列表,点击跳转到对应的聊天处
改造自 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 文件
支持 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 划词搜索
兼容所有网页
// ==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/
感觉比国内版的通义千问强大和好用。
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于