File size: 8,866 Bytes
924fd67
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c10d739
 
924fd67
 
c10d739
 
924fd67
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c10d739
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# NewsApp β€” Agent Summary

## Project Structure

```
newsapp/
β”œβ”€β”€ AGENTS.md               ← this file
β”œβ”€β”€ config.py               ← dataclass with all settings (feeds, weights, interests)
β”œβ”€β”€ main.py                 ← entrypoint (CLI or module)
β”œβ”€β”€ requirements.txt
β”œβ”€β”€ webapp.py               ← Flask web server (serves frontend)
β”œβ”€β”€ templates/
β”‚   └── index.html          ← tabbed UI, dynamically generated from categories
β”œβ”€β”€ static/                 ← (empty, reserved for assets)
└── src/
    β”œβ”€β”€ __init__.py
    β”œβ”€β”€ rss_feed_scraper.py ← RSS feed fetcher + article extractor (trafilatura)
    β”œβ”€β”€ models.py           ← NewsItem, Article, Post, Cluster, Analysis dataclasses
    β”œβ”€β”€ analyzer.py         ← NLP: summarisation, topic classification, trust, opinion, leaning
    β”œβ”€β”€ clustering.py       ← similarity-based article clustering + scoring (removed β€” logic in presenter)
    └── presenter.py        ← output formatting (terminal + web JSON)
```

## Current State

### RSS Feeds (42 sources across 9 categories)
- **Geopolitical**: BBC World, NYT World, NYT Politics, NPR, Al Jazeera, The Guardian
- **World Health**: BBC Health, NYT Science, Stat News, Science Daily
- **Tech**: BBC Tech, NYT Tech, TechCrunch, Wired, The Verge, Ars Technica
- **Cybersecurity**: The Hacker News, Krebs on Security, BleepingComputer, Threatpost, The Record
- **Funny/Weird**: The Onion, r/nottheonion, Daily Mash, Babylon Bee
- **Gaming**: IGN, Eurogamer, PC Gamer, Kotaku, Gamespot, Polygon
- **Movies**: Variety, Hollywood Reporter, Deadline, Screen Rant
- **Arab World**: Arab News, Middle East Eye, The New Arab, France24 ME
- **Tunisia**: Tunisia Online News, North Africa Post, Africa News
- `posts_per_subreddit = 3` β†’ ~126 posts total per run

### Topic Detection (keyword-based, word-boundary regex)
- 21 topics tracked: gaming, movies, tunisia, arab_world, AI, climate, health, economy, space, cybersecurity, politics, science, technology, sports, education, immigration, energy, world, funny, weird, onion
- Source-domain fallback: applies only when keyword matching finds zero topics (avoids false positives for off-topic articles from movie/entertainment sites)
- Priority ordering determines which category wins: onion > funny > weird > cybersecurity > gaming > technology > AI > health > science > tunisia > arab_world > world > politics > immigration > economy > energy > education > climate > space > sports > movies

### Categories (9)
Geopolitical | World Health | Tech | Cybersecurity | Funny/Weird | Gaming | Movies | Arab World | Tunisia

### Scoring Model
- `final_score = 0.20*pop + 0.35*trust + 0.30*coverage + 0.15*recency`
- Trust spread 0.05–1.00 based on source reputation, extraction success, article length, factual language, clickbait/opinion penalties
- Clustering: similarity threshold 0.70; articles merge into clusters; cluster gets max(article scores)
- Recency: 1.0 for <1h, decays linearly to 0.0 at 72h

### Web UI
- Flask app at port 5050
- Tabbed interface (dynamically generated from CATEGORIES list)
- Cards with image, topic badge, summary, trust/coverage badges, bias/factuality badges, relevance score bar, date badge, sponsor modal
- Articles grouped by date (date headers in red uppercase) and sorted by relevance within each day
- Article extraction via trafilatura with readability fallback
- NYT blocked (403) β†’ falls back to title-only extraction
- **PressBook News Dark theme**: pure black bg, red accent (#d72924), IBM Plex Serif + Lora fonts
- **Alive animations**: entrance stagger (60ms steps), card hover glow+scale+image zoom, tab sliding underline, status dot pulse, score bar fill on reveal, button hover brightness+scale, counter count-up, scroll-triggered reveal (IntersectionObserver), loading skeleton shimmer

## What We Did

### Category Overhaul (prior to this session)
- Split everything into 5 categories: Geopolitical, World Health, Tech, Cybersecurity, Funny/Weird
- Removed crypto topic; merged funny/weird/onion/sports into Funny/Weird
- Fixed category "bleeding" (NYT World β†’ Geopolitical, not Tech)
- Added subject-based keywords + regex for all topics
- Added source-domain fallback for krebs, bleepingcomputer, theonion
- Priority-based `_map_category` with word-boundary patterns
- Removed fluff tagging; expanded factual/clickbait/opinion signals
- Recency weight reduced from 0.25 to 0.15
- Off-topic detection: penalized AI/space articles in general news feeds
- Rebranded "Health" β†’ "World Health"

### Stability & Config
- Moved all settings to `Config` dataclass
- Reduced feed count, added per-feed error tolerance (continues on failure)
- Removed pointless re-clustering in presenter; now uses clusters from pipeline directly

### Gaming + Arab World (previous session)
- Added 3 gaming feeds and 2 Arab world feeds
- Added `gaming` and `arab_world` topics with keyword patterns + domain fallback
- Moved `arab_world` above `world` in priority
- Added Gaming and Arab World to CATEGORIES
- Lowered `posts_per_subreddit` to 2

### Date Grouping (recent)
- Added `published_iso` field to Article model for reliable date sorting
- Clusters sorted by date (newest first), then by relevance score within each day
- Date headers rendered as indigo uppercase badges above article groups
- Failed date parsing falls back to ISO format parsing for display

### Movies + Tunisia (current session)
- Added 4 movie feeds (Variety, Hollywood Reporter, Deadline, Screen Rant)
- Added 3 Tunisia feeds (Tunisia Online News, North Africa Post, Africa News)
- Added `movies` and `tunisia` topics to TOPIC_MAP with keyword patterns
- Added movie/entertainment and Tunisia domains to DOMAIN_TOPICS
- Changed domain fallback to only trigger when keyword matching finds zero topics (reduces off-topic leakage)
- Movies placed last in priority (acts as catch-all for entertainment sites)
- Tunisia placed above arab_world/world for correct categorization of Tunisia articles
- Added Movies and Tunisia to CATEGORIES (now 9 total)
- Raised `posts_per_subreddit` to 3 for adequate article counts per category
 
 
 ### HOW TO RUN:
 - python webapp.py 

### Media Bias / Factuality + Ownership (current session)
- Expanded `Analysis` model with `source_bias`/`source_factuality`/`article_leaning` fields
- `_detect_article_leaning()` replaces old `_detect_political_leaning()` with a 6-point scale: left, left-center, center, right-center, right, satire (keyword-count-based)
- SPONSOR_INFO now stores `bias` (6-point MBFC-style) and `factuality` (high/mixed/low/satire) per source β€” 42+ outlets mapped
- `_detect_sponsor()` returns `category` (Ground News 7-type system) instead of old `type` key
- Sponsor page (`/sponsors`) shows bias + factuality badges per ownership group
- Article cards show bias + factuality badges next to trust/coverage badges
- Bias/factuality from source assigned to all articles from that source (matching Ground News methodology)
- `article_leaning` kept as separate signal (keyword-based, article-specific) vs `source_bias` (MBFC rating of the outlet)
- Removed orphaned `_detect_political_leaning()` static method
- All new fields exposed in both HTML templates and JSON REST API

### PressBook Dark Theme + Animations (latest session)
- Applied PressBook News Dark theme: pure black bg (#000), red accent (#d72924), dark cards (rgba(12,12,12,0.92)), IBM Plex Serif + Lora fonts, red gradient buttons
- Replaced standalone sponsors page with per-article sponsor modal (owner name, parent, category badge, bias/factuality badges, shareholders, Wikipedia link)
- Removed header link to standalone sponsors page
- Changed card display from `source_bias` to `article_leaning` (keyword-based), with source bias as muted hint when different
- Fixed political leaning algorithm: expanded LEFT_KEYWORDS to 30+ terms, lowered threshold to diff >= 2
- Added sourcing penalty: detects explicit outlet citations ("According to The Guardian"), penalizes score up to 0.12
- Added all "alive" animations:
  - Entrance stagger: cards fade+slide up with 60ms step delay per card
  - Hover: card glow (#d72924 shadow) + scale 1.02 + image zoom 1.05
  - Tab sliding underline: JS-positioned element slides between tabs (300ms cubic-bezier)
  - Status dot pulse: CSS keyframe pulse (scale + box-shadow oscillation, 2s infinite)
  - Score bar fill: animate width from 0 to target via double rAF
  - Button hover brightness (1.2) + scale (1.04), press (0.97)
  - Counter count-up: step-wise increment from 0 to target
  - Scroll reveal: IntersectionObserver with 100ms threshold, reveals cards on scroll
  - Loading skeleton shimmer: CSS gradient shimmer (1.5s infinite), hidden on JS init
- All animation durations in 150-350ms range (snappy), skeletons/shimmer at 1.5s