"""2. Reader + router: what is asked, and how the extracted values fit together. PLACEHOLDER: keyword rules standing in for the TinyLLM, which will read the same marked text and return the same choices once it is trained. read("A car at brakes at . How long until it stops?") -> {"target": "t", "order": ("u",), "sign": -1, "u0": False, "v0": True, "a_source": None} Returns None when the question isn't one it can answer. """ import re # what is asked, by priority: the first cue found picks the target TARGET_CUES = { "s": r"how far|distance|how much (slip )?road", "t": r"how long|\btime\b", "v": r"how fast|\bspeed\b", "F": r"\bforce\b", "a": r"how hard|acceleration|deceleration", } OFF_TOPIC = r"\b(fuel|engine|legal|tyres?|insurance|poem|gear)\b" REST = r"from (rest|a standstill|stationary)|pulls? away" STOP = r"\bstop|stationary|\bahead\b" # "a dog 30 m ahead": stop before it BRAKE = r"\bbrak|\bstop|decel" CONSTANT = r"constant|cruis|steady" FINAL = r"(\bto|reach\w*) " # a lone speed that is where the car ends up SURFACE_DECEL = {"icy": 2.0, "wet": 5.0, "dry": 7.5} # typical braking on each road, m/s² SURFACE_CUES = {"icy": r"\bic[ey]|snow", "wet": r"rain|\bwet\b"} def read(marked): text = marked.lower() words = re.sub(r"<\w+>", "#", text) # cues are words, never the value markers ("