Полностью локальный голосовой ассистент на Python. Стек: - Wake word: openWakeWord (onnxruntime) - STT: RealtimeSTT + faster-whisper + Silero VAD (CUDA) - LLM-агент: smolagents ToolCallingAgent + Ollama qwen2.5:7b - TTS: Silero V4 (torch.hub) + sounddevice - Shell: Git Bash (Windows) / bash (macOS) Поддерживает Windows и macOS. Агент с памятью и tool calling — находит программы самостоятельно, запоминает пути, выполняет произвольные shell-команды. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
209 lines
8.0 KiB
Markdown
209 lines
8.0 KiB
Markdown
# Cosmo — локальный голосовой ассистент
|
||
|
||
Полностью локальный голосовой ассистент на Python. Не использует облачные API, всё работает на твоём железе.
|
||
|
||
## Архитектура
|
||
|
||
```
|
||
Микрофон → Wake Word → STT → LLM-агент → TTS → Динамики
|
||
↓ ↓ ↓
|
||
openWakeWord Whisper smolagents
|
||
(hey_jarvis) (cuda) + Ollama
|
||
↓
|
||
Инструменты:
|
||
run_shell, find_program,
|
||
open_browser, read/write_file,
|
||
memory_get/set
|
||
```
|
||
|
||
**Поток работы:**
|
||
1. `wake_word.py` — непрерывно слушает микрофон, детектирует слово-триггер
|
||
2. `transcriber.py` — записывает команду, транскрибирует через Whisper
|
||
3. `agent.py` — отправляет текст в Ollama, LLM вызывает инструменты в цикле пока не решит задачу
|
||
4. `tts.py` — озвучивает ответ через Silero
|
||
|
||
## Структура файлов
|
||
|
||
```
|
||
cosmo/
|
||
├── main.py — точка входа, класс Cosmo
|
||
├── wake_word.py — детект wake word (openWakeWord + onnxruntime)
|
||
├── transcriber.py — STT (RealtimeSTT + faster-whisper + Silero VAD)
|
||
├── agent.py — LLM-агент (smolagents ToolCallingAgent + Ollama)
|
||
├── tools.py — инструменты агента для Windows (Git Bash)
|
||
├── tools_mac.py — инструменты агента для macOS (нативный bash)
|
||
├── memory.py — персистентная память (data/memory.json)
|
||
└── tts.py — TTS (Silero V4 через torch.hub + sounddevice)
|
||
|
||
config/
|
||
├── config.yaml — настройки для Windows
|
||
└── config_mac.yaml — настройки для macOS (CPU, int8)
|
||
|
||
train_wakeword/
|
||
├── record_samples.py — запись голосовых примеров
|
||
├── cosmo_config.yaml — конфиг обучения wake word
|
||
├── Dockerfile — среда Python 3.11 для обучения
|
||
├── entrypoint.sh — шаги обучения внутри Docker
|
||
└── train.sh — главный скрипт обучения
|
||
|
||
data/
|
||
└── memory.json — долгосрочная память агента (создаётся автоматически)
|
||
|
||
models/
|
||
└── *.onnx — кастомные wake word модели (после обучения)
|
||
```
|
||
|
||
## Железо (Windows машина)
|
||
|
||
- CPU: Intel i5-13400F (10 ядер / 16 потоков)
|
||
- RAM: 32 ГБ DDR5 6000
|
||
- GPU: RTX 4060 8 ГБ VRAM
|
||
- OS: Windows 11, Python 3.13
|
||
|
||
## Стек технологий
|
||
|
||
| Компонент | Технология | Версия |
|
||
|---|---|---|
|
||
| Wake word | openWakeWord + onnxruntime | 0.6.0 |
|
||
| STT | RealtimeSTT + faster-whisper | 0.3.104 / 1.1.1 |
|
||
| VAD | Silero VAD (внутри RealtimeSTT) | — |
|
||
| LLM | Ollama + qwen2.5:7b | ollama 0.6.1 |
|
||
| Agent | smolagents ToolCallingAgent | 1.11.0 |
|
||
| TTS | Silero V4 (torch.hub) + sounddevice | — |
|
||
| Shell | Git Bash (Windows) / bash (macOS) | — |
|
||
|
||
## Запуск
|
||
|
||
### Windows
|
||
```bash
|
||
bash install.sh # первый раз
|
||
bash run.sh
|
||
```
|
||
|
||
### macOS
|
||
```bash
|
||
bash install_mac.sh # первый раз
|
||
bash run_mac.sh
|
||
```
|
||
|
||
При первом запуске автоматически скачаются:
|
||
- Whisper модель (~1.5 ГБ на Windows / ~150 МБ на Mac)
|
||
- Silero TTS модель (~38 МБ)
|
||
|
||
## Активация
|
||
|
||
Сейчас: говори **"Hey Jarvis"** — это fallback пока нет кастомной модели.
|
||
|
||
После обучения кастомной модели: говори **"Hey Cosmo"**.
|
||
|
||
После активации говори команду на русском: *"открой браузер"*, *"найди в гугле погоду"*, *"запусти WebStorm"*.
|
||
|
||
## Конфиг (config/config.yaml)
|
||
|
||
```yaml
|
||
whisper:
|
||
model_size: "distil-large-v3" # Windows GPU
|
||
# model_size: "small" # Mac CPU
|
||
device: "cuda" # "cpu" для Mac
|
||
compute_type: "float16" # "int8" для CPU
|
||
|
||
ollama:
|
||
model: "qwen2.5:7b" # модель должна быть скачана: ollama pull qwen2.5:7b
|
||
max_agent_steps: 10 # макс. шагов агента на одну команду
|
||
|
||
tts:
|
||
silero_speaker: "eugene" # голоса: xenia (ж), baya, aidar, eugene, kseniya
|
||
```
|
||
|
||
## Память агента
|
||
|
||
Агент автоматически запоминает информацию в `data/memory.json`:
|
||
|
||
```json
|
||
{
|
||
"facts": {
|
||
"app.webstorm": "C:/Program Files/JetBrains/WebStorm.../webstorm64.exe",
|
||
"user.name": "Даниил"
|
||
},
|
||
"history": [...]
|
||
}
|
||
```
|
||
|
||
**Ключи памяти:**
|
||
- `app.<название>` — пути к программам
|
||
- `user.<поле>` — данные о пользователе
|
||
- `pref.<что>` — предпочтения
|
||
|
||
После первого поиска программы агент запомнит её путь и больше не будет искать.
|
||
|
||
## Инструменты агента
|
||
|
||
| Инструмент | Описание |
|
||
|---|---|
|
||
| `run_shell` | Выполнить bash команду |
|
||
| `find_program` | Найти программу (PATH, Program Files, реестр / Spotlight на Mac) |
|
||
| `open_browser` | Открыть URL или поиск Google |
|
||
| `read_file` | Прочитать файл |
|
||
| `write_file` | Записать файл |
|
||
| `memory_get` | Получить факт из памяти |
|
||
| `memory_set` | Сохранить факт в память |
|
||
| `memory_list` | Показать все факты |
|
||
|
||
## Обучение кастомной wake word "Hey Cosmo"
|
||
|
||
Требования: Docker Desktop, ~25 ГБ свободного места.
|
||
|
||
```bash
|
||
# Опционально: запиши свой голос (30 примеров)
|
||
python train_wakeword/record_samples.py
|
||
|
||
# Запусти обучение (~1 час)
|
||
bash train_wakeword/train.sh
|
||
```
|
||
|
||
Датасет (~20 ГБ) скачается в `train_wakeword/docker_data/` и сохранится для повторного использования.
|
||
|
||
После обучения `.onnx` модель автоматически появится в `models/` и `wake_word.py` подхватит её.
|
||
|
||
## Известные ограничения
|
||
|
||
- Wake word только английский ("Hey Jarvis" / "Hey Cosmo") — openWakeWord не поддерживает русский TTS для обучения
|
||
- На Mac нет CUDA — Whisper работает на CPU, латентность выше (~2-3 сек вместо ~0.5 сек)
|
||
- smolagents требует модель с поддержкой tool calling — qwen2.5:7b, llama3.2, mistral v0.3+
|
||
|
||
## Добавление новых инструментов
|
||
|
||
В `cosmo/tools.py` (Windows) или `cosmo/tools_mac.py` (Mac):
|
||
|
||
```python
|
||
@tool
|
||
def my_tool(param: str) -> str:
|
||
"""
|
||
Описание что делает инструмент — LLM читает это.
|
||
|
||
Args:
|
||
param: описание параметра
|
||
"""
|
||
# реализация
|
||
return "результат"
|
||
```
|
||
|
||
Добавь в список `ALL_TOOLS` в конце файла — агент автоматически получит доступ.
|
||
|
||
## Разработка
|
||
|
||
Логи пишутся в `logs/cosmo.log`. Уровень логирования меняется в конфиге (`logging.level: DEBUG`).
|
||
|
||
Для тестирования агента без голоса:
|
||
```bash
|
||
python -c "
|
||
import yaml, sys
|
||
sys.path.insert(0, '.')
|
||
from cosmo.memory import Memory
|
||
from cosmo.agent import Agent
|
||
config = yaml.safe_load(open('config/config.yaml'))
|
||
agent = Agent(config, Memory())
|
||
print(agent.run('открой браузер'))
|
||
"
|
||
```
|