import os
import time
import requests
API = "https://api.zerodrift.ai"
HEADERS = {"x-api-key": os.environ["ZERODRIFT_API_KEY"]}
TERMINAL = {"completed", "done", "failed"}
NEWSLETTER = (
"Dear client,\n\n"
"Our fund guarantees 18% returns with no downside risk.\n\n"
"Sincerely,\nAdvisor"
)
def payload(job: dict) -> dict:
inner = job.get("result")
return inner if isinstance(inner, dict) else job
def confident(value) -> bool:
if isinstance(value, str):
return value == "high"
try:
return float(value) >= 0.85
except (TypeError, ValueError):
return False
def submit(text: str, scenario: str = "scenario_retail_investor_letter") -> str:
r = requests.post(
f"{API}/api/v3/content/validate",
headers=HEADERS,
json={
"content": text,
"model_engine": "anchor_3_0",
"mode": "async",
"document_category": scenario,
},
timeout=30,
)
r.raise_for_status()
return r.json()["poll"]["url"]
def wait(poll_url: str, timeout_s: int = 180) -> dict:
delay, waited = 1.0, 0.0
while waited < timeout_s:
response = requests.get(f"{API}{poll_url}", headers=HEADERS, timeout=10)
response.raise_for_status()
job = response.json()
if job["status"] == "failed":
raise RuntimeError(job.get("error"))
if job["status"] in TERMINAL:
return job
time.sleep(delay)
waited += delay
delay = min(delay * 2, 5.0)
raise TimeoutError(poll_url)
def fix_all(text: str, job: dict) -> tuple[str, list[dict]]:
"""Apply confident line-level replace only. Leave Block and grouped-only findings for review."""
body = payload(job)
items = body.get("violations_by_line") or body.get("violations") or []
if body.get("overall_status") == "do not send":
return text, items or [{"overall_status": "do not send"}]
if not items:
if body.get("overall_status") == "approved":
return text, []
return text, [{"overall_status": body.get("overall_status")}]
needs_review = []
for v in items:
fix = v.get("best_fix") or v.get("fix") or {}
action = fix.get("action") or "replace"
suggested = fix.get("suggested_text")
conf = fix.get("confidence", v.get("confidence"))
if action != "replace" or not suggested or not confident(conf):
needs_review.append(v)
continue
if v.get("line_number"):
lines = text.split("\n")
lines[v["line_number"] - 1] = suggested
text = "\n".join(lines)
else:
quote = v.get("quote") or v.get("line_text") or ""
if quote and quote in text:
text = text.replace(quote, suggested)
else:
needs_review.append(v)
return text, needs_review
poll_url = submit(NEWSLETTER)
job = wait(poll_url)
body = payload(job)
print(body.get("overall_status"), body.get("summary"), body.get("revalidation_recommended"))
fixed, review = fix_all(NEWSLETTER, job)
print(fixed)
print("needs_review:", len(review))
if body.get("revalidation_recommended") and fixed != NEWSLETTER and not review:
recheck = payload(wait(submit(fixed)))
print("revalidation:", recheck.get("overall_status"))