Greasy Fork

来自缓存

Greasy Fork is available in English.

我的提示

直接在 ChatGPT、DeepSeek、Google AI Studio、Qwen、Z.ai、Gemini 和 LMArena 中保存、编辑、删除、导入和导出您的自定义提示。

当前为 2025-09-22 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name               My Prompt
// @name:en            My Prompt
// @name:pt-BR         Meu Prompt
// @name:es            Mi Prompt
// @name:zh-CN         我的提示
// @namespace          https://github.com/0H4S
// @version            1.2
// @description        Save, edit, delete, import, and export your custom prompts directly in ChatGPT, DeepSeek, Google AI Studio, Qwen, Z.ai, Gemini, and LMArena
// @description:en     Save, edit, delete, import, and export your custom prompts directly in ChatGPT, DeepSeek, Google AI Studio, Qwen, Z.ai, Gemini, and LMArena
// @description:pt-BR  Salve, edite, exclua, importe e exporte seus prompts personalizados diretamente no ChatGPT, DeepSeek, Google AI Studio, Qwen, Z.ai, Gemini e LMArena
// @description:es     Guarda, edita, elimina, importa y exporta tus prompts personalizados directamente en ChatGPT, DeepSeek, Google AI Studio, Qwen, Z.ai, Gemini y LMArena
// @description:zh-CN  直接在 ChatGPT、DeepSeek、Google AI Studio、Qwen、Z.ai、Gemini 和 LMArena 中保存、编辑、删除、导入和导出您的自定义提示。
// @author             OHAS
// @homepage           https://github.com/0H4S
// @icon               https://cdn-icons-png.flaticon.com/512/4997/4997543.png
// @license            Copyright (c) 2025 OHAS. All Rights Reserved.
// @match              https://chatgpt.com/*
// @match              https://chat.deepseek.com/*
// @match              https://aistudio.google.com/*
// @match              https://chat.qwen.ai/*
// @match              https://chat.z.ai/*
// @match              https://gemini.google.com/*
// @match              https://lmarena.ai/*
// @require            https://update.greasyfork.icu/scripts/549920/Script%20Notifier.js
// @connect            gist.githubusercontent.com
// @grant              GM_getValue
// @grant              GM_setValue
// @grant              GM_registerMenuCommand
// @grant              GM_xmlhttpRequest
// @run-at             document-end
// @tag                ai
// @tag                prompts
// @tag                productivity
// ==/UserScript==
(function() {
    'use strict';
	/* globals ScriptNotifier */
    if (window.top !== window.self) {
        return;
    }
    const SCRIPT_CONFIG = {
        notificationsUrl: 'https://gist.githubusercontent.com/0H4S/40b2a2feb2ba18d0bf63a1943ba5cec3/raw/my_prompt_notifications.json',
        scriptVersion: '1.1',
        currentLang: navigator.language || 'en'
    };
  const notifier = new ScriptNotifier(SCRIPT_CONFIG);
  notifier.run();
  const PROMPT_STORAGE_KEY = 'Prompts';
  const LANG_STORAGE_KEY = 'Lang';
  const translations = {
    'en': {
      'langName': 'English',
      'prompt': 'Prompt',
      'prompts': 'Prompts',
      'newPrompt': 'New Prompt',
      'editPrompt': 'Edit Prompt',
      'title': 'Title',
      'text': 'Prompt',
      'save': 'Save',
      'close': 'Close',
      'edit': 'Edit',
      'delete': 'Delete',
      'noSavedPrompts': 'No saved prompts.',
      'addPrompt': 'Add prompt',
      'import': 'Import',
      'export': 'Export',
      'confirmDelete': 'Delete prompt "{title}"?',
      'noPromptsToExport': 'No prompts to export.',
      'promptsImported': '{count} prompts imported successfully!',
      'errorImporting': 'Error importing file: {error}',
      'requiredFields': 'Title and prompt are required.',
      'editorNotFound': 'Could not find the text area for {platform}.',
      'languageSettings': '🌐 Language',
      'fileName': 'My Prompt.json'
    },
    'es': {
      'langName': 'Español',
      'prompt': 'Prompt',
      'prompts': 'Prompts',
      'newPrompt': 'Nuevo Prompt',
      'editPrompt': 'Editar Prompt',
      'title': 'Título',
      'text': 'Prompt',
      'save': 'Guardar',
      'close': 'Cerrar',
      'edit': 'Editar',
      'delete': 'Eliminar',
      'noSavedPrompts': 'No hay prompts guardados.',
      'addPrompt': 'Añadir prompt',
      'import': 'Importar',
      'export': 'Exportar',
      'confirmDelete': '¿Eliminar prompt "{title}"?',
      'noPromptsToExport': 'No hay prompts para exportar.',
      'promptsImported': '¡{count} prompts importados con éxito!',
      'errorImporting': 'Error al importar el archivo: {error}',
      'requiredFields': 'El título y el prompt son obligatorios.',
      'editorNotFound': 'No se pudo encontrar el área de texto para {platform}.',
      'languageSettings': '🌐 Idioma',
      'fileName': 'Mi Prompt.json'
    },
    'pt-BR': {
      'langName': 'Português (BR)',
      'prompt': 'Prompt',
      'prompts': 'Prompts',
      'newPrompt': 'Novo Prompt',
      'editPrompt': 'Editar Prompt',
      'title': 'Título',
      'text': 'Prompt',
      'save': 'Salvar',
      'close': 'Fechar',
      'edit': 'Editar',
      'delete': 'Excluir',
      'noSavedPrompts': 'Nenhum prompt salvo.',
      'addPrompt': 'Adicionar prompt',
      'import': 'Importar',
      'export': 'Exportar',
      'confirmDelete': 'Excluir prompt "{title}"?',
      'noPromptsToExport': 'Não há prompts para exportar.',
      'promptsImported': '{count} prompts importados com sucesso!',
      'errorImporting': 'Erro ao importar o arquivo: {error}',
      'requiredFields': 'Título e prompt são obrigatórios.',
      'editorNotFound': 'Não foi possível encontrar a área de texto para {platform}.',
      'languageSettings': '🌐 Idioma',
      'fileName': 'Meu Prompt.json'
    },
    'zh-CN': {
      'langName': '简体中文',
      'prompt': '提示',
      'prompts': '提示',
      'newPrompt': '新建提示',
      'editPrompt': '编辑提示',
      'title': '标题',
      'text': '提示内容',
      'save': '保存',
      'close': '关闭',
      'edit': '编辑',
      'delete': '删除',
      'noSavedPrompts': '没有已保存的提示。',
      'addPrompt': '添加提示',
      'import': '导入',
      'export': '导出',
      'confirmDelete': '确定要删除提示 "{title}" 吗?',
      'noPromptsToExport': '沒有可導出的提示。',
      'promptsImported': '成功导入 {count} 个提示!',
      'errorImporting': '导入文件时出错: {error}',
      'requiredFields': '标题和提示内容为必填项。',
      'editorNotFound': '未能找到 {platform} 的文本输入区域。',
      'languageSettings': '🌐 语言',
      'fileName': '我的提示.json'
    }
  };
  let currentLang = 'en';
  function getTranslation(key, replacements = {}) {
    let text = translations[currentLang]?.[key] || translations.en [key];
    for (const placeholder in replacements) {
      text = text.replace(`{${placeholder}}`, replacements[placeholder]);
    }
    return text;
  }
  async function determineLanguage() {
    let savedLang = await GM_getValue(LANG_STORAGE_KEY);
    if (savedLang && translations[savedLang]) {
      currentLang = savedLang;
      return;
    }
    let browserLang = (navigator.language || navigator.userLanguage).toLowerCase();
    if (browserLang.startsWith('pt')) currentLang = 'pt-BR';
    else if (browserLang.startsWith('es')) currentLang = 'es';
    else if (browserLang.startsWith('zh')) currentLang = 'zh-CN';
    else currentLang = 'en';
  }
  let isInitialized = false;
  let isInitializing = false;
  let currentButton = null;
  let currentMenu = null;
  let currentModal = null;
  let languageModal = null;
  let currentPlatform = null;
  let pageObserver = null;
  const scriptPolicy = window.trustedTypes
    ? window.trustedTypes.createPolicy('MyPromptPolicy', { createHTML: (input) => input })
    : null;
  function setSafeInnerHTML(element, html) {
    if (!element) return;
    if (scriptPolicy) {
      element.innerHTML = scriptPolicy.createHTML(html);
    } else {
      element.innerHTML = html;
    }
  }
  function detectPlatform() {
    const hostname = window.location.hostname;
    if (hostname.includes('chatgpt.com')) return 'chatgpt';
    if (hostname.includes('deepseek.com')) return 'deepseek';
    if (hostname.includes('aistudio.google.com')) return 'googlestudio';
    if (hostname.includes('chat.qwen.ai')) return 'qwen';
    if (hostname.includes('chat.z.ai')) return 'zai';
    if (hostname.includes('gemini.google.com')) return 'gemini';
    if (hostname.includes('lmarena.ai')) return 'lmarena';
    return null;
  }
  function waitFor(selector, timeout = 8000) {
    return new Promise((resolve, reject) => {
      const el = document.querySelector(selector);
      if (el) { resolve(el); return; }
      const timer = setTimeout(() => {
        obs.disconnect();
        reject(`Timeout esperando por ${selector}`);
      }, timeout);
      const obs = new MutationObserver(() => {
        const target = document.querySelector(selector);
        if (target) {
          clearTimeout(timer);
          obs.disconnect();
          resolve(target);
        }
      });
      if (document.body) {
        obs.observe(document.body, { childList: true, subtree: true });
      } else {
        document.addEventListener('DOMContentLoaded', () => obs.observe(document.body, { childList: true, subtree: true }));
      }
    });
  }
  const debounce = (func, wait) => {
    let timeout;
    return (...args) => {
      clearTimeout(timeout);
      timeout = setTimeout(() => func.apply(this, args), wait);
    };
  };
  async function getAll() { return (await GM_getValue(PROMPT_STORAGE_KEY, [])); }
  async function addItem(item) {
    const prompts = await getAll();
    prompts.push(item);
    await GM_setValue(PROMPT_STORAGE_KEY, prompts);
    return item;
  }
  async function update(index, itemToUpdate) {
    let prompts = await getAll();
    if (prompts[index]) {
      prompts[index] = itemToUpdate;
      await GM_setValue(PROMPT_STORAGE_KEY, prompts);
    }
  }
  async function remove(index) {
    let prompts = await getAll();
    prompts.splice(index, 1);
    await GM_setValue(PROMPT_STORAGE_KEY, prompts);
  }
  function createCustomTooltip(button, text, position = 'top') {
    let tooltipElement = null;
    const showTooltip = () => {
      if (tooltipElement) return;
      tooltipElement = document.createElement('div');
      const innerDiv = document.createElement('div');
      innerDiv.textContent = text;
      innerDiv.style.cssText = "color: #1d1d20; text-align: center; font-family: 'Inter', sans-serif; font-size: 14px; font-weight: 400; line-height: 1;";
      tooltipElement.appendChild(innerDiv);
      tooltipElement.style.cssText = "position: fixed; z-index: 2147483647; background-color: #f4f4f6; border-radius: 6px; padding: 6px 12px; pointer-events: none; opacity: 0; transform: scale(0.95); transition: opacity 150ms cubic-bezier(0.4, 0, 0.2, 1), transform 150ms cubic-bezier(0.4, 0, 0.2, 1); white-space: nowrap;";
      document.body.appendChild(tooltipElement);
      const btnRect = button.getBoundingClientRect();
      const tooltipRect = tooltipElement.getBoundingClientRect();
      let top;
      const margin = 8;
      if (position === 'bottom') {
        top = btnRect.bottom + margin;
        if (top + tooltipRect.height > window.innerHeight) {
          top = btnRect.top - tooltipRect.height - margin;
        }
      } else {
        top = btnRect.top - tooltipRect.height - margin;
        if (top < 0) {
          top = btnRect.bottom + margin;
        }
      }
      let left = btnRect.left + (btnRect.width / 2) - (tooltipRect.width / 2);
      if (left < 0) { left = margin; }
      if (left + tooltipRect.width > window.innerWidth) { left = window.innerWidth - tooltipRect.width - margin; }
      tooltipElement.style.left = `${left}px`;
      tooltipElement.style.top = `${top}px`;
      requestAnimationFrame(() => {
        tooltipElement.style.opacity = '1';
        tooltipElement.style.transform = 'scale(1)';
      });
    };
    const hideTooltip = () => {
      if (!tooltipElement) return;
      const el = tooltipElement;
      tooltipElement = null;
      el.style.opacity = '0';
      el.style.transform = 'scale(0.95)';
      setTimeout(() => {
        if (document.body.contains(el)) {
          document.body.removeChild(el);
        }
      }, 150);
    };
    button.addEventListener('mouseenter', showTooltip);
    button.addEventListener('mouseleave', hideTooltip);
    button.addEventListener('mousedown', hideTooltip);
  }
  function createChatGPTButton() {
    const btn = document.createElement('button');
    btn.type = 'button';
    btn.setAttribute('data-testid', 'composer-button-prompts');
    btn.setAttribute('aria-label', getTranslation('prompts'));
    btn.setAttribute('title', getTranslation('prompt'));
    btn.className = 'composer-btn';
    setSafeInnerHTML(btn, `<svg width="20" height="20" viewBox="0 0 20 20" fill="currentColor" xmlns="http://www.w3.org/2000/svg" aria-label="" class="icon"><path d="M4 5h12M4 10h12M4 15h12" stroke="currentColor" stroke-width="2"/></svg>`);
    return btn;
  }
  function createDeepSeekButton() {
    const btn = document.createElement('button');
    btn.setAttribute('role', 'button');
    btn.setAttribute('tabindex', '0');
    btn.setAttribute('data-testid', 'composer-button-prompts');
    setSafeInnerHTML(btn, `<div class="ds-icon" style="font-size: 17px; width: 17px; height: 17px; color: currentColor; margin-right: 6px; visibility: visible;"><svg width="20" height="20" fill="currentColor" viewBox="0 0 20 20"><path d="M4 5h12M4 10h12M4 15h12" stroke="currentColor" stroke-width="2"/></svg></div><span class=""><span class="_6dbc175">${getTranslation('prompt')}</span></span>`);
    return btn;
  }
  function createGoogleStudioButton() {
    const btn = document.createElement('button');
    btn.setAttribute('data-testid', 'composer-button-prompts');
    btn.setAttribute('ms-button', '');
    btn.setAttribute('variant', 'icon');
    btn.className = 'mat-mdc-tooltip-trigger icon';
    btn.setAttribute('aria-label', getTranslation('prompts'));
    btn.setAttribute('title', getTranslation('prompt'));
    const svgHTML = `<svg fill="currentColor" style="width: 24px; height: 24px; display: flex;" version="1.1" viewBox="0 0 100 100"><g><path d="M17.563,30.277h0.012c0,1.245,1.004,2.254,2.246,2.267v0.002h60.359v-0.001c1.248-0.006,2.259-1.018,2.259-2.268h0.01 l0-10.459h0c-0.002-1.251-1.017-2.265-2.269-2.265l0,0H19.821v0c0,0,0,0,0,0c-1.253,0-2.269,1.017-2.269,2.269 c0,0.039,0.01,0.076,0.012,0.115L17.563,30.277z"/><path d="M80.179,42.504L80.179,42.504H19.821v0c0,0,0,0,0,0c-1.253,0-2.269,1.017-2.269,2.269c0,0.039,0.01,0.076,0.012,0.115 l0,10.34h0.012c0,1.245,1.004,2.254,2.246,2.267v0.002h60.359v-0.001c1.248-0.006,2.259-1.018,2.259-2.268h0.01l0-10.459h0 C82.446,43.518,81.431,42.504,80.179,42.504z"/><path d="M80.179,67.454L80.179,67.454H19.821l0,0c0,0,0,0,0,0c-1.253,0-2.269,1.017-2.269,2.269c0,0.039,0.01,0.076,0.012,0.115 l0,10.34h0.012c0,1.245,1.004,2.254,2.246,2.267v0.002h60.359v-0.001c1.248-0.006,2.259-1.019,2.259-2.269h0.01l0-10.459h0 C82.446,68.468,81.431,67.454,80.179,67.454z"/></g></svg>`;
    setSafeInnerHTML(btn, svgHTML);
    return btn;
  }
  function createQwenButton() {
    const btn = document.createElement('button');
    btn.className = 'chat-input-feature-btn';
    btn.setAttribute('data-testid', 'composer-button-prompts');
    setSafeInnerHTML(btn, `<svg width="20" height="20" viewBox="0 0 20 20" fill="currentColor" xmlns="http://www.w3.org/2000/svg" class="chat-input-feature-btn-icon" style="font-size: 16px;"><path d="M4 5h12M4 10h12M4 15h12" stroke="currentColor" stroke-width="2"/></svg><span class="chat-input-feature-btn-text">${getTranslation('prompt')}</span>`);
    return btn;
  }
  function createZaiButton() {
    const btnWrapper = document.createElement('div');
    setSafeInnerHTML(btnWrapper, `<button type="button" class="px-2 @xl:px-3 py-1.5 flex gap-1.5 items-center text-sm rounded-lg border transition-colors duration-300 focus:outline-hidden max-w-full overflow-hidden bg-transparent dark:text-gray-300 border-[#E5E5E5] dark:border-[#3C3E3F] hover:bg-black/5 dark:hover:bg-white/5"><svg class=" size-4" stroke-width="2" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M9 17L3 12L9 7" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path><path d="M15 17L21 12L15 7" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path></svg><span class="hidden @sm:block whitespace-nowrap overflow-hidden text-ellipsis translate-y-[0.5px] mr-0.5">${getTranslation('prompt')}</span></button>`);
    const btn = btnWrapper.firstElementChild;
    btn.setAttribute('data-testid', 'composer-button-prompts');
    return btn;
  }
  function createGeminiButton() {
    const btn = document.createElement('button');
    btn.setAttribute('data-testid', 'composer-button-prompts');
    btn.className = 'mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-primary mat-mdc-tooltip-trigger';
    const svgHTML = `<span class="mat-mdc-button-persistent-ripple mdc-icon-button__ripple"></span>
    <svg style="width: 24px; height: 24px; display: flex;" viewBox="0 0 20 20" fill="currentColor"><path d="M4 5h12M4 10h12M4 15h12" stroke="currentColor" stroke-width="2"/></svg>
    <span class="mat-focus-indicator"></span><span class="mat-mdc-button-touch-target"></span><span class="mat-ripple mat-mdc-button-ripple"></span>`;
    setSafeInnerHTML(btn, svgHTML);
    // Adicionamos 'bottom' para especificar a posição
    createCustomTooltip(btn, getTranslation('prompt'), 'bottom');
    return btn;
  }
  function createLmarenaButton() {
    const btn = document.createElement('button');
    btn.setAttribute('data-testid', 'composer-button-prompts');
    btn.className = 'inline-flex items-center justify-center gap-2 whitespace-nowrap text-sm font-medium focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring ring-offset-2 focus-visible:ring-offset-surface-primary disabled:pointer-events-none disabled:opacity-50 text-interactive-active border border-border-faint bg-transparent hover:text-interactive-normal active:text-text-tertiary h-8 w-8 p-2 rounded-md active:scale-[0.96] active:transition-transform active:duration-75 transition-colors duration-150 ease-out hover:shadow-sm hover:bg-interactive-normal/10 hover:border-interactive-normal/10';
    btn.type = 'button';
    const svgHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 20 20" fill="currentColor" class="w-4 h-4 transition-colors duration-150 ease-out text-interactive-normal"><path d="M4 5h12M4 10h12M4 15h12" stroke="currentColor" stroke-width="2"/></svg>`;
    setSafeInnerHTML(btn, svgHTML);
    createCustomTooltip(btn, getTranslation('prompt'));
    return btn;
  }
  function createMenu() {
    const m = document.createElement('div');
    m.setAttribute('data-state', 'closed');
    m.setAttribute('data-prompts-menu', 'true');
    m.style.cssText = `position: fixed; display: none; min-width: 320px; max-width: 420px; background-color: #353535; border: 1px solid #626262; border-radius: 16px; box-shadow: 0 10px 25px rgba(0, 0, 0, 0.3); z-index: 2147483647; flex-direction: column; padding: 6px 0; user-select: none; color: #F8FAFF;`;
    return m;
  }
  function createModal() {
    const overlay = document.createElement('div');
    overlay.id = '__ap_modal';
    overlay.setAttribute('data-prompts-modal', 'true');
    overlay.style.cssText = `position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.6); display: none; z-index: 2147483647; justify-content: center; align-items: center; backdrop-filter: blur(4px);`;
    const box = document.createElement('div');
    box.style.cssText = `position: relative; background-color: #2a2a2e; color: #e0e0e0; border-radius: 16px; padding: 28px; box-shadow: 0 4px 6px rgba(0,0,0,0.1), 0 10px 20px rgba(0,0,0,0.4); width: min(90vw, 520px); display: flex; flex-direction: column; border: 1px solid #444; transform: scale(0.95); opacity: 0; transition: transform 0.2s ease-out, opacity 0.2s ease-out;`;
    setSafeInnerHTML(box, `
    <style>
    #__ap_modal input:focus, #__ap_modal textarea:focus { border-color: #22c55e; box-shadow: 0 0 0 3px rgba(34, 197, 94, 0.4); }
    </style>
    <button id="__ap_close" aria-label="${getTranslation('close')}" style="position: absolute; top: 12px; right: 12px; background: none; border: none; color: #999; font-size: 22px; cursor: pointer; width: 32px; height: 32px; border-radius: 50%; transition: transform 0.3s ease, color 0.3s ease; display: flex; justify-content: center; align-items: center;">✕</button>
    <h2 id="__ap_modal_title" style="font-size: 18px; font-weight: 600; margin: 0 0 20px; text-align: center; color: #f0f0f0; letter-spacing: 0.5px;">${getTranslation('newPrompt')}</h2>
      <label for="__ap_title" style="margin-bottom: 6px; font-size: 13px; font-weight: 500; color: #bbb;">${getTranslation('title')}</label>
      <input id="__ap_title" style="background-color: #1e1e22; color: #e0e0e0; border: 1px solid #555; border-radius: 8px; padding: 10px; margin-bottom: 16px; width: 100%; box-sizing: border-box; transition: all 0.2s; outline: none;" />
      <label for="__ap_text" style="margin-bottom: 6px; font-size: 13px; font-weight: 500; color: #bbb;">${getTranslation('text')}</label>
      <textarea id="__ap_text" style="background-color: #1e1e22; color: #e0e0e0; border: 1px solid #555; border-radius: 8px; padding: 10px; height: 120px; width: 100%; margin-bottom: 24px; box-sizing: border-box; resize: vertical; outline: none; font-family: inherit;"></textarea>
      <div style="display: flex; justify-content: center;">
        <button id="__ap_save" style="padding: 10px 28px; border-radius: 8px; background-color: #22c55e; color: white; border: none; font-weight: 600; cursor: pointer; transition: all 0.2s ease-in-out; box-shadow: 0 2px 4px rgba(0,0,0,0.2);">${getTranslation('save')}</button>
      </div>`);
    const saveBtn = box.querySelector('#__ap_save');
    saveBtn.addEventListener('mouseenter', () => { saveBtn.style.backgroundColor = '#16a34a'; saveBtn.style.transform = 'translateY(-1px)'; });
    saveBtn.addEventListener('mouseleave', () => { saveBtn.style.backgroundColor = '#22c55e'; saveBtn.style.transform = 'translateY(0)'; });
    const closeBtn = box.querySelector('#__ap_close');
    closeBtn.addEventListener('mouseenter', () => { closeBtn.style.transform = 'rotate(90deg)'; closeBtn.style.color = '#ef4444'; });
    closeBtn.addEventListener('mouseleave', () => { closeBtn.style.transform = 'rotate(0deg)'; closeBtn.style.color = '#999'; });
    overlay.appendChild(box);
    closeBtn.onclick = (e) => { e.stopPropagation(); hideModal(currentModal); };
    return overlay;
  }
  function createLanguageModal() {
    const overlay = document.createElement('div');
    overlay.id = '__ap_lang_modal';
    overlay.style.cssText = `position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.6); display: none; z-index: 2147483647; justify-content: center; align-items: center; backdrop-filter: blur(4px);`;
    const box = document.createElement('div');
    box.style.cssText = `position: relative; background-color: #2a2a2e; color: #e0e0e0; border-radius: 16px; padding: 40px 28px 28px; box-shadow: 0 4px 6px rgba(0,0,0,0.1), 0 10px 20px rgba(0,0,0,0.4); width: min(90vw, 380px); display: flex; flex-direction: column; border: 1px solid #444; transform: scale(0.95); opacity: 0; transition: transform 0.2s ease-out, opacity 0.2s ease-out;`;
    const buttonsContainer = document.createElement('div');
    buttonsContainer.style.cssText = 'display: flex; flex-direction: column; gap: 12px;';
    Object.keys(translations).forEach(langKey => {
      const btn = document.createElement('button');
      btn.textContent = translations[langKey].langName;
      btn.style.cssText = `padding: 12px 20px; border-radius: 8px; background-color: #3e3e42; color: white; border: 1px solid #555; font-weight: 500; cursor: pointer; transition: all 0.2s ease-in-out; text-align: center;`;
      btn.addEventListener('mouseenter', () => { btn.style.borderColor = '#22c55e'; btn.style.backgroundColor = '#4a4a50'; });
      btn.addEventListener('mouseleave', () => { btn.style.borderColor = '#555'; btn.style.backgroundColor = '#3e3e42'; });
      btn.onclick = async () => {
        await GM_setValue(LANG_STORAGE_KEY, langKey);
        window.location.reload();
      };
      buttonsContainer.appendChild(btn);
    });
    setSafeInnerHTML(box, `
      <button id="__ap_lang_close" aria-label="${getTranslation('close')}" style="position: absolute; top: 5px; right: 5px; background: none; border: none; color: #999; font-size: 22px; cursor: pointer; width: 32px; height: 32px; border-radius: 50%; transition: transform 0.3s ease, color 0.3s ease; display: flex; justify-content: center; align-items: center;">✕</button>
    `);
    box.appendChild(buttonsContainer);
    overlay.appendChild(box);
    const closeBtnLang = box.querySelector('#__ap_lang_close');
    closeBtnLang.onclick = (e) => { e.stopPropagation(); hideModal(languageModal); };
    closeBtnLang.addEventListener('mouseenter', () => { closeBtnLang.style.transform = 'rotate(90deg)'; closeBtnLang.style.color = '#ef4444'; });
    closeBtnLang.addEventListener('mouseleave', () => { closeBtnLang.style.transform = 'rotate(0deg)'; closeBtnLang.style.color = '#999'; });
    return overlay;
  }
  function positionMenu(menu, button) {
    const btnRect = button.getBoundingClientRect();
    const menuHeight = menu.offsetHeight;
    const menuWidth = menu.offsetWidth;
    const viewportHeight = window.innerHeight;
    const viewportWidth = window.innerWidth;
    const margin = 8;
    let top = btnRect.bottom + margin;
    const spaceBelow = viewportHeight - btnRect.bottom;
    const spaceAbove = btnRect.top;
    if (spaceBelow < menuHeight + margin && spaceAbove > menuHeight + margin) { top = btnRect.top - menuHeight - margin; }
    let left = btnRect.left;
    if (left + menuWidth > viewportWidth) { left = viewportWidth - menuWidth - margin; }
    if (top < margin) { top = margin; }
    if (left < margin) { left = margin; }
    menu.style.top = `${top}px`;
    menu.style.left = `${left}px`;
    menu.style.visibility = 'visible';
  }
  function showModal(modal) {
    if (!modal) return;
    modal.style.display = 'flex';
    setTimeout(() => {
      const box = modal.querySelector('div');
      box.style.opacity = '1';
      box.style.transform = 'scale(1)';
    }, 10);
  }
  function hideModal(modal) {
    if (!modal) return;
    const box = modal.querySelector('div');
    box.style.opacity = '0';
    box.style.transform = 'scale(0.95)';
    setTimeout(() => { modal.style.display = 'none'; }, 200);
  }
  function openModal(item = null, index = -1) {
    if (!currentModal) return;
    const isEditing = !!item;
    currentModal.setAttribute('data-index', index);
    document.getElementById('__ap_modal_title').textContent = isEditing ? getTranslation('editPrompt') : getTranslation('newPrompt');
    document.getElementById('__ap_title').value = item?.title || '';
    document.getElementById('__ap_text').value = item?.text || '';
    showModal(currentModal);
    setTimeout(() => { document.getElementById('__ap_title').focus(); }, 100);
  }
  function ensureZaiToolsButtonIsVisible() {
    if (currentPlatform !== 'zai') return;
    setTimeout(() => {
      const referenceIconPath = document.querySelector('svg path[d="M2.6499 4.48322H13.3166"]');
      if (referenceIconPath) {
        const toolsButton = referenceIconPath.closest('button[data-melt-popover-trigger]');
        if (toolsButton && toolsButton.style.display === 'none') {
          toolsButton.removeAttribute('style');
        }
      }
    }, 0);
  }
  function closeMenu() {
    if (currentMenu && currentMenu.getAttribute('data-state') === 'open') {
      currentMenu.setAttribute('data-state', 'closed');
      currentMenu.style.display = 'none';
      currentMenu.style.visibility = 'hidden';
      ensureZaiToolsButtonIsVisible();
    }
  }
  function closeOtherMenus() {
    document.querySelectorAll('[data-state="open"]:not([data-prompts-menu])').forEach(menu => {
      if (menu.setAttribute) {
        menu.setAttribute('data-state', 'closed');
        if (menu.style) menu.style.display = 'none';
      }
    });
  }
  async function refreshMenu() {
    if (!currentMenu) return;
    setSafeInnerHTML(currentMenu, '');
    const promptsListContainer = document.createElement('div');
    promptsListContainer.style.cssText = 'max-height: 190px; overflow-y: auto;';
    const items = await getAll();
    if (!items.length) {
      const empty = document.createElement('div');
      empty.style.cssText = `padding: 8px 16px; color: #A0A0A0; font-size: 13px;`;
      empty.textContent = getTranslation('noSavedPrompts');
      promptsListContainer.appendChild(empty);
    } else {
      items.forEach((p, index) => {
        const row = document.createElement('div');
        row.style.cssText = `display: flex; align-items: center; justify-content: space-between; padding: 8px 12px; border-bottom: 1px solid #626262; cursor: pointer; transition: background-color 0.2s;`;
        row.addEventListener('mouseenter', () => { row.style.backgroundColor = '#424451'; });
        row.addEventListener('mouseleave', () => { row.style.backgroundColor = 'transparent'; });
        const titleDiv = document.createElement('div');
        titleDiv.style.cssText = `font-size: 14px; font-weight: 500; cursor: pointer; flex: 1; padding-right: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: #F8FAFF;`;
        titleDiv.textContent = p.title;
        titleDiv.title = p.title;
        titleDiv.onclick = (e) => { e.stopPropagation(); inserirPrompt(p, index); closeMenu(); };
        row.appendChild(titleDiv);
        const actionsDiv = document.createElement('div');
        actionsDiv.style.cssText = `display: flex; align-items: center; gap: 8px; flex-shrink: 0;`;
        const btnE = document.createElement('button');
        btnE.textContent = getTranslation('edit');
        btnE.title = getTranslation('edit');
        btnE.style.cssText = `background: none; border: none; color: #fbbf24; cursor: pointer; font-size: 12px; padding: 4px 8px; border-radius: 4px; transition: background-color 0.2s;`;
        btnE.addEventListener('mouseenter', () => { btnE.style.backgroundColor = '#92400e'; });
        btnE.addEventListener('mouseleave', () => { btnE.style.backgroundColor = 'transparent'; });
        btnE.onclick = (e) => { e.stopPropagation(); openModal(p, index); };
        actionsDiv.appendChild(btnE);
        const btnD = document.createElement('button');
        btnD.textContent = getTranslation('delete');
        btnD.title = getTranslation('delete');
        btnD.style.cssText = `background: none; border: none; color: #ef4444; cursor: pointer; font-size: 12px; padding: 4px 8px; border-radius: 4px; transition: background-color 0.2s;`;
        btnD.addEventListener('mouseenter', () => { btnD.style.backgroundColor = '#7f1d1d'; });
        btnD.addEventListener('mouseleave', () => { btnD.style.backgroundColor = 'transparent'; });
        btnD.onclick = (e) => { e.stopPropagation(); if (confirm(getTranslation('confirmDelete', { title: p.title }))) { remove(index).then(refreshMenu); } };
        actionsDiv.appendChild(btnD);
        row.appendChild(actionsDiv);
        promptsListContainer.appendChild(row);
      });
    }
    currentMenu.appendChild(promptsListContainer);
    const add = document.createElement('div');
    add.style.cssText = `display: flex; align-items: center; justify-content: center; padding: 8px 12px; cursor: pointer; transition: background-color 0.2s; color: #F8FAFF; border-top: 1px solid #626262;`;
    add.addEventListener('mouseenter', () => { add.style.backgroundColor = '#424451'; });
    add.addEventListener('mouseleave', () => { add.style.backgroundColor = 'transparent'; });
    setSafeInnerHTML(add, `<svg width="16" height="16" fill="currentColor" viewBox="0 0 20 20" style="margin-right: 8px;"><path d="M10 5v10m5-5H5" stroke="currentColor" stroke-width="2"/></svg><span style="font-size: 13px;">${getTranslation('addPrompt')}</span>`);
    add.title = getTranslation('addPrompt');
    add.onclick = (e) => { e.stopPropagation(); openModal(); };
    currentMenu.appendChild(add);
    const importExportHr = document.createElement('hr');
    importExportHr.style.cssText = "border: none; border-top: 1px solid #626262; margin: 0; padding: 0;";
    currentMenu.appendChild(importExportHr);
    const importExportContainer = document.createElement('div');
    importExportContainer.style.cssText = `display: flex; justify-content: space-around; align-items: center;`;
    const exportBtn = createMenuButton(getTranslation('export'));
    exportBtn.onclick = (e) => { e.stopPropagation(); exportPrompts(); };
    const importBtn = createMenuButton(getTranslation('import'));
    importBtn.onclick = (e) => { e.stopPropagation(); importPrompts(); };
    const divider = document.createElement('div');
    divider.style.cssText = "border-left: 1px solid rgb(98, 98, 98); height: 24px;";
    importExportContainer.appendChild(exportBtn);
    importExportContainer.appendChild(divider);
    importExportContainer.appendChild(importBtn);
    currentMenu.appendChild(importExportContainer);
  }
  function createMenuButton(text) {
    const btn = document.createElement('div');
    btn.textContent = text;
    btn.style.cssText = `flex: 1; text-align: center; padding: 8px 12px; cursor: pointer; transition: background-color 0.2s; color: #F8FAFF; font-size: 13px;`;
    btn.addEventListener('mouseenter', () => { btn.style.backgroundColor = '#424451'; });
    btn.addEventListener('mouseleave', () => { btn.style.backgroundColor = 'transparent'; });
    return btn;
  }
  async function exportPrompts() {
    const prompts = await getAll();
    if (prompts.length === 0) { alert(getTranslation('noPromptsToExport')); return; }
    const jsonString = JSON.stringify(prompts, null, 2);
    const blob = new Blob([jsonString], { type: 'application/json' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = getTranslation('fileName');
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
    URL.revokeObjectURL(url);
    closeMenu();
  }
  function importPrompts() {
    const input = document.createElement('input');
    input.type = 'file';
    input.accept = '.json,application/json';
    input.onchange = async (e) => {
      const file = e.target.files[0];
      if (!file) return;
      const reader = new FileReader();
      reader.onload = async (event) => {
        try {
          const importedPrompts = JSON.parse(event.target.result);
          if (!Array.isArray(importedPrompts)) { throw new Error("O arquivo JSON não é um array válido."); }
          const currentPrompts = await getAll();
          const newPrompts = importedPrompts.map((p) => ({ title: p.title || 'Sem Título', text: p.text || '' }));
          await GM_setValue(PROMPT_STORAGE_KEY, [...currentPrompts, ...newPrompts]);
          await refreshMenu();
          alert(getTranslation('promptsImported', { count: newPrompts.length }));
        } catch (error) { alert(getTranslation('errorImporting', { error: error.message })); }
      };
      reader.readAsText(file);
    };
    input.click();
    closeMenu();
  }
  async function inserirPrompt(promptItem, index) {
    const platformSelectors = {
        chatgpt: '#prompt-textarea',
        deepseek: 'textarea[placeholder="Message DeepSeek"]',
        googlestudio: 'ms-autosize-textarea textarea',
        qwen: 'textarea#chat-input',
        zai: 'textarea#chat-input',
        gemini: 'div.ql-editor[contenteditable="true"]',
        lmarena: 'textarea[name="message"]'
    };
    const selector = platformSelectors[currentPlatform];
    const editor = document.querySelector(selector);
    if (!editor) {
        alert(getTranslation('editorNotFound', { platform: currentPlatform }));
        return;
    }
    editor.focus();

    setTimeout(() => {
        if (currentPlatform === 'gemini') {
            let p = editor.querySelector('p');
            if (!p) {
                p = document.createElement('p');
                editor.appendChild(p);
            }
            p.textContent = promptItem.text;
            editor.dispatchEvent(new Event('input', { bubbles: true, composed: true }));
        } else {
            const dataTransfer = new DataTransfer();
            dataTransfer.setData('text/plain', promptItem.text);
            editor.dispatchEvent(new ClipboardEvent('paste', {
                clipboardData: dataTransfer,
                bubbles: true,
                cancelable: true
            }));
            if (editor.value !== promptItem.text) {
                const nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype, 'value').set;
                nativeInputValueSetter.call(editor, promptItem.text);
                editor.dispatchEvent(new Event('input', { bubbles: true }));
            }
        }
    }, 50);

    let prompts = await getAll();
    if (index > 0) {
        const item = prompts.splice(index, 1)[0];
        prompts.unshift(item);
        await GM_setValue(PROMPT_STORAGE_KEY, prompts);
    }
  }
  function cleanup() {
    if (currentButton) { currentButton.remove(); currentButton = null; }
    if (currentMenu) { currentMenu.remove(); currentMenu = null; }
    if (currentModal) { currentModal.remove(); currentModal = null; }
    if (languageModal) { languageModal.remove(); languageModal = null; }
    isInitialized = false;
  }
  async function initUI() {
    if (pageObserver) pageObserver.disconnect();
    cleanup();
    currentPlatform = detectPlatform();
    if (!currentPlatform) return;
    try {
      let btn, elementToInsert, insertionPoint, insertionMethod = 'before';
      if (currentPlatform === 'chatgpt') {
        insertionPoint = await waitFor('div[class*="[grid-area:leading]"]').catch(() => null);
        if (insertionPoint) {
          insertionPoint.style.display = 'flex';
          insertionPoint.style.flexDirection = 'row';
          insertionPoint.style.alignItems = 'center';
          insertionPoint.style.gap = '8px';
          btn = createChatGPTButton();
          elementToInsert = btn;
          insertionMethod = 'append';
        }
      } else if (currentPlatform === 'deepseek') {
        const buttonsContainer = await waitFor('.ec4f5d61');
        const referenceButton = buttonsContainer.querySelector('button:has(span._6dbc175)');
        insertionPoint = buttonsContainer.querySelector('.bf38813a');
        if (!referenceButton || !insertionPoint) { throw new Error('Elementos da UI do DeepSeek não encontrados.'); }
        btn = createDeepSeekButton();
        btn.className = referenceButton.className;
        elementToInsert = btn;
        insertionMethod = 'before';
      } else if (currentPlatform === 'googlestudio') {
        insertionPoint = await waitFor('ms-add-chunk-menu', 5000).then(el => el.closest('.button-wrapper')).catch(() => null);
        if (insertionPoint) {
          const wrapper = document.createElement('div');
          wrapper.className = 'button-wrapper';
          btn = createGoogleStudioButton();
          wrapper.appendChild(btn);
          elementToInsert = wrapper;
          insertionMethod = 'before';
          const parentContainer = insertionPoint.closest('.prompt-input-wrapper-container');
          if (parentContainer) { parentContainer.style.alignItems = 'center'; }
        }
      } else if (currentPlatform === 'qwen') {
        insertionPoint = await waitFor('button.websearch_button', 5000).catch(() => null);
        if (insertionPoint) {
          btn = createQwenButton();
          elementToInsert = btn;
          insertionMethod = 'after';
        }
      } else if (currentPlatform === 'zai') {
        const referenceIconPath = await waitFor('svg path[d="M2.6499 4.48322H13.3166"]', 8000).catch(() => null);
        if (referenceIconPath) {
          insertionPoint = referenceIconPath.closest('button[data-melt-popover-trigger]');
          if (insertionPoint) {
            btn = createZaiButton();
            elementToInsert = btn;
            insertionMethod = 'after';
          }
        }
      } else if (currentPlatform === 'gemini') {
        insertionPoint = await waitFor('button.upload-card-button', 8000).catch(() => null);
        if (insertionPoint) {
            btn = createGeminiButton();
            elementToInsert = btn;
            insertionMethod = 'after';
            const wrapper = insertionPoint.closest('div.leading-actions-wrapper');
            if (wrapper) {
                wrapper.style.display = 'flex';
                wrapper.style.alignItems = 'center';
                wrapper.style.gap = '8px';
            }
        }
      } else if (currentPlatform === 'lmarena') {
        insertionPoint = await waitFor('div[data-sentry-component="SelectChatModality"]', 8000).catch(() => null);
        if (insertionPoint) {
            btn = createLmarenaButton();
            elementToInsert = btn;
            insertionMethod = 'append';
        }
      }
      if (!btn || !insertionPoint) {
        return;
      }
      currentButton = elementToInsert;
      const clickableElement = btn;
      currentMenu = createMenu();
      currentModal = createModal();
      languageModal = createLanguageModal();
      if (insertionMethod === 'append') {
        insertionPoint.appendChild(elementToInsert);
      } else if (insertionMethod === 'before') {
        insertionPoint.parentNode.insertBefore(elementToInsert, insertionPoint);
      } else {
        insertionPoint.parentNode.insertBefore(elementToInsert, insertionPoint.nextSibling);
      }
      document.body.appendChild(currentMenu);
      document.body.appendChild(currentModal);
      document.body.appendChild(languageModal);
      clickableElement.addEventListener('click', e => {
        e.stopPropagation();
        e.preventDefault();
        if (currentMenu.getAttribute('data-state') === 'open') {
          closeMenu();
          return;
        }
        closeOtherMenus();
        ensureZaiToolsButtonIsVisible();
        currentMenu.style.display = 'flex';
        currentMenu.style.visibility = 'hidden';
        refreshMenu().then(() => {
          setTimeout(() => {
            positionMenu(currentMenu, clickableElement);
            currentMenu.setAttribute('data-state', 'open');
          }, 10);
        });
      });
      currentModal.querySelector('#__ap_save').onclick = (e) => {
        e.stopPropagation();
        const indexStr = currentModal.getAttribute('data-index');
        const index = indexStr !== '-1' ? Number(indexStr) : -1;
        const title = document.getElementById('__ap_title').value.trim();
        const text = document.getElementById('__ap_text').value.trim();
        if (!title || !text) { alert(getTranslation('requiredFields')); return; }
        const item = { title, text };
        const op = index > -1 ? update(index, item) : addItem(item);
        op.then(() => { hideModal(currentModal); refreshMenu(); });
      };
      isInitialized = true;
    } catch (error) {
      cleanup();
    } finally {
      setupPageObserver();
    }
  }
  function setupGlobalEventListeners() {
    document.addEventListener('click', ev => {
      if (!currentMenu || !currentButton) return;
      if (ev.target.closest('[data-prompts-menu],[data-testid="composer-button-prompts"],[data-prompts-modal]')) return;
      closeMenu();
    });
    document.addEventListener('keydown', ev => {
      if (ev.key === 'Escape') {
        closeMenu();
        if (currentModal && currentModal.style.display === 'flex') { hideModal(currentModal); }
        if (languageModal && languageModal.style.display === 'flex') { hideModal(languageModal); }
      }
    });
    window.addEventListener('resize', debounce(() => {
      if (currentMenu && currentMenu.getAttribute('data-state') === 'open') {
        const clickable = currentButton.hasAttribute('data-testid') ? currentButton : currentButton.querySelector('[data-testid="composer-button-prompts"]');
        if (clickable) positionMenu(currentMenu, clickable);
      }
    }, 100));
  }
  function registerLanguageMenu() {
    GM_registerMenuCommand(getTranslation('languageSettings'), () => {
      if (!languageModal) {
        languageModal = createLanguageModal();
        document.body.appendChild(languageModal);
      }
      showModal(languageModal);
    });
  }
  const debouncedTryInit = debounce(tryInit, 500);
  function setupPageObserver() {
    if (pageObserver) pageObserver.disconnect();
    pageObserver = new MutationObserver(() => {
      if (!document.body.contains(currentButton)) {
        debouncedTryInit();
      }
    });
    pageObserver.observe(document.body, { childList: true, subtree: true });
  }
  function tryInit() {
    if (isInitializing) return;
    if (isInitialized && currentButton && document.body.contains(currentButton) && currentPlatform === detectPlatform()) {
      return;
    }
    isInitializing = true;
    initUI().catch(()=> {
    }).finally(() => {
      isInitializing = false;
    });
  }
  async function start() {
    await determineLanguage();
    setupGlobalEventListeners();
    registerLanguageMenu();
    tryInit();
  }
  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', start);
  } else {
    start();
  }
})();