"""Centralized configuration for the AI Research Oracle. Single source of truth for all paths, defaults, and constants. """ import os from pathlib import Path # ── Paths ────────────────────────────────────────────────────────────────── ROOT = Path(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) DB_PATH = ROOT / "oracle.db" SCHEMA_PATH = ROOT / "schema.sql" # ── Web output ───────────────────────────────────────────────────────────── WEBROOT = "/var/www/preprod2" FALLBACK_WEBROOT = ROOT / "site" SEEN_JSON = ROOT.parent / "ai-oracle-site" / "seen_urls.json" # ── Pipeline defaults ────────────────────────────────────────────────────── ENABLED_SOURCES = ["github", "arxiv", "reddit", "hackernews", "huggingface", "rss"] DEFAULT_LIMIT = 20 # ── Source tiers (World Monitor pattern) ─────────────────────────────────── # Tier 1: Primary trusted sources (official releases, peer-reviewed) # Tier 2: Secondary credible sources (curated communities, major outlets) # Tier 3: Tertiary noise sources (user-generated, unverified) SOURCE_TIERS = { "arxiv": {"tier": 1, "label": "PRIMARY", "description": "Peer-reviewed research"}, "github": {"tier": 1, "label": "PRIMARY", "description": "Official code releases"}, "huggingface": {"tier": 1, "label": "PRIMARY", "description": "Model registry"}, "rss": {"tier": 2, "label": "SECONDARY", "description": "Curated tech media"}, "hackernews": {"tier": 2, "label": "SECONDARY", "description": "Curated community"}, "reddit": {"tier": 3, "label": "TERTIARY", "description": "User-generated discussion"}, } # Tier-based signal score bonus/penalty (applied to final_score) TIER_BONUS = {1: 0.05, 2: 0.0, 3: -0.05} # Freshness SLA per tier (hours after which a source is flagged stale) FRESHNESS_SLA_H = {1: 48, 2: 24, 3: 12} # ── Composite verdict thresholds ─────────────────────────────────────────── # PUBLISH: High score + fresh, goes to top # WATCH: Medium score, monitor for follow-ups # ARCHIVE: Low score or aged out, move to archive # DROP: Junk score, ignore VERDICT_THRESHOLDS = { "PUBLISH": {"min_score": 6.0, "max_age_h": 48}, "WATCH": {"min_score": 4.0, "max_age_h": 168}, # 7 days "ARCHIVE": {"min_score": 2.0, "max_age_h": 720}, # 30 days "DROP": {"min_score": 0.0, "max_age_h": 999999}, # catch-all } # ── Content hash dedup ───────────────────────────────────────────────────── CONTENT_HASH_PREFIX = "sha256" HASH_LENGTH = 16 # characters # ── Clickability weights ─────────────────────────────────────────────────── VEL_W = 0.50 ENG_W = 0.50 SIG_W = 0.0 HALF_LIFE_H = 18.0 # ── Render ───────────────────────────────────────────────────────────────── TOP_N = 8 # ── Archive ──────────────────────────────────────────────────────────────── ARCHIVE_DAYS = 30 ARCHIVE_CAP = 5000