A library for generating F1 blog posts from RSS feeds using AI
Project description
F1 Blog Pipeline
A Python library for generating F1 blog posts from RSS feeds using AI. Automatically extracts articles from F1 news sources and generates comprehensive blog posts using Google's Gemini API.
Features
- ๐ฐ RSS Feed Parsing with date filtering support
- ๐ค AI-Powered Blog Generation using Gemini API
- ๐ Web Scraping with Playwright for full article extraction
- ๐ Flexible Date Filtering (today, yesterday, specific dates, date ranges)
- ๐ง Library-First Design - use programmatically in your applications
- โ๏ธ Configurable feeds, extraction settings, and generation parameters
- ๐ก๏ธ Robust Error Handling with partial results on failures
Installation
Basic Installation
# Clone the repository
git clone https://github.com/yourusername/f1-blog-pipeline.git
cd f1-blog-pipeline
# Install dependencies
pip install -r requirements.txt
# Install Playwright browsers
playwright install chromium
Development Installation
# Install in editable mode
pip install -e .
Quick Start
from f1_blog_pipeline import F1BlogPipeline
# Initialize pipeline with API key
pipeline = F1BlogPipeline(api_key='your-gemini-api-key')
# Run full pipeline
result = pipeline.run_full_pipeline(filter_date='today')
# Check results
if result.success:
print(f"Extracted {result.articles_extracted} articles")
print(f"Blog: {len(result.blog_content)} characters")
Configuration
Environment Variables
Create a .env file (optional):
# Required
GEMINI_API_KEY=your_gemini_api_key_here
# Optional
GEMINI_MODEL=gemini-2.0-flash
Note: The library does NOT load .env files automatically. Your application is responsible for credential management (use python-dotenv or your own config system).
Security: Never commit .env files to version control. The .env file is in .gitignore by default. Always use .env for local development and CI/CD secrets management for production deployments.
Custom Feeds
custom_feeds = {
"Autosport": "https://www.autosport.com/rss/feed/f1",
"The Race": "https://www.the-race.com/feed/",
"RaceFans": "https://www.racefans.net/feed/"
}
pipeline = F1BlogPipeline(
api_key='your-key',
feeds=custom_feeds,
max_per_feed=10
)
Configuration File
Copy config.yaml.example to config.yaml and customize:
feeds:
Autosport: "https://www.autosport.com/rss/feed/f1"
Motorsport: "https://www.motorsport.com/rss/f1/news"
extraction:
max_per_feed: 5
timeout: 30
delay: 2
generation:
model: "gemini-2.0-flash"
temperature: 0.7
Usage
Basic Pipeline
from f1_blog_pipeline import F1BlogPipeline
# Initialize
pipeline = F1BlogPipeline(api_key='your-key')
# Run full pipeline
result = pipeline.run_full_pipeline(filter_date='today')
# Access results
print(result.success) # True/False
print(result.articles_extracted) # Number of articles
print(result.blog_content) # Generated blog markdown
print(result.errors) # List of errors if any
Individual Stages
# Just extract articles
articles = pipeline.extract_articles(filter_date='today')
# Generate blog from existing articles
blog = pipeline.generate_blog(articles, author='Your Name')
Custom Configuration
import logging
pipeline = F1BlogPipeline(
api_key='your-key',
feeds={'Source': 'https://...'},
max_per_feed=10,
timeout=45000,
delay=3,
model='gemini-2.0-pro',
temperature=0.8,
max_tokens=8000,
output_dir='./output',
logger_level=logging.DEBUG
)
Credential Management
The library is designed to work with any credential management strategy:
# Option 1: Pass API key directly
pipeline = F1BlogPipeline(api_key='sk-...')
# Option 2: Use environment variable (your app sets it)
import os
os.environ['GEMINI_API_KEY'] = get_key_from_your_config()
pipeline = F1BlogPipeline() # Falls back to env var
# Option 3: Load from .env in your app (library doesn't do this)
from dotenv import load_dotenv
load_dotenv() # YOUR responsibility, not library's
pipeline = F1BlogPipeline()
Date Filtering
# Today's articles only
result = pipeline.run_full_pipeline(filter_date='today')
# Yesterday
result = pipeline.run_full_pipeline(filter_date='yesterday')
# Specific date
result = pipeline.run_full_pipeline(filter_date='2026-02-22')
# Last N days
result = pipeline.run_full_pipeline(days_back=7)
# No filter (latest articles per feed)
result = pipeline.run_full_pipeline()
Examples
See the examples/ directory for detailed usage examples:
basic_usage.py- Basic library usagecustom_feeds.py- Custom RSS feedsdate_range.py- Date filtering examples
Output Formats
Extracted Articles
The pipeline saves extracted articles to articles/extracted_articles.txt in this format:
================================================================================
Source: Autosport
Title: Hamilton explains Mercedes 2026 strategy shift
Authors: ['Scott Mitchell-Malm']
URL: https://www.autosport.com/f1/news/...
[Full article text content with proper formatting and paragraphs...]
================================================================================
Source: Motorsport
Title: Red Bull confirms major technical update for Bahrain
...
Generated Blog Post
The pipeline generates a markdown blog post with YAML frontmatter:
---
title: "2026 Testing Unpacked: Regulation Chaos and Team Performance"
date: 2026-02-22
author: "Adrian"
tags: [f1, testing, 2026-season, bahrain, ferrari, mercedes, red-bull]
summary: "Welcome to the 2026 era. If pre-season testing in Bahrain..."
---
# 2026 Testing Unpacked: Regulation Chaos and Team Performance
Welcome to the 2026 era. If pre-season testing in Bahrain has taught us anything...
## Team Performance Analysis
**Mercedes** emerged as the early pace-setters:
- Russell topped FP1 with a 1:31.247
- New power unit showing promising reliability
- Aerodynamic package generating consistent downforce
**Ferrari** showed mixed results:
- Leclerc struggled with rear stability in high-speed corners
- Team working on suspension geometry adjustments
- Power unit performance on par with expectations
## Technical Updates
The new 2026 regulations have forced teams to rethink...
Project Structure
f1_app/
โโโ f1_blog_pipeline/ # Main library package
โ โโโ __init__.py # Public API
โ โโโ pipeline.py # Pipeline orchestrator
โ โโโ core/ # Core modules
โ โ โโโ rss_parser.py # RSS feed parsing with date filtering
โ โ โโโ article_extractor.py # Article extraction
โ โ โโโ blog_generator.py # AI blog generation
โ โ โโโ text_cleaner.py # Text cleaning utilities
โโโ examples/ # Usage examples
โโโ articles/ # Extracted articles (generated)
โโโ posts/ # Generated blog posts (generated)
โโโ requirements.txt # Dependencies
โโโ pyproject.toml # Package configuration
โโโ config.yaml.example # Example configuration
โโโ README.md # This file
API Reference
F1BlogPipeline
Main pipeline class for orchestrating the entire workflow.
class F1BlogPipeline:
def __init__(
api_key: Optional[str] = None,
feeds: Optional[Dict[str, str]] = None,
max_per_feed: int = 5,
timeout: int = 30000,
delay: int = 2,
model: str = "gemini-2.0-flash",
temperature: float = 0.7,
max_tokens: int = 4000,
output_dir: Optional[str] = None,
logger_level: Optional[int] = None
)
PipelineResult
Result object returned by pipeline execution.
@dataclass
class PipelineResult:
success: bool # Overall success
articles_extracted: int # Number of articles
articles: List[Dict[str, Any]] # Extracted articles
blog_content: Optional[str] # Generated blog
errors: List[Dict[str, str]] # Errors
warnings: List[str] # Warnings
Advanced Usage
Batch Processing
Generate blog posts for multiple dates:
from datetime import datetime, timedelta
from f1_blog_pipeline import F1BlogPipeline
pipeline = F1BlogPipeline(api_key='your-key')
# Generate posts for last 7 days
for days_ago in range(7):
date = datetime.now() - timedelta(days=days_ago)
date_str = date.strftime('%Y-%m-%d')
result = pipeline.run_full_pipeline(filter_date=date_str)
if result.success:
with open(f'posts/blog_{date_str}.md', 'w') as f:
f.write(result.blog_content)
print(f"โ Generated blog for {date_str}")
Custom Model Configuration
Test different Gemini models:
pipeline = F1BlogPipeline(
api_key='your-key',
model='gemini-2.0-pro',
temperature=0.9, # More creative
max_tokens=8000 # Longer output
)
result = pipeline.run_full_pipeline(filter_date='today')
Available models:
gemini-2.0-flash(fast, good quality, cost-effective)gemini-2.0-pro(higher quality, slower, more expensive)gemini-2.0-flash-exp-preview(experimental features)
Error Handling
The pipeline continues on partial failures:
result = pipeline.run_full_pipeline(filter_date='today')
if result.success:
print(f"Success! {result.articles_extracted} articles")
else:
print("Pipeline failed")
for error in result.errors:
print(f"[{error['stage']}] {error['message']}")
# Check warnings even on success
for warning in result.warnings:
print(f"Warning: {warning}")
Requirements
- Python 3.10+
- google-genai >= 0.4.0
- playwright >= 1.40.0
- python-dotenv >= 1.0.0
Troubleshooting
Playwright Browsers Not Installed
playwright install chromium
API Key Not Found
# Option 1: Pass directly
pipeline = F1BlogPipeline(api_key='your-key')
# Option 2: Use environment variable
import os
os.environ['GEMINI_API_KEY'] = 'your-key'
pipeline = F1BlogPipeline()
# Option 3: Load from .env file
from dotenv import load_dotenv
load_dotenv()
pipeline = F1BlogPipeline()
Bot Detection / 403 Errors
Increase delay between requests:
pipeline = F1BlogPipeline(delay=5) # 5 seconds
result = pipeline.run_full_pipeline(filter_date='today')
License
MIT
Contributing
Contributions welcome! Please open an issue or submit a pull request.
Acknowledgments
- Powered by Google Gemini API
- Browser automation by Playwright
- RSS feeds from Autosport, Motorsport.com, and other F1 news sources
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file f1_blog_pipeline-0.1.0.tar.gz.
File metadata
- Download URL: f1_blog_pipeline-0.1.0.tar.gz
- Upload date:
- Size: 20.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
33d20bf6d57998cee5f9aef27c90db652437501e8c100ec4e0d7d2320b749bc0
|
|
| MD5 |
bdd517f1c824762ac299361056ebfc7d
|
|
| BLAKE2b-256 |
8660f186cb7694a9360a35389ae29cc43799a7f259d2886505609ce263b3b69f
|
File details
Details for the file f1_blog_pipeline-0.1.0-py3-none-any.whl.
File metadata
- Download URL: f1_blog_pipeline-0.1.0-py3-none-any.whl
- Upload date:
- Size: 20.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d05fbc399c9a47ef912cd913a86dd5ec208b45936d48f59e59ad8124a1b0c560
|
|
| MD5 |
4cc9e35696ebfa8759c39c3a40ce5d24
|
|
| BLAKE2b-256 |
3ae080bfb01807b1c2db3157bb5105ebcd1c8007af198729f4a6ad9574c76c01
|