File size: 12,054 Bytes
db2ea12
8f11219
42397ec
7340672
9c81979
1cb973f
 
 
db2ea12
7340672
db2ea12
7340672
8f11219
7340672
9708d0e
38a2fd0
1cb973f
 
 
db2ea12
 
 
 
42397ec
db2ea12
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38a2fd0
 
db2ea12
 
 
9708d0e
7340672
c124d82
 
 
 
0bc91b7
ee84103
7340672
c124d82
 
 
 
 
 
 
 
 
 
 
 
9708d0e
 
db2ea12
 
 
 
 
 
9708d0e
1cb973f
 
db2ea12
1cb973f
 
db2ea12
1cb973f
db2ea12
1cb973f
 
 
 
 
7340672
db2ea12
9708d0e
 
 
 
 
1cb973f
7340672
db2ea12
 
9708d0e
1cb973f
7340672
1cb973f
7340672
 
db2ea12
1cb973f
7340672
1cb973f
7340672
 
 
1cb973f
 
7340672
1cb973f
db2ea12
 
9708d0e
1cb973f
7340672
9708d0e
db2ea12
 
 
9708d0e
 
7340672
9708d0e
1cb973f
db2ea12
38a2fd0
db2ea12
 
9708d0e
db2ea12
 
9708d0e
1cb973f
9708d0e
 
8f11219
 
38a2fd0
 
 
 
9708d0e
7340672
9708d0e
1cb973f
9708d0e
 
db2ea12
7340672
9708d0e
 
 
 
7340672
8f11219
10152dd
 
9708d0e
 
 
 
 
 
38a2fd0
 
 
9708d0e
 
 
 
 
8f11219
9708d0e
 
 
7340672
9708d0e
 
 
 
 
7340672
9708d0e
 
db2ea12
38a2fd0
 
 
 
 
 
 
9708d0e
 
db2ea12
 
9708d0e
a0a25b4
 
3f549e4
db2ea12
7340672
db2ea12
9708d0e
 
3f549e4
9708d0e
1cb973f
42397ec
 
7340672
db2ea12
7340672
9708d0e
 
1cb973f
db2ea12
 
 
9708d0e
 
db2ea12
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
# app.py
import gradio as gr
from tool2 import * # Make sure this is tool2, and tool2.py is updated with correct code
from backend1 import *

# Global variable to store the currently selected set of exam questions
selected_questions = []

description_str = """Developed by Ruslan Magana, this interactive quiz platform is designed to help you prepare and assess your knowledge in a variety of exams.
For more information about the developer, please visit [ruslanmv.com](https://ruslanmv.com/).
**Get Started with Your Quiz**
Select an exam from the dropdown menu below and start testing your skills. You can also choose to enable audio feedback to enhance your learning experience. Simply toggle the "Enable Audio" checkbox to turn it on or off."""

# --- FUNCTION DEFINITIONS ---

def start_exam(exam_choice, start_question, audio_enabled):
    """Starts the exam by selecting questions, setting up UI."""
    global selected_questions
    selected_questions = select_exam_vce(exam_choice)

    if not selected_questions: # Handle case where no questions are loaded for selected exam
        return (
            gr.update(visible=True),  # Show title
            gr.update(value="**Error: No Questions Found for this Exam**", visible=True), # Update description to error message
            gr.update(visible=True), # Show exam_selector
            gr.update(visible=True), # Show start_button
            gr.update(visible=True),  # Show the audio_checkbox
            gr.update(visible=True),  # Show start_question_slider
            # Hide quiz elements
            gr.update(visible=False),  # Hide question_text
            "",  # Question to display
            gr.update(choices=[], visible=False),  # Hide Radio choices
            gr.update(visible=False),  # Hide answer_button
            gr.update(visible=False),  # Hide next_button
            gr.update(visible=False),  # Hide prev_button
            gr.update(visible=False),  # Hide home_button
            0, "",  # Update the question state
            None, # Provide the audio_path
            gr.update(visible=False),  # Hide explain_button
            gr.update(visible=False),
            None # None for audio stop
        )


    if start_question >= len(selected_questions):
        start_question = 0  # Default to the first question if the input exceeds available questions

    question, options, audio_path = display_question(start_question, audio_enabled, selected_questions)

    return (
        # Hide start screen elements
        gr.update(visible=False),  # Hide title
        gr.update(visible=False), # Hide description
        gr.update(visible=False), # Hide exam_selector
        gr.update(visible=False), # Hide start_button
        gr.update(visible=False),  # Hide the audio_checkbox
        gr.update(visible=False),  # Hide start_question_slider
        # Show quiz elements
        gr.update(visible=True),  # Show question_text
        question,  # Question to display
        gr.update(choices=options, visible=True),  # Update Radio choices and make visible
        gr.update(visible=True),  # Show answer_button
        gr.update(visible=True),# Show next_button
        gr.update(visible=True), # Show prev_button
        gr.update(visible=True), # Show home_button
        start_question, "",  # Update the question state
        audio_path, # Provide the audio_path
        gr.update(visible=True),  # Show explain_button
        gr.update(visible=True),
        None  # None for the audio stop signal
    )


def display_question_ui(index, audio_enabled): # Changed function name and parameters
    """Displays a question with options and generates audio (if enabled) and updates UI elements."""
    question, options, audio_path = display_question(index, audio_enabled, selected_questions)
    return question, gr.update(choices=options), audio_path


def show_explanation(index):
    """Shows the explanation for the current question and hides previous results."""
    explanation, correct_answer = get_explanation_and_answer(index, selected_questions) # Get both explanation and answer
    if 0 <= index < len(selected_questions):
        return (
            f"**Explanation:** {explanation}",
            gr.update(visible=True),  # Show explanation_text
            gr.update(visible=True)   # Show result_text - ensure result_text is shown when explanation is shown
        )
    else:
        return "No explanation available for this question.", gr.update(visible=False), gr.update(visible=False)

def check_answer(index, answer):
    """Checks the given answer against the correct answer."""
    explanation, correct_answer = get_explanation_and_answer(index, selected_questions) # Get correct answer
    if answer == correct_answer:
        return f"Correct! The answer is: {correct_answer}"
    else:
        return f"Incorrect. The correct answer is: {correct_answer}"

def update_question(index, audio_enabled):
    """Updates the displayed question when the index changes."""
    return display_question_ui(index, audio_enabled) # Use display_question_ui for UI updates


def handle_answer(index, answer, audio_enabled, current_audio):
    """Handles answer submission, provides feedback, and generates audio."""
    # Handle the case when no answer is selected
    if answer is None:
        return "Please select an option before submitting.", None, None

    # Stop the current question audio before playing the answer audio
    stop_audio = True if current_audio else False
    result = check_answer(index, answer)
    answer_audio_path = text_to_speech(result) if audio_enabled else None
    return result, answer_audio_path, stop_audio


def handle_next(index, audio_enabled):
    """Moves to the next question and updates the UI."""
    new_index = min(index + 1, len(selected_questions) - 1)
    question, options, audio_path = update_question(new_index, audio_enabled)
    return question, options, new_index, "", audio_path, gr.update(visible=False), gr.update(value="") # Hide explanation and clear result text

def handle_previous(index, audio_enabled):
    """Moves to the previous question and updates the UI."""
    new_index = max(index - 1, 0)
    question, options, audio_path = update_question(new_index, audio_enabled)
    return question, options, new_index, "", audio_path, gr.update(visible=False), gr.update(value="") # Hide explanation and clear result text


def return_home():
    """Returns to the home screen."""
    return (
        # Show start screen elements
        gr.update(visible=True), gr.update(value="**AWS Exam Simulator (Quiz)**", visible=True), gr.update(visible=True), gr.update(visible=True), # Reset title and description value
        gr.update(visible=True),  # Show the audio_checkbox
        gr.update(visible=True),  # Show start_question_slider - show slider on home return
        # Hide quiz elements
        gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(visible=False),
        gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), 0, "", gr.update(visible=False), gr.update(visible=False),
        gr.update(visible=False), gr.update(value="") # Hide explain button and clear result text
    )

with gr.Blocks() as demo:
    # Home page elements
    title = gr.Markdown(value="**AWS Exam Simulator (Quiz)**")
    description = gr.Markdown(value=description_str)
    exam_selector = gr.Dropdown(label="Select an exam", choices=exams, value=None)
    audio_checkbox = gr.Checkbox(label="Enable Audio", value=True, visible=False)
    start_question_slider = gr.Slider(minimum=0, maximum=50, step=1, label="Select starting question", visible=False)  # Slider for selecting the starting question
    start_button = gr.Button("Start Exam", visible=False)

    # Quiz elements (initially hidden)
    question_state = gr.State(0)
    current_audio_state = gr.State(None)  # State to track the current audio playing
    question_text = gr.Markdown(visible=False, elem_id="question-text")
    choices = gr.Radio(visible=False, label="Options")
    result_text = gr.Markdown(visible=False) # Initially hidden, shown when answer is submitted or explanation is shown
    explanation_text = gr.Markdown(visible=False)
    answer_button = gr.Button("Submit Answer", visible=False)
    next_button = gr.Button("Next Question", visible=False)
    prev_button = gr.Button("Previous Question", visible=False)
    home_button = gr.Button("Return to Home", visible=False)
    explain_button = gr.Button("Explain", visible=False)
    question_audio = gr.Audio(visible=False, label="Question Audio", autoplay=True)
    answer_audio = gr.Audio(visible=False, label="Answer Audio", autoplay=True)

    # Layout for the home page
    with gr.Row():
        gr.Column([title])
    with gr.Row():
        gr.Column([description])
    with gr.Row():
        gr.Column([exam_selector])
    with gr.Row():
        gr.Column([audio_checkbox, start_question_slider])
    with gr.Row():
        gr.Column([start_button])

    # Layout for the quiz
    with gr.Row():
        gr.Column([question_text, question_audio])
    with gr.Row():
        gr.Column([choices])
    with gr.Row():
        gr.Column([result_text, explanation_text, answer_audio])
    with gr.Row():
        gr.Column([prev_button], scale=1)
        gr.Column([], scale=8)
        gr.Column([next_button], scale=1)
    with gr.Row():
        gr.Column([answer_button, explain_button])
    with gr.Row():
        gr.Column([home_button])

    # Show settings after exam selection
    def show_settings(exam_choice):
        return gr.update(visible=True), gr.update(visible=True), gr.update(visible=True)

    # Connect exam selection to display settings section
    exam_selector.change(fn=show_settings, inputs=[exam_selector], outputs=[audio_checkbox, start_question_slider, start_button])

    # Connect the start button to start the exam
    start_button.click(
        fn=start_exam,
        inputs=[exam_selector, start_question_slider, audio_checkbox],
        outputs=[
            title, description, exam_selector, start_button,
            audio_checkbox,  # Ensure the checkbox visibility is updated
            start_question_slider,  # Ensure the slider is hidden
            question_text, question_text, choices, answer_button,
            next_button, prev_button, home_button, question_state, result_text, question_audio,
            explain_button, explanation_text, current_audio_state  # Add explanation_text to outputs, corrected from result_text, and use explanation_text for explanation
        ]
    )

    # Connect the quiz buttons to their functions
    answer_button.click(fn=handle_answer, inputs=[question_state, choices, audio_checkbox, current_audio_state], outputs=[result_text, answer_audio, current_audio_state])
    next_button.click(fn=handle_next, inputs=[question_state, audio_enabled], outputs=[question_text, choices, question_state, result_text, question_audio, explanation_text, result_text]) # Added result_text to clear on next
    prev_button.click(fn=handle_previous, inputs=[question_state, audio_enabled], outputs=[question_text, choices, question_state, result_text, question_audio, explanation_text, result_text]) # Added result_text to clear on prev

    explain_button.click(fn=show_explanation, inputs=[question_state], outputs=[explanation_text, result_text, explanation_text]) # Corrected output to explanation_text for the last element which was incorrectly result_text

    home_button.click(fn=return_home, inputs=None, outputs=[
        title, description, exam_selector, start_button,
        audio_checkbox,  # Ensure the checkbox visibility is updated
        start_question_slider,  # Ensure the slider is shown
        question_text, question_text, choices, answer_button,
        next_button, prev_button, home_button, question_state, result_text, explanation_text, explain_button, result_text # Added result_text to clear on home, and corrected outputs to include explanation_text
    ])

demo.launch()