Greasy Fork 支持简体中文。

Promptimizer

AI-powered prompt optimization tool that works with OpenAI-compatible APIs

目前為 2025-02-26 提交的版本,檢視 最新版本

// ==UserScript==
// @name         Promptimizer
// @namespace    https://github.com/NoahTheGinger/Promptimizer/
// @version      1.1
// @description  AI-powered prompt optimization tool that works with OpenAI-compatible APIs
// @author       NoahTheGinger
// @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;
            /* Changed default position to top:20px; left:20px for more natural left/top resizing */
            top: 20px;
            left: 20px;
            width: 400px;
            height: auto; /* Let the container's height auto-adjust at the start */
            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;
            transition: width 0.2s ease, height 0.2s ease, top 0.2s ease, left 0.2s ease;
            overflow: hidden;
            min-height: 300px;
            min-width: 300px;
        }

        #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;
        }

        #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;
            /* Also changed toggle to top-left for convenience; adapt as desired */
            top: 20px;
            left: 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);
        }

        /* Make the container content area fill the space under the header for better resizing */
        #promptimizer-content {
            /* We’ll rely on flexible layout to keep the text area resizing well. */
            display: flex;
            flex-direction: column;
            background: #ffffff;
            overflow: hidden;
            /* Subtract height of header (48px is approximate; adjust if your header is bigger/smaller) */
            max-height: calc(100% - 48px);
        }

        /* Use a vertical scroll inside the content if it extends beyond container height: */
        .scrollable-flex {
            overflow-y: auto;
            flex: 1; /* Flexible region that takes leftover space */
            padding: 16px; /* Keep the content from brushing edges */
        }

        .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 specific styles */
        textarea.promptimizer-input {
            resize: none; /* We'll handle resizing through container or auto-resizing logic */
            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;
        }

        /* Custom resize handles for the container—moved to top & left instead of bottom & right */
        .resize-handle {
            position: absolute;
            background: transparent;
            z-index: 10;
        }
        .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;
        }

        /* Container resize visual feedback */
        #promptimizer-container.resizing {
            transition: none;
            box-shadow: 0 2px 15px rgba(33, 150, 243, 0.4);
        }

        /* Example highlight for whichever handle is being dragged. Adjust as you like. */
        #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;
        }

        .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;
        }
    `);

    // Default dimensions and position
    const defaultDimensions = {
        width: '400px',
        height: 'auto',
        top: '20px',
        left: '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>
            <!-- Note the new scrollable-flex class to hold inputs, etc. -->
            <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>
            <!-- Resizing handles moved to top & left -->
            <div class="resize-handle resize-handle-left"></div>
            <div class="resize-handle resize-handle-top"></div>
            <div class="resize-handle resize-handle-corner"></div>
        `;
        document.body.appendChild(container);

        // Make the container draggable
        makeDraggable(container);

        // Add container resizing
        makeResizable(container);

        // Load saved configuration
        loadConfiguration();

        // Event listeners
        toggle.addEventListener('click', () => {
            // Toggle the entire UI
            container.style.display = (container.style.display === 'none' ? 'block' : 'none');
        });

        document.getElementById('promptimizer-minimize').addEventListener('click', () => {
            container.style.display = 'none';
        });

        // 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
    function makeDraggable(element) {
        const header = element.querySelector('#promptimizer-header');
        let isDragging = false;
        let currentX;
        let currentY;
        let initialX;
        let initialY;
        let xOffset = 0;
        let yOffset = 0;

        // Function to reset position and size
        function resetPosition() {
            element.style.transform = 'translate(0, 0)';
            element.style.top = defaultDimensions.top;
            element.style.left = defaultDimensions.left;
            element.style.width = defaultDimensions.width;
            element.style.height = defaultDimensions.height;
            xOffset = 0;
            yOffset = 0;

            // 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 drag start
            resetPosition();
        });

        header.addEventListener('mousedown', dragStart);
        document.addEventListener('mousemove', drag);
        document.addEventListener('mouseup', dragEnd);

        function dragStart(e) {
            // If the click was on a button in the header, don't drag
            if (e.target.closest('.header-button')) {
                return;
            }
            initialX = e.clientX - xOffset;
            initialY = e.clientY - yOffset;

            if (e.target === header || e.target.closest('#promptimizer-header')) {
                isDragging = true;
            }
        }

        function drag(e) {
            if (isDragging) {
                e.preventDefault();
                currentX = e.clientX - initialX;
                currentY = e.clientY - initialY;
                xOffset = currentX;
                yOffset = currentY;

                element.style.transform = `translate(${currentX}px, ${currentY}px)`;
            }
        }

        function dragEnd() {
            initialX = currentX;
            initialY = currentY;
            isDragging = false;

            // After dropping, compute final top/left to keep container in a new position:
            const rect = element.getBoundingClientRect();
            // The transform we used is purely visual, so we remove it and set real top/left
            element.style.transform = '';
            // Snap to new absolute left/top to remain at the same visible location
            element.style.left = rect.left + 'px';
            element.style.top = rect.top + 'px';
            // Reset the offsets since transform is removed
            xOffset = 0;
            yOffset = 0;
        }

        // Initialize at default position
        resetPosition();
    }

    // Make container resizable (top, left, corner)
    function makeResizable(container) {
        const leftHandle = container.querySelector('.resize-handle-left');
        const topHandle = container.querySelector('.resize-handle-top');
        const cornerHandle = container.querySelector('.resize-handle-corner');

        let isResizing = false;
        let currentResizeType = '';
        let startX, startY, startWidth, startHeight, startTop, startLeft;

        function startResize(e, type) {
            e.preventDefault();
            e.stopPropagation();

            isResizing = true;
            currentResizeType = type;

            // Current bounding info
            const rect = container.getBoundingClientRect();
            startWidth = rect.width;
            startHeight = rect.height;
            startTop = rect.top;
            startLeft = rect.left;
            startX = e.clientX;
            startY = e.clientY;

            // Add visual feedback classes
            container.classList.add('resizing');
            container.classList.add(`resizing-${type}`);

            document.addEventListener('mousemove', resize);
            document.addEventListener('mouseup', stopResize);
        }

        function resize(e) {
            if (!isResizing) return;

            // We’ll compute new top/left/width/height based on which handle
            let newWidth = startWidth;
            let newHeight = startHeight;
            let newTop = startTop;
            let newLeft = startLeft;

            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':
                    newWidth = startWidth - dx;
                    newHeight = startHeight - dy;
                    newLeft = startLeft + dx;
                    newTop = startTop + dy;
                    break;
            }

            // Enforce minimum dimensions
            if (newWidth < 300) {
                // If it’s going below min, readjust left so we don’t jump
                const diff = 300 - newWidth;
                newWidth = 300;
                newLeft -= (currentResizeType === 'left' || currentResizeType === 'corner') ? diff : 0;
            }
            if (newHeight < 300) {
                const diff = 300 - newHeight;
                newHeight = 300;
                newTop -= (currentResizeType === 'top' || currentResizeType === 'corner') ? diff : 0;
            }

            // Keep the container within viewport bounds if desired:
            const viewportWidth = window.innerWidth;
            const viewportHeight = window.innerHeight;

            // If the top is going above the screen, clamp it
            if (newTop < 0) {
                const overshoot = 0 - newTop;
                newTop = 0;
                // Increase height accordingly if we’re pulling from the top
                if (currentResizeType === 'top' || currentResizeType === 'corner') {
                    newHeight -= overshoot;
                }
            }
            // Similarly clamp left
            if (newLeft < 0) {
                const overshoot = 0 - newLeft;
                newLeft = 0;
                if (currentResizeType === 'left' || currentResizeType === 'corner') {
                    newWidth -= overshoot;
                }
            }
            // If the container extends beyond the right edge, clamp it
            if (newLeft + newWidth > viewportWidth) {
                newWidth = viewportWidth - newLeft;
            }
            // If the container extends beyond bottom edge, clamp it
            if (newTop + newHeight > viewportHeight) {
                newHeight = viewportHeight - newTop;
            }

            // Apply new geometry
            container.style.width = newWidth + 'px';
            container.style.height = newHeight + 'px';
            container.style.top = newTop + 'px';
            container.style.left = newLeft + 'px';
        }

        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 = 'width 0.2s ease, height 0.2s ease, top 0.2s ease, left 0.2s ease';
        }

        leftHandle.addEventListener('mousedown', (e) => startResize(e, 'left'));
        topHandle.addEventListener('mousedown', (e) => startResize(e, 'top'));
        cornerHandle.addEventListener('mousedown', (e) => startResize(e, 'corner'));
    }

    // 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';
        // Apply the new height with transition
        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' : '';

        // Show/hide copy button based on whether there's a successful response
        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();
})();