"""Local terminal demo for the constrained Ollama RollCalc adapter.""" from __future__ import annotations import argparse from dataclasses import replace import json from conversation_service import ConversationService from ollama_nlu import OllamaConfig, OllamaNLUClient def _arguments() -> argparse.Namespace: parser = argparse.ArgumentParser( description="Constrained local natural-language demo for RollCalc", ) parser.add_argument("--model", help="Override ROLLCALC_OLLAMA_MODEL") parser.add_argument("--url", help="Override ROLLCALC_OLLAMA_URL") parser.add_argument("--timeout", type=float, help="Ollama timeout in seconds") parser.add_argument( "--debug", action="store_true", help="Show raw model JSON, validated interpretation, outcome, and latency", ) return parser.parse_args() def main() -> int: args = _arguments() config = OllamaConfig.from_env() overrides = {} if args.model: overrides["model"] = args.model if args.url: overrides["base_url"] = args.url if args.timeout is not None: overrides["timeout_seconds"] = args.timeout if overrides: config = replace(config, **overrides) service = ConversationService(OllamaNLUClient(config)) conversation_id = service.create_conversation() print( f"RollCalc NLU demo ({config.model}). " "Enter 'exit' or 'quit' to stop." ) while True: try: message = input("> ").strip() except (EOFError, KeyboardInterrupt): print() return 0 if message.casefold() in {"exit", "quit"}: return 0 if not message: continue response = service.handle_message( conversation_id, message, include_diagnostics=args.debug, ) print(response["message"]) if args.debug: debug = { "raw_model_json": response.get("nlu", {}).get("raw_model_json"), "validated_interpretation": response.get("interpretation"), "deterministic_outcome": response.get("result", {}).get("status"), "latency_ms": response.get("nlu", {}).get("latency_ms"), } print(json.dumps(debug, ensure_ascii=False, indent=2)) if __name__ == "__main__": raise SystemExit(main())