Spaces:
Runtime error
Runtime error
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
|
|
|