Загрузка данных


#---------------------------------------------------ГЕНЕРАТОР ТЕСТА (остаточный принцип)---------------------------------------------------
import tkinter as tk
from tkinter import filedialog, messagebox
import random
import re
from docx import Document

INVISIBLE_MARKER = "\u200b"


class QuizGenerator:
    def __init__(self, root):
        self.root = root
        self.root.title("Quiz Genius Pro (уникальные тесты)")
        self.root.geometry("500x350")

        self.questions_pool = []
        self.current_test = []

        # UI элементы
        tk.Label(root, text="Генератор уникальных тестов", font=("Arial", 14, "bold")).pack(pady=10)

        self.btn_load = tk.Button(root, text="1. Загрузить базу из .docx", command=self.load_file,
                                  width=40, bg="#f0f0f0")
        self.btn_load.pack(pady=5)

        self.btn_generate = tk.Button(root, text="2. Сгенерировать вариант (30 вопр.)",
                                      command=self.generate_test, width=40, state=tk.DISABLED, bg="#e1f5fe")
        self.btn_generate.pack(pady=5)

        self.btn_save = tk.Button(root, text="3. Сохранить вариант в файл",
                                  command=self.save_test, width=40, state=tk.DISABLED, bg="#e8f5e9")
        self.btn_save.pack(pady=5)

        self.btn_reset = tk.Button(root, text="Сбросить и перезагрузить базу",
                                   command=self.load_file, width=40, fg="red")

        self.status_label = tk.Label(root, text="Ожидание загрузки файла...", fg="gray", wraplength=400)
        self.status_label.pack(pady=20)

    def clean_text(self, text):
        if not text: return ""
        text = re.sub(r'\s+', ' ', text).strip()
        return text

    def load_file(self):
        file_path = filedialog.askopenfilename(filetypes=[("Word documents", "*.docx")])
        if not file_path:
            return

        try:
            doc = Document(file_path)
            raw_questions = []
            seen_texts = set()

            for table in doc.tables:
                content = []
                for row in table.rows:
                    for cell in row.cells:
                        txt = self.clean_text(cell.text)
                        if txt and txt not in content:
                            content.append(txt)

                if content:
                    question_text = content[0]
                    options = content[1:]

                    if question_text not in seen_texts:
                        raw_questions.append({
                            'q': question_text,
                            'a': options
                        })
                        seen_texts.add(question_text)

            if not raw_questions:
                messagebox.showwarning("Пусто", "В файле не найдено таблиц с вопросами.")
                return

            self.questions_pool = raw_questions
            random.shuffle(self.questions_pool)

            self.status_label.config(
                text=f"База загружена!\nУникальных вопросов: {len(self.questions_pool)}\n(Дубликаты отсеяны)",
                fg="green"
            )
            self.btn_generate.config(state=tk.NORMAL)
            self.btn_save.config(state=tk.DISABLED)

        except Exception as e:
            messagebox.showerror("Ошибка", f"Не удалось прочитать файл: {e}")

    def generate_test(self):
        if not self.questions_pool:
            messagebox.showwarning("База пуста", "Вопросы в базе закончились. Загрузите файл снова.")
            return

        count = min(len(self.questions_pool), 30)

        selected_batch = self.questions_pool[:count]

        self.questions_pool = self.questions_pool[count:]

        self.current_test = []
        for item in selected_batch:
            q_text = item['q']
            options = list(item['a'])

            if options:
                options[0] = INVISIBLE_MARKER + options[0]

            random.shuffle(options)

            # Форматируем блок текста
            block = q_text + "\n"
            for idx, opt in enumerate(options):
                letter = chr(97 + idx)
                block += f"   {letter}) {opt}\n"

            self.current_test.append(block)

        self.btn_save.config(state=tk.NORMAL)
        self.status_label.config(
            text=f"Тест сформирован (30 вопр.)\nОсталось свежих вопросов в базе: {len(self.questions_pool)}",
            fg="blue"
        )
        messagebox.showinfo("Готово",
                            f"Сгенерировано. В текущей сессии осталось {len(self.questions_pool)} неиспользованных вопросов.")

    def save_test(self):
        if not self.current_test: return

        save_path = filedialog.asksaveasfilename(defaultextension=".docx", filetypes=[("Word documents", "*.docx")])
        if save_path:
            try:
                new_doc = Document()
                new_doc.add_heading('Вариант теста', 0)

                for i, q_block in enumerate(self.current_test, 1):
                    p = new_doc.add_paragraph()
                    run = p.add_run(f"Вопрос №{i}:")
                    run.bold = True
                    p.add_run(f"\n{q_block}")
                    new_doc.add_paragraph("-" * 40)

                new_doc.save(save_path)
                self.btn_save.config(state=tk.DISABLED)
                messagebox.showinfo("Успех", "Файл успешно сохранен.")
            except Exception as e:
                messagebox.showerror("Ошибка", f"Ошибка сохранения: {e}")


if __name__ == "__main__":
    root = tk.Tk()
    app = QuizGenerator(root)
    root.mainloop()