Automatically selects correct answers for Miacademy assignments
Size
14.3 KB
Version
1.1.4
Created
Mar 20, 2026
Updated
26 days ago
1// ==UserScript==
2// @name Miacademy Auto-Correct Answer Helper
3// @description Automatically selects correct answers for Miacademy assignments
4// @version 1.1.4
5// @match https://*.miacademy.co/*
6// @icon https://robomonkey.io/favicon.ico
7// ==/UserScript==
8(function() {
9 'use strict';
10
11 console.log('Miacademy Auto-Correct Answer Helper loaded');
12
13 // Debounce function to prevent multiple rapid calls
14 function debounce(func, wait) {
15 let timeout;
16 return function executedFunction(...args) {
17 const later = () => {
18 clearTimeout(timeout);
19 func(...args);
20 };
21 clearTimeout(timeout);
22 timeout = setTimeout(later, wait);
23 };
24 }
25
26 // Function to extract question and answers from the page
27 function extractQuestionData() {
28 try {
29 // Get the question text
30 const questionElement = document.querySelector('.mia-Prompt .mia-promptText');
31 if (!questionElement) {
32 console.log('No question found on page');
33 return null;
34 }
35
36 const questionText = questionElement.textContent.trim();
37
38 // Get all answer options
39 const answerElements = document.querySelectorAll('.mia-SelectableAnswer');
40 if (answerElements.length === 0) {
41 console.log('No answer options found');
42 return null;
43 }
44
45 const answers = Array.from(answerElements).map((el, index) => {
46 const textBlock = el.querySelector('.mia-TextBlock');
47 return {
48 index: index,
49 text: textBlock ? textBlock.textContent.trim() : '',
50 element: el
51 };
52 });
53
54 console.log('Question extracted:', questionText);
55 console.log('Answers extracted:', answers.map(a => a.text));
56
57 return {
58 question: questionText,
59 answers: answers
60 };
61 } catch (error) {
62 console.error('Error extracting question data:', error);
63 return null;
64 }
65 }
66
67 // Function to select the correct answer using AI
68 async function selectCorrectAnswer() {
69 try {
70 const questionData = extractQuestionData();
71 if (!questionData) {
72 console.log('Could not extract question data');
73 return;
74 }
75
76 console.log('Asking AI for the correct answer...');
77
78 // Check if we have a stored correct answer for this question
79 const storedAnswers = await GM.getValue('miacademy_correct_answers', {});
80 const questionKey = questionData.question.substring(0, 100); // Use first 100 chars as key
81
82 let correctIndex = -1;
83
84 if (storedAnswers[questionKey] !== undefined) {
85 console.log('Found stored answer for this question!');
86 correctIndex = storedAnswers[questionKey];
87 } else {
88 // Create a prompt for the AI
89 const prompt = `You are helping with a Miacademy quiz question.
90
91Question: ${questionData.question}
92
93Answer options:
94${questionData.answers.map((a, i) => `${i + 1}. ${a.text}`).join('\n')}
95
96Which answer is correct? Respond with ONLY the number (1, 2, 3, or 4) of the correct answer.`;
97
98 // Use AI to determine the correct answer
99 const aiResponse = await RM.aiCall(prompt, {
100 type: 'json_schema',
101 json_schema: {
102 name: 'correct_answer',
103 schema: {
104 type: 'object',
105 properties: {
106 answerNumber: {
107 type: 'number',
108 minimum: 1,
109 maximum: 10,
110 description: 'The number of the correct answer'
111 },
112 reasoning: {
113 type: 'string',
114 description: 'Brief explanation of why this is correct'
115 }
116 },
117 required: ['answerNumber']
118 }
119 }
120 });
121
122 console.log('AI Response:', aiResponse);
123 console.log('Reasoning:', aiResponse.reasoning);
124 correctIndex = aiResponse.answerNumber - 1;
125 }
126
127 if (correctIndex >= 0 && correctIndex < questionData.answers.length) {
128 const correctAnswer = questionData.answers[correctIndex];
129 console.log(`Selecting answer ${correctIndex + 1}: ${correctAnswer.text}`);
130
131 // Click the radio button for the correct answer
132 const radioButton = correctAnswer.element.querySelector('input[type="radio"]');
133 if (radioButton) {
134 radioButton.click();
135 console.log('Answer selected successfully!');
136
137 // Wait a moment, then click submit
138 setTimeout(() => {
139 const submitButton = document.querySelector('.mia-SubmitButton:not(.disabled)');
140 if (submitButton) {
141 console.log('Clicking submit button...');
142 submitButton.click();
143
144 // After submitting, check if answer was correct and store it
145 setTimeout(() => {
146 checkAnswerResult(questionKey, correctIndex);
147 }, 1000);
148 } else {
149 console.log('Submit button not available yet');
150 }
151 }, 500);
152 } else {
153 console.error('Could not find radio button for answer');
154 }
155 } else {
156 console.error('Invalid answer index from AI:', correctIndex);
157 }
158 } catch (error) {
159 console.error('Error selecting correct answer:', error);
160 }
161 }
162
163 // Function to check if the answer was correct and store it
164 async function checkAnswerResult(questionKey, answerIndex) {
165 try {
166 // Look for correct/incorrect indicators
167 const correctIndicator = document.querySelector('.mia-SelectableAnswer.correct, .mia-correct, [class*="correct"]');
168 const incorrectIndicator = document.querySelector('.mia-SelectableAnswer.incorrect, .mia-incorrect, [class*="incorrect"]');
169
170 if (correctIndicator) {
171 console.log('Answer was CORRECT! Storing for future reference...');
172 const storedAnswers = await GM.getValue('miacademy_correct_answers', {});
173 storedAnswers[questionKey] = answerIndex;
174 await GM.setValue('miacademy_correct_answers', storedAnswers);
175 } else if (incorrectIndicator) {
176 console.log('Answer was INCORRECT. Looking for the correct answer...');
177
178 // Find which answer is marked as correct
179 const allAnswers = document.querySelectorAll('.mia-SelectableAnswer');
180 for (let i = 0; i < allAnswers.length; i++) {
181 if (allAnswers[i].classList.contains('correct') ||
182 allAnswers[i].querySelector('.correct, [class*="correct"]')) {
183 console.log(`Correct answer was option ${i + 1}. Storing for next time...`);
184 const storedAnswers = await GM.getValue('miacademy_correct_answers', {});
185 storedAnswers[questionKey] = i;
186 await GM.setValue('miacademy_correct_answers', storedAnswers);
187 break;
188 }
189 }
190 }
191
192 // Click next button after checking result
193 setTimeout(() => {
194 clickNextButton();
195 }, 1500);
196 } catch (error) {
197 console.error('Error checking answer result:', error);
198 // Still try to click next even if there's an error
199 setTimeout(() => {
200 clickNextButton();
201 }, 1500);
202 }
203 }
204
205 // Function to click the next button
206 function clickNextButton() {
207 // Look for various "next" button selectors
208 const nextButton = document.querySelector(
209 '.mia-NextButton, .mia-ContinueButton, button[class*="next"], button[class*="continue"], ' +
210 'button:contains("Next"), button:contains("Continue")'
211 );
212
213 if (nextButton && !nextButton.disabled) {
214 console.log('Clicking next button...');
215 nextButton.click();
216 } else {
217 // Try alternative selectors
218 const buttons = document.querySelectorAll('button');
219 for (const button of buttons) {
220 const text = button.textContent.toLowerCase();
221 if ((text.includes('next') || text.includes('continue')) && !button.disabled) {
222 console.log('Found and clicking next/continue button...');
223 button.click();
224 return;
225 }
226 }
227 console.log('No next button found or button is disabled');
228 }
229 }
230
231 // Function to check if we're on a quiz page
232 function isQuizPage() {
233 return document.querySelector('.mia-Prompt') !== null &&
234 document.querySelector('.mia-SelectableAnswer') !== null;
235 }
236
237 // Track which questions we've already answered
238 let lastQuestionText = '';
239 let isProcessing = false;
240
241 // Function to check and auto-answer new questions
242 async function checkAndAutoAnswer() {
243 // Don't process if already processing
244 if (isProcessing) {
245 console.log('Already processing a question, skipping...');
246 return;
247 }
248
249 // Check if we're on a quiz page
250 if (!isQuizPage()) {
251 console.log('Not on a quiz page');
252 lastQuestionText = '';
253 return;
254 }
255
256 // Extract current question
257 const questionElement = document.querySelector('.mia-Prompt .mia-promptText');
258 if (!questionElement) {
259 return;
260 }
261
262 const currentQuestionText = questionElement.textContent.trim();
263
264 // Check if this is a new question
265 if (currentQuestionText === lastQuestionText) {
266 return;
267 }
268
269 // Check if question is already answered
270 const selectedAnswer = document.querySelector('.mia-SelectableAnswer input[type="radio"]:checked');
271 if (selectedAnswer) {
272 console.log('Question already answered, skipping...');
273 lastQuestionText = currentQuestionText;
274 return;
275 }
276
277 console.log('New question detected! Auto-answering...');
278 lastQuestionText = currentQuestionText;
279 isProcessing = true;
280
281 try {
282 await selectCorrectAnswer();
283 } catch (error) {
284 console.error('Error auto-answering:', error);
285 } finally {
286 isProcessing = false;
287 }
288 }
289
290 // Debounced version of auto-answer check
291 const debouncedAutoAnswer = debounce(checkAndAutoAnswer, 1000);
292
293 // Function to add a helper button to the page
294 function addHelperButton() {
295 // Check if button already exists
296 if (document.getElementById('mia-auto-answer-btn')) {
297 return;
298 }
299
300 // Only add button if we're on a quiz page
301 if (!isQuizPage()) {
302 return;
303 }
304
305 const button = document.createElement('button');
306 button.id = 'mia-auto-answer-btn';
307 button.textContent = '🤖 Auto Answer';
308 button.style.cssText = `
309 position: fixed;
310 top: 20px;
311 right: 20px;
312 z-index: 10000;
313 padding: 12px 20px;
314 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
315 color: white;
316 border: none;
317 border-radius: 8px;
318 font-size: 16px;
319 font-weight: bold;
320 cursor: pointer;
321 box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
322 transition: all 0.3s ease;
323 `;
324
325 button.addEventListener('mouseenter', () => {
326 button.style.transform = 'translateY(-2px)';
327 button.style.boxShadow = '0 6px 20px rgba(0, 0, 0, 0.3)';
328 });
329
330 button.addEventListener('mouseleave', () => {
331 button.style.transform = 'translateY(0)';
332 button.style.boxShadow = '0 4px 15px rgba(0, 0, 0, 0.2)';
333 });
334
335 button.addEventListener('click', async () => {
336 button.disabled = true;
337 button.textContent = '⏳ Thinking...';
338 try {
339 await selectCorrectAnswer();
340 } finally {
341 setTimeout(() => {
342 button.disabled = false;
343 button.textContent = '🤖 Auto Answer';
344 }, 2000);
345 }
346 });
347
348 document.body.appendChild(button);
349 console.log('Auto Answer button added to page');
350 }
351
352 // Watch for page changes and add button when quiz appears
353 const debouncedAddButton = debounce(addHelperButton, 500);
354
355 // Use MutationObserver to detect when quiz content loads
356 const observer = new MutationObserver(() => {
357 debouncedAddButton();
358 debouncedAutoAnswer();
359 });
360
361 // Initialize when page loads
362 function init() {
363 console.log('Initializing Miacademy Auto-Correct Answer Helper');
364 console.log('Auto-answer mode: ENABLED - will automatically answer new questions');
365
366 // Add button immediately if quiz is already visible
367 addHelperButton();
368
369 // Check for questions immediately
370 checkAndAutoAnswer();
371
372 // Watch for changes in the page
373 observer.observe(document.body, {
374 childList: true,
375 subtree: true
376 });
377
378 console.log('Watching for quiz questions...');
379 }
380
381 // Wait for page to be ready
382 if (document.readyState === 'loading') {
383 document.addEventListener('DOMContentLoaded', init);
384 } else {
385 init();
386 }
387})();