p08-seo-tweaks

This commit is contained in:
2026-02-13 00:49:22 -05:00
parent a1da041f14
commit 88a5540b7d
63 changed files with 2228 additions and 37 deletions

View File

@@ -2,8 +2,9 @@ import logging
import os
from apscheduler.schedulers.background import BackgroundScheduler
from fastapi import Depends, FastAPI, Query
from fastapi import Depends, FastAPI, Query, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.middleware.gzip import GZipMiddleware
from fastapi.staticfiles import StaticFiles
from fastapi.responses import FileResponse
from sqlalchemy.orm import Session
@@ -20,6 +21,7 @@ from backend.repository import (
get_translation,
normalize_language,
resolve_news_content,
resolve_summary_fields,
)
from backend.schemas import HealthResponse, NewsItemResponse, PaginatedNewsResponse
@@ -39,6 +41,30 @@ app.add_middleware(
allow_headers=["*"],
)
app.add_middleware(GZipMiddleware, minimum_size=500)
@app.middleware("http")
async def add_cache_headers(request: Request, call_next):
response = await call_next(request)
path = request.url.path
if path.startswith("/static/"):
response.headers.setdefault("Cache-Control", "public, max-age=604800, immutable")
elif path.startswith("/api/"):
response.headers.setdefault(
"Cache-Control", "public, max-age=60, stale-while-revalidate=120"
)
response.headers.setdefault("Vary", "Accept-Encoding")
elif path in {"/", "/terms", "/attribution"}:
response.headers.setdefault(
"Cache-Control", "public, max-age=300, stale-while-revalidate=600"
)
response.headers.setdefault("X-Content-Type-Options", "nosniff")
return response
static_dir = os.path.join(os.path.dirname(__file__), "static")
app.mount("/static", StaticFiles(directory=static_dir), name="static")
@@ -101,6 +127,7 @@ def api_get_news(
if lang != "en":
translation = get_translation(db, item.id, lang)
headline, summary = resolve_news_content(item, translation)
tldr_points, summary_body, source_citation = resolve_summary_fields(item, translation)
response_items.append(
NewsItemResponse(
id=item.id,
@@ -109,6 +136,11 @@ def api_get_news(
source_url=item.source_url,
image_url=item.image_url,
image_credit=item.image_credit,
tldr_points=tldr_points,
summary_body=summary_body,
source_citation=source_citation,
summary_image_url=item.summary_image_url,
summary_image_credit=item.summary_image_credit,
published_at=item.published_at,
created_at=item.created_at,
language=lang if translation is not None else "en",
@@ -136,6 +168,7 @@ def api_get_latest_news(
if lang != "en":
translation = get_translation(db, item.id, lang)
headline, summary = resolve_news_content(item, translation)
tldr_points, summary_body, source_citation = resolve_summary_fields(item, translation)
return NewsItemResponse(
id=item.id,
headline=headline,
@@ -143,6 +176,11 @@ def api_get_latest_news(
source_url=item.source_url,
image_url=item.image_url,
image_credit=item.image_credit,
tldr_points=tldr_points,
summary_body=summary_body,
source_citation=source_citation,
summary_image_url=item.summary_image_url,
summary_image_credit=item.summary_image_credit,
published_at=item.published_at,
created_at=item.created_at,
language=lang if translation is not None else "en",
@@ -163,6 +201,16 @@ async def serve_frontend() -> FileResponse:
return FileResponse(os.path.join(frontend_dir, "index.html"))
@app.get("/terms")
async def serve_terms() -> FileResponse:
return FileResponse(os.path.join(frontend_dir, "terms.html"))
@app.get("/attribution")
async def serve_attribution() -> FileResponse:
return FileResponse(os.path.join(frontend_dir, "attribution.html"))
@app.get("/config")
async def serve_config() -> dict:
return {