refactor(tts): remove Piper TTS provider #9

Closed
opened 2026-08-11 14:42:49 +03:00 by slaid098 · 0 comments
Owner

Контекст

Piper TTS — устаревший провайдер. Vosk TTS — более качественная модель (5 спикеров, ONNX). Piper занимает ~60 МБ в релизе, усложняет dispatch и preload логику. Пользователь решил полностью удалить Piper TTS из проекта. Остаются два провайдера: Google (cloud) + Vosk TTS (local).

Затронуто ~15 файлов: код, тесты, конфиги, документация, release workflow.

Задача

Полностью удалить Piper TTS из проекта. Все изменения ниже:

1. Удалить файлы

  • src/voice_assistant/speech/providers/piper_tts.py — удалить целиком (117 строк, класс PiperTTSProvider, синглтон piper_tts)
  • tests/test_piper.py — удалить целиком (41 строка, 3 теста)

2. src/voice_assistant/speech/tts.py

  • Убрать импорт: from voice_assistant.speech.providers.piper_tts import piper_tts (стр. 13)
  • Переписать _active_providers() (стр. 92-104). Новая логика:
    def _active_providers() -> list[TTSProvider]:
        """Возвращает провайдеры согласно настройке TTS_PROVIDER.
    
        google → [google, vosk]   (cloud основной, local fallback)
        vosk   → [vosk, google]   (local основной, cloud fallback)
        auto   → [vosk, google]   (local основной, cloud fallback)
        """
        if settings.tts_provider in {"vosk", "auto"}:
            return [vosk_tts, google_tts]
        return [google_tts, vosk_tts]
    
  • Удалить функцию preload_piper() целиком (стр. 171-191)
  • Обновить docstrings где упоминается Piper

3. src/voice_assistant/speech/model_loader.py

  • Удалить piper_model_path() и piper_config_path() (стр. 35-42)
  • Убрать Piper из docstring (стр. 7)

4. src/voice_assistant/config.py

  • Удалить поле piper_model: str (стр. 51)
  • Удалить загрузку piper_model=os.getenv("PIPER_MODEL", ...) (стр. 207)

5. src/voice_assistant/cli.py

  • Убрать preload_piper из импорта (стр. 15): from voice_assistant.speech.tts import preload_piper, speakfrom voice_assistant.speech.tts import speak
  • Удалить вызов preload_piper(wait=True) (стр. 53)
  • Изменить условие предзагрузки Vosk TTS (стр. 56-58): if settings.tts_provider == "vosk":if settings.tts_provider in {"vosk", "auto"}:
  • preload_vosk_tts() уже блокирующая (синхронная) — STARTUP звук играет после загрузки модели

6. Docstrings (убрать упоминания Piper)

  • src/voice_assistant/audio/sounds.py:58Google → Piper → звук ошибкиGoogle → Vosk → звук ошибки
  • src/voice_assistant/speech/providers/base.py:10Piper, Silero, RHVoiceVosk TTS, Silero, RHVoice
  • src/voice_assistant/speech/providers/vosk_tts.py:6общий с Piper → убрать
  • src/voice_assistant/speech/text_normalize.py:4Piper ru_RU-irina, → убрать

7. Тесты

  • tests/test_model_loader.py — удалить test_piper_model_path и test_piper_config_path (стр. 28-43)
  • tests/test_tts.py — переименовать mock_pipermock_local в 4 тестах (стр. 26-69, 111-124). Тесты мокают _active_providers напрямую, логика не меняется
  • tests/test_cli.py — удалить мок mock_piper (стр. 27-28) и проверку mock_piper.assert_called_once_with(wait=True) (стр. 35-36). monkeypatch.setattr(cli_mod, "preload_piper", ...) упадёт с AttributeError если не убрать — preload_piper больше не существует
  • tests/test_config.py:23-26 — заменить TTS_PROVIDER=piperTTS_PROVIDER=vosk в тесте test_settings_tts_provider_from_env

8. Зависимости

  • pyproject.toml:28 — удалить "piper-tts>=1.4.0",
  • Выполнить uv lock для перегенерации uv.lock (НЕ редактировать вручную)

9. .env.template

  • Стр. 49-55: убрать piper из списка TTS_PROVIDER, обновить auto описание:
    # Провайдер синтеза: google | vosk | auto
    #   google — онлайн, голос Google (основной, нужен интернет)
    #   vosk   — офлайн, локальная модель Vosk TTS (5 спикеров, 135 МБ)
    #   auto   — vosk основной, google резерв
    TTS_PROVIDER=google
    
  • Стр. 63: удалить PIPER_MODEL=ru_RU-irina-medium.onnx

10. .github/workflows/release.yml

  • Удалить шаг "Download Piper voice model" целиком (стр. 31-38)
  • Удалить --collect-all piper из PyInstaller команды (стр. 66)

11. Документация

  • README.md:54 — убрать piper из TTS_PROVIDER вариантов
  • README.md:56 — удалить строку PIPER_MODEL
  • AGENTS.md — обновить 7 строк (см. детальный список ниже в контрактах)

12. .gitignore

  • Удалить мёртвые паттерны (стр. 20-23): src/voice_assistant/assets/sounds/voices/*.onnx и *.onnx.json — устаревшие пути Piper

Контракты

auto режим (PRODUCT DECISION)

  • До: auto[piper, google] (local=piper основной, cloud fallback)
  • После: auto[vosk, google] (local=vosk основной, cloud fallback) — симметрично STT auto
  • piper как значение TTS_PROVIDER — больше не валидно. При piper fallback на google (через default branch в _active_providers)

Blocking preload (PRODUCT DECISION)

  • preload_vosk_tts() — уже синхронная (блокирующая), НЕ использует threading
  • Sound.STARTUP должен играть ПОСЛЕ загрузки Vosk TTS модели (для vosk/auto режимов)
  • Для google режима — STARTUP играет после preload_wake_word_detector() (нет local TTS модели для preload)

AGENTS.md изменения (7 строк)

  • Стр. 20: tts.py (gTTS/Piper + pygame)tts.py (gTTS/Vosk + pygame)
  • Стр. 22: убрать piper_tts.py из списка providers
  • Стр. 31: Piper + Vosk STT + Vosk TTS loadedVosk STT + Vosk TTS loaded
  • Стр. 51: google / piper / vosk / autogoogle / vosk / auto
  • Стр. 53: удалить PIPER_MODEL строку
  • Стр. 71: Google (cloud) + Piper (local, ONNX) + Vosk TTS (local, ONNX)Google (cloud) + Vosk TTS (local, ONNX)
  • Стр. 76: удалить models/piper/ строку

CHANGELOG.md — НЕ ТРОГАТЬ

История CHANGELOG будет обнулена в отдельном PR (issue про release pipeline v0.1.0). В этом PR CHANGELOG не меняется.

Инварианты

  • Удаляются только Piper-следы. Vosk TTS и Google TTS не затрагиваются (кроме dispatch логики)
  • TTSProvider Protocol в providers/base.py не меняется
  • vosk_tts синглтон в vosk_tts.py не меняется
  • Тесты conftest.py не меняются (моков piper там нет)
  • ci.yml не меняется (piper там не упоминается)
  • scripts/gen_phrases.py не меняется (использует Google TTS, не Piper)
  • threading импорт в cli.py остаётся (используется в _crash_handler через threading.Timer)

Граничные случаи

  • TTS_PROVIDER=piper в .env пользователя — после обновления fallback на google (default branch). Не падать, молча использовать google
  • preload_vosk_tts() при TTS_PROVIDER=google — НЕ вызывается (условие in {"vosk", "auto"})
  • ensure_vosk_tts_model импорт в cli.py:13 — проверить, используется ли он. Если да — оставить
  • uv.lock — перегенерировать через uv lock, НЕ редактировать вручную
  • Тест test_speak_fallback_to_piper → переименовать в test_speak_fallback_to_local, мокать vosk_tts вместо piper_tts

Влияние на связанные компоненты

  • tts.py — dispatch логика упрощается (3 режима вместо 4)
  • cli.py — preload последовательность меняется (убрать Piper, расширить Vosk условие на auto)
  • config.pySettings dataclass теряет поле piper_model
  • model_loader.py — теряет 2 функции (piper_model_path, piper_config_path)
  • release.yml — убирается шаг скачивания Piper модели (~60 МБ экономии в сборке)
  • pyproject.toml — убирается зависимость piper-tts (уменьшение dep-дерева)

Вне scope

  • CHANGELOG.md (будет обнулён в следующем PR про release pipeline)
  • Добавление новых TTS провайдеров (Silero, RHVoice — future enhancement)
  • Рефакторинг preload_vosk_tts в threading-модель (не нужен — уже блокирующая)
  • release.yml адаптация под Forgejo (отдельный issue)

Критерии приемки

  • piper_tts.py удалён
  • test_piper.py удалён
  • piper-tts убран из pyproject.toml, uv.lock перегенерирован
  • _active_providers() переписан: auto[vosk, google], piper значение невалидно
  • preload_piper() удалена из tts.py
  • cli.py: preload_piper(wait=True) убран, условие Vosk TTS расширено на auto
  • config.py: поле piper_model и PIPER_MODEL загрузка удалены
  • model_loader.py: piper_model_path и piper_config_path удалены
  • .env.template: PIPER_MODEL удалён, piper убран из TTS_PROVIDER
  • release.yml: шаг скачивания Piper и --collect-all piper удалены
  • Все docstrings очищены от упоминаний Piper
  • .gitignore: мёртвые Piper паттерны удалены
  • README.md и AGENTS.md обновлены
  • Все тесты переименованы/исправлены (mock_pipermock_local, test_config.py fix)
  • uv run ruff check src/ tests/ — зелёный
  • uv run ruff format --check src/ tests/ — зелёный
  • uv run mypy src/ — зелёный
  • uv run pytest — зелёный, покрытие ≥75%
  • uv run xenon --max-absolute B --max-modules B --max-average A src/ — зелёный
## Контекст Piper TTS — устаревший провайдер. Vosk TTS — более качественная модель (5 спикеров, ONNX). Piper занимает ~60 МБ в релизе, усложняет dispatch и preload логику. Пользователь решил полностью удалить Piper TTS из проекта. Остаются два провайдера: Google (cloud) + Vosk TTS (local). Затронуто ~15 файлов: код, тесты, конфиги, документация, release workflow. ## Задача Полностью удалить Piper TTS из проекта. Все изменения ниже: ### 1. Удалить файлы - `src/voice_assistant/speech/providers/piper_tts.py` — удалить целиком (117 строк, класс `PiperTTSProvider`, синглтон `piper_tts`) - `tests/test_piper.py` — удалить целиком (41 строка, 3 теста) ### 2. `src/voice_assistant/speech/tts.py` - Убрать импорт: `from voice_assistant.speech.providers.piper_tts import piper_tts` (стр. 13) - Переписать `_active_providers()` (стр. 92-104). Новая логика: ```python def _active_providers() -> list[TTSProvider]: """Возвращает провайдеры согласно настройке TTS_PROVIDER. google → [google, vosk] (cloud основной, local fallback) vosk → [vosk, google] (local основной, cloud fallback) auto → [vosk, google] (local основной, cloud fallback) """ if settings.tts_provider in {"vosk", "auto"}: return [vosk_tts, google_tts] return [google_tts, vosk_tts] ``` - Удалить функцию `preload_piper()` целиком (стр. 171-191) - Обновить docstrings где упоминается Piper ### 3. `src/voice_assistant/speech/model_loader.py` - Удалить `piper_model_path()` и `piper_config_path()` (стр. 35-42) - Убрать Piper из docstring (стр. 7) ### 4. `src/voice_assistant/config.py` - Удалить поле `piper_model: str` (стр. 51) - Удалить загрузку `piper_model=os.getenv("PIPER_MODEL", ...)` (стр. 207) ### 5. `src/voice_assistant/cli.py` - Убрать `preload_piper` из импорта (стр. 15): `from voice_assistant.speech.tts import preload_piper, speak` → `from voice_assistant.speech.tts import speak` - Удалить вызов `preload_piper(wait=True)` (стр. 53) - Изменить условие предзагрузки Vosk TTS (стр. 56-58): `if settings.tts_provider == "vosk":` → `if settings.tts_provider in {"vosk", "auto"}:` - `preload_vosk_tts()` уже блокирующая (синхронная) — STARTUP звук играет после загрузки модели ### 6. Docstrings (убрать упоминания Piper) - `src/voice_assistant/audio/sounds.py:58` — `Google → Piper → звук ошибки` → `Google → Vosk → звук ошибки` - `src/voice_assistant/speech/providers/base.py:10` — `Piper, Silero, RHVoice` → `Vosk TTS, Silero, RHVoice` - `src/voice_assistant/speech/providers/vosk_tts.py:6` — `общий с Piper` → убрать - `src/voice_assistant/speech/text_normalize.py:4` — `Piper ru_RU-irina,` → убрать ### 7. Тесты - `tests/test_model_loader.py` — удалить `test_piper_model_path` и `test_piper_config_path` (стр. 28-43) - `tests/test_tts.py` — переименовать `mock_piper` → `mock_local` в 4 тестах (стр. 26-69, 111-124). Тесты мокают `_active_providers` напрямую, логика не меняется - `tests/test_cli.py` — удалить мок `mock_piper` (стр. 27-28) и проверку `mock_piper.assert_called_once_with(wait=True)` (стр. 35-36). `monkeypatch.setattr(cli_mod, "preload_piper", ...)` упадёт с `AttributeError` если не убрать — `preload_piper` больше не существует - `tests/test_config.py:23-26` — заменить `TTS_PROVIDER=piper` → `TTS_PROVIDER=vosk` в тесте `test_settings_tts_provider_from_env` ### 8. Зависимости - `pyproject.toml:28` — удалить `"piper-tts>=1.4.0",` - Выполнить `uv lock` для перегенерации `uv.lock` (НЕ редактировать вручную) ### 9. `.env.template` - Стр. 49-55: убрать `piper` из списка `TTS_PROVIDER`, обновить `auto` описание: ``` # Провайдер синтеза: google | vosk | auto # google — онлайн, голос Google (основной, нужен интернет) # vosk — офлайн, локальная модель Vosk TTS (5 спикеров, 135 МБ) # auto — vosk основной, google резерв TTS_PROVIDER=google ``` - Стр. 63: удалить `PIPER_MODEL=ru_RU-irina-medium.onnx` ### 10. `.github/workflows/release.yml` - Удалить шаг "Download Piper voice model" целиком (стр. 31-38) - Удалить `--collect-all piper` из PyInstaller команды (стр. 66) ### 11. Документация - `README.md:54` — убрать `piper` из `TTS_PROVIDER` вариантов - `README.md:56` — удалить строку `PIPER_MODEL` - `AGENTS.md` — обновить 7 строк (см. детальный список ниже в контрактах) ### 12. `.gitignore` - Удалить мёртвые паттерны (стр. 20-23): `src/voice_assistant/assets/sounds/voices/*.onnx` и `*.onnx.json` — устаревшие пути Piper ## Контракты ### `auto` режим (PRODUCT DECISION) - До: `auto` → `[piper, google]` (local=piper основной, cloud fallback) - После: `auto` → `[vosk, google]` (local=vosk основной, cloud fallback) — симметрично STT `auto` - `piper` как значение `TTS_PROVIDER` — больше не валидно. При `piper` fallback на google (через default branch в `_active_providers`) ### Blocking preload (PRODUCT DECISION) - `preload_vosk_tts()` — уже синхронная (блокирующая), НЕ использует threading - `Sound.STARTUP` должен играть ПОСЛЕ загрузки Vosk TTS модели (для `vosk`/`auto` режимов) - Для `google` режима — STARTUP играет после `preload_wake_word_detector()` (нет local TTS модели для preload) ### AGENTS.md изменения (7 строк) - Стр. 20: `tts.py (gTTS/Piper + pygame)` → `tts.py (gTTS/Vosk + pygame)` - Стр. 22: убрать `piper_tts.py` из списка providers - Стр. 31: `Piper + Vosk STT + Vosk TTS loaded` → `Vosk STT + Vosk TTS loaded` - Стр. 51: `google / piper / vosk / auto` → `google / vosk / auto` - Стр. 53: удалить `PIPER_MODEL` строку - Стр. 71: `Google (cloud) + Piper (local, ONNX) + Vosk TTS (local, ONNX)` → `Google (cloud) + Vosk TTS (local, ONNX)` - Стр. 76: удалить `models/piper/` строку ### CHANGELOG.md — НЕ ТРОГАТЬ История CHANGELOG будет обнулена в отдельном PR (issue про release pipeline v0.1.0). В этом PR CHANGELOG не меняется. ## Инварианты - Удаляются только Piper-следы. Vosk TTS и Google TTS не затрагиваются (кроме dispatch логики) - `TTSProvider` Protocol в `providers/base.py` не меняется - `vosk_tts` синглтон в `vosk_tts.py` не меняется - Тесты `conftest.py` не меняются (моков piper там нет) - `ci.yml` не меняется (piper там не упоминается) - `scripts/gen_phrases.py` не меняется (использует Google TTS, не Piper) - `threading` импорт в `cli.py` остаётся (используется в `_crash_handler` через `threading.Timer`) ## Граничные случаи - `TTS_PROVIDER=piper` в .env пользователя — после обновления fallback на google (default branch). Не падать, молча использовать google - `preload_vosk_tts()` при `TTS_PROVIDER=google` — НЕ вызывается (условие `in {"vosk", "auto"}`) - `ensure_vosk_tts_model` импорт в `cli.py:13` — проверить, используется ли он. Если да — оставить - `uv.lock` — перегенерировать через `uv lock`, НЕ редактировать вручную - Тест `test_speak_fallback_to_piper` → переименовать в `test_speak_fallback_to_local`, мокать vosk_tts вместо piper_tts ## Влияние на связанные компоненты - `tts.py` — dispatch логика упрощается (3 режима вместо 4) - `cli.py` — preload последовательность меняется (убрать Piper, расширить Vosk условие на `auto`) - `config.py` — `Settings` dataclass теряет поле `piper_model` - `model_loader.py` — теряет 2 функции (`piper_model_path`, `piper_config_path`) - `release.yml` — убирается шаг скачивания Piper модели (~60 МБ экономии в сборке) - `pyproject.toml` — убирается зависимость `piper-tts` (уменьшение dep-дерева) ## Вне scope - CHANGELOG.md (будет обнулён в следующем PR про release pipeline) - Добавление новых TTS провайдеров (Silero, RHVoice — future enhancement) - Рефакторинг `preload_vosk_tts` в threading-модель (не нужен — уже блокирующая) - release.yml адаптация под Forgejo (отдельный issue) ## Критерии приемки - [ ] `piper_tts.py` удалён - [ ] `test_piper.py` удалён - [ ] `piper-tts` убран из `pyproject.toml`, `uv.lock` перегенерирован - [ ] `_active_providers()` переписан: `auto` → `[vosk, google]`, `piper` значение невалидно - [ ] `preload_piper()` удалена из `tts.py` - [ ] `cli.py`: `preload_piper(wait=True)` убран, условие Vosk TTS расширено на `auto` - [ ] `config.py`: поле `piper_model` и `PIPER_MODEL` загрузка удалены - [ ] `model_loader.py`: `piper_model_path` и `piper_config_path` удалены - [ ] `.env.template`: `PIPER_MODEL` удалён, `piper` убран из `TTS_PROVIDER` - [ ] `release.yml`: шаг скачивания Piper и `--collect-all piper` удалены - [ ] Все docstrings очищены от упоминаний Piper - [ ] `.gitignore`: мёртвые Piper паттерны удалены - [ ] `README.md` и `AGENTS.md` обновлены - [ ] Все тесты переименованы/исправлены (`mock_piper` → `mock_local`, `test_config.py` fix) - [ ] `uv run ruff check src/ tests/` — зелёный - [ ] `uv run ruff format --check src/ tests/` — зелёный - [ ] `uv run mypy src/` — зелёный - [ ] `uv run pytest` — зелёный, покрытие ≥75% - [ ] `uv run xenon --max-absolute B --max-modules B --max-average A src/` — зелёный
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
slaid098/voice_assistant#9
No description provided.