Copilot as a Python coding partner

How I Used AI to Automate a Repetitive, Error-Prone Task


The Challenge

I needed to change the font and position of two words per page in a 435-page PDF. Each page had similar content. Let’s call the two words “Apples” and “Oranges.”

What made it tricky:

  • The two words were repeated multiple times on every page. Only some occurrences needed to be replaced. 

    In this long PDF, the phrase “Buy Bob’s apples” needed to be replaced on each page. The word “apples” was used in other phrases on different lines and did not need to be replaced there.
  • In “Buy Bob’s apples,” the font used for the word “apples” differed from the font used for the words “Buy Bob’s.” This also was the case for “Bob’s oranges are great too!”
  • Several lines moved whenever the two words were replaced. 

Trying to edit this large PDF manually, one word at a time, twice per page would have taken a while and it could induce errors. When you multitask for a living, you need solutions that reduce error because distractions happen.

My Method

To get this done I used Copilot to write and refine a Python script through prompt engineering. I worked iteratively describing what I wanted in plain language letting Copilot generate the code.

Each time I encountered a challenge, like aligning text, simulating bold, adjusting spacing, or Copilot code errors, I simply described the issue in a prompt. Copilot responded with updated code, explanations, and suggestions. 

Here are some of the tasks the script had to perform:

  • Quickly test different font styles and placements
  • Fine-tune the horizontal offset for natural-looking spacing
  • Switch between fonts and styling strategies without rewriting everything
  • Programmatically determine which was the correct “Apple” that needed a font change

This process took some time. But it gave me a deeper understanding of Python, how to run scripts locally, and how a PDF is rendered.

My Tools  
  • Python 3.9+ (Locally on my Mac OSX laptop)
  • PyMuPDF (fitz): for PDF manipulation
  • Font: Lucida Calligraphy Bold.otf
What I Learned 
  • PyMuPDF gives you control over text placement and styling.
  • Custom fonts can be embedded and used precisely.
  • While free open source libraries like PyMuPDF are powerful, they can’t do everything. More complicated edits require a paid Adobe API. 
  • AI or LLM are not perfect. Although they code well, I spent a lot of time fixing mistakes. But it got done!
  • Coding this way is fun and productive.

The Finished Script, after 25 Iterations
import fitz  # PyMuPDF
from datetime import datetime
# File paths
pdf_path = "bobs-fruit.pdf"  # Replace with your actual PDF file
font_path = "Lucida Calligraphy Bold.otf" # Replace with your actual font file
# Generate a unique output file name with timestamp
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
output_path = f"bobs_fruit_{timestamp}.pdf"
# Open the PDF
doc = fitz.open(pdf_path)
# Register the custom font
custom_font = fitz.Font(fontfile=font_path)
custom_font_name = "LucidaCalligraphyBold"
# Loop through each page
for page_num in range(doc.page_count):
    page = doc[page_num]
    instances_apples = page.search_for("apples")
    instances_oranges = page.search_for("oranges")
    # Combine and sort instances by vertical position
    instances = sorted(instances_apples + instances_oranges, key=lambda inst: inst.y0)
    for inst in instances:
        # Extract the full line containing the word
        text_dict = page.get_text("dict", clip=fitz.Rect(0, inst.y0, page.rect.width, inst.y1))
        try:
            line = text_dict["blocks"][0]["lines"][0]
            full_line_text = "".join([span["text"] for span in line["spans"]])
            font_size = line["spans"][0]["size"]
            y_position = line["spans"][0]["origin"][1]
        except (IndexError, KeyError):
            continue
        # Skip lines containing "apples, red delicious"
        if "apples, red delicious" in full_line_text:
            continue
        # Remove the entire line
        page.add_redact_annot(fitz.Rect(0, inst.y0, page.rect.width, inst.y1), fill=(1, 1, 1))
        page.apply_redactions()
        # Center the line using the custom font
        line_width = custom_font.text_length(full_line_text, fontsize=font_size)
        x_position = (page.rect.width - line_width) / 2
        # Reinsert the full line in the custom font
        page.insert_text(
            (x_position, y_position),
            full_line_text,
            fontname=custom_font_name,
            fontfile=font_path,
            fontsize=font_size,
            color=(0, 0, 0),
        )
# Save the updated PDF
doc.save(output_path)
print(f"✅ Updated PDF saved as: {output_path}")

Disclaimer: I used the AI Copilot to generate a draft of this post and to perform the tasks I described. I heavily edited the post with the help of other humans.