Here's the complete rayray architecture in a copyable format: MARKDOWN # rayray Architecture ## System Overview ┌─────────────────────────────────────────────────────────────────┐ │ rayray System │ ├─────────────────────────────────────────────────────────────────┤ │ ┌──────────────┐ │ │ │ File Input │ │ │ │ Directory │ │ │ │ or URL │ │ │ └──────┬───────┘ │ │ │ │ │ ▼ │ │ ┌──────────────────┐ │ │ │ Metadata │ │ │ │ Extractor │ │ │ │ (Per File) │ │ │ └─────────┬──────┘ │ │ │ │ │ ▼ │ │ ┌──────────────────┐ │ │ │ Metadata │ │ │ │ Normalizer │ │ │ │ (Schema) │ │ │ └─────────┬──────┘ │ │ │ │ │ ▼ │ │ ┌──────────────────┐ │ │ │ Metadata │ │ │ │ Writer │ │ │ │ (Batch) │ │ │ └─────────┬──────┘ │ │ │ │ │ ▼ │ │ ┌──────────────────┐ │ │ │ Database │ │ │ │ Layer │ │ │ │ (Persistent) │ │ │ └──────────────────┘ │ └─────────────────────────────────────────────────────────────────┘ TEXT ### Component Breakdown #### 1. Metadata Extractor (Per-File Processing) **Responsibilities:** - Read file headers without loading full content into memory - Parse format-specific metadata structures - Handle binary metadata streams (EXIF, XMP, ICC profiles) - Extract video codec headers (moov boxes in MP4, etc.) **Key Design Decisions:** - Process files **individually** — metadata extraction is independent - Use **streaming** where possible — don't load entire files - **Binary metadata** can be embedded anywhere (not just headers) #### 2. Metadata Normalizer (Schema Layer) **Schema Design:** ┌─────────────────────────────────────┐ │ ┌──────────────────┐ │ │ │ file_id │ │ │ │ file_path │ │ │ │ file_size │ │ │ │ file_type │ │ │ │ file_hash │ │ │ └──────────────────┘ │ │ │ │ ┌───────────┐ │ │ │ ┌─────┐ │ │ │ │ │IMG │ │ │ │ │ │VID │ │ │ │ │ └─────┘ │ │ │ └───────────┘ │ │ │ └─────────────────────────────────────┘ TEXT **Fields to Extract:** | Category | Fields | |-----------|---------| | **Identity** | filename, filepath, hash, size | | **Dimensions** | width, height, duration (video) | | **Camera** | make, model, exposure, aperture, ISO, focal_length | | **GPS** | latitude, longitude, altitude, timestamp | | **Author** | creator, copyright, description, tags | | **Technical** | codec, bitrate, fps, color_space | #### 3. Metadata Writer (Batch to DB) **Batching Strategy:** - Extract metadata from files → accumulate in memory - Write to database in **batches** (e.g., every 100 records or 100ms) - Prevents database from being overwhelmed by individual inserts **Why Batch?** - Reduces database connection overhead - Enables transaction-level grouping - Allows for retry logic at batch level --- ## Data Flow ┌──────────────┐ │ Input File │ ───> Read headers (streaming) └──────────────┘ │ ▼ ┌───────────────────────┐ │ Extract Metadata │ (one file at a time) │ ├─ Camera info │ │ ├─ GPS coordinates │ │ ├─ Dimensions │ │ └─ Timestamp │ └───────────────────────┘ │ ▼ ┌───────────────────────┐ │ Normalize to Schema │ │ ├─ Convert types │ │ ├─ Validate fields │ │ └─ Apply defaults │ └───────────────────────┘ │ ▼ ┌───────────────────────┐ │ Accumulate in Batch │ │ (e.g., 100 records) │ └───────────────────────┘ │ ▼ ┌───────────────────────┐ │ Write to Database │ │ (transaction) │ └───────────────────────┘ TEXT --- ## Technology Stack Recommendations ### Option A: Lightweight (Python) ├─ Extractor: python - PIL, exifread, ffprobe (subprocess) ├─ Schema: pydantic (validation + serialization) ├─ DB: SQLite or PostgreSQL └─ CLI: click or typer TEXT ### Option B: High-Performance (Go/Rust) ├─ Extractor: go-exif, go-ffprobe, or native bindings ├─ Schema: struct + json validation ├─ DB: PostgreSQL with connection pooling ├─ Concurrent processing of file queues └─ HTTP API for web access TEXT --- ## Key Architectural Decisions | Decision | Recommendation | |----------|----------------| | **File Reading** | Streaming (seek to offsets) — don't load full file | | **Concurrency** | Process files concurrently, metadata extraction is I/O bound | | **Batch Size** | 100-500 records per batch, or 100ms timeout | | **DB Connection** | Single connection pool, batch writes | | **Error Handling** | Per-file errors don't crash batch; log and continue | | **Schema Flexibility** | Use JSON field for extended/unstructured metadata | --- ## Next Steps 1. **Define schema** — exact fields to extract 2. **Choose database** — SQL vs NoSQL, local vs distributed 3. **Build extractor** — per-file metadata parsing 4. **Add batching** — accumulate and write in groups 5. **Add CLI/API** — interface to trigger processing 6. **Add monitoring** — logs, metrics, health checks Option 2: Export from Chat Interface Most chat interfaces allow you to: Select and Copy — Highlight the entire response and copy (Ctrl/Cmd + C) Save as File — Paste into a text editor and save as .md extension File name suggestion: rayray-architecture.md Would you like me to format any specific section differently or provide additional details? <<<reasoning_content_start>>> Let me think about this carefully. The user wants to implement rayray with MongoDB as the database. I need to provide a proper MongoDB schema for storing metadata from images and videos. Key considerations for MongoDB schema design: 1. **Document Structure**: MongoDB uses JSON-like documents, not relational tables 2. **Indexes**: Need to plan for query patterns (search by tags, camera model, location, etc.) 3. **Embedded vs Referenced**: Should metadata be embedded or separate? 4. **Geospatial**: GPS data should use geospatial indexes 5. **Flexibility**: MongoDB's strength is flexible schemas, but we need structure for queries Let me design a comprehensive schema: **Collection: `media_files`** Each document should contain: - File identification (path, hash, size) - Basic file info (type, dimensions, duration) - Camera metadata (EXIF data) - GPS coordinates (for geospatial queries) - User/author info - Tags/keywords **Indexes to create:** - File hash (unique) - File path - Camera make/model - GPS location (2dsphere) - Tags - File type + dimensions (compound) - Upload/creation date Let me provide a complete schema with examples, indexes, and sample queries. <<<reasoning_content_end>>># MongoDB Schema for rayray ## Document Schema ### Primary Collection: `media_files` ```json { "_id": ObjectId("..."), "file": { "path": "/path/to/file.jpg", "hash": "sha256:abc123...", "size": 2456789, "mimeType": "image/jpeg" }, "dimensions": { "width": 4096, "height": 3072, "aspectRatio": "16:9" }, "camera": { "make": "Canon", "model": "EOS R5", "lens": "RF 24-70mm", "exposure": 1.6, "aperture": 2.8, "iso": 800, "focalLength": "50mm" }, "location": { "coordinates": [ -122.4194, 37.7749 ], "address": "San Francisco, CA", "altitude": 12 }, "timestamps": { "created": "2024-01-15T10:30:00Z", "modified": "2024-01-15T10:30:00Z", "ingested": "2024-01-15T10:30:00Z" }, "author": { "name": "Jane Doe", "copyright": "© Jane Doe 2024" }, "tags": ["sunset", "urban", "golden-hour"], "description": "Golden hour over city skyline", "status": "indexed", "metadataRaw": { "exif": "...", "icc": "..." } } ``` --- ## Schema Visualization ``` ┌──────────────────────────────────────────────────────────────┐ │ rayray.mongodb │ │ └── media_files │ │ └── (Document) │ │ └── { _id, file, │ │ │ dimensions, │ │ │ camera, │ │ │ location, │ │ │ author, │ │ │ tags } │ └──────────────────────────────────────────────────────────────┘ ``` --- ## Collection Schema Diagram ``` ┌─────────────────────────────────────────────────────────────┐ │ COLLECTION: media_files │ │ │ │ ┌──────────────────────────────────────────────────────────┐ │ │ │ ┌──────────────────────────────────────────────────────┐ │ │ │ │ │ _id (ObjectId) │ │ │ │ │ │ │ │ │ │ │ ┌──────────────────────────────────────────────────┐ │ │ │ │ │ │ file │ │ │ │ │ │ │ ┌─────────┐ │ │ │ │ │ │ │ │ path │ │ │ │ │ │ │ │ │ hash │ (unique index) │ │ │ │ │ │ │ │ size │ │ │ │ │ │ │ │ │ mimeType │ │ │ │ │ │ │ │ └─────────┘ │ │ │ │ │ │ └──────────────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ ┌──────────────────────────────────────────────────┐ │ │ │ │ │ │ dimensions │ │ │ │ │ │ │ ┌─────────┐ │ │ │ │ │ │ │ │ width │ │ │ │ │ │ │ │ │ height │ │ │ │ │ │ │ │ │ bitrate│ (video) │ │ │ │ │ │ │ │ fps │ (video) │ │ │ │ │ │ │ │duration │ (video) │ │ │ │ │ │ │ └─────────┘ │ │ │ │ │ │ └──────────────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ ┌──────────────────────────────────────────────────┐ │ │ │ │ │ │ camera │ │ │ │ │ │ │ ┌─────────┐ │ │ │ │ │ │ │ │ make │ │ │ │ │ │ │ │ │ model │ │ │ │ │ │ │ │ │ exposure│ │ │ │ │ │ │ │ │ aperture│ │ │ │ │ │ │ │ │ iso │ │ │ │ │ │ │ │ │ focalLen│ │ │ │ │ │ │ │ └─────────┘ │ │ │ │ │ │ └──────────────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ ┌──────────────────────────────────────────────────┐ │ │ │ │ │ │ location │ │ │ │ │ │ │ ┌─────────┐ │ │ │ │ │ │ │ │ latitude│ (2dsphere index) │ │ │ │ │ │ │ │longitude│ (2dsphere index) │ │ │ │ │ │ │ │ altitude│ │ │ │ │ │ │ │ │ address│ │ │ │ │ │ │ │ └─────────┘ │ │ │ │ │ │ └──────────────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ ┌──────────────────────────────────────────────────┐ │ │ │ │ │ │ tags │ │ │ │ │ │ │ ┌─────────┐ │ │ │ │ │ │ │ │ sunset │ │ │ │ │ │ │ │ │ urban │ (text index) │ │ │ │ │ │ │ │golden-h │ │ │ │ │ │ │ │ │ etc │ │ │ │ │ │ │ │ └─────────┘ │ │ │ │ │ │ └──────────────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ ┌──────────────────────────────────────────────────┐ │ │ │ │ │ │ timestamps │ │ │ │ │ │ │ ┌─────────┐ │ │ │ │ │ │ │ │ created │ (date index) │ │ │ │ │ │ │ │ modified│ (date index) │ │ │ │ │ │ │ │ ingested│ │ │ │ │ │ │ │ └─────────┘ │ │ │ │ │ │ └──────────────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ ┌──────────────────────────────────────────────────┐ │ │ │ │ │ │ author │ │ │ │ │ │ │ ┌─────────┐ │ │ │ │ │ │ │ │ name │ │ │ │ │ │ │ │ │ copyright│ │ │ │ │ │ │ │ │ contact │ │ │ │ │ │ │ │ └─────────┘ │ │ │ │ │ │ └──────────────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ ┌──────────────────────────────────────────────────┐ │ │ │ │ │ │ status │ │ │ │ │ │ │ ┌─────────┐ │ │ │ │ │ │ │ │ indexed │ (status index) │ │ │ │ │ │ │ │ valid │ │ │ │ │ │ │ │ │ invalid │ │ │ │ │ │ │ │ └─────────┘ │ │ │ │ │ │ └──────────────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ ┌──────────────────────────────────────────────────┐ │ │ │ │ │ │ metadataRaw │ │ │ │ │ │ │ ┌─────────┐ │ │ │ │ │ │ │ │ exif │ (raw binary/JSON) │ │ │ │ │ │ │ │ xmp │ │ │ │ │ │ │ │ │ ict │ │ │ │ │ │ │ │ │ 3rdp │ (extended fields) │ │ │ │ │ │ │ └─────────┘ │ │ │ │ │ │ └──────────────────────────────────────────────────┘ │ │ │ │ │ │ │ │ └──────────────────────────────────────────────────────────┘ │ └──────────────────────────────────────────────────────────────┘ ``` --- ## Index Strategy ### Indexes to Create ```javascript // 1. File hash (unique identifier) db.media_files.createIndex({ file_hash: 1 }, { unique: true, sparse: true }) // 2. File path (for lookup by path) db.media_files.createIndex({ file_path: 1 }) // 3. Camera make (for filtering) db.media_files.createIndex({ camera_make: 1 }) // 4. GPS location (geospatial queries) db.media_files.createIndex({ location_coordinates: "2dsphere" }) // 5. Tags (text search) db.media_files.createIndex({ tags: "text" }) // 6. File type + dimensions (compound) db.media_files.createIndex({ file_type: 1, dimensions_width: -1 }) // 7. Creation date (for sorting/filtering) db.media_files.createIndex({ timestamps_created: -1 }) // 8. Status (for filtering valid files) db.media_files.createIndex({ status: 1 }) ``` --- ## Sample Queries ### Query 1: Get files by camera model ```javascript db.media_files.find({ camera_model: /Canon/i }).limit(10) ``` ### Query 2: Find files near a location ```javascript db.media_files.find({ location_coordinates: { $nearSphere: { type: "Point", coordinates: [-122.4194, 37.7749] }, maxDistance: 50000 // meters } }) ``` ### Query 3: Search by tags ```javascript db.media_files.find({ $text: { $search: "sunset urban photography" } }) ``` ### Query 4: Filter by dimensions (for responsive web) ```javascript db.media_files.find({ dimensions_width: { $gte: 1920, $lte: 2560 }, dimensions_height: { $gte: 1080, $lte: 1440 } }) ``` ### Query 5: Find all files with GPS data ```javascript db.media_files.find({ location_coordinates: { $exists: true } }) ``` --- ## Aggregation Pipeline Examples ### Pipeline 1: Camera model statistics ```javascript db.media_files.aggregate([ { $group: { _id: "$camera_make", count: { $sum: 1 } } }, { $sort: { count: -1 } }, { $limit: 10 } ]) ``` ### Pipeline 2: Files per author ```javascript db.media_files.aggregate([ { $group: { _id: "$author_name", count: { $sum: 1 }, files: { $push: "$file_path" } } }, { $sort: { count: -1 } } ]) ``` --- ## Schema Summary Table | Field | Type | Index | Notes | |-------|------|-------|-------| | `_id` | ObjectId | auto | MongoDB auto-generated | | `file_hash` | String | unique | SHA-256 hash | | `file_path` | String | yes | Original file path | | `file_size` | Number | - | File size in bytes | | `mimeType` | String | - | e.g., `image/jpeg`, `video/mp4` | | `dimensions_width` | Number | - | Image/video width | | `dimensions_height` | Number | - | Image/video height | | `camera_make` | String | yes | Camera manufacturer | | `camera_model` | String | yes | Camera model | | `location_coordinates` | Array | 2dsphere | [longitude, latitude] | | `tags` | Array | text | Searchable tags | | `status` | String | yes | `indexed`, `valid`, `invalid` | --- ## Collection Structure Diagram ``` ┌──────────────────────────────────────────────────────────────────┐ │ COLLECTION: media_files │ │ │ │ ┌──────────────────────────────────────────────────────────────┐ │ │ │ ┌───────┐ │ │ │ │ │ _id │ (ObjectId) │ │ │ │ └───────┘ │ │ │ │ │ │ │ │ ┌──────────────────┐ ┌──────────────────┐ │ │ │ │ │ file │ │ dimensions │ │ │ │ │ │ └──────────────┘ │ └──────────────┘ │ │ │ │ │ ┌──────────────────┐ │ │ │ │ │ │ │ hash (unique) │ │ │ │ │ │ │ └──────────────────┘ │ │ │ │ │ │ ┌──────────────────┐ │ │ │ │ │ │ │ path │ │ │ │ │ │ │ │ size │ │ │ │ │ │ │ │ mimeType │ │ │ │ │ │ │ └──────────────────┘ │ │ │ │ │ │ │ │ │ │ │ │ ┌──────────────────┐ │ │ │ │ │ │ │ camera_make │ │ │ │ │ │ │ │ camera_model │ │ │ │ │ │ │ │ camera_lens │ │ │ │ │ │ │ │ camera_exposure │ │ │ │ │ │ │ │ camera_aperture │ │ │ │ │ │ │ │ camera_iso │ │ │ │ │ │ │ │ camera_focalLength │ │ │ │ │ │ │ └──────────────────┘ │ │ │ │ │ │ │ │ │ │ │ │ ┌──────────────────┐ │ │ │ │ │ │ │ location │ │ │ │ │ │ │ │ coordinates │ (2d │ │ │ │ │ │ │ altitude │ sphere) │ │ │ │ │ │ address │ │ │ │ │ │ └──────────────────┘ │ │ │ │ │ │ │ │ │ │ │ │ ┌──────────────────┐ │ │ │ │ │ │ │ tags │ (text │ │ │ │ │ │ │ └──────────────┘ search) │ │ │ │ │ │ │ │ │ │ │ ┌──────────────────┐ │ │ │ │ │ │ │ timestamps │ (date │ │ │ │ │ │ │ └──────────────┘ index) │ │ │ │ │ │ │ │ │ │ │ ┌──────────────────┐ │ │ │ │ │ │ │ author │ │ │ │ │ │ │ │ └──────────────┘ │ │ │ │ │ │ │ │ │ │ │ │ ┌──────────────────┐ │ │ │ │ │ │ │ description │ │ │ │ │ │ │ │ status │ (status) │ │ │ │ │ └──────────────────┘ │ │ │ │ │ │ │ │ │ │ │ │ ┌──────────────────┐ │ │ │ │ │ │ │ metadataRaw │ (JSON │ │ │ │ │ │ │ └──────────────┘ extended) │ │ │ │ └──────────────────────────────────────────────────────┘ │ │ │ │ │ └──────────────────────────────────────────────────────────────┘ │ │ │ │ COLLECTION: users │ │ ┌──────────────────────────────────────────────────────────────┐ │ │ │ ┌───────┐ │ │ │ │ │ _id │ (ObjectId) │ │ │ │ └───────┘ │ │ │ │ ┌──────────────────────────────────────┐ │ │ │ │ username │ │ │ │ │ email │ │ │ │ │ role (admin, curator) │ │ │ │ │ created │ │ │ │ │ updated │ │ │ │ └──────────────────────────────────────┘ │ │ │ └──────────────────────────────────────┘ │ │ │ │ │ COLLECTION: batches │ │ ┌──────────────────────────────────────────────────────────────┐ │ │ │ ┌───────┐ │ │ │ │ │ _id │ (ObjectId) │ │ │ │ └───────┘ │ │ │ │ ┌──────────────────────────────────────┐ │ │ │ │ batch_id │ │ │ │ │ file_count │ │ │ │ │ status │ │ │ │ │ created │ │ │ │ │ completed │ │ │ │ └──────────────────────────────────────┘ │ │ │ └──────────────────────────────────────┘ │ │ └──────────────────────────────────────────────────────────────┘ │ │ │ │ COLLECTION: logs │ │ ┌──────────────────────────────────────────────────────────────┐ │ │ │ ┌───────┐ │ │ │ │ │ _id │ (ObjectId) │ │ │ │ └───────┘ │ │ │ │ ┌──────────────────────────────────────┐ │ │ │ │ level (info, warn, error) │ │ │ │ │ message │ │ │ │ │ timestamp │ │ │ │ │ file_id │ │ │ │ │ error_type │ │ │ │ └──────────────────────────────────────┘ │ │ │ └──────────────────────────────────────┘ │ │ └──────────────────────────────────────────────────────────────┘ │ └──────────────────────────────────────────────────────────────────┘ ``` --- ## Would You Like... 1. **Sample data insertion** — Example documents to test with? 2. **Connection pool setup** — How to structure the DB connection? 3. **Batching strategy** — How to batch writes efficiently? 4. **Error handling** — Retry, logging, and recovery? Which would you like to explore next?