Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // ==UserScript==
- // @name Auto Answer Ujian UG (Zest API Version)
- // @namespace http://tampermonkey.net/
- // @version v1.9
- // @description Automated exam assistant with GPT-4o-mini integration using Zest API and UI controls; with optional autonomous mode and delay settings
- // @author Invictus
- // @match https://ujian.gunadarma.ac.id/ujian.aspx
- // @match https://ujian-gunadarma-palsu.netlify.app/
- // @match https://www.google.com
- // @icon https://www.google.com/s2/favicons?sz=64&domain=ac.id
- // @grant GM_addStyle
- // @grant GM_setValue
- // @grant GM_getValue
- // @connect api.zpi.my.id
- // ==/UserScript==
- (function() {
- 'use strict';
- console.log("π Script initialization started");
- let isRunning = GM_getValue('isRunning', false);
- let currentStatus = 'Idle';
- console.log(`π’ Initial running state: ${isRunning ? "Running" : "Stopped"}`);
- const API_ENDPOINT = 'https://api.zpi.my.id/v1/ai/gpt-4o-mini';
- GM_addStyle(`
- #controlPanel {
- position: fixed;
- top: 20px;
- right: 20px;
- z-index: 9999;
- background: rgba(255, 255, 255, 0.95);
- padding: 15px;
- border-radius: 8px;
- box-shadow: 0 2px 10px rgba(0,0,0,0.2);
- font-family: Arial, sans-serif;
- min-width: 250px;
- }
- .control-header {
- font-weight: bold;
- margin-bottom: 10px;
- color: #2c3e50;
- }
- .status-indicator {
- margin: 10px 0;
- padding: 5px;
- border-radius: 4px;
- text-align: center;
- }
- .button-group {
- display: flex;
- gap: 8px;
- margin-top: 10px;
- justify-content: center;
- }
- .control-btn {
- padding: 8px 12px;
- border: none;
- border-radius: 4px;
- cursor: pointer;
- transition: opacity 0.2s;
- }
- .control-btn:disabled {
- opacity: 0.3;
- cursor: default;
- }
- .start-btn { background: #27ae60; color: white; }
- .stop-btn { background: #e74c3c; color: white; }
- .auto-options {
- margin-top: 10px;
- font-size: 0.9em;
- }
- .auto-options label {
- display: block;
- margin-top: 5px;
- }
- .auto-options input[type="number"] {
- width: 50px;
- margin-left: 5px;
- }
- `);
- console.log("π οΈ Creating control panel elements");
- const panel = document.createElement('div');
- panel.id = 'controlPanel';
- panel.innerHTML = `
- <div class="control-header">Auto Answer Controls</div>
- <div class="status-indicator" id="statusDisplay">Status: Idle</div>
- <div class="button-group">
- <button class="control-btn start-btn" id="startBtn">Start</button>
- <button class="control-btn stop-btn" id="stopBtn">Stop</button>
- </div>
- <div class="auto-options">
- <label>
- <input type="checkbox" id="autoModeCheckbox">
- Autonomous Mode
- </label>
- <label>
- Delay (sec):
- <input type="number" id="delayInput" value="2" min="0" step="0.1" disabled>
- </label>
- </div>
- `;
- document.body.appendChild(panel);
- console.log("β Control panel injected successfully");
- const autoModeCheckbox = document.getElementById('autoModeCheckbox');
- const delayInput = document.getElementById('delayInput');
- const startBtn = document.getElementById('startBtn');
- const stopBtn = document.getElementById('stopBtn');
- const storedAutoMode = GM_getValue('autoMode', false);
- const storedDelay = GM_getValue('delay', '2');
- console.log(`βοΈ Loaded stored settings - AutoMode: ${storedAutoMode}, Delay: ${storedDelay}s`);
- autoModeCheckbox.checked = storedAutoMode;
- delayInput.value = storedDelay;
- delayInput.disabled = !storedAutoMode;
- function updateButtons() {
- console.log(`π Updating buttons - isRunning: ${isRunning}`);
- startBtn.disabled = isRunning;
- stopBtn.disabled = !isRunning;
- }
- updateButtons();
- autoModeCheckbox.addEventListener('change', () => {
- console.log(`π AutoMode checkbox changed: ${autoModeCheckbox.checked}`);
- GM_setValue('autoMode', autoModeCheckbox.checked);
- delayInput.disabled = !autoModeCheckbox.checked;
- });
- delayInput.addEventListener('change', () => {
- console.log(`β±οΈ Delay input changed: ${delayInput.value}s`);
- GM_setValue('delay', delayInput.value);
- });
- function updateStatus(newStatus, color = '#3498db') {
- console.log(`π‘ Status update: ${currentStatus} β ${newStatus}`);
- currentStatus = newStatus;
- const statusDisplay = document.getElementById('statusDisplay');
- statusDisplay.textContent = `Status: ${newStatus}`;
- statusDisplay.style.backgroundColor = color;
- }
- document.getElementById('startBtn').addEventListener('click', () => {
- console.log("π¬ Start button clicked");
- if (!isRunning) {
- isRunning = true;
- GM_setValue('isRunning', isRunning);
- updateStatus('Running', '#2ecc71');
- updateButtons();
- processQuestion();
- }
- });
- document.getElementById('stopBtn').addEventListener('click', () => {
- console.log("βΉοΈ Stop button clicked");
- isRunning = false;
- GM_setValue('isRunning', isRunning);
- updateStatus('Stopped', '#e74c3c');
- updateButtons();
- });
- window.addEventListener('beforeunload', () => {
- console.log("β οΈ Page unloading - saving state");
- GM_setValue('isRunning', isRunning);
- });
- let pendingDelay = GM_getValue('pendingDelay', null);
- if (isRunning && autoModeCheckbox.checked) {
- console.log(`β³ Resuming pending delay: ${pendingDelay}s`);
- if (pendingDelay !== null) {
- updateStatus(`Delaying (${pendingDelay}s)...`, '#8e44ad');
- setTimeout(() => {
- GM_setValue('pendingDelay', null);
- processQuestion();
- }, parseFloat(pendingDelay) * 1000);
- } else {
- updateStatus('Running', '#2ecc71');
- setTimeout(processQuestion, 1000);
- }
- }
- async function processQuestion() {
- if (!isRunning) {
- console.log("π Process halted - script not running");
- return;
- }
- try {
- console.log("π Starting question processing");
- updateStatus('Processing Question...', '#3498db');
- const questionElement = document.querySelector('.form-group.label-ers span');
- const questionText = questionElement?.innerText?.trim() || '';
- console.log(`π Question text: ${questionText.substring(0, 50)}${questionText.length > 50 ? '...' : ''}`);
- const choices = Array.from(document.querySelectorAll('.form-check'))
- .slice(0, 4)
- .map(el => el.querySelector('label')?.textContent?.trim() || '');
- console.log("π Choices found:", choices);
- if (!questionText || choices.length !== 4) {
- console.warn("β Invalid question/choices structure");
- updateStatus('No Question Found', '#95a5a6');
- isRunning = false;
- GM_setValue('isRunning', isRunning);
- updateButtons();
- return;
- }
- console.log("π€ Requesting answer from Zest API...");
- const answer = await getGPTAnswer(questionText, choices);
- console.log(`π© Received answer: ${answer}`);
- const radioButton = document.querySelector(`#rdPilihan${answer}`);
- if (radioButton) {
- console.log(`β Selecting answer ${answer}`);
- radioButton.click();
- updateStatus('Answer Selected', '#2ecc71');
- if (autoModeCheckbox.checked) {
- const delayValue = parseFloat(delayInput.value) || 0;
- console.log(`β±οΈ Autonomous delay activated: ${delayValue}s`);
- GM_setValue('pendingDelay', delayValue);
- setTimeout(() => {
- GM_setValue('pendingDelay', null);
- const nextBtn = document.getElementById('lnkNext');
- if (nextBtn) {
- // If the next button's text does NOT contain "TAMPILKAN", assume it's the last question.
- if (!nextBtn.innerText.includes('TAMPILKAN')) {
- console.log("π Last question reached. Stopping the script gracefully.");
- isRunning = false;
- GM_setValue('isRunning', isRunning);
- updateStatus('Last question reached. Script stopped.', '#e74c3c');
- updateButtons();
- return;
- } else {
- console.log("β‘οΈ Clicking next question button");
- nextBtn.click();
- }
- }
- }, delayValue * 1000);
- } else {
- isRunning = false;
- GM_setValue('isRunning', isRunning);
- updateStatus('Idle (Awaiting Next Start)', '#95a5a6');
- updateButtons();
- }
- } else {
- throw new Error(`π¨ Answer element for ${answer} not found`);
- }
- } catch (error) {
- console.error(`β Processing error: ${error.message}`);
- isRunning = false;
- GM_setValue('isRunning', isRunning);
- updateStatus(`Error: ${error.message}`, '#e74c3c');
- updateButtons();
- }
- }
- async function getGPTAnswer(question, choices) {
- 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)`;
- console.log("π¨ Sending API request with prompt:", prompt);
- try {
- const response = await fetch(API_ENDPOINT, {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({ messages: [{ role: "user", content: prompt }] })
- });
- if (!response.ok) {
- console.error(`π¨ API response error: ${response.status} ${response.statusText}`);
- throw new Error(`API error: ${response.status}`);
- }
- const result = await response.json();
- console.log("π¦ API response received:", result);
- const answer = result.data?.choices?.content?.trim().toUpperCase();
- if (!['A', 'B', 'C', 'D'].includes(answer)) {
- throw new Error(`Invalid response format: ${answer}`);
- }
- return answer;
- } catch (error) {
- console.error("β API request failed:", error);
- throw error;
- }
- }
- })();
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement