"""Procedurally generated spatial-control decisions (no game data). A controller (camera, turret, drone, UI cursor, robot arm, car) has a centre/aim point; a target is left of it, right of it, on it, or not visible; distractors may sit elsewhere. The model must pick the control whose *description* matches, and answer yes/no probes such as "is the target centred?". Surface forms, units, action names and languages vary so nothing ties it to one domain. """ import json, random OUT = "./data/synth/spatial.jsonl" DOMAINS = [ dict(name="security camera", aim="the centre of the camera view", target=["intruder", "person", "car", "drone"], left="pan left", right="pan right", on="record a close-up", idle="keep scanning (pan left)", keys=("PAN_LEFT", "PAN_RIGHT", "CAPTURE")), dict(name="UI automation agent", aim="the mouse cursor", target=["'Submit' button", "search box", "close icon", "menu item"], left="move the cursor left", right="move the cursor right", on="click", idle="scroll to search (move left)", keys=("CURSOR_LEFT", "CURSOR_RIGHT", "CLICK")), dict(name="delivery drone", aim="the drone's heading", target=["landing pad", "customer", "beacon"], left="yaw left", right="yaw right", on="descend and drop the parcel", idle="rotate left to search", keys=("YAW_LEFT", "YAW_RIGHT", "DROP")), dict(name="robot arm", aim="the gripper", target=["red cube", "bolt", "bottle", "package"], left="rotate the base left", right="rotate the base right", on="close the gripper", idle="rotate left to search", keys=("ROTATE_LEFT", "ROTATE_RIGHT", "GRAB")), dict(name="self-driving car", aim="the car's lane centre", target=["lane centre line", "parking spot", "exit ramp"], left="steer left", right="steer right", on="keep straight and accelerate", idle="steer left to find the lane", keys=("STEER_LEFT", "STEER_RIGHT", "GO_STRAIGHT")), dict(name="telescope", aim="the eyepiece reticle", target=["comet", "Jupiter", "satellite"], left="slew left", right="slew right", on="start the exposure", idle="slew left to search", keys=("SLEW_LEFT", "SLEW_RIGHT", "EXPOSE")), dict(name="sports camera robot", aim="the frame centre", target=["ball", "player 10", "goalkeeper"], left="pan left", right="pan right", on="zoom in", idle="pan left to search", keys=("PAN_LEFT", "PAN_RIGHT", "ZOOM_IN")), dict(name="paintball turret", aim="the sight", target=["red flag", "moving target", "balloon"], left="traverse left", right="traverse right", on="fire", idle="traverse left to search", keys=("TRAVERSE_LEFT", "TRAVERSE_RIGHT", "FIRE")), ] UNITS = [("deg", lambda r: f"{r.randint(3, 120)} degrees"), ("px", lambda r: f"{r.randint(8, 400)} px"), ("cm", lambda r: f"{r.randint(2, 90)} cm"), ("clock", lambda r: None)] AZ = {"left": "solda", "right": "sağda", "on": "tam mərkəzdə", "none": "görünmür"} RU = {"left": "слева", "right": "справа", "on": "точно в центре", "none": "не видно"} def make(rng, dom, lang): kind = rng.choice(["left", "right", "on", "none", "left", "right"]) tgt = rng.choice(dom["target"]) unit, f = rng.choice(UNITS) off = f(rng) if f else None if lang == "en": pos = {"left": f"the {tgt} is to the LEFT of {dom['aim']}" + (f" by {off}" if off else ""), "right": f"the {tgt} is to the RIGHT of {dom['aim']}" + (f" by {off}" if off else ""), "on": f"the {tgt} is exactly on {dom['aim']}", "none": f"no {tgt} is visible"}[kind] elif lang == "az": pos = f"{tgt}: {AZ[kind]}" + (f" ({off})" if off and kind in ("left", "right") else "") else: pos = f"{tgt}: {RU[kind]}" + (f" ({off})" if off and kind in ("left", "right") else "") lines = [f"{dom['name']} status", pos] if rng.random() < 0.6: # a distractor on some other side, marked as not the target side = rng.choice(["left", "right"]) lines.append(f"other object (not the target): {side} side, {rng.randint(5, 90)} units away") if rng.random() < 0.6: hist = [rng.choice(dom["keys"]) for _ in range(rng.randint(1, 4))] lines.append("last actions: " + " ".join(hist)) if rng.random() < 0.5: lines.append(f"battery {rng.randint(5, 100)}% | step {rng.randint(1, 900)}") body = lines[1:]; rng.shuffle(body) state = "\n".join([lines[0]] + body) L, R, O = dom["keys"] crit = {L: f"{dom['left']}: the {'target' if rng.random() < .5 else tgt} is to the LEFT" + (", or it is not visible" if rng.random() < .7 else ""), R: f"{dom['right']}: the {'target' if rng.random() < .5 else tgt} is to the RIGHT", O: f"{dom['on']}: the target is exactly on {dom['aim']}"} if ", or it is not visible" not in crit[L]: crit[L] = crit[L] # 'none' then has no matching option; skip such items below gold_a = {"left": L, "right": R, "on": O, "none": L}[kind] if kind == "none" and ", or it is not visible" not in crit[L]: return [] items = list(crit.items()); rng.shuffle(items) ins = rng.choice(["Which control fits the current situation?", "Pick the action whose description matches the state.", f"What should the {dom['name']} do next?", "Which action is correct now?"]) out = [(state, {"action": {"type": "choice", "instructions": ins, "criteria": dict(items)}}, {"action": gold_a})] probes = [(f"Is the target exactly on {dom['aim']}?", kind == "on"), (f"Is {dom['aim']} empty (the target is not on it)?", kind != "on"), ("Is the target to the left?", kind == "left"), ("Is the target to the right?", kind == "right"), ("Is the target visible?", kind != "none")] pq, pg = rng.choice(probes) out.append((state, {"probe": {"type": "noul", "instructions": pq}}, {"probe": pg})) return out def main(n=9000, seed=0): rng = random.Random(seed) with open(OUT, "w") as fh: k = 0 while k < n: dom = rng.choice(DOMAINS) lang = rng.choices(["en", "az", "ru"], [70, 20, 10])[0] for s, q, g in make(rng, dom, lang): fh.write(json.dumps({"state": s, "questions": q, "gold": g, "meta": {"gen": "spatial", "group": f"s{k // 40}", "lang": lang}}, ensure_ascii=False) + "\n") k += 1 print("wrote", k) if __name__ == "__main__": main()