Abhinav commited on
Commit
f2f372e
Β·
1 Parent(s): 1ffa385

Add initial project files

Browse files
Files changed (6) hide show
  1. .gitignore +5 -0
  2. README.md +6 -7
  3. app.py +128 -0
  4. prompts.py +74 -0
  5. requirements.txt +60 -0
  6. stylesheet.py +100 -0
.gitignore ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ env/
2
+ .env
3
+ .env.*
4
+ .env.local
5
+ __pycache__/
README.md CHANGED
@@ -1,14 +1,13 @@
1
  ---
2
  title: Quizy
3
- emoji: 🐒
4
- colorFrom: red
5
- colorTo: blue
6
  sdk: gradio
7
  sdk_version: 5.33.0
8
  app_file: app.py
9
  pinned: false
10
- license: mit
11
  short_description: Quiz Generator by PDFs
12
- ---
13
-
14
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
  title: Quizy
3
+ emoji: πŸ†
4
+ colorFrom: green
5
+ colorTo: yellow
6
  sdk: gradio
7
  sdk_version: 5.33.0
8
  app_file: app.py
9
  pinned: false
10
+ tag: agent-demo-track
11
  short_description: Quiz Generator by PDFs
12
+ videoOverview: https://youtu.be/DcDEcS23ssc
13
+ ---
 
app.py ADDED
@@ -0,0 +1,128 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import json
3
+ import gradio as gr
4
+ import PyPDF2 as pypdf
5
+ from prompts import prompts
6
+ from stylesheet import style
7
+ from dotenv import load_dotenv
8
+ from azure.ai.inference import ChatCompletionsClient
9
+ from azure.ai.inference.models import SystemMessage, UserMessage
10
+ from azure.core.credentials import AzureKeyCredential
11
+
12
+ load_dotenv()
13
+
14
+ css, js = style()
15
+
16
+
17
+ # AI Response Generation Function
18
+ def ai(system_prompt, user_prompt):
19
+ endpoint = "https://abhin-marwbf2g-eastus2.cognitiveservices.azure.com/openai/deployments/gpt-4o"
20
+ model_name = "gpt-4o"
21
+ api_key = os.getenv("API_KEY")
22
+ client = ChatCompletionsClient(
23
+ endpoint=endpoint,
24
+ credential=AzureKeyCredential(api_key),
25
+ )
26
+ response = client.complete(
27
+ messages=[
28
+ SystemMessage(content=system_prompt),
29
+ UserMessage(content=user_prompt),
30
+ ],
31
+ max_tokens=4096,
32
+ temperature=1.0,
33
+ top_p=1.0,
34
+ model=model_name,
35
+ )
36
+ # print("---------AI RESPONSE RECEIVED-----------")
37
+ return response.choices[0].message.content
38
+
39
+
40
+ # PDF To Text Conversion Function
41
+ def convertPdfIntoText(file):
42
+ if file is None:
43
+ return "No file uploaded."
44
+ pypdf_reader = pypdf.PdfReader(file.name)
45
+ text = ""
46
+ for page in pypdf_reader.pages:
47
+ text += page.extract_text() + "\n"
48
+ # print("---------PDF TEXT EXTRACTION DONE-----------")
49
+ return text.strip()
50
+
51
+
52
+ # Gradio Interface Setup
53
+ with gr.Blocks(title="Quizy", css=css, head=js) as demo:
54
+ gr.Markdown("# Quizy: Quiz Generator")
55
+ gr.Markdown("Upload a PDF file to generate a quiz based on its content.")
56
+
57
+ file_input = gr.File(label="Upload PDF File", file_types=[".pdf"])
58
+ submit_btn = gr.Button("Generate Quiz", visible=True, elem_id="generate-btn")
59
+
60
+ with gr.Accordion("Quiz", open=False, visible=False) as quiz_accordion:
61
+ output_container = gr.HTML()
62
+
63
+ # Main Function
64
+ def generate_quiz(file):
65
+ if file is None:
66
+ return "<p>No file uploaded.</p>", gr.Accordion(visible=False)
67
+
68
+ inputData = convertPdfIntoText(file)
69
+
70
+ systemPrompt, userPrompt = prompts(inputData)
71
+ response = ai(systemPrompt, userPrompt)
72
+
73
+ clean_response = response.strip().removeprefix("```json").removesuffix("```")
74
+ clean_response = clean_response.strip()
75
+ quiz_data = json.loads(clean_response)
76
+
77
+ html = "<div class='quiz-container'>"
78
+
79
+ # Store the answers in a separate div for JavaScript access
80
+ answers_json = {
81
+ str(i): question["answer"] for i, question in enumerate(quiz_data["quiz"])
82
+ }
83
+ html += f"<div id='quiz-answers' style='display:none;'>{json.dumps(answers_json)}</div>"
84
+
85
+ for i, question in enumerate(quiz_data["quiz"]):
86
+ question_type = question["type"]
87
+
88
+ answer_json = json.dumps(question["answer"]).replace('"', "&quot;")
89
+ html += f"<div class='question' data-id='{i}' data-type='{question_type}' data-answer='{answer_json}'>"
90
+ html += f"<h3>Question {i+1}: {question['question']}</h3>"
91
+
92
+ if question_type == "single_choice":
93
+ if "options" in question:
94
+ html += "<div class='options'>"
95
+ for option in question["options"]:
96
+ html += f"<div><input type='radio' name='q{i}' value='{option}'> {option}</div>"
97
+ html += "</div>"
98
+ if question_type == "true_false":
99
+ html += "<div class='options'>"
100
+ html += "<div><input type='radio' name='q{i}' value='True'> True</div>"
101
+ html += (
102
+ "<div><input type='radio' name='q{i}' value='False'> False</div>"
103
+ )
104
+ html += "</div>"
105
+ elif question_type == "multiple_choice":
106
+ if "options" in question:
107
+ html += "<div class='options'>"
108
+ for option in question["options"]:
109
+ html += f"<div><input type='checkbox' name='q{i}[]' value='{option}'> {option}</div>"
110
+ html += "</div>"
111
+ elif question_type == "fill_in_the_blank":
112
+ html += "<input type='text' placeholder='Enter your answer here...'>"
113
+
114
+ html += "</div>"
115
+
116
+ html += "<button class='submit-btn' onclick='checkAnswers()'>Submit</button>"
117
+ html += "<div id='result'></div>"
118
+ html += "</div>"
119
+
120
+ return html, gr.Accordion(visible=True)
121
+
122
+ submit_btn.click(
123
+ fn=generate_quiz,
124
+ inputs=file_input,
125
+ outputs=[output_container, quiz_accordion],
126
+ )
127
+
128
+ demo.launch()
prompts.py ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ def prompts(data: str) -> tuple[str, str]:
2
+ """
3
+ System and User prompts for a quiz question generation task.
4
+
5
+ Args:
6
+ data (str): The input data string containing factual or conceptual information.
7
+
8
+ Returns:
9
+ tuple[str, str]: A tuple containing the system prompt and the user prompt.
10
+ """
11
+
12
+ if not isinstance(data, str):
13
+ raise ValueError("Input data must be a string.")
14
+
15
+ if not data.strip():
16
+ raise ValueError("Input data cannot be an empty string.")
17
+
18
+ data = data.strip()
19
+ json_example = r"""
20
+ {"quiz": [
21
+ {"question": "What is the capital of France?",
22
+ "type": "single_choice",
23
+ "options": ["Paris", "London", "Berlin", "Madrid"],
24
+ "answer": "Paris"
25
+ },
26
+ {"question": "Select all the programming languages:",
27
+ "type": "multiple_choice",
28
+ "options": ["Python", "HTML", "Java", "CSS"],
29
+ "answer": ["Python", "Java"]
30
+ },
31
+ {"question": "The sky is blue. (True/False)",
32
+ "type": "true_false",
33
+ "answer": "True"
34
+ },
35
+ {"question": "________ is known as the Red Planet.",
36
+ "type": "fill_in_the_blank",
37
+ "answer": "Mars"
38
+ }
39
+ ]
40
+ }
41
+ """
42
+ system_prompt = f"""
43
+ You are a Quiz Question Generator AI. Your task is to read and understand the provided input data (a plain text string containing factual or conceptual information), and generate a set of quiz questions based on it.
44
+
45
+ The questions should:
46
+ - Be clear, relevant, and varied in format (e.g., multiple choice, single choice, true/false, fill-in-the-blank, etc.).
47
+ - Be phrased in a way that tests comprehension, recall, or reasoning based on the input data.
48
+ - Include 3 to 4 answer options where applicable (e.g., multiple/single choice).
49
+ - Clearly indicate the correct answer(s).
50
+
51
+ Return your output in **valid raw JSON format** using the following structure:
52
+
53
+ ```json
54
+ {json_example}
55
+ ```
56
+ Additional Guidelines:
57
+ Ensure the question and answer pair is clearly and correctly based on the input data string.
58
+
59
+ Do not hallucinate facts that are not present in the provided data.
60
+
61
+ Keep the language simple and clear.
62
+
63
+ Avoid repetition across questions.
64
+
65
+ Only return the JSON structure as your final output. Do not include any commentary or explanation.
66
+ """
67
+ user_prompt = f"""
68
+ Please generate a set of quiz questions based on the following data:
69
+
70
+ {data}
71
+
72
+ Return the questions in JSON format as described, including the correct answers for each. Use a variety of question types such as multiple choice, single choice, true/false, and fill-in-the-blank.
73
+ """
74
+ return system_prompt.strip(), user_prompt.strip()
requirements.txt ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ aiofiles==24.1.0
2
+ annotated-types==0.7.0
3
+ anyio==4.9.0
4
+ azure-ai-inference==1.0.0b9
5
+ azure-core==1.34.0
6
+ certifi==2025.4.26
7
+ charset-normalizer==3.4.2
8
+ click==8.2.1
9
+ colorama==0.4.6
10
+ dotenv==0.9.9
11
+ fastapi==0.115.12
12
+ ffmpy==0.6.0
13
+ filelock==3.18.0
14
+ fsspec==2025.5.1
15
+ gradio==5.32.1
16
+ gradio_client==1.10.2
17
+ groovy==0.1.2
18
+ h11==0.16.0
19
+ httpcore==1.0.9
20
+ httpx==0.28.1
21
+ huggingface-hub==0.32.4
22
+ idna==3.10
23
+ isodate==0.7.2
24
+ Jinja2==3.1.6
25
+ markdown-it-py==3.0.0
26
+ MarkupSafe==3.0.2
27
+ mdurl==0.1.2
28
+ numpy==2.2.6
29
+ orjson==3.10.18
30
+ packaging==25.0
31
+ pandas==2.2.3
32
+ pillow==11.2.1
33
+ pydantic==2.11.5
34
+ pydantic_core==2.33.2
35
+ pydub==0.25.1
36
+ Pygments==2.19.1
37
+ PyPDF2==3.0.1
38
+ python-dateutil==2.9.0.post0
39
+ python-dotenv==1.1.0
40
+ python-multipart==0.0.20
41
+ pytz==2025.2
42
+ PyYAML==6.0.2
43
+ requests==2.32.3
44
+ rich==14.0.0
45
+ ruff==0.11.12
46
+ safehttpx==0.1.6
47
+ semantic-version==2.10.0
48
+ shellingham==1.5.4
49
+ six==1.17.0
50
+ sniffio==1.3.1
51
+ starlette==0.46.2
52
+ tomlkit==0.13.2
53
+ tqdm==4.67.1
54
+ typer==0.16.0
55
+ typing-inspection==0.4.1
56
+ typing_extensions==4.14.0
57
+ tzdata==2025.2
58
+ urllib3==2.4.0
59
+ uvicorn==0.34.3
60
+ websockets==15.0.1
stylesheet.py ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ def style():
2
+ css = """
3
+ .submit-btn {
4
+ padding: 10px 20px;
5
+ color: #333;
6
+ background-color: #face00;
7
+ border: 1px solid #ddd;
8
+ border-radius: 5px;
9
+ margin-top: 20px;
10
+ }
11
+ #result {
12
+ display: none;
13
+ margin: 0;
14
+ padding-left: 20px;
15
+ padding-bottom: 20px;
16
+ color: #000000;
17
+ background-color: darkviolet
18
+ }
19
+ input[type="text"] {
20
+ width: 100%;
21
+ padding: 10px;
22
+ color: #333333;
23
+ border-radius: 5px;
24
+ }
25
+ """
26
+ js = """
27
+ <script>
28
+ function checkAnswers() {
29
+ let score = 0;
30
+ let total = 0;
31
+ const questions = document.querySelectorAll(".question");
32
+ let userAnswer = "";
33
+ const resultElement = document.getElementById("result");
34
+
35
+ questions.forEach((question) => {
36
+ total++;
37
+ const questionType = question.getAttribute("data-type");
38
+ const correctAnswerJSON = question.getAttribute("data-answer");
39
+ const correctAnswer = JSON.parse(correctAnswerJSON);
40
+ const inputs = question.querySelectorAll("input");
41
+
42
+ if (questionType === "single_choice" || questionType === "true_false") {
43
+ // For radio buttons (single selection)
44
+ inputs.forEach((input) => {
45
+ if (input.checked) {
46
+ userAnswer = input.value;
47
+ }
48
+ });
49
+
50
+ if (userAnswer === correctAnswer) {
51
+ score++;
52
+ }
53
+ } else if (questionType === "multiple_choice") {
54
+ // For checkboxes (multiple selection)
55
+ const selectedOptions = Array.from(inputs)
56
+ .filter((input) => input.checked)
57
+ .map((input) => input.value);
58
+
59
+ // Compare arrays (needs to match exactly)
60
+ const correctArray = Array.isArray(correctAnswer)
61
+ ? correctAnswer
62
+ : [correctAnswer];
63
+ if (
64
+ selectedOptions.length === correctArray.length &&
65
+ selectedOptions.every((opt) => correctArray.includes(opt))
66
+ ) {
67
+ score++;
68
+ }
69
+ } else if (questionType === "fill_in_the_blank") {
70
+ // For text input
71
+ userAnswer = inputs[0].value.trim().toLowerCase();
72
+ const correctText = String(correctAnswer).trim().toLowerCase();
73
+
74
+ if (userAnswer === correctText) {
75
+ score++;
76
+ }
77
+ }
78
+ });
79
+
80
+ // Display the result
81
+ resultElement.style.display = "block";
82
+ if (score === total) {
83
+ resultElement.innerHTML = `<h2>Result: </h2> <br />
84
+ <h3>Congratulations! You answered all questions correctly!</h3>
85
+ <h3>Your score: ${score}/${total}</h3>`;
86
+ } else if (score < total / 2) {
87
+ resultElement.innerHTML = `<h2>Result: </h2> <br /> <h3>Keep trying! You can do better!</h3> <h3>Your score: ${score}/${total}</h3>`;
88
+ } else {
89
+ resultElement.innerHTML = `<h2>Result: </h2> <br />
90
+ <h3>Good job! You answered ${score} out of ${total} questions correctly.</h3>
91
+ <h3>Your score: ${score}/${total}</h3>`;
92
+ }
93
+ // resultElement.style.backgroundColor = score > (total/2) ? '#e6ffe6' : '#fff0f0';
94
+ resultElement.style.border = "1px solid #ddd";
95
+ resultElement.style.borderRadius = "5px";
96
+ resultElement.style.marginTop = "20px";
97
+ }
98
+ </script>
99
+ """
100
+ return css, js