Spaces:
Running
Running
Download intel/events.py from Success-dev/venthrive-api: direct link, hf CLI and curl.
- Browser
- Download file 3.12 kB
-
https://huggingface.co/spaces/Success-dev/venthrive-api/resolve/main/intel/events.py
- Command line
-
hf download hf://spaces/Success-dev/venthrive-api/intel/events.py
-
curl -L -o events.py https://huggingface.co/spaces/Success-dev/venthrive-api/resolve/main/intel/events.py
3.12 kB
| """ | |
| News → permanent event history. The news pipeline (ADR-0015) decides what users | |
| *see* and lets items expire from the feed; this keeps every published item as a | |
| dated, located event because, for the correlation step, past events are the | |
| history — the reason the `threat` value was removed (no value in showing | |
| after-the-fact news) doesn't apply to *learning* from it. | |
| record_news_item() is called from the news pipeline and the admin publish route. | |
| It never raises and is a no-op when the intel store is off (INTEL_DB_PATH unset), | |
| so the deployed backend is unaffected. | |
| """ | |
| from datetime import date, datetime | |
| from intel import db | |
| from intel.locations import resolve | |
| SOURCE_ID = "news_pipeline" | |
| # news categories → event family; identical names except where noted. | |
| CATEGORY_TO_FAMILY = { | |
| "policy": "policy", "weather": "weather", "infrastructure": "infrastructure", | |
| "funding": "funding", "security": "security", "other": "other", | |
| } | |
| def _day(value) -> str | None: | |
| if value is None: | |
| return None | |
| if isinstance(value, (date, datetime)): | |
| return value.date().isoformat() if isinstance(value, datetime) else value.isoformat() | |
| return str(value)[:10] | |
| def record_news_item(item: dict) -> bool: | |
| """item: a news_items-shaped dict (url_hash, title, raw_text, category, | |
| location, published_at, scraped_at, deadline). Returns True if an event was | |
| written. Only published (status 'classified') items should be passed in.""" | |
| if not db.enabled(): | |
| return False | |
| try: | |
| con = db.connect() | |
| try: | |
| location_id = resolve(con, item.get("location")) or resolve(con, item.get("title")) | |
| con.execute( | |
| """insert into events (id, family, type, location_id, starts_on, ends_on, title, detail, | |
| is_estimate, source_id, source_ref, ingested_at) | |
| values (?, ?, 'news', ?, ?, ?, ?, ?, 0, ?, ?, ?) | |
| on conflict (source_id, source_ref) do update set family = excluded.family, | |
| location_id = excluded.location_id, title = excluded.title, detail = excluded.detail""", | |
| ( | |
| f"{SOURCE_ID}:{item['url_hash']}", | |
| CATEGORY_TO_FAMILY.get(item.get("category") or "other", "other"), | |
| location_id, | |
| _day(item.get("published_at")) or _day(item.get("scraped_at")), | |
| _day(item.get("deadline")), | |
| item["title"], | |
| (item.get("raw_text") or "")[:2000] or None, | |
| SOURCE_ID, | |
| item["url_hash"], | |
| db.now_iso(), | |
| ), | |
| ) | |
| con.commit() | |
| from intel.freshness import record_attempt | |
| record_attempt(con, SOURCE_ID, ok=True, latest_data_period=_day(item.get("published_at")) or _day(item.get("scraped_at"))) | |
| return True | |
| finally: | |
| con.close() | |
| except Exception as e: | |
| print(f"[intel] could not record news event {item.get('url_hash')}: {e}") | |
| return False | |