// ==UserScript==
// @name Deepseek Chat 增强版Deepseek API对话助手,支持历史记录、参数设置、网页内容检索和自定义人格提示词
// @namespace shy
// @version 1.9.1
// @description 增强版Deepseek API对话助手,支持历史记录、参数设置、网页内容检索和自定义人格提示词
// @author shy
// @match *://*/*
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_xmlhttpRequest
// @grant GM_registerMenuCommand
// @grant GM_addStyle
// @grant GM_getResourceText
// @connect api.deepseek.com
// @license MIT
// ==/UserScript==
(function() {
'use strict';
// 添加CSS样式
GM_addStyle(`
.ds-chat-icon {
position: fixed;
bottom: 20px;
right: 20px;
width: 50px;
height: 50px;
background-color: rgba(0, 123, 255, 0.5);
border-radius: 50%;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
color: #fff;
font-size: 24px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3);
transition: transform 0.2s, box-shadow 0.2s;
z-index: 2147483647;
backdrop-filter: blur(5px);
border: 1px solid rgba(255, 255, 255, 0.4);
}
.ds-chat-icon:hover {
transform: scale(1.05);
box-shadow: 0 6px 8px rgba(0, 0, 0, 0.3);
background-color: rgba(0, 123, 255, 0.6);
}
.ds-chat-window {
position: fixed;
bottom: 20px;
right: 20px;
width: 350px;
max-width: 40vw;
max-height: 70vh;
background-color: rgba(249, 249, 249, 0.3);
border: 1px solid #ddd;
border-radius: 15px;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
display: none;
flex-direction: column;
overflow: hidden;
transition: opacity 0.3s, transform 0.3s, width 0.3s;
opacity: 0;
transform: translateY(20px);
z-index: 2147483646;
backdrop-filter: blur(5px);
}
.ds-chat-window.active {
display: flex;
opacity: 1;
transform: translateY(0);
}
.ds-chat-header {
padding: 10px 15px;
background-color: rgba(0, 123, 255, 0.3);
color: white;
display: flex;
justify-content: space-between;
align-items: center;
border-radius: 15px 15px 0 0;
}
.ds-chat-title {
font-weight: bold;
}
.ds-chat-close {
cursor: pointer;
font-size: 18px;
}
.ds-chat-content {
flex: 1;
padding: 15px;
overflow-y: auto;
background-color: rgba(255, 255, 255, 0.3);
border-bottom: 1px solid #ddd;
}
.ds-chat-message {
margin-bottom: 10px;
padding: 8px 12px;
border-radius: 8px;
line-height: 1.4;
word-wrap: break-word;
}
.ds-user-message {
background-color: rgba(227, 242, 253, 0.7);
margin-left: auto;
text-align: right;
}
.ds-ai-message {
background-color: rgba(241, 241, 241, 0.7);
margin-right: 20%;
opacity: 0;
animation: fadeIn 0.5s ease-in-out forwards;
}
.ds-chat-input-area {
padding: 10px;
display: flex;
flex-direction: column;
backdrop-filter: blur(5px);
background-color: rgba(255, 255, 255, 0.3);
border-top: 1px solid rgba(221, 221, 221, 0.5);
}
.ds-chat-input {
width: 100%;
padding: 10px;
border: 1px solid #ddd;
border-radius: 8px;
margin-bottom: 8px;
outline: none;
transition: border-color 0.3s;
}
.ds-chat-input:focus {
border-color: #007bff;
}
.ds-chat-settings {
display: flex;
justify-content: space-between;
font-size: 12px;
color: #666;
}
.ds-chat-settings-btn {
cursor: pointer;
text-decoration: underline;
}
.ds-thinking {
color: #666;
font-style: italic;
}
.ds-error {
color: #ff0000;
}
.ds-context-toggle {
margin-bottom: 8px;
display: flex;
align-items: center;
font-size: 12px;
}
.ds-context-toggle input {
margin-right: 5px;
}
.ds-context-summary {
font-size: 11px;
color: #666;
margin-top: 5px;
font-style: italic;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
`);
// 初始化配置
let config = {
apiKey: GM_getValue('apiKey', ''),
model: GM_getValue('model', 'deepseek-chat'),
temperature: GM_getValue('temperature', 0.7),
maxTokens: GM_getValue('maxTokens', 1024),
chatHistory: GM_getValue('chatHistory', []),
usePageContext: GM_getValue('usePageContext', true),
personalityPrompt: GM_getValue('personalityPrompt', `
输出文本控制不能超过600字
你是锐锐,一个18岁、热爱数学的可爱女孩。你性格聪明冷静,语言犀利,堪称“怼人”专业户,但内心善良,对朋友真诚,伙伴遇困定会援手相助。
你外貌甜美,皮肤白皙,大眼睛灵动有神。总是身着背带制服,搭配白色腿袜和小皮鞋,乌黑亮丽的高马尾活泼摆动,头上戴着红色蝴蝶结发箍。充满青春活力。
你的性格特点:聪明、冷静、犀利、善良、真诚。
你的说话风格:言辞简洁有力,逻辑清晰,关心朋友时又温柔贴心。
`) // 新增:人格提示词
};
// 创建UI元素
const icon = document.createElement('div');
icon.className = 'ds-chat-icon';
icon.innerText = 'AI';
document.body.appendChild(icon);
const chatWindow = document.createElement('div');
chatWindow.className = 'ds-chat-window';
document.body.appendChild(chatWindow);
// 聊天窗口头部
const chatHeader = document.createElement('div');
chatHeader.className = 'ds-chat-header';
chatWindow.appendChild(chatHeader);
const chatTitle = document.createElement('div');
chatTitle.className = 'ds-chat-title';
chatTitle.innerText = 'Deepseek Chat';
chatHeader.appendChild(chatTitle);
const closeBtn = document.createElement('div');
closeBtn.className = 'ds-chat-close';
closeBtn.innerText = '×';
chatHeader.appendChild(closeBtn);
// 聊天内容区域
const chatContent = document.createElement('div');
chatContent.className = 'ds-chat-content';
chatWindow.appendChild(chatContent);
// 输入区域
const inputArea = document.createElement('div');
inputArea.className = 'ds-chat-input-area';
chatWindow.appendChild(inputArea);
// 添加网页上下文开关
const contextToggle = document.createElement('div');
contextToggle.className = 'ds-context-toggle';
inputArea.appendChild(contextToggle);
const contextCheckbox = document.createElement('input');
contextCheckbox.type = 'checkbox';
contextCheckbox.id = 'ds-context-checkbox';
contextCheckbox.checked = config.usePageContext;
contextToggle.appendChild(contextCheckbox);
const contextLabel = document.createElement('label');
contextLabel.htmlFor = 'ds-context-checkbox';
contextLabel.innerText = '包含当前网页内容';
contextToggle.appendChild(contextLabel);
const contextSummary = document.createElement('div');
contextSummary.className = 'ds-context-summary';
contextSummary.innerText = '当前网页: ' + document.title;
inputArea.appendChild(contextSummary);
const inputBox = document.createElement('textarea');
inputBox.className = 'ds-chat-input';
inputBox.placeholder = '输入你的问题...';
inputBox.rows = 3;
inputArea.appendChild(inputBox);
const settingsArea = document.createElement('div');
settingsArea.className = 'ds-chat-settings';
inputArea.appendChild(settingsArea);
const settingsBtn = document.createElement('span');
settingsBtn.className = 'ds-chat-settings-btn';
settingsBtn.innerText = '⚙️';
settingsArea.appendChild(settingsBtn);
const clearBtn = document.createElement('span');
clearBtn.className = 'ds-chat-settings-btn';
clearBtn.innerText = '🗑️';
settingsArea.appendChild(clearBtn);
// 显示历史消息
function displayHistory() {
chatContent.innerHTML = '';
config.chatHistory.forEach(msg => {
const msgDiv = document.createElement('div');
msgDiv.className = `ds-chat-message ds-${msg.role}-message`;
msgDiv.innerText = msg.content;
chatContent.appendChild(msgDiv);
});
chatContent.scrollTop = chatContent.scrollHeight;
}
// 初始化显示历史消息
displayHistory();
// 图标点击事件
icon.addEventListener('click', () => {
chatWindow.classList.toggle('active');
icon.style.display = 'none';
});
// 关闭按钮事件
closeBtn.addEventListener('click', () => {
chatWindow.classList.remove('active');
icon.style.display = 'flex';
});
// 上下文开关事件
contextCheckbox.addEventListener('change', () => {
config.usePageContext = contextCheckbox.checked;
GM_setValue('usePageContext', config.usePageContext);
});
// 设置按钮事件
settingsBtn.addEventListener('click', () => {
const newApiKey = prompt('DeepSeek API密钥:', config.apiKey);
if (newApiKey !== null) {
config.apiKey = newApiKey;
GM_setValue('apiKey', config.apiKey);
}
const newModel = prompt('模型 (deepseek-chat, deepseek-coder等):', config.model);
if (newModel !== null) {
config.model = newModel;
GM_setValue('model', config.model);
}
const newTemp = parseFloat(prompt('Temperature (0-2):', config.temperature));
if (!isNaN(newTemp) && newTemp >= 0 && newTemp <= 2) {
config.temperature = newTemp;
GM_setValue('temperature', config.temperature);
}
const newMaxTokens = parseInt(prompt('最大令牌数:', config.maxTokens));
if (!isNaN(newMaxTokens) && newMaxTokens > 0) {
config.maxTokens = newMaxTokens;
GM_setValue('maxTokens', config.maxTokens);
}
// 新增:自定义人格提示词设置
const newPersonalityPrompt = prompt('自定义人格提示词(例如性格、外貌、说话风格等):', config.personalityPrompt);
if (newPersonalityPrompt !== null) {
config.personalityPrompt = newPersonalityPrompt;
GM_setValue('personalityPrompt', config.personalityPrompt);
}
});
// 清空历史按钮事件
clearBtn.addEventListener('click', () => {
config.chatHistory = [];
GM_setValue('chatHistory', config.chatHistory);
chatContent.innerHTML = '';
});
// 获取网页主要内容
function getPageContent() {
const mainContent = document.querySelector('main, article, .main, .content, #content') || document.body;
const clone = mainContent.cloneNode(true);
const elementsToRemove = clone.querySelectorAll('script, style, noscript, iframe, nav, footer, header, aside');
elementsToRemove.forEach(el => el.remove());
let text = clone.textContent
.replace(/\s+/g, ' ')
.trim()
.substring(0, 5000);
return {
url: window.location.href,
title: document.title,
content: text
};
}
// 获取网页HTML内容
function getPageHTML() {
const mainContent = document.querySelector('main, article, .main, .content, #content') || document.body;
const clone = mainContent.cloneNode(true);
const elementsToRemove = clone.querySelectorAll('script, style, noscript, iframe, nav, footer, header, aside');
elementsToRemove.forEach(el => el.remove());
return clone.innerHTML;
}
// 获取网页图片名称
function getImageNames() {
const images = document.querySelectorAll('img');
const imageNames = [];
images.forEach(img => {
const src = img.src;
const name = src.split('/').pop();
imageNames.push(name);
});
return imageNames.join(', ');
}
// 调整对话框宽度
function adjustChatWindowWidth(text) {
const chatWindow = document.querySelector('.ds-chat-window');
const maxWidth = window.innerWidth * 0.4;
const minWidth = 350;
const textLength = text.length;
let newWidth = minWidth + (textLength * 5);
newWidth = Math.min(newWidth, maxWidth);
chatWindow.style.width = `${newWidth}px`;
}
// 逐行显示AI回答
function typeMessage(message, container) {
const lines = message.split('\n');
let index = 0;
const interval = setInterval(() => {
if (index < lines.length) {
const line = document.createElement('div');
line.innerText = lines[index];
container.appendChild(line);
chatContent.scrollTop = chatContent.scrollHeight;
index++;
} else {
clearInterval(interval);
}
}, 200);
}
// 发送消息函数
function sendMessage(message) {
if (!message.trim()) return;
if (!config.apiKey) {
alert('请先设置API密钥!');
settingsBtn.click();
return;
}
let finalMessage = message;
if (config.usePageContext) {
const pageContent = getPageContent();
const pageHTML = getPageHTML();
const imageNames = getImageNames();
finalMessage = `[当前网页信息]
标题: ${pageContent.title}
URL: ${pageContent.url}
内容摘要: ${pageContent.content}
HTML内容: ${pageHTML}
图片名称: ${imageNames}
基于以上网页内容,请回答以下问题:
${message}`;
}
const userMsg = { role: 'user', content: message };
config.chatHistory.push(userMsg);
GM_setValue('chatHistory', config.chatHistory);
const userMsgDiv = document.createElement('div');
userMsgDiv.className = 'ds-chat-message ds-user-message';
userMsgDiv.innerText = message;
chatContent.appendChild(userMsgDiv);
const thinkingMsgDiv = document.createElement('div');
thinkingMsgDiv.className = 'ds-chat-message ds-thinking';
thinkingMsgDiv.innerText = '思考中...';
chatContent.appendChild(thinkingMsgDiv);
chatContent.scrollTop = chatContent.scrollHeight;
const requestData = {
model: config.model,
messages: [
{ role: 'system', content: config.personalityPrompt }, // 使用自定义人格提示词
...config.chatHistory.map(msg => ({
role: msg.role,
content: msg.role === 'user' && config.usePageContext ? finalMessage : msg.content
}))
],
temperature: config.temperature,
max_tokens: config.maxTokens
};
GM_xmlhttpRequest({
method: 'POST',
url: 'https://api.deepseek.com/v1/chat/completions',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${config.apiKey}`
},
data: JSON.stringify(requestData),
onload: function(response) {
try {
const data = JSON.parse(response.responseText);
if (data.choices && data.choices[0]) {
const aiMessage = data.choices[0].message.content;
chatContent.removeChild(thinkingMsgDiv);
const aiMsg = { role: 'assistant', content: aiMessage };
config.chatHistory.push(aiMsg);
GM_setValue('chatHistory', config.chatHistory);
const aiMsgDiv = document.createElement('div');
aiMsgDiv.className = 'ds-chat-message ds-ai-message';
typeMessage(aiMessage, aiMsgDiv);
chatContent.appendChild(aiMsgDiv);
adjustChatWindowWidth(aiMessage); // 调整对话框宽度
} else {
throw new Error('无效的API响应');
}
} catch (e) {
showError(`错误: ${e.message}`);
}
chatContent.scrollTop = chatContent.scrollHeight;
},
onerror: function(error) {
showError(`请求失败: ${error.statusText || '网络错误'}`);
}
});
}
// 显示错误消息
function showError(message) {
const errorMsgDiv = document.createElement('div');
errorMsgDiv.className = 'ds-chat-message ds-error';
errorMsgDiv.innerText = message;
chatContent.appendChild(errorMsgDiv);
chatContent.scrollTop = chatContent.scrollHeight;
}
// 输入框事件
inputBox.addEventListener('keydown', (e) => {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
const message = inputBox.value.trim();
if (message) {
sendMessage(message);
inputBox.value = '';
}
}
});
// 注册菜单命令
GM_registerMenuCommand("设置DeepSeek API", () => settingsBtn.click());
GM_registerMenuCommand("清空聊天历史", () => clearBtn.click());
GM_registerMenuCommand("切换网页上下文", () => {
contextCheckbox.checked = !contextCheckbox.checked;
config.usePageContext = contextCheckbox.checked;
GM_setValue('usePageContext', config.usePageContext);
});
GM_registerMenuCommand("设置自定义人格提示词", () => {
const newPersonalityPrompt = prompt('请输入自定义人格提示词:', config.personalityPrompt);
if (newPersonalityPrompt !== null) {
config.personalityPrompt = newPersonalityPrompt;
GM_setValue('personalityPrompt', config.personalityPrompt);
}
});
})();