Files
athena-oracle/_live_compare.py
T

180 lines
7.1 KiB
Python

#!/usr/bin/env python3
"""Live re-fetch right now and compare to today's cron snapshot in oracle.db.
Read-only against the DB (only reads). Does NOT store anything."""
import json, math, sys, os, time
sys.path.insert(0, os.path.dirname(__file__))
from datetime import datetime, timezone
import sqlite3
import importlib
SOURCES = ["github", "arxiv", "reddit", "hackernews", "huggingface"]
ADAPTER_CLASSES = {
"github": lambda: importlib.import_module("adapters.github").GitHubAdapter(),
"arxiv": lambda: importlib.import_module("adapters.arxiv").ArxivAdapter(),
"reddit": lambda: importlib.import_module("adapters.reddit").RedditAdapter(),
"hackernews": lambda: importlib.import_module("adapters.hackernews").HackerNewsAdapter(),
"huggingface": lambda: importlib.import_module("adapters.huggingface").HuggingFaceAdapter(),
}
NOW = datetime.now(timezone.utc)
TODAY = NOW.strftime("%Y-%m-%d")
# ---- DB: what cron already pulled today ----
db = sqlite3.connect(os.path.join(os.path.dirname(__file__), "oracle.db"))
db_rows = db.execute(
"select source,source_id,title,url,signal_score,raw_metadata "
"from entries where first_seen >= ?", (TODAY + "T00:00:00",)
).fetchall()
db_by_srcid = {}
for r in db_rows:
src, sid = r[0], r[1]
db_by_srcid.setdefault(src, {})[sid] = r
print(f"[DB today] {len(db_rows)} entries across {len(set(r[0] for r in db_rows))} sources")
# ---- LIVE re-fetch right now ----
live = {} # source -> list of entries
fail = {}
for name in SOURCES:
try:
adapter = ADAPTER_CLASSES[name]()
t0 = time.time()
entries = adapter.fetch(limit=20)
live[name] = entries
print(f"[LIVE] {name:11} {len(entries):2} entries in {time.time()-t0:5.1f}s")
except Exception as e:
fail[name] = str(e)
live[name] = []
print(f"[LIVE] {name:11} FAILED: {e}")
def norm(metric, values):
"""0-100 normalization via log scale for skewed engagement."""
vals = [v for v in values if v is not None and v >= 0]
if not vals:
return {}
mx = max(vals)
out = {}
for k, v in metric.items():
if v is None or v <= 0:
out[k] = 0.0
else:
out[k] = round(100 * math.log(1 + v) / math.log(1 + mx), 1) if mx > 0 else 0.0
return out
# ---- engagement extraction per source ----
def engagement(e):
"""Return (raw_engagement, metrics_dict, virality_0_100) per source."""
src = e["source"]
md = json.loads(e.get("raw_metadata", "{}") or "{}")
if src == "hackernews":
score = md.get("score", 0) or 0
desc = md.get("descendants", 0) or 0
eng = score + desc * 2 # comments weighted as stronger virality signal
metrics = {"points": score, "comments": desc}
elif src == "reddit":
ups = md.get("ups", 0) or 0
comments = md.get("num_comments", 0) or 0
eng = ups + comments * 2
metrics = {"ups": ups, "comments": comments}
elif src == "huggingface":
likes = md.get("likes", 0) or 0
dl = md.get("downloads", 0) or 0
eng = likes * 10 + dl * 0.01 # downloads are huge; down-weight
metrics = {"likes": likes, "downloads": dl}
elif src == "github":
spd = md.get("stars_per_day", 0) or 0
stars = md.get("stars", 0) or 0
eng = spd * 50 + stars * 0.001
metrics = {"stars/day": round(spd, 1), "stars": stars}
elif src == "arxiv":
eng = 0 # no engagement metrics; virality N/A, treat as research signal only
metrics = {"categories": ", ".join(md.get("categories", [])[:3])}
else:
eng = 0
metrics = {}
return eng, metrics
# ---- Build unified compare list ----
unified = []
for src, entries in live.items():
dbset = db_by_srcid.get(src, {})
for e in entries:
sid = e.get("source_id")
eng, metrics = engagement(e)
is_new = sid not in dbset # NEW since cron
unified.append({
"source": src,
"title": e.get("title", "")[:90],
"url": e.get("url", ""),
"signal": e.get("signal_score", 0),
"engagement": eng,
"metrics": metrics,
"new": is_new,
"sid": sid,
})
# ---- Normalize virality across ALL live items (cross-source) ----
all_eng = {u["sid"]: u["engagement"] for u in unified if u["engagement"] > 0}
norm_map = norm({k: v for k, v in all_eng.items()}, list(all_eng.values()))
for u in unified:
u["virality"] = norm_map.get(u["sid"], 0.0)
# ---- RANK by virality (desc), tiebreak signal_score ----
ranked = sorted(unified, key=lambda u: (u["virality"], u["signal"]), reverse=True)
print("\n" + "="*100)
print(f"LIVE PULL @ {NOW.strftime('%Y-%m-%d %H:%M UTC')} | {len(ranked)} items | NEW since cron: {sum(1 for u in unified if u['new'])}")
print("="*100)
# Full list
print("\n### FULL RANKED LIST (by virality)")
for i, u in enumerate(ranked, 1):
tag = "NEW" if u["new"] else " "
m = " ".join(f"{k}={v}" for k, v in u["metrics"].items())
print(f"{i:2}. [{u['virality']:5.1f}] {tag} {u['source']:10} | {u['title']}")
if m:
print(f" {m} (signal {u['signal']:.2f})")
# Trending = NEW items ranked by virality
trending = [u for u in ranked if u["new"]]
print("\n### TRENDING NOW (NEW since today's cron pull, by virality)")
if not trending:
print(" (no new items — live pull matches today's snapshot exactly)")
for i, u in enumerate(trending, 1):
m = " ".join(f"{k}={v}" for k, v in u["metrics"].items())
print(f"{i:2}. [{u['virality']:5.1f}] {u['source']:10} | {u['title']}")
if m: print(f" {m}")
# Source-level engagement summary
print("\n### PER-SOURCE VIRALITY CEILING (top live engagement)")
by_src = {}
for u in unified:
by_src.setdefault(u["source"], []).append(u)
for src in SOURCES:
items = by_src.get(src, [])
if not items:
print(f" {src:11}: (no live data)"); continue
top = max(items, key=lambda x: x["virality"])
print(f" {src:11}: top_virality={top['virality']:.1f} items_live={len(items)} new={sum(1 for x in items if x['new'])}")
db.close()
# ---- Persist full list as markdown (downloadable) ----
import os as _os
out_md = f"# Athena Live Compare — {NOW.strftime('%Y-%m-%d %H:%M UTC')}\n\n"
out_md += f"- **Live pull:** {len(ranked)} items (Reddit excluded — rate-limited)\n"
out_md += f"- **NEW since today's 13:00 UTC cron:** {sum(1 for u in unified if u['new'])}\n"
out_md += f"- **Caveat:** HF scores = cumulative traction, not 24h velocity. Velocity signals = GitHub stars/day, HN points/comments.\n\n"
out_md += "## FULL RANKED LIST (by cross-source virality)\n\n"
out_md += "| # | Virality | New | Source | Title | Key metric | Signal |\n"
out_md += "|---|---|---|---|---|---|---|\n"
for i, u in enumerate(ranked, 1):
tag = "NEW" if u["new"] else ""
m = ", ".join(f"{k}={v}" for k, v in u["metrics"].items())
out_md += f"| {i} | {u['virality']:.1f} | {tag} | {u['source']} | {u['title']} | {m} | {u['signal']:.2f} |\n"
out_path = _os.path.join(_os.path.dirname(__file__), f"live_compare_{NOW.strftime('%Y%m%d_%H%M')}.md")
with open(out_path, "w") as f:
f.write(out_md)
print(f"\n[SAVED] {out_path}")