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.
