Spaces:
Running
Running
burtenshaw
commited on
Commit
·
31157e8
1
Parent(s):
fca3f7b
first commit
Browse files- .gitignore +10 -0
- .python-version +1 -0
- app.py +178 -0
- example.json +82 -0
- pyproject.toml +12 -0
- uv.lock +0 -0
.gitignore
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Python-generated files
|
2 |
+
__pycache__/
|
3 |
+
*.py[oc]
|
4 |
+
build/
|
5 |
+
dist/
|
6 |
+
wheels/
|
7 |
+
*.egg-info
|
8 |
+
|
9 |
+
# Virtual environments
|
10 |
+
.venv
|
.python-version
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
3.11
|
app.py
ADDED
@@ -0,0 +1,178 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
|
3 |
+
import gradio as gr
|
4 |
+
from datasets import load_dataset, Dataset
|
5 |
+
from huggingface_hub import whoami
|
6 |
+
|
7 |
+
|
8 |
+
EXAM_DATASET_ID = os.getenv("EXAM_DATASET_ID") or "burtenshaw/exam_questions"
|
9 |
+
|
10 |
+
ds = load_dataset(EXAM_DATASET_ID, split="train")
|
11 |
+
|
12 |
+
# Convert dataset to a list of dicts so we can iterate similarly to quiz_data
|
13 |
+
quiz_data = ds.to_pandas().to_dict("records") # or use a for-loop if you prefer
|
14 |
+
|
15 |
+
|
16 |
+
def on_user_logged_in(token: gr.OAuthToken | None):
|
17 |
+
"""
|
18 |
+
If the user has a valid token, hide the login button and show the Start button.
|
19 |
+
Otherwise, keep the login button visible, hide Start.
|
20 |
+
"""
|
21 |
+
if token is not None:
|
22 |
+
return gr.update(visible=False), gr.update(visible=True)
|
23 |
+
else:
|
24 |
+
# Not logged in, keep the login visible, hide Start
|
25 |
+
return gr.update(visible=True), gr.update(visible=False)
|
26 |
+
|
27 |
+
|
28 |
+
def push_results_to_hub(user_answers, token: gr.OAuthToken | None):
|
29 |
+
"""
|
30 |
+
Create a new dataset from user_answers and push it to the Hub.
|
31 |
+
We use the user's HF token to determine the correct repo.
|
32 |
+
If no one is logged in, we'll return an error message.
|
33 |
+
"""
|
34 |
+
if token is None:
|
35 |
+
gr.Warning("Please log in to Hugging Face before pushing!")
|
36 |
+
return
|
37 |
+
else:
|
38 |
+
gr.Info("Submitting answers to the Hub. Please wait...", duration=2)
|
39 |
+
user_info = whoami(token=token.token)
|
40 |
+
repo_id = f"{user_info['name']}/quiz-responses" # e.g. 'myUsername/quiz-responses'
|
41 |
+
|
42 |
+
new_ds = Dataset.from_list(user_answers)
|
43 |
+
new_ds.push_to_hub(repo_id)
|
44 |
+
gr.Success("Your responses have been submitted to the Hub!")
|
45 |
+
|
46 |
+
|
47 |
+
def handle_quiz(question_idx, user_answers, selected_answer, is_start):
|
48 |
+
"""
|
49 |
+
A single function that handles both 'Start' and 'Next' logic:
|
50 |
+
- If is_start=True, skip storing an answer and show the first question.
|
51 |
+
- Otherwise, store the last answer and move on.
|
52 |
+
- If we've reached the end, display results.
|
53 |
+
"""
|
54 |
+
# Hide the start button once the first question is shown
|
55 |
+
start_btn_update = gr.update(visible=False) if is_start else None
|
56 |
+
|
57 |
+
# If this is the first time (start=True), begin at question_idx=0
|
58 |
+
if is_start:
|
59 |
+
question_idx = 0
|
60 |
+
else:
|
61 |
+
# If not the very first question, store the user's last selection
|
62 |
+
if question_idx < len(quiz_data):
|
63 |
+
current_q = quiz_data[question_idx]
|
64 |
+
user_answers.append(
|
65 |
+
{"question": current_q["question"], "selected_answer": selected_answer}
|
66 |
+
)
|
67 |
+
question_idx += 1
|
68 |
+
|
69 |
+
# If we've reached the end, show final results
|
70 |
+
if question_idx >= len(quiz_data):
|
71 |
+
final_text = f"**All questions answered!**\n\nHere are your selections:\n\n{user_answers}"
|
72 |
+
return (
|
73 |
+
"", # question_text becomes blank
|
74 |
+
gr.update(choices=[], visible=False),
|
75 |
+
"", # status_text (can clear or reuse)
|
76 |
+
question_idx,
|
77 |
+
user_answers,
|
78 |
+
start_btn_update,
|
79 |
+
gr.update(value=final_text, visible=True), # show final_markdown
|
80 |
+
)
|
81 |
+
else:
|
82 |
+
# Otherwise, show the next question
|
83 |
+
q = quiz_data[question_idx]
|
84 |
+
updated_question = f"## **Question {question_idx + 1}**: {q['question']}"
|
85 |
+
return (
|
86 |
+
updated_question,
|
87 |
+
gr.update(
|
88 |
+
choices=[
|
89 |
+
q["answer_a"],
|
90 |
+
q["answer_b"],
|
91 |
+
q["answer_c"],
|
92 |
+
q["answer_d"],
|
93 |
+
],
|
94 |
+
value=None,
|
95 |
+
visible=True,
|
96 |
+
),
|
97 |
+
"Select an answer and click 'Next' to continue.",
|
98 |
+
question_idx,
|
99 |
+
user_answers,
|
100 |
+
start_btn_update,
|
101 |
+
gr.update(visible=False), # Hide final_markdown for now
|
102 |
+
)
|
103 |
+
|
104 |
+
|
105 |
+
def success_message(response):
|
106 |
+
# response is whatever push_results_to_hub returned
|
107 |
+
return f"{response}\n\n**Success!**"
|
108 |
+
|
109 |
+
|
110 |
+
with gr.Blocks() as demo:
|
111 |
+
demo.title = f"Dataset Quiz for {EXAM_DATASET_ID}"
|
112 |
+
|
113 |
+
# Header
|
114 |
+
gr.Markdown(f"## Welcome to the {EXAM_DATASET_ID} Quiz")
|
115 |
+
gr.Markdown(
|
116 |
+
"Log in first, then click 'Start' to begin. Answer each question, click 'Next', and finally click 'Submit' to publish your results to the Hugging Face Hub."
|
117 |
+
)
|
118 |
+
|
119 |
+
# Step 1: Login
|
120 |
+
login_btn = gr.LoginButton()
|
121 |
+
# We'll hide the Start button until user logs in
|
122 |
+
start_btn = gr.Button("Start", visible=False)
|
123 |
+
|
124 |
+
# State variables
|
125 |
+
question_idx = gr.State(value=0)
|
126 |
+
user_answers = gr.State(value=[])
|
127 |
+
|
128 |
+
# We display question text with Markdown
|
129 |
+
question_text = gr.Markdown("")
|
130 |
+
status_text = gr.Markdown("")
|
131 |
+
radio_choices = gr.Radio(label="Your Answer", choices=[], visible=False)
|
132 |
+
|
133 |
+
# Final results after all questions are done
|
134 |
+
final_markdown = gr.Markdown("", visible=False)
|
135 |
+
|
136 |
+
next_btn = gr.Button("Next")
|
137 |
+
submit_btn = gr.Button("Submit")
|
138 |
+
|
139 |
+
# Use click() instead of login()
|
140 |
+
login_btn.click(fn=on_user_logged_in, inputs=None, outputs=[login_btn, start_btn])
|
141 |
+
|
142 |
+
# Click "Start" => show first question, hide Start button
|
143 |
+
start_btn.click(
|
144 |
+
fn=handle_quiz,
|
145 |
+
inputs=[question_idx, user_answers, radio_choices, gr.State(True)],
|
146 |
+
outputs=[
|
147 |
+
question_text,
|
148 |
+
radio_choices,
|
149 |
+
status_text,
|
150 |
+
question_idx,
|
151 |
+
user_answers,
|
152 |
+
start_btn,
|
153 |
+
final_markdown,
|
154 |
+
],
|
155 |
+
)
|
156 |
+
|
157 |
+
# Click "Next" => store selection, move on
|
158 |
+
next_btn.click(
|
159 |
+
fn=handle_quiz,
|
160 |
+
inputs=[question_idx, user_answers, radio_choices, gr.State(False)],
|
161 |
+
outputs=[
|
162 |
+
question_text,
|
163 |
+
radio_choices,
|
164 |
+
status_text,
|
165 |
+
question_idx,
|
166 |
+
user_answers,
|
167 |
+
start_btn,
|
168 |
+
final_markdown,
|
169 |
+
],
|
170 |
+
)
|
171 |
+
|
172 |
+
submit_btn.click(fn=push_results_to_hub, inputs=[user_answers])
|
173 |
+
|
174 |
+
|
175 |
+
if __name__ == "__main__":
|
176 |
+
# Note: If testing locally, you'll need to run `huggingface-cli login` or set HF_TOKEN
|
177 |
+
# environment variable for the login to work locally.
|
178 |
+
demo.launch()
|
example.json
ADDED
@@ -0,0 +1,82 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
[
|
2 |
+
{
|
3 |
+
"question": "Which of the following best describes a Large Language Model (LLM)?",
|
4 |
+
"answer_a": "A model specializing in language recognition",
|
5 |
+
"answer_b": "A massive neural network that understands and generates human language",
|
6 |
+
"answer_c": "A model exclusively used for language data tasks like summarization or classification",
|
7 |
+
"answer_d": "A rule-based chatbot used for conversations",
|
8 |
+
"correct_answer": "B"
|
9 |
+
},
|
10 |
+
{
|
11 |
+
"question": "LLMs are typically:",
|
12 |
+
"answer_a": "Pre-trained on small, curated datasets",
|
13 |
+
"answer_b": "Trained on large text corpora to capture linguistic patterns",
|
14 |
+
"answer_c": "Trained purely on translation tasks",
|
15 |
+
"answer_d": "Designed to function solely with GPU resources",
|
16 |
+
"correct_answer": "B"
|
17 |
+
},
|
18 |
+
{
|
19 |
+
"question": "Which of the following is a common architecture for LLMs?",
|
20 |
+
"answer_a": "Convolutional Neural Networks (CNNs)",
|
21 |
+
"answer_b": "Transformer",
|
22 |
+
"answer_c": "Recurrent Neural Networks (RNNs) with LSTM",
|
23 |
+
"answer_d": "Support Vector Machines",
|
24 |
+
"correct_answer": "B"
|
25 |
+
},
|
26 |
+
{
|
27 |
+
"question": "What does it mean when we say LLMs are \"autoregressive\"?",
|
28 |
+
"answer_a": "They regress to the mean to reduce variance",
|
29 |
+
"answer_b": "They generate text by predicting the next token based on previous tokens",
|
30 |
+
"answer_c": "They can only handle labeled data",
|
31 |
+
"answer_d": "They can output text only after the entire input is known at once",
|
32 |
+
"correct_answer": "B"
|
33 |
+
},
|
34 |
+
{
|
35 |
+
"question": "Which of these is NOT a common use of LLMs?",
|
36 |
+
"answer_a": "Summarizing content",
|
37 |
+
"answer_b": "Generating code",
|
38 |
+
"answer_c": "Playing strategy games like chess or Go",
|
39 |
+
"answer_d": "Conversational AI",
|
40 |
+
"correct_answer": "C"
|
41 |
+
},
|
42 |
+
{
|
43 |
+
"question": "Which of the following best describes a \"special token\"?",
|
44 |
+
"answer_a": "A token that makes the model forget all context",
|
45 |
+
"answer_b": "A model signature required for API calls",
|
46 |
+
"answer_c": "A token that helps segment or structure the conversation in the model",
|
47 |
+
"answer_d": "A token that always represents the end of text",
|
48 |
+
"correct_answer": "C"
|
49 |
+
},
|
50 |
+
{
|
51 |
+
"question": "What is the primary goal of a \"chat template\"?",
|
52 |
+
"answer_a": "To force the model into a single-turn conversation",
|
53 |
+
"answer_b": "To structure interactions and define roles in a conversation",
|
54 |
+
"answer_c": "To replace the need for system messages",
|
55 |
+
"answer_d": "To store prompts into the model's weights permanently",
|
56 |
+
"correct_answer": "B"
|
57 |
+
},
|
58 |
+
{
|
59 |
+
"question": "How do tokenizers handle text for modern NLP models?",
|
60 |
+
"answer_a": "By splitting text into individual words only",
|
61 |
+
"answer_b": "By breaking words into subword units and assigning numerical IDs",
|
62 |
+
"answer_c": "By storing text directly without transformation",
|
63 |
+
"answer_d": "By removing all punctuation automatically",
|
64 |
+
"correct_answer": "B"
|
65 |
+
},
|
66 |
+
{
|
67 |
+
"question": "Which role in a conversation sets the overall behavior for a model?",
|
68 |
+
"answer_a": "user",
|
69 |
+
"answer_b": "system",
|
70 |
+
"answer_c": "assistant",
|
71 |
+
"answer_d": "developer",
|
72 |
+
"correct_answer": "B"
|
73 |
+
},
|
74 |
+
{
|
75 |
+
"question": "Which statement is TRUE about tool usage in chat templates?",
|
76 |
+
"answer_a": "Tools cannot be used within the conversation context.",
|
77 |
+
"answer_b": "Tools are used only for logging messages.",
|
78 |
+
"answer_c": "Tools allow the assistant to offload tasks like web search or calculations.",
|
79 |
+
"answer_d": "Tools are unsupported in all modern LLMs.",
|
80 |
+
"correct_answer": "C"
|
81 |
+
}
|
82 |
+
]
|
pyproject.toml
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
[project]
|
2 |
+
name = "quiz-app"
|
3 |
+
version = "0.1.0"
|
4 |
+
description = "Add your description here"
|
5 |
+
readme = "README.md"
|
6 |
+
requires-python = ">=3.11"
|
7 |
+
dependencies = [
|
8 |
+
"datasets>=3.2.0",
|
9 |
+
"gradio[oauth]>=5.13.1",
|
10 |
+
"huggingface-hub>=0.27.1",
|
11 |
+
"ipykernel>=6.29.5",
|
12 |
+
]
|
uv.lock
ADDED
The diff for this file is too large to render.
See raw diff
|
|