Skip to content

Instantly share code, notes, and snippets.

@lilianalillyy
Created December 28, 2023 14:38
Show Gist options
  • Save lilianalillyy/c639e00c6d650630b88e5c4737abd5f3 to your computer and use it in GitHub Desktop.
Save lilianalillyy/c639e00c6d650630b88e5c4737abd5f3 to your computer and use it in GitHub Desktop.
Fuck Moodle (based on Fuck Apex Learning)
(() => {
const OPENAI_TOKEN = "";
const MODEL = "gpt-4-1106-preview";
//const MODEL = "gpt-3.5-turbo"
const ADDITIONAL_QUERY = "These questions are asked within the context of the Czech Republic and it's law.";
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]"}. ${ADDITIONAL_QUERY}`.trimEnd();
// for browser env, leave empty if not needed
const CORS_PROXY = ""; // "https://cors-anywhere.herokuapp.com/";
const MAX_ATTEMPTS = 3;
let attempts = 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 = () => {
const question = (document.querySelector(".qtext")?.innerText ?? "").trim();
const answers = [...document.querySelectorAll(".answer > div")]
.map((el) => {
const value = el.textContent.replaceAll("\n", "");
const letter = value.charAt(0).toUpperCase();
return {
value,
letter,
select: () => {
el.querySelector("input")?.click()
},
};
})
.filter((answer) => answer.value.trim().length >= 1);
return {
question,
answers,
formattedQuery: [
question,
"",
"Options:",
...new Set(answers.map(({ value }) => value)),
].join("\n"),
};
};
const run = async () => {
if (attempts >= MAX_ATTEMPTS) {
console.log(`giving up after ${attempts} attempts`);
return;
}
attempts++;
const { formattedQuery, answers, question } = getContext();
if (question.trim().length < 1) {
console.log("cannot get another question, 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;
answer.letters.forEach((letter) => {
const answerObj = answers.find((answer) => answer.letter.toLowerCase() === letter.toLowerCase());
if (answerObj) {
console.log("selecting", answerObj);
answerObj.select();
}
});
};
return run();
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment