// ==UserScript== // @name AI Chat // @namespace Auntilz // @version 1.0 // @description ai助手 // @author Auntilz // @license MIT // @match *://*/* // @grant GM_getValue // @grant GM_setValue // @grant GM_xmlhttpRequest // @grant GM_registerMenuCommand // @connect api.siliconflow.cn // @downloadURL https://update.greasyfork.icu/scripts/528941/AI%20Chat.user.js // @updateURL https://update.greasyfork.icu/scripts/528941/AI%20Chat.meta.js // ==/UserScript== (function() { 'use strict'; window.addEventListener('error', function(e) { alert('脚本错误: ' + e.message); console.error('脚本错误:', e) }); function debugLog(...args) { if (!debugMode) return; console.log('[SiliconFlow Debug]', ...args); let debugEl = document.getElementById('silicon-flow-debug'); if (!debugEl) { debugEl = document.createElement('div'); debugEl.id = 'silicon-flow-debug'; debugEl.style.position = 'fixed'; debugEl.style.bottom = '10px'; debugEl.style.left = '10px'; debugEl.style.background = 'rgba(0,0,0,0.8)'; debugEl.style.color = 'white'; debugEl.style.padding = '10px'; debugEl.style.borderRadius = '5px'; debugEl.style.maxHeight = '200px'; debugEl.style.overflowY = 'auto'; debugEl.style.maxWidth = '500px'; debugEl.style.zIndex = '10000'; debugEl.style.fontSize = '12px'; debugEl.style.fontFamily = 'monospace'; debugEl.style.display = 'none'; document.body.appendChild(debugEl) } if (debugMode) { const line = document.createElement('div'); line.textContent = args.map(a => typeof a === 'object' ? JSON.stringify(a) : a).join(' '); debugEl.appendChild(line); debugEl.scrollTop = debugEl.scrollHeight; while (debugEl.children.length > 50) { debugEl.removeChild(debugEl.firstChild) } } debugEl.style.display = debugMode ? 'block' : 'none' } let apiKey = GM_getValue('apiKey', ''); let model = GM_getValue('model', 'deepseek-ai/DeepSeek-V3'); let currentStream = null; let chatHistory = GM_getValue('chatHistory', []); let isDarkMode = GM_getValue('isDarkMode', false); let fontSize = GM_getValue('fontSize', 14); let debugMode = GM_getValue('debugMode', true); let useStreamMode = GM_getValue('useStreamMode', true); debugLog('脚本初始化', '模型:', model, '深色模式:', isDarkMode, '调试模式:', debugMode); const colors = { light: { background: '#ffffff', secondaryBg: '#f8f9fa', border: '#e1e4e8', text: '#24292e', primaryText: '#0366d6', secondaryText: '#586069', iconBg: '#0366d6', iconHover: '#0257c5', inputBg: '#ffffff', aiResponse: '#f1f8ff' }, dark: { background: '#1e1e1e', secondaryBg: '#252525', border: '#333333', text: '#e1e4e8', primaryText: '#58a6ff', secondaryText: '#8b949e', iconBg: '#1f6feb', iconHover: '#388bfd', inputBg: '#2d2d2d', aiResponse: '#161b22' } }; const getColor = (key) => isDarkMode ? colors.dark[key] : colors.light[key]; const style = document.createElement('style'); document.head.appendChild(style); function updateStyles() { style.textContent = `.ai-chat-icon{position:fixed;width:56px;height:56px;background-color:${getColor('iconBg')};border-radius:50%;display:flex;align-items:center;justify-content:center;color:white;font-weight:bold;box-shadow:0 4px 14px rgba(0,0,0,0.16);cursor:grab;user-select:none;touch-action:none;z-index:2147483647;font-family:system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif}.ai-chat-icon svg{filter:drop-shadow(0 2px 4px rgba(0,0,0,0.2));transition:transform 0.2s ease}.ai-chat-icon:hover{transform:scale(1.08);box-shadow:0 6px 20px rgba(0,0,0,0.2)}.ai-chat-icon:hover svg{transform:scale(1.1)}.ai-chat-icon:hover{transform:scale(1.05);background-color:${getColor('iconHover')}}.ai-chat-window{position:fixed;bottom:85px;right:20px;width:380px;height:550px;background-color:${getColor('background')};border-radius:16px;box-shadow:0 8px 30px rgba(0,0,0,0.12);display:flex;flex-direction:column;overflow:hidden;z-index:9998;font-family:system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;border:1px solid ${getColor('border')};transition:all 0.3s ease}.ai-chat-header{display:flex;align-items:center;justify-content:space-between;padding:14px 16px;background-color:${getColor('secondaryBg')};border-bottom:1px solid ${getColor('border')};border-top-left-radius:16px;border-top-right-radius:16px}.ai-chat-title{font-weight:600;font-size:16px;color:${getColor('text')};margin:0}.ai-chat-actions{display:flex;align-items:center;gap:14px}.ai-chat-action{background:none;border:none;color:${getColor('secondaryText')};cursor:pointer;font-size:18px;padding:0;display:flex;align-items:center;justify-content:center;width:30px;height:30px;border-radius:6px;transition:all 0.2s ease}.ai-chat-action:hover{background-color:${getColor('border')};color:${getColor('primaryText')}}.ai-chat-content{flex:1;padding:16px;overflow-y:auto;overflow-x:hidden;scroll-behavior:smooth}.ai-chat-content::-webkit-scrollbar{width:6px}.ai-chat-content::-webkit-scrollbar-thumb{background-color:${getColor('border')};border-radius:10px}.ai-chat-content::-webkit-scrollbar-track{background-color:transparent}.ai-message{margin-bottom:18px;font-size:${fontSize}px;line-height:1.5;word-wrap:break-word}.ai-user-message{color:${getColor('text')}}.ai-response{padding:12px 16px;background-color:${getColor('aiResponse')};border-radius:10px;margin-top:6px;color:${getColor('text')};word-break:break-word}.ai-sender{font-weight:600;margin-bottom:4px;color:${getColor('primaryText')};display:flex;align-items:center;gap:6px}.ai-chat-input-container{padding:12px 16px;border-top:1px solid ${getColor('border')};background-color:${getColor('secondaryBg')}}.ai-chat-input-wrapper{position:relative;border-radius:10px;background-color:${getColor('inputBg')};border:1px solid ${getColor('border')};padding:8px 40px 8px 12px;transition:border-color 0.2s ease}.ai-chat-input-wrapper:focus-within{border-color:${getColor('primaryText')};box-shadow:0 0 0 2px rgba(3,102,214,0.2)}.ai-chat-input{width:100%;min-height:24px;max-height:120px;border:none;outline:none;background:transparent;resize:none;font-family:inherit;font-size:${fontSize}px;line-height:1.5;color:${getColor('text')};overflow-y:auto}.ai-chat-input::placeholder{color:${getColor('secondaryText')}}.ai-chat-send{position:absolute;right:8px;bottom:8px;width:28px;height:28px;border-radius:50%;background-color:${getColor('iconBg')};color:white;border:none;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all 0.2s ease}.ai-chat-send:hover{background-color:${getColor('iconHover')}}.ai-chat-send svg{width:16px;height:16px}.ai-settings-panel{position:absolute;top:60px;right:16px;background-color:${getColor('background')};border-radius:10px;border:1px solid ${getColor('border')};box-shadow:0 8px 24px rgba(0,0,0,0.12);padding:16px;width:270px;z-index:10000;display:none;flex-direction:column;gap:14px}.ai-settings-group{display:flex;flex-direction:column;gap:8px}.ai-settings-label{font-size:14px;font-weight:600;color:${getColor('text')}}.ai-settings-input{padding:8px 12px;border-radius:6px;border:1px solid ${getColor('border')};font-size:14px;background-color:${getColor('inputBg')};color:${getColor('text')};width:100%;outline:none}.ai-settings-input:focus{border-color:${getColor('primaryText')};box-shadow:0 0 0 2px rgba(3,102,214,0.2)}.ai-toggle-wrapper{display:flex;justify-content:space-between;align-items:center}.ai-toggle{position:relative;display:inline-block;width:44px;height:22px}.ai-toggle input{opacity:0;width:0;height:0}.ai-toggle-slider{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background-color:${getColor('border')};transition:0.4s;border-radius:22px}.ai-toggle-slider:before{position:absolute;content:"";height:18px;width:18px;left:2px;bottom:2px;background-color:white;transition:0.4s;border-radius:50%}input:checked+.ai-toggle-slider{background-color:${getColor('iconBg')}}input:checked+.ai-toggle-slider:before{transform:translateX(22px)}.ai-settings-footer{display:flex;justify-content:flex-end;gap:10px;margin-top:6px}.ai-settings-button{padding:8px 14px;border-radius:6px;font-size:14px;font-weight:500;cursor:pointer;transition:all 0.2s ease}.ai-settings-cancel{background-color:transparent;border:1px solid ${getColor('border')};color:${getColor('text')}}.ai-settings-cancel:hover{background-color:${getColor('border')}}.ai-settings-save{background-color:${getColor('iconBg')};border:1px solid ${getColor('iconBg')};color:white}.ai-settings-save:hover{background-color:${getColor('iconHover')}}.ai-typing{display:inline-block;font-weight:bold;animation:ai-cursor-blink 0.8s infinite;white-space:nowrap}@keyframes ai-cursor-blink{0%{opacity:1}50%{opacity:0}100%{opacity:1}}.ai-code-block{background-color:${isDarkMode?'#1a1a1a':'#f6f8fa'};border-radius:6px;padding:12px;margin:10px 0;overflow-x:auto;font-family:monospace}.ai-markdown p{margin:4px 0}.ai-markdown br{display:block;margin-bottom:2px;content:""}.ai-markdown ul,.ai-markdown ol{padding-left:24px;margin:10px 0}.ai-markdown code{background-color:${isDarkMode?'#1a1a1a':'#f6f8fa'};padding:2px 4px;border-radius:4px;font-family:monospace}.ai-font-size-control{display:flex;align-items:center;gap:10px}.ai-font-button{width:28px;height:28px;display:flex;align-items:center;justify-content:center;border-radius:6px;background-color:${getColor('secondaryBg')};border:1px solid ${getColor('border')};color:${getColor('text')};cursor:pointer}.ai-font-button:hover{background-color:${getColor('border')}}.ai-font-size-display{width:30px;text-align:center;font-size:14px;color:${getColor('text')}}.ai-settings-note{font-size:12px;color:${getColor('secondaryText')};margin-top:4px}.ai-clear-chat{color:#d73a49;cursor:pointer;font-size:14px;display:flex;align-items:center;gap:6px;margin-top:10px}.ai-clear-chat:hover{text-decoration:underline}.ai-model-selector{position:relative}.ai-model-selector select{width:100%;padding:8px 12px;border-radius:6px;border:1px solid ${getColor('border')};background-color:${getColor('inputBg')};color:${getColor('text')};appearance:none;font-size:14px;cursor:pointer}.ai-model-selector::after{content:"▼";font-size:12px;color:${getColor('secondaryText')};position:absolute;right:12px;top:50%;transform:translateY(-50%);pointer-events:none}.ai-debug-toggle{margin-top:5px}.ai-debug-panel{display:${debugMode?'block':'none'};position:fixed;bottom:10px;left:10px;background-color:rgba(0,0,0,0.8);color:white;padding:10px;border-radius:5px;max-height:200px;overflow-y:auto;max-width:500px;z-index:10000;font-size:12px;font-family:monospace}.ai-status-badge{display:inline-block;padding:2px 6px;border-radius:10px;font-size:10px;margin-left:8px;font-weight:normal}.ai-status-online{background-color:#28a745;color:white}.ai-status-error{background-color:#dc3545;color:white}.ai-error-message{color:#dc3545;font-weight:bold;margin-top:4px}.ai-code-container{position:relative;margin:12px 0;border-radius:6px;overflow:hidden;background-color:${isDarkMode?'#1a1a1a':'#f6f8fa'}}.ai-code-header{display:flex;justify-content:space-between;align-items:center;padding:8px 12px;background-color:${isDarkMode?'#2d2d2d':'#e8e8e8'};font-family:monospace;font-size:14px}.ai-copy-button{background:none;border:1px solid ${getColor('border')};color:${getColor('text')};padding:4px 8px;border-radius:4px;cursor:pointer;transition:all 0.2s ease}.ai-copy-button:hover{background-color:${getColor('border')}}.ai-code-block{padding:12px;margin:0;overflow-x:auto;tab-size:4}.ai-inline-code{background-color:${isDarkMode?'#2d2d2d':'#e8e8e8'};padding:2px 4px;border-radius:4px}.ai-markdown-h1{font-size:2em;margin:0.67em 0}.ai-markdown-h2{font-size:1.5em;margin:0.75em 0}.ai-markdown-h3{font-size:1.17em;margin:0.83em 0}.ai-markdown-h4{margin:1.12em 0}.ai-markdown-h5{font-size:0.83em;margin:1.5em 0}.ai-markdown-h6{font-size:0.75em;margin:1.67em 0}` } function createUI() { updateStyles(); const icon = document.createElement('div'); icon.className = 'ai-chat-icon'; icon.innerHTML = ``; let isDragging = false; let startX, startY; let startLeft, startTop; icon.addEventListener('mousedown', function(e) { isDragging = true; icon.style.cursor = 'grabbing'; startX = e.clientX; startY = e.clientY; const rect = icon.getBoundingClientRect(); startLeft = rect.left; startTop = rect.top; e.preventDefault(); e.stopPropagation() }); document.addEventListener('mousemove', function(e) { if (!isDragging) return; const deltaX = e.clientX - startX; const deltaY = e.clientY - startY; let newLeft = startLeft + deltaX; let newTop = startTop + deltaY; const windowWidth = window.innerWidth; const windowHeight = window.innerHeight; const iconWidth = icon.offsetWidth; const iconHeight = icon.offsetHeight; newLeft = Math.max(0, Math.min(windowWidth - iconWidth, newLeft)); newTop = Math.max(0, Math.min(windowHeight - iconHeight, newTop)); const threshold = 20; if (newLeft < threshold) { newLeft = 0 } else if (newLeft > windowWidth - iconWidth - threshold) { newLeft = windowWidth - iconWidth } if (newTop < threshold) { newTop = 0 } else if (newTop > windowHeight - iconHeight - threshold) { newTop = windowHeight - iconHeight } icon.style.left = `${newLeft}px`; icon.style.top = `${newTop}px` }); document.addEventListener('mouseup', function() { if (!isDragging) return; isDragging = false; icon.style.cursor = 'grab'; const rect = icon.getBoundingClientRect(); GM_setValue('iconPosition', { x: rect.left, y: rect.top }) }); const savedPos = GM_getValue('iconPosition'); let initialLeft, initialTop; if (savedPos) { initialLeft = savedPos.x; initialTop = savedPos.y } else { initialLeft = window.innerWidth - 76; initialTop = window.innerHeight - 76 } const windowWidth = window.innerWidth; const windowHeight = window.innerHeight; const iconWidth = 56; const iconHeight = 56; initialLeft = Math.max(0, Math.min(windowWidth - iconWidth, initialLeft)); initialTop = Math.max(0, Math.min(windowHeight - iconHeight, initialTop)); icon.style.left = `${initialLeft}px`; icon.style.top = `${initialTop}px`; document.body.appendChild(icon); const chatWindow = document.createElement('div'); chatWindow.className = 'ai-chat-window'; chatWindow.style.display = 'none'; chatWindow.style.opacity = '0'; chatWindow.style.transform = 'translateY(20px)'; const header = document.createElement('div'); header.className = 'ai-chat-header'; const title = document.createElement('h3'); title.className = 'ai-chat-title'; title.innerHTML = 'AI 助手 V1.0'; const actions = document.createElement('div'); actions.className = 'ai-chat-actions'; const settingsButton = document.createElement('button'); settingsButton.className = 'ai-chat-action ai-settings-button'; settingsButton.innerHTML = '⚙️'; settingsButton.title = '设置'; const themeButton = document.createElement('button'); themeButton.className = 'ai-chat-action ai-theme-button'; themeButton.innerHTML = isDarkMode ? '☀️' : '🌙'; themeButton.title = isDarkMode ? '切换到亮色模式' : '切换到暗色模式'; const minimizeButton = document.createElement('button'); minimizeButton.className = 'ai-chat-action ai-minimize-button'; minimizeButton.innerHTML = '—'; minimizeButton.title = '最小化'; actions.appendChild(settingsButton); actions.appendChild(themeButton); actions.appendChild(minimizeButton); header.appendChild(title); header.appendChild(actions); const content = document.createElement('div'); content.className = 'ai-chat-content'; const inputContainer = document.createElement('div'); inputContainer.className = 'ai-chat-input-container'; const inputWrapper = document.createElement('div'); inputWrapper.className = 'ai-chat-input-wrapper'; const textarea = document.createElement('textarea'); textarea.className = 'ai-chat-input'; textarea.placeholder = '输入消息...'; textarea.rows = 1; const sendButton = document.createElement('button'); sendButton.className = 'ai-chat-send'; sendButton.innerHTML = ``; inputWrapper.appendChild(textarea); inputWrapper.appendChild(sendButton); inputContainer.appendChild(inputWrapper); chatWindow.appendChild(header); chatWindow.appendChild(content); chatWindow.appendChild(inputContainer); const settingsPanel = document.createElement('div'); settingsPanel.className = 'ai-settings-panel'; settingsPanel.innerHTML = `
$1
');
text = text.replace(/\n{2,}/g, '