ipin-vr/docs/SPEC.md

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

  1. Poprawność fleksji jest krytyczna. Wszystkie powierzchniowe formy słów pochodzą wyłącznie z docs/LEXICON.md. Nie wolno generować ani modyfikować odmian.
  2. LLM zwraca tylko identyfikatory, nigdy polski tekst. Tekst składa kod z leksykonu. Dzięki temu mały model nie może zepsuć gramatyki.
  3. Offline. Brak zależności sieciowych w czasie działania poza opcjonalnym, lokalnym serwerem LLM (localhost).
  4. 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:

  1. wyciągnij JSON, sparsuj,
  2. zwaliduj każdy identyfikator względem leksykonu,
  3. 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

  • pytest przechodzi w całości.
  • python -m ipin_vr --level 3 --count 6 --no-audio wypisuje 6 poprawnych poleceń.
  • README zawiera działający szybki start (tryb bez audio) i instrukcje audio/LLM.