diff --git a/backend/scripts/README.md b/backend/scripts/README.md new file mode 100644 index 0000000..2dc3487 --- /dev/null +++ b/backend/scripts/README.md @@ -0,0 +1,225 @@ +# Eye Catalog Import Scripts + +Tools for populating your carved eye catalog with public domain examples. + +--- + +## Quick Start + +### 1. Download Classical Eyes + +Follow the guide: `/docs/PUBLIC_DOMAIN_EYE_SOURCES.md` + +**Best sources:** +- Metropolitan Museum (CC0) +- Smithsonian Open Access +- Getty Museum Open Content + +**Download 10-20 high-res images** of carved eyes from classical sculptures. + +--- + +### 2. Crop the Eyes + +Use any image editor (Photoshop, GIMP, Preview, etc.): + +1. Open statue photo +2. Zoom in on eye +3. Crop just the eye (include eyelids, socket, tear duct) +4. Save as PNG with descriptive name: + - `greek_serene_left.png` + - `roman_fierce_right.png` + - `egyptian_wise_left.png` + +--- + +### 3. Import to Catalog + +**Easy way (one at a time):** +```bash +cd backend/scripts + +# Import a Greek serene eye +python import_eyes.py greek_serene_left.png \ + --emotion serene \ + --side left \ + --style greek + +# Import a Roman fierce eye +python import_eyes.py roman_fierce_right.png \ + --emotion fierce \ + --side right \ + --style roman +``` + +**Batch import:** +```bash +# Import all Greek eyes at once +python import_eyes.py greek_*.png \ + --emotion serene \ + --side both \ + --style greek + +# Import all Roman eyes +python import_eyes.py roman_*.png \ + --emotion fierce \ + --side both \ + --style roman +``` + +--- + +## Available Options + +### Emotions +- `serene` - Peaceful, calm (most classical Greek) +- `fierce` - Intense, powerful (Hellenistic, Alexander) +- `wise` - Aged, experienced (Roman senators) +- `peaceful` - Gentle, kind (Archaic Greek) +- `joyful` - Happy, smiling (rare in classical) +- `sorrowful` - Sad, mourning (some Hellenistic) +- `neutral` - Default, no strong emotion + +### Styles +- `greek` - Classical Greek (450-400 BCE) +- `roman` - Roman Republican/Imperial +- `egyptian` - Ancient Egyptian carved eyes +- `renaissance` - Renaissance sculpture +- `baroque` - Baroque period +- `modern` - Contemporary carving +- `custom` - Your own style + +### Sides +- `left` - Left eye +- `right` - Right eye +- `both` - Can be used for either (symmetric) + +--- + +## Example Workflow + +### Build a Complete Catalog + +```bash +# 1. Download eyes from Met Museum +# (See PUBLIC_DOMAIN_EYE_SOURCES.md) + +# 2. Crop and save them: +# greek_serene_left.png +# greek_serene_right.png +# roman_fierce_left.png +# roman_fierce_right.png +# etc. + +# 3. Import them all: + +python import_eyes.py greek_serene_left.png --emotion serene --side left --style greek +python import_eyes.py greek_serene_right.png --emotion serene --side right --style greek +python import_eyes.py roman_fierce_left.png --emotion fierce --side left --style roman +python import_eyes.py roman_fierce_right.png --emotion fierce --side right --style roman + +# Or batch: +python import_eyes.py greek_*.png --emotion serene --side both --style greek +python import_eyes.py roman_*.png --emotion fierce --side both --style roman +``` + +--- + +## Recommended Starting Collection + +### 10 Essential Eyes + +1. **Greek Serene Left** (peaceful carvings) +2. **Greek Serene Right** +3. **Greek Archaic Left** (stylized, simple) +4. **Greek Archaic Right** +5. **Roman Fierce Left** (powerful portraits) +6. **Roman Fierce Right** +7. **Roman Wise Left** (aged, realistic) +8. **Roman Wise Right** +9. **Egyptian Stylized Left** (distinctive style) +10. **Egyptian Stylized Right** + +This gives you 5 styles/emotions to start! + +--- + +## Check Your Catalog + +### Via API + +```bash +# List all eyes in catalog +curl http://localhost:8101/patches/?category=carved_eye + +# Filter by emotion +curl http://localhost:8101/patches/?category=carved_eye&tags=serene + +# Filter by style +curl http://localhost:8101/patches/?tags=greek +``` + +### Via Web Interface + +Go to: `http://your-server:3080` + +Navigate to patch library to browse your eyes visually. + +--- + +## Advanced: Seed Script + +For batch importing from the `seed_data/eyes/` directory: + +```bash +# 1. Place all cropped eyes in: +mkdir -p seed_data/eyes/ +# Copy your eye images there + +# 2. Edit seed_eye_catalog.py to add metadata + +# 3. Run: +python seed_eye_catalog.py +``` + +This auto-imports all eyes in `seed_data/eyes/` with pre-configured metadata. + +--- + +## Tips + +1. **High resolution:** Use images 1000px+ for best results +2. **Clean crops:** Include some surrounding area, not just the eyeball +3. **Consistent naming:** Use descriptive filenames +4. **Test first:** Import 2-3 eyes to test the workflow +5. **Build gradually:** Start with 10 eyes, expand as needed + +--- + +## Troubleshooting + +**"File not found":** +- Make sure you're in `backend/scripts/` directory +- Use full path or relative path to image + +**"Database connection error":** +- Make sure backend is running: `docker compose up backend` +- Check database exists: `ls -la ../../data/` + +**"Import failed":** +- Check image format (PNG, JPG supported) +- Verify file isn't corrupted +- Check file permissions + +--- + +## Next Steps + +After importing eyes: + +1. **Test them:** Apply to a colored photo via API +2. **Refine:** Add more variations as needed +3. **Build library:** Aim for 20-30 eyes covering all emotions +4. **Share:** Your best eyes can be exported and shared + +**Your catalog of master sculptor's eyes is ready to use!** diff --git a/backend/scripts/import_eyes.py b/backend/scripts/import_eyes.py new file mode 100755 index 0000000..216f524 --- /dev/null +++ b/backend/scripts/import_eyes.py @@ -0,0 +1,210 @@ +#!/usr/bin/env python3 +""" +Quick eye import script + +Usage: + python import_eyes.py greek_serene_left.png --emotion serene --side left --style greek + python import_eyes.py *.png --emotion fierce --style roman + +This will add eyes to the patch library with proper metadata. +""" + +import sys +import argparse +from pathlib import Path +from PIL import Image + +# Add parent directory to path to import app modules +sys.path.insert(0, str(Path(__file__).parent.parent)) + +from app.database import SessionLocal +from app.models.patch import Patch +from app.services.patch_library import PatchLibraryService + + +def import_eye( + image_path: Path, + emotion: str, + side: str, + style: str, + description: str = None +): + """ + Import a single eye image into the catalog + + Args: + image_path: Path to eye image file + emotion: serene, fierce, wise, peaceful, joyful, sorrowful + side: left, right, both + style: greek, roman, egyptian, renaissance, custom + description: Optional custom description + """ + + db = SessionLocal() + patch_service = PatchLibraryService() + + # Generate name from filename if not provided + name = image_path.stem.replace('_', ' ').title() + + # Auto-generate description if not provided + if not description: + description = f"{style.title()} carved eye, {emotion} expression, {side} side. Suitable for CNC wood carving." + + # Generate tags + tags = f"{style}, {emotion}, {side}, carved, cnc-ready, wood-carving" + + print(f"\nšŸ“ø Importing: {name}") + print(f" File: {image_path.name}") + print(f" Style: {style}") + print(f" Emotion: {emotion}") + print(f" Side: {side}") + + try: + # Create patch record + patch = Patch( + name=name, + description=description, + source_type="imported", + category="carved_eye", + tags=tags, + width=0, + height=0, + user_id=None, + file_path="" + ) + + db.add(patch) + db.commit() + db.refresh(patch) + + # Save image file + file_path = patch_service.save_patch_from_file( + patch.id, + str(image_path), + create_thumb=True + ) + + # Get and update dimensions + width, height = patch_service.get_patch_size(patch.id) + patch.width = width + patch.height = height + patch.file_path = file_path + patch.thumbnail_path = str(patch_service.get_thumbnail_path(patch.id)) + + db.commit() + + print(f"āœ… Successfully imported!") + print(f" ID: {patch.id}") + print(f" Size: {width}x{height}px") + + return patch.id + + except Exception as e: + print(f"āŒ Error importing: {e}") + db.rollback() + return None + + finally: + db.close() + + +def main(): + parser = argparse.ArgumentParser( + description="Import carved eye images into the patch library", + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=""" +Examples: + # Import a single eye + python import_eyes.py greek_serene_left.png --emotion serene --side left --style greek + + # Import multiple eyes with same metadata + python import_eyes.py roman_*.png --emotion fierce --side both --style roman + + # With custom description + python import_eyes.py statue_eye.png --emotion wise --side right --style roman --description "Emperor Augustus portrait eye" + +Emotions: serene, fierce, wise, peaceful, joyful, sorrowful, neutral +Sides: left, right, both +Styles: greek, roman, egyptian, renaissance, baroque, modern, custom + """ + ) + + parser.add_argument( + 'images', + nargs='+', + help='Image file(s) to import (supports wildcards)' + ) + + parser.add_argument( + '--emotion', + required=True, + choices=['serene', 'fierce', 'wise', 'peaceful', 'joyful', 'sorrowful', 'neutral'], + help='Emotional expression of the eye' + ) + + parser.add_argument( + '--side', + required=True, + choices=['left', 'right', 'both'], + help='Which eye (left or right)' + ) + + parser.add_argument( + '--style', + required=True, + choices=['greek', 'roman', 'egyptian', 'renaissance', 'baroque', 'modern', 'custom'], + help='Carving style/period' + ) + + parser.add_argument( + '--description', + help='Custom description (optional)' + ) + + args = parser.parse_args() + + # Resolve wildcards and get all image files + image_files = [] + for pattern in args.images: + path = Path(pattern) + if '*' in pattern: + # Wildcard - expand it + parent = path.parent if path.parent.exists() else Path('.') + image_files.extend(parent.glob(path.name)) + else: + # Single file + if path.exists(): + image_files.append(path) + else: + print(f"āš ļø File not found: {pattern}") + + if not image_files: + print("āŒ No image files found!") + return + + print(f"\nšŸŽØ Importing {len(image_files)} eye image(s) into catalog...") + print(f" Style: {args.style}") + print(f" Emotion: {args.emotion}") + print(f" Side: {args.side}") + print("="*60) + + imported_count = 0 + for image_path in image_files: + patch_id = import_eye( + image_path, + args.emotion, + args.side, + args.style, + args.description + ) + if patch_id: + imported_count += 1 + + print("="*60) + print(f"\nāœ… Import complete! {imported_count}/{len(image_files)} eyes added to catalog") + print(f"\nšŸ’” Access your eye catalog at: http://your-server:3080") + print(f" Or via API: GET /patches/?category=carved_eye") + + +if __name__ == "__main__": + main() diff --git a/backend/scripts/seed_eye_catalog.py b/backend/scripts/seed_eye_catalog.py new file mode 100644 index 0000000..bee23fc --- /dev/null +++ b/backend/scripts/seed_eye_catalog.py @@ -0,0 +1,176 @@ +""" +Seed the patch library with classical carved eyes from public domain sources + +This script helps pre-populate the eye catalog with examples from: +- Greek statues (Metropolitan Museum, Louvre) +- Roman sculptures (Smithsonian, British Museum) +- Renaissance carvings +- Ancient Egyptian carved eyes + +All images should be public domain (CC0, Public Domain Mark) +""" + +import asyncio +import httpx +from pathlib import Path +from PIL import Image +from io import BytesIO + +# Public domain eye examples to seed the catalog +# These are examples - you would add actual URLs from museum APIs +CLASSICAL_EYES = [ + { + "name": "Greek Statue - Serene Left Eye", + "description": "Classical Greek marble carving, convex eyeball, defined upper lid, deep socket. Perfect for serene expressions.", + "category": "carved_eye", + "tags": "greek, serene, left, marble, classical, convex, deep-socket", + "style": "greek_classical", + "emotion": "serene", + "side": "left", + "source_url": "https://images.metmuseum.org/...", # Example + "source": "Metropolitan Museum of Art - Public Domain" + }, + { + "name": "Roman Sculpture - Fierce Right Eye", + "description": "Roman marble, prominent brow ridge, intense gaze, sharp eyelid definition.", + "category": "carved_eye", + "tags": "roman, fierce, right, marble, intense, sharp-detail", + "style": "roman_classical", + "emotion": "fierce", + "side": "right", + "source_url": "https://...", + "source": "Smithsonian - CC0" + }, + { + "name": "Greek Kouros - Peaceful Left Eye", + "description": "Archaic Greek style, almond-shaped, subtle carving, peaceful expression.", + "category": "carved_eye", + "tags": "greek, peaceful, left, archaic, almond-shaped, subtle", + "style": "greek_archaic", + "emotion": "peaceful", + "side": "left", + "source_url": "https://...", + "source": "Getty Museum - Public Domain" + }, + { + "name": "Roman Portrait - Wise Right Eye", + "description": "Late Roman period, detailed eyelids, slight downward gaze, wisdom and age.", + "category": "carved_eye", + "tags": "roman, wise, right, portrait, detailed, aged", + "style": "roman_portrait", + "emotion": "wise", + "side": "right", + "source_url": "https://...", + "source": "British Museum - CC0" + }, +] + +async def download_image(url: str) -> bytes: + """Download image from URL""" + async with httpx.AsyncClient() as client: + response = await client.get(url) + response.raise_for_status() + return response.content + +async def crop_eye_from_statue(image_bytes: bytes, crop_box: tuple) -> bytes: + """ + Crop just the eye from a full statue photo + + Args: + image_bytes: Full statue image + crop_box: (left, top, right, bottom) coordinates + + Returns: + Cropped eye image bytes + """ + img = Image.open(BytesIO(image_bytes)) + eye = img.crop(crop_box) + + # Save as PNG + buffer = BytesIO() + eye.save(buffer, format='PNG') + return buffer.getvalue() + +async def seed_eye_catalog(): + """ + Seed the patch library with classical carved eyes + + NOTE: This is a template. You need to: + 1. Get actual public domain image URLs + 2. Manually crop the eyes (or provide crop coordinates) + 3. Run this to populate the catalog + """ + + from app.database import SessionLocal + from app.models.patch import Patch + from app.services.patch_library import PatchLibraryService + + db = SessionLocal() + patch_service = PatchLibraryService() + + print("Seeding eye catalog with classical carved eyes...") + + for eye_data in CLASSICAL_EYES: + print(f"\nAdding: {eye_data['name']}") + + # Create patch record + patch = Patch( + name=eye_data['name'], + description=eye_data['description'], + source_type="imported", + category=eye_data['category'], + tags=eye_data['tags'], + width=0, # Will be set after image save + height=0, + user_id=None, + file_path="" + ) + + db.add(patch) + db.commit() + db.refresh(patch) + + # Download and save image + # NOTE: You need to manually download/crop these first + # This is just the structure + + try: + # image_bytes = await download_image(eye_data['source_url']) + # cropped_eye = await crop_eye_from_statue(image_bytes, crop_box) + + # For now, you would manually place images in: + # ./seed_data/eyes/greek_serene_left.png + # ./seed_data/eyes/roman_fierce_right.png + # etc. + + seed_image_path = Path(__file__).parent / "seed_data" / "eyes" / f"{eye_data['style']}_{eye_data['emotion']}_{eye_data['side']}.png" + + if seed_image_path.exists(): + file_path = patch_service.save_patch_from_file( + patch.id, + str(seed_image_path), + create_thumb=True + ) + + # Get dimensions + width, height = patch_service.get_patch_size(patch.id) + patch.width = width + patch.height = height + patch.file_path = file_path + patch.thumbnail_path = str(patch_service.get_thumbnail_path(patch.id)) + + db.commit() + print(f"āœ… Added {eye_data['name']}") + else: + print(f"āš ļø Image not found: {seed_image_path}") + print(f" Please download and crop eye from: {eye_data['source']}") + + except Exception as e: + print(f"āŒ Error adding {eye_data['name']}: {e}") + db.rollback() + + db.close() + print("\nāœ… Eye catalog seeding complete!") + +if __name__ == "__main__": + asyncio.run(seed_eye_catalog()) diff --git a/docs/PUBLIC_DOMAIN_EYE_SOURCES.md b/docs/PUBLIC_DOMAIN_EYE_SOURCES.md new file mode 100644 index 0000000..f719c3e --- /dev/null +++ b/docs/PUBLIC_DOMAIN_EYE_SOURCES.md @@ -0,0 +1,300 @@ +# Public Domain Carved Eye Sources + +Where to find high-quality images of carved eyes from classical sculptures (all public domain). + +--- + +## Best Museums with Public Domain Images + +### 1. Metropolitan Museum of Art (CC0 Public Domain) + +**Website:** https://www.metmuseum.org/art/collection + +**Search tips:** +- Search: "greek statue marble head" +- Search: "roman portrait bust" +- Filter: "Public Domain" only +- Download: Click "Download" for high-resolution + +**Great examples:** +- Greek Kouros heads (Archaic period) +- Roman portrait busts +- Hellenistic marble sculptures + +**Direct collections:** +- Greek & Roman Art: https://www.metmuseum.org/art/collection/search#!?department=13 +- Filter by "Images" → "Public Domain" + +--- + +### 2. Smithsonian Open Access (CC0) + +**Website:** https://www.si.edu/openaccess + +**Features:** +- 3 million+ images +- All CC0 (no copyright restrictions) +- High-resolution downloads + +**Search:** +- "roman marble head" +- "greek sculpture eyes" +- "classical portrait bust" + +**API available:** https://api.si.edu/openaccess/api/v1.0/ + +--- + +### 3. Getty Museum (Open Content) + +**Website:** https://www.getty.edu/art/collection/ + +**Search tips:** +- Filter: "Open Content Program" +- Greek and Roman antiquities +- High-resolution IIIF images + +**Great for:** +- Archaic Greek sculptures +- Classical period heads +- Detailed close-ups + +--- + +### 4. Rijksmuseum (Public Domain) + +**Website:** https://www.rijksmuseum.nl/en/rijksstudio + +**Features:** +- Rijksstudio (free download tool) +- High-resolution images +- Classical sculpture collection + +--- + +### 5. British Museum (CC BY-NC-SA 4.0) + +**Website:** https://www.britishmuseum.org/collection + +**Note:** Some restrictions, but many images free for non-commercial use + +**Great for:** +- Egyptian carved eyes +- Greek marble heads +- Roman portraits + +--- + +### 6. Louvre Collections + +**Website:** https://collections.louvre.fr/en/ + +**Search:** "sculpture greek head" or "sculpture roman portrait" + +**Note:** Check individual image licenses + +--- + +## How to Find the Perfect Eyes + +### Search Strategy + +1. **Search for heads/busts, not full statues:** + - "greek marble head" + - "roman portrait bust" + - "classical sculpture face" + +2. **Specific periods:** + - "archaic greek kouros" (serene, stylized) + - "classical greek sculpture" (idealized, peaceful) + - "hellenistic sculpture" (emotional, dramatic) + - "roman portrait" (realistic, wise) + +3. **Look for close-ups:** + - Museums often provide detail shots + - Check "zoom" or "IIIF viewer" options + +--- + +## Recommended Starting Collection + +### Serene/Peaceful Eyes + +**Greek Classical Period (450-400 BCE):** +- Doryphoros (Spear Bearer) type +- Athena heads +- Apollo statues +- Smooth, idealized features +- Almond-shaped eyes +- Minimal lid detail + +**Best sources:** Met Museum, Getty + +--- + +### Fierce/Intense Eyes + +**Hellenistic Period (323-31 BCE):** +- Alexander the Great portraits +- Dying Gaul +- Laocoon group +- Dramatic expressions +- Deep-set eyes +- Strong brow ridges + +**Best sources:** Smithsonian, British Museum + +--- + +### Wise/Aged Eyes + +**Roman Republican Period:** +- Senator portraits +- Veristic portraits +- Realistic aging details +- Detailed wrinkles +- Saggy eyelids +- Life-like features + +**Best sources:** Met Museum, Getty + +--- + +### Stylized/Archaic Eyes + +**Greek Archaic Period (700-480 BCE):** +- Kouros statues +- Kore statues +- Almond-shaped +- Simplified forms +- "Archaic smile" +- Clean, simple carving + +**Best sources:** Getty, Met Museum + +--- + +## How to Download and Crop + +### Step 1: Find the Statue + +Example: Met Museum +1. Go to https://www.metmuseum.org/art/collection +2. Search: "roman portrait marble" +3. Filter: Public Domain only +4. Click on a good example + +### Step 2: Download High-Res + +1. Click "Download" button +2. Choose largest size (usually 4000px+) +3. Save to your computer + +### Step 3: Crop the Eyes + +Use any image editor (Photoshop, GIMP, etc.): + +1. Open the full statue image +2. Zoom in on one eye +3. Crop just the eye area: + - Include: eyeball, eyelids, tear duct, socket + - Leave some surrounding area for context + - Square or slightly rectangular crop + +4. Save as PNG: + - `greek_serene_left.png` + - `roman_fierce_right.png` + - etc. + +5. Repeat for other eye (if different) + +### Step 4: Organize + +Place cropped eyes in: +``` +./backend/scripts/seed_data/eyes/ +ā”œā”€ā”€ greek_serene_left.png +ā”œā”€ā”€ greek_serene_right.png +ā”œā”€ā”€ roman_fierce_left.png +ā”œā”€ā”€ roman_fierce_right.png +ā”œā”€ā”€ greek_peaceful_left.png +└── ... +``` + +### Step 5: Run Seed Script + +```bash +cd backend +python scripts/seed_eye_catalog.py +``` + +--- + +## Recommended Starting Collection (10 Eyes) + +To start, get these 10 eyes: + +### Greek Classical (Serene) +1. Left eye - Greek marble head +2. Right eye - Greek marble head + +### Greek Archaic (Stylized/Peaceful) +3. Left eye - Kouros statue +4. Right eye - Kouros statue + +### Hellenistic (Fierce/Dramatic) +5. Left eye - Alexander portrait +6. Right eye - Alexander portrait + +### Roman Republican (Wise/Aged) +7. Left eye - Roman senator bust +8. Right eye - Roman senator bust + +### Roman Imperial (Powerful) +9. Left eye - Emperor portrait +10. Right eye - Emperor portrait + +This gives you 5 emotional ranges Ɨ 2 eyes = 10 eyes to start! + +--- + +## Quick Links + +- **Met Museum Collection:** https://www.metmuseum.org/art/collection/search#!?department=13&showOnly=openAccess +- **Smithsonian Open Access:** https://www.si.edu/openaccess +- **Getty Open Content:** https://www.getty.edu/about/whatwedo/opencontent.html +- **Rijksmuseum API:** https://data.rijksmuseum.nl/object-metadata/api/ + +--- + +## Legal Notes + +- **CC0/Public Domain:** Use freely for any purpose +- **CC BY:** Must credit the source +- **CC BY-NC:** Non-commercial use only +- **Always check** individual image licenses + +For commercial carving business, stick to **CC0** or **Public Domain** images. + +--- + +## Tips for Best Results + +1. **High resolution:** Download largest size available (2000px+ minimum) +2. **Good lighting:** Look for evenly lit photographs +3. **Straight-on angle:** Avoid extreme angles +4. **Clear detail:** Can you see the eyelid lines clearly? +5. **Minimal damage:** Choose well-preserved sculptures + +--- + +## Next Steps + +1. Browse the museums above +2. Download 10-20 good eye examples +3. Crop them in an image editor +4. Place in `backend/scripts/seed_data/eyes/` +5. Run the seed script +6. Your catalog is ready! + +**You'll have a library of proven carved eyes from master sculptors spanning 2000+ years!**