The Problem
Hacker News headlines are transient—the front page turns over in hours. Capturing them as text is trivial, but turning them into something visually meaningful usually means sending data to a cloud API. This project solves that by generating a daily AI art piece from the top HN stories using only local Apple Silicon hardware, keeping the entire inference pipeline on-device.
What This Does
hn_local_image fetches the current HN front page, uses a local vision-language model to craft an artistic prompt from the headlines, and generates an image with a local diffusion model via MFlux. The output is either a full-color 1280×768 PNG for web or a heavily processed, dithered 1-bit 800×480 image for e-ink displays.
The pipeline is split across five Python modules: fetcher.py pulls headlines, prompter.py converts them into image prompts, generator.py runs the local image model, processor.py handles post-processing (e-ink rendering, watermarking), and main.py orchestrates everything with a CLI supporting multiple styles and models.
How It Is Wired
Execution starts at main.py. Two entry points exist: generate (line 68) and compare (line 404, which delegates to _run_compare). From generate, the flow is linear: fetch_hn_headlines → generate_prompt → generate_local_image → process_image → add_watermark → display_terminal_preview. The shortest path to an external effect is two hops: compare → fetch_hn_headlines, which makes a network call via requests.get.
The module graph is a clean fan-in: main.py imports all four other modules, and each of those modules is imported by exactly one file. No circular dependencies. The highest-blast-radius functions are fetch_hn_headlines (called from 4 places), generate_local_image and generate_prompt (3 each). main.py owns all external effects—network, filesystem, and subprocess execution—making it the single point of change for any I/O behavior.
How To Use It
Setup (pyproject.toml present, no lockfile):
git clone https://github.com/moses-y/hn_local_image
cd hn_local_image
pip install -e .
Configuration: Copy .env.example to .env and set required values. The README documents style flags (--style editorial, --style story_scene) and model selection (default z-image-turbo, plus FLUX.2 Klein, Ernie Image Turbo, Ideogram 4 FP8).
Running it:
hn-local-image generate --style editorial
hn-local-image compare --watermark --style editorial
Real-World Use
A daily cron job on a Mac Mini generates a front-page artwork each morning, saves the web PNG to a shared drive, and pushes the e-ink version to a wall display. The --watermark flag in compare mode labels each model's output, letting you A/B test prompt interpretations before committing to a default.
Code Health & Issues
Static analysis (not opinion) found 3 medium findings across 2 kinds:
- Med/Resilience – Broad exception handling in
processor.pyandmain.py; bareexceptswallows errors indiscriminately. Fix: catch specific exceptions, re-raise or log the rest. - Med/Cognitive load – High branching density in
prompter.py: 42 branch points over 132 lines. Fix: decompose decision-heavy logic, consider table/strategy dispatch.
SDLC observations from file structure: no test files exist; no lockfile committed; CI uses GitHub Actions but pins pypa/gh-action-pypi-release@v1.12.2 by tag (mutable—should be SHA-pinned); no Dependabot configured; no dependency vulnerability scan in CI; checkout leaves credentials persisted. These are real risks for a project that publishes releases.
The Bottom Line
A focused, well-structured tool that does one thing—local HN-to-art—with clean module boundaries and no architectural debt. The missing lockfile and unpinned CI actions are the main production risks, and the lack of tests means changes to prompt logic or image processing are unguarded. Suitable for personal use or as a reference for local MLX pipelines; not yet ready for unattended production deployment.