mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-09-23 16:42:21 +02:00
164 lines
6.1 KiB
Python
164 lines
6.1 KiB
Python
#!/usr/bin/env python3
|
|
"""Semantically review expansion runs and retain only independently approved sessions."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import json
|
|
import subprocess
|
|
import sys
|
|
import tempfile
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
import httpx
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
TRACE_DIR = ROOT / "data" / "sft_traces"
|
|
|
|
|
|
def atomic_json(path: Path, payload: Any) -> None:
|
|
path.parent.mkdir(parents=True, exist_ok=True)
|
|
with tempfile.NamedTemporaryFile("w", encoding="utf-8", dir=path.parent, delete=False) as handle:
|
|
json.dump(payload, handle, ensure_ascii=False, indent=2)
|
|
handle.write("\n")
|
|
temp = Path(handle.name)
|
|
temp.replace(path)
|
|
|
|
|
|
def trace_rows(owner: str, session_ids: set[str]) -> list[dict[str, Any]]:
|
|
path = TRACE_DIR / f"{owner}.jsonl"
|
|
if not path.exists():
|
|
return []
|
|
rows = []
|
|
for raw in path.read_text(encoding="utf-8").splitlines():
|
|
if raw.strip():
|
|
row = json.loads(raw)
|
|
if str(row.get("session_id") or "") in session_ids:
|
|
rows.append(row)
|
|
return rows
|
|
|
|
|
|
def remove_trace_sessions(owner: str, session_ids: set[str]) -> int:
|
|
path = TRACE_DIR / f"{owner}.jsonl"
|
|
if not path.exists() or not session_ids:
|
|
return 0
|
|
kept: list[str] = []
|
|
removed = 0
|
|
for raw in path.read_text(encoding="utf-8").splitlines():
|
|
if not raw.strip():
|
|
continue
|
|
row = json.loads(raw)
|
|
if str(row.get("session_id") or "") in session_ids:
|
|
removed += 1
|
|
else:
|
|
kept.append(json.dumps(row, ensure_ascii=False))
|
|
with tempfile.NamedTemporaryFile("w", encoding="utf-8", dir=path.parent, delete=False) as handle:
|
|
handle.write("\n".join(kept) + ("\n" if kept else ""))
|
|
temp = Path(handle.name)
|
|
temp.replace(path)
|
|
return removed
|
|
|
|
|
|
def delete_live_sessions(base_url: str, password: str, by_owner: dict[str, set[str]]) -> None:
|
|
for owner, session_ids in by_owner.items():
|
|
with httpx.Client() as client:
|
|
response = client.post(
|
|
base_url.rstrip("/") + "/api/auth/login",
|
|
json={"username": owner, "password": password, "remember": True},
|
|
timeout=30,
|
|
)
|
|
response.raise_for_status()
|
|
for session_id in session_ids:
|
|
response = client.delete(
|
|
base_url.rstrip("/") + f"/api/session/{session_id}", timeout=30
|
|
)
|
|
response.raise_for_status()
|
|
|
|
|
|
def main() -> None:
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
parser.add_argument("--run", type=Path, required=True)
|
|
parser.add_argument("--out", type=Path, required=True)
|
|
parser.add_argument("--base-url", default="http://127.0.0.1:7011")
|
|
parser.add_argument("--password", default="SftDemo!2026")
|
|
parser.add_argument("--min-score", type=int, default=80)
|
|
parser.add_argument("--endpoint-id")
|
|
args = parser.parse_args()
|
|
|
|
results = json.loads(args.run.read_text(encoding="utf-8")).get("results", [])
|
|
candidates = [row for row in results if row.get("pass") is True and row.get("session_id")]
|
|
owner_by_session = {str(row["session_id"]): str(row["owner"]) for row in candidates}
|
|
review_rows: list[dict[str, Any]] = []
|
|
for owner in sorted(set(owner_by_session.values())):
|
|
ids = {sid for sid, candidate_owner in owner_by_session.items() if candidate_owner == owner}
|
|
review_rows.extend(trace_rows(owner, ids))
|
|
if not review_rows:
|
|
atomic_json(args.out, {"reviewed": 0, "kept": 0, "rejected": 0, "results": []})
|
|
return
|
|
|
|
args.out.parent.mkdir(parents=True, exist_ok=True)
|
|
review_trace = args.out.with_suffix(".review.jsonl")
|
|
review_trace.write_text(
|
|
"\n".join(json.dumps(row, ensure_ascii=False) for row in review_rows) + "\n",
|
|
encoding="utf-8",
|
|
)
|
|
command = [
|
|
sys.executable,
|
|
str(ROOT / "scripts" / "audit_sft_corpus_with_deepseek.py"),
|
|
"--trace", str(review_trace),
|
|
"--all-sessions", "--workers", "1", "--batch-size", "1",
|
|
]
|
|
if args.endpoint_id:
|
|
command.extend(["--endpoint-id", args.endpoint_id])
|
|
completed = subprocess.run(command, cwd=ROOT, text=True, capture_output=True, check=True)
|
|
output_line = next(
|
|
line for line in reversed(completed.stdout.splitlines()) if line.startswith("output=")
|
|
)
|
|
audit_dir = Path(output_line.split("=", 1)[1])
|
|
verdicts = [
|
|
json.loads(line)
|
|
for line in (audit_dir / "deepseek_verdicts.jsonl").read_text(encoding="utf-8").splitlines()
|
|
if line.strip()
|
|
]
|
|
verdict_by_session = {str(row["session_id"]): row for row in verdicts}
|
|
rejected = {
|
|
sid for sid in owner_by_session
|
|
if sid not in verdict_by_session
|
|
or verdict_by_session[sid].get("verdict") != "keep"
|
|
or int(verdict_by_session[sid].get("score") or 0) < args.min_score
|
|
}
|
|
rejected_by_owner: dict[str, set[str]] = {}
|
|
for sid in rejected:
|
|
rejected_by_owner.setdefault(owner_by_session[sid], set()).add(sid)
|
|
if rejected_by_owner:
|
|
delete_live_sessions(args.base_url, args.password, rejected_by_owner)
|
|
for owner, session_ids in rejected_by_owner.items():
|
|
remove_trace_sessions(owner, session_ids)
|
|
for result in results:
|
|
if str(result.get("session_id") or "") in rejected:
|
|
result["pass"] = False
|
|
result.setdefault("failures", []).append("semantic_review_rejected")
|
|
atomic_json(args.run, {"results": results})
|
|
|
|
report = {
|
|
"reviewed": len(owner_by_session),
|
|
"kept": len(owner_by_session) - len(rejected),
|
|
"rejected": len(rejected),
|
|
"audit_dir": str(audit_dir),
|
|
"results": [
|
|
{
|
|
**row,
|
|
"owner": owner_by_session.get(str(row.get("session_id") or "")),
|
|
"retained": str(row.get("session_id") or "") not in rejected,
|
|
}
|
|
for row in verdicts
|
|
],
|
|
}
|
|
atomic_json(args.out, report)
|
|
print(json.dumps({key: report[key] for key in ("reviewed", "kept", "rejected")}, indent=2))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|