minerva/scripts/quick_start_hey_mycroft.sh
pyr0ball 173f7f37d4 feat: import mycroft-precise work as Minerva foundation
Ports prior voice assistant research and prototypes from devl/Devops
into the Minerva repo. Includes:

- docs/: architecture, wake word guides, ESP32-S3 spec, hardware buying guide
- scripts/: voice_server.py, voice_server_enhanced.py, setup scripts
- hardware/maixduino/: edge device scripts with WiFi credentials scrubbed
  (replaced hardcoded password with secrets.py pattern)
- config/.env.example: server config template
- .gitignore: excludes .env, secrets.py, model blobs, ELF firmware
- CLAUDE.md: Minerva product context and connection to cf-voice roadmap
2026-04-06 22:21:12 -07:00

456 lines
13 KiB
Bash
Executable file

#!/usr/bin/env bash
#
# Path: quick_start_hey_mycroft.sh
#
# Purpose and usage:
# Zero-training quick start using pre-trained "Hey Mycroft" model
# Gets you a working voice assistant in 5 minutes!
#
# Requirements:
# - Heimdall already setup (ran setup_voice_assistant.sh)
# - Mycroft Precise installed (ran setup_precise.sh)
#
# Usage:
# ./quick_start_hey_mycroft.sh [--test-only]
#
# Author: PRbL Library
# ----- PRbL Color and output functions -----
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
BLUE='\033[0;34m'
PURPLE='\033[0;35m'
CYAN='\033[0;36m'
NC='\033[0m'
print_status() {
local level="$1"
shift
case "$level" in
"info") echo -e "${BLUE}[INFO]${NC} $*" >&2 ;;
"success") echo -e "${GREEN}[SUCCESS]${NC} $*" >&2 ;;
"warning") echo -e "${YELLOW}[WARNING]${NC} $*" >&2 ;;
"error") echo -e "${RED}[ERROR]${NC} $*" >&2 ;;
*) echo -e "$*" >&2 ;;
esac
}
# ----- Configuration -----
MODELS_DIR="$HOME/precise-models/pretrained"
MODEL_URL="https://github.com/MycroftAI/precise-data/raw/models-dev/hey-mycroft.tar.gz"
MODEL_NAME="hey-mycroft"
TEST_ONLY=false
# ----- Parse arguments -----
parse_args() {
while [[ $# -gt 0 ]]; do
case "$1" in
--test-only)
TEST_ONLY=true
shift
;;
-h|--help)
cat << EOF
Usage: $(basename "$0") [OPTIONS]
Quick start with pre-trained "Hey Mycroft" wake word model.
No training required!
Options:
--test-only Just test the model, don't start server
-h, --help Show this help
Examples:
$(basename "$0") # Download, test, and run server
$(basename "$0") --test-only # Just download and test
EOF
exit 0
;;
*)
print_status error "Unknown option: $1"
exit 1
;;
esac
done
}
# ----- Functions -----
check_prerequisites() {
print_status info "Checking prerequisites..."
# Check conda
if ! command -v conda &> /dev/null; then
print_status error "conda not found"
return 1
fi
# Check precise environment
if ! conda env list | grep -q "^precise\s"; then
print_status error "Precise environment not found"
print_status info "Run: ./setup_precise.sh first"
return 1
fi
# Check voice-assistant directory
if [[ ! -d "$HOME/voice-assistant" ]]; then
print_status error "Voice assistant not setup"
print_status info "Run: ./setup_voice_assistant.sh first"
return 1
fi
print_status success "Prerequisites OK"
return 0
}
download_pretrained_model() {
print_status info "Downloading pre-trained 'Hey Mycroft' model..."
# Create directory
mkdir -p "$MODELS_DIR"
# Check if already downloaded
if [[ -f "$MODELS_DIR/${MODEL_NAME}.net" ]]; then
print_status info "Model already downloaded"
return 0
fi
# Download
cd "$MODELS_DIR" || return 1
print_status info "Fetching from GitHub..."
wget -q --show-progress "$MODEL_URL" || {
print_status error "Failed to download model"
return 1
}
# Extract
print_status info "Extracting model..."
tar xzf hey-mycroft.tar.gz || {
print_status error "Failed to extract model"
return 1
}
# Verify
if [[ ! -f "${MODEL_NAME}.net" ]]; then
print_status error "Model file not found after extraction"
return 1
fi
print_status success "Model downloaded: $MODELS_DIR/${MODEL_NAME}.net"
return 0
}
test_model() {
print_status info "Testing wake word model..."
cd "$MODELS_DIR" || return 1
# Activate conda
eval "$(conda shell.bash hook)"
conda activate precise || {
print_status error "Failed to activate precise environment"
return 1
}
cat << EOF
${CYAN}═══════════════════════════════════════════════════${NC}
${CYAN} Wake Word Test: "Hey Mycroft"${NC}
${CYAN}═══════════════════════════════════════════════════${NC}
${YELLOW}Instructions:${NC}
1. Speak "Hey Mycroft" into your microphone
2. You should see ${GREEN}"!"${NC} when detected
3. Try other phrases - should ${RED}not${NC} trigger
4. Press ${RED}Ctrl+C${NC} when done testing
${CYAN}Starting in 3 seconds...${NC}
EOF
sleep 3
# Test the model
precise-listen "${MODEL_NAME}.net" || {
print_status error "Model test failed"
return 1
}
print_status success "Model test complete!"
return 0
}
update_config() {
print_status info "Updating voice assistant configuration..."
local config_file="$HOME/voice-assistant/config/.env"
if [[ ! -f "$config_file" ]]; then
print_status error "Config file not found: $config_file"
return 1
fi
# Update PRECISE_MODEL if exists, otherwise add it
if grep -q "^PRECISE_MODEL=" "$config_file"; then
sed -i "s|^PRECISE_MODEL=.*|PRECISE_MODEL=$MODELS_DIR/${MODEL_NAME}.net|" "$config_file"
else
echo "PRECISE_MODEL=$MODELS_DIR/${MODEL_NAME}.net" >> "$config_file"
fi
# Update sensitivity if not set
if ! grep -q "^PRECISE_SENSITIVITY=" "$config_file"; then
echo "PRECISE_SENSITIVITY=0.5" >> "$config_file"
fi
print_status success "Configuration updated"
return 0
}
start_server() {
print_status info "Starting voice assistant server..."
cd "$HOME/voice-assistant" || return 1
# Activate conda
eval "$(conda shell.bash hook)"
conda activate precise || {
print_status error "Failed to activate environment"
return 1
}
cat << EOF
${CYAN}═══════════════════════════════════════════════════${NC}
${GREEN} Starting Voice Assistant Server${NC}
${CYAN}═══════════════════════════════════════════════════${NC}
${YELLOW}Configuration:${NC}
Wake word: ${GREEN}Hey Mycroft${NC}
Model: ${MODEL_NAME}.net
Server: http://0.0.0.0:5000
${YELLOW}What to do next:${NC}
1. Wait for "Precise listening started" message
2. Say ${GREEN}"Hey Mycroft"${NC} to test wake word
3. Say a command like ${GREEN}"turn on the lights"${NC}
4. Check server logs for activity
${YELLOW}Press Ctrl+C to stop the server${NC}
${CYAN}Starting server...${NC}
EOF
# Check if HA token is set
if ! grep -q "^HA_TOKEN=..*" config/.env; then
print_status warning "Home Assistant token not set!"
print_status warning "Commands won't execute without it."
print_status info "Edit config/.env and add your HA token"
echo
read -p "Continue anyway? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
return 1
fi
fi
# Start server
python voice_server.py \
--enable-precise \
--precise-model "$MODELS_DIR/${MODEL_NAME}.net" \
--precise-sensitivity 0.5
return $?
}
create_systemd_service() {
print_status info "Creating systemd service..."
local service_file="/etc/systemd/system/voice-assistant.service"
# Check if we should update existing service
if [[ -f "$service_file" ]]; then
print_status warning "Service file already exists"
read -p "Update with Hey Mycroft configuration? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
return 0
fi
fi
# Create service file
sudo tee "$service_file" > /dev/null << EOF
[Unit]
Description=Voice Assistant with Hey Mycroft Wake Word
After=network.target
[Service]
Type=simple
User=$USER
WorkingDirectory=$HOME/voice-assistant
Environment="PATH=$HOME/miniconda3/envs/precise/bin:/usr/local/bin:/usr/bin:/bin"
EnvironmentFile=$HOME/voice-assistant/config/.env
ExecStart=$HOME/miniconda3/envs/precise/bin/python voice_server.py \\
--enable-precise \\
--precise-model $MODELS_DIR/${MODEL_NAME}.net \\
--precise-sensitivity 0.5
Restart=on-failure
RestartSec=10
StandardOutput=append:$HOME/voice-assistant/logs/voice_assistant.log
StandardError=append:$HOME/voice-assistant/logs/voice_assistant_error.log
[Install]
WantedBy=multi-user.target
EOF
# Reload systemd
sudo systemctl daemon-reload
print_status success "Systemd service created"
cat << EOF
${CYAN}To enable and start the service:${NC}
sudo systemctl enable voice-assistant
sudo systemctl start voice-assistant
sudo systemctl status voice-assistant
${CYAN}To view logs:${NC}
journalctl -u voice-assistant -f
EOF
read -p "Enable service now? (y/N): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
sudo systemctl enable voice-assistant
sudo systemctl start voice-assistant
sleep 2
sudo systemctl status voice-assistant
fi
}
print_next_steps() {
cat << EOF
${GREEN}═══════════════════════════════════════════════════${NC}
${GREEN} Success! Your voice assistant is ready!${NC}
${GREEN}═══════════════════════════════════════════════════${NC}
${CYAN}What you have:${NC}
✓ Pre-trained "Hey Mycroft" wake word
✓ Voice assistant server configured
✓ Ready to control Home Assistant
${CYAN}Quick test:${NC}
1. Say: ${GREEN}"Hey Mycroft"${NC}
2. Say: ${GREEN}"Turn on the living room lights"${NC}
3. Check if command executed
${CYAN}Next steps:${NC}
1. ${YELLOW}Configure Home Assistant entities${NC}
Edit: ~/voice-assistant/config/.env
Add: HA_TOKEN=your_token_here
2. ${YELLOW}Add more entity mappings${NC}
Edit: voice_server.py
Update: IntentParser.ENTITY_MAP
3. ${YELLOW}Fine-tune for your voice (optional)${NC}
cd ~/precise-models/hey-mycroft-custom
./1-record-wake-word.sh
# Record 20-30 samples
precise-train -e 30 hey-mycroft-custom.net . \\
--from-checkpoint $MODELS_DIR/${MODEL_NAME}.net
4. ${YELLOW}Setup Maix Duino${NC}
See: QUICKSTART.md Phase 2
${CYAN}Useful commands:${NC}
# Test wake word only
cd $MODELS_DIR && conda activate precise
precise-listen ${MODEL_NAME}.net
# Check server health
curl http://localhost:5000/health
# Monitor logs
journalctl -u voice-assistant -f
${CYAN}Documentation:${NC}
README.md - Project overview
WAKE_WORD_ADVANCED.md - Multiple wake words guide
QUICKSTART.md - Complete setup guide
${GREEN}Happy voice assisting! 🎙️${NC}
EOF
}
# ----- Main -----
main() {
cat << EOF
${CYAN}═══════════════════════════════════════════════════${NC}
${CYAN} Quick Start: Hey Mycroft Wake Word${NC}
${CYAN}═══════════════════════════════════════════════════${NC}
${YELLOW}This script will:${NC}
1. Download pre-trained "Hey Mycroft" model
2. Test wake word detection
3. Configure voice assistant server
4. Start the server (optional)
${YELLOW}Total time: ~5 minutes (no training!)${NC}
EOF
# Parse arguments
parse_args "$@"
# Check prerequisites
check_prerequisites || exit 1
# Download model
download_pretrained_model || exit 1
# Test model
print_status info "Ready to test wake word"
read -p "Test now? (Y/n): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Nn]$ ]]; then
test_model
fi
# If test-only mode, stop here
if [[ "$TEST_ONLY" == "true" ]]; then
print_status success "Test complete!"
print_status info "Model location: $MODELS_DIR/${MODEL_NAME}.net"
exit 0
fi
# Update configuration
update_config || exit 1
# Start server
read -p "Start voice assistant server now? (Y/n): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Nn]$ ]]; then
start_server
else
# Offer to create systemd service
read -p "Create systemd service instead? (y/N): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
create_systemd_service
fi
fi
# Print next steps
print_next_steps
}
# Run main
main "$@"