mirror of
https://github.com/hanzoai/python-sdk.git
synced 2026-10-23 20:23:00 +00:00
67 lines
2.9 KiB
Python
67 lines
2.9 KiB
Python
"""Act on a yes/no answer only near 0 or 1; send the middle band to review, with the probability on the record."""
|
|
|
|
import gzip
|
|
import json
|
|
import random
|
|
import pathlib
|
|
import tempfile
|
|
import urllib.request
|
|
|
|
from hanzo_kai import Kai, RetryPolicy, UnprocessableEntityError
|
|
|
|
HARNESS = "https://raw.githubusercontent.com/hanzoai/benchmarks/039fbfe5fa5dcb1483407594d829fa822d78974a/decision/results/states.json.gz"
|
|
SUITE, NAME = "app.phishing", "is_phishing"
|
|
|
|
|
|
def harness(suite: str) -> list:
|
|
"""The pinned harness's cases for one suite, each [state, questions, gold]."""
|
|
path = pathlib.Path(tempfile.gettempdir()) / "hanzo-kai-cookbook" / "states.json.gz"
|
|
if not path.exists():
|
|
path.parent.mkdir(parents=True, exist_ok=True)
|
|
urllib.request.urlretrieve(HARNESS, path)
|
|
with gzip.open(path) as file:
|
|
return json.load(file)[suite]
|
|
|
|
|
|
def ask(kai: Kai, email: str, questions: dict) -> float:
|
|
"""P(phishing) for an email; one the API refuses as longer than Kai reads is halved until it fits."""
|
|
while True:
|
|
try:
|
|
return kai.decide(state={"email": email}, questions=questions).nouls[NAME].noul
|
|
except UnprocessableEntityError as error:
|
|
if error.code != "state_too_long":
|
|
raise
|
|
email = email[: len(email) // 2]
|
|
|
|
|
|
def route(p: float, low: float, high: float) -> str:
|
|
"""Where an email goes: automatic at either end of the band, a person in between."""
|
|
return "phishing" if p >= high else "legitimate" if p <= low else "review"
|
|
|
|
|
|
cases = harness(SUITE)
|
|
records = []
|
|
with Kai(retry=RetryPolicy(max_retries=10)) as kai:
|
|
for index in sorted(random.Random(7).sample(range(len(cases)), 80)):
|
|
state, questions, gold = cases[index]
|
|
p = ask(kai, state["email"], questions) # the harness's own question
|
|
records.append({"case": index, "p": p, "route": route(p, 0.1, 0.9), "gold": gold[NAME]["idx"] == 1})
|
|
|
|
print(f"{len(records)} emails, {sum(r['gold'] for r in records)} phishing by gold\n")
|
|
print("P(phishing) emails phishing by gold")
|
|
for low, high in [(0, 0.05), (0.05, 0.2), (0.2, 0.5), (0.5, 0.8), (0.8, 0.95), (0.95, 1.01)]:
|
|
band = [r for r in records if low <= r["p"] < high]
|
|
print(f"[{low:.2f}, {min(high, 1):.2f}{')' if high < 1 else ']'} {len(band):6} {sum(r['gold'] for r in band):16}")
|
|
|
|
print("\nreview band automated right among automated")
|
|
for low, high in [(0.5, 0.5), (0.2, 0.8), (0.1, 0.9), (0.05, 0.95), (0.01, 0.99)]:
|
|
auto = [r for r in records if route(r["p"], low, high) != "review"]
|
|
right = sum((route(r["p"], low, high) == "phishing") == r["gold"] for r in auto)
|
|
band = "none" if low == high else f"({low}, {high})"
|
|
print(f"{band:13} {len(auto):4}/{len(records)} {right:4}/{len(auto)} = {right / len(auto):.3f}")
|
|
|
|
print("\nrecords at (0.1, 0.9) that are wrong or held for review:")
|
|
for r in records:
|
|
if r["route"] == "review" or (r["route"] == "phishing") != r["gold"]:
|
|
print({**r, "p": round(r["p"], 4)})
|