|
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 = [] |
|
feedback_questions = "" |
|
|
|
|
|
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, |
|
gr.update(choices=answers, value=None, interactive=True, visible=True), |
|
gr.update(visible=True), |
|
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, value=""), |
|
) |
|
|
|
|
|
answers_log.append({ |
|
"selected": selected_answer, |
|
"isCorrect": any(answer['answer'] == selected_answer and answer['isCorrect'] for answer in |
|
questions_data[current_question_index]['answers']) |
|
}) |
|
|
|
|
|
current_question_index += 1 |
|
if current_question_index < len(questions_data): |
|
question_text, answers = get_question() |
|
return ( |
|
question_text, |
|
gr.update(choices=answers, value=None, interactive=True, visible=True), |
|
gr.update(visible=True), |
|
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, value=""), |
|
) |
|
else: |
|
|
|
question_text = "#### Дякуємо за участь у тесті!\n#### Нижче можете переглянути ваші та правильні відповіді\n#### Залиште, будь ласка, відгук про тест в кінці сторінки.\n---" |
|
feedback_questions = prepare_questions_for_feedback(questions_data, answers_log) |
|
return ( |
|
question_text, |
|
gr.update(visible=False, value=None), |
|
gr.update(visible=False), |
|
gr.update(visible=True), |
|
gr.update(visible=True), |
|
gr.update(visible=True), |
|
gr.update(visible=True), |
|
gr.update(visible=True), |
|
gr.update(visible=True), |
|
gr.update(visible=True, value=feedback_questions), |
|
) |
|
|
|
|
|
def summarize_results(student_name, |
|
class_name, |
|
model, |
|
book, |
|
feedback, |
|
question_correct, |
|
answers_correct, |
|
interesting_question): |
|
global questions_data, answers_log, feedback_questions |
|
questions = [] |
|
|
|
if question_correct is None or answers_correct is None or interesting_question is None: |
|
return ( |
|
"### Залиште відгук про тест!", |
|
gr.update(visible=True), |
|
gr.update(visible=True), |
|
gr.update(visible=True), |
|
gr.update(visible=True), |
|
gr.update(visible=True), |
|
gr.update(visible=True), |
|
gr.update(visible=True, value=feedback_questions), |
|
gr.update(visible=True), |
|
) |
|
|
|
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" |
|
) |
|
|
|
return ( |
|
summary, |
|
gr.update(visible=False, value=""), |
|
gr.update(visible=False), |
|
gr.update(visible=False, value=None), |
|
gr.update(visible=False, value=None), |
|
gr.update(visible=False, value=None), |
|
gr.update(visible=False), |
|
gr.update(visible=False, value=""), |
|
gr.update(visible=False), |
|
) |
|
|
|
|
|
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), |
|
gr.update(choices=[], value=None, visible=False), |
|
gr.update(choices=[], value=None, visible=False), |
|
) |
|
|
|
|
|
def handle_student_name_change(student_name): |
|
print('handle_student_name_change') |
|
if not student_name: |
|
return ( |
|
gr.update(choices=[], value=None, visible=False), |
|
gr.update(choices=[], value=None, visible=False), |
|
) |
|
|
|
return ( |
|
gr.update(choices=list(BOOKS.keys()), value=None, visible=True), |
|
gr.update(choices=[], value=None, visible=False), |
|
) |
|
|
|
|
|
def filter_models(student_name, class_name, book): |
|
print('filter_models') |
|
if not book: |
|
return gr.update(choices=[], value=None, visible=False) |
|
|
|
tests = get_test_by_student_class_book(student_name, class_name, book) |
|
available_models = list(MODELS.values()) |
|
|
|
for test in tests: |
|
if test.get("model") in available_models: |
|
available_models.remove(test.get("model")) |
|
|
|
print("Available models (before update):", available_models) |
|
|
|
if not available_models: |
|
return gr.update(choices=[], label="Немає доступних моделей", value=None, visible=True) |
|
|
|
models_list = [] |
|
|
|
for model in list(available_models): |
|
models_list.append(MODEL_NAME_TO_CHOICE.get(model)) |
|
|
|
return gr.update(choices=models_list, value=None, visible=True) |
|
|
|
|
|
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, |
|
] |
|
) |
|
|
|
student_name_input.change( |
|
handle_student_name_change, |
|
inputs=[ |
|
student_name_input, |
|
], |
|
outputs=[ |
|
book_radio, |
|
model_radio, |
|
] |
|
) |
|
|
|
book_radio.change( |
|
filter_models, |
|
inputs=[ |
|
student_name_input, |
|
class_name_input, |
|
book_radio, |
|
], |
|
outputs=[ |
|
model_radio, |
|
] |
|
) |
|
|
|
|
|
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, |
|
gr.update(choices=answers, interactive=True, visible=is_field_filled), |
|
gr.update(visible=is_field_filled), |
|
gr.update(visible=False, value=""), |
|
gr.update(visible=False), |
|
gr.update(visible=False), |
|
gr.update(visible=False, value=None), |
|
gr.update(visible=False, value=None), |
|
gr.update(visible=False, value=None), |
|
gr.update(visible=False, value=""), |
|
gr.update(visible=False), |
|
) |
|
|
|
|
|
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, |
|
] |
|
) |
|
|
|
if __name__ == "__main__": |
|
demo.launch() |
|
|