Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c0fdbc4d4a | |||
| 39bd0a359c |
@@ -0,0 +1 @@
|
|||||||
|
.worktrees/
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
alain-ducase-bread|NOT FOUND
|
||||||
|
arugula-pesto-chicken-with-pecans-roasted-butternut|NOT FOUND
|
||||||
|
arugula-pesto-wheat-berries-recipe|NOT FOUND
|
||||||
|
asparagus-salad|NOT FOUND
|
||||||
|
authentic-cacio-e-pepe-recipe|NOT FOUND
|
||||||
|
baked-chile-relleno-with-black-beans|NOT FOUND
|
||||||
|
bang-bang-tofu|NOT FOUND
|
||||||
|
barbecue-chicken-with-crispy-pan-fried-okra-cheddar-biscuits|NOT FOUND
|
||||||
|
black-bean-and-corn-salad|NOT FOUND
|
||||||
|
blackened-shrimp-and-gouda-grits|NOT FOUND
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
butternut-turkey-chili-2|NOT FOUND
|
||||||
|
butternut-turkey-chili-with-sweet-peppers-spiced-pepitas-queso-fresco|NOT FOUND
|
||||||
|
cabbage-salad|NOT FOUND
|
||||||
|
cauliflower-milanese|NOT FOUND
|
||||||
|
chana-chickpea-salad|NOT FOUND
|
||||||
|
chicken-and-pumpkin-gnocchi-with-ricotta|NOT FOUND
|
||||||
|
chickpea-butter-curry|NOT FOUND
|
||||||
|
chickpea-butter-curry-2|NOT FOUND
|
||||||
|
chinese-orange-shrimp|NOT FOUND
|
||||||
|
chocolate-mousse-cake-with-raspberries|NOT FOUND
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
cilantro-pesto-shrimp-over-orzo|NOT FOUND
|
||||||
|
crispy-roasted-chickpeas-garbanzo-beans|NOT FOUND
|
||||||
|
crispy-roasted-chickpeas-garbanzo-beans-2|NOT FOUND
|
||||||
|
dried-fava-soup|NOT FOUND
|
||||||
|
easy-lemon-rosemary-white-bean-soup|NOT FOUND
|
||||||
|
easy-lemon-rosemary-white-bean-soup-2|NOT FOUND
|
||||||
|
gaja-s-bulgogi-lettuce-wraps|NOT FOUND
|
||||||
|
gochugaru-honey-salmon|NOT FOUND
|
||||||
|
indian-spiced-chicken-2|NOT FOUND
|
||||||
|
kale-and-chestnut-stew|NOT FOUND
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
kkanpoong-tofu|NOT FOUND
|
||||||
|
korean-shrimp-tacos|NOT FOUND
|
||||||
|
kung-pao-shrimp-with-sichuan-roasted-green-beans|NOT FOUND
|
||||||
|
lactation-cookies|NOT FOUND
|
||||||
|
lactation-cookies-2|NOT FOUND
|
||||||
|
moroccan-spiced-lentil-and-chickpea-soup|NOT FOUND
|
||||||
|
moroccan-spiced-lentil-chickpea-soup|NOT FOUND
|
||||||
|
orange-rolls|NOT FOUND
|
||||||
|
palak-paneer|NOT FOUND
|
||||||
|
pecan-brown-butter-trout|NOT FOUND
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
roasted-pumpkin-sage|NOT FOUND
|
||||||
|
saag-paneer|NOT FOUND
|
||||||
|
sheet-pan-miso-chicken-with-radishes-and-lime|NOT FOUND
|
||||||
|
spaghetti-carbonara|NOT FOUND
|
||||||
|
spaghetti-squash-w-chickpeas-and-kale|NOT FOUND
|
||||||
|
spanakopita|NOT FOUND
|
||||||
|
spicy-shrimp-paella|NOT FOUND
|
||||||
|
thai-veggie-pad-see-ew|NOT FOUND
|
||||||
|
warm-up-with-a-quick-lemony-chicken-soup|NOT FOUND
|
||||||
|
west-african-peanut-chicken|NOT FOUND
|
||||||
@@ -0,0 +1,450 @@
|
|||||||
|
# Recipe Image Ingestion Implementation Plan
|
||||||
|
|
||||||
|
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||||
|
|
||||||
|
**Goal:** Give every `.cook` recipe file an `image:` field in YAML frontmatter pointing to `https://roux.roo.lol/recipe-images/<slug>.webp`, and download each image locally.
|
||||||
|
|
||||||
|
**Architecture:** Three parallel batches — (1) relink the 19 existing images, (2) discover + download + link 48 missing images (recipes with frontmatter), (3) create frontmatter + discover + link 9 more (recipes without frontmatter). Use subagent parallel dispatch for image discovery to keep wall-clock time manageable.
|
||||||
|
|
||||||
|
**Tech Stack:** bash, curl, ImageMagick (convert), subagent researcher for web image search
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 0: Setup — slug map, image dir, helper script
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Create: `/home/jbrechtel/recipes/docs/slugs.csv`
|
||||||
|
- Modify: none yet
|
||||||
|
|
||||||
|
- [ ] **Step 1: Generate slug mapping**
|
||||||
|
|
||||||
|
Run a one-liner that prints every `.cook` file with its slugified stem:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/jbrechtel/recipes
|
||||||
|
for f in *.cook; do
|
||||||
|
stem="${f%.cook}"
|
||||||
|
slug=$(echo "$stem" \
|
||||||
|
| tr '[:upper:]' '[:lower:]' \
|
||||||
|
| sed -e 's/[^a-z0-9]/-/g' -e 's/--*/-/g' -e 's/^-//' -e 's/-$//')
|
||||||
|
echo "$f|$slug"
|
||||||
|
done > docs/slugs.csv
|
||||||
|
head docs/slugs.csv
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: a pipe-delimited CSV like `Alain-Ducase-Bread.cook|alain-ducase-bread`.
|
||||||
|
|
||||||
|
- [ ] **Step 2: Create image directory**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir -p /home/jbrechtel/recipes/recipe-images
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 3: Classify each recipe**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/jbrechtel/recipes
|
||||||
|
echo "=== Already has image ==="
|
||||||
|
while IFS='|' read -r f slug; do
|
||||||
|
if grep -q "^image:" "$f" 2>/dev/null; then echo "$f|$slug"; fi
|
||||||
|
done < docs/slugs.csv > docs/has-image.csv
|
||||||
|
|
||||||
|
echo "=== Has frontmatter, no image ==="
|
||||||
|
while IFS='|' read -r f slug; do
|
||||||
|
if head -1 "$f" 2>/dev/null | grep -q "^---"; then
|
||||||
|
if ! grep -q "^image:" "$f" 2>/dev/null; then echo "$f|$slug"; fi
|
||||||
|
fi
|
||||||
|
done < docs/slugs.csv > docs/no-image-has-fm.csv
|
||||||
|
|
||||||
|
echo "=== No frontmatter ==="
|
||||||
|
while IFS='|' read -r f slug; do
|
||||||
|
if ! head -1 "$f" 2>/dev/null | grep -q "^---"; then echo "$f|$slug"; fi
|
||||||
|
done < docs/slugs.csv > docs/no-fm.csv
|
||||||
|
|
||||||
|
wc -l docs/has-image.csv docs/no-image-has-fm.csv docs/no-fm.csv
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: 19 / 48 / 9 lines respectively.
|
||||||
|
|
||||||
|
- [ ] **Step 4: Commit setup**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/jbrechtel/recipes
|
||||||
|
git add docs/slugs.csv docs/has-image.csv docs/no-image-has-fm.csv docs/no-fm.csv
|
||||||
|
git commit -m "chore: add recipe slug mapping and classification CSVs"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 1: Download & relink existing images (19 recipes)
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: each of the 19 `.cook` files listed in `docs/has-image.csv`
|
||||||
|
- Create: `recipe-images/<slug>.webp` for each
|
||||||
|
|
||||||
|
- [ ] **Step 1: Write batch relink script**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/jbrechtel/recipes
|
||||||
|
cat > bin/batch-relink.sh << 'SCRIPT'
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
while IFS='|' read -r file slug; do
|
||||||
|
url=$(grep "^image:" "$file" | sed 's/^image:[[:space:]]*//')
|
||||||
|
echo "[$slug] Downloading from $url"
|
||||||
|
curl -sL -o "recipe-images/$slug.webp" "$url" || echo "[$slug] DOWNLOAD FAILED"
|
||||||
|
done
|
||||||
|
SCRIPT
|
||||||
|
chmod +x bin/batch-relink.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 2: Run relink batch**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/jbrechtel/recipes
|
||||||
|
bash bin/batch-relink.sh < docs/has-image.csv
|
||||||
|
ls recipe-images/ | wc -l
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: 19 `.webp` files in `recipe-images/`.
|
||||||
|
|
||||||
|
- [ ] **Step 3: Verify all downloads succeeded**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/jbrechtel/recipes
|
||||||
|
while IFS='|' read -r file slug; do
|
||||||
|
if [ ! -f "recipe-images/$slug.webp" ]; then
|
||||||
|
echo "MISSING: $slug.webp"
|
||||||
|
fi
|
||||||
|
done < docs/has-image.csv
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: no output (all present).
|
||||||
|
|
||||||
|
- [ ] **Step 4: Update image fields in the 19 .cook files**
|
||||||
|
|
||||||
|
Use a script to replace each existing `image:` line with the new URL:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/jbrechtel/recipes
|
||||||
|
cat > bin/update-image-field.sh << 'SCRIPT'
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
while IFS='|' read -r file slug; do
|
||||||
|
new_url="https://roux.roo.lol/recipe-images/$slug.webp"
|
||||||
|
# Replace the image line in-place using sed
|
||||||
|
sed -i "s|^image:.*|image: $new_url|" "$file"
|
||||||
|
echo "[$slug] Updated image field"
|
||||||
|
done
|
||||||
|
SCRIPT
|
||||||
|
chmod +x bin/update-image-field.sh
|
||||||
|
bash bin/update-image-field.sh < docs/has-image.csv
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 5: Verify the updates**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/jbrechtel/recipes
|
||||||
|
while IFS='|' read -r file slug; do
|
||||||
|
expected="https://roux.roo.lol/recipe-images/$slug.webp"
|
||||||
|
actual=$(grep "^image:" "$file" | sed 's/^image:[[:space:]]*//')
|
||||||
|
if [ "$actual" != "$expected" ]; then
|
||||||
|
echo "MISMATCH: $file — expected $expected, got $actual"
|
||||||
|
fi
|
||||||
|
done < docs/has-image.csv
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: no output (all match).
|
||||||
|
|
||||||
|
- [ ] **Step 6: Commit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/jbrechtel/recipes
|
||||||
|
git add recipe-images/ bin/
|
||||||
|
git commit -m "feat: download and relink existing recipe images to roux.roo.lol"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 2: Find & download images for 48 recipes with frontmatter but no image
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: each of the 48 `.cook` files listed in `docs/no-image-has-fm.csv`
|
||||||
|
- Create: `recipe-images/<slug>.webp` for each
|
||||||
|
|
||||||
|
Approach: Use parallel subagent dispatches, each subagent handling a small batch of recipes. The subagent will search the web for an appropriate image URL for each recipe, then the parent session downloads and links.
|
||||||
|
|
||||||
|
- [ ] **Step 1: Split the 48 recipes into manageable batches**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/jbrechtel/recipes
|
||||||
|
split -l 8 docs/no-image-has-fm.csv docs/batch-no-image-
|
||||||
|
ls docs/batch-no-image-*
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: 6 files (48 ÷ 8 = 6 batches).
|
||||||
|
|
||||||
|
- [ ] **Step 2: Dispatch parallel subagents for image discovery**
|
||||||
|
|
||||||
|
For each batch file, dispatch a researcher subagent with task:
|
||||||
|
|
||||||
|
> "For each recipe filename and slug in `docs/<batch-file>`, search the web to find ONE publicly accessible image URL of the finished dish that I can download with curl. Return the result as pipe-delimited lines: `<slug>|<image-url>` or `<slug>|NOT FOUND` if no good image is found."
|
||||||
|
|
||||||
|
Each subagent outputs to `docs/batch-no-image-<xx>-results.txt`.
|
||||||
|
|
||||||
|
Run 6 subagents in parallel (or sequentially if parallelism is limited).
|
||||||
|
|
||||||
|
- [ ] **Step 3: Download all discovered images**
|
||||||
|
|
||||||
|
Collect all results and download:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/jbrechtel/recipes
|
||||||
|
cat docs/batch-no-image-*-results.txt | while IFS='|' read -r slug url; do
|
||||||
|
if [ "$url" != "NOT FOUND" ] && [ -n "$url" ]; then
|
||||||
|
echo "[$slug] Downloading $url"
|
||||||
|
curl -sL -o "recipe-images/$slug.webp" "$url" || echo "[$slug] DOWNLOAD FAILED"
|
||||||
|
else
|
||||||
|
echo "[$slug] SKIPPED — no image found"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 4: Convert any non-WebP images**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/jbrechtel/recipes
|
||||||
|
for img in recipe-images/*; do
|
||||||
|
mime=$(file --mime-type -b "$img")
|
||||||
|
if [ "$mime" != "image/webp" ]; then
|
||||||
|
convert "$img" "$img" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
```
|
||||||
|
|
||||||
|
(ImageMagick's `convert` re-encodes to match extension. The `file` check is advisory; `convert` handles format detection.)
|
||||||
|
|
||||||
|
- [ ] **Step 5: Add image field to each .cook file**
|
||||||
|
|
||||||
|
For each line in `docs/no-image-has-fm.csv`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/jbrechtel/recipes
|
||||||
|
cat > bin/add-image-field.sh << 'SCRIPT'
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
while IFS='|' read -r file slug; do
|
||||||
|
# Only proceed if an image was actually downloaded
|
||||||
|
if [ -f "recipe-images/$slug.webp" ]; then
|
||||||
|
new_url="https://roux.roo.lol/recipe-images/$slug.webp"
|
||||||
|
# Insert image: line after the opening --- or after the last metadata field
|
||||||
|
# Find the line number of the closing --- and insert before it
|
||||||
|
awk -v url="$new_url" '
|
||||||
|
/^---/ && !seen { seen=1; print; next }
|
||||||
|
seen && /^---/ { print "image: " url; print; exit }
|
||||||
|
{ print }
|
||||||
|
' "$file" > "${file}.tmp" && mv "${file}.tmp" "$file"
|
||||||
|
echo "[$slug] Added image field"
|
||||||
|
else
|
||||||
|
echo "[$slug] SKIPPED — no downloaded image"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
SCRIPT
|
||||||
|
chmod +x bin/add-image-field.sh
|
||||||
|
bash bin/add-image-field.sh < docs/no-image-has-fm.csv
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 6: Verify**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/jbrechtel/recipes
|
||||||
|
while IFS='|' read -r file slug; do
|
||||||
|
expected="https://roux.roo.lol/recipe-images/$slug.webp"
|
||||||
|
actual=$(grep "^image:" "$file" | sed 's/^image:[[:space:]]*//')
|
||||||
|
if [ "$actual" != "$expected" ]; then
|
||||||
|
echo "MISSING or MISMATCH: $file"
|
||||||
|
fi
|
||||||
|
done < docs/no-image-has-fm.csv
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: no output (all match).
|
||||||
|
|
||||||
|
- [ ] **Step 7: Commit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/jbrechtel/recipes
|
||||||
|
git add recipe-images/ bin/ docs/batch-no-image-*-results.txt
|
||||||
|
git commit -m "feat: add images to 48 recipes with frontmatter"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 3: Add frontmatter + images for 9 recipes without frontmatter
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: each of the 9 `.cook` files listed in `docs/no-fm.csv`
|
||||||
|
- Create: `recipe-images/<slug>.webp` for each
|
||||||
|
|
||||||
|
- [ ] **Step 1: Inspect each no-frontmatter recipe to determine a title**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/jbrechtel/recipes
|
||||||
|
while IFS='|' read -r file slug; do
|
||||||
|
echo "=== $file ==="
|
||||||
|
head -5 "$file"
|
||||||
|
echo ""
|
||||||
|
done < docs/no-fm.csv
|
||||||
|
```
|
||||||
|
|
||||||
|
For each, determine a reasonable title. Use the filename stem (de-slugified) as the default title, or the first substantive line of the recipe.
|
||||||
|
|
||||||
|
- [ ] **Step 2: Dispatch subagent to find images for these 9 recipes**
|
||||||
|
|
||||||
|
Similar to Task 2 Step 2, but for the smaller batch. Either one batch of 9 or use the same split approach.
|
||||||
|
|
||||||
|
- [ ] **Step 3: Download images**
|
||||||
|
|
||||||
|
Same as Task 2 Step 3.
|
||||||
|
|
||||||
|
- [ ] **Step 4: Add YAML frontmatter + image field to each file**
|
||||||
|
|
||||||
|
For each file, prepend:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
---
|
||||||
|
title: <detected title>
|
||||||
|
description:
|
||||||
|
servings: 1
|
||||||
|
category: uncategorized
|
||||||
|
source: Unknown
|
||||||
|
image: https://roux.roo.lol/recipe-images/<slug>.webp
|
||||||
|
---
|
||||||
|
```
|
||||||
|
|
||||||
|
Using a script:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/jbrechtel/recipes
|
||||||
|
cat > bin/add-frontmatter.sh << 'SCRIPT'
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Input: pipe-delimited file|slug|title
|
||||||
|
while IFS='|' read -r file slug title; do
|
||||||
|
if [ ! -f "recipe-images/$slug.webp" ]; then
|
||||||
|
echo "[$slug] SKIPPED — no image downloaded"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
url="https://roux.roo.lol/recipe-images/$slug.webp"
|
||||||
|
cat > "${file}.tmp" << EOF
|
||||||
|
---
|
||||||
|
title: $title
|
||||||
|
description:
|
||||||
|
servings: 1
|
||||||
|
category: uncategorized
|
||||||
|
source: Unknown
|
||||||
|
image: $url
|
||||||
|
---
|
||||||
|
|
||||||
|
$(cat "$file")
|
||||||
|
EOF
|
||||||
|
mv "${file}.tmp" "$file"
|
||||||
|
echo "[$slug] Added frontmatter"
|
||||||
|
done
|
||||||
|
SCRIPT
|
||||||
|
chmod +x bin/add-frontmatter.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 5: Run the frontmatter addition**
|
||||||
|
|
||||||
|
First create the input with detected titles. The title for each should be extracted from the recipe content or derived from the filename. For example:
|
||||||
|
- `Caramel Cake.cook` → `Caramel Cake`
|
||||||
|
- `example-fried-rice.cook` → `Fried Rice`
|
||||||
|
- `shrimp-feta.cook` → `Shrimp Feta`
|
||||||
|
etc.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/jbrechtel/recipes
|
||||||
|
# Create a pipe-delimited file: filename|slug|title
|
||||||
|
while IFS='|' read -r file slug; do
|
||||||
|
# Extract a reasonable title from the recipe content
|
||||||
|
# Use the filename stem as a fallback
|
||||||
|
stem="${file%.cook}"
|
||||||
|
title="${stem//_/ }"
|
||||||
|
title="${title//-/ }"
|
||||||
|
echo "$file|$slug|$title"
|
||||||
|
done < docs/no-fm.csv > docs/no-fm-with-titles.csv
|
||||||
|
|
||||||
|
bash bin/add-frontmatter.sh < docs/no-fm-with-titles.csv
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 6: Verify**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/jbrechtel/recipes
|
||||||
|
while IFS='|' read -r file slug _; do
|
||||||
|
if ! head -1 "$file" | grep -q "^---"; then
|
||||||
|
echo "NO FRONTMATTER: $file"
|
||||||
|
elif ! grep -q "^image:" "$file"; then
|
||||||
|
echo "NO IMAGE: $file"
|
||||||
|
fi
|
||||||
|
done < docs/no-fm.csv
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: no output (all have frontmatter and image).
|
||||||
|
|
||||||
|
- [ ] **Step 7: Commit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/jbrechtel/recipes
|
||||||
|
git add recipe-images/ bin/ docs/no-fm-with-titles.csv
|
||||||
|
git commit -m "feat: add frontmatter and images to 9 recipes without frontmatter"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 4: Verification & cleanup
|
||||||
|
|
||||||
|
- [ ] **Step 1: Final full audit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/jbrechtel/recipes
|
||||||
|
all_ok=true
|
||||||
|
for f in *.cook; do
|
||||||
|
stem="${f%.cook}"
|
||||||
|
slug=$(echo "$stem" \
|
||||||
|
| tr '[:upper:]' '[:lower:]' \
|
||||||
|
| sed -e 's/[^a-z0-9]/-/g' -e 's/--*/-/g' -e 's/^-//' -e 's/-$//')
|
||||||
|
expected="https://roux.roo.lol/recipe-images/$slug.webp"
|
||||||
|
|
||||||
|
if ! grep -q "^image: $expected" "$f"; then
|
||||||
|
echo "FAIL: $f — missing or wrong image field"
|
||||||
|
all_ok=false
|
||||||
|
fi
|
||||||
|
if [ ! -f "recipe-images/$slug.webp" ]; then
|
||||||
|
echo "FAIL: recipe-images/$slug.webp does not exist"
|
||||||
|
all_ok=false
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if $all_ok; then
|
||||||
|
echo "ALL 78 RECIPES VERIFIED OK"
|
||||||
|
fi
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 2: Clean up temp files**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/jbrechtel/recipes
|
||||||
|
rm -f docs/batch-no-image-* docs/slugs.csv docs/has-image.csv docs/no-image-has-fm.csv docs/no-fm.csv docs/no-fm-with-titles.csv
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 3: Final commit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/jbrechtel/recipes
|
||||||
|
git add -A
|
||||||
|
git commit -m "chore: cleanup temp files after recipe image ingestion"
|
||||||
|
```
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
arugula-pesto-chicken-with-pecans-roasted-butternut|NOT FOUND - NO WEB ACCESS
|
||||||
|
asparagus-salad|NOT FOUND - NO WEB ACCESS
|
||||||
|
baked-chile-relleno-with-black-beans|NOT FOUND - NO WEB ACCESS
|
||||||
|
bang-bang-tofu|NOT FOUND - NO WEB ACCESS
|
||||||
|
barbecue-chicken-with-crispy-pan-fried-okra-cheddar-biscuits|NOT FOUND - NO WEB ACCESS
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
blackened-shrimp-and-gouda-grits|NOT FOUND
|
||||||
|
butternut-turkey-chili-2|NOT FOUND
|
||||||
|
butternut-turkey-chili-with-sweet-peppers-spiced-pepitas-queso-fresco|NOT FOUND
|
||||||
|
chana-chickpea-salad|NOT FOUND
|
||||||
|
chicken-and-pumpkin-gnocchi-with-ricotta|NOT FOUND
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
STATUS: BLOCKED — No web search or HTTP fetch tools available.
|
||||||
|
|
||||||
|
To complete this task, I need:
|
||||||
|
- web_search tool (to find recipe pages)
|
||||||
|
- web_fetch / url_fetch tool (to visit pages and extract og:image URLs)
|
||||||
|
|
||||||
|
Required results format (once tools are available):
|
||||||
|
|
||||||
|
chickpea-butter-curry|<image-url>
|
||||||
|
chickpea-butter-curry-2|<image-url>
|
||||||
|
chinese-orange-shrimp|<image-url>
|
||||||
|
chocolate-mousse-cake-with-raspberries|<image-url>
|
||||||
|
cilantro-pesto-shrimp-over-orzo|<image-url>
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
I am unable to complete this task with my current toolset. I only have `read` and `write` file tools available — I do **not** have any web search or HTTP fetch capability to:
|
||||||
|
|
||||||
|
1. Search Google for each recipe page
|
||||||
|
2. Visit a webpage and parse its HTML for `og:image` meta tags
|
||||||
|
|
||||||
|
The five recipes I need to search for are:
|
||||||
|
|
||||||
|
| Slug | Description |
|
||||||
|
|------|-------------|
|
||||||
|
| `crispy-roasted-chickpeas-garbanzo-beans` | Crispy Roasted Chickpeas (Garbanzo Beans) |
|
||||||
|
| `crispy-roasted-chickpeas-garbanzo-beans-2` | Crispy Roasted Chickpeas |
|
||||||
|
| `dried-fava-soup` | Dried Fava Soup 101cookbooks |
|
||||||
|
| `easy-lemon-rosemary-white-bean-soup` | Easy Lemon Rosemary White Bean Soup |
|
||||||
|
| `easy-lemon-rosemary-white-bean-soup-2` | Easy Lemon Rosemary White Bean Soup |
|
||||||
|
|
||||||
|
**I need either:**
|
||||||
|
- A web search tool (e.g., `web_search`, `duckduckgo`, `google_search`)
|
||||||
|
- An HTTP fetch tool (e.g., `fetch`, `curl`, `httpx`)
|
||||||
|
- Or direct image URLs provided to me so I can write them to `/home/jbrechtel/recipes/docs/search-results-ad.txt`
|
||||||
|
|
||||||
|
Can you provide the web search/fetch tools, or supply the `og:image` URLs directly so I can write the output file?
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
gaja-s-bulgogi-lettuce-wraps|NOT FOUND
|
||||||
|
gochugaru-honey-salmon|NOT FOUND
|
||||||
|
indian-spiced-chicken-2|NOT FOUND
|
||||||
|
kale-and-chestnut-stew|NOT FOUND
|
||||||
|
korean-shrimp-tacos|NOT FOUND
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
# Recipe Image Search Results
|
||||||
|
# Generated: 2026-05-21
|
||||||
|
# Status: Research subagent lacks web search and HTTP fetch tools.
|
||||||
|
# Results could not be obtained.
|
||||||
|
|
||||||
|
kung-pao-shrimp-with-sichuan-roasted-green-beans|ERROR: No web search/fetch tools available
|
||||||
|
lactation-cookies|ERROR: No web search/fetch tools available
|
||||||
|
lactation-cookies-2|ERROR: No web search/fetch tools available
|
||||||
|
moroccan-spiced-lentil-and-chickpea-soup|ERROR: No web search/fetch tools available
|
||||||
|
moroccan-spiced-lentil-chickpea-soup|ERROR: No web search/fetch tools available
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
# Research in progress - will be updated after web searches and page visits
|
||||||
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
spanakopita|NOT FOUND
|
||||||
|
spicy-shrimp-paella|NOT FOUND
|
||||||
|
thai-veggie-pad-see-ew|NOT FOUND
|
||||||
|
warm-up-with-a-quick-lemony-chicken-soup|NOT FOUND
|
||||||
|
west-african-peanut-chicken|NOT FOUND
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
# 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.
|
||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
# Progress — Complete
|
||||||
|
|
||||||
|
## Status
|
||||||
|
Done — but all results are NOT FOUND
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
Could not complete the task as intended. The available tools (read/write files) do not include web search or HTTP fetch capabilities, so I was unable to:
|
||||||
|
- Search Google for recipe pages
|
||||||
|
- Visit recipe websites
|
||||||
|
- Extract og:image meta tags or featured image URLs
|
||||||
|
|
||||||
|
All 5 entries were written as NOT FOUND.
|
||||||
|
|
||||||
|
## Output
|
||||||
|
`docs/search-results-ah.txt` has been written.
|
||||||
Reference in New Issue
Block a user