Code viewer for World: Exam Paper Generator
//styles done
(function () {
    const styles = `
        body {
            font-family: "Times New Roman", serif;
            margin: 20px;
            padding: 0;
            background-color: #3c2f2f; 
            color: #f8f3d4; 
            background-size: cover;
            background-attachment: fixed;
        }
        h1, h3, h5 {
            font-family: "Garamond", serif;
            color: #c9aa71; 
            text-shadow: 1px 1px 2px #1e130e;
        }
        button {
            background-color: #704214; 
            color: #f8f3d4; 
            border: 2px solid #c9aa71; 
            padding: 10px 20px;
            cursor: pointer;
            border-radius: 5px;
            box-shadow: 2px 2px 5px #1e130e; 
            font-family: "Courier New", monospace; 
        }
        button:hover {
            background-color: #c9aa71; 
            color: #704214; 
        }
        #maindiv {
            background-color: rgba(60, 47, 47, 0.9); 
            border: 2px solid #c9aa71; 
            padding: 20px;
            border-radius: 10px;
            box-shadow: 0 0 10px 2px #c9aa71; 
        }
        #output, #answers, #solutions, #answers-to-alt-questions {
            margin-top: 20px;
            padding: 15px;
            border: 2px solid #c9aa71; 
            border-radius: 10px;
            background-color: #423635; 
            display: none; 
        }
        label {
            font-weight: bold;
            color: #c9aa71; 
        }
        input[type="password"], input[type="file"] {
            background-color: #423635;
            color: #f8f3d4;
            border: 1px solid #c9aa71;
            border-radius: 5px;
            padding: 5px;
            font-family: "Courier New", monospace;
        }
        select {
            background-color: #423635;
            color: #f8f3d4;
            border: 1px solid #c9aa71;
            border-radius: 5px;
            padding: 5px;
            font-family: "Courier New", monospace;
        }
        pre {
            font-family: "Courier New", monospace;
            color: #f8f3d4;
            background-color: #322828; 
            padding: 10px;
            border-radius: 5px;
            border: 1px solid #704214;
        }
    `;
    
     // adds the CSS styles into the page
    const styleSheet = document.createElement("style");
    styleSheet.type = "text/css";
    styleSheet.innerText = styles;
    document.head.appendChild(styleSheet);

// adds the html into the page

    document.write(`
        <div id="maindiv">
            <h1>Alternate Exam Question Generator</h1>
            <h3>Upload past exam papers to receive an alternate list of questions from the same core topic</h3>
            <h3>When you receive your new questions, click the button below to reveal your answers</h3>
            <h5>BE PATIENT! I'm fueled by AI, not magic!</h5>
            <div id="model-selector">
                <label>Select Model:</label>
                <select id="model-dropdown">
                    <option value="CHATGPT" selected>CHATGPT</option>
                    <option value="GEMINI">GEMINI</option>
                </select>
            </div>
            <br>
            <div id="api-key-section">
                <label>Enter your API Key:</label>
                <input type="password" id="api-key" placeholder="sk-..." style="width: 60%;">
            </div>
            <br>
            <form id="upload-form">
                <input type="file" id="file-input" accept="application/pdf" required>
                <button type="submit">Upload and Generate Questions</button>
            </form>
            <div id="output">
                <h2>Generated Alternate Questions:</h2>
                <div id="questions"></div>
                <button id="reveal-questions-button" style="display: none;">Reveal Alternate Questions</button>
                <div id="answers" style="display: none;">
                    <h3>Alternate Questions:</h3>
                    <pre id="answers-text"></pre>
                    <button id="reveal-solutions-button" style="margin-top: 10px;">Reveal Solutions</button>
                </div>
            </div>
            <div id="solutions">
                <h2>Solutions to Questions:</h2>
                <pre id="solutions-text"></pre>
                <button id="reveal-answers-to-alt-questions-button" style="margin-top: 10px;">Reveal Answers to Alternate Questions</button>
            </div>
            <div id="answers-to-alt-questions">
                <h2>Answers to Alternate Questions:</h2>
                <pre id="alt-answers-text"></pre>
            </div>
        </div>
    `);

    // imports PDF.js script for handling past exam paper PDFs
    const script = document.createElement("script");
    script.src = "https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.16.105/pdf.min.js";
    document.head.appendChild(script);

    // Wait until the PDF.js script is loaded
    script.onload = function () {
        // Event handlers and functionality
        let apikey = ""; // Stores the API key entered by the user

 // Handles pdf submission for uploading from the client

        document.querySelector("#upload-form").onsubmit = async function (event) {
            event.preventDefault();
            const file = document.getElementById("file-input").files[0];
            apikey = document.getElementById("api-key").value.trim();

            if (!file || !apikey) {
                alert("Please provide all required inputs.");
                return;
            }
            
            // parses text from the uploaded paper, and then extracts test to be later added to a prompt
            const text = await extractTextFromPDF(file);
            const content = [
                "You are an assistant that generates exam questions.",
                `Here are some exam questions: ${text}. Generate alternate related questions, just the questions nothing else.`
            ];
            const alternateQuestions = await model(apikey, content);

            if (alternateQuestions) {
                document.querySelector("#questions").innerHTML = `<p>Alternate questions are ready. Click the button below to reveal them.</p>`;
                document.querySelector("#answers-text").textContent = alternateQuestions;
                document.querySelector("#reveal-questions-button").style.display = "block";
                document.querySelector("#output").style.display = "block";
            } else {
                alert("Failed to generate questions.");
            }
        };
        
                // Reveals alternate questions when the button is clicked

        document.querySelector("#reveal-questions-button").onclick = function () {
            document.querySelector("#answers").style.display = "block";
            this.style.display = "none";
        };

         // Generates solutions when the button is clicked

        document.querySelector("#reveal-solutions-button").onclick = async function () {
            const message = document.querySelector("#answers-text").textContent;
            const content = [
                "You are an assistant that generates exam questions answers.",
                `Here are some exam questions: ${message}. Generate the answers of all of them.`
            ];
            const solutions = await model(apikey, content);

            if (solutions) {
                document.querySelector("#solutions").style.display = "block";
                document.querySelector("#solutions-text").textContent = solutions;
            } else {
                alert("Failed to generate solutions.");
            }
        };

            // Reveals solutions when the button is clicked


        document.querySelector("#reveal-answers-to-alt-questions-button").onclick = function () {
            document.querySelector("#answers-to-alt-questions").style.display = "block";
        };
// Extracts text from the pdf using PDF.js
        async function extractTextFromPDF(file) {
            const pdf = await pdfjsLib.getDocument(URL.createObjectURL(file)).promise;
            let text = "";
            for (let i = 1; i <= pdf.numPages; i++) {
                const page = await pdf.getPage(i);
                const content = await page.getTextContent();
                text += content.items.map(item => item.str).join(" ") + "\n";
            }
            return text;
        }
                // User Chooses the model for generating the alt qs and answers

        async function model(apiKey, content) {
            const selectedModel = document.querySelector("#model-dropdown").value;
            return selectedModel === "CHATGPT"
                ? await callGPTAPI(apiKey, content)
                : await callGemini(apiKey, content);
        }
        
                // Calls the GPT API to generate output

        async function callGPTAPI(apiKey, content) {
            const response = await fetch("https://api.openai.com/v1/chat/completions", {
                method: "POST",
                headers: {
                    "Content-Type": "application/json",
                    "Authorization": `Bearer ${apiKey}`
                },
                body: JSON.stringify({
                    model: "gpt-4",
                    messages: [
                        { role: "system", content: content[0] },
                        { role: "user", content: content[1] }
                    ],
                    max_tokens: 2000
                })
            });
            const data = await response.json();
            return response.ok ? data.choices[0].message.content.trim() : null;
        }


                // Calls the Gemini API to generate output


        async function callGemini(apiKey, content) {
            const response = await fetch(`https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash-latest:generateContent?key=${apiKey}`, {
                method: "POST",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({
                    contents: [
                        { parts: [{ text: content[0] }, { text: content[1] }] }
                    ]
                })
            });
            const data = await response.json();
            return response.ok ? data.candidates[0].content.parts[0].text.trim() : null;
        }
    };
})();