- Fix install_mac.sh: use venv + Python 3.12 (3.14 incompatible with ML libs) - Fix run_mac.sh: activate venv, add CPU thread optimization env vars - Fix agent.py: remove f-string from SYSTEM_PROMPT template (NameError on import) - Add missing deps: sounddevice, pydub, imageio-ffmpeg, omegaconf - Optimize for M1: torch.inference_mode, set_num_threads, OMP/MKL tuning - Switch to qwen2.5:3b for faster LLM responses on Mac - Switch Whisper to medium model with auto compute (small+int8 had poor Russian) - Add initial_prompt for better Russian transcription - Add open_app tool for native macOS app launching - Fix TTS: sanitize Latin text to Cyrillic for Silero compatibility - Fix wake word echo: add cooldown after TTS, reset model state, raise threshold - Make "Слушаю" TTS synchronous to avoid mic interference - Fix train Dockerfile: remove tensorflow/onnx2tf (only ONNX needed), fix deps - Fix train.sh: use wget for dataset download, add --shm-size=2g - Add trained hey_cosmo.onnx wake word model - Add TODO section to CLAUDE.md (ChatterBox TTS, Ollama Modelfile ideas) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
8.8 KiB
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
Поток работы:
wake_word.py— непрерывно слушает микрофон, детектирует слово-триггерtranscriber.py— записывает команду, транскрибирует через Whisperagent.py— отправляет текст в Ollama, LLM вызывает инструменты в цикле пока не решит задачу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 install.sh # первый раз
bash run.sh
macOS
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)
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:
{
"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 ГБ свободного места.
# Опционально: запиши свой голос (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):
@tool
def my_tool(param: str) -> str:
"""
Описание что делает инструмент — LLM читает это.
Args:
param: описание параметра
"""
# реализация
return "результат"
Добавь в список ALL_TOOLS в конце файла — агент автоматически получит доступ.
TODO / Идеи
- ChatterBox TTS вместо Silero — более живой голос с эмоциями и клонированием голоса (10-30 сек сэмпла). Источник: vndee/local-talking-llm. Параметр
exaggeration(0.0–1.0) управляет экспрессивностью. Заменитьcosmo/tts.py, интерфейсsay()/say_async()не меняется. Проверить латентность на M1 CPU. - Ollama Modelfile — запечь системный промпт и параметры (короткие ответы, русский язык) прямо в модель через Modelfile, вместо передачи в каждом запросе.
Разработка
Логи пишутся в logs/cosmo.log. Уровень логирования меняется в конфиге (logging.level: DEBUG).
Для тестирования агента без голоса:
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('открой браузер'))
"