Ever wanted to stop a form that’s clearly going down the wrong track? While this won’t save you tokens on the back-end, it will let your users stop forms mid-stream so they can resubmit immediately.
Installation
Add the following JavaScript to a post or page with an AI Engine form on it:
const aiestop = {}; // Map to store controllers for each fetch request aiestop.fetchControllers = new Map(); aiestop.fetchControllersChange = function() {} // Function to create a new AbortController and store it using a unique identifier aiestop.createAbortSignal = function() { const id = Date.now() + Math.random(); // Create a unique ID const controller = new AbortController(); aiestop.fetchControllers.set(id, controller); aiestop.fetchControllersChange(); // Call to update UI return { signal: controller.signal, id }; } // Function to abort the fetch using the unique identifier aiestop.abortFetch = function(id) { if (aiestop.fetchControllers.has(id)) { aiestop.fetchControllers.get(id).abort(); aiestop.fetchControllers.delete(id); // Clean up the controller after aborting aiestop.fetchControllersChange(); // Call to update UI } } // Function to abort the fetch using the unique identifier aiestop.removeController = function(id) { if (aiestop.fetchControllers.has(id)) { aiestop.fetchControllers.delete(id); // Clean up the controller after aborting aiestop.fetchControllersChange(); // Call to update UI } } // Function to abort all fetches aiestop.abortAllFetches = function() { for (const [id, controller] of aiestop.fetchControllers.entries()) { controller.abort(); // Abort each fetch aiestop.removeController(id); } } aiestopOriginalFetch = window.fetch; // Override the global fetch function window.fetch = async (url, options = {}) => { const stoppable = (url.endsWith('/wp-json/mwai-ui/v1/forms/submit')); let signal = null; let id = null; if (stoppable) { ({ signal, id } = aiestop.createAbortSignal()); options.signal = signal; } else { return aiestopOriginalFetch(url, options); } try { const response = await aiestopOriginalFetch(url, options); if (signal && signal.aborted) { throw new DOMException('The user aborted a request.', 'AbortError'); } // Handle streaming data if (stoppable && response.body) { const reader = response.body.getReader(); const stream = new ReadableStream({ start(controller) { function push() { reader.read().then(({ done, value }) => { if (done) { controller.close(); aiestop.removeController(id); return; } controller.enqueue(value); push(); }).catch(error => { console.error('Stream reading failed:', error); controller.error(error); }); } push(); }, cancel() { reader.cancel(); console.log('Stream cancelled by the user'); } }); if (signal && signal.aborted) { stream.cancel(); throw new DOMException('The user aborted a request.', 'AbortError'); } return new Response(stream, { headers: response.headers }); } if (stoppable) { aiestop.removeController(id); } // Clean up the controller after successful fetch return response; } catch (error) { if (error.name === 'AbortError') { console.log('Fetch aborted'); } else { throw error; } } }; document.addEventListener('DOMContentLoaded', function() { const stopBtn = document.createElement('button'); stopBtn.textContent = 'Stop Generating'; stopBtn.className = 'stop-generating-btn'; stopBtn.style.display = 'none'; // Button is hidden by default document.body.appendChild(stopBtn); stopBtn.addEventListener('click', function() { aiestop.abortAllFetches(); }); // Function to check and display the button function updateButtonVisibility() { if (aiestop.fetchControllers.size > 0) { stopBtn.style.display = 'block'; } else { stopBtn.style.display = 'none'; } } // Call updateButtonVisibility initially and whenever fetchControllers changes updateButtonVisibility(); aiestop.fetchControllersChange = updateButtonVisibility; });
Then add this CSS:
.stop-generating-btn { position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%); padding: 10px 20px; background-color: red; color: white; border: none; border-radius: 5px; cursor: pointer; z-index: 1000; }
Let’s enhance your business! I can help you develop custom AI engine extensions or broader AI strategies.
Contact me.