Analyses book cover images using the OpenAI Vision API and writes the results into a Google Sheet — one row per ISBN — with an inline thumbnail and a column for each data field returned by the model.
- The script scans a folder for
.jpgfiles namedISBN_cov.jpg(e.g.9780008663322_cov.jpg). - Each image is sent to the OpenAI Vision API together with the prompt
defined in
prompt.md. - The model returns a JSON object. Each key becomes a column in the sheet.
- A 100 px-wide thumbnail is created and uploaded to a Google Drive folder.
- A row is written to the Google Sheet: ISBN → Thumbnail → JSON fields.
- Re-processing the same image overwrites the existing row for that ISBN rather than creating a duplicate.
| Requirement | Notes |
|---|---|
| Python 3.11+ | Earlier 3.x versions may work but are untested |
| OpenAI account | Vision access required (GPT-4o or similar) |
| Google Cloud project | Free tier is sufficient |
| Google Sheet | Shared with the service account (see below) |
| Google Drive folder | For thumbnail storage; shared with the service account |
git clone <repo-url>
cd boldwoodtestpython -m venv .venv
source .venv/bin/activate # macOS / Linux
.venv\Scripts\activate # Windowspip install openai Pillow google-api-python-client google-auth- Go to https://console.cloud.google.com.
- Click Select a project → New Project, give it a name, and click Create.
In your new project, go to APIs & Services → Library and enable:
- Google Sheets API
- Google Drive API
- Go to APIs & Services → Credentials → Create Credentials → Service account.
- Give it a name (e.g.
image-processor) and click Done. - Click on the service account you just created, then go to the Keys tab.
- Click Add Key → Create new key → JSON and download the file.
- Save the downloaded file as
credentials.jsonin the project folder (alongsideimage_processor.py).
Security note:
credentials.jsongrants access to your Google account resources. Never commit it to version control. Add it to.gitignore.
- Open Google Drive and create a new folder
(e.g.
Book Cover Thumbnails). - Right-click the folder → Share, and share it with the service account's
email address (visible in the Credentials page, looks like
name@project-id.iam.gserviceaccount.com). Give it Editor access. - Copy the folder ID from its URL:
https://drive.google.com/drive/folders/THIS_PART_IS_THE_ID
- Create a new Google Sheet.
- Share it with the service account email and give it Editor access.
- Copy the Sheet ID from its URL:
https://docs.google.com/spreadsheets/d/THIS_PART_IS_THE_ID/edit
Open config.json and fill in your values:
{
"image_folder": "./images",
"prompt_file": "./prompt.md",
"openai_model": "gpt-4o",
"json_fields": ["description", "objects", "colors", "tags", "notes"],
"google_credentials_file": "./credentials.json",
"google_sheet_id": "YOUR_GOOGLE_SHEET_ID",
"google_drive_folder_id": "YOUR_GOOGLE_DRIVE_FOLDER_ID",
"thumbnail_row_height_px": 130
}| Key | Description |
|---|---|
image_folder |
Path to the folder containing ISBN_cov.jpg files |
prompt_file |
Path to the Markdown prompt file |
openai_model |
OpenAI model name (default: gpt-4o) |
json_fields |
Ordered list of JSON keys the model is expected to return; must match what prompt.md asks for |
google_credentials_file |
Path to the service account JSON key |
google_sheet_id |
ID copied from your Google Sheet URL |
google_drive_folder_id |
ID copied from your Google Drive folder URL |
thumbnail_row_height_px |
Row height in pixels to display the thumbnail (default: 130) |
Open image_processor.py and replace the placeholder near the top of the file:
OPENAI_API_KEY = "sk-..." # Replace this with your actual keyYour key can be found at https://platform.openai.com/api-keys.
Edit prompt.md to change what the model analyses and what fields it returns.
Important: the field names in prompt.md must match the values in the
json_fields list inside config.json. If you add or rename fields you must
update both files.
Example: to add a publisher field, add it to your prompt instructions and
update config.json:
"json_fields": ["description", "objects", "colors", "tags", "notes", "publisher"]Place your .jpg files in the folder specified by image_folder.
Filenames must follow the pattern:
9780008663322_cov.jpg
- Starts with the 13-digit ISBN.
- Followed by
_cov(or any other suffix — only the ISBN prefix matters). - Extension is
.jpg(case-insensitive).
python image_processor.pyTo use a different config file:
python image_processor.py /path/to/my_config.jsonProgress is printed to the terminal:
Found 3 image(s) to process.
9780008663322_cov.jpg ... OK (added, row appended)
9780241999999_cov.jpg ... OK (updated, row 3)
9780000000000_cov.jpg ... SKIPPED — Expected a 13-digit ISBN ...
All images processed.
| Column | Content |
|---|---|
| A | ISBN (13-digit, extracted from filename) |
| B | Thumbnail (=IMAGE(...) formula, 100 px wide) |
| C onwards | One column per field in json_fields |
Row 1 is the header row (written automatically on first run). Each subsequent row corresponds to one unique ISBN.
Simply run the script again after updating an image or the prompt. The script looks up each ISBN in column A and overwrites the existing row if found, or appends a new row if not.
| Symptom | Likely cause |
|---|---|
Error: Please replace OPENAI_API_KEY |
The API key placeholder was not replaced in image_processor.py |
No .jpg files found |
Check the image_folder path in config.json |
HttpError 403 from Google APIs |
The service account was not shared with the Sheet or Drive folder |
| Thumbnail shows broken image in Sheet | The Drive file permission was not set to public; try re-running the script |
| JSON fields missing in sheet | The model returned unexpected JSON; check the raw output by temporarily adding a print(raw_response) call after analyse_image() |
ValueError: Expected a 13-digit ISBN |
Filename does not start with a 13-digit number followed by _ |
image_processor.py Main script
config.json User-configurable settings
prompt.md Editable analysis prompt (sent to OpenAI)
credentials.json Google service account key (you provide this — do not commit)
README.md This file
images/ Place your ISBN_cov.jpg files here