2025, Oct 23 05:15

Пустой MP3 в Tkinter с pyttsx3 на macOS: причины и рабочая альтернатива gTTS

Почему pyttsx3 с Tkinter на macOS создает пустой MP3 и как это исправить: замените asksaveasfile на asksaveasfilename или используйте gTTS для верной записи.

Когда в приложении Tkinter на скорую руку настраиваешь цепочку «текст в речь», кажется, что этап сохранения — пустяк. Но распространённый симптом — MP3-файл нулевого размера или просто пустой файл: он создаётся, но без звука. Именно это происходит в фрагменте ниже, построенном на простейшей конфигурации pyttsx3 в macOS.

Постановка проблемы

Идея понятна: спросить у пользователя место сохранения и дать pyttsx3 синтезировать речь прямо в этот файл. На деле же получается пустой MP3, хотя файл физически есть.

out_target = filedialog.asksaveasfile(filetypes=(("MP3 files", "*.mp3"),
                                                ("All files", "*.*")))  # запросить у пользователя путь
speech_engine = pyttsx3.init()  # создать движок
speech_engine.setProperty('rate', 100)  # задать скорость речи
speech_engine.save_to_file('Hi and welcome to my audiobook.', out_target)  # попытаться сохранить аудио
speech_engine.runAndWait()

Такое поведение сохраняется, даже если фрагмент кода повторяет примеры из документации. Среда — macOS, установка espeak-ng в настройку не входит.

Что происходит

Наблюдаемый результат — пустой MP3-файл. Проблема воспроизводится в этой конфигурации. Из контекста следуют две практические заметки. Во-первых, в вызове диалога выше используется asksaveasfile; рекомендуется заменить его на asksaveasfilename. Во-вторых, переход на gTTS оказывается рабочей альтернативой и упрощает путь от текста к MP3.

Рабочая альтернатива

Замена вызова диалога сохранения и переход с pyttsx3 на gTTS дают компактное решение, которое записывает валидный MP3. Обратная сторона — скорость и другие тонкие настройки в таком подходе не задаются.

out_path = filedialog.asksaveasfilename(filetypes=(("MP3 files", "*.mp3"),
                                                 ("All files", "*.*")))  # получить путь назначения
speech_obj = gTTS(text=text, lang='en')  # создать объект gTTS
speech_obj.save(out_path)  # записать MP3 в выбранное место

Подход сохраняет пользовательский запрос имени файла и использует gTTS для генерации аудио. Как отмечено, gTTS здесь проще в применении, тогда как pyttsx3 позволяет настраивать скорость и другие свойства.

Почему это важно

Небольшие различия в том, как вы получаете путь сохранения и как библиотека ожидает его получить, могут приводить к файлам, которые существуют, но не содержат корректных данных. Узнавая симптом — пустой MP3 — и понимая, что переход на запрос именно имени файла и использование gTTS — рабочий путь, можно сэкономить время. Это также помогает с ожиданиями: если важна тонкая настройка параметров (например, скорости), pyttsx3 даёт такую гибкость, а показанный упрощённый сценарий делает ставку на быстрый и надёжный результат.

Выводы

Если в связке Tkinter + TTS на macOS вы получаете пустой MP3, начните с двух простых рычагов. Предпочитайте asksaveasfilename вместо asksaveasfile для диалога сохранения и рассмотрите gTTS как упрощённый конвейер преобразования. Если нужна настройка скорости, помните, что pyttsx3 это поддерживает, тогда как показанный вариант с gTTS делает акцент на простоте, а не на точной параметризации.

Статья основана на вопросе на StackOverflow от Aadvik и ответе от Aadvik.