Astrology content has a brutal property: it has to be fresh every single day, for every sign, ideally in a few languages, forever. Writing that by hand doesn't scale. For AstroZodify I built a pipeline that generates daily horoscopes and short zodiac videos on a schedule, with humans reviewing rather than writing. Here's the shape of it.
The content problem
Per day you need: 12 signs x N content types (daily horoscope, love, career) x M languages. That's hundreds of pieces of copy a day that all have to feel written, not templated, and stay consistent with each sign's "voice".
Templating alone reads robotic. Free-form generation drifts. The trick is constraining an LLM enough to stay on-brand while still sounding human.
The generation pipeline
- Structured prompts per sign. Each sign has a persona and constraints (tone, themes, length). The model fills the daily specifics, not the whole thing from scratch.
- Scheduled batch runs. A cron job kicks off generation ahead of time so content is ready before it's needed, never on the critical path of a page request.
- Validation. Output is checked for length, banned phrasing, and structure before it's allowed near the site.
- Store, then serve. Everything lands in Postgres. Pages are SSR and just read pre-generated rows, so the LLM is never in the user's request path.
Keeping generation offline from serving is the single most important decision - it keeps pages fast and costs predictable.
Adding video
Text was step one. Short vertical zodiac videos (for social) are step two, and that's a heavier pipeline: script -> imagery -> voiceover -> render. That part runs on Cloud Run as a separate job so a slow render never touches the web app, and we pilot one item before any batch.
Cost and safety rails
Anything that calls a paid API in a loop is a footgun. The rules I follow:
- Always pilot on 1-10 items before a full batch.
- Never an unbounded loop against a paid API.
- Cache and pre-generate so serving is basically free.
Takeaways
- Separate generation from serving. Pre-generate on a schedule, serve static rows.
- Constrain the model with per-entity personas instead of free-form prompts.
- Treat video as its own isolated pipeline, not an extension of the text one.
You can see the output at https://astrozodify.com
If you're generating large volumes of scheduled content, I'd love to compare notes on validation - how do you catch a bad generation before it ships?
Top comments (0)