Skip to content

Repository files navigation

ImageMates CLI Server

A high-performance image generation server built with Swift, Vapor, and FluxSwift for local FLUX model inference. Generate stunning images using text-to-image and image-to-image capabilities with a RESTful API.

Features

  • 🎨 Text-to-Image Generation: Create images from text prompts using FLUX models
  • 🖼️ Image-to-Image Editing: Transform existing images with text prompts
  • 🔐 JWT Authentication: Secure API endpoints with token-based authentication
  • 🚀 Local Inference: Run FLUX models locally on Apple Silicon
  • 📊 Progress Tracking: Real-time generation progress updates
  • 🗄️ SQLite Storage: Persistent storage for users, generations, and models
  • 🎯 Multiple Models: Support for flux-schnell, flux-dev, and flux-kontext

Requirements

  • macOS 14.0+ (Apple Silicon recommended)
  • Xcode 15.0+
  • Swift 5.9+
  • FLUX model weights (downloaded automatically on first use)

Installation

  1. Clone the repository:
git clone https://github.com/mzbac/ImageMatesCLI.git
cd ImageMatesCLI
  1. Build the server using Xcode (required for MLX Metal support):
# Create dist directory
mkdir -p dist

# Build to dist folder (requires absolute path)
xcodebuild -scheme ImageMatesCLI -configuration Release -destination "platform=macOS" CONFIGURATION_BUILD_DIR="$(pwd)/dist" build

Running the Server

  1. Start the server:
# From the dist directory
cd dist
./ImageMatesServer

The server will start on http://localhost:8080

  1. On first run, the server will:
    • Create the SQLite database
    • Seed test user: fluxtest@example.com / password123
    • Register available FLUX models
    • Create necessary storage directories

API Endpoints

Authentication

Login

curl -X POST http://localhost:8080/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{
    "email": "fluxtest@example.com",
    "password": "password123"
  }'

Response:

{
  "success": true,
  "data": {
    "user": {
      "id": "...",
      "email": "fluxtest@example.com",
      "name": "FluxSwift Test User"
    },
    "token": "eyJ0eXAiOiJKV1Q..."
  }
}

Text-to-Image Generation

TOKEN="your-jwt-token"

curl -X POST http://localhost:8080/api/generate \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "A cute robot in a garden, digital art",
    "model": "mzbac/flux1.schnell.4bit.mlx",
    "width": 256,
    "height": 256,
    "steps": 4,
    "guidance": 3.5,
    "seed": 123
  }'

Image-to-Image Editing

TOKEN="your-jwt-token"

curl -X POST http://localhost:8080/api/edit \
  -H "Authorization: Bearer $TOKEN" \
  -F "prompt=A beautiful ocean with waves at sunset" \
  -F "image=@input_image.png" \
  -F "model=mzbac/flux1.kontext.4bit.mlx" \
  -F "strength=0.8" \
  -F "width=256" \
  -F "height=256" \
  -F "steps=4" \
  -F "guidance=3.5"

Check Generation Status

curl -H "Authorization: Bearer $TOKEN" \
  http://localhost:8080/api/generations/{generationId}

List Available Models

curl -H "Authorization: Bearer $TOKEN" \
  http://localhost:8080/api/models

Gallery (List Past Generations)

curl -H "Authorization: Bearer $TOKEN" \
  http://localhost:8080/api/gallery

Real-Time Updates with Server-Sent Events (SSE)

The server provides Server-Sent Events for real-time generation progress updates:

SSE Event Types

  • connected: Initial connection confirmation with session ID
  • progress: Generation progress updates (0-100%)
  • completed: Generation finished successfully
  • error: Generation failed or error occurred
  • heartbeat: Keep-alive signal every 30 seconds

Using SSE in Your Application

// Since EventSource doesn't support custom headers natively,
// use a fetch-based approach for authentication
async function connectSSE(token) {
    const response = await fetch('/api/events', {
        headers: {
            'Authorization': `Bearer ${token}`,
            'Accept': 'text/event-stream'
        }
    });
    
    const reader = response.body.getReader();
    const decoder = new TextDecoder();
    
    // Process the stream
    while (true) {
        const { done, value } = await reader.read();
        if (done) break;
        
        const chunk = decoder.decode(value);
        // Parse SSE events from chunk
        parseSSEEvents(chunk);
    }
}

function parseSSEEvents(chunk) {
    const events = chunk.split('\n\n');
    events.forEach(event => {
        const lines = event.split('\n');
        let eventType = null;
        let eventData = null;
        
        lines.forEach(line => {
            if (line.startsWith('event: ')) {
                eventType = line.slice(7);
            } else if (line.startsWith('data: ')) {
                eventData = JSON.parse(line.slice(6));
            }
        });
        
        if (eventType && eventData) {
            handleSSEEvent(eventType, eventData);
        }
    });
}

3. Manual Testing with Sample Images

Run image-to-image transformation:

# Get auth token
TOKEN=$(curl -s -X POST http://localhost:8080/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email": "fluxtest@example.com", "password": "password123"}' \
  | jq -r '.data.token')

# Submit image for transformation
RESPONSE=$(curl -s -X POST http://localhost:8080/api/edit \
  -H "Authorization: Bearer $TOKEN" \
  -F "prompt=A beautiful mountain landscape with snow" \
  -F "image=@test_input.png" \
  -F "model=flux-schnell" \
  -F "strength=0.8" \
  -F "steps=4")

# Extract generation ID
GEN_ID=$(echo $RESPONSE | jq -r '.data.generationId')

# Check status
curl -s -H "Authorization: Bearer $TOKEN" \
  http://localhost:8080/api/generations/$GEN_ID | jq

Model Management

Available Models

Community MLX Models (Recommended for Apple Silicon)

  1. mzbac/flux1.schnell.4bit.mlx (Default)

    • Fast generation (4 steps)
    • Optimized for Apple Silicon
    • ~3GB download
  2. mzbac/flux1.schnell.8bit.mlx

    • Higher quality Schnell
    • Better than 4-bit
    • ~6GB download
  3. mzbac/flux1.dev.4bit.mlx

    • Development model quality
    • Good quality/speed balance
    • ~6GB download
  4. mzbac/flux1.dev.8bit.mlx

    • Highest quality
    • Slower generation
    • ~12GB download
  5. mzbac/flux1.kontext.4bit.mlx

    • Image-to-image specialist
    • Apple Silicon optimized
    • ~6GB download
  6. mzbac/flux1.kontext.8bit.mlx

    • Best image-to-image quality
    • Higher precision
    • ~12GB download

Official FLUX Models (Require HF_TOKEN)

  1. black-forest-labs/FLUX.1-schnell

    • Original fast model
    • Requires authentication
  2. black-forest-labs/FLUX.1-dev

    • Original development model
    • Requires authentication
  3. black-forest-labs/FLUX.1-Kontext-dev

    • Official image-to-image model
    • Requires authentication

Models are automatically downloaded from Hugging Face on first use.

Model Storage

Models are stored in:

~/Documents/huggingface/models/black-forest-labs/

Loading Custom Models

To use custom FLUX models, update the database:

sqlite3 db.sqlite
INSERT INTO models (id, model_id, name, type, source, path, supports_img2img) 
VALUES (
  '550e8400-e29b-41d4-a716-446655440000',
  'my-custom-model',
  'My Custom FLUX Model',
  'universal',
  'local',
  '/path/to/model/weights',
  true
);

Storage Structure

ImageMatesCLI/
├── db.sqlite                    # SQLite database
├── storage/
│   ├── images/                  # Generated images
│   │   └── {generation-id}.png
│   ├── thumbnails/              # Image thumbnails
│   │   └── thumb_{id}.png
│   └── uploads/                 # Uploaded input images
│       └── {upload-id}.png

Configuration

Environment Variables

  • PORT: Server port (default: 8080)
  • DATABASE_PATH: SQLite database path (default: ./db.sqlite)
  • JWT_SECRET: JWT signing secret (default: test-secret-key)
  • LOG_LEVEL: Logging level (default: debug)

Database Schema

The server uses SQLite with the following main tables:

  • users: User accounts and settings
  • generations: Image generation records
  • models: Available AI models
  • _fluent_sessions: Session storage

Troubleshooting

MLX Metal Library Error

If you see "Failed to load the default metallib", ensure you're building with xcodebuild:

xcodebuild -scheme ImageMatesCLI -configuration Release -destination "platform=macOS" CONFIGURATION_BUILD_DIR="$(pwd)/dist" build

Model Download Issues

If model downloads fail:

  1. Check internet connection
  2. Ensure you have enough disk space (~15GB for all models)
  3. Models are cached after first download

Authentication Errors

If you get 401 errors:

  1. Ensure you're including the Bearer token in headers
  2. Token expires after 7 days
  3. Use the /api/auth/refresh endpoint to get a new token

Generation Failures

Common issues:

  • Insufficient memory (8GB+ RAM recommended)
  • Invalid image formats (use PNG, JPEG)
  • Model not loaded (check /api/models endpoint)

Performance Tips

  1. Model Loading: First generation takes longer due to model loading
  2. Batch Size: Keep dimensions reasonable (256x256 to 1024x1024)
  3. Steps: Lower steps = faster generation (flux-schnell optimized for 4 steps)
  4. Concurrent Requests: Server queues generations to prevent memory issues

Development

Debug Mode

LOG_LEVEL=trace ./ImageMatesServer

Database Inspection

sqlite3 db.sqlite
.tables
SELECT * FROM users;
SELECT * FROM generations ORDER BY created_at DESC LIMIT 5;

License

This project is licensed under the GNU General Public License v3.0

Contributing

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Acknowledgments

  • Built with Vapor web framework
  • Powered by flux.swift for FLUX model inference
  • Uses MLX for efficient computation on Apple Silicon

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages