Initial commit: Cosmo voice assistant

Полностью локальный голосовой ассистент на 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>
This commit is contained in:
d.klimov
2026-04-10 15:58:12 +03:00
commit 6010816f1d
23 changed files with 1969 additions and 0 deletions

119
train_wakeword/train.sh Normal file
View File

@@ -0,0 +1,119 @@
#!/usr/bin/env bash
set -e
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
MODELS_DIR="$PROJECT_DIR/models"
SAMPLES_DIR="$SCRIPT_DIR/samples"
DATA_DIR="$SCRIPT_DIR/docker_data"
echo "============================================"
echo " Cosmo Wake Word — обучение модели"
echo "============================================"
echo ""
# Проверяем Docker
if ! command -v docker &>/dev/null; then
echo "ОШИБКА: Docker не найден."
echo "Установи Docker Desktop: https://www.docker.com/products/docker-desktop/"
exit 1
fi
if ! docker info &>/dev/null; then
echo "ОШИБКА: Docker не запущен. Запусти Docker Desktop и попробуй снова."
exit 1
fi
# Проверяем что есть записанные примеры
POSITIVE_DIR="$SAMPLES_DIR/positive"
if [ ! -d "$POSITIVE_DIR" ] || [ -z "$(ls "$POSITIVE_DIR"/*.wav 2>/dev/null)" ]; then
echo "Записанные примеры не найдены."
echo "Сначала запусти запись голоса:"
echo " python train_wakeword/record_samples.py"
echo ""
read -p "Продолжить без записанных примеров? (используются только TTS) [y/N]: " yn
case "$yn" in
[Yy]*) echo "Продолжаем с только TTS примерами..." ;;
*) exit 0 ;;
esac
fi
mkdir -p "$MODELS_DIR" "$DATA_DIR"
# Собираем Docker образ
echo "[1/4] Собираю Docker образ (первый раз ~5-10 мин)..."
docker build -t cosmo-wakeword-trainer "$SCRIPT_DIR" --quiet
echo " Образ готов."
echo ""
# Скачиваем датасет негативных примеров если нет
NEGATIVE_FEATURES="$DATA_DIR/openwakeword_features_ACAV100M_2000_hrs_16bit.npy"
VALIDATION_FEATURES="$DATA_DIR/validation_set_features.npy"
if [ ! -f "$NEGATIVE_FEATURES" ]; then
echo "[2/4] Скачиваю негативный датасет (~20 GB, один раз)..."
echo " Это займёт время в зависимости от скорости интернета."
docker run --rm \
-v "$DATA_DIR:/data" \
cosmo-wakeword-trainer \
python -c "
from datasets import load_dataset
import numpy as np, os
print('Скачиваю ACAV100M features...')
ds = load_dataset('davidscripka/openwakeword_features', 'ACAV100M_2000_hrs_16bit', split='train')
arr = np.array(ds['features'])
np.save('/data/openwakeword_features_ACAV100M_2000_hrs_16bit.npy', arr)
print('Скачиваю validation features...')
ds_val = load_dataset('davidscripka/openwakeword_features', 'validation_set', split='train')
arr_val = np.array(ds_val['features'])
np.save('/data/validation_set_features.npy', arr_val)
print('Датасет скачан.')
"
echo " Датасет готов."
else
echo "[2/4] Негативный датасет уже скачан. Пропускаю."
fi
echo ""
# Запускаем обучение
echo "[3/4] Запускаю обучение в Docker..."
echo " Это займёт ~30-60 минут."
echo ""
SAMPLES_MOUNT=""
if [ -d "$POSITIVE_DIR" ] && [ -n "$(ls "$POSITIVE_DIR"/*.wav 2>/dev/null)" ]; then
SAMPLES_MOUNT="-v $POSITIVE_DIR:/samples/positive"
fi
docker run --rm \
-v "$SCRIPT_DIR/cosmo_config.yaml:/app/cosmo_config.yaml" \
-v "$DATA_DIR:/data" \
-v "$MODELS_DIR:/output" \
$SAMPLES_MOUNT \
cosmo-wakeword-trainer
echo ""
echo "[4/4] Копирую модель в проект..."
# Ищем готовую модель
ONNX_FILE=$(ls "$MODELS_DIR"/*.onnx 2>/dev/null | head -1)
if [ -n "$ONNX_FILE" ]; then
echo ""
echo "============================================"
echo " Готово! Модель сохранена:"
echo " $ONNX_FILE"
echo ""
echo " Обновляю wake_word детектор..."
# Обновляем путь в конфиге
MODEL_FILENAME=$(basename "$ONNX_FILE")
sed -i "s|wakeword_models=\[\"hey_jarvis\"\]|wakeword_models=[\"models/$MODEL_FILENAME\"]|g" \
"$PROJECT_DIR/cosmo/wake_word.py" 2>/dev/null || true
echo " Теперь запускай: bash run.sh"
echo " и говори 'Hey Cosmo' для активации!"
echo "============================================"
else
echo "ОШИБКА: .onnx файл не найден в $MODELS_DIR"
echo "Проверь логи Docker выше."
exit 1
fi