A personalized daily tech news reader. Users select interest topics and get a curated feed of articles each morning, ranked by how closely they match what the user has been reading.
The project has two independent components:
Scraper (runs everyday ~3 AM using a cron job): Fetches RSS feeds from configured sources, uses Gemini 2.5 Flash Lite to parse raw entries into clean article objects, generates vector embeddings via OpenAI, and stores everything in MongoDB.
Web App: A Flask server that serves a personalized dashboard per user. When the cache is stale (resets daily at 3 AM Pacific), it re-ranks articles from the database using cosine similarity against the user's interest embedding. If the user has opened articles recently, GPT summarizes those into a 1–2 sentence interest description first; otherwise it falls back to their selected topics. That summary will then be used as the query for the vector search of articles that the user will likely be interested in reading.
- Backend: Python, Flask
- Database: MongoDB
- AI: Google
gemini-2.5-flash-lite(article parsing), OpenAItext-embedding-3-small(embeddings), OpenAIgpt-5-nano(interest summarization) - Frontend: Vanilla JS, Tailwind CSS, Lucide icons
- Auth: Werkzeug password hashing, Flask sessions, Flask-WTF CSRF
- Daily article cache that refreshes at 3 AM Pacific (loading screen polls until ready)
- Recommendation engine: cosine similarity between article embeddings and a user interest embedding derived from reading history
- Topic filter sidebar (AI Research, AI Tools, Systems, Web & Frontend, Dev Tools, CS Careers, Startups, Security)
- "Manage Topics" modal — add, remove, and reorder topics with drag-and-drop
- Dark/light mode toggle, persisted in
localStorage - Article click tracking feeds back into interest summarization (up to 20 recent articles kept)
- Hero + card grid layout for articles with images; numbered list for articles without
TechCrunch, MIT Technology Review, IEEE Spectrum, InfoQ, Levels.fyi Blog, Krebs on Security, The Hacker News, Smashing Magazine
pip install -r requirements.txtapp/.env
SECRET_KEY=<flask-secret-key>
DB_URL=<mongodb-connection-string>
OPENAI_API_KEY=<openai-key># used for interest summarization
EMBEDDING=<openai-key># used for generating embeddings (can be same key)scraper/.env
DB_URL=<mongodb-connection-string>
GEMINI_API_KEY=<gemini-key>
OPENAI_API_KEY=<openai-key># used for interest summarization
EMBEDDING=<openai-key># used for generating embeddingsThis clears the existing articles collection and re-populates it.
Run this on a daily schedule (e.g. a cron job) before 3 AM Pacific so fresh articles are available when users' caches
refresh.
cd scraper
python rss.pycd app
flask runThe app will be available at http://localhost:5000.