ipin-vr/ipin_vr/cli.py
Oskar Kapala 921a85d30b Add export subcommand and Unity PoC-1 scaffold (ONDEVICE §4)
Python (ipin_vr/export.py):
- generate_bank(): levels 1–2 enumerated exhaustively (120/720 combos),
  level 3 random with dedup; all deduplicated per-level
- run_export(): CLI --per-level / --out / --seed flags per ONDEVICE §4.1
- cli.py routes "export" subcommand before session args (backward-compat)
- 14 new tests: format, dedup for all 3 levels, space caps (L1=120, L2=720),
  seed determinism, file output

Unity scaffold (ondevice/Scripts/):
- CommandBank.cs: loads commands.json from StreamingAssets (WebRequest on Android)
- TtsManager.cs: sherpa-onnx integration with [SHERPA] stubs, StreamingAssets→
  persistentDataPath copy, defensive Speak() with onDone callback
- SessionController.cs: passthrough flow §6, level switching, busy guard on Next
- ondevice/README.md: full manual Editor steps §5 (Unity setup, Meta XR SDK,
  sherpa-onnx install, scene wiring, font, build, metrics)

pytest: 37/37 passed

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 16:11:53 +02:00

64 lines
2.2 KiB
Python

import argparse
import random
import sys
import time
from .export import run_export
from .generator import random_command, render
from .llm import llm_command
def main() -> None:
raw = sys.argv[1:]
if raw and raw[0] == "export":
run_export(raw[1:])
return
_run_session()
def _run_session() -> None:
parser = argparse.ArgumentParser(
description="ipin-vr: generator poleceń do terapii afazji"
)
parser.add_argument("--level", type=int, choices=[1, 2, 3], default=1,
metavar="{1,2,3}", help="poziom trudności (domyślnie: 1)")
parser.add_argument("--count", type=int, default=5, metavar="N",
help="liczba poleceń (domyślnie: 5)")
parser.add_argument("--delay", type=float, default=4.0, metavar="S",
help="pauza między poleceniami w sekundach (domyślnie: 4.0)")
parser.add_argument("--voice", metavar="PATH",
help="ścieżka do modelu Piper .onnx")
parser.add_argument("--no-audio", action="store_true",
help="wyłącza TTS")
parser.add_argument("--llm", action="store_true",
help="użyj LLM do wyboru poleceń")
parser.add_argument("--llm-endpoint",
default="http://localhost:8080/v1/chat/completions",
metavar="URL", help="endpoint llama.cpp")
parser.add_argument("--llm-model", default="local", metavar="NAME",
help="nazwa modelu")
parser.add_argument("--seed", type=int, metavar="N",
help="deterministyczny generator losowy")
args = parser.parse_args(sys.argv[1:])
if args.seed is not None:
random.seed(args.seed)
use_audio = (not args.no_audio) and (args.voice is not None)
for i in range(1, args.count + 1):
if args.llm:
cmd = llm_command(args.level, args.llm_endpoint, args.llm_model)
else:
cmd = random_command(args.level)
text = render(cmd)
print(f"{i}. {text}")
if use_audio:
from .tts import speak
speak(text, args.voice)
if i < args.count:
time.sleep(args.delay)