5.3 KiB
SPEC — Etap 1 (PC, offline)
Specyfikacja jest wiążącym celem buildu. Implementacja ma być z nią zgodna.
1. Cel i zakres
Generować proste polskie polecenia typu „Połóż jabłko na stole" i opcjonalnie je wypowiadać (Piper TTS). Typ ćwiczenia: wykonywanie poleceń (rozumienie ze słuchu).
W zakresie etapu 1:
- generowanie poleceń (losowo lub przez LLM),
- wypowiadanie ich (TTS, opcjonalne),
- interfejs CLI.
Poza zakresem etapu 1: STT, ocena wykonania, VR/MR, GUI.
2. Zasady naczelne
- Poprawność fleksji jest krytyczna. Wszystkie powierzchniowe formy słów
pochodzą wyłącznie z
docs/LEXICON.md. Nie wolno generować ani modyfikować odmian. - LLM zwraca tylko identyfikatory, nigdy polski tekst. Tekst składa kod z leksykonu. Dzięki temu mały model nie może zepsuć gramatyki.
- Offline. Brak zależności sieciowych w czasie działania poza opcjonalnym, lokalnym serwerem LLM (localhost).
- Defensywność TTS. Brak Pipera lub głosu nie przerywa działania — demo działa wtedy w trybie tekstowym.
3. Stos i układ plików
Python 3.10+. Rdzeń i klient LLM korzystają wyłącznie z biblioteki standardowej
(LLM przez urllib, bez requests). Piper jest opcjonalny.
ipin-vr/
README.md
requirements.txt # tylko opcjonalne: piper-tts; rdzeń = stdlib
.gitignore # venv, __pycache__, *.wav, *.onnx, *.onnx.json
docs/
ipin_vr/
__init__.py
__main__.py # uruchamia cli.main()
lexicon.py # dane z docs/LEXICON.md (przepisane DOKŁADNIE)
generator.py # Clause, Command, render(), random_command()
llm.py # generator oparty na llama.cpp (opcjonalny)
tts.py # Piper przez subprocess (opcjonalny, defensywny)
cli.py # argparse + pętla główna
tests/
test_generator.py
Uruchamianie: python -m ipin_vr [opcje].
4. Model danych
Clause(verb_id, object_id, location_id, color_id: str | None)Command(clauses: list[Clause], level: int)
Identyfikatory muszą istnieć w leksykonie; walidacja przy tworzeniu z danych LLM.
5. Reguły renderowania
Klauzula = Czasownik + (przymiotnik[rodzaj obiektu] + spacja, jeśli kolor) +
obiekt.acc + spacja + miejsce.fraza.
- Czasownik w pierwszej klauzuli pisany wielką literą; w kolejnych — małą.
- Klauzule łączone separatorem
" i ". - Całość zakończona kropką.
- Poziom 1: jedna klauzula, bez koloru.
- Poziom 2: jedna klauzula, z kolorem.
- Poziom 3: dwie klauzule o różnych obiektach; kolor opcjonalny w każdej.
Przykłady poprawnych wyników:
Połóż jabłko na stole.Połóż żółtą piłkę na parapecie.Umieść niebieskie jabłko na stole.Połóż zieloną książkę na półce i umieść klucz na biurku.
6. Generator losowy
random_command(level) losuje czasownik, obiekt, miejsce (oraz kolor zależnie od
poziomu). Dla poziomu 3 gwarantuje różne obiekty w obu klauzulach.
7. Generator LLM (opcjonalny)
Klient POST na endpoint zgodny z OpenAI (/v1/chat/completions,
domyślnie http://localhost:8080/v1/chat/completions).
System prompt wymusza zwrot wyłącznie obiektu JSON:
{"clauses":[{"verb":"<id>","object":"<id>","location":"<id>","color":"<id|null>"}],"level":1}
Przekaż modelowi dozwolone listy identyfikatorów (z leksykonu). Po odebraniu:
- wyciągnij JSON, sparsuj,
- zwaliduj każdy identyfikator względem leksykonu,
- renderuj z leksykonu.
Każdy błąd (timeout, brak serwera, niepoprawny JSON, nieznany identyfikator) ⇒
fallback na random_command(level). Tekst z LLM nigdy nie trafia na wyjście.
8. TTS (opcjonalny, defensywny)
Piper przez subprocess: piper --model <onnx> --output_file <wav>, tekst na stdin.
Odtwarzanie zależnie od OS: aplay (Linux), afplay (macOS), winsound (Windows).
Brak Pipera/głosu/odtwarzacza ⇒ wypisz [TTS off: <powód>] i kontynuuj.
9. CLI
| Flaga | Domyślnie | Opis |
|---|---|---|
--level {1,2,3} |
1 | poziom trudności |
--count N |
5 | liczba poleceń |
--delay S |
4.0 | pauza między poleceniami (s) |
--voice PATH |
— | ścieżka do modelu Piper .onnx |
--no-audio |
— | wyłącza TTS |
--llm |
— | użyj LLM do wyboru poleceń |
--llm-endpoint URL |
localhost:8080 | endpoint llama.cpp |
--llm-model NAME |
local |
nazwa modelu |
--seed N |
— | deterministyczny losowy generator |
Każde polecenie wypisywane na stdout (numerowane) i — jeśli włączone audio — wypowiadane.
10. Testy (pytest)
tests/test_generator.py sprawdza render() dla ustalonych speców względem
oczekiwanych stringów. Pokrycie obowiązkowe:
- kolor + rzeczownik dla każdego rodzaju (m, f, n),
- poprawny miejscownik miejsca,
- łączenie dwóch klauzul (poziom 3),
- kapitalizacja: pierwsza klauzula wielką, druga małą literą.
11. Zależności
Rdzeń, generator i klient LLM: tylko biblioteka standardowa. requirements.txt
zawiera jedynie opcjonalne piper-tts. README opisuje pobranie głosu polskiego.
12. Definition of done
pytestprzechodzi w całości.python -m ipin_vr --level 3 --count 6 --no-audiowypisuje 6 poprawnych poleceń.- README zawiera działający szybki start (tryb bez audio) i instrukcje audio/LLM.