-
-
Save flleeppyy/0d06012f07d334c6d4659a61679b44b9 to your computer and use it in GitHub Desktop.
Fuck Apex Learning
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// const fetch = require("node-fetch") | |
let createPlaceholderAnswer = (letter, description) => ({ | |
value: `${letter}. ${description}`, | |
letter, | |
select: () => { | |
console.log("debug: called select() in answer", letter); | |
}, | |
}); | |
let sleep = (time = 1000) => { | |
console.log("sleeping for", time); | |
return new Promise((resolve) => setTimeout(() => resolve(), time)); | |
} | |
let PLACEHOLDER_QUESTION = | |
"According to the CIA Triad, which situation is the best example of confidentiality of data?"; | |
let PLACEHOLDER_ANSWERS = [ | |
createPlaceholderAnswer( | |
"A", | |
"A hospital hires a specialist to make sure medical records are accurate and reviewed for any errors.", | |
), | |
createPlaceholderAnswer( | |
"B", | |
"An app developer merges user data from two separate accounts but only has access to the data needed to do their job.", | |
), | |
createPlaceholderAnswer( | |
"C", | |
"A website that sells concert tickets online makes all customers use CAPTCHA to complete their transactions.", | |
), | |
createPlaceholderAnswer( | |
"D", | |
"An educational company provides 24-hour web access to its training videos.", | |
), | |
]; | |
let autoclickStudy = async () => { | |
// Activity Completed | |
const activityCompletedYes = document.querySelector(".cdk-overlay-pane mat-dialog-container .mat-dialog-actions button:nth-child(2)") | |
if (activityCompletedYes) { | |
activityCompletedYes.click(); | |
return; | |
} | |
const next = document.querySelector("kp-nav-footer kp-content-lane .nav-section:nth-child(3) button"); | |
if (!next) { | |
return; | |
} | |
next.click(); | |
await new Promise((resolve) => setTimeout(() => resolve(), 1000)) | |
return autoclickStudy(); | |
} | |
let apexnt = () => { | |
const OPENAI_TOKEN = ""; | |
const MODEL = "gpt-4-1106-preview"; | |
const WAIT_BEFORE_NEXT = 25; | |
//const MODEL = "gpt-3.5-turbo" | |
const QUERY_TASK = `Task: Identify the correct option (or options in case of a multiple-answer question) that best answers the provided question and provide your answer in the format: {"letters": ["Letter(s) to the correct options"], "explanation": "[Few words explaining why the choice is correct]", "certainty": "[How certain, in %, are you that the answer is correct]"}.`; | |
// for browser env, leave empty if not needed | |
const CORS_PROXY = ""; // "https://cors-anywhere.herokuapp.com/"; | |
const MAX_ATTEMPTS = 3; | |
const ENABLE_SABOTAGE = true; | |
const INCORRECT_ANSWERS = 2; | |
const INCORRECT_RANDOM_PERCENT = 40; | |
let loopStopped = false; | |
let attempts = 0; | |
let incorrectAnswers = 0; | |
const sendQuery = async (content = "", model = MODEL, task = QUERY_TASK) => { | |
try { | |
const response = await ( | |
await fetch(`${CORS_PROXY}https://api.openai.com/v1/chat/completions`, { | |
method: "POST", | |
body: JSON.stringify({ | |
model, | |
messages: [ | |
{ | |
role: "user", | |
content: `${content}\n\n${task}`, | |
}, | |
], | |
}), | |
response_format: { type: "json_object" }, | |
headers: { | |
Authorization: `Bearer ${OPENAI_TOKEN}`, | |
"Content-Type": "application/json", | |
}, | |
}) | |
).json(); | |
const result = response?.choices?.[0]?.message?.content; | |
if (typeof result === "string") { | |
return JSON.parse(result); | |
} | |
return null; | |
} catch (error) { | |
console.log("failed to fetch query", { error }); | |
return null; | |
} | |
}; | |
const getContext = () => { | |
let question; | |
let answers; | |
let questionNum = 1; | |
let totalQuestions = 1; | |
if (typeof window === "undefined") { | |
console.warn("cannot automatically retrieve query in node environment"); | |
question = PLACEHOLDER_QUESTION; | |
answers = PLACEHOLDER_ANSWERS; | |
} else { | |
question = document.querySelector(".sia-question-stem")?.innerText ?? ""; | |
answers = [...document.querySelectorAll(".sia-input .label")] | |
.map((el) => { | |
const value = ( | |
el.querySelector(".label")?.innerText ?? "" | |
).replaceAll("\n", ""); | |
const letter = value.charAt(0).toUpperCase(); | |
return { | |
value, | |
letter, | |
select: () => { | |
el.click(); | |
}, | |
}; | |
}) | |
.filter((answer) => answer.value.trim().length >= 1); | |
const questionInfoText = document.querySelector(".sia-question-number")?.innerText ?? ""; | |
const questionRegexResult = /Question (.*) of (.*)/.exec(questionInfoText); | |
if (questionRegexResult) { | |
questionNum = parseInt(questionRegexResult[1]) || 1; | |
totalQuestions = parseInt(questionRegexResult[2]) || 1; | |
} | |
} | |
return { | |
question, | |
answers, | |
questionNum, | |
totalQuestions, | |
formattedQuery: [ | |
question, | |
"", | |
"Options:", | |
...new Set(answers.map(({ value }) => value)), | |
].join("\n"), | |
}; | |
}; | |
const shouldSabotage = (totalQuestions) => { | |
if (!ENABLE_SABOTAGE) { | |
return false; | |
} | |
if (totalQuestions <= INCORRECT_ANSWERS) { | |
return false; | |
} | |
if (incorrectAnswers >= INCORRECT_ANSWERS) { | |
return false; | |
} | |
return Math.random() < INCORRECT_RANDOM_PERCENT / 100; | |
} | |
const run = async () => { | |
if (attempts >= MAX_ATTEMPTS) { | |
console.log(`giving up after ${attempts} attempts`); | |
return; | |
} | |
attempts++; | |
const { formattedQuery, answers, question, totalQuestions } = getContext(); | |
if (question.trim().length < 1) { | |
console.log("cannot get another question, exiting"); | |
return; | |
} | |
if (loopStopped) { | |
console.log("loop forcefully stopped, exiting"); | |
return; | |
} | |
console.log(`Query: \n${formattedQuery}\n`); | |
const answer = await sendQuery(formattedQuery); | |
console.log(`Query result: \n`, answer); | |
if (!answer) { | |
console.log("Failed to retrieve an answer"); | |
return run(); | |
} | |
attempts = 0; | |
const sabotage = shouldSabotage(totalQuestions); | |
answer.letters.forEach((letter) => { | |
const answerObj = answers.find((answer) => sabotage ? answer.letter !== letter : answer.letter === letter); | |
if (answerObj) { | |
answerObj.select(); | |
if (sabotage) { | |
console.log("sabotaging this question, correct answer is", answer.letters, "choosing", answerObj.letter, "instead"); | |
} | |
} | |
}); | |
await sleep(WAIT_BEFORE_NEXT * formattedQuery.length); | |
// Submit | |
document.querySelector("kp-question-controls button")?.click(); | |
await sleep(); | |
const answerTextEl = document.querySelector(".feedback-body.active kp-feedback-header span.header-text") | |
const isIncorrect = answerTextEl?.innerText === "Incorrect"; | |
console.log(answerTextEl, isIncorrect) | |
if (isIncorrect) { | |
console.log("answer is incorrect"); | |
incorrectAnswers++; | |
} | |
// Next question | |
document.querySelector("kp-question-controls button")?.click(); | |
await sleep(); | |
return run(); | |
}; | |
const stopLoop = () => { | |
loopStopped = true; | |
}; | |
if (typeof window !== "undefined") { | |
window.stopLoop = stopLoop; | |
} else { | |
process.stopLoop = stopLoop; | |
} | |
return run(); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment