|
|
|
import json, argparse, uuid
|
|
from pathlib import Path
|
|
|
|
SYS = "You output ONLY JSON, no explanation. Validate against AttackPlan v1.1 semantics."
|
|
|
|
def plan_to_prompt(p):
|
|
|
|
bits=[]
|
|
for it in p.get("plan", [])[:6]:
|
|
op = it.get("op","set"); pt = it.get("point",""); val = it.get("attack_value")
|
|
nm = it.get("name","")
|
|
scope = (it.get("scope") or {})
|
|
area = scope.get("mg"); mim = scope.get("mim")
|
|
s = f"{op} {pt} on {nm} to {val}"
|
|
if mim: s += f" in {mim}"
|
|
if area: s += f" ({area})"
|
|
bits.append(s)
|
|
return "; ".join(bits) if bits else "Generate an AttackPlan JSON v1.1 for no-op."
|
|
|
|
def main():
|
|
ap = argparse.ArgumentParser()
|
|
ap.add_argument("--src", required=True, help="scripts/train_attackplan.aug.jsonl (or filtered)")
|
|
ap.add_argument("--out", default="datasets/chat_attackplan.jsonl")
|
|
args = ap.parse_args()
|
|
|
|
src = Path(args.src).read_text(encoding="utf-8-sig").splitlines()
|
|
out = []
|
|
for ln in src:
|
|
if not ln.strip(): continue
|
|
obj = json.loads(ln)
|
|
prompt = plan_to_prompt(obj)
|
|
out.append({
|
|
"id": str(uuid.uuid4()),
|
|
"messages": [
|
|
{"role":"system","content":SYS},
|
|
{"role":"user","content":f"Task: {prompt}\nReturn ONLY the JSON."},
|
|
{"role":"assistant","content": json.dumps(obj, ensure_ascii=False)}
|
|
]
|
|
})
|
|
Path(args.out).parent.mkdir(parents=True, exist_ok=True)
|
|
Path(args.out).write_text("\n".join(json.dumps(x, ensure_ascii=False) for x in out)+"\n", encoding="utf-8")
|
|
print("[ok] wrote", Path(args.out).resolve(), "rows:", len(out))
|
|
|
|
if __name__ == "__main__":
|
|
main()
|
|
|