Enhance your ChatGPT prompts with AI to make them more effective and detailed
Size
10.9 KB
Version
1.1.1
Created
Nov 5, 2025
Updated
3 months ago
1// ==UserScript==
2// @name ChatGPT Prompt Enhancer
3// @description Enhance your ChatGPT prompts with AI to make them more effective and detailed
4// @version 1.1.1
5// @match https://*.chatgpt.com/*
6// @icon https://cdn.oaistatic.com/assets/favicon-l4nq08hd.svg
7// @grant GM.getValue
8// @grant GM.setValue
9// ==/UserScript==
10(function() {
11 'use strict';
12
13 console.log('ChatGPT Prompt Enhancer extension loaded');
14
15 // Debounce function to prevent excessive calls
16 function debounce(func, wait) {
17 let timeout;
18 return function executedFunction(...args) {
19 const later = () => {
20 clearTimeout(timeout);
21 func(...args);
22 };
23 clearTimeout(timeout);
24 timeout = setTimeout(later, wait);
25 };
26 }
27
28 // Create the enhance button
29 function createEnhanceButton() {
30 const button = document.createElement('button');
31 button.type = 'button';
32 button.className = 'composer-btn';
33 button.id = 'prompt-enhancer-btn';
34 button.setAttribute('aria-label', 'Enhance prompt with AI');
35 button.title = 'Enhance prompt with AI';
36 button.innerHTML = `
37 <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
38 <path d="M12 2L15.09 8.26L22 9.27L17 14.14L18.18 21.02L12 17.77L5.82 21.02L7 14.14L2 9.27L8.91 8.26L12 2Z"
39 stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/>
40 </svg>
41 `;
42 button.style.cssText = `
43 display: flex;
44 align-items: center;
45 justify-content: center;
46 width: 36px;
47 height: 36px;
48 border-radius: 8px;
49 cursor: pointer;
50 transition: all 0.2s;
51 background: transparent;
52 border: none;
53 color: var(--text-primary);
54 `;
55
56 button.addEventListener('mouseenter', () => {
57 button.style.backgroundColor = 'var(--surface-hover, rgba(0, 0, 0, 0.05))';
58 });
59
60 button.addEventListener('mouseleave', () => {
61 button.style.backgroundColor = 'transparent';
62 });
63
64 button.addEventListener('click', handleEnhanceClick);
65
66 return button;
67 }
68
69 // Get the current prompt text from the textarea
70 function getPromptText() {
71 const promptTextarea = document.querySelector('#prompt-textarea');
72 if (!promptTextarea) {
73 console.error('Prompt textarea not found');
74 return '';
75 }
76 return promptTextarea.textContent.trim();
77 }
78
79 // Set the prompt text in the textarea
80 function setPromptText(text) {
81 const promptTextarea = document.querySelector('#prompt-textarea');
82 if (!promptTextarea) {
83 console.error('Prompt textarea not found');
84 return false;
85 }
86
87 // Clear existing content
88 promptTextarea.innerHTML = '';
89
90 // Create a new paragraph element with the text
91 const p = document.createElement('p');
92 p.textContent = text;
93 promptTextarea.appendChild(p);
94
95 // Trigger input event to update ChatGPT's internal state
96 const inputEvent = new Event('input', { bubbles: true, cancelable: true });
97 promptTextarea.dispatchEvent(inputEvent);
98
99 console.log('Prompt text updated successfully');
100 return true;
101 }
102
103 // Show loading state
104 function showLoadingState(button) {
105 button.disabled = true;
106 button.style.opacity = '0.5';
107 button.style.cursor = 'not-allowed';
108 button.innerHTML = `
109 <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
110 <circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2" opacity="0.25"/>
111 <path d="M12 2a10 10 0 0 1 10 10" stroke="currentColor" stroke-width="2" stroke-linecap="round">
112 <animateTransform attributeName="transform" type="rotate" from="0 12 12" to="360 12 12" dur="1s" repeatCount="indefinite"/>
113 </path>
114 </svg>
115 `;
116 }
117
118 // Reset button state
119 function resetButtonState(button) {
120 button.disabled = false;
121 button.style.opacity = '1';
122 button.style.cursor = 'pointer';
123 button.innerHTML = `
124 <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
125 <path d="M12 2L15.09 8.26L22 9.27L17 14.14L18.18 21.02L12 17.77L5.82 21.02L7 14.14L2 9.27L8.91 8.26L12 2Z"
126 stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/>
127 </svg>
128 `;
129 }
130
131 // Show notification
132 function showNotification(message, type = 'info') {
133 const notification = document.createElement('div');
134 notification.style.cssText = `
135 position: fixed;
136 top: 20px;
137 right: 20px;
138 background: ${type === 'error' ? '#ef4444' : type === 'success' ? '#10b981' : '#3b82f6'};
139 color: white;
140 padding: 12px 20px;
141 border-radius: 8px;
142 box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
143 z-index: 10000;
144 font-size: 14px;
145 max-width: 300px;
146 animation: slideIn 0.3s ease-out;
147 `;
148 notification.textContent = message;
149
150 // Add animation
151 const style = document.createElement('style');
152 style.textContent = `
153 @keyframes slideIn {
154 from {
155 transform: translateX(400px);
156 opacity: 0;
157 }
158 to {
159 transform: translateX(0);
160 opacity: 1;
161 }
162 }
163 `;
164 document.head.appendChild(style);
165
166 document.body.appendChild(notification);
167
168 setTimeout(() => {
169 notification.style.transition = 'opacity 0.3s ease-out';
170 notification.style.opacity = '0';
171 setTimeout(() => notification.remove(), 300);
172 }, 3000);
173 }
174
175 // Handle enhance button click
176 async function handleEnhanceClick() {
177 console.log('Enhance button clicked');
178
179 const button = document.querySelector('#prompt-enhancer-btn');
180 const currentPrompt = getPromptText();
181
182 if (!currentPrompt) {
183 showNotification('Please enter a prompt first', 'error');
184 return;
185 }
186
187 console.log('Current prompt:', currentPrompt);
188
189 try {
190 showLoadingState(button);
191 showNotification('Enhancing your prompt...', 'info');
192
193 // Call AI to enhance the prompt
194 const enhancedPrompt = await RM.aiCall(
195 `You are a prompt engineering expert. Enhance the following prompt to make it more effective, detailed, and clear for ChatGPT.
196
197The enhanced prompt should:
198- Be more specific and detailed
199- Include relevant context
200- Use clear instructions
201- Be well-structured
202- Maintain the original intent
203
204Original prompt: "${currentPrompt}"
205
206Return ONLY the enhanced prompt text, nothing else.`
207 );
208
209 console.log('Enhanced prompt:', enhancedPrompt);
210
211 if (enhancedPrompt && enhancedPrompt.trim()) {
212 setPromptText(enhancedPrompt.trim());
213 showNotification('Prompt enhanced successfully!', 'success');
214
215 // Store usage stats
216 const usageCount = await GM.getValue('enhancer_usage_count', 0);
217 await GM.setValue('enhancer_usage_count', usageCount + 1);
218 console.log('Total enhancements:', usageCount + 1);
219 } else {
220 throw new Error('Empty response from AI');
221 }
222
223 } catch (error) {
224 console.error('Error enhancing prompt:', error);
225 showNotification('Failed to enhance prompt. Please try again.', 'error');
226 } finally {
227 resetButtonState(button);
228 }
229 }
230
231 // Insert the enhance button into the composer
232 function insertEnhanceButton() {
233 // Find the trailing area where other buttons are
234 const trailingArea = document.querySelector('form[data-type="unified-composer"] .flex.items-center.gap-2[class*="trailing"]');
235
236 if (!trailingArea) {
237 console.error('Trailing area not found');
238 return false;
239 }
240
241 // Check if button already exists
242 if (document.querySelector('#prompt-enhancer-btn')) {
243 console.log('Enhance button already exists');
244 return true;
245 }
246
247 // Find the inner flex container
248 const innerContainer = trailingArea.querySelector('.ms-auto.flex.items-center');
249
250 if (!innerContainer) {
251 console.error('Inner container not found');
252 return false;
253 }
254
255 // Create and insert the button
256 const enhanceButton = createEnhanceButton();
257
258 // Insert before the voice mode button
259 const voiceButtonContainer = innerContainer.querySelector('[data-testid="composer-speech-button-container"]');
260 if (voiceButtonContainer) {
261 innerContainer.insertBefore(enhanceButton, voiceButtonContainer);
262 } else {
263 innerContainer.appendChild(enhanceButton);
264 }
265
266 console.log('Enhance button inserted successfully');
267 return true;
268 }
269
270 // Initialize the extension
271 function init() {
272 console.log('Initializing ChatGPT Prompt Enhancer...');
273
274 // Wait for the composer to be ready
275 const checkComposer = setInterval(() => {
276 const composer = document.querySelector('form[data-type="unified-composer"]');
277 if (composer) {
278 clearInterval(checkComposer);
279 console.log('Composer found, inserting enhance button');
280
281 if (insertEnhanceButton()) {
282 console.log('Extension initialized successfully');
283
284 // Watch for DOM changes in case ChatGPT rebuilds the composer
285 const observer = new MutationObserver(debounce(() => {
286 if (!document.querySelector('#prompt-enhancer-btn')) {
287 console.log('Button removed, re-inserting...');
288 insertEnhanceButton();
289 }
290 }, 500));
291
292 observer.observe(document.body, {
293 childList: true,
294 subtree: true
295 });
296 }
297 }
298 }, 500);
299
300 // Stop checking after 10 seconds
301 setTimeout(() => {
302 clearInterval(checkComposer);
303 }, 10000);
304 }
305
306 // Start the extension when DOM is ready
307 if (document.readyState === 'loading') {
308 document.addEventListener('DOMContentLoaded', init);
309 } else {
310 init();
311 }
312
313})();