- // ==UserScript==
- // @name Promptimizer
- // @namespace https://github.com/NoahTheGinger/Promptimizer/
- // @version 1.2
- // @description AI-powered prompt optimization tool that works with OpenAI-compatible APIs
- // @author NoahTheGinger
- // @namespace https://github.com/NoahTheGinger/Promptimizer/
- // @match *://*/*
- // @license MIT
- // @grant GM_xmlhttpRequest
- // @grant GM_setValue
- // @grant GM_getValue
- // @grant GM_addStyle
- // ==/UserScript==
-
- (function() {
- 'use strict';
-
- // Styles for the UI
- GM_addStyle(`
- #promptimizer-container {
- position: fixed;
- /*
- UI CHANGE:
- Default position now near bottom-right.
- This corresponds with the toggle's new position in the bottom-right corner.
- */
- bottom: 80px;
- right: 20px;
- width: 400px;
- height: auto; /* Let container height auto-adjust initially */
- background: #ffffff;
- border-radius: 8px;
- box-shadow: 0 2px 10px rgba(0,0,0,0.3);
- z-index: 2147483647;
- font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
- display: none;
- color: #000000;
- /* UI CHANGE: Added transform and opacity transitions for smoother show/hide + repositioning. */
- transition:
- opacity 0.2s ease,
- width 0.2s ease,
- height 0.2s ease,
- top 0.2s ease,
- left 0.2s ease,
- right 0.2s ease,
- bottom 0.2s ease;
- overflow: hidden;
- min-height: 300px;
- min-width: 300px;
- opacity: 0; /* For fade effect upon showing */
- }
- /* UI CHANGE: A "show" class that toggles visibility with a fade */
- #promptimizer-container.show {
- opacity: 1;
- }
-
- #promptimizer-header {
- padding: 12px;
- background: #2196F3;
- border-radius: 8px 8px 0 0;
- cursor: move;
- display: flex;
- justify-content: space-between;
- align-items: center;
- color: #ffffff;
- user-select: none; /* UI CHANGE: Prevent text selection while dragging header */
- }
-
- #promptimizer-header-controls {
- display: flex;
- gap: 12px;
- align-items: center;
- }
-
- .header-button {
- background: none;
- border: none;
- color: #ffffff;
- cursor: pointer;
- font-size: 16px;
- padding: 0;
- display: flex;
- align-items: center;
- opacity: 0.8;
- transition: opacity 0.2s;
- }
-
- .header-button:hover {
- opacity: 1;
- }
-
- #promptimizer-title {
- margin: 0;
- font-size: 16px;
- font-weight: bold;
- color: #ffffff;
- }
-
- #promptimizer-toggle {
- position: fixed;
- /*
- UI CHANGE:
- Toggle button now in bottom-right corner.
- */
- bottom: 20px;
- right: 20px;
- width: 50px;
- height: 50px;
- background: #2196F3;
- border-radius: 25px;
- color: white;
- display: flex;
- align-items: center;
- justify-content: center;
- cursor: pointer;
- font-size: 24px;
- box-shadow: 0 2px 5px rgba(0,0,0,0.2);
- z-index: 2147483647;
- border: 2px solid rgba(255,255,255,0.2);
- }
-
- #promptimizer-content {
- display: flex;
- flex-direction: column;
- background: #ffffff;
- overflow: hidden;
- max-height: calc(100% - 48px);
- }
-
- .scrollable-flex {
- overflow-y: auto;
- flex: 1;
- padding: 16px;
- }
-
- .promptimizer-input {
- width: 100%;
- padding: 8px;
- margin-bottom: 10px;
- border: 1px solid #ddd;
- border-radius: 4px;
- box-sizing: border-box;
- background: #ffffff;
- color: #000000;
- }
-
- textarea.promptimizer-input {
- resize: none;
- min-height: 100px;
- transition: border-color 0.2s ease, box-shadow 0.2s ease;
- overflow-y: auto;
- }
-
- textarea.promptimizer-input:focus {
- border-color: #2196F3;
- box-shadow: 0 0 0 2px rgba(33, 150, 243, 0.2);
- outline: none;
- }
-
- .prompt-type-select {
- width: 100%;
- padding: 8px;
- margin-bottom: 10px;
- border: 1px solid #ddd;
- border-radius: 4px;
- background: #ffffff;
- color: #000000;
- font-size: 14px;
- cursor: pointer;
- }
-
- .prompt-type-select:focus {
- border-color: #2196F3;
- outline: none;
- }
-
- .input-group {
- margin-bottom: 16px;
- }
-
- .input-label {
- display: block;
- margin-bottom: 6px;
- color: #000000;
- font-size: 14px;
- font-weight: 500;
- }
-
- .promptimizer-button {
- background: #2196F3;
- color: white;
- border: none;
- padding: 8px 16px;
- border-radius: 4px;
- cursor: pointer;
- font-size: 14px;
- margin-bottom: 10px;
- width: 100%;
- }
-
- .promptimizer-button:hover {
- background: #1976D2;
- }
-
- #promptimizer-response-container {
- position: relative;
- margin-top: 16px;
- }
-
- #promptimizer-response {
- margin-top: 0;
- padding: 12px;
- background: #f8f9fa;
- border-radius: 4px;
- white-space: pre-wrap;
- max-height: 300px;
- overflow-y: auto;
- color: #000000;
- border: 1px solid #e9ecef;
- }
-
- #copy-button {
- position: absolute;
- top: 8px;
- right: 8px;
- background: #2196F3;
- color: white;
- border: none;
- border-radius: 4px;
- padding: 4px 8px;
- font-size: 12px;
- cursor: pointer;
- opacity: 0;
- transition: opacity 0.2s;
- z-index: 1;
- }
-
- #copy-button:hover {
- background: #1976D2;
- }
-
- #copy-button.visible {
- opacity: 1;
- }
-
- #copy-button.copied {
- background: #4CAF50;
- }
-
- .promptimizer-error {
- color: #dc3545;
- margin-top: 8px;
- font-size: 14px;
- background: #fff;
- padding: 8px;
- border-radius: 4px;
- }
-
- .config-section {
- margin-bottom: 15px;
- overflow: hidden;
- transition: max-height 0.3s ease-out;
- }
-
- .config-section.collapsed {
- max-height: 40px;
- }
-
- .config-section.expanded {
- max-height: 300px;
- }
-
- .config-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- cursor: pointer;
- padding: 8px 0;
- }
-
- .config-header h3 {
- margin: 0;
- font-size: 16px;
- color: #333;
- }
-
- .config-toggle {
- font-size: 18px;
- color: #666;
- transition: transform 0.3s;
- }
-
- .config-toggle.collapsed {
- transform: rotate(-90deg);
- }
-
- .config-content {
- transition: opacity 0.3s;
- }
-
- .config-content.collapsed {
- opacity: 0;
- height: 0;
- overflow: hidden;
- }
-
- .config-content.expanded {
- opacity: 1;
- height: auto;
- }
-
- /*
- UI CHANGE:
- Previously, only top-left resizing was available (.resize-handle-left, .resize-handle-top, .resize-handle-corner).
- Now we add handles on all sides + both corners (top-left & bottom-right) for a more standard resizing experience.
- */
- .resize-handle {
- position: absolute;
- background: transparent;
- z-index: 10;
- }
- /* Existing top-left handles */
- .resize-handle-left {
- cursor: ew-resize;
- width: 8px;
- height: 100%;
- left: 0;
- top: 0;
- }
- .resize-handle-top {
- cursor: ns-resize;
- height: 8px;
- width: 100%;
- top: 0;
- left: 0;
- }
- .resize-handle-corner {
- cursor: nwse-resize;
- width: 14px;
- height: 14px;
- left: 0;
- top: 0;
- }
-
- /* NEW bottom-right corner handle */
- .resize-handle-corner-br {
- cursor: nwse-resize;
- width: 14px;
- height: 14px;
- right: 0;
- bottom: 0;
- }
- /* NEW right-only handle */
- .resize-handle-right {
- cursor: ew-resize;
- width: 8px;
- height: 100%;
- top: 0;
- right: 0;
- }
- /* NEW bottom-only handle */
- .resize-handle-bottom {
- cursor: ns-resize;
- height: 8px;
- width: 100%;
- bottom: 0;
- left: 0;
- }
-
- #promptimizer-container.resizing {
- transition: none;
- box-shadow: 0 2px 15px rgba(33, 150, 243, 0.4);
- }
-
- #promptimizer-container.resizing-left {
- border-left: 2px solid #2196F3;
- }
- #promptimizer-container.resizing-top {
- border-top: 2px solid #2196F3;
- }
- #promptimizer-container.resizing-corner {
- border-left: 2px solid #2196F3;
- border-top: 2px solid #2196F3;
- }
-
- /* UI CHANGE: Additional highlighting classes for new handles. */
- #promptimizer-container.resizing-right {
- border-right: 2px solid #2196F3;
- }
- #promptimizer-container.resizing-bottom {
- border-bottom: 2px solid #2196F3;
- }
- #promptimizer-container.resizing-corner-br {
- border-right: 2px solid #2196F3;
- border-bottom: 2px solid #2196F3;
- }
- `);
-
- // Default dimensions and position
- const defaultDimensions = {
- // UI CHANGE: Adjusted to bottom-right defaults
- width: '400px',
- height: 'auto',
- bottom: '80px',
- right: '20px'
- };
-
- // Create UI elements
- function createUI() {
- // Toggle button
- const toggle = document.createElement('div');
- toggle.id = 'promptimizer-toggle';
- toggle.innerHTML = '✨';
- toggle.title = 'Toggle Promptimizer';
- document.body.appendChild(toggle);
-
- // Main container
- const container = document.createElement('div');
- container.id = 'promptimizer-container';
- container.innerHTML = `
- <div id="promptimizer-header">
- <h2 id="promptimizer-title">Promptimizer</h2>
- <div id="promptimizer-header-controls">
- <button class="header-button" id="promptimizer-reset" title="Reset UI Position and Size">↺</button>
- <button class="header-button" id="promptimizer-minimize" title="Minimize">−</button>
- </div>
- </div>
- <div id="promptimizer-content">
- <div class="scrollable-flex">
- <div class="config-section expanded" id="config-section">
- <div class="config-header" id="config-header">
- <h3>API Configuration</h3>
- <span class="config-toggle">▼</span>
- </div>
- <div class="config-content expanded">
- <input type="text" id="api-url" class="promptimizer-input" placeholder="API URL (e.g., https://api.openai.com/v1)" />
- <input type="password" id="api-key" class="promptimizer-input" placeholder="API Key" />
- <input type="text" id="model-name" class="promptimizer-input" placeholder="Model name" />
- <input type="text" id="provider-name" class="promptimizer-input" placeholder="Provider name (optional, for gpt4free)" />
- <button id="save-config" class="promptimizer-button">Save Configuration</button>
- </div>
- </div>
- <div class="input-group">
- <label class="input-label" for="prompt-type">Prompt Type:</label>
- <select id="prompt-type" class="prompt-type-select">
- <option value="user">User Prompt</option>
- <option value="system">System Prompt</option>
- </select>
- </div>
- <div class="input-group">
- <label class="input-label" for="prompt-input">Enter Your Prompt:</label>
- <textarea id="prompt-input" class="promptimizer-input" rows="4" placeholder="Enter your prompt here..."></textarea>
- </div>
- <button id="optimize-button" class="promptimizer-button">Optimize Prompt</button>
- <div id="promptimizer-response-container">
- <button id="copy-button" style="display: none;">Copy Enhanced Prompt</button>
- <div id="promptimizer-response"></div>
- </div>
- </div>
- </div>
- <!-- UI CHANGE: A complete set of resize handles: top-left corner, top, left, bottom-right corner, right, bottom. -->
- <div class="resize-handle resize-handle-left"></div>
- <div class="resize-handle resize-handle-top"></div>
- <div class="resize-handle resize-handle-corner"></div>
- <div class="resize-handle resize-handle-right"></div>
- <div class="resize-handle resize-handle-bottom"></div>
- <div class="resize-handle resize-handle-corner-br"></div>
- `;
- document.body.appendChild(container);
-
- // Make the container draggable (UI only)
- makeDraggable(container);
-
- // Add container resizing
- makeResizable(container);
-
- // Load saved configuration
- loadConfiguration();
-
- // Event listeners
- // UI CHANGE: Now using a smoother show/hide approach with fade
- toggle.addEventListener('click', () => {
- if (container.style.display === 'none' || container.style.display === '') {
- container.style.display = 'block';
- // Force reflow, then add .show for fade-in
- requestAnimationFrame(() => container.classList.add('show'));
- } else {
- // Remove .show for fade-out
- container.classList.remove('show');
- // Wait for transition to complete, then hide
- setTimeout(() => {
- if (!container.classList.contains('show')) {
- container.style.display = 'none';
- }
- }, 200);
- }
- });
-
- document.getElementById('promptimizer-minimize').addEventListener('click', () => {
- // Fade out on minimize
- container.classList.remove('show');
- setTimeout(() => {
- if (!container.classList.contains('show')) {
- container.style.display = 'none';
- }
- }, 200);
- });
-
- // Config section toggle
- const configHeader = document.getElementById('config-header');
- const configSection = document.getElementById('config-section');
- const configToggle = configHeader.querySelector('.config-toggle');
- const configContent = configSection.querySelector('.config-content');
-
- configHeader.addEventListener('click', () => {
- const isExpanded = configSection.classList.contains('expanded');
-
- if (isExpanded) {
- configSection.classList.remove('expanded');
- configSection.classList.add('collapsed');
- configContent.classList.remove('expanded');
- configContent.classList.add('collapsed');
- configToggle.classList.add('collapsed');
- } else {
- configSection.classList.remove('collapsed');
- configSection.classList.add('expanded');
- configContent.classList.remove('collapsed');
- configContent.classList.add('expanded');
- configToggle.classList.remove('collapsed');
- }
- });
-
- document.getElementById('save-config').addEventListener('click', saveConfiguration);
- document.getElementById('optimize-button').addEventListener('click', optimizePrompt);
- document.getElementById('copy-button').addEventListener('click', copyEnhancedPrompt);
-
- // Initialize auto-height for textarea
- const textarea = document.getElementById('prompt-input');
- if (textarea) {
- autoResizeTextarea(textarea);
- textarea.addEventListener('input', function() {
- autoResizeTextarea(this);
- });
- }
- }
-
- // Make an element draggable (UI only; no functional logic changed)
- function makeDraggable(element) {
- const header = element.querySelector('#promptimizer-header');
- let isDragging = false;
- let startX, startY, offsetX, offsetY;
-
- // Function to reset position and size
- function resetPosition() {
- // Remove transform usage; set position explicitly
- element.style.width = defaultDimensions.width;
- element.style.height = defaultDimensions.height;
- element.style.bottom = defaultDimensions.bottom;
- element.style.right = defaultDimensions.right;
- element.style.top = 'auto';
- element.style.left = 'auto';
-
- // Reset any set textarea dimensions
- const textarea = document.getElementById('prompt-input');
- if (textarea) {
- textarea.style.height = '';
- autoResizeTextarea(textarea);
- }
- }
-
- // Add reset button event listener
- document.getElementById('promptimizer-reset').addEventListener('click', (e) => {
- e.stopPropagation(); // Prevent initiating a drag
- resetPosition();
- });
-
- header.addEventListener('mousedown', dragStart);
- document.addEventListener('mousemove', drag);
- document.addEventListener('mouseup', dragEnd);
-
- function dragStart(e) {
- if (e.target.closest('.header-button')) {
- return;
- }
- isDragging = true;
- // Compute how far from the element's top-left corner the pointer is
- const rect = element.getBoundingClientRect();
- startX = rect.left;
- startY = rect.top;
- offsetX = e.clientX - startX;
- offsetY = e.clientY - startY;
-
- // Disable transition during actual drag for a crisper effect
- element.style.transition = 'none';
- }
-
- function drag(e) {
- if (!isDragging) return;
- e.preventDefault();
-
- // Figure out the new top-left based on pointer
- let newLeft = e.clientX - offsetX;
- let newTop = e.clientY - offsetY;
-
- // Keep within viewport, if desired
- const rect = element.getBoundingClientRect();
- const w = rect.width;
- const h = rect.height;
- const vw = window.innerWidth;
- const vh = window.innerHeight;
-
- // Adjust so it won't go offscreen
- if (newLeft < 0) newLeft = 0;
- if (newTop < 0) newTop = 0;
- if (newLeft + w > vw) newLeft = vw - w;
- if (newTop + h > vh) newTop = vh - h;
-
- // Clear bottom/right so we can use top/left
- element.style.bottom = 'auto';
- element.style.right = 'auto';
-
- // Apply new position
- element.style.left = newLeft + 'px';
- element.style.top = newTop + 'px';
- }
-
- function dragEnd() {
- isDragging = false;
- // Re-enable transitions for nice layout changes after drag
- element.style.transition =
- 'opacity 0.2s ease, width 0.2s ease, height 0.2s ease, top 0.2s ease, left 0.2s ease, right 0.2s ease, bottom 0.2s ease';
- }
-
- // Initialize at default bottom-right position
- resetPosition();
- }
-
- // Make container resizable (UI only)
- function makeResizable(container) {
- const leftHandle = container.querySelector('.resize-handle-left');
- const topHandle = container.querySelector('.resize-handle-top');
- const cornerTLHandle = container.querySelector('.resize-handle-corner'); // top-left corner
- // UI CHANGE: Additional handles
- const rightHandle = container.querySelector('.resize-handle-right');
- const bottomHandle = container.querySelector('.resize-handle-bottom');
- const cornerBRHandle = container.querySelector('.resize-handle-corner-br');
-
- let isResizing = false;
- let currentResizeType = '';
- let startX, startY, startWidth, startHeight, startTop, startLeft, startBottom, startRight;
-
- function startResize(e, type) {
- e.preventDefault();
- e.stopPropagation();
-
- isResizing = true;
- currentResizeType = type;
-
- const rect = container.getBoundingClientRect();
- startWidth = rect.width;
- startHeight = rect.height;
- startTop = rect.top;
- startLeft = rect.left;
- startBottom = window.innerHeight - rect.bottom; // distance from bottom to viewport
- startRight = window.innerWidth - rect.right; // distance from right to viewport
- startX = e.clientX;
- startY = e.clientY;
-
- container.classList.add('resizing');
- container.classList.add(`resizing-${type}`);
-
- document.addEventListener('mousemove', resize);
- document.addEventListener('mouseup', stopResize);
-
- // Disable transitions during actual resize
- container.style.transition = 'none';
- }
-
- function resize(e) {
- if (!isResizing) return;
-
- let newWidth = startWidth;
- let newHeight = startHeight;
- let newTop = startTop;
- let newLeft = startLeft;
- let newRight = startRight;
- let newBottom = startBottom;
-
- const dx = e.clientX - startX;
- const dy = e.clientY - startY;
-
- switch (currentResizeType) {
- case 'left':
- newWidth = startWidth - dx;
- newLeft = startLeft + dx;
- break;
- case 'top':
- newHeight = startHeight - dy;
- newTop = startTop + dy;
- break;
- case 'corner': // top-left corner
- newWidth = startWidth - dx;
- newHeight = startHeight - dy;
- newLeft = startLeft + dx;
- newTop = startTop + dy;
- break;
- // UI CHANGE: Additional cases for new handles
- case 'right':
- // Resizing from the right edge outward
- newWidth = startWidth + dx;
- break;
- case 'bottom':
- // Resizing from the bottom edge downward
- newHeight = startHeight + dy;
- break;
- case 'corner-br': // bottom-right corner
- newWidth = startWidth + dx;
- newHeight = startHeight + dy;
- break;
- }
-
- // Enforce minimum dimensions
- if (newWidth < 300) {
- newWidth = 300;
- // If resizing from left or top-left corner, shift left to keep min width
- if (['left','corner'].includes(currentResizeType)) {
- newLeft = startLeft + (startWidth - 300);
- }
- // If resizing from right or bottom-right corner, we just clamp
- }
- if (newHeight < 300) {
- newHeight = 300;
- // If resizing from top or top-left corner, shift top
- if (['top','corner'].includes(currentResizeType)) {
- newTop = startTop + (startHeight - 300);
- }
- }
-
- // Keep within viewport (optional)
- const vw = window.innerWidth;
- const vh = window.innerHeight;
- if (['left','corner'].includes(currentResizeType) && newLeft < 0) {
- newLeft = 0;
- }
- if (['top','corner'].includes(currentResizeType) && newTop < 0) {
- newTop = 0;
- }
- if (['right','corner-br'].includes(currentResizeType) && (startLeft + newWidth > vw)) {
- newWidth = vw - startLeft;
- }
- if (['bottom','corner-br'].includes(currentResizeType) && (startTop + newHeight > vh)) {
- newHeight = vh - startTop;
- }
-
- // Apply geometry. For bottom/right-based resizing, keep the container's top/left unless
- // we're specifically resizing from top or left.
- container.style.width = newWidth + 'px';
- container.style.height = newHeight + 'px';
-
- // If resizing from left or top or top-left corner, update top/left explicitly
- if (['left','top','corner'].includes(currentResizeType)) {
- container.style.left = newLeft + 'px';
- container.style.top = newTop + 'px';
- // Clear bottom/right so they won't conflict
- container.style.bottom = 'auto';
- container.style.right = 'auto';
- }
- }
-
- function stopResize() {
- isResizing = false;
- container.classList.remove('resizing');
- container.classList.remove(`resizing-${currentResizeType}`);
-
- document.removeEventListener('mousemove', resize);
- document.removeEventListener('mouseup', stopResize);
-
- // Re-enable transitions
- container.style.transition =
- 'opacity 0.2s ease, width 0.2s ease, height 0.2s ease, top 0.2s ease, left 0.2s ease, right 0.2s ease, bottom 0.2s ease';
- }
-
- leftHandle.addEventListener('mousedown', (e) => startResize(e, 'left'));
- topHandle.addEventListener('mousedown', (e) => startResize(e, 'top'));
- cornerTLHandle.addEventListener('mousedown', (e) => startResize(e, 'corner'));
- // UI CHANGE: New handles
- rightHandle.addEventListener('mousedown', (e) => startResize(e, 'right'));
- bottomHandle.addEventListener('mousedown', (e) => startResize(e, 'bottom'));
- cornerBRHandle.addEventListener('mousedown', (e) => startResize(e, 'corner-br'));
- }
-
- // Helper function to auto-resize textarea based on content
- function autoResizeTextarea(textarea) {
- // Save scroll position
- const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
- // Reset height temporarily to get accurate scrollHeight
- textarea.style.height = 'auto';
- // Set new height based on content (with minimum)
- const newHeight = Math.max(textarea.scrollHeight, 100) + 'px';
- textarea.style.transition = 'height 0.15s ease-out';
- textarea.style.height = newHeight;
- // Restore scroll position to prevent page jump
- window.scrollTo(0, scrollTop);
- }
-
- // Save API configuration
- function saveConfiguration() {
- const apiUrl = document.getElementById('api-url').value;
- const apiKey = document.getElementById('api-key').value;
- const modelName = document.getElementById('model-name').value;
- const providerName = document.getElementById('provider-name').value;
-
- GM_setValue('apiUrl', apiUrl);
- GM_setValue('apiKey', apiKey);
- GM_setValue('modelName', modelName);
- GM_setValue('providerName', providerName);
-
- showResponse('Configuration saved!');
- }
-
- // Load saved configuration
- function loadConfiguration() {
- const apiUrl = GM_getValue('apiUrl', '');
- const apiKey = GM_getValue('apiKey', '');
- const modelName = GM_getValue('modelName', '');
- const providerName = GM_getValue('providerName', '');
-
- document.getElementById('api-url').value = apiUrl;
- document.getElementById('api-key').value = apiKey;
- document.getElementById('model-name').value = modelName;
- document.getElementById('provider-name').value = providerName;
- }
-
- // Show response or error message
- function showResponse(message, isError = false) {
- const responseDiv = document.getElementById('promptimizer-response');
- const copyButton = document.getElementById('copy-button');
- responseDiv.textContent = message;
- responseDiv.className = isError ? 'promptimizer-error' : '';
-
- if (!isError && message !== 'Optimizing prompt...') {
- copyButton.style.display = 'block';
- setTimeout(() => copyButton.classList.add('visible'), 10);
- } else {
- copyButton.style.display = 'none';
- copyButton.classList.remove('visible');
- }
- }
-
- // Extract enhanced prompt from response
- function extractEnhancedPrompt(text) {
- const match = text.match(/<enhanced_prompt>([\s\S]*?)<\/enhanced_prompt>/);
- return match ? match[1].trim() : text;
- }
-
- // Copy enhanced prompt to clipboard
- function copyEnhancedPrompt() {
- const responseDiv = document.getElementById('promptimizer-response');
- const copyButton = document.getElementById('copy-button');
- const textToCopy = extractEnhancedPrompt(responseDiv.textContent);
-
- navigator.clipboard.writeText(textToCopy).then(() => {
- copyButton.textContent = 'Copied!';
- copyButton.classList.add('copied');
- setTimeout(() => {
- copyButton.textContent = 'Copy Enhanced Prompt';
- copyButton.classList.remove('copied');
- }, 2000);
- }).catch(err => {
- console.error('Failed to copy text: ', err);
- });
- }
-
- // Optimize prompt using the API
- async function optimizePrompt() {
- const apiUrl = GM_getValue('apiUrl', '');
- const apiKey = GM_getValue('apiKey', '');
- const modelName = GM_getValue('modelName', '');
- const providerName = GM_getValue('providerName', '');
- const promptType = document.getElementById('prompt-type').value;
- const promptInput = document.getElementById('prompt-input').value;
-
- if (!apiUrl || !apiKey || !modelName) {
- showResponse('Please configure API settings first!', true);
- return;
- }
-
- if (!promptInput.trim()) {
- showResponse('Please enter a prompt to optimize!', true);
- return;
- }
-
- showResponse('Optimizing prompt...');
-
- const systemPrompt = `You are a specialized prompt optimization AI focused on enhancing both user prompts and system prompts for AI interactions.
-
- <instructions>
- 1. You will receive prompts marked with either <user_prompt> or <system_prompt> tags
- 2. ALWAYS maintain the same type of prompt in your enhancement
- 3. NEVER engage in conversation or provide explanations
- 4. ONLY return the enhanced prompt within <enhanced_prompt> tags
- 5. Apply appropriate prompt engineering techniques based on the prompt type:
-
- For User Prompts:
- - Maintain conversational context and flow
- - Clarify user intent and expectations
- - Add specific parameters for the response
- - Include relevant context from prior conversation
- - Structure multi-part requests clearly
-
- For System Prompts:
- - Define clear roles and responsibilities
- - Establish behavioral boundaries
- - Include success criteria and constraints
- - Structure hierarchical instructions
- - Define interaction patterns
- - Specify output formats and preferences
- - Include error handling instructions
- </instructions>
-
- <examples>
- <example>
- <input_type>user_prompt</input_type>
- <input>Thanks for your help! Can you search the web for more information about this topic?</input>
- <enhanced_prompt>Please conduct a comprehensive web search on our current topic with the following parameters:
- 1. Focus on authoritative sources from the last 2 years
- 2. Include academic and expert perspectives
- 3. Compare and contrast different viewpoints
- 4. Identify emerging trends and developments
- 5. Extract key insights and practical applications
-
- Format the response with:
- - Main findings in bullet points
- - Source citations for each major claim
- - Relevance assessment for each source
- - Synthesis of conflicting information
- - Suggestions for further research</enhanced_prompt>
- </example>
-
- <example>
- <input_type>system_prompt</input_type>
- <input>You are a web search AI assistant. Your role is to help users find information.</input>
- <enhanced_prompt>You are a specialized web search AI assistant designed to provide comprehensive, accurate, and well-structured information retrieval services.
-
- Core Responsibilities:
- 1. Execute precise web searches based on user queries
- 2. Evaluate source credibility and relevance
- 3. Synthesize information from multiple sources
- 4. Present findings in clear, structured formats
-
- Behavioral Guidelines:
- - Maintain objectivity in information presentation
- - Clearly distinguish between facts and interpretations
- - Acknowledge information gaps or uncertainties
- - Proactively suggest related topics for exploration
-
- Output Requirements:
- 1. Structure all responses with:
- - Executive summary
- - Detailed findings
- - Source citations
- - Confidence levels
- 2. Use formatting for clarity:
- - Bullet points for key facts
- - Tables for comparisons
- - Markdown for emphasis
- - Hierarchical headings
-
- Error Handling:
- - Acknowledge when information is outdated
- - Flag potential misinformation
- - Suggest alternative search strategies
- - Provide confidence levels for findings</enhanced_prompt>
- </example>
- </examples>
-
- <success_criteria>
- For User Prompts:
- - Enhanced clarity and specificity
- - Maintained conversation context
- - Clear parameters for response
- - Structured multi-part requests
- - Defined output preferences
-
- For System Prompts:
- - Clear role definition
- - Comprehensive behavioral guidelines
- - Specific output requirements
- - Error handling procedures
- - Interaction patterns defined
- </success_criteria>`;
-
- // Wrap the input with appropriate type tags
- const taggedInput = `<${promptType}_prompt>${promptInput}</${promptType}_prompt>`;
-
- GM_xmlhttpRequest({
- method: 'POST',
- url: `${apiUrl}/chat/completions`,
- headers: {
- 'Content-Type': 'application/json',
- 'Authorization': `Bearer ${apiKey}`
- },
- data: JSON.stringify({
- model: modelName,
- ...(providerName && { provider: providerName }),
- messages: [
- {
- role: 'system',
- content: systemPrompt
- },
- {
- role: 'user',
- content: taggedInput
- }
- ],
- temperature: 0.7,
- max_tokens: 16384
- }),
- onload: function(response) {
- try {
- const result = JSON.parse(response.responseText);
- if (result.error) {
- showResponse(`Error: ${result.error.message}`, true);
- } else if (result.choices && result.choices[0]) {
- showResponse(result.choices[0].message.content);
- } else {
- showResponse('Unexpected API response format', true);
- }
- } catch (error) {
- showResponse(`Error processing response: ${error.message}`, true);
- }
- },
- onerror: function(error) {
- showResponse(`Network error: ${error.statusText}`, true);
- }
- });
- }
-
- // Initialize the UI
- createUI();
- })();