Alexa słucha 24/7 i wysyła nagrania na serwery Amazon. Google Home robi to samo dla Alphabet. Każde Twoje „OK Google" trafia do chmury, jest analizowane, profilowane i może być odsłuchane przez pracowników.
Rozwiązanie: własny asystent głosowy działający całkowicie offline, na Raspberry Pi 4, który rozumie polecenia i odpowiada naturalnym głosem – bez żadnego połączenia z internetem.
| Element | Rekomendacja | Cena |
|---|---|---|
| Komputer | Raspberry Pi 4 8 GB RAM (min. 4 GB) | ~420 zł |
| Karta pamięci | microSD 32 GB lub SSD USB 3.0 | ~50 zł |
| Mikrofon | Mikrofon USB (np. Fifine K053 lub ReSpeaker 2-Mic HAT) | ~50–130 zł |
| Głośnik | Aktywny głośnik 3.5 mm lub Bluetooth | ~30–80 zł |
| Zasilacz | Pi 4 USB-C 3A | ~60 zł |
Łącznie: ok. 610–740 zł jednorazowo (brak abonamentów).
# Raspberry Pi OS Lite (64-bit) – zalecane
# Po flashowaniu i SSH:
sudo apt update && sudo apt upgrade -y
sudo apt install -y python3-pip python3-venv portaudio19-dev \
alsa-utils ffmpeg git libffi-dev
# Test mikrofonu
arecord -l # wyświetl urządzenia
arecord -D plughw:1,0 -f S16_LE -r 16000 -c 1 test.wav
aplay test.wav
curl -fsSL https://ollama.com/install.sh | sh
# Pobierz lekki model (Llama 3.2:3b – 2.0 GB)
ollama pull llama3.2:3b
# Test modelu
ollama run llama3.2:3b "Odpowiedz krótko po polsku: co to jest Arduino?"
tinyllama:1.1b (637 MB). Na Pi 4 z 8 GB możesz wygodnie używać llama3.2:3b.cd ~
wget https://github.com/rhasspy/piper/releases/download/2023.11.14-2/piper_arm64.tar.gz
tar xzf piper_arm64.tar.gz
# Pobierz głos polski (Gosia)
mkdir -p ~/piper-voices
wget -P ~/piper-voices \
https://huggingface.co/rhasspy/piper-voices/resolve/main/pl/pl_PL/gosia/medium/pl_PL-gosia-medium.onnx \
https://huggingface.co/rhasspy/piper-voices/resolve/main/pl/pl_PL/gosia/medium/pl_PL-gosia-medium.onnx.json
# Test głosu
echo "Cześć, jestem Twoim asystentem." | \
./piper/piper --model ~/piper-voices/pl_PL-gosia-medium.onnx --output_file /tmp/test.wav
aplay /tmp/test.wav
python3 -m venv ~/asystent
source ~/asystent/bin/activate
pip install openai-whisper sounddevice numpy
pip install openwakeword pyaudio
cat > ~/asystent/asystent.py << 'EOF'
import io, os, subprocess, tempfile, time, threading
import numpy as np
import sounddevice as sd
import whisper
import requests
from openwakeword.model import Model
# ── Konfiguracja ──────────────────────────────────────────
WAKE_WORD_MODEL = "hey_mycroft" # najbliższe "Hej Komputer"
WHISPER_MODEL = "small" # tiny/base/small/medium
OLLAMA_MODEL = "llama3.2:3b"
PIPER_BIN = os.path.expanduser("~/piper/piper")
PIPER_MODEL = os.path.expanduser("~/piper-voices/pl_PL-gosia-medium.onnx")
SAMPLE_RATE = 16000
CHUNK = 1280 # 80 ms przy 16 kHz
# System prompt po polsku
SYSTEM_PROMPT = """Jesteś pomocnym asystentem domowym.
Odpowiadaj KRÓTKO (1-3 zdania), po polsku.
Nie używaj emoji ani markdown."""
# ── Inicjalizacja ─────────────────────────────────────────
print("Ładuję modele…")
oww = Model(wakeword_models=[WAKE_WORD_MODEL], inference_framework="onnx")
asr = whisper.load_model(WHISPER_MODEL)
print("Gotowy! Powiedz 'Hej Mycroft' aby aktywować.")
def nagraj_polecenie(sek=5) -> np.ndarray:
"""Nagrywa audio przez 'sek' sekund po aktywacji."""
print("🎙 Słucham…")
audio = sd.rec(int(sek * SAMPLE_RATE), samplerate=SAMPLE_RATE,
channels=1, dtype="float32")
sd.wait()
return audio.flatten()
def transkrybuj(audio: np.ndarray) -> str:
wynik = asr.transcribe(audio, language="pl", fp16=False)
return wynik["text"].strip()
def zapytaj_llm(tekst: str) -> str:
r = requests.post("http://localhost:11434/api/generate", json={
"model": OLLAMA_MODEL,
"prompt": tekst,
"system": SYSTEM_PROMPT,
"stream": False,
}, timeout=60)
return r.json().get("response", "Przepraszam, nie rozumiem.").strip()
def synteza_i_odtwarzanie(tekst: str):
with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as f:
wav_path = f.name
subprocess.run([PIPER_BIN, "--model", PIPER_MODEL,
"--output_file", wav_path],
input=tekst.encode(), capture_output=True)
subprocess.run(["aplay", "-q", wav_path])
os.unlink(wav_path)
# ── Główna pętla ──────────────────────────────────────────
buffer = np.zeros(CHUNK * 30, dtype=np.float32)
def callback(indata, frames, time_info, status):
global buffer
buffer = np.roll(buffer, -frames)
buffer[-frames:] = indata[:, 0]
prediction = oww.predict(buffer[-CHUNK:])
if prediction.get(WAKE_WORD_MODEL, 0) > 0.5:
threading.Thread(target=obsluz_polecenie, daemon=True).start()
aktywny = False
def obsluz_polecenie():
global aktywny
if aktywny:
return
aktywny = True
synteza_i_odtwarzanie("Słucham.")
audio = nagraj_polecenie(5)
pytanie = transkrybuj(audio)
print(f"Pytanie: {pytanie}")
if pytanie:
odpowiedz = zapytaj_llm(pytanie)
print(f"Odpowiedź: {odpowiedz}")
synteza_i_odtwarzanie(odpowiedz)
aktywny = False
with sd.InputStream(callback=callback, channels=1, samplerate=SAMPLE_RATE,
blocksize=CHUNK, dtype="float32"):
while True:
time.sleep(0.1)
EOF
source ~/asystent/bin/activate
python ~/asystent/asystent.py
sudo nano /etc/systemd/system/asystent.service
[Unit]
Description=Asystent głosowy AI
After=network.target ollama.service
[Service]
User=pi
WorkingDirectory=/home/pi
ExecStart=/home/pi/asystent/bin/python /home/pi/asystent/asystent.py
Restart=always
RestartSec=5
Environment=PYTHONUNBUFFERED=1
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable asystent
sudo systemctl start asystent
sudo journalctl -u asystent -f # podgląd logów
| Etap | Pi 4 (4 GB) | Pi 4 (8 GB) | Pi 5 (8 GB) |
|---|---|---|---|
| Wake word (latencja) | <100 ms | <100 ms | <100 ms |
| Whisper small (5 sek.) | ~8 sek. | ~8 sek. | ~4 sek. |
| Ollama tinyllama (odpowiedź) | ~6 sek. | ~4 sek. | ~2 sek. |
| Piper TTS | <1 sek. | <1 sek. | <0.5 sek. |
| Łączny czas odpowiedzi | ~15 sek. | ~13 sek. | ~7 sek. |
whisper tiny zamiast small aby skrócić transkrypcję o połowę kosztem niewielkiej dokładności.Ten projekt kosztuje jednorazowo ~650 zł i zapewnia pełną prywatność. Żaden gigant technologiczny nie dowie się, co pytasz swojego asystenta.