Spaces:
Running
Running
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_categorywith 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
Configdataclass - 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
gamingandarab_worldtopics with keyword patterns + domain fallback - Moved
arab_worldaboveworldin priority - Added Gaming and Arab World to CATEGORIES
- Lowered
posts_per_subredditto 2
Date Grouping (recent)
- Added
published_isofield 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
moviesandtunisiatopics 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_subredditto 3 for adequate article counts per category
HOW TO RUN:
- python webapp.py
Media Bias / Factuality + Ownership (current session)
- Expanded
Analysismodel withsource_bias/source_factuality/article_leaningfields _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) andfactuality(high/mixed/low/satire) per source β 42+ outlets mapped _detect_sponsor()returnscategory(Ground News 7-type system) instead of oldtypekey- 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_leaningkept as separate signal (keyword-based, article-specific) vssource_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_biastoarticle_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