#!/usr/bin/env python3
"""P2Z-G: Process exactly 3 productive queue items with Qwen non-thinking, measuring cost."""
import sqlite3, subprocess, time, json, urllib.request, datetime
def credits():
key = ""
with open("/etc/graphiti/graphiti.env") as f:
for line in f:
if line.startswith("OPENROUTER_API_KEY="):
key = line.split("=", 1)[1].strip()
break
req = urllib.request.Request("https://openrouter.ai/api/v1/credits",
headers={"Authorization": f"Bearer {key}"})
return json.loads(urllib.request.urlopen(req, timeout=30).read())["data"]
k = sqlite3.connect('/opt/struktur/youtube-research/knowledge.db')
now = datetime.datetime.now(datetime.timezone.utc)
# Recover stale processing rows first (they are from pre-patch era)
rows = k.execute("select id, lease_expires_at from graphiti_import_queue "
"where reconciliation_record_id like 'aa043:%' and graphiti_status='processing'").fetchall()
stale = [rid for rid, lease in rows if not lease or datetime.datetime.fromisoformat(lease) < now]
for rid in stale:
k.execute("""update graphiti_import_queue set graphiti_status='lease_expired',
last_error_class='lease_expired', updated_at=CURRENT_TIMESTAMP where id=?""", (rid,))
k.commit()
print(f"Recovered {len(stale)} stale rows")
# Pick 3 oldest lease_expired
targets = [r[0] for r in k.execute(
"select id from graphiti_import_queue where reconciliation_record_id like 'aa043:%' "
"and graphiti_status='lease_expired' order by id limit 3").fetchall()]
print(f"Targets: {targets}")
c0 = credits()
usage0 = c0["total_usage"]
print(f"Usage BEFORE: ${usage0:.6f} | total_usage={usage0}")
results = []
for qid in targets:
t0 = time.time()
r = subprocess.run(['python3', '/opt/struktur/obsidian-graphiti-reconciler-staging/aa043_single_writer.py',
'--queue-id', str(qid)],
capture_output=True, text=True, timeout=900, cwd='/opt/obsidian-vault')
dur = time.time() - t0
out = r.stdout.strip().split('\n')[-1] if r.stdout.strip() else ''
# status after
st, ep = k.execute("select graphiti_status, graphiti_episode_id from graphiti_import_queue where id=?", (qid,)).fetchone()
c1 = credits()
u1 = c1["total_usage"]
cost = u1 - usage0
usage0 = u1
results.append({'qid': qid, 'dur': round(dur,1), 'status': st, 'has_ep': bool(ep),
'rc': r.returncode, 'out': out[:120], 'cost': round(cost,6)})
print(f"\nQueue {qid}: {dur:.1f}s rc={r.returncode} status={st} episode={bool(ep)} cost=${cost:.6f}")
print(f" out: {out[:120]}")
if st != 'done':
print(f" STDERR: {r.stderr.strip()[-300:]}")
break
c_end = credits()
print(f"\nUsage AFTER: ${c_end['total_usage']:.6f}")
ok = [r for r in results if r['status']=='done']
if ok:
avg_cost = sum(r['cost'] for r in ok)/len(ok)
avg_dur = sum(r['dur'] for r in ok)/len(ok)
print(f"Erfolgreiche Writes: {len(ok)}/{len(results)}")
print(f"Ø Kosten/Datei: ${avg_cost:.6f}")
print(f"Ø Dauer/Datei: {avg_dur:.1f}s")
print(f"Durchsatz: {3600/avg_dur:.1f} Dateien/h")
print(json.dumps(results, indent=2))