burtenshaw commited on
Commit
31157e8
·
1 Parent(s): fca3f7b

first commit

Browse files
Files changed (6) hide show
  1. .gitignore +10 -0
  2. .python-version +1 -0
  3. app.py +178 -0
  4. example.json +82 -0
  5. pyproject.toml +12 -0
  6. 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