Files
recipes/docs/specs/2026-05-21-recipe-images-design.md
T

72 lines
3.4 KiB
Markdown

# Recipe Image Ingestion Spec
**Goal:** Give every `.cook` recipe file in the repository a high-quality, relevant food image hosted at `https://roux.roo.lol/recipe-images/` and referenced in its YAML frontmatter.
## Scope
| Category | Count | Action |
|---|---|---|
| Has YAML frontmatter + already has `image:` | 19 | Download existing image, re-host, update URL |
| Has YAML frontmatter + no `image:` | 48 | Find + download image, add `image:` field |
| No YAML frontmatter | 9 | Add frontmatter with title, find + download image, add `image:` field |
| **Total** | **76** | |
## Image Filename Convention
Slugify the `.cook` filename stem:
1. Strip `.cook` extension
2. Lowercase
3. Replace runs of non-alphanumeric characters (spaces, punctuation, `&`, etc.) with a single hyphen
4. Strip leading/trailing hyphens
5. Append `.webp`
**Examples:**
- `Black Bean and Corn Salad.cook``black-bean-and-corn-salad.webp`
- `BUTTERNUT & TURKEY CHILI with sweet peppers, spiced pepitas & queso fresco.cook``butternut-turkey-chili-with-sweet-peppers-spiced-pepitas-queso-fresco.webp`
- `Chickpea_Butter_Curry.cook``chickpea-butter-curry.webp`
## Image URL Format
```
https://roux.roo.lol/recipe-images/<slug>.webp
```
## Image Sourcing
### For recipes that already have an `image:` field
- Download the image from its current URL (e.g., `https://kitchen.roo.lol/data/images/<uuid>.webp`)
- Save locally as `<slug>.webp`
- Update the `image:` field to `https://roux.roo.lol/recipe-images/<slug>.webp`
### For recipes without an `image:` field
- Use the recipe title (from frontmatter or content) to search for a relevant, free-to-use food image online
- Prefer reputable recipe sites, Unsplash/Pexels, or other permissively-licensed sources
- Download as `<slug>.webp`
- Add `image: https://roux.roo.lol/recipe-images/<slug>.webp` to the frontmatter
### For recipes without frontmatter
- Parse the recipe content to determine a title (from context, first line, or filename)
- Construct minimal YAML frontmatter: `---`, `title: <detected title>`, `---`
- Find and download image as above
- Insert frontmatter + image field above the recipe body
## Implementation Approach
1. **Batch by category** to minimize context switching:
- Batch 1: 19 existing-image recipes (download + relink)
- Batch 2: 48 no-image recipes with frontmatter (find + download + add field)
- Batch 3: 9 no-frontmatter recipes (create frontmatter + find + download + add field)
2. **For image discovery**, use a web-search agent to find an appropriate image URL for each recipe, then download via `curl`.
3. **Parallelize** image discovery across multiple subagent workers to keep total time reasonable.
## Edge Cases
- **Duplicate-ish recipes** (e.g., `butternut-turkey-chili.cook`, `Butternut Turkey Chili.cook`, `BUTTERNUT & TURKEY CHILI...`): Each gets its own image slug. They may share similar images, but each file gets its own entry.
- **Image download failure**: If an image URL is unreachable (for existing images) or no suitable image is found (for new ones), log the recipe slug and skip it.
- **Special characters in filenames**: Slugify handles `&`, `'`, `(`, `)`, etc. by collapsing them into hyphens.
- **Existing image URLs that are already in the target format**: Skip re-download (they're already correct).
- **Non-WebP source images**: Downloaded images should be saved as `.webp`. If the source is not WebP, use `ffmpeg` or `convert` to re-encode.