feat: rewrite cover generation — 480×800 portrait, themed AI backgrounds, two-layer pipeline

Made-with: Cursor
This commit is contained in:
cottongin
2026-04-06 17:02:36 -04:00
parent 5fec07c287
commit 49acf09aa1
5 changed files with 190 additions and 71 deletions

View File

@@ -1,29 +1,50 @@
import os
from collections import Counter
from datetime import date
from unittest.mock import patch, MagicMock
from io import BytesIO
from PIL import Image as PILImage
from src.cover import generate_text_cover, generate_ai_cover, generate_cover
from src.cover import (
generate_programmatic_cover,
generate_ai_cover,
generate_cover,
_get_dominant_category,
CATEGORY_PROMPTS,
)
def test_text_cover_creates_jpeg(tmp_path):
path = generate_text_cover(
def test_programmatic_cover_is_portrait(tmp_path):
path = generate_programmatic_cover(
output_dir=str(tmp_path),
week_start=date(2026, 4, 6),
week_end=date(2026, 4, 12),
headlines=["Article One", "Article Two", "Article Three"],
categories=["Government", "Government", "Culture"],
)
assert os.path.exists(path)
img = PILImage.open(path)
assert img.format == "JPEG"
assert img.width <= 800
assert img.height <= 480
assert img.size == (480, 800)
def test_ai_cover_creates_jpeg(tmp_path):
fake_img = PILImage.new("RGB", (800, 480), color="blue")
def test_programmatic_cover_no_headlines(tmp_path):
path = generate_programmatic_cover(
output_dir=str(tmp_path),
week_start=date(2026, 4, 6),
week_end=date(2026, 4, 12),
headlines=[],
categories=[],
)
assert os.path.exists(path)
img = PILImage.open(path)
assert img.size == (480, 800)
def test_ai_cover_is_portrait(tmp_path):
fake_img = PILImage.new("RGB", (480, 800), color="blue")
buf = BytesIO()
fake_img.save(buf, format="JPEG")
fake_bytes = buf.getvalue()
@@ -38,40 +59,53 @@ def test_ai_cover_creates_jpeg(tmp_path):
week_start=date(2026, 4, 6),
week_end=date(2026, 4, 12),
headlines=["Test Headline"],
categories=["Government"],
)
assert os.path.exists(path)
img = PILImage.open(path)
assert img.format == "JPEG"
assert img.width <= 800
assert img.height <= 480
assert img.size == (480, 800)
def test_ai_cover_falls_back_on_failure(tmp_path):
def test_ai_cover_falls_back_to_programmatic(tmp_path):
with patch("src.cover.requests.get", side_effect=Exception("API down")):
path = generate_ai_cover(
output_dir=str(tmp_path),
week_start=date(2026, 4, 6),
week_end=date(2026, 4, 12),
headlines=["Test"],
categories=["Government"],
)
assert os.path.exists(path)
img = PILImage.open(path)
assert img.format == "JPEG"
assert img.size == (480, 800)
def test_generate_cover_dispatches(tmp_path):
with patch("src.cover.generate_ai_cover") as mock_ai:
mock_ai.return_value = "/fake/ai.jpg"
result = generate_cover("ai", str(tmp_path), date(2026, 4, 6),
date(2026, 4, 12), ["A"])
date(2026, 4, 12), ["A"], ["Government"])
assert result == "/fake/ai.jpg"
mock_ai.assert_called_once()
with patch("src.cover.generate_text_cover") as mock_text:
mock_text.return_value = "/fake/text.jpg"
with patch("src.cover.generate_programmatic_cover") as mock_prog:
mock_prog.return_value = "/fake/text.jpg"
result = generate_cover("text", str(tmp_path), date(2026, 4, 6),
date(2026, 4, 12), ["A"])
date(2026, 4, 12), ["A"], ["Government"])
assert result == "/fake/text.jpg"
mock_text.assert_called_once()
mock_prog.assert_called_once()
def test_get_dominant_category():
assert _get_dominant_category(["Government", "Government", "Culture"]) == "Government"
assert _get_dominant_category(["Culture", "Government"]) == "Culture"
assert _get_dominant_category([]) == "Default"
def test_category_prompts_include_massachusetts():
for category, prompt in CATEGORY_PROMPTS.items():
assert "Massachusetts" in prompt, f"Prompt for {category} missing 'Massachusetts'"