Skip to content

Raudbjorn/metadata-extractor

Repository files navigation

Image Metadata Storyteller

A React application that extracts EXIF metadata from uploaded images and uses Google's Gemini AI to generate creative narrative stories based on the hidden data within your photos.

Features

  • πŸ“Έ Image Upload: Drag-and-drop image upload powered by Uppy
  • πŸ” Metadata Extraction: Server-side EXIF metadata extraction from JPG, PNG, TIFF, and WEBP images
  • 🎨 Perceptual Hashing: Client-side visual fingerprinting for future duplicate detection
  • πŸ€– AI Story Generation: Creative narratives generated by Google Gemini based on image metadata
  • πŸ’Ύ Supabase Integration: Edge Functions for serverless metadata processing

Prerequisites

  • Node.js (v18 or higher recommended)
  • Docker (for local Supabase development)
  • Supabase CLI (install via npm install -g supabase)
  • Google Gemini API Key (get one at aistudio.google.com)

Local Development

1. Install Dependencies

npm install

2. Configure Environment

Create a .env.local file in the project root:

GEMINI_API_KEY=your_gemini_api_key_here

3. Start Supabase (Required)

supabase start

This starts a local Supabase instance with PostgreSQL and Edge Functions on port 54321.

4. Run the App

npm run dev

The app will be available at http://localhost:3000

Project Structure

/
β”œβ”€β”€ App.tsx                      # Main application component
β”œβ”€β”€ components/
β”‚   β”œβ”€β”€ UppyUploader.tsx         # File upload interface
β”‚   β”œβ”€β”€ MetadataDisplay.tsx      # Metadata and story display
β”‚   └── Icons.tsx                # SVG icons
β”œβ”€β”€ services/
β”‚   β”œβ”€β”€ geminiService.ts         # Google Gemini AI integration
β”‚   β”œβ”€β”€ mediaService.ts          # Perceptual hash generation
β”‚   β”œβ”€β”€ configService.ts         # Metadata configuration loader
β”‚   └── supabaseService.ts       # Supabase client (stub)
β”œβ”€β”€ supabase/
β”‚   β”œβ”€β”€ functions/
β”‚   β”‚   β”œβ”€β”€ process-upload/      # Main metadata extraction endpoint
β”‚   β”‚   └── extract-metadata/    # Alternative extraction endpoint
β”‚   └── migrations/              # Database schema migrations
β”œβ”€β”€ metadata.json                # EXIF tag configuration
└── vite.config.ts              # Vite bundler configuration

How It Works

  1. User uploads an image via the Uppy interface
  2. Image is posted to Supabase Edge Function (process-upload)
  3. Server extracts EXIF metadata using the exifr library
  4. Client generates a perceptual hash of the image
  5. Metadata is sent to Google Gemini for creative story generation
  6. Results are displayed in an interactive interface

Application Flow Diagram

sequenceDiagram
    participant User
    participant UppyUploader
    participant EdgeFunction as Process-Upload<br/>(Edge Function)
    participant MediaService
    participant GeminiService
    participant Display as MetadataDisplay

    User->>UppyUploader: Upload Image
    UppyUploader->>EdgeFunction: POST multipart/form-data
    EdgeFunction->>EdgeFunction: Extract EXIF with exifr
    EdgeFunction-->>UppyUploader: Return metadata JSON

    UppyUploader->>MediaService: generatePerceptualHash(imageUrl)
    MediaService->>MediaService: Generate blockhash
    MediaService-->>UppyUploader: Return pHash

    UppyUploader->>GeminiService: analyzeMetadataWithGemini()
    GeminiService->>GeminiService: Call Gemini API
    GeminiService-->>UppyUploader: Return AI story

    UppyUploader->>Display: Display results
    Display->>User: Show metadata & story
Loading

Database Schema

The app includes migrations for a media_metadata table that can store:

  • File information (name, type, size)
  • EXIF metadata (JSON)
  • Perceptual hashes for duplicate detection
  • Hamming distance function for similarity comparison

Build for Production

npm run build

Output will be in the dist/ directory.

Architecture & Services

This project features comprehensive service documentation with JSDoc comments for IntelliSense support. All exported functions are extensively documented with parameters, return types, examples, and usage patterns.

Core Services

πŸ€– Gemini Service (services/geminiService.ts)

Integrates with Google's Gemini AI to generate creative narrative stories from image metadata.

Key Function:

analyzeMetadataWithGemini(
  embeddedMetadata: Record<string, any>,
  providerMetadata: Record<string, any> | undefined,
  config: AppConfig | null,
  imageFormat: string
): Promise<string>

πŸ–ΌοΈ Media Service (services/mediaService.ts)

Client-side perceptual hash generation for image fingerprinting and duplicate detection.

Key Function:

generatePerceptualHash(imageUrl: string): Promise<string>

Generates a 64-bit perceptual hash using the blockhash algorithm (16-bit precision).

βš™οΈ Config Service (services/configService.ts)

Loads and caches EXIF tag configuration with singleton pattern.

Key Function:

getConfig(): Promise<AppConfig>

Fetches configuration once and caches for subsequent calls.

πŸ”§ Edge Functions (supabase/functions/)

  • process-upload: Receives multipart uploads from Uppy, extracts EXIF metadata
  • extract-metadata: Alternative endpoint for raw binary uploads

Component Architecture

graph TB
    subgraph Frontend["Frontend (React)"]
        App[App.tsx]
        Uppy[UppyUploader.tsx]
        ImageUploader[ImageUploader.tsx<br/>ALTERNATIVE]
        Display[MetadataDisplay.tsx]
    end

    subgraph Services["Services Layer"]
        Config[configService.ts]
        Media[mediaService.ts]
        Gemini[geminiService.ts]
    end

    subgraph Backend["Edge Functions"]
        ProcessUpload[process-upload]
    end

    subgraph External["External APIs"]
        GeminiAPI[Google Gemini API]
    end

    App --> Uppy
    App -.alternative.-> ImageUploader
    Uppy --> ProcessUpload
    Uppy --> Media
    Uppy --> Gemini
    Gemini --> GeminiAPI

    ImageUploader -.-> ProcessUpload
Loading

For comprehensive flowcharts, detailed service documentation, and data flow diagrams, see ARCHITECTURE.md.

Technologies

  • Frontend: React 19, TypeScript, Vite
  • File Upload: Uppy (with native HTML5 alternative in ImageUploader)
  • AI: Google Gemini 2.5 Flash
  • Backend: Supabase Edge Functions (Deno)
  • Database: PostgreSQL (via Supabase)
  • Image Processing: exifr, blockhash-js

License

MIT

AI Studio

This project was scaffolded from Google AI Studio. View the original app at: https://ai.studio/apps/drive/19DcgZ9yN-Afb8vXOCHdy_wcMhEHdapEy

About

Extract metadata+duplicate detection

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •