TestGen / app.py
vladyslav
Fixed bug with removing model from choices list after passing the test
560d420
raw
history blame
23.9 kB
import json
import os
import random
import gradio as gr
from dotenv import load_dotenv
from constants import MODELS, MODELS_PATH, BOOKS, CLASSES, STUDENTS, MODEL_NAME_TO_CHOICE
from utils import save_results, get_test_by_student_class_book
load_dotenv()
if os.getenv("ENV_TYPE") == "dev":
MODELS["Test"] = "test"
MODELS_PATH["Test"] = "test"
BOOKS["Test"] = "test.json"
MODEL_NAME_TO_CHOICE["test"] = "Test"
questions_data = []
current_question_index = 0
answers_log = [] # Log for saving answers
feedback_questions = ""
available_models = []
def get_question():
global questions_data, current_question_index
question = questions_data[current_question_index]
question_text = f"### Питання {current_question_index + 1}/{len(questions_data)}:\n#### {question['question']}"
answers = [answer['answer'] for answer in question['answers']]
random.shuffle(answers)
return question_text, answers
def load_questions(model, book, student_name, class_name):
global questions_data, current_question_index
current_question_index = 0
answers_log.clear()
if not model or not book or student_name is None or class_name is None:
return "# Будь ласка, заповніть усі поля!", []
model_path = MODELS_PATH[model]
book_filename = BOOKS[book]
file_path = os.path.join("questions", model_path, book_filename)
if not os.path.exists(file_path):
return f"Файл за шляхом {file_path} не знайдено.", []
with open(file_path, "r", encoding="utf-8") as file:
questions_data = json.load(file)
if questions_data:
return get_question()
else:
return "У файлі немає питань.", []
def get_next_question(selected_answer):
global current_question_index, answers_log, feedback_questions
if not selected_answer:
question_text, answers = get_question()
return (
question_text, # question_radio
gr.update(choices=answers, value=None, interactive=True, visible=True), # answer_radio
gr.update(visible=True), # next_button
gr.update(visible=False), # feedback_input
gr.update(visible=False), # submit_feedback_button
gr.update(visible=False), # rating_text
gr.update(visible=False), # question_correct
gr.update(visible=False), # answers_correct
gr.update(visible=False), # interesting_question
gr.update(visible=False, value=""), # feedback_questions_output
)
# Writing answer in log
answers_log.append({
"selected": selected_answer,
"isCorrect": any(answer['answer'] == selected_answer and answer['isCorrect'] for answer in
questions_data[current_question_index]['answers'])
})
# Move to the next question
current_question_index += 1
if current_question_index < len(questions_data):
question_text, answers = get_question()
return (
question_text, # question_radio
gr.update(choices=answers, value=None, interactive=True, visible=True), # answer_radio
gr.update(visible=True), # next_button
gr.update(visible=False), # feedback_input
gr.update(visible=False), # submit_feedback_button
gr.update(visible=False), # rating_text
gr.update(visible=False), # question_correct
gr.update(visible=False), # answers_correct
gr.update(visible=False), # interesting_question
gr.update(visible=False, value=""), # feedback_questions_output
)
else:
# All questions are completed — ask for feedback
question_text = "#### Дякуємо за участь у тесті!\n#### Нижче можете переглянути ваші та правильні відповіді\n#### Залиште, будь ласка, відгук про тест в кінці сторінки.\n---"
feedback_questions = prepare_questions_for_feedback(questions_data, answers_log)
return (
question_text, # question_radio
gr.update(visible=False, value=None), # answer_radio
gr.update(visible=False), # next_button
gr.update(visible=True), # feedback_input
gr.update(visible=True), # submit_feedback_button
gr.update(visible=True), # rating_text
gr.update(visible=True), # question_correct
gr.update(visible=True), # answers_correct
gr.update(visible=True), # interesting_question
gr.update(visible=True, value=feedback_questions), # feedback_questions_output
)
def summarize_results(student_name,
class_name,
model,
book,
feedback,
question_correct,
answers_correct,
interesting_question):
global questions_data, answers_log, feedback_questions, available_models
questions = []
if question_correct is None or answers_correct is None or interesting_question is None:
return (
"### Залиште відгук про тест!", # question_output
gr.update(visible=True), # feedback_input
gr.update(visible=True), # submit_feedback_button
gr.update(visible=True), # question_correct
gr.update(visible=True), # answers_correct
gr.update(visible=True), # interesting_question
gr.update(visible=True), # rating_text
gr.update(visible=True, value=feedback_questions), # feedback_questions_output
gr.update(visible=True), # feedback_not_provided
)
for question, answer in zip(questions_data, answers_log):
questions.append({
"question": question,
"answer": answer
})
correct_answers_count = sum(1 for answer in answers_log if answer['isCorrect'])
total_questions = len(questions_data)
grade_12 = (correct_answers_count / total_questions) * 12
save_results(
student_name,
class_name,
MODELS[model],
book,
questions,
feedback,
question_correct,
answers_correct,
interesting_question,
grade_12,
correct_answers_count,
)
summary = (
f"#### Тест для моделі {model} закінчено!\n\n"
f"#### Ви відповіли правильно на {correct_answers_count} з {total_questions} питань.\n\n"
f"#### Оцінка за 12-бальною шкалою: {grade_12:.2f}.\n\n"
)
if student_name != "Вчитель":
available_models.remove(model)
return (
summary, # question_output
gr.update(visible=False, value=""), # feedback_input
gr.update(visible=False), # submit_feedback_button
gr.update(visible=False, value=None), # question_correct
gr.update(visible=False, value=None), # answers_correct
gr.update(visible=False, value=None), # interesting_question
gr.update(visible=False), # rating_text
gr.update(visible=False, value=""), # feedback_questions_output
gr.update(visible=False), # feedback_not_provided
gr.update(choices=available_models, value=None, visible=True), # model_radio
)
def prepare_questions_for_feedback(questions, answer_log):
feedback = []
for i, question in enumerate(questions):
question_text = f"#### Питання: {question['question']}"
quote = f"#### Цитата: *{question['textPart']}*"
user_answer = answer_log[i]['selected']
answers_text = "\n".join(
[
f"- {'**(Правильна)**' if ans['isCorrect'] else ''} {'**(Обрана)**' if ans['answer'] == user_answer else ''} {ans['answer']}"
for ans in question['answers']
]
)
feedback.append(f"{question_text}\n{quote}\n#### Відповіді:\n{answers_text}\n---")
return "\n".join(feedback)
def update_students(class_name):
print('update_students')
students = STUDENTS.get(class_name, [])
return (
gr.update(choices=students, value=None, visible=True), # student_name_input
gr.update(choices=[], value=None, visible=False), # book_radio
gr.update(choices=[], value=None, visible=False), # model_radio
gr.update(value=""), # questions_output
gr.update(choices=[], value=None, visible=False), # answer_radio
gr.update(visible=False), # next_button
gr.update(value="", visible=False), # feedback_questions_output
gr.update(visible=False), # rating_text
gr.update(visible=False), # feedback_not_provided
gr.update(value=None, visible=False), # question_correct_radio
gr.update(value=None, visible=False), # answers_correct_radio
gr.update(value=None, visible=False), # interesting_question_radio
gr.update(value="", visible=False), # feedback_input
gr.update(visible=False), # submit_feedback_button
)
def handle_student_name_change(student_name):
print('handle_student_name_change')
if not student_name:
return (
gr.update(choices=[], value=None, visible=False), # book_radio
gr.update(choices=[], value=None, visible=False), # model_radio
gr.update(value=""), # questions_output
gr.update(choices=[], value=None, visible=False), # answer_radio
gr.update(visible=False), # next_button
gr.update(value="", visible=False), # feedback_questions_output
gr.update(visible=False), # rating_text
gr.update(visible=False), # feedback_not_provided
gr.update(value=None, visible=False), # question_correct_radio
gr.update(value=None, visible=False), # answers_correct_radio
gr.update(value=None, visible=False), # interesting_question_radio
gr.update(value="", visible=False), # feedback_input
gr.update(visible=False), # submit_feedback_button
)
return (
gr.update(choices=list(BOOKS.keys()), value=None, visible=True), # book_radio
gr.update(choices=[], value=None, visible=False), # model_radio
gr.update(value=""), # questions_output
gr.update(choices=[], value=None, visible=False), # answer_radio
gr.update(visible=False), # next_button
gr.update(value="", visible=False), # feedback_questions_output
gr.update(visible=False), # rating_text
gr.update(visible=False), # feedback_not_provided
gr.update(value=None, visible=False), # question_correct_radio
gr.update(value=None, visible=False), # answers_correct_radio
gr.update(value=None, visible=False), # interesting_question_radio
gr.update(value="", visible=False), # feedback_input
gr.update(visible=False), # submit_feedback_button
)
def filter_models(student_name, class_name, book):
global available_models
print('filter_models')
if not book:
return (
gr.update(choices=[], value=None, visible=False),
gr.update(value=""), # questions_output
gr.update(choices=[], value=None, visible=False), # answer_radio
gr.update(visible=False), # next_button
gr.update(value="", visible=False), # feedback_questions_output
gr.update(visible=False), # rating_text
gr.update(visible=False), # feedback_not_provided
gr.update(value=None, visible=False), # question_correct_radio
gr.update(value=None, visible=False), # answers_correct_radio
gr.update(value=None, visible=False), # interesting_question_radio
gr.update(value="", visible=False), # feedback_input
gr.update(visible=False), # submit_feedback_button
)
if student_name == "Вчитель":
return (
gr.update(choices=MODELS.keys(), value=None, visible=True),
gr.update(value=""), # questions_output
gr.update(choices=[], value=None, visible=False), # answer_radio
gr.update(visible=False), # next_button
gr.update(value="", visible=False), # feedback_questions_output
gr.update(visible=False), # rating_text
gr.update(visible=False), # feedback_not_provided
gr.update(value=None, visible=False), # question_correct_radio
gr.update(value=None, visible=False), # answers_correct_radio
gr.update(value=None, visible=False), # interesting_question_radio
gr.update(value="", visible=False), # feedback_input
gr.update(visible=False), # submit_feedback_button
)
tests = get_test_by_student_class_book(student_name, class_name, book)
available_models_names = list(MODELS.values())
for test in tests:
if test.get("model") in available_models_names:
available_models_names.remove(test.get("model"))
print("Available models (before update):", available_models_names)
if not available_models_names:
return gr.update(choices=[], label="Немає доступних моделей", value=None, visible=True)
models_list = []
for model in list(available_models_names):
models_list.append(MODEL_NAME_TO_CHOICE.get(model))
available_models = models_list
return (
gr.update(choices=models_list, value=None, visible=True),
gr.update(value=""), # questions_output
gr.update(choices=[], value=None, visible=False), # answer_radio
gr.update(visible=False), # next_button
gr.update(value="", visible=False), # feedback_questions_output
gr.update(visible=False), # rating_text
gr.update(visible=False), # feedback_not_provided
gr.update(value=None, visible=False), # question_correct_radio
gr.update(value=None, visible=False), # answers_correct_radio
gr.update(value=None, visible=False), # interesting_question_radio
gr.update(value="", visible=False), # feedback_input
gr.update(visible=False), # submit_feedback_button
)
def handle_model_change(model):
print(model)
print("handle_model_change")
if model is not None:
return (
gr.update(value=""), # questions_output
gr.update(choices=[], value=None, visible=False), # answer_radio
gr.update(visible=False), # next_button
gr.update(value="", visible=False), # feedback_questions_output
gr.update(visible=False), # rating_text
gr.update(visible=False), # feedback_not_provided
gr.update(value=None, visible=False), # question_correct_radio
gr.update(value=None, visible=False), # answers_correct_radio
gr.update(value=None, visible=False), # interesting_question_radio
gr.update(value="", visible=False), # feedback_input
gr.update(visible=False), # submit_feedback_button
)
return (
gr.update(visible=True), # questions_output
gr.update(choices=[], value=None, visible=False), # answer_radio
gr.update(visible=False), # next_button
gr.update(value="", visible=False), # feedback_questions_output
gr.update(visible=False), # rating_text
gr.update(visible=False), # feedback_not_provided
gr.update(value=None, visible=False), # question_correct_radio
gr.update(value=None, visible=False), # answers_correct_radio
gr.update(value=None, visible=False), # interesting_question_radio
gr.update(value="", visible=False), # feedback_input
gr.update(visible=False), # submit_feedback_button
)
with gr.Blocks() as demo:
with gr.Column():
gr.Markdown("## Оберіть модель та книгу, щоб завантажити питання")
class_name_input = gr.Dropdown(choices=CLASSES, label="Ваш клас", value=None)
student_name_input = gr.Dropdown(label="Ваше ім'я", value=None, visible=False)
book_radio = gr.Radio([], label="Оберіть книгу", interactive=True, value=None, visible=False)
model_radio = gr.Radio([], label="Оберіть модель", interactive=True, value=None, visible=False)
load_button = gr.Button("Завантажити питання")
question_output = gr.Markdown(label="Питання")
answer_radio = gr.Radio([], label="Варіанти відповіді", interactive=True, visible=False)
next_button = gr.Button("Наступне питання", visible=False)
feedback_questions_output = gr.Markdown(label="Пройдені питання", value="Nothing", visible=False)
rating_text = gr.Markdown(
"### Шкала оцінювання:\n\n#### -2 — дуже погано\n\n#### -1 — погано\n\n#### 0 — задовільно\n\n#### 1 — добре\n\n#### 2 — відмінно",
visible=False)
feedback_not_provided = gr.Markdown("# Заповніть поля відгуку та залишіть оцінку!", visible=False)
question_correct_radio = gr.Radio([-2, -1, 0, 1, 2], label="Чи коректно поставлені запитання?", visible=False,
interactive=True)
answers_correct_radio = gr.Radio([-2, -1, 0, 1, 2], label="Чи коректно поставлені варіанти відповідей?",
visible=False, interactive=True)
interesting_question_radio = gr.Radio([-2, -1, 0, 1, 2], label="Чи цікаві були запитання?", visible=False,
interactive=True)
feedback_input = gr.Textbox(label="Будь-який коментар про тест (за бажанням)", visible=False)
submit_feedback_button = gr.Button("Завершити тест", visible=False)
class_name_input.change(
update_students,
inputs=[
class_name_input,
],
outputs=[
student_name_input,
book_radio,
model_radio,
question_output,
answer_radio,
next_button,
feedback_questions_output,
rating_text,
feedback_not_provided,
question_correct_radio,
answers_correct_radio,
interesting_question_radio,
feedback_input,
submit_feedback_button,
]
)
student_name_input.change(
handle_student_name_change,
inputs=[
student_name_input,
],
outputs=[
book_radio,
model_radio,
question_output,
answer_radio,
next_button,
feedback_questions_output,
rating_text,
feedback_not_provided,
question_correct_radio,
answers_correct_radio,
interesting_question_radio,
feedback_input,
submit_feedback_button,
]
)
book_radio.change(
filter_models,
inputs=[
student_name_input,
class_name_input,
book_radio,
],
outputs=[
model_radio,
question_output,
answer_radio,
next_button,
feedback_questions_output,
rating_text,
feedback_not_provided,
question_correct_radio,
answers_correct_radio,
interesting_question_radio,
feedback_input,
submit_feedback_button,
]
)
model_radio.change(
handle_model_change,
inputs=[
model_radio
],
outputs=[
question_output,
answer_radio,
next_button,
feedback_questions_output,
rating_text,
feedback_not_provided,
question_correct_radio,
answers_correct_radio,
interesting_question_radio,
feedback_input,
submit_feedback_button,
]
)
def update_question(model, book, student_name, class_name):
question, answers = load_questions(model, book, student_name, class_name)
is_field_filled = len(answers) > 0
return (
question, # question_output
gr.update(choices=answers, interactive=True, visible=is_field_filled), # answer_radio
gr.update(visible=is_field_filled), # next_button
gr.update(visible=False, value=""), # feedback_input
gr.update(visible=False), # submit_feedback_button
gr.update(visible=False), # rating_text
gr.update(visible=False, value=None), # question_correct
gr.update(visible=False, value=None), # answers_correct
gr.update(visible=False, value=None), # interesting_question
gr.update(visible=False, value=""), # feedback_questions_output
gr.update(visible=False), # feedback_not_provided
)
load_button.click(
update_question,
inputs=[
model_radio,
book_radio,
student_name_input,
class_name_input,
],
outputs=[
question_output,
answer_radio,
next_button,
feedback_input,
submit_feedback_button,
rating_text,
question_correct_radio,
answers_correct_radio,
interesting_question_radio,
feedback_questions_output,
feedback_not_provided,
]
)
next_button.click(
get_next_question,
inputs=[answer_radio],
outputs=[
question_output,
answer_radio,
next_button,
feedback_input,
submit_feedback_button,
rating_text,
question_correct_radio,
answers_correct_radio,
interesting_question_radio,
feedback_questions_output,
]
)
submit_feedback_button.click(
summarize_results,
inputs=[
student_name_input,
class_name_input,
model_radio,
book_radio,
feedback_input,
question_correct_radio,
answers_correct_radio,
interesting_question_radio,
],
outputs=[
question_output,
feedback_input,
submit_feedback_button,
question_correct_radio,
answers_correct_radio,
interesting_question_radio,
rating_text,
feedback_questions_output,
feedback_not_provided,
model_radio,
]
)
if __name__ == "__main__":
demo.launch()