Low-latency voice frontend z rozpoznawaniem lidera (ECAPA / SpeechBrain), transkrypcją (Whisper via Faster-Whisper),
kolejką ZMQ oraz TTS (Piper). Łączy się z lokalnym backendem LLM (watus-ai) przez HTTP. Kamera i jej pliki są obowiązkowe – projekt korzysta z detekcji (Ultralytics RT-DETR/YOLO) i zapisuje kontekst do camera.jsonl.
- Opis
- Wymagania
- Szybki start (TL;DR)
- Instalacja — krok po kroku
- Uruchomienie
- Konfiguracja i parametry
- Scenariusze
- Troubleshooting
- Uwaga o plikach w repo
watus.py– nasłuch audio (PortAudio), VAD (WebRTC), rozpoznawanie mówcy (ECAPA/SpeechBrain), transkrypcja (Faster-Whisper tylko; brak openai-whisper), zapis dodialog.jsonl, PUBdialog.leadertylko dla lidera, SUBtts.speaki odtwarzanie (Piper). Loguje czasy etapów (ASR, I/O) w terminalu.reporter.py– SUBdialog.leader, buduje meldunek (tekst + meta + czas systemowy + scenariusz + ostatnie dane z kamery), POST do backendu LLM (/api1/process_question), PUBtts.speakz odpowiedzią (dla Watusia). Ma retry dla 429/timeout i krótki fallback TTS.camera_runner.py(OBOWIĄZKOWO) – zapisuje docamera.jsonlinformacje o wykrytych obiektach i jasności kadru. Domyślnie pracuje bez podglądu; snapshoty i overlay ogarnia komponent kamerowy (tu integrujemy tylko dane).
Przepływ:
Mic → Watus (VAD + STT + ECAPA) → dialog.jsonl → (leader→ZMQ) → Reporter → HTTP→LLM → (odp) ZMQ→Watus → TTS (Piper)
Kamera (ciągle) → camera.jsonl → kontekst w meldunku Repotera
- Python 3.11+
- Wolne porty: 7780, 7781, 8781 oraz 8000 (LLM).
- Piper (binarka + model ONNX + config) i piper-phonemize (biblioteka fonemizacji).
- Głosy Piper (pl):
- Darkman medium:
https://huggingface.co/rhasspy/piper-voices/tree/main/pl/pl_PL/darkman/medium - Piper releases (binarki):
https://github.com/rhasspy/piper/releases/tag/2023.11.14-2 - piper-phonemize (biblioteki .dll/.so/.dylib):
https://github.com/rhasspy/piper-phonemize/releases/tag/2023.11.14-4
- Darkman medium:
- Głosy Piper (pl):
- Biblioteki systemowe: PortAudio + libsndfile.
- ECAPA (SpeechBrain) – wymagane do weryfikacji mówcy.
- Kamera – obowiązkowa: Ultralytics (RT-DETR/YOLO) + OpenCV + Torch + Torchvision (wg systemu).
git clone https://github.com/misialyna/watus_project.git
cd watus_project python3 -m venv .venv
source .venv/bin/activate python -m venv .venv
.\.venv\Scripts\Activate.ps1 pip install -U pip wheel
pip install -r requirements.txt
cp .env.example .env
# uzupełnij: PIPER_BIN, PIPER_MODEL, PIPER_CONFIG, urządzenia audio, ścieżki kameryW linii 30 w reporter.py zmień ścieżkę absolutną na swoją!
CAMERA_JSONL = os.environ.get("CAMERA_JSONL", "/Users/michalinamoszynska/Documents/GitHub/watus_project/camera.jsonl")
#zmień na własnąścieżkę absolutną
CAMERA_JSONL = os.environ.get("CAMERA_JSONL", "Twoja_sciezka_absolutna.")
Repo:
https://github.com/pasjonatprogramowania/watus-ai
uvicorn src.main:app --host 127.0.0.1 --port 8000 --reloadpython3 reporter.py# kamera – patrz sekcja E
python3 camera_runner.py --jsonl ./camera.jsonl --device 0 --rt 1 # RT-DETR (zalecane)
# lub fallback YOLO:
# python3 camera_runner.py --jsonl ./camera.jsonl --device 0python3 watus.pybrew install portaudio libsndfilesudo apt update
sudo apt install -y libportaudio2 libsndfile1Zwykle nic nie trzeba. Jeśli są błędy z PortAudio – doinstaluj odpowiedni pakiet.
python3 -m venv .venv
source .venv/bin/activatepython -m venv .venv
.\.venv\Scripts\Activate.ps1Plik requirements.txt w repo zawiera wszystko poza torch/torchaudio/torchvision i paczkami kamery:
numpy==1.26.4
sounddevice==0.4.6
soundfile==0.12.1
webrtcvad==2.0.10
faster-whisper==1.0.3
pyzmq==25.1.2
requests==2.32.3
python-dotenv==1.0.1
fastapi==0.112.2
uvicorn==0.30.6
speechbrain==0.5.16Instalacja:
pip install -U pip wheel
pip install -r requirements.txtUwaga: nie instalujemy tu Torcha – zrobimy to świadomie w kolejnym kroku, aby dobrać poprawne koło dla danego systemu (eliminujemy konflikty).
pip install "torch==2.6.*"
# (opcjonalnie) bezpieczny fallback na CPU gdy MPS nie wspiera operacji:
export PYTORCH_ENABLE_MPS_FALLBACK=1 # bash/zsh- ECAPA (SpeechBrain) skorzysta z MPS, Faster-Whisper i tak działa głównie na CPU – to OK.
pip install --index-url https://download.pytorch.org/whl/cpu "torch==2.6.*"pip install --index-url https://download.pytorch.org/whl/cu124 "torch==2.6.*"pip install --index-url https://download.pytorch.org/whl/cpu "torch==2.6.*"Po zainstalowaniu Torch dołóż zgodną wersję torchvision:
pip install "torchvision==0.21.*"pip install --index-url https://download.pytorch.org/whl/cpu "torchvision==0.21.*"pip install --index-url https://download.pytorch.org/whl/cu124 "torchvision==0.21.*"
torchaudionie jest wymagane dla Watus/Reporter/Kamery i często generuje zbędne konflikty (zwłaszcza na macOS). Instaluj tylko, jeśli naprawdę potrzebujesz.
Jeżeli chcesz, by Reporter wzbogacał meldunki o kontekst wizji, kamera musi działać – uruchom camera_runner.py, który dopisuje rekordy JSONL do camera.jsonl.
Zależności kamery (instaluj po Torchu/Torchvision):
pip install "ultralytics==8.3.0" opencv-python-headlessWażne pliki w repo:
camera_runner.py– runner zapisujący docamera.jsonlcamera.jsonl– output JSONL (czytany przezreporter.py)- katalog
oczyWatusia/– kod RT-DETR; wagirtdetr-l.pt(nie commitujemy, pobierz i umieść w tym katalogu) - katalog
oczyWatusia_extracted/– może pojawiać się automatycznie przy pierwszym uruchomieniu; jest w.gitignore
Uruchomienie (przykłady):
# urządzenie 0 (np. wbudowana kamera), fallback YOLO
python3 camera_runner.py --jsonl ./camera.jsonl --device 0
# urządzenie 0, RT-DETR (zalecane – szybsze i dokładniejsze, bez podglądu)
python3 camera_runner.py --jsonl ./camera.jsonl --device 0 --rt 1camera_runner.py działa w tle, bez podglądu. Reporter co ~2.5 s (domyślnie CAMERA_WINDOW_SEC) bierze ostatni wpis.
Skopiuj i uzupełnij:
cp .env.example .envKluczowe pola (dopasuj do swoich ścieżek/urządzeń):
# ==== ZMQ ====
ZMQ_PUB_ADDR=tcp://127.0.0.1:7780
ZMQ_SUB_ADDR=tcp://127.0.0.1:7781
# ==== STT (Faster-Whisper only) ====
ASR_BACKEND=faster
WHISPER_MODEL=small # mapowane w kodzie na guillaumekln/faster-whisper-small
WHISHER_DEVICE=cpu # cuda na Linux/Windows z NVIDIA
WHISPER_COMPUTE_TYPE=int8
WATUS_CPU_THREADS=8
WHISPER_NUM_WORKERS=1
# ==== Audio / VAD ====
WATUS_INPUT_DEVICE=1 # ustaw po numerze z listy urządzeń wypisywanych przez watus.py
WATUS_OUTPUT_DEVICE=2
WATUS_SR=16000
WATUS_BLOCKSIZE=160 # 10 ms @ 16 kHz (niska latencja)
WATUS_VAD_MODE=1
WATUS_VAD_MIN_MS=280
WATUS_SIL_MS_END=650
ASR_MIN_DBFS=-34
WATUS_START_MIN_FRAMES=8
WATUS_START_MIN_DBFS=-30
WATUS_MIN_MS_BEFORE_ENDPOINT=500
END_AT_DBFS_DROP=0
EMIT_COOLDOWN_MS=300
MAX_UTT_MS=6500
WAIT_REPLY_S=0.9
# ==== TTS Piper ====
PIPER_BIN=/absolute/path/to/models/piper/piper
PIPER_MODEL=/absolute/path/to/models/piper/pl_PL-darkman-medium.onnx
PIPER_CONFIG=/absolute/path/to/models/piper/pl_PL-darkman-medium.onnx.json
# ==== LLM HTTP (lokalny backend) ====
LLM_HTTP_URL=http://127.0.0.1:8000/api1/process_question
HTTP_TIMEOUT=20
LLM_HTTP_TIMEOUT=30
# ==== Logi / meta ====
LOG_DIR=./
DIALOG_PATH=dialog.jsonl
# (ECAPA)
SPEAKER_VERIFY=1
SPEAKER_REQUIRE_MATCH=1
# ==== Scenariusze ====
WATUS_SCENARIOS_DIR=./scenarios_text
SCENARIO_ACTIVE_PATH=./scenarios_text/active.jsonl
# ==== Kamera / wizja ====
CAMERA_NAME=cam_front
CAMERA_DEVICE=0
CAMERA_JSONL=./camera.jsonl
VISION_SCORE_THR=0.5
VISION_WRITE_HZ=1.0
VISION_USE_RTDETR=1
RTDETR_DIR=./oczyWatusia
RTDETR_WEIGHTS=./oczyWatusia/rtdetr-l.pt
CAMERA_WINDOW_SEC=2.5
# ==== Wątki BLAS ====
OMP_NUM_THREADS=4
MKL_NUM_THREADS=4
# (macOS) pozwala SpeechBrain spadać na CPU, gdy MPS nie wspiera op
PYTORCH_ENABLE_MPS_FALLBACK=1Binarka Piper
https://github.com/rhasspy/piper/releases/tag/2023.11.14-2
Wypakuj np. do models/piper/ i ustaw PIPER_BIN w .env.
Głos PL („darkman/medium”)
https://huggingface.co/rhasspy/piper-voices/tree/main/pl/pl_PL/darkman/medium
Zapisz .onnx i .onnx.json w models/piper/ i ustaw w .env.
piper-phonemize (biblioteki fonemizacji – wymagane)
https://github.com/rhasspy/piper-phonemize/releases/tag/2023.11.14-4
- macOS: paczka
piper-phonemize-...-macos-...→ skopiuj.dylibdomodels/piper/lubmodels/piper/piper-phonemize/lib/.
Przy błędzie typudyld: Library not loaded: @rpath/libpiper_phonemize...:
brew install onnxruntime re2 # ew. skopiuj podstawowe dylib-y obok binarki piper - Linux: paczka
piper-phonemize-...-linux-...→.soobok binarki albo do/usr/local/lib(+ldconfig), w razie braków:
sudo apt install -y espeak-ng-data libespeak-ng1 libsndfile1
- Windows: paczka
piper-phonemize-...-win-...→piper_phonemize.dllobokpiper.exe(lub dodaj folder doPATH).
https://github.com/pasjonatprogramowania/watus-ai
uvicorn src.main:app --host 127.0.0.1 --port 8000 --reloadpython3 reporter.py
# health: http://127.0.0.1:8781/health# YOLO (fallback)
python3 camera_runner.py --jsonl ./camera.jsonl --device 0
# RT-DETR (zalecane)
python3 camera_runner.py --jsonl ./camera.jsonl --device 0 --rt 1python3 watus.pyWatus loguje: LISTENING / THINKING / SPEAKING / IDLE oraz czasy etapów.
unknown_* → zapis do dialog.jsonl, brak wysyłki do LLM.
leader_* → zapis i wysyłka do LLM (ZMQ → Reporter).
WATUS_BLOCKSIZE=160→ 10 ms @ 16 kHz (niska latencja)WATUS_VAD_MIN_MS=280,WATUS_SIL_MS_END=650→ krótkie, naturalne kończenie turWAIT_REPLY_S=0.9→ po wysyłce pytania czekamy na TTS, nie zbieramy „śmieci”
SPEAKER_VERIFY=1,SPEAKER_REQUIRE_MATCH=1– odpowiadamy tylko liderowi- Progi (w
watus.py/.env) uwzględniają „sticky” tolerancję (emocje/zmęczenie)
LLM_HTTP_URL=http://127.0.0.1:8000/api1/process_question,HTTP_TIMEOUT=20- Reporter dodaje
SYS_TIME/SCENARIO/CAMERA_*(ostatnie okno ~2.5 s)
- Pliki tekstowe w
scenarios_text/(np. persona, styl, ograniczenia). - Aktywny scenariusz wskazuje
SCENARIO_ACTIVE_PATH(domyślniescenarios_text/active.jsonl). - Do szybkiej zmiany skorzystaj z helpera
set_scenario.pyalbo podmień plikactive.jsonl.
- Zajęte porty (7780/7781) – zamknij poprzednie procesy
watus.py/reporter.py. - Brak głosu z Piper / błędy .dll/.so/.dylib – sprawdź instalację piper-phonemize i (na macOS)
onnxruntime+re2.
Upewnij się, że biblioteki leżą obok binarki lub są wDYLD_LIBRARY_PATH/PATH/LD_LIBRARY_PATH. - macOS – torchvision/torchaudio –
torchaudionie jest potrzebny;torchvisionpinuj do0.21.*. - GPU dla kamery (CUDA 12.4) – utrzymuj spójny zestaw
torch==2.6.*+torchvision==0.21.*z indexemcu124. - Ultralytics/RT-DETR – instaluj po Torchu; pin
ultralytics==8.3.0(z tym testowano). - Mikrofon (macOS) –
Settings → Privacy & Security → Microphone(zezwól Terminalowi/IDE). - Wysoka latencja – sprawdź
WATUS_BLOCKSIZE=160,SIL_MS_END≈600–700,WHISPER_COMPUTE_TYPE(int8na CPU /float16na CUDA).
- Modele i binarki (Piper/Whisper/ECAPA/RT-DETR) nie są dołączone – pobierz je linkami i ustaw w
.env. - Logi (
dialog.jsonl,meldunki.jsonl,camera.jsonl) oraz katalogi cache/ekstrakcji (np.oczyWatusia_extracted/) są wykluczone przez.gitignore. - Nie usuwaj katalogu
oczyWatusia/ani placeholderu wagirtdetr-l.pt, jeśli używasz kamery. KatalogoczyWatusia_extracted/może się pojawiać automatycznie – jest ignorowany w Git.
- Wybierz scenariusz (opcjonalnie, ale zalecane)
Scenariusze są w
./scenarios_text/.
Aby ustawić aktywny:
python3 set_scenario.py # interaktywnie
# lub:
python3 set_scenario.py <id> # nazwa pliku bez rozszerzeniaAktywny jest ostatni wpis w scenarios_text/active.jsonl.
3) Uruchom backend LLM (repo watus-ai)
Repo:
https://github.com/pasjonatprogramowania/watus-ai
uvicorn src.main:app --host 127.0.0.1 --port 8000 --reload- Uruchom Reporter (terminal A)
python3 reporter.py
# zdrowie serwisu:
# http://127.0.0.1:8781/health- Uruchom kamerę (terminal B) RT-DETR (zalecane, bez podglądu):
python3 camera_runner.py --jsonl ./camera.jsonl --device 0 --rt 1Fallback YOLO (gdy RT-DETR nie jest gotowy):
python3 camera_runner.py --jsonl ./camera.jsonl --device 0Kamera zapisuje camera.jsonl; reporter.py automatycznie dołącza ostatnie detekcje (okno CAMERA_WINDOW_SEC) do meldunku wysyłanego do LLM.
6) Uruchom Watus (terminal C)
python3 watus.pyNa starcie Watus wypisze listę urządzeń audio. Dopasuj WATUS_INPUT_DEVICE i WATUS_OUTPUT_DEVICE w .env, jeśli trzeba, i uruchom ponownie.
- Poczekaj, aż Watus pokaże w terminalu
[Watus][STATE] LISTENING. - Powiedz krótko do mikrofonu, np. „Hej, WATUSiu” i dokończ zdanie/pytanie naturalnie.
- Pierwsza poprawna wypowiedź enroluje Twój głos jako lidera (ECAPA).
Watus wykona: LISTENING → THINKING → SPEAKING i odtworzy odpowiedź (Piper).
Kolejne wypowiedzi: Watus odpowiada tylko liderowi (SPEAKER_REQUIRE_MATCH=1).
- Głosy innych osób są logowane jako
unknown_*i nie idą do LLM.
- Reporter wypisuje
„MELDUNEK”i pokazuje m.in.[SCENARIO=...], [CAMERA=...], [SPEECH=...]orazUSER: .... - W logu widać też
„HTTP→/HTTP←”i publikacjętts.speak. - Watus po odpowiedzi Piper przechodzi znów w
LISTENING. - W logach są czasy etapów:
ASR_ms=...,TTS_play_ms=..., itp. - Kamera tworzy i dopisuje do
camera.jsonl; wreporter.pyw meldunku pojawia się[VISION=...]z podsumowaniem detekcji.
- Brak odpowiedzi / TTS milczy → sprawdź ścieżki w
.env(PIPER_BIN/MODEL/CONFIG)i bibliotekipiper-phonemize. „Address already in use (7780/7781)”→ zakończ poprzednie watus.py/reporter.py.- Kamera nie startuje → najpierw zainstaluj Torch + Torchvision zgodnie z systemem, potem
ultralytics==8.3.0iopencv-python-headless. - ECAPA wolna lub błąd na macOS → zainstaluj torch==2.6.* (MPS), ustaw
PYTORCH_ENABLE_MPS_FALLBACK=1. - Wysoka latencja → w
.envustawWATUS_BLOCKSIZE=160,WHISPER_COMPUTE_TYPE=int8(CPU) lubWHISPER_DEVICE=cuda + compute float16(GPU).
- LLM → uvicorn ...
- Reporter →
python3 reporter.py
Kamera →python3 camera_runner.py --jsonl ./camera.jsonl --device 0 --rt 1
Watus →python3 watus.py
Zatrzymywanie: Ctrl+C w każdym z terminali.
Logi runtime:dialog.jsonl,meldunki.jsonl,camera.jsonl(ignorowane przez Git).
