Вот мой код:
```py
import asyncio
import json
import threading
from tkinter import (
    Tk,
    Text,
    Button,
    Scale,
    HORIZONTAL,
    filedialog,
    Label,
    Scrollbar,
    RIGHT,
    Y,
    LEFT,
    BOTH,
    END,
    Frame,
    BooleanVar,
    Checkbutton,
)
import edge_tts
import os
import tempfile
from playsound import playsound


class TTSPlayer:
    def __init__(self, json_data, speed, split_all_words=False, per_word=False, on_update=None):
        self.json_data = json_data
        self.speed = speed  # Значение скорости от ползунка
        self.split_all_words = split_all_words  # Флаг для раздельного зачитывания всех слов
        self.per_word = per_word  # Флаг для зачитывания по словам (для отдельных элементов)
        self.on_update = on_update  # Callback для обновления интерфейса
        self._stop_event = threading.Event()
        self._current_chunk = 0
        self.flat_text = []
        self.generate_flat_text(self.json_data)
        self.total_chunks = len(self.flat_text)

    def generate_flat_text(self, data, depth=0):
        """Рекурсивно разворачивает JSON-документ в плоский список элементов с типами."""
        sections = data.get("sections", [])
        for section in sections:
            if self._stop_event.is_set():
                break

            heading = section.get("heading")
            if heading:
                self.flat_text.append({"type": "Heading", "text": heading})

            definitions = section.get("definitions", [])
            for definition in definitions:
                self.flat_text.append({"type": "Definition", "text": definition})

            enumeration = section.get("enumeration", [])
            if enumeration:
                self.flat_text.append({"type": "Enumeration_Start", "text": ""})
                for item in enumeration:
                    self.flat_text.append({"type": "Enumeration_Item", "text": item})
                self.flat_text.append({"type": "Enumeration_End", "text": ""})

    async def speak_text(self, text, voice, rate, fixed_speed=False):
        """Генерирует аудио и воспроизводит его."""
        # Определяем скорость
        if fixed_speed:
            current_rate = "+0%"  # Нормальная скорость
        else:
            current_rate = rate

        communicate = edge_tts.Communicate(text, voice, rate=current_rate)
        all_audio = b""
        async for chunk in communicate.stream():
            if chunk["type"] == "audio":
                all_audio += chunk["data"]

        if all_audio:
            with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as tmp:
                tmp.write(all_audio)
                tmp_path = tmp.name
            try:
                playsound(tmp_path)
            except Exception as e:
                if self.on_update:
                    self.on_update(f"Ошибка воспроизведения аудио: {e}")
            finally:
                os.remove(tmp_path)

    def play(self):
        """Запускает воспроизведение в отдельном потоке."""
        threading.Thread(target=self._play_thread, daemon=True).start()

    def _play_thread(self):
        asyncio.run(self._amain())

    async def _amain(self):
        for idx, element in enumerate(self.flat_text[self._current_chunk:], start=self._current_chunk):
            if self._stop_event.is_set():
                break

            # Определяем, является ли текущий элемент фиксированной фразой
            if element["type"] in ["Enumeration_Start", "Enumeration_End"]:
                # Фиксированные фразы с нормальной скоростью
                if element["type"] == "Enumeration_Start":
                    await self.speak_text("Начинается перечисление.", "ru-RU-DmitryNeural", "+0%", fixed_speed=True)
                elif element["type"] == "Enumeration_End":
                    await self.speak_text("Перечисление завершено.", "ru-RU-DmitryNeural", "+0%", fixed_speed=True)
            elif element["type"] in ["Heading", "Definition"]:
                # Обработка заголовков и определений
                text_to_speak = element['text']
                #text_to_speak = f"Заголовок: {element['text']}" if element["type"] == "Heading" else f"Определение: {element['text']}"
                
                # Произносим тип с нормальной скоростью
                if element["type"] == "Heading":
                    await self.speak_text("Заголовок", "ru-RU-DmitryNeural", "+0%")
                else:
                    await self.speak_text("Определение", "ru-RU-DmitryNeural", "+0%")

                if self.split_all_words:
                    words = self.split_text(text_to_speak)
                    for word in words:
                        if self._stop_event.is_set():
                            break
                        await self.speak_text(word, "ru-RU-DmitryNeural", self.speed_adjust())
                        # Пауза между словами (можно настроить)
                        await asyncio.sleep(0.3)  # Пауза 300 мс
                else:
                    await self.speak_text(text_to_speak, "ru-RU-DmitryNeural", self.speed_adjust())
            elif element["type"] == "Enumeration_Item":
                # Обработка элементов перечисления
                text_to_speak = element["text"]
                if self.per_word or self.split_all_words:
                    words = self.split_text(text_to_speak)
                    for word in words:
                        if self._stop_event.is_set():
                            break
                        await self.speak_text(word, "ru-RU-DmitryNeural", self.speed_adjust())
                        # Пауза между словами (можно настроить)
                        await asyncio.sleep(0.3)  # Пауза 300 мс
                else:
                    await self.speak_text(text_to_speak, "ru-RU-DmitryNeural", self.speed_adjust())

            self._current_chunk = idx + 1
            if self.on_update:
                self.on_update(self._current_chunk, self.total_chunks)

    def speed_adjust(self):
        """Конвертирует значение скорости ползунка в формат, понятный edge-tts."""
        speed_percentage = self.speed - 100  # Ползунок от 50 до 150
        rate = f"{speed_percentage}%"
        if speed_percentage > 0:
            rate = f"+{rate}"
        else:
            rate = f"{rate}"  # Уже содержит знак минус или 0
        return rate

    def stop(self):
        """Останавливает воспроизведение."""
        self._stop_event.set()

    def reset(self):
        """Сбрасывает состояние воспроизведения."""
        self.stop()
        self._current_chunk = 0

    @staticmethod
    def split_text(text):
        """Разделяет текст на слова, учитывая знаки препинания."""
        import re
        # Разделяем по пробелам и сохраняем знаки препинания как отдельные элементы
        tokens = re.findall(r'\w+|[^\w\s]', text, re.UNICODE)
        return tokens


class Application(Tk):
    def __init__(self):
        super().__init__()
        self.title("Конспект диктор")
        self.geometry("800x800")  # Увеличил высоту для нового элемента интерфейса

        # Метка для JSON
        self.json_label = Label(self, text="Вставьте JSON-конспект ниже:")
        self.json_label.pack()

        # Текстовое поле с прокруткой
        self.text_frame = Frame(self)
        self.text_frame.pack(fill=BOTH, expand=True)

        self.scrollbar = Scrollbar(self.text_frame)
        self.scrollbar.pack(side=RIGHT, fill=Y)

        self.text = Text(
            self.text_frame,
            wrap="word",
            yscrollcommand=self.scrollbar.set,
            font=("Arial", 12),
        )
        self.text.pack(side=LEFT, fill=BOTH, expand=True)
        self.scrollbar.config(command=self.text.yview)

        # Ползунок скорости
        self.speed_label = Label(self, text="Скорость:")
        self.speed_label.pack()

        self.speed_slider = Scale(
            self,
            from_=50,  # Стандартная скорость 50%
            to=150,
            orient=HORIZONTAL,
            length=400,
            label="Скорость (%)",
            tickinterval=25,
        )
        self.speed_slider.set(50)  # Установил стандартную скорость
        self.speed_slider.pack()

        # Чекбокс для зачитывания по словам для перечислений
        self.per_word_var = BooleanVar()
        self.per_word_checkbox = Checkbutton(
            self,
            text="Зачитывать элементы перечисления по словам с паузами",
            variable=self.per_word_var
        )
        self.per_word_checkbox.pack(pady=5)

        # Чекбокс для раздельного зачитывания всех слов
        self.split_all_words_var = BooleanVar()
        self.split_all_words_checkbox = Checkbutton(
            self,
            text="Зачитывать весь текст по словам с паузами",
            variable=self.split_all_words_var
        )
        self.split_all_words_checkbox.pack(pady=5)

        # Кнопки управления
        self.button_frame = Frame(self)
        self.button_frame.pack()

        self.play_button = Button(self.button_frame, text="Воспроизвести", command=self.play)
        self.play_button.pack(side=LEFT, padx=5, pady=5)

        self.stop_button = Button(self.button_frame, text="Стоп", command=self.stop)
        self.stop_button.pack(side=LEFT, padx=5, pady=5)

        self.load_button = Button(self.button_frame, text="Загрузить JSON из файла", command=self.load_json)
        self.load_button.pack(side=LEFT, padx=5, pady=5)

        # Индикатор прогресса
        self.progress_label = Label(self, text="Прогресс: 0/0")
        self.progress_label.pack(pady=10)

        self.player = None

    def load_json(self):
        """Загружает JSON из файла и вставляет в текстовое поле."""
        file_path = filedialog.askopenfilename(
            filetypes=[("JSON Files", "*.json"), ("All Files", "*.*")]
        )
        if file_path:
            try:
                with open(file_path, "r", encoding="utf-8") as f:
                    content = f.read()
                    # Проверка валидности JSON
                    json_content = json.loads(content)
                    self.text.delete(1.0, END)
                    # Отформатировать JSON с отступами для удобства чтения
                    formatted_json = json.dumps(json_content, ensure_ascii=False, indent=4)
                    self.text.insert(END, formatted_json)
            except json.JSONDecodeError as e:
                self.update_progress(f"Ошибка JSON: {e}")

    def play(self):
        """Запускает воспроизведение."""
        if self.player and not self.player._stop_event.is_set():
            # Уже идет воспроизведение
            return
        try:
            json_content = json.loads(self.text.get(1.0, END))
        except json.JSONDecodeError as e:
            self.update_progress("Ошибка JSON: " + str(e))
            return

        speed = self.speed_slider.get()
        split_all_words = self.split_all_words_var.get()
        per_word = self.per_word_var.get()

        self.player = TTSPlayer(json_content, speed, split_all_words, per_word, self.update_progress)
        self.player.play()

    def stop(self):
        """Останавливает воспроизведение."""
        if self.player:
            self.player.stop()
            self.update_progress("Остановлено.")
            self.player = None

    def update_progress(self, current, total=None):
        """Обновляет индикатор прогресса."""
        if isinstance(current, int) and total is not None:
            self.progress_label.config(text=f"Прогресс: {current}/{total}")
        else:
            self.progress_label.config(text=current)


if __name__ == "__main__":
    app = Application()
    app.mainloop()
```
Сделай полный рефакторинг и сделай, чтобы он был чистым, по стандартам CeanCode. Вынеси отдельные части, если нужно, в отдельные методы и классы. Весь код должен остаться в одном файле