- 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>
114 lines
4.3 KiB
Bash
114 lines
4.3 KiB
Bash
#!/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] Скачиваю негативный датасет (~17 GB + ~500 MB, один раз)..."
|
||
echo " Это займёт время в зависимости от скорости интернета."
|
||
echo ""
|
||
echo " Скачиваю ACAV100M features (~17 GB)..."
|
||
wget -q --show-progress \
|
||
-O "$NEGATIVE_FEATURES" \
|
||
"https://huggingface.co/datasets/davidscripka/openwakeword_features/resolve/main/openwakeword_features_ACAV100M_2000_hrs_16bit.npy"
|
||
echo " Скачиваю validation features (~500 MB)..."
|
||
wget -q --show-progress \
|
||
-O "$VALIDATION_FEATURES" \
|
||
"https://huggingface.co/datasets/davidscripka/openwakeword_features/resolve/main/validation_set_features.npy"
|
||
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 \
|
||
--shm-size=2g \
|
||
-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
|