Advertisement
EnTGeA

Untitled

Feb 3rd, 2025 (edited)
36
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // ==UserScript==
  2. // @name         Auto Answer Ujian UG (Zest API Version)
  3. // @namespace    http://tampermonkey.net/
  4. // @version      v1.9
  5. // @description  Automated exam assistant with GPT-4o-mini integration using Zest API and UI controls; with optional autonomous mode and delay settings
  6. // @author       Invictus
  7. // @match        https://ujian.gunadarma.ac.id/ujian.aspx
  8. // @match        https://ujian-gunadarma-palsu.netlify.app/
  9. // @match        https://www.google.com
  10. // @icon         https://www.google.com/s2/favicons?sz=64&domain=ac.id
  11. // @grant        GM_addStyle
  12. // @grant        GM_setValue
  13. // @grant        GM_getValue
  14. // @connect      api.zpi.my.id
  15. // ==/UserScript==
  16.  
  17. (function() {
  18.     'use strict';
  19.  
  20.     console.log("πŸš€ Script initialization started");
  21.     let isRunning = GM_getValue('isRunning', false);
  22.     let currentStatus = 'Idle';
  23.     console.log(`πŸ“’ Initial running state: ${isRunning ? "Running" : "Stopped"}`);
  24.  
  25.     const API_ENDPOINT = 'https://api.zpi.my.id/v1/ai/gpt-4o-mini';
  26.  
  27.     GM_addStyle(`
  28.         #controlPanel {
  29.             position: fixed;
  30.             top: 20px;
  31.             right: 20px;
  32.             z-index: 9999;
  33.             background: rgba(255, 255, 255, 0.95);
  34.             padding: 15px;
  35.             border-radius: 8px;
  36.             box-shadow: 0 2px 10px rgba(0,0,0,0.2);
  37.             font-family: Arial, sans-serif;
  38.             min-width: 250px;
  39.         }
  40.         .control-header {
  41.             font-weight: bold;
  42.             margin-bottom: 10px;
  43.             color: #2c3e50;
  44.         }
  45.         .status-indicator {
  46.             margin: 10px 0;
  47.             padding: 5px;
  48.             border-radius: 4px;
  49.             text-align: center;
  50.         }
  51.         .button-group {
  52.             display: flex;
  53.             gap: 8px;
  54.             margin-top: 10px;
  55.             justify-content: center;
  56.         }
  57.         .control-btn {
  58.             padding: 8px 12px;
  59.             border: none;
  60.             border-radius: 4px;
  61.             cursor: pointer;
  62.             transition: opacity 0.2s;
  63.         }
  64.         .control-btn:disabled {
  65.             opacity: 0.3;
  66.             cursor: default;
  67.         }
  68.         .start-btn { background: #27ae60; color: white; }
  69.         .stop-btn { background: #e74c3c; color: white; }
  70.         .auto-options {
  71.             margin-top: 10px;
  72.             font-size: 0.9em;
  73.         }
  74.         .auto-options label {
  75.             display: block;
  76.             margin-top: 5px;
  77.         }
  78.         .auto-options input[type="number"] {
  79.             width: 50px;
  80.             margin-left: 5px;
  81.         }
  82.     `);
  83.  
  84.     console.log("πŸ› οΈ Creating control panel elements");
  85.     const panel = document.createElement('div');
  86.     panel.id = 'controlPanel';
  87.     panel.innerHTML = `
  88.         <div class="control-header">Auto Answer Controls</div>
  89.         <div class="status-indicator" id="statusDisplay">Status: Idle</div>
  90.         <div class="button-group">
  91.             <button class="control-btn start-btn" id="startBtn">Start</button>
  92.             <button class="control-btn stop-btn" id="stopBtn">Stop</button>
  93.         </div>
  94.         <div class="auto-options">
  95.             <label>
  96.                 <input type="checkbox" id="autoModeCheckbox">
  97.                 Autonomous Mode
  98.             </label>
  99.             <label>
  100.                 Delay (sec):
  101.                 <input type="number" id="delayInput" value="2" min="0" step="0.1" disabled>
  102.             </label>
  103.         </div>
  104.     `;
  105.     document.body.appendChild(panel);
  106.     console.log("βœ… Control panel injected successfully");
  107.  
  108.     const autoModeCheckbox = document.getElementById('autoModeCheckbox');
  109.     const delayInput = document.getElementById('delayInput');
  110.     const startBtn = document.getElementById('startBtn');
  111.     const stopBtn = document.getElementById('stopBtn');
  112.  
  113.     const storedAutoMode = GM_getValue('autoMode', false);
  114.     const storedDelay = GM_getValue('delay', '2');
  115.     console.log(`βš™οΈ Loaded stored settings - AutoMode: ${storedAutoMode}, Delay: ${storedDelay}s`);
  116.     autoModeCheckbox.checked = storedAutoMode;
  117.     delayInput.value = storedDelay;
  118.     delayInput.disabled = !storedAutoMode;
  119.  
  120.     function updateButtons() {
  121.         console.log(`πŸ”„ Updating buttons - isRunning: ${isRunning}`);
  122.         startBtn.disabled = isRunning;
  123.         stopBtn.disabled = !isRunning;
  124.     }
  125.     updateButtons();
  126.  
  127.     autoModeCheckbox.addEventListener('change', () => {
  128.         console.log(`πŸ”˜ AutoMode checkbox changed: ${autoModeCheckbox.checked}`);
  129.         GM_setValue('autoMode', autoModeCheckbox.checked);
  130.         delayInput.disabled = !autoModeCheckbox.checked;
  131.     });
  132.     delayInput.addEventListener('change', () => {
  133.         console.log(`⏱️ Delay input changed: ${delayInput.value}s`);
  134.         GM_setValue('delay', delayInput.value);
  135.     });
  136.  
  137.     function updateStatus(newStatus, color = '#3498db') {
  138.         console.log(`πŸ“‘ Status update: ${currentStatus} β†’ ${newStatus}`);
  139.         currentStatus = newStatus;
  140.         const statusDisplay = document.getElementById('statusDisplay');
  141.         statusDisplay.textContent = `Status: ${newStatus}`;
  142.         statusDisplay.style.backgroundColor = color;
  143.     }
  144.  
  145.     document.getElementById('startBtn').addEventListener('click', () => {
  146.         console.log("🎬 Start button clicked");
  147.         if (!isRunning) {
  148.             isRunning = true;
  149.             GM_setValue('isRunning', isRunning);
  150.             updateStatus('Running', '#2ecc71');
  151.             updateButtons();
  152.             processQuestion();
  153.         }
  154.     });
  155.  
  156.     document.getElementById('stopBtn').addEventListener('click', () => {
  157.         console.log("⏹️ Stop button clicked");
  158.         isRunning = false;
  159.         GM_setValue('isRunning', isRunning);
  160.         updateStatus('Stopped', '#e74c3c');
  161.         updateButtons();
  162.     });
  163.  
  164.     window.addEventListener('beforeunload', () => {
  165.         console.log("⚠️ Page unloading - saving state");
  166.         GM_setValue('isRunning', isRunning);
  167.     });
  168.  
  169.     let pendingDelay = GM_getValue('pendingDelay', null);
  170.     if (isRunning && autoModeCheckbox.checked) {
  171.         console.log(`⏳ Resuming pending delay: ${pendingDelay}s`);
  172.         if (pendingDelay !== null) {
  173.             updateStatus(`Delaying (${pendingDelay}s)...`, '#8e44ad');
  174.             setTimeout(() => {
  175.                 GM_setValue('pendingDelay', null);
  176.                 processQuestion();
  177.             }, parseFloat(pendingDelay) * 1000);
  178.         } else {
  179.             updateStatus('Running', '#2ecc71');
  180.             setTimeout(processQuestion, 1000);
  181.         }
  182.     }
  183.  
  184.     async function processQuestion() {
  185.         if (!isRunning) {
  186.             console.log("πŸ›‘ Process halted - script not running");
  187.             return;
  188.         }
  189.  
  190.         try {
  191.             console.log("πŸ” Starting question processing");
  192.             updateStatus('Processing Question...', '#3498db');
  193.  
  194.             const questionElement = document.querySelector('.form-group.label-ers span');
  195.             const questionText = questionElement?.innerText?.trim() || '';
  196.             console.log(`πŸ“„ Question text: ${questionText.substring(0, 50)}${questionText.length > 50 ? '...' : ''}`);
  197.  
  198.             const choices = Array.from(document.querySelectorAll('.form-check'))
  199.                 .slice(0, 4)
  200.                 .map(el => el.querySelector('label')?.textContent?.trim() || '');
  201.             console.log("πŸ“‹ Choices found:", choices);
  202.  
  203.             if (!questionText || choices.length !== 4) {
  204.                 console.warn("❌ Invalid question/choices structure");
  205.                 updateStatus('No Question Found', '#95a5a6');
  206.                 isRunning = false;
  207.                 GM_setValue('isRunning', isRunning);
  208.                 updateButtons();
  209.                 return;
  210.             }
  211.  
  212.             console.log("πŸ€– Requesting answer from Zest API...");
  213.             const answer = await getGPTAnswer(questionText, choices);
  214.             console.log(`πŸ“© Received answer: ${answer}`);
  215.  
  216.             const radioButton = document.querySelector(`#rdPilihan${answer}`);
  217.             if (radioButton) {
  218.                 console.log(`βœ… Selecting answer ${answer}`);
  219.                 radioButton.click();
  220.                 updateStatus('Answer Selected', '#2ecc71');
  221.  
  222.                 if (autoModeCheckbox.checked) {
  223.                     const delayValue = parseFloat(delayInput.value) || 0;
  224.                     console.log(`⏱️ Autonomous delay activated: ${delayValue}s`);
  225.                     GM_setValue('pendingDelay', delayValue);
  226.                     setTimeout(() => {
  227.                         GM_setValue('pendingDelay', null);
  228.                         const nextBtn = document.getElementById('lnkNext');
  229.                         if (nextBtn) {
  230.                             // If the next button's text does NOT contain "TAMPILKAN", assume it's the last question.
  231.                             if (!nextBtn.innerText.includes('TAMPILKAN')) {
  232.                                 console.log("πŸ›‘ Last question reached. Stopping the script gracefully.");
  233.                                 isRunning = false;
  234.                                 GM_setValue('isRunning', isRunning);
  235.                                 updateStatus('Last question reached. Script stopped.', '#e74c3c');
  236.                                 updateButtons();
  237.                                 return;
  238.                             } else {
  239.                                 console.log("➑️ Clicking next question button");
  240.                                 nextBtn.click();
  241.                             }
  242.                         }
  243.                     }, delayValue * 1000);
  244.                 } else {
  245.                     isRunning = false;
  246.                     GM_setValue('isRunning', isRunning);
  247.                     updateStatus('Idle (Awaiting Next Start)', '#95a5a6');
  248.                     updateButtons();
  249.                 }
  250.             } else {
  251.                 throw new Error(`🚨 Answer element for ${answer} not found`);
  252.             }
  253.         } catch (error) {
  254.             console.error(`❌ Processing error: ${error.message}`);
  255.             isRunning = false;
  256.             GM_setValue('isRunning', isRunning);
  257.             updateStatus(`Error: ${error.message}`, '#e74c3c');
  258.             updateButtons();
  259.         }
  260.     }
  261.  
  262.     async function getGPTAnswer(question, choices) {
  263.         const prompt = `Question: ${question}\n\nChoices:\nA) ${choices[0]}\nB) ${choices[1]}\nC) ${choices[2]}\nD) ${choices[3]}\n\nRespond ONLY with the correct letter (A/B/C/D)`;
  264.         console.log("πŸ“¨ Sending API request with prompt:", prompt);
  265.  
  266.         try {
  267.             const response = await fetch(API_ENDPOINT, {
  268.                 method: 'POST',
  269.                 headers: { 'Content-Type': 'application/json' },
  270.                 body: JSON.stringify({ messages: [{ role: "user", content: prompt }] })
  271.             });
  272.  
  273.             if (!response.ok) {
  274.                 console.error(`🚨 API response error: ${response.status} ${response.statusText}`);
  275.                 throw new Error(`API error: ${response.status}`);
  276.             }
  277.  
  278.             const result = await response.json();
  279.             console.log("πŸ“¦ API response received:", result);
  280.  
  281.             const answer = result.data?.choices?.content?.trim().toUpperCase();
  282.             if (!['A', 'B', 'C', 'D'].includes(answer)) {
  283.                 throw new Error(`Invalid response format: ${answer}`);
  284.             }
  285.  
  286.             return answer;
  287.         } catch (error) {
  288.             console.error("❌ API request failed:", error);
  289.             throw error;
  290.         }
  291.     }
  292. })();
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement