Image Gallery Creator¶
Difficulty: Intermediate
Time: 45-60 minutes
Learning Focus: File handling, HTML generation, metadata management, API integration
Module: chat
Overview¶
Create a tool that generates an HTML gallery from a collection of images. The tool manages image metadata, generates descriptions (optionally with AI assistance), and creates a responsive web gallery to showcase the images.
Instructions¶
import os
import json
from hands_on_ai.chat import get_response
from datetime import datetime
def create_image_gallery():
"""
Creates an HTML image gallery from a collection of images.
Students can add their own images to the 'gallery_images' folder.
"""
print("=== Image Gallery Creator ===")
# Create necessary directories
image_dir = "gallery_images"
output_dir = "gallery_output"
os.makedirs(image_dir, exist_ok=True)
os.makedirs(output_dir, exist_ok=True)
# Check if there are images to process
image_files = [f for f in os.listdir(image_dir)
if f.lower().endswith(('.jpg', '.jpeg', '.png', '.gif'))]
if not image_files:
print(f"No images found in '{image_dir}' folder.")
print(f"Please add some image files (JPG, PNG, GIF) to the '{image_dir}' folder.")
return
print(f"Found {len(image_files)} images.")
# Load existing metadata or create new
metadata_file = os.path.join(output_dir, "gallery_metadata.json")
if os.path.exists(metadata_file):
with open(metadata_file, 'r') as f:
try:
gallery_data = json.load(f)
except json.JSONDecodeError:
gallery_data = {"title": "My Image Gallery", "images": []}
else:
gallery_data = {"title": "My Image Gallery", "images": []}
# Update gallery title
gallery_title = input(f"Gallery title [{gallery_data['title']}]: ")
if gallery_title:
gallery_data["title"] = gallery_title
# Process each image
existing_images = {img["filename"]: img for img in gallery_data["images"]}
for image_file in image_files:
if image_file in existing_images:
# Image already has metadata
print(f"\nImage {image_file} already has metadata:")
print(f"Title: {existing_images[image_file]['title']}")
print(f"Description: {existing_images[image_file]['description']}")
update = input("Update this image's information? (y/n): ").lower() == 'y'
if not update:
continue
print(f"\nProcessing: {image_file}")
# Get metadata for this image
default_title = os.path.splitext(image_file)[0].replace('_', ' ').title()
title = input(f"Image title [{default_title}]: ") or default_title
description = input("Image description: ")
# Optionally generate description using AI
if not description:
generate_ai = input("Generate description with AI? (y/n): ").lower() == 'y'
if generate_ai:
try:
prompt = f"Generate a brief, interesting description for an image named '{image_file}'. Create something imaginative based on the filename, without stating that you're guessing or that you haven't seen the image."
description = get_response(prompt)
print(f"AI-generated description: {description}")
use_desc = input("Use this description? (y/n): ").lower() == 'y'
if not use_desc:
description = input("Enter alternative description: ")
except Exception as e:
print(f"Error generating AI description: {e}")
description = input("Enter description manually: ")
# Add or update metadata
image_data = {
"filename": image_file,
"title": title,
"description": description,
"date_added": datetime.now().strftime("%Y-%m-%d")
}
if image_file in existing_images:
# Update existing entry
for i, img in enumerate(gallery_data["images"]):
if img["filename"] == image_file:
gallery_data["images"][i] = image_data
break
else:
# Add new entry
gallery_data["images"].append(image_data)
# Save updated metadata
with open(metadata_file, 'w') as f:
json.dump(gallery_data, f, indent=2)
print("\nGenerating HTML gallery...")
# Generate HTML gallery
html_output = f"""<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{gallery_data['title']}</title>
<style>
body {{
font-family: Arial, sans-serif;
margin: 0;
padding: 20px;
background-color: #f5f5f5;
}}
h1 {{
text-align: center;
color: #333;
}}
.gallery {{
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
grid-gap: 20px;
max-width: 1200px;
margin: 0 auto;
}}
.gallery-item {{
border-radius: 5px;
overflow: hidden;
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16);
background-color: white;
transition: transform 0.3s;
}}
.gallery-item:hover {{
transform: translateY(-5px);
}}
.gallery-image {{
width: 100%;
height: 200px;
object-fit: cover;
}}
.gallery-content {{
padding: 15px;
}}
.gallery-title {{
margin-top: 0;
color: #333;
}}
.gallery-description {{
color: #666;
font-size: 0.9em;
}}
.gallery-date {{
color: #999;
font-size: 0.8em;
text-align: right;
margin-top: 10px;
}}
footer {{
text-align: center;
margin-top: 30px;
color: #999;
font-size: 0.8em;
}}
</style>
</head>
<body>
<h1>{gallery_data['title']}</h1>
<div class="gallery">
"""
# Add each image to the gallery
for img in gallery_data["images"]:
html_output += f""" <div class="gallery-item">
<img src="../{image_dir}/{img['filename']}" alt="{img['title']}" class="gallery-image">
<div class="gallery-content">
<h3 class="gallery-title">{img['title']}</h3>
<p class="gallery-description">{img['description']}</p>
<p class="gallery-date">Added: {img['date_added']}</p>
</div>
</div>
"""
# Complete the HTML
html_output += """ </div>
<footer>
<p>Created with Image Gallery Creator</p>
</footer>
</body>
</html>
"""
# Save the HTML file
html_file = os.path.join(output_dir, "index.html")
with open(html_file, 'w') as f:
f.write(html_output)
print(f"\nGallery created successfully!")
print(f"HTML file saved to: {html_file}")
print(f"Open this file in a web browser to view your gallery.")
# Optional: Open the gallery in the default browser
try_open = input("\nOpen gallery in browser? (y/n): ").lower() == 'y'
if try_open:
try:
import webbrowser
webbrowser.open('file://' + os.path.abspath(html_file))
except Exception as e:
print(f"Could not open browser: {e}")
# Run the gallery creator
if __name__ == "__main__":
create_image_gallery()
Extension Ideas¶
- Add image filtering by tags or categories
- Implement image resising and thumbnail generation
- Create a lightbox effect for viewing full-sise images
- Add EXIF data extraction to display camera information
- Implement a theme selector with different gallery styles
- Create a server-side component to host the gallery online