Skip to content

Instantly share code, notes, and snippets.

@andrewrjones
Last active July 16, 2025 11:20
Show Gist options
  • Select an option

  • Save andrewrjones/f70f58fbcf7e9c2860061adbd5f352f1 to your computer and use it in GitHub Desktop.

Select an option

Save andrewrjones/f70f58fbcf7e9c2860061adbd5f352f1 to your computer and use it in GitHub Desktop.
A script to add alt text to figures in a Hugo site, using ChatGPT to generate the alt text
#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.11"
# dependencies = ["llm", "requests"]
# ///
#
# A script to add alt text to figures in a Hugo site, using ChatGPT to generate the alt text.
# Works for both images saved locally and those with a URL.
# Save this to the root of your Hugo site and, if you have `uv` installed, simply run with `./alt-text.py`.
# See also https://andrew-jones.com/blog/adding-alt-text-to-my-all-my-images-with-openai/
import os
import glob
import llm
import requests
def process_markdown_for_alt_text(content):
lines = content.splitlines()
updated_lines = []
for line in lines:
if '{{< figure src="' in line and not 'alt="' in line:
src_start = line.find('src="') + 5
src_end = line.find('"', src_start)
image_src = line[src_start:src_end]
attachments = []
if image_src.startswith("http"):
response = requests.head(image_src, allow_redirects=False, timeout=5)
if response.status_code == 200:
attachments.append(llm.Attachment(url=image_src))
else:
image_path = f"static{image_src}"
if os.path.exists(image_path):
attachments.append(llm.Attachment(path=image_path))
else:
print(f"Warning: Image not found: {image_path}")
if attachments:
model = llm.get_model("gpt-4.1-nano")
try:
response = model.prompt(
"Generate a concise alt text for the image. The alt text should be descriptive and suitable for a screen reader. Do not include any introductory phrases like 'Alt text:' or 'An image of'",
attachments=attachments,
)
alt_text = response.text().replace('"', '\\"')
updated_line = line.replace('>}}', f'alt="{alt_text}" >}}}}')
updated_lines.append(updated_line)
except Exception as e:
print("Exception from OpenAI: " + e)
updated_lines.append(line)
else:
updated_lines.append(line)
else:
updated_lines.append(line)
content = "\n".join(updated_lines)
return content
def generate_alt_text_for_all_markdown_files():
content_directory = "content"
markdown_files = glob.glob(os.path.join(content_directory, "**/*.md"), recursive=True)
for file_path in markdown_files:
with open(file_path, 'r') as f:
content = f.read()
updated_content = process_markdown_for_alt_text(content)
with open(file_path, 'w') as f:
f.write(updated_content)
if __name__ == "__main__":
generate_alt_text_for_all_markdown_files()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment