Perplexity helper

Simple script that adds buttons to Perplexity website for repeating request using Copilot.

当前为 2023-08-20 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name        Perplexity helper
// @namespace   Tiartyos
// @match       https://www.perplexity.ai/*
// @grant       none
// @version     1.7
// @author      Tiartyos
// @description Simple script that adds buttons to Perplexity website for repeating request using Copilot.
// @require     https://code.jquery.com/jquery-3.6.0.min.js
// @require     https://cdnjs.cloudflare.com/ajax/libs/jquery-modal/0.9.1/jquery.modal.min.js
// @require     https://cdnjs.cloudflare.com/ajax/libs/lodash-fp/0.10.4/lodash-fp.min.js
// @require     https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.8/clipboard.min.js
// @homepageURL https://www.perplexity.ai/
// @license GPL-3.0-or-later
// ==/UserScript==

const jq = $.noConflict();

let debugMode = false;
const enableDebugMode = () => {
  debugMode = true;
};

const debugLog = (...args) => {
  if (debugMode) {
    console.log('[DEBUG]', ...args);
  }
}

const button = (id, icoName, title) => `<button title="${title}" type="button" id="${id}" class="btn-helper bg-super dark:bg-superDark dark:text-backgroundDark text-white hover:opacity-80 font-sans focus:outline-none outline-none outline-transparent transition duration-300 ease-in-out font-sans  select-none items-center relative group  justify-center text-center items-center rounded-full cursor-point active:scale-95 origin-center whitespace-nowrap inline-flex text-base aspect-square h-10">
<div class="flex items-center leading-none justify-center gap-xs">
    ${icoName}
</div></button>`;

const upperButton = (id, icoName, title) => `
<div title="${title}" id="${id}" class="border rounded-full px-sm py-xs flex items-center gap-x-sm  border-borderMain/60 dark:border-borderMainDark/60 divide-borderMain dark:divide-borderMainDark ring-borderMain dark:ring-borderMainDark  bg-transparent"><div class="border-borderMain/60 dark:border-borderMainDark/60 divide-borderMain dark:divide-borderMainDark ring-borderMain dark:ring-borderMainDark  bg-transparent"><div class="flex items-center gap-x-xs transition duration-300 select-none cursor-pointer hover:text-superAlt light font-sans text-sm font-medium text-textOff dark:text-textOffDark selection:bg-super selection:text-white dark:selection:bg-opacity-50 selection:bg-opacity-70"><div class="">${icoName}<path fill="currentColor" d="M64 288L39.8 263.8C14.3 238.3 0 203.8 0 167.8C0 92.8 60.8 32 135.8 32c36 0 70.5 14.3 96 39.8L256 96l24.2-24.2c25.5-25.5 60-39.8 96-39.8C451.2 32 512 92.8 512 167.8c0 36-14.3 70.5-39.8 96L448 288 256 480 64 288z"></path></svg></div><div></div></div></div></div>
`

const textButton = (id, text, title) => `
<button title="${title}" id="${id}" type="button" class="bg-super text-white hover:opacity-80 font-sans focus:outline-none outline-none transition duration-300 ease-in-out font-sans  select-none items-center relative group justify-center rounded-md cursor-point active:scale-95 origin-center whitespace-nowrap inline-flex text-sm px-sm font-medium h-8">
<div class="flex items-center leading-none justify-center gap-xs"><span class="flex items-center relative ">${text}</span></div></button>
`
const icoColor = '#1F1F1F';
const robotIco = `<svg style="width: 23px; fill: ${icoColor};" viewBox="0 0 640 512" xmlns="http://www.w3.org/2000/svg"><path d="m32 224h32v192h-32a31.96166 31.96166 0 0 1 -32-32v-128a31.96166 31.96166 0 0 1 32-32zm512-48v272a64.06328 64.06328 0 0 1 -64 64h-320a64.06328 64.06328 0 0 1 -64-64v-272a79.974 79.974 0 0 1 80-80h112v-64a32 32 0 0 1 64 0v64h112a79.974 79.974 0 0 1 80 80zm-280 80a40 40 0 1 0 -40 40 39.997 39.997 0 0 0 40-40zm-8 128h-64v32h64zm96 0h-64v32h64zm104-128a40 40 0 1 0 -40 40 39.997 39.997 0 0 0 40-40zm-8 128h-64v32h64zm192-128v128a31.96166 31.96166 0 0 1 -32 32h-32v-192h32a31.96166 31.96166 0 0 1 32 32z"/></svg>`;
const robotRepeatIco = `<svg style="width: 23px; fill: ${icoColor};"  viewBox="0 0 640 512" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/">    <path d="M442.179,325.051L442.179,459.979C442.151,488.506 418.685,511.972 390.158,512L130.053,512C101.525,511.972 78.06,488.506 78.032,459.979L78.032,238.868C78.032,203.208 107.376,173.863 143.037,173.863L234.095,173.863L234.095,121.842C234.095,107.573 245.836,95.832 260.105,95.832C274.374,95.832 286.116,107.573 286.116,121.842L286.116,173.863L309.247,173.863C321.515,245.71 373.724,304.005 442.179,325.051ZM26.011,277.905L52.021,277.905L52.021,433.968L25.979,433.968C11.727,433.968 -0,422.241 -0,407.989L-0,303.885C-0,289.633 11.727,277.905 25.979,277.905L26.011,277.905ZM468.19,331.092C478.118,332.676 488.289,333.497 498.65,333.497C505.935,333.497 513.126,333.091 520.211,332.299L520.211,407.989C520.211,422.241 508.483,433.968 494.231,433.968L468.19,433.968L468.19,331.092ZM208.084,407.958L156.063,407.958L156.063,433.968L208.084,433.968L208.084,407.958ZM286.116,407.958L234.095,407.958L234.095,433.968L286.116,433.968L286.116,407.958ZM364.147,407.958L312.126,407.958L312.126,433.968L364.147,433.968L364.147,407.958ZM214.587,303.916C214.587,286.08 199.91,271.403 182.074,271.403C164.238,271.403 149.561,286.08 149.561,303.916C149.561,321.752 164.238,336.429 182.074,336.429C182.075,336.429 182.075,336.429 182.076,336.429C199.911,336.429 214.587,321.753 214.587,303.918C214.587,303.917 214.587,303.917 214.587,303.916ZM370.65,303.916C370.65,286.08 355.973,271.403 338.137,271.403C320.301,271.403 305.624,286.08 305.624,303.916C305.624,321.752 320.301,336.429 338.137,336.429C338.138,336.429 338.139,336.429 338.139,336.429C355.974,336.429 370.65,321.753 370.65,303.918C370.65,303.917 370.65,303.917 370.65,303.916Z" style="fill-rule:nonzero;"/>
    <g transform="matrix(14.135,0,0,14.135,329.029,-28.2701)">
        <path d="M12,2C6.48,2 2,6.48 2,12C2,17.52 6.48,22 12,22C17.52,22 22,17.52 22,12C22,6.48 17.52,2 12,2ZM17.19,15.94C17.15,16.03 17.1,16.11 17.03,16.18L15.34,17.87C15.19,18.02 15,18.09 14.81,18.09C14.62,18.09 14.43,18.02 14.28,17.87C13.99,17.58 13.99,17.1 14.28,16.81L14.69,16.4L9.1,16.4C7.8,16.4 6.75,15.34 6.75,14.05L6.75,12.28C6.75,11.87 7.09,11.53 7.5,11.53C7.91,11.53 8.25,11.87 8.25,12.28L8.25,14.05C8.25,14.52 8.63,14.9 9.1,14.9L14.69,14.9L14.28,14.49C13.99,14.2 13.99,13.72 14.28,13.43C14.57,13.14 15.05,13.14 15.34,13.43L17.03,15.12C17.1,15.19 17.15,15.27 17.19,15.36C17.27,15.55 17.27,15.76 17.19,15.94ZM17.25,11.72C17.25,12.13 16.91,12.47 16.5,12.47C16.09,12.47 15.75,12.13 15.75,11.72L15.75,9.95C15.75,9.48 15.37,9.1 14.9,9.1L9.31,9.1L9.72,9.5C10.01,9.79 10.01,10.27 9.72,10.56C9.57,10.71 9.38,10.78 9.19,10.78C9,10.78 8.81,10.71 8.66,10.56L6.97,8.87C6.9,8.8 6.85,8.72 6.81,8.63C6.73,8.45 6.73,8.24 6.81,8.06C6.85,7.97 6.9,7.88 6.97,7.81L8.66,6.12C8.95,5.83 9.43,5.83 9.72,6.12C10.01,6.41 10.01,6.89 9.72,7.18L9.31,7.59L14.9,7.59C16.2,7.59 17.25,8.65 17.25,9.94L17.25,11.72Z" style="fill-rule:nonzero;"/>
    </g></svg>`;

const cogIco = `<svg style="width: 23px; fill: white;" version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"viewBox="0 0 38.297 38.297"
\t xml:space="preserve">
<g>
\t<path d="M25.311,18.136l2.039-2.041l-2.492-2.492l-2.039,2.041c-1.355-0.98-2.941-1.654-4.664-1.934v-2.882H14.63v2.883
\t\tc-1.722,0.278-3.308,0.953-4.662,1.934l-2.041-2.041l-2.492,2.492l2.041,2.041c-0.98,1.354-1.656,2.941-1.937,4.662H2.658v3.523
\t\tH5.54c0.279,1.723,0.955,3.309,1.937,4.664l-2.041,2.039l2.492,2.492l2.041-2.039c1.354,0.979,2.94,1.653,4.662,1.936v2.883h3.524
\t\tv-2.883c1.723-0.279,3.309-0.955,4.664-1.936l2.039,2.039l2.492-2.492l-2.039-2.039c0.98-1.355,1.654-2.941,1.934-4.664h2.885
\t\tv-3.524h-2.885C26.967,21.078,26.293,19.492,25.311,18.136z M16.393,30.869c-3.479,0-6.309-2.83-6.309-6.307
\t\tc0-3.479,2.83-6.308,6.309-6.308c3.479,0,6.307,2.828,6.307,6.308C22.699,28.039,19.871,30.869,16.393,30.869z M35.639,8.113v-2.35
\t\th-0.965c-0.16-0.809-0.474-1.561-0.918-2.221l0.682-0.683l-1.664-1.66l-0.68,0.683c-0.658-0.445-1.41-0.76-2.217-0.918V0h-2.351
\t\tv0.965c-0.81,0.158-1.562,0.473-2.219,0.918L24.625,1.2l-1.662,1.66l0.683,0.683c-0.445,0.66-0.761,1.412-0.918,2.221h-0.966v2.35
\t\th0.966c0.157,0.807,0.473,1.559,0.918,2.217l-0.681,0.68l1.658,1.664l0.685-0.682c0.657,0.443,1.409,0.758,2.219,0.916v0.967h2.351
\t\tv-0.968c0.807-0.158,1.559-0.473,2.217-0.916l0.682,0.68l1.662-1.66l-0.682-0.682c0.444-0.658,0.758-1.41,0.918-2.217H35.639
\t\tL35.639,8.113z M28.701,10.677c-2.062,0-3.74-1.678-3.74-3.74c0-2.064,1.679-3.742,3.74-3.742c2.064,0,3.742,1.678,3.742,3.742
\t\tC32.443,9,30.766,10.677,28.701,10.677z"/>
</g>
</svg>`;

const modalHTML = `
<div id="perplexityHelperModal" class="modal">
  <div class="modal-content">
    <span class="close">&times;</span>
    <p>Perplexity helper settings</p>
  </div>
</div>
`;

const styles = `
.checkbox_label {
  color: white;
}

.btn-helper{
margin-left: 10px
}

.modal {
  display: none;
  position: fixed;
  z-index: 1000;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  overflow: auto;
  background-color: rgba(0, 0, 0, 0.8)
}

.modal-content {
  display: flex;
  margin: 15% auto;
  padding: 20px;
  border: 1px solid #888;
  background-color: #202025;
  border-radius: 6px;
  color: rgb(206, 206, 210);
  flex-direction: column;
  position: relative;
  row-gap: 10px;
}

.modal-content label {
  padding-right: 10px;
}

.close {
  color: rgb(206, 206, 210);
  float: right;
  font-size: 28px;
  font-weight: bold;
  position: absolute;
  right: 5px;
  top: 5px;
}

.close:hover,
.close:focus {
  color: black;
  text-decoration: none;
  cursor: pointer;
}

#copied-modal,#copied-modal-2 {
  padding: 5px 5px;
  background:gray;
  position:absolute;
  display: none;
  color: white;
  font-size: 15px;
}

label > div.select-none {
  user-select: text;
  cursor: initial;
}
`;


(function () {
  // enableDebugMode();

  'use strict';
  jq("head").append(`<style>${styles}</style>`);

  debugLog(jq.fn.jquery);
  const getSavedStates = () => JSON.parse(localStorage.getItem('checkBoxStates'));

  const getModal = () => jq(".bg-black\\/80").next();
  const getBtnDotFromTextArea = (textArea) => jq('#ppl-message-scroll-target ~ div textarea ~ div').find('button .rounded-full').first();
  const upperControls = () => jq('svg[data-icon="heart"]').parent().parent().parent().parent().parent().first();

  const getControlsArea = () => jq('#ppl-message-scroll-target ~ div textarea ~ div').last();

  const getCopilotNewThreadButton = () => jq('#copilot_new_thread');
  const getCopilotRepeatLastButton = () => jq('#copilot_repeat_last');
  const getSelectAllButton = () => jq('#perplexity_helper_select_all');
  const getSelectAllAndSubmitButton = () => jq('#perplexity_helper_select_all_and_submit');
  const getCopyPlaceholder = () => jq('#perplexity_helper_copy_placeholder');
  const getCopyAndFillInPlaceholder = () => jq('#perplexity_helper_copy_placeholder_and_fill_in');
  const getSettingsEl = () => jq('#perplexity_helper_settings');
  const getSideMenu = () => jq('.sticky').parent().parent();
  const getSettingsModalContent = () => jq('#perplexityHelperModal').find('.modal-content');

  const getSubmitBtn0 = () => jq('svg[data-icon="arrow-up"]').last().parent().parent();
  const getSubmitBtn1 = () => jq('svg[data-icon="arrow-right"]').last().parent().parent();
  const getSubmitBtn2 = () => jq('svg[data-icon="code-fork"]').last().parent().parent();

  const isStandardControlsAreaFc = () => getControlsArea().hasClass('bg-green');
  const getCurrentControlsArea = () => isStandardControlsAreaFc() ? getControlsArea() : getControlsArea().find('.bg-green');

  const getDashedCheckboxButton = () => jq('svg[data-icon="square-dashed"]').parent().parent();
  const getStarSVG = () => jq('svg[data-icon="star-christmas"]');
  const getSpecifyQuestionBox = () => jq('svg[data-icon="star-christmas"]').parent().parent().parent().last();


  const getNumberOfDashedSVGs = () => getSpecifyQuestionBox().find('svg[data-icon="square-dashed"]').length;
  const getSpecifyQuestionControlsWrapper = () => getSpecifyQuestionBox().find('button:contains("Continue")').parent()
  const getCopiedModal = () => jq('#copied-modal');
  const getCopiedModal2 = () => jq('#copied-modal-2');
  const getCopyPlaceholderInput = () => getSpecifyQuestionBox().find('textarea');


  const getSubmitButton0or2 = () => getSubmitBtn0().length < 1 ? getSubmitBtn2() : getSubmitBtn0();
  ;

  const questionBoxWithPlaceholderExists = () => getSpecifyQuestionBox().find('textarea')?.attr('placeholder')?.length > 0 ?? false;

  const selectAllCheckboxes = () => {
    const currentCheckboxes = getDashedCheckboxButton();
    debugLog('checkboxes', currentCheckboxes);

    const removeLastObject = (arr) => {
      if (!_.isEmpty(arr)) {
        debugLog('arr', arr);
        const newArr = _.dropRight(arr, 1);
        debugLog("newArr", newArr);
        getDashedCheckboxButton().last().click();

        return setTimeout(() => {
          removeLastObject(newArr)
        }, 1)

      }
    };

    removeLastObject(currentCheckboxes);
  }

  const isCopilotOn = (el) => {
    return el.hasClass('text-super');
  }

  const toggleBtnDot = (btnDot, value) => {
    debugLog(' toggleBtnDot btnDot', btnDot);

    const btnDotInner = btnDot.find('.rounded-full');

    debugLog('btnDotInner', btnDotInner);

    if (!btnDotInner.hasClass('bg-super') && value === true) {
      btnDot.click();
    }
  }

  const checkForCopilotToggleState = (timer, checkCondition, submitWhenTrue, submitButtonVersion) => {
    debugLog("checkForCopilotToggleState run", timer, checkCondition(), submitWhenTrue, submitButtonVersion);
    if (checkCondition()) {
      clearInterval(timer);
      debugLog("checkForCopilotToggleState condition met, interval cleared");
      const submitBtn = submitButtonVersion === 0 ? getSubmitButton0or2() : getSubmitBtn1();

      debugLog('submitBtn', submitBtn);
      if (submitWhenTrue) {
        submitBtn.click();
      }
    }
  }

  const changeValueUsingEvent = (selector, value) => {
    debugLog('changeValueUsingEvent', value, selector);

    const nativeTextareaValueSetter = Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype, 'value').set;
    nativeTextareaValueSetter.call(selector, value);
    const inputEvent = new Event('input', {bubbles: true});
    selector.dispatchEvent(inputEvent);
  }

  const openNewThreadModal = (lastQuery) => {
    debugLog('openNewThreadModal', lastQuery)

    const newThreadText = jq(".sticky div").filter(function () {
      return /^New Thread$/i.test(jq(this).text());
    });

    newThreadText.click();
    setTimeout(() => {
        debugLog('newThreadText.click()');
        const modal = getModal();

        if (modal.length > 0) {
          const textArea = modal.find('textarea');
          debugLog('textArea.length should be 1', textArea.length);

          const newTextArea = textArea.last();
          const textareaElement = newTextArea[0];
          debugLog('textareaElement', textareaElement);
          changeValueUsingEvent(textareaElement, lastQuery);

          const btnDot = getBtnDotFromTextArea(newTextArea);

          const btn = btnDot.parent().parent().parent();
          debugLog('btn', btn);

          toggleBtnDot(btnDot, true);
          const isCopilotOnBtn = () => isCopilotOn(btn);

          const coPilotNewThreadAutoSubmit = getSavedStates() ? getSavedStates().coPilotNewThreadAutoSubmit : jq('#copilot_new_thread').prop('checked');

          const copilotCheck = () => {
            const ctx = {timer: null};
            ctx.timer = setInterval(() => checkForCopilotToggleState(ctx.timer, isCopilotOnBtn, coPilotNewThreadAutoSubmit, 1), 500);
          }

          copilotCheck()
        } else {
          debugLog('modal.length > 0', textArea)
        }
      },
      2000);
  }

  const getLastQuery = () => {
    const lastQueryBoxU = jq('svg[data-icon="flag"]').last().parent().parent().parent().parent().parent();
    if (lastQueryBoxU.length === 0) {
      debugLog('lastQueryBoxU.length === 0');
    }

    const wasCopilotUsed = lastQueryBoxU.find('svg[data-icon="star-christmas"]').length > 0;
    if (lastQueryBoxU.find('svg[data-icon="star-christmas"]').length === 0) {
      debugLog('wasCopilotUsed.length === 0');
    }

    const lastQueryBoxWithoutCopilot = lastQueryBoxU.find('.whitespace-pre-line').text();
    if (lastQueryBoxWithoutCopilot.length === 0) {
      debugLog('lastQueryBoxWithoutCopilot', lastQueryBoxWithoutCopilot);
    }

    const lastQueryBoxWithCopilot = lastQueryBoxU.find('.whitespace-pre-line').text();
    if (lastQueryBoxWithCopilot.length === 0) {
      debugLog('lastQueryBoxWithCopilot', lastQueryBoxWithCopilot);
    }

    return wasCopilotUsed ? lastQueryBoxWithCopilot : lastQueryBoxWithoutCopilot;
  }

  const createCheckbox = (id, saveCheckboxStates) => {
    debugLog("createCheckbox", id);
    const checkbox = jq(`<input type="checkbox" id=${id}>`);
    const label = jq(`<label class="checkbox_label">${id}</label>`);
    const checkboxWithLabel = jq('<div class="checkbox_wrapper"></div>').append(label).append(checkbox);
    debugLog('checkboxwithlabel', checkboxWithLabel)

    getSettingsModalContent().append(checkboxWithLabel);
    checkbox.on('change', saveCheckboxStates);
    return checkbox;
  };

  const saveCheckboxStates = () => {
    debugLog('saveCheckboxStates');
    const checkBoxStates = {
      coPilotNewThreadAutoSubmit: jq(coPilotNewThreadAutoSubmit).prop('checked'),
      coPilotRepeatLastAutoSubmit: jq(coPilotRepeatLastAutoSubmit).prop('checked'),
      hideSideMenu: jq(hideSideMenu).prop('checked')
    };
    localStorage.setItem('checkBoxStates', JSON.stringify(checkBoxStates));
  };

  setInterval(() => {
    if (jq("#perplexityHelperModal").length > 0 && jq("#coPilotNewThreadAutoSubmit").length < 1) {
      const coPilotNewThreadAutoSubmit = createCheckbox('coPilotNewThreadAutoSubmit', saveCheckboxStates);
      const coPilotRepeatLastAutoSubmit = createCheckbox('coPilotRepeatLastAutoSubmit', saveCheckboxStates);
      const hideSideMenu = createCheckbox('hideSideMenu', saveCheckboxStates);

      const savedStates = JSON.parse(localStorage.getItem('checkBoxStates'));
      if (savedStates !== null) {
        jq(coPilotNewThreadAutoSubmit).prop('checked', savedStates.coPilotNewThreadAutoSubmit);
        jq(coPilotRepeatLastAutoSubmit).prop('checked', savedStates.coPilotRepeatLastAutoSubmit);
        jq(hideSideMenu).prop('checked', savedStates.hideSideMenu);
      }

    }


    const settingsEl = getSettingsEl();

    if (jq('#perplexityHelperModal').length < 1 && settingsEl.length === 1 && !settingsEl.attr('data-has-custom-click-event')) {
      jq("body").append(modalHTML);

      if (settingsEl.length > 0) {
        debugLog('settingsEl', settingsEl);
      }


      settingsEl.on("click", () => {
        debugLog('perplexity_helper_settings open click');
        jq("#perplexityHelperModal").show().css('display', 'flex');
      });

      jq("#perplexityHelperModal .close").on("click", () => {
        debugLog('perplexity_helper_settings close  click');
        jq("#perplexityHelperModal").hide();
      });

      settingsEl.attr('data-has-custom-click-event', true);

    }

    const regex = /^https:\/\/www\.perplexity\.ai\/search\/?.*/;
    const currentURL = jq(location).attr('href');
    const matched = regex.test(currentURL);

    // debugLog("currentURL", currentURL);
    // debugLog("matched", matched);

    if (matched) {
      const sideMenu = getSideMenu();
      if (getSavedStates()) getSavedStates().hideSideMenu || jq('#hideSideMenu').prop('checked') ? sideMenu.hide() : sideMenu.show();
      const controlsArea = getCurrentControlsArea();

      if (controlsArea.length === 0) {
        debugLog('controlsArea', controlsArea);
        debugLog('getControlsArea()', getControlsArea());
        debugLog('getControlsArea().find(\'bg-green\')', getControlsArea().find('.bg-green'));
      }

      const lastQueryBoxText = getLastQuery();


      const mainTextArea = isStandardControlsAreaFc() ? controlsArea.prev().prev() : controlsArea.parent().prev();

      if (mainTextArea.length === 0) {
        debugLog('mainTextArea', mainTextArea);
      }


      if (lastQueryBoxText) {
        const copilotNewThread = getCopilotNewThreadButton();
        const copilotRepeatLast = getCopilotRepeatLastButton();
        const copilotHelperSettings = getSettingsEl();

        if (controlsArea.length > 0 && copilotNewThread.length < 1) {
          controlsArea.append(button('copilot_new_thread', robotIco, "Starts new thread for with last query text and Copilot ON"));
        }

        if (controlsArea.length > 0 && copilotRepeatLast.length < 1)
          controlsArea.append(button('copilot_repeat_last', robotRepeatIco, "Repeats last query with Copilot ON"));


        if (upperControls().length > 0 && copilotHelperSettings.length < 1)
          upperControls().append(upperButton('perplexity_helper_settings', cogIco, "perplexity_helper_settings"));

        if (!copilotNewThread.attr('data-has-custom-click-event')) {
          copilotNewThread.on("click", function () {
            debugLog('copilotNewThread Button clicked!');
            openNewThreadModal(getLastQuery());
          })
          copilotNewThread.attr('data-has-custom-click-event', true);
        }

        if (!copilotRepeatLast.attr('data-has-custom-click-event')) {
          copilotRepeatLast.on("click", function () {

            const textAreaElement = mainTextArea[0];

            const coPilotRepeatLastAutoSubmit = getSavedStates() ? getSavedStates().coPilotRepeatLastAutoSubmit : jq('#copilot_repeat_last_auto_submit').prop('checked');

            debugLog('coPilotRepeatLastAutoSubmit', coPilotRepeatLastAutoSubmit);
            changeValueUsingEvent(textAreaElement, getLastQuery());
            const btnDot = getBtnDotFromTextArea(mainTextArea)
            debugLog('mainTextArea', mainTextArea);
            debugLog('btnDot', btnDot);

            toggleBtnDot(btnDot, true);
            const btn = btnDot.parent().parent().parent();
            const isCopilotOnBtn = () => isCopilotOn(btn);

            const copilotCheck = () => {
              const ctx = {timer: null};
              ctx.timer = setInterval(() => checkForCopilotToggleState(ctx.timer, isCopilotOnBtn, coPilotRepeatLastAutoSubmit, 0), 500);
            }

            copilotCheck();
            debugLog('copilot_repeat_last Button clicked!');
          })
          copilotRepeatLast.attr('data-has-custom-click-event', true);
        }
      }

      if (getNumberOfDashedSVGs() > 0 && getNumberOfDashedSVGs() === getDashedCheckboxButton().length
        && getSelectAllButton().length < 1 && getSelectAllAndSubmitButton().length < 1) {
        debugLog('getNumberOfDashedSVGs() === getNumberOfDashedSVGs()', getNumberOfDashedSVGs());
        debugLog('getSpecifyQuestionBox', getSpecifyQuestionBox());

        const specifyQuestionControlsWrapper = getSpecifyQuestionControlsWrapper();
        debugLog('specifyQuestionControlsWrapper', specifyQuestionControlsWrapper);
        const selectAllButton = textButton('perplexity_helper_select_all', 'Select all', 'Selects all options');
        const selectAllAndSubmitButton = textButton('perplexity_helper_select_all_and_submit', 'Select all & submit', 'Selects all options and submits');

        specifyQuestionControlsWrapper.append(selectAllButton);
        specifyQuestionControlsWrapper.append(selectAllAndSubmitButton);

        getSelectAllButton().on("click", function () {
          selectAllCheckboxes();
        })

        getSelectAllAndSubmitButton().on("click", function () {
          selectAllCheckboxes();
          setTimeout(() => {
            getSpecifyQuestionControlsWrapper().find('button:contains("Continue")').click();
          }, 200);
        })
      }

      const constructClipBoard = (buttonId,buttonGetter,modalGetter, copiedModalId, elementGetter) =>{
        const placeholderValue = getSpecifyQuestionBox().find('textarea').attr('placeholder')

        const clipboardInstance = new ClipboardJS(`#${buttonId}`, {
          text: () => placeholderValue
        });

        const copiedModal = `<span id="${copiedModalId}">Copied!</span>`;
        debugLog('copiedModalId', copiedModalId);
        debugLog('copiedModal', copiedModal);

        jq('main').append(copiedModal);

        clipboardInstance.on('success', _ => {
          var buttonPosition = buttonGetter().position();
          jq(`#${copiedModalId}`).css({
            top: buttonPosition.top - 30,
            left: buttonPosition.left + 50
          }).show();

          if (elementGetter !== undefined){
            changeValueUsingEvent(elementGetter()[0], placeholderValue);
          }

          setTimeout(() => {
            modalGetter().hide();
          }, 5000);
        });
      }

      if (questionBoxWithPlaceholderExists() && getCopyPlaceholder().length < 1) {
        const copyPlaceholder = textButton('perplexity_helper_copy_placeholder', 'Copy placeholder', 'Copies placeholder value');
        const copyPlaceholderAndFillIn = textButton('perplexity_helper_copy_placeholder_and_fill_in', 'Copy placeholder and fill in',
          'Copies placeholder value and fills in input');

        const specifyQuestionControlsWrapper = getSpecifyQuestionControlsWrapper();

        specifyQuestionControlsWrapper.append(copyPlaceholder);
        specifyQuestionControlsWrapper.append(copyPlaceholderAndFillIn);

        constructClipBoard('perplexity_helper_copy_placeholder', getCopyPlaceholder, getCopiedModal,'copied-modal')
        constructClipBoard('perplexity_helper_copy_placeholder_and_fill_in', getCopyAndFillInPlaceholder, getCopiedModal2,'copied-modal-2',getCopyPlaceholderInput)
      }


    }
  }, 1000)

}());