您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Highly customizable mini A.I. floating menu that can define words, answer questions, translate, and much more in a single click and with your custom prompts. Includes useful click to search on Google and copy selected text buttons, along with Rocker+Mouse Gestures and Units+Currency Converters, all features can be easily modified or disabled.
当前为
// ==UserScript== // @name AI Everywhere // @namespace OperaBrowserGestures // @description Highly customizable mini A.I. floating menu that can define words, answer questions, translate, and much more in a single click and with your custom prompts. Includes useful click to search on Google and copy selected text buttons, along with Rocker+Mouse Gestures and Units+Currency Converters, all features can be easily modified or disabled. // @version 71 // @author hacker09 // @include * // @exclude https://accounts.google.com/v3/signin/* // @icon https://i.imgur.com/8iw8GOm.png // @grant GM_registerMenuCommand // @grant GM_getResourceText // @grant GM.xmlHttpRequest // @grant GM_setClipboard // @grant GM_deleteValue // @grant GM_openInTab // @grant window.close // @run-at document-end // @grant GM_setValue // @grant GM_getValue // @connect google.com // @connect generativelanguage.googleapis.com // @resource AIMenuHTMLContent https://hacker09.glitch.me/AIMenuHTML.html // @require https://update.gf.qytechs.cn/scripts/506699/1440902/marked.js // ==/UserScript== /* jshint esversion: 11 */ const BypassTT = window.trustedTypes?.createPolicy('BypassTT', { createHTML: HTML => HTML }); //Bypass trustedTypes if (GM_getResourceText('AIMenuHTMLContent') === '') { alert('Failed to load the HTML file resource!\n\nPlease contact your network admin to have the https://glitch.me domain unblocked.'); return; //Stop running } if ((location.href === 'https://aistudio.google.com/app/apikey' && document.querySelector(".apikey-link") !== null) && GM_getValue("APIKey") === undefined || GM_getValue("APIKey") === null || GM_getValue("APIKey") === '') { //Set up the API Key window.onload = setTimeout(function() { document.querySelectorAll(".apikey-link")[1].click(); //Click on the API Key setTimeout(function() { GM_setValue("APIKey", document.querySelector(".apikey-text").innerText); //Store the API Key (GM_getValue("APIKey") !== undefined && GM_getValue("APIKey") !== null && GM_getValue("APIKey") !== '') ? alert('API Key automatically added!') : alert('Failed to automatically add API Key!'); }, 500); }, 1000); } //Mouse Gestures__________________________________________________________________________________________________________________________________________________________________________________ GM_registerMenuCommand("Enable/Disable Mouse Gestures", MouseGestures); function MouseGestures() //Enable/disable MouseGestures { if (GM_getValue("MouseGestures") === true) { GM_setValue("MouseGestures", false); } else { GM_setValue("MouseGestures", true); location.reload(); } } if (GM_getValue("MouseGestures") === true) //If the MouseGestures is enabled { const SENSITIVITY = 3; const TOLERANCE = 3; const funcs = { //Store the MouseGestures functions 'L': function() { //Detect the Left movement window.history.back(); }, 'R': function() { //Detect the Right movement window.history.forward(); }, 'D': function() { //Detect the Down movement if (IsShiftNotPressed === true) { GM_openInTab(link, { active: true, insert: true, setParent: true }); } }, 'UD': function() { //Detect the Up+Down movement location.reload(); }, 'DR': function(e) { //Detect the Down+Right movement top.close(); e.preventDefault(); e.stopPropagation(); }, 'DU': function() { //Detect the Down+Up movement GM_openInTab(link, { active: false, insert: true, setParent: true }); } }; //Math codes to track the mouse movement gestures var x, y, path; const s = 1 << ((7 - SENSITIVITY) << 1); const t1 = Math.tan(0.15708 * TOLERANCE),t2 = 1 / t1; const tracer = function(e) { var cx = e.clientX, cy = e.clientY, deltaX = cx - x, deltaY = cy - y, distance = deltaX * deltaX + deltaY * deltaY; if (distance > s) { var slope = Math.abs(deltaY / deltaX), direction = ''; if (slope > t1) { direction = deltaY > 0 ? 'D' : 'U'; } else if (slope <= t2) { direction = deltaX > 0 ? 'R' : 'L'; } if (path.charAt(path.length - 1) !== direction) { path += direction; } x = cx; y = cy; } }; window.addEventListener('mousedown', function(e) { if (e.which === 3) { x = e.clientX; y = e.clientY; path = ""; window.addEventListener('mousemove', tracer, false); //Detect the mouse position } }, false); var IsShiftNotPressed = true; //Store the shift key status window.addEventListener("contextmenu", function(e) { //When the shift key is/isn't pressed if (e.shiftKey) { IsShiftNotPressed = false; open(link, '_blank', 'height=' + screen.height + ',width=' + screen.width); } if (LeftClicked === true) { //If the Left Click was released when the Rocker Mouse Gestures were enabled e.preventDefault(); e.stopPropagation(); } setTimeout(function() { IsShiftNotPressed = true; }, 500); }, false); window.addEventListener('contextmenu', function(e) { //When the right click BTN is released window.removeEventListener('mousemove', tracer, false); //Track the mouse movements if (path !== "") { e.preventDefault(); if (funcs.hasOwnProperty(path)) { funcs[path](); } } }, false); var link; Array.from(document.querySelectorAll('a')).forEach(Element => Element.onmouseover = function() { link = this.href; //Store the hovered link to a variable }); Array.from(document.querySelectorAll('a')).forEach(Element => Element.onmouseout = function() { const PreviousLink = link; //Save the hovered link setTimeout(function() { if (PreviousLink === link) //If the hovered link is still the same as the previously hovered Link { link = 'about:newtab'; //Make the script open a new browser tab when the mouse leaves any link that was hovered } }, 200); }); } //Rocker Mouse Gestures___________________________________________________________________________________________________________________________________________________________________________ GM_registerMenuCommand("Enable/Disable Rocker Mouse Gestures", RockerMouseGestures); function RockerMouseGestures() //Enable/disable RockerMouseGestures { if (GM_getValue("RockerMouseGestures") === true) { GM_setValue("RockerMouseGestures", false); } else { GM_setValue("RockerMouseGestures", true); location.reload(); } } if (GM_getValue("RockerMouseGestures") === true || GM_getValue("SearchHiLight") === true) //If the RockerMouseGestures or the SearchHiLight is enabled { var LeftClicked, RightClicked; window.addEventListener("mousedown", function(e) { //Track which side of the mouse was the first one to be pressed switch (e.button) { case 0: LeftClicked = true; break; case 2: RightClicked = true; break; } }, false); window.addEventListener("mouseup", function(e) { //Track which side of the mouse was the last one to be released switch (e.button) { case 0: LeftClicked = false; break; case 2: RightClicked = false; break; } if (LeftClicked && RightClicked === false) { //If Left was Clicked and then Right Click was released history.back(); } if (RightClicked && LeftClicked === false) { //If Right was Clicked and then Left Click was released history.forward(); } }, false); } //SearchHighLight + CurrenciesConverter + UnitsConverter__________________________________________________________________________________________________________________________________________ GM_registerMenuCommand("Enable/Disable SearchHiLight", SearchHiLight); if (GM_getValue("SearchHiLight") === undefined) { //Set up everything on the first run GM_setValue("SearchHiLight", true); GM_setValue("MouseGestures", true); GM_setValue("UnitsConverter", true); GM_setValue("RockerMouseGestures", false); GM_setValue("CurrenciesConverter", true); } function SearchHiLight() //Enable/disable the SearchHiLight and the Currency/Unit converters { if (GM_getValue("SearchHiLight") === true) { GM_setValue("SearchHiLight", false); GM_deleteValue('YourLocalCurrency'); GM_setValue("UnitsConverter", false); GM_setValue("CurrenciesConverter", false); } else { GM_setValue("SearchHiLight", true); if (confirm('If you want to enable the Currency Converter press OK.')) { GM_setValue("CurrenciesConverter", true); } else { GM_setValue("CurrenciesConverter", false); } if (confirm('If you want to enable the Units Converter press OK.')) { GM_setValue("UnitsConverter", true); } else { GM_setValue("UnitsConverter", false); } location.reload(); } } if (GM_getValue("SearchHiLight") === true) //If the SearchHiLight is enabled { var SelectedTextIsLink, FinalCurrency, SelectedText, SelectedTextSearch = ''; const Links = new RegExp(/\.org|\.ly|\.net|\.co|\.tv|\.me|\.biz|\.club|\.site|\.br|\.gov|\.io|\.jp|\.edu|\.au|\.in|\.it|\.ca|\.mx|\.fr|\.tw|\.il|\.uk|\.zoom\.us|\youtu.be/i); document.body.addEventListener('mouseup', function() { //When the user releases the mouse click after selecting something HtmlMenu.style.display = 'block'; //Display the container div SelectedText = getSelection().toString(); //Store the selected text SelectedTextSearch = getSelection().toString().replaceAll('&', '%26'); //Store the selected text to be opened on Google shadowRoot.querySelector("#ShowCurrencyORUnits").innerText = ''; //Remove the previous Units/Currency text const CurrencySymbols = new RegExp(/\$|R\$|HK\$|US\$|\$US|¥|€|Rp|kn|Kč|kr|zł|£|฿|₩/i); const Currencies = new RegExp(/^[ \t\xA0]*(?=.*?(\d+(?:.\d+)?))(?=(?:\1[ \t\xA0]*)?(Dólares|dolares|dólares|dollars|AUD|BGN|BRL|BCH|BTC|BYN|CAD|CHF|CNY|CZK|DKK|EUR|EGP|ETH|GBP|GEL|HKD|HRK|HUF|IDR|ILS|INR|JPY|LTC|KRW|MXN|MYR|NOK|NZD|PHP|PLN|RON|RM|RUB|SEK|SGD|THB|TRY|USD|UAH|ZAR|KZT|YTL|\$|R\$|HK\$|US\$|\$US|¥|€|Rp|kn|Kč|kr|zł|£|฿|₩))(?:\1[ \t\xA0]*\2|\2[ \t\xA0]*\1)[ \t\xA0]*$/i); function ShowConvertion(UnitORCurrency, Type, Result) { shadowRoot.querySelector("#SearchBTN span")?.remove(); //Return previous HTML shadowRoot.querySelector("#SearchBTN").innerHTML = (html => BypassTT?.createHTML(html) || html)('<span class="GreyBar">│ </span>' + shadowRoot.querySelector("#SearchBTN").innerHTML); if (UnitORCurrency === 'Currencies') { const hasSymbol = SelectedText.match(Currencies)[2].match(CurrencySymbols) !== null; const currencyFormat = Intl.NumberFormat(navigator.language, { style: 'currency', currency: GM_getValue("YourLocalCurrency") }).format(Result); const displayText = hasSymbol ? (Type + ' 🠂 ' + currencyFormat) : currencyFormat; shadowRoot.querySelector("#ShowCurrencyORUnits").innerHTML = (html => BypassTT?.createHTML(html) || html)(displayText); } UnitORCurrency === 'Units' ? shadowRoot.querySelector("#ShowCurrencyORUnits").innerHTML = (html => BypassTT?.createHTML(html) || html)(Result + ' ' + Type) : ''; //Show the converted unit results setTimeout(() => { //Wait for Units to show up to get the right offsetWidth const offsetWidth = shadowRoot.querySelector("#ShowCurrencyORUnits").offsetWidth; //Store the current menu size shadowRoot.querySelector("#ShowCurrencyORUnits").onmouseover = function() { //When the mouse hovers the unit/currency shadowRoot.querySelector("#ShowCurrencyORUnits").innerHTML = (html => BypassTT?.createHTML(html) || html)(`Copy`); shadowRoot.querySelector("#ShowCurrencyORUnits").style.display = 'inline-flex'; shadowRoot.querySelector("#ShowCurrencyORUnits").style.width = `${offsetWidth}px`; //Maintain the aspect ratio }; }, 0); const htmlcode = shadowRoot.querySelector("#ShowCurrencyORUnits").innerHTML; //Save the converted unit/currency value shadowRoot.querySelector("#ShowCurrencyORUnits").onmouseout = function() { //When the mouse leaves the unit/currency shadowRoot.querySelector("#ShowCurrencyORUnits").style.width = ''; //Return the original aspect ratio shadowRoot.querySelector("#ShowCurrencyORUnits").style.display = ''; //Return the original aspect ratio shadowRoot.querySelector("#ShowCurrencyORUnits").innerHTML = (html => BypassTT?.createHTML(html) || html)(htmlcode); //Return the previous html }; shadowRoot.querySelector("#ShowCurrencyORUnits").onclick = function() { //When the unit/currency is clicked UnitORCurrency === 'Units' ? GM_setClipboard(`${Result} ${Type}`) : GM_setClipboard(Intl.NumberFormat(navigator.language, { style: 'currency', currency: GM_getValue("YourLocalCurrency") }).format(Result)); }; } //CurrenciesConverter____________________________________________________________________________________________________________________________________________________________________________ if (GM_getValue("CurrenciesConverter") === true && SelectedText.match(Currencies) !== null) { //If Currencies Converter is enabled and if the selected text is a currency if (GM_getValue("YourLocalCurrency") === undefined) { const UserInput = prompt('Write your local currency.\nThe script will always use your local currency to make exchange-rate conversions.\n\n*Currency input examples:\nBRL\nCAD\nUSD\netc...\n\n*Press OK'); GM_setValue("YourLocalCurrency", UserInput); } const currencyMap = { '$': 'USD', 'us$': 'USD', '$us': 'USD', 'r$': 'BRL', 'hk$': 'HKD', '¥': 'JPY', '€': 'EUR', 'rp': 'IDR', 'kn': 'HRK', 'kč': 'CZK', 'kr': 'DKK', 'zł': 'PLN', '£': 'GBP', '฿': 'THB', '₩': 'KRW' }; const CurrencySymbol = currencyMap[SelectedText.match(CurrencySymbols)?.[0].toLowerCase()] || SelectedText.match(Currencies)[2]; //Store the currency symbol GM.xmlHttpRequest({ //Get the final converted currency value method: "GET", url: `https://www.google.com/search?q=${SelectedText.match(Currencies)[1]} ${CurrencySymbol} in ${GM_getValue("YourLocalCurrency")}`, onload: (response) => { const newDocument = new DOMParser().parseFromString(response.responseText, 'text/html'); //Parse the fetch response const FinalCurrency = parseFloat(newDocument.querySelector(".SwHCTb").innerText.split(' ')[0].replaceAll(',', '')); //Store the FinalCurrency and erase all commas ShowConvertion('Currencies', CurrencySymbol, FinalCurrency); } }); } //UnitsConverter_________________________________________________________________________________________________________________________________________________________________________________ const conversionMap = {}; const Units = new RegExp(/^[ \t\xA0]*(-?\d+(?:[., ]\d+)?)(?:[ \t\xA0]*x[ \t\xA0]*(-?\d+(?:[., ]\d+)?))?[ \t\xA0]*(in|inch|inches|cm|cms|centimeters?|mt|mts|meters?|ft|kg|lbs?|pounds?|kilograms?|ounces?|g|ozs?|fl oz|fl oz (us)|fluid ounces?|kphs?|km\/h|kilometers per hours?|mphs?|meters per hours?|°?º?[CF]|km\/hs?|ml|milliliters?|l|liters?|litres?|gal|gallons?|yards?|yd|Millimeter|millimetre|kilometers?|mi|mm|miles?|km|ft|fl|feets?|grams?|kilowatts?|kws?|brake horsepower|mechanical horsepower|hps?|bhps?|miles per gallons?|mpgs?|liters per 100 kilometers?|l\/100km|liquid quarts?|lqs?|foot-?pounds?|ft-?lbs?|lb fts?|newton-?meters?|nm|\^\d+)[ \t\xA0]*(?:\(\w+\)[ \t\xA0]*)?$/i); function addConversion(keys, unit, factor, convert) { //Helper function to add multiple keys with the same value keys.forEach(key => { conversionMap[key] = { unit, factor, convert }; }); } if (GM_getValue("UnitsConverter") === true && SelectedText.match(Units) !== null) { //If the Units Converter option is enabled and if the selected text is an unit addConversion(['inch', 'inches', 'in', '"', '”'], 'cm', 2.54); addConversion(['centimeter', 'centimeters', 'cm', 'cms'], 'in', 1/2.54); addConversion(['meter', 'meters', 'mt', 'mts'], 'ft', 3.281); addConversion(['kilogram', 'kilograms', 'kg'], 'lb', 2.205); addConversion(['pound', 'pounds', 'lb', 'lbs'], 'kg', 1/2.205); addConversion(['ounce', 'ounces', 'oz', 'ozs'], 'g', 28.35); addConversion(['gram', 'grams', 'g'], 'oz', 1/28.35); addConversion(['kilometer', 'kilometers', 'km'], 'mi', 1/1.609); addConversion(['kph', 'kphs', 'km/h', 'km/hs', 'kilometers per hour', 'kilometers per hours'], 'mph', 0.621371); addConversion(['mph', 'mphs', 'meters per hour', 'meters per hours'], 'km/h', 1*1.609); addConversion(['mi', 'mile', 'miles'], 'km', 1.609); addConversion(['°c', '°f', 'ºc', 'ºf'], '°F', v => (v*9/5)+32); addConversion(['°f', 'ºf'], '°C', v => (v-32)*5/9); addConversion(['milliliter', 'milliliters', 'ml'], 'fl oz (US)', 1/29.574); addConversion(['fl oz (US)', 'fl oz', 'fl', 'fluid ounce', 'fluid ounces'], 'ml', 29.574); addConversion(['litre', 'liter', 'litres', 'liters', 'l'], 'gal (US)', 1/3.785); addConversion(['gal', 'gallon', 'gallons'], 'lt', 3.785); addConversion(['yard', 'yards', 'yd'], 'm', 1/1.094); addConversion(['millimetre', 'millimeters', 'millimetres', 'mm'], 'in', 1/25.4); addConversion(['feet', 'feets', 'ft'], 'mt', 0.3048); addConversion(['kilowatt', 'kilowatts', 'kw', 'kws'], 'mhp', 1.341); addConversion(['mhp', 'mhps', 'hp', 'hps', 'brake horsepower', 'mechanical horsepower'], 'kw', 1/1.341); addConversion(['mpg', 'mpgs', 'miles per gallon', 'miles per gallons'], 'l/100km', v => 235.215/v); addConversion(['l/100km', 'liters per 100 kilometer', 'liters per 100 kilometers'], 'US mpg', v => 235.215/v); addConversion(['lq', 'lqs', 'liquid quart', 'liquid quarts'], 'l', 1/1.057); addConversion(['foot-pound', 'foot-pounds', 'foot pound', 'foot pounds', 'ft-lbs', 'ft-lb', 'ft lbs', 'ft lb', 'lb ft', 'lb-ft'], 'Nm', 1.3558179483); addConversion(['nm', 'newton-meter', 'newton-meters', 'newton meter', 'newton meters'], 'ft lb', 1/1.3558179483); const selectedUnitType = SelectedText.match(Units)[3].toLowerCase(); const SelectedUnitValue = SelectedText.match(Units)[1].replaceAll(',', '.'); const SecondSelectedUnitValue = SelectedText.match(Units)[2]?.replaceAll(',', '.') || 0; const convertValue = (value, unitType) => { const { factor, convert } = conversionMap[unitType] || {}; return convert ? convert(value) : value * factor; }; var NewUnit = conversionMap[selectedUnitType]?.unit || selectedUnitType; var ConvertedUnit = SecondSelectedUnitValue != 0 ? `${convertValue(parseFloat(SelectedUnitValue), selectedUnitType).toFixed(2)} x ${convertValue(parseFloat(SecondSelectedUnitValue), selectedUnitType).toFixed(2)}` : convertValue(parseFloat(SelectedUnitValue), selectedUnitType).toFixed(2); ConvertedUnit = SelectedText.match(/\^(\d+\.?\d*)/) ? (NewUnit = 'power', Math.pow(parseFloat(SelectedUnitValue), parseFloat(SelectedText.match(/\^(\d+\.?\d*)/)[1]))) : ConvertedUnit; ShowConvertion('Units', NewUnit, ConvertedUnit); } //Menu___________________________________________________________________________________________________________________________________________________________________________________________ if (shadowRoot.querySelector("#SearchBTN").innerText === 'Open') //If the Search BTN text is 'Open' { shadowRoot.querySelector("#highlight_menu > ul").style.paddingInlineStart = '19px'; //Increase the menu size shadowRoot.querySelector("#SearchBTN").innerText = 'Search'; //Display the BTN text as Search again shadowRoot.querySelectorAll(".AI-BG-box button").forEach(button => { button.style.marginLeft = ''; }); //Remove the margin left shadowRoot.querySelector("#OpenAfter").remove(); //Remove the custom Open white hover overlay SelectedTextIsLink = false; //Make common words searchable again } if (SelectedText.match(Links) !== null) //If the selected text is a link { SelectedTextIsLink = true; shadowRoot.querySelector("#highlight_menu > ul").style.paddingInlineStart = '27px'; //Increase the menu size shadowRoot.querySelector("#SearchBTN").innerText = 'Open'; //Change the BTN text to Open shadowRoot.querySelectorAll(".AI-BG-box button").forEach(button => { button.style.marginLeft = '-2%'; }); //Add a margin left shadowRoot.innerHTML += (html => BypassTT?.createHTML(html) || html)(` <style id="OpenAfter"> #SearchBTN::after { width: 177% !important; transform: translate(-34%, -71%) !important; } </style> `); //Add a custom Open white hover overlay } shadowRoot.querySelector("#SearchBTN").onmousedown = function() { var LinkfyOrSearch = 'https://www.google.com/search?q='; if (SelectedTextIsLink === true) { LinkfyOrSearch = 'https://'; //Make the non-HTTP and non-HTTPS links able to be opened } if (SelectedText.match(/http:|https:/) !== null) //If the selected text is a link that already has HTTP or HTTPS { LinkfyOrSearch = ''; //Remove the https:// that was previously added to this var } GM_openInTab(LinkfyOrSearch + SelectedTextSearch, { active: true, setParent: true, loadInBackground: true }); //Open google and search for the selected text getSelection().removeAllRanges(); //UnSelect the selected text after the search BTN is clicked so that if the user clicks on the past selected text the menu won't show up again. shadowRoot.querySelector("#highlight_menu").classList.remove('show'); //Hide the menu }; const menu = shadowRoot.querySelector("#highlight_menu"); if (document.getSelection().toString().trim() !== '') { //If text has been selected const p = document.getSelection().getRangeAt(0).getBoundingClientRect(); //Store the selected position menu.classList.add('show'); //Show the menu menu.offsetHeight; //Trigger reflow by forcing a style calculation menu.style.left = p.left + (p.width / 2) - (menu.offsetWidth / 2) + 'px'; menu.style.top = p.top - menu.offsetHeight - 10 + 'px'; menu.classList.add('highlight_menu_animate'); return; //Keep the menu open } menu.classList.remove('show'); //Hide the menu shadowRoot.querySelector("#SearchBTN span")?.remove(); //Return previous HTML }); //Finishes the mouseup event listener //AI Menu_______________________________________________________________________________________________________________________________________________________________________________________ var desiredVoice = null, isRecognizing = false; const HtmlMenu = document.createElement('div'); //Create a container div HtmlMenu.setAttribute('style', `width: 0px; height: 0px; display: none;`); //Hide the container div by default const shadowRoot = HtmlMenu.attachShadow({ mode: 'closed' }); const BGColor = matchMedia('(prefers-color-scheme: dark)').matches ? 'rgb(37, 36, 53)' : '#e7edf1'; //Change AI theme according to the browser theme const IMGsColor = BGColor === '#e7edf1' ? 'filter: invert(1)' : ''; //If on white mode invert black svg colors to white const TextColor = BGColor === '#e7edf1' ? 'black' : 'white'; //Depending on the browser theme change the AI menu text color const UniqueLangs = navigator.languages.filter((l, i, arr) => !arr.slice(0, i).some(e => e.split('-')[0].toLowerCase() === l.split('-')[0].toLowerCase()) ); //Filter unique languages const Lang = UniqueLangs.length > 1 ? `${UniqueLangs[0]} and into ${UniqueLangs[1]}` : UniqueLangs[0]; //Use 1 or 2 languages const GeminiSVG = '<svg viewBox="0 0 32 32" fill="none"> <path d="M14 28C14 26.0633 13.6267 24.2433 12.88 22.54C12.1567 20.8367 11.165 19.355 9.905 18.095C8.645 16.835 7.16333 15.8433 5.46 15.12C3.75667 14.3733 1.93667 14 0 14C1.93667 14 3.75667 13.6383 5.46 12.915C7.16333 12.1683 8.645 11.165 9.905 9.905C11.165 8.645 12.1567 7.16333 12.88 5.46C13.6267 3.75667 14 1.93667 14 0C14 1.93667 14.3617 3.75667 15.085 5.46C15.8317 7.16333 16.835 8.645 18.095 9.905C19.355 11.165 20.8367 12.1683 22.54 12.915C24.2433 13.6383 26.0633 14 28 14C26.0633 14 24.2433 14.3733 22.54 15.12C20.8367 15.8433 19.355 16.835 18.095 18.095C16.835 19.355 15.8317 20.8367 15.085 22.54C14.3617 24.2433 14 26.0633 14 28Z" fill="url(#paint)"></path></svg>'; shadowRoot.innerHTML = (html => BypassTT?.createHTML(html) || html)(GM_getResourceText("AIMenuHTMLContent").replaceAll(/\$\{(BGColor|TextColor|GeminiSVG|IMGsColor)\}/g, (_, key) => ({BGColor, TextColor, GeminiSVG, IMGsColor, }[key]))); //Set the AI menu html function Generate(Prompt, button) { //Call the AI endpoint const context = !!shadowRoot.querySelector("#context.show") ? `(You're not allowed to say anything like "Based on the provided text")\n"${Prompt} mainly base yourself on the text below\n${document.body.innerText}` : Prompt; //Add the page context if context is enabled const IsQuestion = Prompt.includes('?') ? 'Give me a very short, then a long detailed answer' : 'Help me further explore a term or topic from the text/word'; const AIFunction = button.match('translate') ? `(You're not allowed to say anything like (The text is already in ${UniqueLangs[0]}"\nNo translation is needed).\Translate into ${Lang} the following text:\n"${Prompt}".\nAfter showing (in order) a few possible "Translations:" also give me a "Definition:" and "Examples:".You must answer using only 1 language first, then use only the other language, don't mix both languages! ` : button.match('Prompt') ? context : `(PS*I'm unable to provide you with more context, so don't ask for it! Also, don't mention that I haven't provided context or anything similar to it!) ${IsQuestion}: "${Prompt}"`; //AI prompts const msg = button.match('translate') ? `Translate this text: "${Prompt.length > 215 ? Prompt.trim().slice(0, 215) + '…' : Prompt.trim()}"` : button.match('Prompt') ? Prompt.length > 240 ? Prompt.trim().slice(0, 240) + '…' : Prompt.trim() : `Help me further explore a term or topic from the text: "${Prompt.length > 180 ? Prompt.trim().slice(0, 180) + '…' : Prompt.trim()}"`; //User text const request = GM.xmlHttpRequest({ //Call the AI API method: "POST", url: `https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash-latest:streamGenerateContent?key=${GM_getValue("APIKey")}`, responseType: 'stream', headers: { "Content-Type": "application/json" }, data: JSON.stringify({ contents: [{ parts: [{ text: `${AIFunction}` //Use our AI prompt }] }], safetySettings: [ //Allow all content { category: "HARM_CATEGORY_HARASSMENT", threshold: "BLOCK_NONE" }, { category: "HARM_CATEGORY_HATE_SPEECH", threshold: "BLOCK_NONE" }, { category: "HARM_CATEGORY_SEXUALLY_EXPLICIT", threshold: "BLOCK_NONE" }, { category: "HARM_CATEGORY_DANGEROUS_CONTENT", threshold: "BLOCK_NONE" } ], }), onerror: function(err) { shadowRoot.querySelector("#finalanswer").innerHTML = (html => BypassTT?.createHTML(html) || html)(`<br>Please copy and paste the error below:<br><a class="feedback" href="https://gf.qytechs.cn/scripts/419825/feedback">Click here to report this bug</a><br><br> Prompt: ${Prompt}<br> Button: ${button}<br> Error: ${err}}<br><br><br>`); }, onload: function(response) { shadowRoot.querySelector("#AIMenu").classList.add('show'); shadowRoot.querySelector("#dictate").classList.add('show'); shadowRoot.querySelector("#TopPause").classList.remove('show'); }, onabort: function(response) { shadowRoot.querySelector("#AIMenu").classList.add('show'); shadowRoot.querySelector("#dictate").classList.add('show'); shadowRoot.querySelector("#TopPause").classList.remove('show'); shadowRoot.querySelector("#finalanswer").innerText = 'ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤResponse has been interrupted.'; }, onloadstart: function(test) { shadowRoot.querySelector("#prompt").focus(); shadowRoot.querySelector("#msg").innerHTML = msg; shadowRoot.querySelector("#TopPause").classList.add('show'); shadowRoot.querySelector("#AIMenu").classList.remove('show'); shadowRoot.querySelector("#dictate").classList.remove('show'); shadowRoot.querySelector("#copyAnswer").onclick = function() { shadowRoot.querySelector("#copyAnswer").style.display = 'none'; shadowRoot.querySelector("#AnswerCopied").style.display = 'inline-flex'; GM_setClipboard(shadowRoot.querySelector("#finalanswer").innerText.replace('ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤ', '')); setTimeout(() => { //Return play BTN svg shadowRoot.querySelector("#copyAnswer").style.display = 'inline-flex'; shadowRoot.querySelector("#AnswerCopied").style.display = 'none'; }, 1000); }; const reader = test.response.getReader(); const decoder = new TextDecoder(); var buffer = '', partialMarkdown = ''; function readStream() { reader.read().then(({ value }) => { buffer += decoder.decode(value, { stream: true }); var startIdx = 0; while (true) { const openBrace = buffer.indexOf('{', startIdx); if (openBrace === -1) break; var balance = 1, closeBrace = openBrace + 1; while (balance > 0 && closeBrace < buffer.length) { if (buffer[closeBrace] === '{') balance++; if (buffer[closeBrace] === '}') balance--; closeBrace++; } if (balance !== 0) break; //Incomplete JSON object const jsonString = buffer.substring(openBrace, closeBrace); const item = JSON.parse(jsonString); partialMarkdown += item.candidates[0].content.parts[0].text; const tempDiv = document.createElement('div'); tempDiv.innerHTML = marked.parse(partialMarkdown); shadowRoot.querySelector("#finalanswer").innerHTML = ''; shadowRoot.querySelector("#finalanswer").appendChild(tempDiv); startIdx = closeBrace; } buffer = buffer.substring(startIdx); readStream(); }); } readStream(); shadowRoot.querySelector("#CloseOverlay").classList.add('show'); shadowRoot.querySelector("#highlight_menu").classList.remove('show'); //Hide the mini menu on the page shadowRoot.querySelectorAll("#AIBox, .animated-border, #AIBox.AnswerBox").forEach(el => el.classList.add('show')); //Show the AI input and box getSelection().removeAllRanges(); //UnSelect the selected text so that if the user clicks on a previously selected text the menu won't show up again var SpeechRecognition = SpeechRecognition || webkitSpeechRecognition; const recognition = new SpeechRecognition(); recognition.interimResults = true; //Show partial results recognition.continuous = true; //Keep listening until stopped var transcript = ""; //Add words shadowRoot.querySelector("#CloseOverlay").onclick = function() { [...shadowRoot.querySelector("#finalanswer div").childNodes].slice(0, -1).forEach(node => node.remove()); //Reset the text content shadowRoot.querySelectorAll("#AIBox, .animated-border, #AIBox.AnswerBox").forEach(el => el.classList.remove('show')); //Hide the AI input and box this.classList.remove('show'); recognition.stop(); //Stop recognizing audio speechSynthesis.cancel(); //Stop speaking request.abort(); //Abort any ongoing request if (shadowRoot.querySelector("#gemini").style.display === 'none') { shadowRoot.querySelector("#AddContext").remove(); //Return original prompt input styles shadowRoot.querySelector("#context").classList.remove('show'); shadowRoot.querySelector("#prompt").placeholder = 'Enter your prompt to Gemini'; //Return default placeholder } }; shadowRoot.querySelector("#TopPause").onclick = function() { shadowRoot.querySelector("#dictate").classList.add('show'); shadowRoot.querySelector("#TopPause").classList.remove('show'); request.abort(); }; recognition.onend = function() { isRecognizing = false; shadowRoot.querySelectorAll('.state1, .state2, .state3').forEach((state, index) => { //ForEach SVG animation state index.toString().match(/1|2/) ? state.style.display = 'none' : ''; //Show only the 1 state state.classList.remove('animate'+index); //Stop the voice recording animation }); transcript !== '' ? Generate(transcript, shadowRoot.querySelector("#prompt").className) : shadowRoot.querySelector("#finalanswer").innerHTML = (html => BypassTT?.createHTML(html) || html)(`<br>No audio detected. Please try again or check your mic settings.ㅤㅤㅤㅤㅤㅤㅤㅤㅤ<br><br>`); //Call the AI API if audio has been detected or show an error message }; //Finish the recognition end event listener recognition.onresult = function(event) { //Handle voice recognition results transcript = ""; //Clear the transcript at the start of the event for (var i = 0; i < event.results.length; i++) { //For all transcript results transcript += event.results[i][0].transcript + ' '; //Concatenate all intermediate transcripts } shadowRoot.querySelector("#msg").innerText = transcript.length > 240 ? transcript.slice(0, 240) + '…' : transcript; //Display recognized words }; shadowRoot.querySelector("#dictate").onclick = function() { if (isRecognizing) { recognition.stop(); } else { isRecognizing = true; recognition.start(); shadowRoot.querySelectorAll('.state1, .state2, .state3').forEach((state, index) => { //ForEach SVG animation state state.style.display = 'unset'; //Show all states state.classList.add('animate'+index); //Start the voice recording animation }); } }; speechSynthesis.onvoiceschanged = () => desiredVoice = speechSynthesis.getVoices().find(v => v.name === "Microsoft Zira - English (United States)"); //Get and store the desired voice speechSynthesis.onvoiceschanged(); //Handle cases where the event doesn't fire shadowRoot.querySelectorAll("#speak, #SpeakingPause").forEach(function(el) { el.onclick = function() { //When the speak or the bottom pause BTNs are clicked if (speechSynthesis.speaking) { speechSynthesis.cancel(); shadowRoot.querySelector("#speak").style.display = 'inline-flex'; //Show the play BTN shadowRoot.querySelector("#SpeakingPause").classList.remove('show'); //Hide the pause BTN } else { shadowRoot.querySelector("#speak").style.display = 'none'; //Hide the play BTN shadowRoot.querySelector("#SpeakingPause").classList.add('show'); var audio = new SpeechSynthesisUtterance(shadowRoot.querySelector("#finalanswer").innerText.replace(/\(?..-..\)?:?|[^a-zA-Z0-9\s%.,!?]/g, '')); //Play the AI response text, removing non-alphanumeric characters and lang locales for better pronunciation audio.voice = desiredVoice; //Use the desiredVoice speechSynthesis.speak(audio); //Speak the text audio.onend = (event) => { shadowRoot.querySelector("#speak").style.display = 'inline-flex'; //Show the play BTN shadowRoot.querySelector("#SpeakingPause").classList.remove('show'); }; } }; }); shadowRoot.querySelector("#NewAnswer").onclick = function() { recognition.stop(); //Stop recognizing audio speechSynthesis.cancel(); //Stop speaking shadowRoot.querySelector("#speak").style.display = 'inline-flex'; //Show the play BTN shadowRoot.querySelector("#SpeakingPause").classList.remove('show'); //Hide the pause BTN shadowRoot.querySelector("#dictate").classList.remove('show'); shadowRoot.querySelector("#TopPause").classList.add('show'); Generate(Prompt, button); //Call the AI API }; } //Finishes the onloadstart event listener });//Finishes the GM.xmlHttpRequest function } //Finishes the Generate function shadowRoot.querySelector("#prompt").addEventListener("keydown", (event) => { if (event.key === "Enter") { Generate(shadowRoot.querySelector("#prompt").value, shadowRoot.querySelector("#prompt").className); //Call the AI API shadowRoot.querySelector("#prompt").value = ''; //Erase the prompt text } if (event.key === "Tab") { if (shadowRoot.querySelector("#prompt").placeholder.match('using')) { //If the input bar contains the word "using" shadowRoot.querySelector("#AddContext").remove(); //Return original prompt input styles shadowRoot.querySelector("#context").classList.remove('show'); //Hide the context view shadowRoot.querySelector("#prompt").placeholder = 'Enter your prompt to Gemini'; //Return default placeholder } else { shadowRoot.querySelector("#context").classList.add('show'); //Show the context view shadowRoot.querySelector("#prompt").placeholder = `Gemini is using ${location.host.replace('www.','')} for context...`; //Change placeholder shadowRoot.querySelector("#highlight_menu").insertAdjacentHTML('beforebegin', ` <style id="AddContext"> #gemini { display: none; } #prompt { left: 12%; width: 75%; } #tabcontext { display: none; } .animated-border { --color-OrangeORLilac: #FF8051; /* Change the border effect color to orange */ } </style> `); //Show the context bar } } setTimeout(() => { //Wait for the code above to execute shadowRoot.querySelector("#prompt").focus(); //Refocus on the input bar }, 0); }); shadowRoot.querySelectorAll("#AIBTN").forEach(function(button) { button.onmousedown = function(event, i) { //When the Explore or the Translate BTNs are clicked if (GM_getValue("APIKey") === undefined || GM_getValue("APIKey") === null || GM_getValue("APIKey") === '') { //Set up the API Key if it isn't already set GM_setValue("APIKey", prompt('Enter your API key\n*Press OK\n\nYou can get a free API key at https://aistudio.google.com/app/apikey')); } if (GM_getValue("APIKey") !== null && GM_getValue("APIKey") !== '') { Generate(SelectedText, this.className); //Call the AI API } }; }); if (document.body.textContent !== '' || document.body.innerText !== '') //If the body has any text { document.body.appendChild(HtmlMenu); //Add the script menu div container } shadowRoot.querySelector('#CopyBTN').onmousedown = function() { GM_setClipboard(getSelection().toString()); }; window.addEventListener('scroll', async function() { shadowRoot.querySelector("#highlight_menu").classList.remove('show'); //Hide the menu if (LeftClicked === false && SelectedText !== '') { //If the Left Click isn't being held, and if something is currently selected getSelection().removeAllRanges(); //UnSelect the selected text when scrolling the page down so that if the user clicks on the past selected text the menu won't show up again } }); }
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址