Загрузка данных
#---------------------------------------------------ГЕНЕРАТОР ТЕСТА (остаточный принцип)---------------------------------------------------
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()