Make news accessible, unbiased, and generationally relatable.
Reframe is a Chrome extension + FastAPI backend that analyzes news articles for political bias, generates neutral summaries, and translates them into generational styles — from Gen Alpha brainrot to Boomer formal.
| Layer | Technology |
|---|---|
| Backend | Python 3.12, FastAPI |
| AI / LLM | Google Gemini 2.5 Flash via google-genai SDK |
| Web Scraping | BeautifulSoup4, Requests |
| Frontend | Chrome Extension (Manifest V3), vanilla HTML/CSS/JS |
| Data Store | In-memory dict (article text + analysis results) |
git clone https://github.com/yourteam/Reframe-API.git
cd Reframe-API/backend
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txtCreate a .env file in the project root:
# Single key
GEMINI_API_KEY=your_key_here
# Or multiple keys for automatic rotation (4 keys = 80 RPD)
GEMINI_API_KEYS=key1,key2,key3,key4Get a free key at Google AI Studio.
cd Reframe-API
python -m uvicorn backend.main:app --reloadThe API is now live at http://localhost:8000.
- Swagger UI: http://localhost:8000/docs
- ReDoc: http://localhost:8000/redoc
Base URL: http://localhost:8000/api/v1
GET /api/v1/health
curl http://localhost:8000/api/v1/healthResponse 200 OK:
{
"status": "healthy",
"version": "1.0.0",
"model": "gemini-2.5-flash",
"api_keys_configured": 2,
"analyses_stored": 3
}POST /api/v1/analyses
Submit a news article URL. Returns bias score, neutral summary, and 5 generational translations.
Idempotent — re-submitting the same URL returns the cached result.
curl -X POST http://localhost:8000/api/v1/analyses \
-H "Content-Type: application/json" \
-d '{"url": "https://www.bbc.com/news/articles/c1d5r7z7z7ro"}'Response 200 OK:
{
"id": "a1b2c3d4e5f6",
"url": "https://www.bbc.com/news/articles/c1d5r7z7z7ro",
"created_at": "2026-02-28T05:14:00+00:00",
"data": {
"bias": {
"score": -15,
"label": "Leans Left",
"explanation": "The article uses emotionally loaded language favoring progressive viewpoints."
},
"summary": "A factual, unbiased summary of the article...",
"translations": {
"Gen Alpha": "No cap this is lowkenuinely crazy...",
"Gen Z": "ngl this situation is giving major red flags...",
"Millennial": "Adulting is hard enough, but this news takes the cake. #relatable",
"Gen X": "Here's the deal on what happened. Whatever.",
"Boomer": "IMPORTANT UPDATE: Please read this pertinent information."
}
}
}Error 422 Unprocessable Entity:
{
"error": {
"code": 422,
"type": "validation_error",
"message": "Invalid URL format: 'not-a-url'. Must start with http:// or https://"
}
}GET /api/v1/analyses
Returns a paginated list of all previously analyzed articles. Supports filtering by bias label.
| Parameter | Type | Default | Description |
|---|---|---|---|
bias |
string | — | Filter by bias label (Left, Leans Left, Neutral, Leans Right, Right) |
limit |
int | 20 | Max results (1–100) |
offset |
int | 0 | Results to skip |
# List all
curl http://localhost:8000/api/v1/analyses
# Filter by bias
curl "http://localhost:8000/api/v1/analyses?bias=Neutral&limit=5"Response 200 OK:
{
"count": 3,
"analyses": [
{
"id": "a1b2c3d4e5f6",
"url": "https://www.bbc.com/news/...",
"created_at": "2026-02-28T05:14:00+00:00",
"bias_label": "Leans Left",
"bias_score": -15
}
]
}GET /api/v1/analyses/{analysis_id}
curl http://localhost:8000/api/v1/analyses/a1b2c3d4e5f6Response 200 OK: Same shape as the POST response.
Error 404 Not Found:
{
"error": {
"code": 404,
"type": "not_found",
"message": "No analysis found with id 'abc123'. Use POST /api/v1/analyses to create one."
}
}DELETE /api/v1/analyses/{analysis_id}
curl -X DELETE http://localhost:8000/api/v1/analyses/a1b2c3d4e5f6Response 200 OK:
{
"message": "Analysis 'a1b2c3d4e5f6' deleted successfully."
}POST /api/v1/analyses/{analysis_id}/chat
Ask follow-up questions about a previously analyzed article. The LLM answers strictly from the article's context.
curl -X POST http://localhost:8000/api/v1/analyses/a1b2c3d4e5f6/chat \
-H "Content-Type: application/json" \
-d '{"message": "What are the key claims in this article?"}'Response 200 OK:
{
"analysis_id": "a1b2c3d4e5f6",
"question": "What are the key claims in this article?",
"reply": "The article makes three key claims..."
}All errors return a consistent JSON structure:
{
"error": {
"code": 422,
"type": "validation_error",
"message": "Human-readable description of what went wrong"
}
}| Code | When |
|---|---|
400 |
Bad request / extraction failed |
404 |
Analysis ID not found |
422 |
Invalid URL format or no text found |
429 |
All API keys rate-limited |
500 |
Internal LLM error |
502 |
LLM returned unparseable response |
- Open Chrome →
chrome://extensions/ - Enable Developer mode (top right)
- Click Load unpacked → select the
extension/folder - Navigate to any news article and click the Reframe icon
The API supports automatic key rotation across multiple Gemini API keys. When one key hits the free-tier rate limit (429), it automatically tries the next key.
GEMINI_API_KEYS=key1,key2,key3,key4With 4 keys, you get 80 requests/day on the free tier (20 RPD per key).
MIT