230 lines
13 KiB
Markdown
230 lines
13 KiB
Markdown
# Alexander Smart Speaker
|
||
|
||
<div align="center">
|
||
|
||
Голосовой ассистент для Linux: wake word, STT/TTS, AI-диалог и полезные голосовые навыки.
|
||
|
||
[](https://www.python.org/)
|
||
[](https://www.linux.org/)
|
||
[](LICENSE.txt)
|
||
[](https://picovoice.ai/platform/porcupine/)
|
||
[](https://deepgram.com/)
|
||
[](https://github.com/snakers4/silero-models)
|
||
|
||
</div>
|
||
|
||
## Что это
|
||
|
||
`Alexander Smart Speaker` слушает ключевое слово `Alexandr`, распознает речь, маршрутизирует команду в нужный модуль и озвучивает ответ.
|
||
Проект оптимизирован под русский язык, но поддерживает RU/EN сценарии (включая перевод и mixed-language TTS).
|
||
|
||
Проект собран как локальная голосовая колонка под Linux: активация по wake word, распознавание речи, маршрутизация команд, ответ через AI или встроенные модули и затем озвучка результата.
|
||
|
||
## Возможности
|
||
|
||
- Активация по wake word `Alexandr` (Porcupine).
|
||
- Follow-up окно 4 секунды после ответа: если пользователь молчит, ассистент возвращается к ожиданию wake word.
|
||
- Распознавание речи через Deepgram (WebSocket, VAD, fast stop).
|
||
- Озвучка через Silero TTS (RU + EN, с прерыванием по wake word).
|
||
- AI-диалог через OpenRouter, OpenAI, Gemini, Z.ai и Anthropic Claude API со streaming-ответом и контекстом.
|
||
- Перевод RU -> EN и EN -> RU.
|
||
- Погода: текущий прогноз по городу по умолчанию или по названию города.
|
||
- Таймеры, будильники (включая будни/выходные), секундомеры.
|
||
- Управление громкостью системы (через `pactl`/`amixer`).
|
||
- Управление Spotify (play/pause/next/what's playing).
|
||
- Мини-игра "Города".
|
||
|
||
## Как это работает
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
A[Wake Word: Alexandr] --> B[STT: Deepgram]
|
||
B --> C{Маршрутизация команды}
|
||
C --> D[Feature modules]
|
||
C --> E[AI/Translation]
|
||
D --> F[TTS: Silero]
|
||
E --> F
|
||
F --> G[Follow-up режим или ожидание wake word]
|
||
```
|
||
|
||
## Что Важно В Этой Реализации
|
||
|
||
- Контекст диалога хранится в памяти текущей сессии, поэтому после первого вопроса можно продолжать разговор без потери нити.
|
||
- Системная роль ассистента и `ROLE_JSON` сохраняются для всех поддерживаемых AI-провайдеров.
|
||
- Для AI используется строго один активный API key. Если в `.env` оставить несколько ключей, ассистент покажет ошибку конфигурации вместо случайного выбора.
|
||
- Поддержка провайдеров сделана внутри одного модуля, но с разным форматом запросов для OpenAI-compatible API и Anthropic.
|
||
|
||
## Быстрый старт
|
||
|
||
### 1) Системные зависимости (Ubuntu/Debian)
|
||
|
||
```bash
|
||
sudo apt-get update
|
||
sudo apt-get install -y portaudio19-dev libasound2-dev mpg123 pulseaudio-utils alsa-utils
|
||
```
|
||
|
||
### 2) Установка Python-зависимостей
|
||
|
||
```bash
|
||
git clone <URL_ВАШЕГО_РЕПОЗИТОРИЯ>
|
||
cd alexander_smart-speaker
|
||
python3 -m venv venv
|
||
source venv/bin/activate
|
||
pip install -r requirements.txt
|
||
```
|
||
|
||
### 3) Настройка `.env`
|
||
|
||
```bash
|
||
cp .env.example .env
|
||
```
|
||
|
||
Минимально обязательные переменные:
|
||
|
||
```ini
|
||
AI_PROVIDER= # опционально; можно оставить пустым
|
||
# Раскомментируйте только один AI API KEY:
|
||
# OPENROUTER_API_KEY=...
|
||
# OPENAI_API_KEY=...
|
||
# GEMINI_API_KEY=...
|
||
# ZAI_API_KEY=...
|
||
# ANTHROPIC_API_KEY=...
|
||
DEEPGRAM_API_KEY=...
|
||
PORCUPINE_ACCESS_KEY=...
|
||
```
|
||
|
||
Если одновременно оставить несколько AI API key, ассистент вернет ошибку: он не будет выбирать провайдера наугад.
|
||
|
||
Пример:
|
||
|
||
```ini
|
||
# правильно
|
||
OPENAI_API_KEY=sk-...
|
||
# GEMINI_API_KEY=...
|
||
# ANTHROPIC_API_KEY=...
|
||
|
||
# неправильно
|
||
OPENAI_API_KEY=sk-...
|
||
GEMINI_API_KEY=AIza...
|
||
```
|
||
|
||
### 4) Запуск
|
||
|
||
```bash
|
||
make run
|
||
# или
|
||
python run.py
|
||
```
|
||
|
||
После запуска ассистент перейдет в режим ожидания фразы `Alexandr`.
|
||
|
||
### Кросс-платформенный аудио режим
|
||
|
||
- Приложение автоматически подбирает рабочий микрофон/динамик через PortAudio.
|
||
- Если основное аудио-устройство не подходит, включается fallback по другим устройствам и sample rate.
|
||
- При проблемах можно явно задать устройство через `.env` (`AUDIO_*_DEVICE_NAME` или `AUDIO_*_DEVICE_INDEX`).
|
||
|
||
## Конфигурация `.env`
|
||
|
||
| Переменная | Обязательно | По умолчанию | Назначение |
|
||
|---|---|---|---|
|
||
| `AI_PROVIDER` | Нет | `openrouter` | Опциональный провайдер AI (`openrouter`, `openai`, `gemini`, `zai`, `anthropic`; также понимает `claude`) |
|
||
| `OPENROUTER_API_KEY` | Да* | - | Ключ OpenRouter API (*если выбран OpenRouter и только этот AI ключ активен) |
|
||
| `OPENROUTER_MODEL` | Нет | `openai/gpt-4o-mini` | Модель OpenRouter |
|
||
| `OPENROUTER_API_URL` | Нет | `https://openrouter.ai/api/v1/chat/completions` | Endpoint OpenRouter Chat Completions |
|
||
| `OPENAI_API_KEY` | Да* | - | Ключ OpenAI API (*если выбран OpenAI и только этот AI ключ активен) |
|
||
| `OPENAI_MODEL` | Нет | `gpt-4o-mini` | Модель OpenAI |
|
||
| `OPENAI_API_URL` | Нет | `https://api.openai.com/v1/chat/completions` | Endpoint OpenAI Chat Completions |
|
||
| `GEMINI_API_KEY` | Да* | - | Ключ Google Gemini API (*если выбран Gemini и только этот AI ключ активен) |
|
||
| `GEMINI_MODEL` | Нет | `gemini-2.5-flash` | Модель Gemini |
|
||
| `GEMINI_API_URL` | Нет | `https://generativelanguage.googleapis.com/v1beta/openai/chat/completions` | OpenAI-compatible endpoint Gemini |
|
||
| `ZAI_API_KEY` | Да* | - | Ключ Z.ai API (*если выбран Z.ai и только этот AI ключ активен) |
|
||
| `ZAI_MODEL` | Нет | `glm-5` | Модель Z.ai |
|
||
| `ZAI_API_URL` | Нет | `https://api.z.ai/api/paas/v4/chat/completions` | Endpoint Z.ai Chat Completions |
|
||
| `ANTHROPIC_API_KEY` | Да* | - | Ключ Anthropic API (*если выбран Anthropic и только этот AI ключ активен) |
|
||
| `ANTHROPIC_MODEL` | Нет | `claude-sonnet-4-20250514` | Модель Claude |
|
||
| `ANTHROPIC_API_URL` | Нет | `https://api.anthropic.com/v1/messages` | Endpoint Anthropic Messages API |
|
||
| `ANTHROPIC_API_VERSION` | Нет | `2023-06-01` | Версия Anthropic API |
|
||
| `DEEPGRAM_API_KEY` | Да | - | Ключ Deepgram STT |
|
||
| `PORCUPINE_ACCESS_KEY` | Да | - | Ключ PicoVoice Porcupine |
|
||
| `PORCUPINE_SENSITIVITY` | Нет | `0.8` | Чувствительность wake word |
|
||
| `AUDIO_INPUT_DEVICE_NAME` | Нет | auto | Подстрока имени микрофона (например `pulse`), если нужно выбрать конкретный input device |
|
||
| `AUDIO_INPUT_DEVICE_INDEX` | Нет | auto | Индекс PortAudio для микрофона (приоритетнее `AUDIO_INPUT_DEVICE_NAME`) |
|
||
| `AUDIO_OUTPUT_DEVICE_NAME` | Нет | auto | Подстрока имени динамика/выхода (например `pulse`) |
|
||
| `AUDIO_OUTPUT_DEVICE_INDEX` | Нет | auto | Индекс PortAudio для вывода (приоритетнее `AUDIO_OUTPUT_DEVICE_NAME`) |
|
||
| `TTS_EN_SPEAKER` | Нет | `en_0` | Английский голос TTS |
|
||
| `WEATHER_LAT` | Нет | - | Широта города по умолчанию |
|
||
| `WEATHER_LON` | Нет | - | Долгота города по умолчанию |
|
||
| `WEATHER_CITY` | Нет | `Ухта` | Город по умолчанию для погоды |
|
||
| `SPOTIFY_CLIENT_ID` | Нет | - | Spotify OAuth Client ID |
|
||
| `SPOTIFY_CLIENT_SECRET` | Нет | - | Spotify OAuth Client Secret |
|
||
| `SPOTIFY_REDIRECT_URI` | Нет | `http://localhost:8888/callback` | Redirect URI для Spotify |
|
||
|
||
## Примеры голосовых команд
|
||
|
||
| Категория | Примеры |
|
||
|---|---|
|
||
| Активация | `Alexandr` |
|
||
| AI-диалог | `Почему небо голубое?` |
|
||
| Перевод | `Переведи на английский: как дела` |
|
||
| Погода | `Какая погода?`, `Погода в Москве` |
|
||
| Таймер | `Поставь таймер на 5 минут` |
|
||
| Будильник | `Поставь будильник на 7:30`, `Будильник по будням в 8:00` |
|
||
| Секундомер | `Запусти секундомер`, `Покажи активные секундомеры` |
|
||
| Громкость | `Громкость 7` |
|
||
| Spotify | `Включи музыку`, `Пауза`, `Что сейчас играет` |
|
||
| Игра | `Давай сыграем в города` |
|
||
| Управление диалогом | `Повтори`, `Стоп`, `Хватит` |
|
||
|
||
Память текущего диалога, история сообщений и `ROLE_JSON` системной роли сохраняются для всех поддерживаемых AI-провайдеров.
|
||
|
||
## Как Выбирается AI-Провайдер
|
||
|
||
1. Приложение проверяет, какие AI API key реально активны в `.env`.
|
||
2. Если активен ровно один ключ, используется именно он.
|
||
3. Если активны несколько ключей, ассистент возвращает ошибку конфигурации.
|
||
4. Если активных ключей нет, приложение ориентируется на `AI_PROVIDER`, но без ключа работать не сможет.
|
||
|
||
Такое поведение сделано специально, чтобы конфигурация была предсказуемой и при демонстрации не возникало скрытого переключения между сервисами.
|
||
|
||
## Полезные команды
|
||
|
||
| Команда | Что делает |
|
||
|---|---|
|
||
| `make run` | Запуск ассистента |
|
||
| `make check` | Локальная проверка проекта (`scripts/qwen-check.sh`) |
|
||
| `make qwen-context` | Сбор контекста проекта (`scripts/qwen-context.sh`) |
|
||
|
||
## Структура проекта
|
||
|
||
```text
|
||
alexander_smart-speaker/
|
||
├── run.py
|
||
├── app/
|
||
│ ├── main.py
|
||
│ ├── audio/ # wakeword, stt, tts, volume
|
||
│ ├── core/ # config, ai, command helpers, cleaner
|
||
│ └── features/ # weather, timer, alarm, stopwatch, music, cities game
|
||
├── assets/
|
||
│ ├── models/ # Porcupine keyword model (.ppn)
|
||
│ └── sounds/ # звуки уведомлений и будильника
|
||
├── data/ # persisted JSON: alarms, timers, stopwatches
|
||
└── scripts/
|
||
```
|
||
|
||
## Диагностика
|
||
|
||
| Проблема | Что проверить |
|
||
|---|---|
|
||
| Не реагирует на `Alexandr` | `PORCUPINE_ACCESS_KEY`, микрофон, чувствительность `PORCUPINE_SENSITIVITY` |
|
||
| STT не распознает речь | `DEEPGRAM_API_KEY`, сетевой доступ, выбранный микрофон |
|
||
| Нет звука | корректное аудиоустройство и доступность `pactl`/`amixer` |
|
||
| `Audio input/output initialization failed` | проверить, что звук-сервер запущен (PipeWire/PulseAudio), и при необходимости задать `AUDIO_INPUT_DEVICE_NAME`/`AUDIO_OUTPUT_DEVICE_NAME` |
|
||
| Будильник/таймер не звонит | наличие `mpg123` в системе |
|
||
| Ошибка про несколько AI API | в `.env` должен остаться только один незакомментированный AI ключ |
|
||
| Spotify не управляется | заполнены `SPOTIFY_*`, есть активное устройство, Premium-аккаунт |
|
||
|
||
## Лицензия
|
||
|
||
Проект распространяется по лицензии MIT. См. `LICENSE.txt`.
|