油猴脚本:便于Google AI Studio移动端用户的快捷操作栏

2026-04-29 08:412阅读0评论SEO资源
  • 内容介绍
  • 文章标签
  • 相关推荐
问题描述:

4月20日开始Google one(Gemini Pro套餐)在Google AI Studio有更多额度了,在此分享一个本人自制移动端用户专用的油猴脚本。
经常在移动端用Google AI Studio的佬友应该都懂,填充个提示词需要点好几个地方,开启新对话按钮太靠上点击费力,还有不打开侧边栏看不见当前所选的模型,这个脚本就是解决这个问题的,我在输入框上方集成了这些功能的按钮,具体效果如图所示。

Screenshot2026-04-21-20-03-55-472com.xbrowser.play1220×2712 242 KB

// ==UserScript== // @name Google AI Studio 移动端快捷操作栏 // @namespace https://tampermonkey.net/ // @version 5.6 // @description “NEW”按钮用于开启新对话窗口,“ON”按钮用于打开填充System instructions面板,“OFF”按钮用于关闭System instructions面板;按钮上方横列显示当前模型名称。 // @match https://aistudio.google.com/* // @run-at document-idle // @grant none // ==/UserScript== (function () { 'use strict'; const SCAN_INTERVAL = 500; const GAP_TO_INPUT = 20; const wrap = document.createElement('div'); wrap.id = 'aiStudioCustomBtnGroup'; const css = document.createElement('style'); css.textContent = ` #aiStudioCustomBtnGroup { position: fixed; display: flex; flex-direction: column; align-items: center; gap: 5px; z-index: 2147483647; pointer-events: none; transform: translate(-50%, -100%); transition: opacity 0.2s ease; opacity: 0; padding-bottom: 2px; } #custom-model-name { font-family: -apple-system, BlinkMacSystemFont, 'Inter', 'Segoe UI', sans-serif; font-size: 10.5px; font-weight: 600; letter-spacing: 0.04em; color: rgba(50, 42, 36, 0.88); white-space: nowrap; pointer-events: none; user-select: none; padding: 3px 10px; background: rgba(255, 248, 242, 0.82); border-radius: 20px; border: 0.5px solid rgba(180, 140, 110, 0.25); margin-bottom: 1px; } .custom-btn-row { display: flex; gap: 6px; pointer-events: none; align-items: center; justify-content: center; } .custom-circle-btn { display: flex; align-items: center; justify-content: center; width: 34px; height: 34px; border-radius: 50%; color: #fff; font-weight: 700; font-size: 11px; letter-spacing: 0.04em; font-family: -apple-system, BlinkMacSystemFont, 'Inter', 'Segoe UI', sans-serif; border: none; pointer-events: auto; cursor: pointer; user-select: none; transition: transform 0.12s ease, filter 0.12s ease; padding: 0; margin: 0; -webkit-font-smoothing: antialiased; background: #CC785C; box-shadow: 0 1px 6px rgba(180, 90, 60, 0.4); } .custom-circle-btn:hover { transform: scale(1.07); filter: brightness(1.1); } .custom-circle-btn:active { transform: scale(0.92); filter: brightness(0.88); } `; document.head.appendChild(css); const modelLabel = document.createElement('div'); modelLabel.id = 'custom-model-name'; modelLabel.textContent = '—'; const makeBtn = (id, txt) => { const el = document.createElement('button'); el.id = id; el.className = 'custom-circle-btn'; el.textContent = txt; return el; }; const btnNew = makeBtn('custom-btn-new', 'NEW'); const btnOn = makeBtn('custom-btn-on', 'ON'); const btnOff = makeBtn('custom-btn-off', 'OFF'); const rowNew = document.createElement('div'); rowNew.className = 'custom-btn-row'; rowNew.appendChild(btnNew); const rowOnOff = document.createElement('div'); rowOnOff.className = 'custom-btn-row'; rowOnOff.append(btnOn, btnOff); wrap.append(modelLabel, rowNew, rowOnOff); document.body.appendChild(wrap); const updatePosition = () => { let targetInput = null; const selectors = ['[placeholder*="Start typing a prompt"]', '[placeholder*="Optional tone"]']; for (const sel of selectors) { const el = document.querySelector(sel); if (el && el.getBoundingClientRect().width > 0) { targetInput = el; break; } } if (targetInput) { const rect = targetInput.getBoundingClientRect(); if (rect.top > 0) { wrap.style.opacity = '1'; wrap.style.left = `${window.innerWidth / 2}px`; wrap.style.top = `${rect.top - GAP_TO_INPUT}px`; } else { wrap.style.opacity = '0'; } } else { wrap.style.opacity = '0'; } requestAnimationFrame(updatePosition); }; const attachToTopLayer = () => { try { const vw = window.innerWidth; const vh = window.innerHeight; let bestEl = document.body; let bestZ = -Infinity; const all = document.body.querySelectorAll('*'); for (let i = 0; i < all.length; i++) { const el = all[i]; if (el === wrap) continue; const rect = el.getBoundingClientRect(); if (rect.width >= vw * 0.9 && rect.height >= vh * 0.9 && rect.left <= vw * 0.1 && rect.top <= vh * 0.1) { const style = getComputedStyle(el); if ((style.position === 'fixed' || style.position === 'absolute') && style.visibility !== 'hidden' && style.display !== 'none') { let zi = parseInt(style.zIndex, 10); if (Number.isNaN(zi)) zi = 0; if (zi >= bestZ) { bestZ = zi; bestEl = el; } } } } if (!bestEl.contains(wrap) || bestEl.lastElementChild !== wrap) { bestEl.appendChild(wrap); } } catch (e) {} }; const readModel = () => { try { const raw = localStorage.getItem('aiStudioUserPreference'); if (!raw) return '—'; const pm = JSON.parse(raw)?.promptModel; return pm ? pm.replace('models/', '') : '—'; } catch (e) { return '—'; } }; let lastModel = ''; const tickModel = () => { const now = readModel(); if (now !== lastModel) { modelLabel.textContent = now; lastModel = now; } }; requestAnimationFrame(updatePosition); setInterval(attachToTopLayer, SCAN_INTERVAL); tickModel(); setInterval(tickModel, 1000); btnNew.addEventListener('click', () => { document.querySelector('a[href*="prompts/new_chat"]')?.click(); setTimeout(() => { document.querySelector("button[data-test-category-id='17']")?.click(); }, 50); }); btnOn.addEventListener('click', () => { const sysBtn = document.querySelector("button[aria-label='System instructions']"); if (sysBtn) { sysBtn.click(); } else { document.querySelector("button[aria-label='Toggle run settings panel']")?.click(); setTimeout(() => { document.querySelector("button[aria-label='System instructions']")?.click(); }, 300); } }); btnOff.addEventListener('click', () => { document.querySelector("button[aria-label='关闭面板'], button[aria-label='Close panel'], button[aria-label='Close']")?.click(); }); })(); 网友解答:


--【壹】--:

佬的移动端用的是啥软件能支持油猴脚本的?

问题描述:

4月20日开始Google one(Gemini Pro套餐)在Google AI Studio有更多额度了,在此分享一个本人自制移动端用户专用的油猴脚本。
经常在移动端用Google AI Studio的佬友应该都懂,填充个提示词需要点好几个地方,开启新对话按钮太靠上点击费力,还有不打开侧边栏看不见当前所选的模型,这个脚本就是解决这个问题的,我在输入框上方集成了这些功能的按钮,具体效果如图所示。

Screenshot2026-04-21-20-03-55-472com.xbrowser.play1220×2712 242 KB

// ==UserScript== // @name Google AI Studio 移动端快捷操作栏 // @namespace https://tampermonkey.net/ // @version 5.6 // @description “NEW”按钮用于开启新对话窗口,“ON”按钮用于打开填充System instructions面板,“OFF”按钮用于关闭System instructions面板;按钮上方横列显示当前模型名称。 // @match https://aistudio.google.com/* // @run-at document-idle // @grant none // ==/UserScript== (function () { 'use strict'; const SCAN_INTERVAL = 500; const GAP_TO_INPUT = 20; const wrap = document.createElement('div'); wrap.id = 'aiStudioCustomBtnGroup'; const css = document.createElement('style'); css.textContent = ` #aiStudioCustomBtnGroup { position: fixed; display: flex; flex-direction: column; align-items: center; gap: 5px; z-index: 2147483647; pointer-events: none; transform: translate(-50%, -100%); transition: opacity 0.2s ease; opacity: 0; padding-bottom: 2px; } #custom-model-name { font-family: -apple-system, BlinkMacSystemFont, 'Inter', 'Segoe UI', sans-serif; font-size: 10.5px; font-weight: 600; letter-spacing: 0.04em; color: rgba(50, 42, 36, 0.88); white-space: nowrap; pointer-events: none; user-select: none; padding: 3px 10px; background: rgba(255, 248, 242, 0.82); border-radius: 20px; border: 0.5px solid rgba(180, 140, 110, 0.25); margin-bottom: 1px; } .custom-btn-row { display: flex; gap: 6px; pointer-events: none; align-items: center; justify-content: center; } .custom-circle-btn { display: flex; align-items: center; justify-content: center; width: 34px; height: 34px; border-radius: 50%; color: #fff; font-weight: 700; font-size: 11px; letter-spacing: 0.04em; font-family: -apple-system, BlinkMacSystemFont, 'Inter', 'Segoe UI', sans-serif; border: none; pointer-events: auto; cursor: pointer; user-select: none; transition: transform 0.12s ease, filter 0.12s ease; padding: 0; margin: 0; -webkit-font-smoothing: antialiased; background: #CC785C; box-shadow: 0 1px 6px rgba(180, 90, 60, 0.4); } .custom-circle-btn:hover { transform: scale(1.07); filter: brightness(1.1); } .custom-circle-btn:active { transform: scale(0.92); filter: brightness(0.88); } `; document.head.appendChild(css); const modelLabel = document.createElement('div'); modelLabel.id = 'custom-model-name'; modelLabel.textContent = '—'; const makeBtn = (id, txt) => { const el = document.createElement('button'); el.id = id; el.className = 'custom-circle-btn'; el.textContent = txt; return el; }; const btnNew = makeBtn('custom-btn-new', 'NEW'); const btnOn = makeBtn('custom-btn-on', 'ON'); const btnOff = makeBtn('custom-btn-off', 'OFF'); const rowNew = document.createElement('div'); rowNew.className = 'custom-btn-row'; rowNew.appendChild(btnNew); const rowOnOff = document.createElement('div'); rowOnOff.className = 'custom-btn-row'; rowOnOff.append(btnOn, btnOff); wrap.append(modelLabel, rowNew, rowOnOff); document.body.appendChild(wrap); const updatePosition = () => { let targetInput = null; const selectors = ['[placeholder*="Start typing a prompt"]', '[placeholder*="Optional tone"]']; for (const sel of selectors) { const el = document.querySelector(sel); if (el && el.getBoundingClientRect().width > 0) { targetInput = el; break; } } if (targetInput) { const rect = targetInput.getBoundingClientRect(); if (rect.top > 0) { wrap.style.opacity = '1'; wrap.style.left = `${window.innerWidth / 2}px`; wrap.style.top = `${rect.top - GAP_TO_INPUT}px`; } else { wrap.style.opacity = '0'; } } else { wrap.style.opacity = '0'; } requestAnimationFrame(updatePosition); }; const attachToTopLayer = () => { try { const vw = window.innerWidth; const vh = window.innerHeight; let bestEl = document.body; let bestZ = -Infinity; const all = document.body.querySelectorAll('*'); for (let i = 0; i < all.length; i++) { const el = all[i]; if (el === wrap) continue; const rect = el.getBoundingClientRect(); if (rect.width >= vw * 0.9 && rect.height >= vh * 0.9 && rect.left <= vw * 0.1 && rect.top <= vh * 0.1) { const style = getComputedStyle(el); if ((style.position === 'fixed' || style.position === 'absolute') && style.visibility !== 'hidden' && style.display !== 'none') { let zi = parseInt(style.zIndex, 10); if (Number.isNaN(zi)) zi = 0; if (zi >= bestZ) { bestZ = zi; bestEl = el; } } } } if (!bestEl.contains(wrap) || bestEl.lastElementChild !== wrap) { bestEl.appendChild(wrap); } } catch (e) {} }; const readModel = () => { try { const raw = localStorage.getItem('aiStudioUserPreference'); if (!raw) return '—'; const pm = JSON.parse(raw)?.promptModel; return pm ? pm.replace('models/', '') : '—'; } catch (e) { return '—'; } }; let lastModel = ''; const tickModel = () => { const now = readModel(); if (now !== lastModel) { modelLabel.textContent = now; lastModel = now; } }; requestAnimationFrame(updatePosition); setInterval(attachToTopLayer, SCAN_INTERVAL); tickModel(); setInterval(tickModel, 1000); btnNew.addEventListener('click', () => { document.querySelector('a[href*="prompts/new_chat"]')?.click(); setTimeout(() => { document.querySelector("button[data-test-category-id='17']")?.click(); }, 50); }); btnOn.addEventListener('click', () => { const sysBtn = document.querySelector("button[aria-label='System instructions']"); if (sysBtn) { sysBtn.click(); } else { document.querySelector("button[aria-label='Toggle run settings panel']")?.click(); setTimeout(() => { document.querySelector("button[aria-label='System instructions']")?.click(); }, 300); } }); btnOff.addEventListener('click', () => { document.querySelector("button[aria-label='关闭面板'], button[aria-label='Close panel'], button[aria-label='Close']")?.click(); }); })(); 网友解答:


--【壹】--:

佬的移动端用的是啥软件能支持油猴脚本的?