您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
谷歌AI Studio 自动续写助手 (支持Agent模式)
// ==UserScript== // @name Google AI Studio auto-continue helper // @name:zh-CN Google AI Studio 自动续写助手 // @namespace http://tampermonkey.net/ // @version 5.2 // @description auto-continue helper for Google AI Studio with Agent mode // @description:zh-CN 谷歌AI Studio 自动续写助手 (支持Agent模式) // @author metrovoc // @match https://aistudio.google.com/prompts/* // @grant GM_addStyle // @icon https://www.google.com/s2/favicons?domain=aistudio.google.com // @license MIT // ==/UserScript== (function () { "use strict"; // --- 配置区域 --- const SCROLL_CONTAINER_SELECTOR = "ms-autoscroll-container"; const MESSAGE_TURN_SELECTOR = "ms-chat-turn"; const AUTOSIZE_CONTAINER_SELECTOR = "ms-autosize-textarea"; const TEXTAREA_SELECTOR = "ms-autosize-textarea textarea"; const RUN_BUTTON_SELECTOR = 'run-button button[aria-label="Run"]'; const STOP_BUTTON_SELECTOR = "run-button button.stoppable"; const DEFAULT_CONTINUE_PROMPT = "continue"; // --- 脚本状态变量 --- let isAutoContinueEnabled = false; let isAgentModeEnabled = false; // Agent模式开关 let targetMessageCount = 10; // 目标消息数 let isPanelExpanded = false; let customContinuePrompt = DEFAULT_CONTINUE_PROMPT; let debugPanel = null; let agentProgressPanel = null; // Agent进度显示 let continueButton = null; let toggleButton = null; let customPromptInput = null; let targetCountInput = null; // 目标数量输入框 let agentToggle = null; // Agent模式开关 let uiContainer = null; let scrollTimeout = null; let agentInterval = null; // Agent模式定时器 let countdownInterval = null; // 倒计时进度条定时器 let countdownProgressBar = null; // 倒计时进度条元素 let isAgentSectionExpanded = false; // Agent区域展开状态 let currentScrollContainer = null; let containerWatcher = null; let lastMessageCount = 0; // 上次消息数量 let pendingAgentTrigger = false; // 防止重复触发 // --- 启动逻辑 --- console.log("Gemini 自动续写脚本 v4.2 (Agent Mode) 已启动!"); createAdvancedUI(); startContainerWatcher(); // 调试函数 - 可在控制台手动调用 window.debugAgentBreathing = function () { const agentSection = document.querySelector(".agent-section"); if (agentSection) { agentSection.classList.toggle("breathing"); console.log( "呼吸效果状态:", agentSection.classList.contains("breathing") ); } }; function startContainerWatcher() { // 持续监控容器的存在和变化 containerWatcher = setInterval(() => { const scrollContainer = document.querySelector(SCROLL_CONTAINER_SELECTOR); // 检查容器是否发生变化 if (scrollContainer !== currentScrollContainer) { if (currentScrollContainer) { console.log("检测到容器变化,重新绑定监听器"); // 移除旧的监听器 currentScrollContainer.removeEventListener("scroll", handleScroll); } if (scrollContainer) { console.log("找到新的滚动容器,绑定监听器"); currentScrollContainer = scrollContainer; bindScrollListener(scrollContainer); // 立即更新一次状态 setTimeout(() => updateDebugInfoAndTrigger(scrollContainer), 100); } else { console.log("未找到滚动容器"); currentScrollContainer = null; if (debugPanel) { debugPanel.textContent = "..."; } if (agentProgressPanel) { agentProgressPanel.textContent = "0/0"; } } } // Agent模式独立更新 if (isAgentModeEnabled && scrollContainer) { updateAgentProgress(scrollContainer); } else if (isAgentModeEnabled) { // 即使没有容器也要更新视觉状态 updateAgentVisualState(); } // 每次都检查视觉状态,确保及时清除 updateAgentVisualState(); // 同步UI状态,确保continue button在fetching时被禁用 syncUIState(); }, 500); } function handleScroll() { clearTimeout(scrollTimeout); scrollTimeout = setTimeout(() => { if (currentScrollContainer) { updateDebugInfoAndTrigger(currentScrollContainer); } }, 100); } function bindScrollListener(scrollContainer) { scrollContainer.addEventListener("scroll", handleScroll); } // --- Agent模式相关函数 --- function updateAgentProgress(container) { const validTurns = getValidChatTurns(container); const currentCount = validTurns.length; if (agentProgressPanel) { agentProgressPanel.textContent = `${currentCount}/${targetMessageCount}`; } // 更新Agent UI状态 updateAgentVisualState(); // 检查是否需要触发Agent自动续写 if ( isAgentModeEnabled && currentCount < targetMessageCount && !isCurrentlyFetching() && !pendingAgentTrigger ) { // 检查消息数是否有增加(说明AI已经回复完成) if (currentCount > lastMessageCount || lastMessageCount === 0) { lastMessageCount = currentCount; scheduleAgentContinue(); } } else if (currentCount >= targetMessageCount) { stopAgentMode(); } } function updateAgentVisualState() { const agentSection = document.querySelector(".agent-section"); if (!agentSection) return; // 如果Agent模式未启用,强制清除呼吸效果 if (!isAgentModeEnabled) { agentSection.classList.remove("breathing"); return; } const isGenerating = isCurrentlyFetching(); const isCountingDown = pendingAgentTrigger; console.log( `视觉状态更新: Agent=${isAgentModeEnabled}, 生成中=${isGenerating}, 倒计时=${isCountingDown}` ); // 只在AI正在生成且不在倒计时时显示呼吸效果 if (isGenerating && !isCountingDown) { agentSection.classList.add("breathing"); } else { agentSection.classList.remove("breathing"); } } function scheduleAgentContinue() { // 随机间隔: 2-8秒,防止风控 const randomDelay = Math.random() * 6000 + 2000; // 2000-8000ms console.log( `Agent模式: 将在 ${(randomDelay / 1000).toFixed(1)} 秒后继续生成` ); pendingAgentTrigger = true; updateAgentVisualState(); // 更新视觉状态 startCountdownProgress(randomDelay); agentInterval = setTimeout(() => { if (isAgentModeEnabled && !isCurrentlyFetching()) { console.log("Agent模式: 执行自动续写"); performAutoContinue(); } pendingAgentTrigger = false; updateAgentVisualState(); // 更新视觉状态 hideCountdownProgress(); }, randomDelay); } function startCountdownProgress(totalDelay) { if (!countdownProgressBar) return; countdownProgressBar.style.display = "block"; const startTime = Date.now(); const updateInterval = 50; // 每50ms更新一次 countdownInterval = setInterval(() => { const elapsed = Date.now() - startTime; const progress = Math.min((elapsed / totalDelay) * 100, 100); const progressFill = countdownProgressBar.querySelector(".progress-fill"); if (progressFill) { progressFill.style.width = `${progress}%`; } if (progress >= 100) { clearInterval(countdownInterval); countdownInterval = null; } }, updateInterval); } function hideCountdownProgress() { if (countdownProgressBar) { countdownProgressBar.style.display = "none"; const progressFill = countdownProgressBar.querySelector(".progress-fill"); if (progressFill) { progressFill.style.width = "0%"; } } if (countdownInterval) { clearInterval(countdownInterval); countdownInterval = null; } } function startAgentMode() { console.log(`Agent模式启动: 目标 ${targetMessageCount} 条消息`); isAgentModeEnabled = true; lastMessageCount = 0; pendingAgentTrigger = false; updateAgentProgressVisibility(); // 立即检查一次状态 if (currentScrollContainer) { updateAgentProgress(currentScrollContainer); } } function stopAgentMode() { console.log("Agent模式已停止"); isAgentModeEnabled = false; pendingAgentTrigger = false; lastMessageCount = 0; if (agentInterval) { clearTimeout(agentInterval); agentInterval = null; } hideCountdownProgress(); updateAgentProgressVisibility(); // 强制清除呼吸效果 const agentSection = document.querySelector(".agent-section"); if (agentSection) { agentSection.classList.remove("breathing"); } updateAgentVisualState(); if (agentToggle) { agentToggle.checked = false; } } function updateAgentProgressVisibility() { if (agentProgressPanel) { const agentStatusSection = agentProgressPanel.closest(".panel-section"); if (agentStatusSection) { agentStatusSection.style.display = isAgentModeEnabled ? "flex" : "none"; } } } // 页面卸载时清理 window.addEventListener("beforeunload", () => { stopAgentMode(); if (containerWatcher) { clearInterval(containerWatcher); } if (countdownInterval) { clearInterval(countdownInterval); } }); // --- 核心功能函数 --- function isCurrentlyFetching() { return !!document.querySelector(STOP_BUTTON_SELECTOR); } function syncUIState() { if (continueButton) { continueButton.disabled = isCurrentlyFetching(); } } function performAutoContinue() { if (isCurrentlyFetching()) { console.log("正在等待AI响应,续写操作已跳过。"); return; } const autosizeContainer = document.querySelector( AUTOSIZE_CONTAINER_SELECTOR ); const textarea = document.querySelector(TEXTAREA_SELECTOR); const runButton = document.querySelector(RUN_BUTTON_SELECTOR); if (autosizeContainer && textarea && runButton) { console.log(`尝试执行续写,发送: "${customContinuePrompt}"`); autosizeContainer.setAttribute("data-value", customContinuePrompt); textarea.value = customContinuePrompt; textarea.dispatchEvent( new Event("input", { bubbles: true, composed: true }) ); // Generate random delay between 50ms and 250ms to simulate human behavior const humanDelay = Math.random() * 200 + 50; // 50-250ms console.log( `Human-like delay: ${humanDelay.toFixed( 0 )}ms before clicking run button` ); setTimeout(() => { // Re-check conditions before clicking to avoid conflicts during delay if (isCurrentlyFetching()) { console.log( "AI started responding during delay, skipping button click" ); return; } const finalRunButton = document.querySelector(RUN_BUTTON_SELECTOR); if (finalRunButton && !finalRunButton.disabled) { finalRunButton.click(); console.log("消息已发送!"); // 立即同步UI状态,禁用continue button setTimeout(() => syncUIState(), 100); } else { console.error("发送失败:按钮在填充输入后仍然被禁用。"); } }, humanDelay); } else { console.warn("无法执行续写:缺少必要的UI组件。"); } } // 过滤有效的聊天轮次:包含model-prompt-container且不含ms-thought-chunk的ms-chat-turn function getValidChatTurns(container) { const allTurns = container.querySelectorAll(MESSAGE_TURN_SELECTOR); const validTurns = []; console.log(`[getValidChatTurns] 总聊天轮次: ${allTurns.length}`); allTurns.forEach((turn, index) => { // 检查是否包含 model-prompt-container const hasModelPromptContainer = turn.querySelector( ".model-prompt-container" ); if (!hasModelPromptContainer) { console.log( `[getValidChatTurns] 轮次 ${ index + 1 }: 跳过 - 无 model-prompt-container` ); return; } // 检查是否不包含 ms-thought-chunk (自定义元素,不用点号) const hasThoughtChunk = turn.querySelector("ms-thought-chunk"); if (hasThoughtChunk) { console.log( `[getValidChatTurns] 轮次 ${index + 1}: 跳过 - 包含 ms-thought-chunk` ); return; } console.log(`[getValidChatTurns] 轮次 ${index + 1}: ✓ 有效`); validTurns.push(turn); }); console.log( `[getValidChatTurns] 有效聊天轮次: ${validTurns.length}/${allTurns.length}` ); return validTurns; } function updateDebugInfoAndTrigger(container) { if (!debugPanel || !container) return; const validTurns = getValidChatTurns(container); const total = validTurns.length; if (total === 0) { debugPanel.textContent = "0/0"; return; } let currentIndex = -1; const viewportTopThreshold = container.getBoundingClientRect().top + 60; for (let i = 0; i < validTurns.length; i++) { const rect = validTurns[i].getBoundingClientRect(); if (rect.top >= viewportTopThreshold) { currentIndex = i; break; } } // 计算显示位置: // currentIndex = -1 表示所有validturn都已滚动过,显示最后一个 // currentIndex = 0 表示还没开始看第一个validturn,显示0 // currentIndex = i 表示正在看第i个validturn,显示i let displayPosition; if (currentIndex === -1) { displayPosition = total; // 所有都看过了 } else if (currentIndex === 0) { displayPosition = 0; // 还没开始看第一个 } else { displayPosition = currentIndex; // 正在看第currentIndex个(从0开始) } debugPanel.textContent = `${displayPosition}/${total}`; // 只有在非Agent模式下才使用滚动逻辑触发 if (!isAgentModeEnabled) { const shouldTrigger = isAutoContinueEnabled && total > 1 && displayPosition >= total - 1; if (shouldTrigger && !isCurrentlyFetching()) { console.log(`自动续写条件满足:位置 ${displayPosition}/${total}`); performAutoContinue(); } } } // --- SVG图标创建函数 --- function createSVGIcon(pathData, viewBox = "0 0 24 24") { const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); svg.setAttribute("width", "20"); svg.setAttribute("height", "20"); svg.setAttribute("viewBox", viewBox); svg.setAttribute("fill", "currentColor"); const path = document.createElementNS("http://www.w3.org/2000/svg", "path"); path.setAttribute("d", pathData); svg.appendChild(path); return svg; } function createExpandIcon() { return createSVGIcon("M7 14l5-5 5 5z"); } function createCollapseIcon() { return createSVGIcon("M7 10l5 5 5-5z"); } function createSettingsIcon() { return createSVGIcon( "M12 15.5A3.5 3.5 0 0 1 8.5 12A3.5 3.5 0 0 1 12 8.5a3.5 3.5 0 0 1 3.5 3.5 3.5 3.5 0 0 1-3.5 3.5m7.43-2.53c.04-.32.07-.64.07-.97 0-.33-.03-.66-.07-1l2.11-1.63c.19-.15.24-.42.12-.64l-2-3.46c-.12-.22-.39-.31-.61-.22l-2.49 1c-.52-.39-1.06-.73-1.69-.98l-.37-2.65A.506.506 0 0 0 14 2h-4c-.25 0-.46.18-.5.42l-.37 2.65c-.63.25-1.17.59-1.69.98l-2.49-1c-.22-.09-.49 0-.61.22l-2 3.46c-.13.22-.07.49.12.64L4.57 11c-.04.34-.07.67-.07 1 0 .33.03.65.07.97l-2.11 1.66c-.19.15-.25.42-.12.64l2 3.46c.12.22.39.3.61.22l2.49-1.01c.52.4 1.06.74 1.69.99l.37 2.65c.04.24.25.42.5.42h4c.25 0 .46-.18.5-.42l.37-2.65c.63-.26 1.17-.59 1.69-.99l2.49 1.01c.22.08.49 0 .61-.22l2-3.46c.12-.22.07-.49-.12-.64l-2.11-1.66Z" ); } function togglePanel() { isPanelExpanded = !isPanelExpanded; updatePanelState(); } function updatePanelState() { const panel = document.getElementById("tampermonkey-panel"); const toggleBtnIcon = document.getElementById("tampermonkey-toggle-icon"); if (isPanelExpanded) { panel.style.display = "flex"; // 清空并重新添加icon toggleBtnIcon.textContent = ""; toggleBtnIcon.appendChild(createCollapseIcon()); uiContainer.classList.add("expanded"); } else { panel.style.display = "none"; // 清空并重新添加icon toggleBtnIcon.textContent = ""; toggleBtnIcon.appendChild(createSettingsIcon()); uiContainer.classList.remove("expanded"); } } function toggleAgentSection() { isAgentSectionExpanded = !isAgentSectionExpanded; const agentDetails = document.querySelector(".agent-details"); const expandArrow = document.querySelector(".expand-arrow"); if (agentDetails && expandArrow) { if (isAgentSectionExpanded) { agentDetails.style.display = "block"; expandArrow.textContent = "▼"; expandArrow.classList.add("expanded"); } else { agentDetails.style.display = "none"; expandArrow.textContent = "▶"; expandArrow.classList.remove("expanded"); } } } // --- 高级UI创建 --- function createAdvancedUI() { // 主容器 uiContainer = document.createElement("div"); uiContainer.id = "tampermonkey-ui-container"; uiContainer.className = "collapsed"; document.body.appendChild(uiContainer); // 切换按钮(始终可见) toggleButton = document.createElement("button"); toggleButton.id = "tampermonkey-toggle-btn"; toggleButton.className = "toggle-button"; toggleButton.setAttribute("title", "Toggle Gemini Assistant Panel"); const toggleIcon = document.createElement("span"); toggleIcon.id = "tampermonkey-toggle-icon"; toggleIcon.appendChild(createSettingsIcon()); toggleButton.appendChild(toggleIcon); toggleButton.addEventListener("click", togglePanel); uiContainer.appendChild(toggleButton); // 主面板容器(可折叠) const panel = document.createElement("div"); panel.id = "tampermonkey-panel"; panel.className = "main-panel"; panel.style.display = "none"; uiContainer.appendChild(panel); // 状态显示区域 const statusSection = document.createElement("div"); statusSection.className = "panel-section"; const statusLabel = document.createElement("span"); statusLabel.className = "section-label"; statusLabel.textContent = "Scroll Position:"; debugPanel = document.createElement("div"); debugPanel.id = "tampermonkey-debug-panel"; debugPanel.className = "status-display"; debugPanel.textContent = "..."; statusSection.appendChild(statusLabel); statusSection.appendChild(debugPanel); panel.appendChild(statusSection); // Agent模式状态区域(初始隐藏) const agentStatusSection = document.createElement("div"); agentStatusSection.className = "panel-section"; agentStatusSection.style.display = "none"; const agentStatusLabel = document.createElement("span"); agentStatusLabel.className = "section-label"; agentStatusLabel.textContent = "Agent Progress:"; agentProgressPanel = document.createElement("div"); agentProgressPanel.id = "tampermonkey-agent-panel"; agentProgressPanel.className = "status-display agent-status"; agentProgressPanel.textContent = "0/0"; agentStatusSection.appendChild(agentStatusLabel); agentStatusSection.appendChild(agentProgressPanel); panel.appendChild(agentStatusSection); // 控制按钮区域 const controlSection = document.createElement("div"); controlSection.className = "panel-section compact"; // 手动继续按钮行 const continueRow = document.createElement("div"); continueRow.className = "control-row"; continueButton = document.createElement("button"); continueButton.id = "tampermonkey-continue-btn"; continueButton.className = "control-button primary compact"; continueButton.textContent = "Continue"; continueButton.addEventListener("click", () => { console.log("手动触发续写..."); performAutoContinue(); // 更新Agent视觉状态,因为可能开始了新的生成 setTimeout(() => { updateAgentVisualState(); syncUIState(); }, 100); }); continueRow.appendChild(continueButton); // 自动续写开关行 const autoRow = document.createElement("div"); autoRow.className = "control-row"; const autoLabel = document.createElement("label"); autoLabel.className = "control-label"; autoLabel.textContent = "Auto continue:"; const autoSwitchContainer = document.createElement("div"); autoSwitchContainer.className = "switch-container"; const autoSwitchLabel = document.createElement("label"); autoSwitchLabel.className = "switch-label small"; autoSwitchLabel.setAttribute("title", "Auto-Continue Toggle"); const autoContinueToggle = document.createElement("input"); autoContinueToggle.type = "checkbox"; autoContinueToggle.checked = isAutoContinueEnabled; autoContinueToggle.addEventListener("change", (e) => { isAutoContinueEnabled = e.target.checked; // 开启普通自动续写时,关闭Agent模式 if (isAutoContinueEnabled && isAgentModeEnabled) { stopAgentMode(); } console.log(`自动续写已 ${isAutoContinueEnabled ? "开启" : "关闭"}`); }); const switchSlider = document.createElement("span"); switchSlider.className = "switch-slider"; autoSwitchLabel.appendChild(autoContinueToggle); autoSwitchLabel.appendChild(switchSlider); autoSwitchContainer.appendChild(autoSwitchLabel); autoRow.appendChild(autoLabel); autoRow.appendChild(autoSwitchContainer); controlSection.appendChild(continueRow); controlSection.appendChild(autoRow); panel.appendChild(controlSection); // Agent模式控制区域 const agentSection = document.createElement("div"); agentSection.className = "panel-section agent-section"; // Agent模式主标题和展开箭头 const agentMainHeader = document.createElement("div"); agentMainHeader.className = "agent-main-header"; agentMainHeader.addEventListener("click", toggleAgentSection); const agentMainTitle = document.createElement("span"); agentMainTitle.className = "section-label clickable"; agentMainTitle.textContent = "Agent Mode"; const expandArrow = document.createElement("span"); expandArrow.className = "expand-arrow"; expandArrow.textContent = "▶"; agentMainHeader.appendChild(agentMainTitle); agentMainHeader.appendChild(expandArrow); // Agent详细控制区域(可折叠) const agentDetailsSection = document.createElement("div"); agentDetailsSection.className = "agent-details"; agentDetailsSection.style.display = "none"; // Agent模式开关行 const agentToggleRow = document.createElement("div"); agentToggleRow.className = "agent-control-row"; const agentToggleLabel = document.createElement("label"); agentToggleLabel.className = "control-label"; agentToggleLabel.textContent = "Enable:"; const agentSwitchContainer = document.createElement("div"); agentSwitchContainer.className = "switch-container"; const agentSwitchLabel = document.createElement("label"); agentSwitchLabel.className = "switch-label small"; agentSwitchLabel.setAttribute("title", "Agent Mode Toggle"); agentToggle = document.createElement("input"); agentToggle.type = "checkbox"; agentToggle.checked = isAgentModeEnabled; agentToggle.addEventListener("change", (e) => { if (e.target.checked) { // 开启Agent模式时,关闭普通自动续写 if (isAutoContinueEnabled) { isAutoContinueEnabled = false; const normalToggle = document.querySelector( '#tampermonkey-panel input[type="checkbox"]' ); if (normalToggle && normalToggle !== agentToggle) { normalToggle.checked = false; } } startAgentMode(); } else { stopAgentMode(); } }); const agentSwitchSlider = document.createElement("span"); agentSwitchSlider.className = "switch-slider"; agentSwitchLabel.appendChild(agentToggle); agentSwitchLabel.appendChild(agentSwitchSlider); agentSwitchContainer.appendChild(agentSwitchLabel); agentToggleRow.appendChild(agentToggleLabel); agentToggleRow.appendChild(agentSwitchContainer); // 目标数量输入行 const targetRow = document.createElement("div"); targetRow.className = "agent-control-row"; const targetLabel = document.createElement("label"); targetLabel.className = "control-label"; targetLabel.setAttribute("for", "tampermonkey-target-input"); targetLabel.textContent = "Target:"; targetCountInput = document.createElement("input"); targetCountInput.id = "tampermonkey-target-input"; targetCountInput.type = "number"; targetCountInput.className = "number-input compact"; targetCountInput.value = targetMessageCount; targetCountInput.min = "1"; targetCountInput.max = "999"; targetCountInput.placeholder = "10"; targetCountInput.addEventListener("input", (e) => { const value = parseInt(e.target.value); if (value && value > 0) { targetMessageCount = value; console.log(`目标消息数已更新: ${targetMessageCount}`); } }); targetRow.appendChild(targetLabel); targetRow.appendChild(targetCountInput); // 倒计时进度条 countdownProgressBar = document.createElement("div"); countdownProgressBar.className = "countdown-progress"; countdownProgressBar.style.display = "none"; const progressLabel = document.createElement("div"); progressLabel.className = "progress-label"; progressLabel.textContent = "Next generation in:"; const progressBarContainer = document.createElement("div"); progressBarContainer.className = "progress-bar-container"; const progressFill = document.createElement("div"); progressFill.className = "progress-fill"; progressBarContainer.appendChild(progressFill); countdownProgressBar.appendChild(progressLabel); countdownProgressBar.appendChild(progressBarContainer); agentDetailsSection.appendChild(agentToggleRow); agentDetailsSection.appendChild(targetRow); agentDetailsSection.appendChild(countdownProgressBar); agentSection.appendChild(agentMainHeader); agentSection.appendChild(agentDetailsSection); panel.appendChild(agentSection); // 自定义提示词区域 const promptSection = document.createElement("div"); promptSection.className = "panel-section"; const promptLabel = document.createElement("label"); promptLabel.className = "section-label"; promptLabel.setAttribute("for", "tampermonkey-prompt-input"); promptLabel.textContent = "Custom Prompt:"; customPromptInput = document.createElement("input"); customPromptInput.id = "tampermonkey-prompt-input"; customPromptInput.type = "text"; customPromptInput.className = "prompt-input"; customPromptInput.value = customContinuePrompt; customPromptInput.placeholder = "Enter custom continue prompt..."; customPromptInput.addEventListener("input", (e) => { customContinuePrompt = e.target.value.trim() || DEFAULT_CONTINUE_PROMPT; console.log(`自定义提示词已更新: "${customContinuePrompt}"`); }); promptSection.appendChild(promptLabel); promptSection.appendChild(customPromptInput); panel.appendChild(promptSection); // 添加样式 GM_addStyle(` #tampermonkey-ui-container { position: fixed; bottom: 20px; right: 20px; z-index: 9999; display: flex; flex-direction: column; align-items: flex-end; gap: 12px; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; } .toggle-button { width: 48px; height: 48px; border: none; border-radius: 50%; background: linear-gradient(135deg, #1a73e8, #185abc); color: white; cursor: pointer; display: flex; align-items: center; justify-content: center; box-shadow: 0 4px 12px rgba(26, 115, 232, 0.3); transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); backdrop-filter: blur(10px); } .toggle-button:hover { transform: translateY(-2px); box-shadow: 0 6px 20px rgba(26, 115, 232, 0.4); background: linear-gradient(135deg, #185abc, #1557a0); } .toggle-button:active { transform: translateY(0); } #tampermonkey-toggle-icon { display: flex; align-items: center; justify-content: center; transition: transform 0.3s ease; } .expanded #tampermonkey-toggle-icon { transform: rotate(180deg); } .main-panel { background: rgba(255, 255, 255, 0.95); backdrop-filter: blur(20px); border-radius: 16px; padding: 16px; min-width: 280px; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1); border: 1px solid rgba(255, 255, 255, 0.2); display: none; flex-direction: column; gap: 12px; animation: slideIn 0.3s cubic-bezier(0.4, 0, 0.2, 1); } @keyframes slideIn { from { opacity: 0; transform: translateY(20px) scale(0.95); } to { opacity: 1; transform: translateY(0) scale(1); } } .panel-section { display: flex; flex-direction: column; gap: 8px; } .panel-section.compact { gap: 6px; } .control-row { display: flex; justify-content: space-between; align-items: center; min-height: 32px; } .section-label { font-size: 12px; font-weight: 600; color: #5f6368; text-transform: uppercase; letter-spacing: 0.5px; } .status-display { background: rgba(26, 115, 232, 0.1); color: #1a73e8; padding: 8px 12px; border-radius: 8px; font-family: 'SF Mono', 'Monaco', 'Cascadia Code', monospace; font-size: 14px; font-weight: 600; text-align: center; border: 1px solid rgba(26, 115, 232, 0.2); } .agent-status { background: rgba(34, 139, 34, 0.1); color: #228b22; border: 1px solid rgba(34, 139, 34, 0.2); } .control-button { background: linear-gradient(135deg, #1a73e8, #185abc); color: white; border: none; padding: 12px 20px; border-radius: 10px; font-size: 14px; font-weight: 600; cursor: pointer; transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); box-shadow: 0 2px 8px rgba(26, 115, 232, 0.3); } .control-button:hover { transform: translateY(-1px); box-shadow: 0 4px 12px rgba(26, 115, 232, 0.4); } .control-button:disabled { background: #e0e0e0; color: #9e9e9e; cursor: not-allowed; transform: none; box-shadow: none; } .control-button.compact { padding: 8px 16px; font-size: 13px; width: 100%; } .switch-label { position: relative; display: inline-block; width: 52px; height: 28px; cursor: pointer; align-self: flex-start; } .switch-label input { opacity: 0; width: 0; height: 0; } .switch-slider { position: absolute; top: 0; left: 0; right: 0; bottom: 0; background-color: #ccc; border-radius: 28px; transition: 0.4s cubic-bezier(0.4, 0, 0.2, 1); } .switch-slider:before { position: absolute; content: ""; height: 20px; width: 20px; left: 4px; bottom: 4px; background-color: white; border-radius: 50%; transition: 0.4s cubic-bezier(0.4, 0, 0.2, 1); box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); } .switch-label input:checked + .switch-slider { background: linear-gradient(135deg, #1a73e8, #185abc); } .switch-label input:checked + .switch-slider:before { transform: translateX(24px); } .switch-label.small { width: 40px; height: 22px; } .switch-label.small .switch-slider { border-radius: 22px; } .switch-label.small .switch-slider:before { height: 16px; width: 16px; left: 3px; bottom: 3px; } .switch-label.small input:checked + .switch-slider:before { transform: translateX(18px); } .prompt-input { width: 100%; padding: 12px 16px; border: 2px solid #e0e0e0; border-radius: 10px; font-size: 14px; font-family: inherit; transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); background: rgba(255, 255, 255, 0.8); box-sizing: border-box; } .prompt-input:focus { outline: none; border-color: #1a73e8; box-shadow: 0 0 0 3px rgba(26, 115, 232, 0.1); background: white; } .prompt-input::placeholder { color: #9e9e9e; font-style: italic; } .agent-section { border-top: 1px solid #e0e0e0; background: rgba(34, 139, 34, 0.03); border-radius: 10px; padding: 10px; margin-top: 4px; transition: all 0.3s ease; position: relative; overflow: hidden; } .agent-section.breathing { animation: agentBreathing 2.2s ease-in-out infinite; } .agent-section.breathing::before { content: ''; position: absolute; top: 2px; left: 2px; right: 2px; bottom: 2px; background: radial-gradient(circle at center, rgba(34, 139, 34, 0.4) 0%, rgba(34, 139, 34, 0.2) 40%, transparent 70%); border-radius: inherit; transform: scale(0); animation: rippleBreathing 2.2s ease-in-out infinite; pointer-events: none; z-index: 1; } .agent-section.breathing::after { content: ''; position: absolute; top: 4px; left: 4px; right: 4px; bottom: 4px; background: radial-gradient(circle at center, rgba(34, 139, 34, 0.5) 0%, rgba(34, 139, 34, 0.3) 30%, transparent 60%); border-radius: inherit; transform: scale(0); animation: rippleBreathing 2.2s ease-in-out infinite 0.6s; pointer-events: none; z-index: 1; } .agent-section.breathing > * { position: relative; z-index: 2; } @keyframes agentBreathing { 0%, 100% { background: rgba(34, 139, 34, 0.03); box-shadow: 0 0 0 0 rgba(34, 139, 34, 0.1), 0 0 15px 0 rgba(34, 139, 34, 0.05); border-color: #e0e0e0; transform: scale(1); } 50% { background: rgba(34, 139, 34, 0.12); box-shadow: 0 0 0 4px rgba(34, 139, 34, 0.2), 0 0 25px 5px rgba(34, 139, 34, 0.15); border-color: rgba(34, 139, 34, 0.4); transform: scale(1.02); } } @keyframes rippleBreathing { 0%, 100% { transform: scale(0); opacity: 0; } 15% { transform: scale(0.5); opacity: 0.8; } 35% { transform: scale(1.2); opacity: 0.7; } 60% { transform: scale(1.8); opacity: 0.4; } 85% { transform: scale(2.2); opacity: 0.1; } 100% { transform: scale(2.5); opacity: 0; } } .agent-main-header { display: flex; justify-content: space-between; align-items: center; cursor: pointer; padding: 4px 0; transition: all 0.2s ease; } .agent-main-header:hover { background: rgba(34, 139, 34, 0.1); border-radius: 6px; padding: 4px 8px; } .section-label.clickable { user-select: none; transition: color 0.2s ease; } .expand-arrow { font-size: 12px; transition: transform 0.3s ease; color: #228b22; font-weight: bold; } .expand-arrow.expanded { transform: rotate(0deg); } .agent-details { margin-top: 8px; padding-top: 8px; border-top: 1px solid rgba(34, 139, 34, 0.2); display: none; } .agent-control-row { display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px; min-height: 28px; } .control-label { font-size: 12px; font-weight: 600; color: #5f6368; min-width: 60px; } .switch-container { display: flex; align-items: center; } .input-label { font-size: 12px; font-weight: 600; color: #5f6368; text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 4px; display: block; } .number-input { width: 100%; padding: 10px 14px; border: 2px solid #e0e0e0; border-radius: 8px; font-size: 14px; font-family: inherit; transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); background: rgba(255, 255, 255, 0.8); box-sizing: border-box; text-align: center; font-weight: 600; } .number-input:focus { outline: none; border-color: #228b22; box-shadow: 0 0 0 3px rgba(34, 139, 34, 0.1); background: white; } .number-input.compact { width: 80px; padding: 8px 12px; font-size: 13px; } .countdown-progress { background: rgba(34, 139, 34, 0.1); border-radius: 8px; padding: 8px; margin: 6px 0; border: 1px solid rgba(34, 139, 34, 0.2); } .progress-label { font-size: 11px; color: #228b22; font-weight: 600; margin-bottom: 6px; text-transform: uppercase; letter-spacing: 0.5px; } .progress-bar-container { width: 100%; height: 4px; background: rgba(34, 139, 34, 0.2); border-radius: 2px; overflow: hidden; } .progress-fill { height: 100%; background: linear-gradient(90deg, #228b22, #32cd32); border-radius: 2px; width: 0%; transition: width 0.1s ease-out; } /* Dark mode support */ @media (prefers-color-scheme: dark) { .main-panel { background: rgba(32, 33, 36, 0.95); border: 1px solid rgba(255, 255, 255, 0.1); } .section-label { color: #bdc1c6; } .prompt-input { background: rgba(32, 33, 36, 0.8); border-color: #5f6368; color: #e8eaed; } .prompt-input:focus { background: #32333; border-color: #1a73e8; } .agent-section { background: rgba(34, 139, 34, 0.08); border-top: 1px solid #5f6368; } .agent-section.breathing::before { background: radial-gradient(circle at center, rgba(74, 222, 128, 0.4) 0%, rgba(34, 139, 34, 0.2) 40%, transparent 70%); } .agent-section.breathing::after { background: radial-gradient(circle at center, rgba(74, 222, 128, 0.5) 0%, rgba(34, 139, 34, 0.3) 30%, transparent 60%); } @keyframes agentBreathing { 0%, 100% { background: rgba(34, 139, 34, 0.08); box-shadow: 0 0 0 0 rgba(34, 139, 34, 0.15), 0 0 20px 0 rgba(34, 139, 34, 0.1); border-color: #5f6368; transform: scale(1); } 50% { background: rgba(34, 139, 34, 0.20); box-shadow: 0 0 0 4px rgba(34, 139, 34, 0.35), 0 0 30px 8px rgba(34, 139, 34, 0.25); border-color: rgba(74, 222, 128, 0.5); transform: scale(1.02); } } .agent-main-header:hover { background: rgba(34, 139, 34, 0.15); } .agent-details { border-top: 1px solid rgba(34, 139, 34, 0.3); } .input-label, .control-label { color: #bdc1c6; } .number-input { background: rgba(32, 33, 36, 0.8); border-color: #5f6368; color: #e8eaed; } .number-input:focus { background: #323336; border-color: #228b22; } .countdown-progress { background: rgba(34, 139, 34, 0.15); border-color: rgba(34, 139, 34, 0.3); } .progress-label { color: #4ade80; } .progress-bar-container { background: rgba(34, 139, 34, 0.3); } } `); // 初始化面板状态 updatePanelState(); } })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址