🏡 Home > 🤖 AI Blog | ⏮️ ⏭️

♻️ Gemini Model Refresh and Blog Post Regeneration

🎯 The Problem

🤖 Our auto-generated blog posts rely on Google’s Gemini API for content generation.
📉 The Gemini 2.5 series models were producing noticeably lower quality blog posts compared to the newer 3.1 series.
⚠️ When the preferred gemini-3.1-flash-lite-preview model was unavailable, our fallback chain dropped all the way down to gemini-2.5-flash and gemini-2.5-flash-lite.
😞 This meant that on bad days, readers got a subpar post with no easy way to request a do-over.

🔬 Research Phase

🌐 We surveyed the current Gemini model landscape to understand what’s available on the free tier for text generation.
🆓 Here’s what we found across the major model families.

🟢 Free Tier Text Generation Models

  • 🚀 gemini-3.1-flash-lite-preview is our workhorse, optimized for high-volume tasks and available free of charge
  • 🧠 gemini-3-flash-preview is a frontier-class model with intelligence rivaling much larger models, also free
  • ⚡ gemini-2.5-flash is a hybrid reasoning model with a one million token context window, free but lower quality for creative writing
  • 💰 gemini-2.5-flash-lite is the budget option in the 2.5 family, suitable for simple tasks
  • 🔒 gemini-3.1-pro-preview is paid only, so it’s not an option for our free-tier setup
  • 🤖 gemma-3-27b-it remains our go-to for lightweight tasks like social media tag generation

🧪 Live Testing Results

✅ We tested each model with a simple prompt to verify availability.
🎉 Five out of six models responded successfully.
📊 The only failure was gemini-2.5-pro, which hit its daily quota limit, confirming it’s not reliable for our use case.

🤔 Three Plans Considered

📋 Plan A: Keep 2.5 Fallbacks, Add gemini-3-flash-preview

🔄 Simply add gemini-3-flash-preview to the existing chain alongside the 2.5 models.
👍 Maximum resilience with many fallback options.
👎 Posts generated by 2.5 models would still be low quality, and users would have no recourse.

📋 Plan B: Restrict to 3.1 Plus Only, No New Fallbacks

🔒 Use only gemini-3.1-flash-lite-preview with no fallbacks.
👍 Guarantees highest quality from the newest model family.
👎 A single point of failure with zero resilience when that model goes down.

📋 Plan C: Restrict to Generation 3 Plus with Regeneration Support

🎯 Use gemini-3.1-flash-lite-preview as primary with gemini-3-flash-preview as fallback, and add a user-facing regeneration mechanism.
👍 Quality floor stays high since both models are generation 3 or newer.
👍 Users can request regeneration when a post doesn’t meet their standards.
👍 The system remains resilient with a strong fallback that’s still a frontier-class model.
👎 Slightly more implementation complexity for the regeneration feature.

✅ The Chosen Path

🏆 We went with Plan C because it balances quality, resilience, and user control.

🔧 What Changed

🤖 Model Chain Updates

🔄 Chickie Loo and Auto Blog Zero now use gemini-3.1-flash-lite-preview as primary with gemini-3-flash-preview as fallback, both generation 3 or newer for highest quality.
🌐 Systems for Public Good leads with gemini-2.5-flash because it needs Google Search grounding to reference current events, which is only available on the free tier for 2.5 models at 500 requests per day.
🔗 Its fallback chain is gemini-2.5-flash-lite, then gemini-3.1-flash-lite-preview as a last resort without grounding.
🚫 The 2.5 series models have been removed from the non-grounding blog series where quality is the top priority.
📝 Other tasks like social media posting, fiction generation, and internal linking retain their existing model assignments since quality concerns are less critical there.

♻️ Blog Post Regeneration

🆕 A new frontmatter property called regenerate_post enables on-demand post regeneration.
📱 From Obsidian, the user simply toggles regenerate_post to true on any post they want regenerated.
🔄 On the next hourly cron run, the scheduler detects the flag, removes the old post, and generates a fresh one.
✨ The newly generated post never includes regenerate_post in its frontmatter, preventing infinite regeneration loops.
📅 Only today’s post can be regenerated, so the flag is harmlessly ignored on historical posts.

🐛 The initial regeneration implementation had three subtle bugs that left stale links behind when the regenerated post received a new slug.

🔀 The first bug was in the previous post’s forward link. When a post is regenerated, the AI generates a new title, which produces a new slug and filename. The previous post already had a forward link pointing to the old filename. The original code skipped updating the forward link if one already existed, so the stale link was never corrected. The fix replaces the existing forward link with the new one instead of skipping.

📓 The second bug was in the daily reflection. The reflection note for today had a link to the old filename. When the new post was generated, a second link was added without removing the old one, resulting in duplicate links with one pointing to a deleted file. The fix threads the old filename through the regeneration path and explicitly replaces the stale link.

🗑️ The third bug was in vault cleanup. The old post file was deleted locally but never removed from the Obsidian vault. This left a ghost file in the vault that would reappear on the next sync. The fix deletes the old file from the vault directory when the new filename differs from the old one.

🐛 Midnight Bug Fix

🕛 We discovered and fixed a bug in nowPacificHour where midnight was returned as hour 24 instead of hour 0.
🔧 The fix applies a modulo 24 operation to the output of Intl.DateTimeFormat, which uses hour 24 to represent midnight in some locales.
🧪 This was caught by an existing test that was already failing before our changes.

🧪 Testing

📊 All 1296 tests pass across the entire test suite.
🆕 Seven tests cover the findPostToRegenerate function, including edge cases for missing directories, posts without the flag, posts with the flag set to false, date filtering, and non-markdown file filtering.
🔗 One new test verifies that updatePreviousPost replaces stale forward links when regeneration produces a new filename.
📓 Two new tests verify that insertPostLink replaces stale reflection links when an explicit old filename is provided and that it leaves unrelated links alone when no replacement is requested.
✅ The three previously failing scheduler tests were fixed as part of this work.

📖 Book Recommendations

📚 Similar

  • 🤖 Designing Machine Learning Systems by Chip Huyen
  • 🏗️ Building Intelligent Systems by Geoff Hulten
  • 🔄 Release It! by Michael Nygard

🔀 Contrasting