Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions README-selenium.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Kahoot God (Kahoot Answer Bot)

Fork of: https://github.com/The-CodingSloth/kahoot-god

## Description

This project scrapes a Kahoot quiz page, extracts the question and answer choices, and sends them to a local LLM via Ollama for prediction. The model returns the most likely correct answer (0–3 index).

The current version outputs the selected answer to the console. Automated clicking support is planned for future updates.

## How it works

1. Opens Kahoot quiz page
2. Scrapes question + answers using Selenium
3. Sends data to an Ollama model
4. Prints predicted answer index (0–3)

## Prerequisites

- Python 3.10+
- Ollama installed and running
- A compatible model (e.g. llama3, mistral, etc.)
- Required Python packages:
- selenium
- requests
- pyautogui
- pyperclip
- colorama

## Notes

- This project depends on DOM structure and may break if the page layout changes.
- Model accuracy depends heavily on the selected LLM.
- The script may open a new Chrome window. This is expected and is used to scrape the page.
- This repository is a fork of the original project. It has been modified and tuned for additional functionality and is redistributed under the MIT License.

## Credits

Original project: https://github.com/The-CodingSloth/kahoot-god

---
#### Result of using a model with less parameters
[Recording 2026-05-21 105818.mp4](Recording%202026-05-21%20105818.mp4)
270 changes: 270 additions & 0 deletions kahoot_god_selenium.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,270 @@
# ====================
# CONFIG
# ====================

import time
import requests
import pyautogui
import pyperclip
from colorama import init, Fore
import keyboard
import openai


init()

RED = Fore.RED
GREEN = Fore.GREEN
YELLOW = Fore.YELLOW
CYAN = Fore.CYAN
BLUE = Fore.BLUE

provider = input(CYAN + "[1] Ollama\n[2] OpenAi\n[+]\nPlease choose your provider:")
usingOpenai = False

match(provider):
case "1":
usingOpenai = False
case "2":

usingOpenai = True
case _:
print(RED + "[!] Invalid provider")


match(usingOpenai):
case True:
selected_model = input(BLUE + "[!] Please choose your OpenAi model: ").lower() # You can change to your actual model if you are lazy and don't want to enter the model again and again
case False:
selected_model = input(BLUE + "[!] Please choose your model: ").lower()

HOTKEY = "ctrl+b"
WAIT_BEFORE_CAPTURE = 3

def chooseBrowser():
usingBrowsers = []
which_browser = None
a = input(BLUE + "[?] Do you have Chrome (True/False or T/F or 0/1): ")
usingChrome = True
if a.lower() == "f" or a.lower() == "false" or a.lower() == "0":
usingChrome = False
if 'chrome' in usingBrowsers:
usingBrowsers.remove('chrome')

elif a.lower() == "t" or a.lower() == "true" or a.lower() == "1":
usingChrome = True
if 'chrome' not in usingBrowsers:
usingBrowsers.append('chrome')

b = input(BLUE + "[?] Do you have Edge (True/False or T/F or 0/1): ")
usingEdge = False
if b.lower() == "f" or b.lower() == "false" or b.lower() == "0":
usingEdge = False
if 'edge' in usingBrowsers:
usingBrowsers.remove('edge')

elif b.lower() == "t" or b.lower() == "true" or b.lower() == "1":
usingEdge = True
if 'edge' not in usingBrowsers:
usingBrowsers.append('edge')

c = input(BLUE + "[?] Do you have Firefox (True/False or T/F or 0/1): ")
usingFirefox = False
if c.lower() == "f" or c.lower() == "false" or c.lower() == "0":
usingFirefox = False
if 'firefox' in usingBrowsers:
usingBrowsers.remove('firefox')

elif c.lower() == "t" or c.lower() == "true" or c.lower() == "1":
usingFirefox = True
if 'firefox' not in usingBrowsers:
usingBrowsers.append('firefox')

d = input(BLUE + "[?] Do you have Chromium (True/False or T/F or 0/1): ")
usingChromium = False
if d.lower() == "f" or d.lower() == "false" or d.lower() == "0":
usingChromium = False
if 'chrome' in usingChrome:
usingBrowsers.remove('chromium')

elif d.lower() == "t" or d.lower() == "true" or d.lower() == "1":
usingChromium = True
if 'chromium' not in usingChromium:
usingBrowsers.append('chromium')

e = input(BLUE + "[?] Do you have Safari (True/False or T/F or 0/1): ")
usingSafari = False
if e.lower() == "f" or e.lower() == "false" or e.lower() == "0":
usingSafari = False
if 'safari' in usingBrowsers:
usingBrowsers.remove('safari')

elif e.lower() == "t" or e.lower() == "true" or e.lower() == "1":
usingSafari = True
if 'safari' not in usingBrowsers:
usingBrowsers.append('safari')


if len(usingBrowsers) > 1:
for i, browser in enumerate(usingBrowsers):
print(CYAN + f"[{i+1}] {browser}")
which_browser = input(BLUE + f"[+] Which browser you want to use: ")
while which_browser not in usingBrowsers:
print(RED + "[!] Invalid browser")
which_browser = input(YELLOW + f"[+] Try again: ")
print(GREEN + f"[✓] Browser Chosen: {which_browser}")

elif len(usingBrowsers) == 1:
which_browser = usingBrowsers[0]

else:
print(RED + "[!] Does this bro seriously needs TOR just for playing some Kahoot??")

return which_browser

from selenium import webdriver
from selenium.webdriver.common.by import By

def _getOllamaModel(model_list_url):
res = requests.get(model_list_url).json()
model_list = [model["name"].lower() for model in res["models"]]

return model_list

def useOllama(question, answers):
OLLAMA_BASE_URL = "http://localhost:11434"
OLLAMA_MODEL_LIST_URL = f"{OLLAMA_BASE_URL}/api/tags"
OLLAMA_CHAT_URL = f"{OLLAMA_BASE_URL}/api/chat"

model_list = _getOllamaModel(OLLAMA_MODEL_LIST_URL)
for i, model in enumerate(model_list):
print(CYAN + f"[{i+1}] {model}")

while selected_model not in model_list:
print(RED + "[!] Invalid model")
model = input(Fore.MAGENTA + "[!] Please try entering the model name again: ").lower()

print(GREEN + "[✓] Model Chosen: " + selected_model)

system_prompt = """
You are a multiple-choice classifier.

Return ONLY 0, 1, 2, or more positive integers..

No words. No explanation.
IF NO OPTIONS ARE PROVIDED. Make an educational guess.
"""

user_prompt = f"""
Question: {question}
Answers: {answers}
"""

payload = {
"model": selected_model,
"messages": [
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt}
],
"stream": False
}
try:
res = requests.post(OLLAMA_CHAT_URL, json=payload).json()
reply = res["message"]["content"].strip()
return int(reply), selected_model
except ValueError:
print(RED + "[!] Invalid model response: " + reply)
return int(reply[0]), selected_model
except Exception:
print(RED + "[!] Something went wrong.")
print(YELLOW + res)
return None, selected_model




def useOpenAi(question, answers):
openai.api_key = "YOUR_OPENAI_API_KEY"

conversation = [
{
"role": "system",
"content": "You are a helpful assistant specialized in answering multiple-choice questions who only responds with the button number corresponding to the most likely answer do not respond with words only a integer. You'll do this even if the question involves content you can't analyze, such as videos or images. If you cannot answer the question, you'll respond with an educated guess. Remember only respond with an integer between 1 and 4 that corresponds to the answer.",
},
{"role": "user", "content": f"Questions: {question}, Answer choices: {answers}"},
]
try:
response = openai.ChatCompletion.create(model=selected_model,
messages=conversation) # # can be set to 'gpt-4' if needed (yeah I commented the comment, because I am too lazy to delete it)

# Extract the assistant's reply
reply = response["choices"][0]["message"]["content"].strip()
# Return the button number as an integer
return int(reply), selected_model
except ValueError:
# Handle exception here if the reply is not an integer
print(f"Unexpected reply: {reply}")
return int(reply[0]), selected_model
except:
# Handle exception here if something else goes wrong
print("Something went wrong.")
print(response)
return None, selected_model

def get_kahoot_url():
print(YELLOW + "[!] Open Kahoot browser window")
print(YELLOW + f"[!] Waiting {WAIT_BEFORE_CAPTURE} seconds...")

time.sleep(WAIT_BEFORE_CAPTURE)

pyautogui.hotkey('ctrl', 'l')
time.sleep(0.2)
pyautogui.hotkey('ctrl', 'c')

return pyperclip.paste()

def scrape_kahoot(driver):
question = driver.find_element(
By.CSS_SELECTOR,
'span[data-functional-selector="block-title"]'
).text

answers = driver.find_elements(
By.CSS_SELECTOR,
'p[class*="break-long-words"]'
)

answer_list = [a.text for a in answers if a.text != ""]

return question, answer_list

def run_bot(driver):
question, answers = scrape_kahoot(driver)

print(GREEN + f"Q: {question}")
print(GREEN + f"A: {answers}")

if usingOpenai:
answer, model = useOpenAi(question, answers)
elif not usingOpenai:
answer, model = useOllama(question, answers)

print(YELLOW + f"[{model}] Answer: {answer}")

def main():
url = get_kahoot_url()
# ==============================
# Browser Configuration
# ==============================

driver = webdriver.Chrome()
driver.get(url)

print(GREEN + "[✓] Bot ready. Press hotkey to answer.")

keyboard.add_hotkey(HOTKEY, lambda: run_bot(driver))
keyboard.wait()


if __name__ == "__main__":
main()
4 changes: 4 additions & 0 deletions requirements-selenium.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
colorama
pyautogui
pyperclip
selenium