Images phase 1: attention-triggered og:image coverage

Tie image enrichment to attention (per review): when an article earns a summary
(i.e. a reader reached it), best-effort fetch a real og:image if it lacks one —
never blanket-fetch every ingested article. Adds:

* enrich_article_image() — single-article fetch, leaves existing images alone,
  retries an imageless article only after 7 days, stamps image_checked_at.
* generate_summary() calls it after caching (wrapped; never breaks summaries).
* enrich_summarized_images() + `goodnews enrich-images` CLI — slow background
  backfill of already-summarized, accepted, imageless articles.
* Quality gate: extend the generic-image skip list with data:/tracking-pixel/
  spacer markers (on top of the existing logo/placeholder + unbranded-BBC logic).

This is coverage only; display (editorial rhythm, tile treatment) comes next.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
jay
2026-06-07 12:30:11 -04:00
parent 9813af40ed
commit 403749e26f
4 changed files with 143 additions and 1 deletions
+8
View File
@@ -104,4 +104,12 @@ def generate_summary(conn: sqlite3.Connection, article_id: int, client: LocalMod
(article_id, summary, client.model),
)
conn.commit()
# Attention-triggered image enrichment: a summarized article is one a reader
# has reached, so it's worth a real image. Best-effort — an image fetch
# failure must never break summarization.
try:
from .enrich import enrich_article_image
enrich_article_image(conn, article_id)
except Exception:
pass
return summary