Top 10 AI automation articles from Zapier's blog in 2025 (part 3)

August 2, 2025
tl;dr: I filtered and concatenated all articles from 2025, saving them to a markdown file. When hitting token limits with gpt-4.1, I switched to Gemini, running full article and summary-based rankings. Playing with prompts and model limits kept me entertained!

You're reading part 3 of the Top 10 AI Automation Articles from Zapier's Blog in 2025 series, where I let AI do the ranking for me:

  • Check out Part 1 to see the ranking.

  • Check out Part 2 to see how I downloaded and converted the articles to markdown.

So now that I had all the articles, it was time to rank them.

Concatenating the articles of 2025

I started by filtering out articles not from 2025. Then, I concatenated the rest into the variable last_articles_md, and also saved them to the file data/ranks/articles_2025.md.

# zapier_automation_inspiration.py
# ...
# 1. List of Articles
# ...
# 2. Download articles and convert to Markdown format
# ...
# 3. Concatenate the articles of 2025

last_articles = [a for a in articles if a.get("editorialLastPublishedDateComputed").startswith("2025")]
last_articles_md = ""
for a in last_articles:
    with open(f"data/articles/{a.get('slug')}.md", "r", encoding="utf-8") as f:
        last_articles_md += "\n\n" + f.read()

os.makedirs("data/ranks/", exist_ok=True)

with open("data/ranks/articles_2025.md", "w", encoding="utf-8") as f:
    f.write(last_articles_md)

Ranker prompt

Next, I asked gpt-4.1 to help me create an effective prompt for ranking these articles. I started with this request:

I try to rank articles in Zapier's blog using an LLM.  I've already
all articles contents.  Help me write a performant prompt for this.
Here is a starting point.  Improve it.

-----
- I'm a programmer and I'm learning about AI automation.
- I don't have much time to read all the articles written on Zapier's
  blog that talks about automation.  So I need your help.
- Rank the following articles.
- For each article tell me:
  1. why I should read the article in a sentence?
  2. why it is ranked there

After refining its reply, the prompt evolved into this:

*You are an expert AI assistant helping a programmer interested in AI
automation.  Your task is to rank a list of articles from Zapier's
blog about automation from most to least useful for someone with this
profile.*

*Instructions:*

1. You are ranking these articles for a programmer (with some coding
   skills) who wants to learn practical and advanced concepts in AI
   automation, and who values depth, clarity, and actionable insights.
2. Assume the user has limited time and can read only the most
   relevant articles.
3. Only include the 10 best articles in your ranked list.  This should
   be a top 10 list with exactly 10 articles.
4. For each article, provide in *one sentence*:

   - *Why it's worth reading for this user.*

5. For each article, provide in *one sentence*:

   - *Why you placed it at this rank*.

6. For each article, include its metadata (Link, Author, Last updated,
   Time to read)
7. Output your answer as a numbered list---most recommended article
   first.

*Example output format:*

1. [Article 1 Title]
   - Link: [The link]
   - Author: [The Author]
   - Last updated: [Last update date]
   - Time to read: [The time to read] min
   - Why read: [One-sentence value proposition for a programmer
     learning AI automation.]
   - Ranking reason: [Concise justification for its rank.]
2. [Article 2 Title]
   - Link: ...
   - Author: ...
   - ...

Hitting the tokens per min (TPM) limit with gpt-4.1

I tried using that prompt with gpt-4.1 model and pasted about half the articles into Eden, my ChatGPT interface. It didn't work. The number of tokens was too high for my tokens per minute (TPM) limit:

{
  "message": "Request too large for gpt-4.1-long-context in
organization org-wNqdQ1eu6ZLRZYX79oeMbGio on tokens per
min (TPM): Limit 200000, Requested 264554.  The input or
output tokens must be reduced in order to run successfully.
Visit https://platform.openai.com/account/rate-limits to
learn more.",
  "type": "tokens",
  "param": null,
  "code": "rate_limit_exceeded"
}

Too bad, gpt-4.1's context window is 1,047,576 tokens, and I really wanted to use it for some reason.

Anyway, I verified that I was not limited in such way on Google Cloud with gemini-2.5-flash model and switched to that model.

But before running it, I checked the token count for all these articles using the tiktoken package:

import tiktoken
encoding = tiktoken.get_encoding("o200k_base")
len(encoding.encode(last_articles_md))
# 417814

Ranking the articles of 2025 with gemini-2.5-flash passing it the full articles

Finally, I passed the full articles and the ranker prompt to gemini-2.5-flash. I saved the model's answer in data/ranks/articles_2025_rank_by_gemini-2.5-flash.md.

You can see this output in part 1 of the series.

# zapier_automation_inspiration.py
# ...
from google import genai
from google.genai import types
from dotenv import load_dotenv

# add in .env file
# GEMINI_API_KEY=...
# OPENAI_API_KEY=...
load_dotenv()

# 1. List of Articles
# ...
# 2. Download articles and convert to Markdown format
# ...
# 3. Concatenate the articles of 2025
# ...
# 4. Rank the articles of 2025 with gemini-2.5-flash passing it the full articles

ranker_prompt = """*You are an expert AI assistant helping a programmer interested in AI automation.  Your task is to rank a list of articles from Zapier's blog about automation from most to least useful for someone with this profile.*

*Instructions:*

1. You are ranking these articles for a programmer (with some coding skills) who wants to learn practical and advanced concepts in AI automation, and who values depth, clarity, and actionable insights.
2. Assume the user has limited time and can read only the most relevant articles.
3. Only include the 10 best articles in your ranked list.  This should be a top 10 list with exactly 10 articles.
4. For each article, provide in *one sentence*:

   - *Why it's worth reading for this user.*

5. For each article, provide in *one sentence*:

   - *Why you placed it at this rank*.

6. For each article, include its metadata (Link, Author, Last updated, Time to read)
7. Output your answer as a numbered list---most recommended article
   first.

*Example output format:*

1. [Article 1 Title]
   - Link: [The link]
   - Author: [The Author]
   - Last updated: [Last update date]
   - Time to read: [The time to read] min
   - Why read: [One-sentence value proposition for a programmer learning AI automation.]
   - Ranking reason: [Concise justification for its rank.]
2. [Article 2 Title]
   - Link: ...
   - Author: ...
   - ...
"""

client = genai.Client()
response = client.models.generate_content(
    model="gemini-2.5-flash",
    config=types.GenerateContentConfig(
        system_instruction=ranker_prompt),
    contents=last_articles_md
)

with open("data/ranks/articles_2025_rank_by_gemini-2.5-flash.md", "w", encoding="utf-8") as f:
    f.write(response.text)

Ranking the articles of 2025 using summaries

I could have stopped here, but I was curious: how would the rankings change if the models used only article summaries instead of the full content?

Summarizer prompt

So, I asked gpt-4.1 for a prompt to generate summaries that would be useful as input for the ranker prompt. Here's what I asked:

Give me a prompt to produce a summary for each article which would be
useful then to do the ranking of the articles with the ranker prompt
above?

After refining, I settled on this:

You are an assistant helping a programmer with some coding experience
who wants to quickly find the most relevant articles about AI
automation.

*Instructions:*

1. For the following article, provide a concise summary (2-4
   sentences) that highlights:

   - The main topic or purpose of the article
   - Any practical techniques or insights related to AI automation that a
     programmer could learn from it
   - Any noteworthy examples, case studies, or real-world applications
     mentioned

2. Focus on information that would help a programmer decide whether
   this article is worth reading to advance their understanding of AI
   automation.

*Example output format:*

# [Article Title]

- Link: [The link]
- Author: [The Author]
- Last updated: [Last update date]
- Time to read: [The time to read] min
- Summary: [Concise summary]

Generating summaries

I generated the summaries using gemini-2.5-flash. I saved each one in data/ranks/summaries/ directory, and concatenated them all into last_articles_summaries_md variable, also saved as data/ranks/summaries_2025.md.

# zapier_automation_inspiration.py
# ...
# 5. Generate summaries of articles

last_articles = [a for a in articles if a.get("editorialLastPublishedDateComputed").startswith("2025")]

os.makedirs("data/ranks/summaries/", exist_ok=True)

last_articles_summaries_md = ""
for a in last_articles:
    slug = a.get('slug')
    with open(f"data/articles/{slug}.md", "r", encoding="utf-8") as f:
        article_content = f.read()
    logger.info(f"Summarizing '{slug}'.")
    response = client.models.generate_content(
        model="gemini-2.5-flash",
        config=types.GenerateContentConfig(
        system_instruction=ranker_prompt),
        contents=article_content
    )
    summary = response.text
    last_articles_summaries_md += "\n\n" + summary
    with open(f"data/ranks/summaries/{slug}.md", "w", encoding="utf-8") as f:
        f.write(summary)

with open("data/ranks/summaries_2025.md", "w", encoding="utf-8") as f:
    f.write(last_articles_summaries_md)

This time, the number of tokens is in the my TPM limit:

encoding = tiktoken.get_encoding("o200k_base")
len(encoding.encode(last_articles_summaries_md))
# 22550

Ranking using summaries

Finally, I generated the rankings using the ranker prompt, this time with the summaries as input:

# zapier_automation_inspiration.py
# ...
from openai import OpenAI
# ...
# 6. Rank articles of 2025 using summaries

client = genai.Client()

response = client.models.generate_content(
    model="gemini-2.5-flash",
    config=types.GenerateContentConfig(
        system_instruction=ranker_prompt),
    contents=last_articles_summaries_md
)

with open("data/ranks/articles_2025_rank_using_summaries_by_gemini-2.5-flash.md", "w", encoding="utf-8") as f:
    f.write(response.text)

client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
response = client.responses.create(
    model="gpt-4.1",
    input=[{"role": "user", "content": last_articles_summaries_md}],
    instructions=ranker_prompt
)

with open("data/ranks/articles_2025_rank_using_summaries_by_gpt-4.1.md", "w", encoding="utf-8") as f:
    f.write(response.output_text)

zapier_automation_inspiration.py

To install and run:

$ uv init
$ uv add beautifulsoup4 google-genai markdownify openai python-dotenv requests tiktoken
$ uv run zapier_automation_inspiration.py
# zapier_automation_inspiration.py

import requests
from bs4 import BeautifulSoup
import os
import logging
import json
from markdownify import markdownify as md
import re
from datetime import datetime
import time
from google import genai
from google.genai import types
from dotenv import load_dotenv
from openai import OpenAI

# add in .env file
# GEMINI_API_KEY=...
# OPENAI_API_KEY=...
load_dotenv()

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("zapier-inspiration")

# 1. List of Articles

base_url = "https://zapier.com"
list_url = base_url + "/blog/all-articles/automation-inspiration/"
resp = requests.get(list_url)
soup = BeautifulSoup(resp.text, "html.parser")
next_data_tag = soup.find("script", id="__NEXT_DATA__")

if next_data_tag:
    next_data = json.loads(next_data_tag.string)
    pagination_urls = data.get("props", {}).get("pageProps", {}).get("paginationUrls")
else:
    logger.error(f'No tag with id "__NEXT_DATA__" found in {list_url}.')

articles = []

for p in pagination_urls:
    articles_url = base_url + p
    resp = requests.get(articles_url)
    soup = BeautifulSoup(resp.text, "html.parser")
    next_data_tag = soup.find("script", id="__NEXT_DATA__")
    if next_data_tag:
        next_data = json.loads(next_data_tag.string)
        if (articles_most_recent := next_data.get("props", {}).get("pageProps", {}).get("articlesMostRecent")):
            articles.extend(articles_most_recent)
            logger.info(f"{len(articles_most_recent)} articles found in {articles_url}.")
        else:
            logger.info(f"No articles found in {articles_url}.")

os.mkdir("data")
with open("data/articles.json", "w", encoding="utf-8") as f:
    json.dump(articles, f, ensure_ascii=False, indent=2)

logger.info(f"{len(articles)} articles found.")
logger.info(f"The list of articles has been saved in data/articles.json file.")



os.makedirs("data/articles/", exist_ok=True)

articles = [a for a in articles if isinstance(a, dict) and "slug" in a]

for article in articles:
    slug = article.get("slug")
    article_url = f"{base_url}/blog/{slug}/"

    logger.info(f"Processing '{article_url}'.")

    try:
        resp = requests.get(article_url)
    except requests.exceptions.RequestException as e:
        logger.error(f"Failed to fetch {article_url}: {e}")
        continue
    time.sleep(2)

    soup = BeautifulSoup(resp.text, "html.parser")
    article_tag = soup.find("article")

    if article_tag:
        # Always use #-style Markdown headings
        article_md = md(str(article_tag), heading_style="atx")
        # Remove lines like these:
        # [Try it](/webintent/create-zap?template=1379702)
        # * ![RSS by Zapier logo](https://zapier-images.imgix.net/storage/services/aa4f3d27fda1e4ca2e1a64c3e62d3b7c.png?auto=format&fit=crop&h=30&ixlib=react-9.8.1&q=50&w=30)
        article_md = "\n".join(line for line in article_md.splitlines() if not line.startswith("* ![") and not line.startswith("[Try"))
        # Remove consecutive line breaks
        article_md = re.sub(r"\n\s*\n+", "\n\n", article_md)
    else:
        article_md = ""

    title = article.get("title", slug)
    author = article.get("author", {}).get("name", "")
    email = article.get("author", {}).get("email", "")
    last_updated = datetime.fromisoformat(article.get("editorialLastPublishedDateComputed"))
    time_to_read = str(int(article.get("timeToRead", 0) / 60))
    description = article.get("description", "")

    article_md = f"""# {title}

* Link: {article_url}
* Author: {author}
* Email: {email}
* Last updated: {last_updated.strftime('%B %d, %Y')}
* Time to read: {time_to_read} min
* Description: {description}

{article_md}"""

    filename = f"data/articles/{slug}.md"
    with open(filename, "w", encoding="utf-8") as f:
        f.write(article_md)

    if article_tag:
        logger.info(f"Proccesing '{article_url}' done.  See {filename}.")
    else:
        logger.error(f"Failed to fetch '{article_url}':  no <article> tag found.")

# 3. Concatenate the articles of 2025

last_articles = [a for a in articles if a.get("editorialLastPublishedDateComputed").startswith("2025")]
last_articles_md = ""
for a in last_articles:
    with open(f"data/articles/{a.get('slug')}.md", "r", encoding="utf-8") as f:
        last_articles_md += "\n\n" + f.read()

os.makedirs("data/ranks/", exist_ok=True)

with open("data/ranks/articles_2025.md", "w", encoding="utf-8") as f:
    f.write(last_articles_md)

# 4. Rank the articles of 2025 with gemini-2.5-flash passing it the full articles

ranker_prompt = """*You are an expert AI assistant helping a programmer interested in AI automation.  Your task is to rank a list of articles from Zapier's blog about automation from most to least useful for someone with this profile.*

*Instructions:*

1. You are ranking these articles for a programmer (with some coding skills) who wants to learn practical and advanced concepts in AI automation, and who values depth, clarity, and actionable insights.
2. Assume the user has limited time and can read only the most relevant articles.
3. Only include the 10 best articles in your ranked list.  This should be a top 10 list with exactly 10 articles.
4. For each article, provide in *one sentence*:

   - *Why it's worth reading for this user.*

5. For each article, provide in *one sentence*:

   - *Why you placed it at this rank*.

6. For each article, include its metadata (Link, Author, Last updated, Time to read)
7. Output your answer as a numbered list---most recommended article
   first.

*Example output format:*

1. [Article 1 Title]
   - Link: [The link]
   - Author: [The Author]
   - Last updated: [Last update date]
   - Time to read: [The time to read] min
   - Why read: [One-sentence value proposition for a programmer learning AI automation.]
   - Ranking reason: [Concise justification for its rank.]
2. [Article 2 Title]
   - Link: ...
   - Author: ...
   - ...
"""

client = genai.Client()
response = client.models.generate_content(
    model="gemini-2.5-flash",
    config=types.GenerateContentConfig(
        system_instruction=ranker_prompt),
    contents=last_articles_md
)

with open("data/ranks/articles_2025_rank_by_gemini-2.5-flash.md", "w", encoding="utf-8") as f:
    f.write(response.text)

# 5. Generate summaries of articles

last_articles = [a for a in articles if a.get("editorialLastPublishedDateComputed").startswith("2025")]

os.makedirs("data/ranks/summaries/", exist_ok=True)

last_articles_summaries_md = ""
for a in last_articles:
    slug = a.get('slug')
    with open(f"data/articles/{slug}.md", "r", encoding="utf-8") as f:
        article_content = f.read()
    logger.info(f"Summarizing '{slug}'.")
    response = client.models.generate_content(
        model="gemini-2.5-flash",
        config=types.GenerateContentConfig(
        system_instruction=ranker_prompt),
        contents=article_content
    )
    summary = response.text
    last_articles_summaries_md += "\n\n" + summary
    with open(f"data/ranks/summaries/{slug}.md", "w", encoding="utf-8") as f:
        f.write(summary)

with open("data/ranks/summaries_2025.md", "w", encoding="utf-8") as f:
    f.write(last_articles_summaries_md)

# 6. Rank articles of 2025 using summaries

client = genai.Client()

response = client.models.generate_content(
    model="gemini-2.5-flash",
    config=types.GenerateContentConfig(
        system_instruction=ranker_prompt),
    contents=last_articles_summaries_md
)

with open("data/ranks/articles_2025_rank_using_summaries_by_gemini-2.5-flash.md", "w", encoding="utf-8") as f:
    f.write(response.text)

client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
response = client.responses.create(
    model="gpt-4.1",
    input=[{"role": "user", "content": last_articles_summaries_md}],
    instructions=ranker_prompt
)

with open("data/ranks/articles_2025_rank_using_summaries_by_gpt-4.1.md", "w", encoding="utf-8") as f:
    f.write(response.output_text)

That's all I have for today! Talk to you soon ;)

Built with one.el.