mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
docs: add VitePress documentation site with GitHub Pages deployment
Rewrites all documentation with accurate project details (Fastify, port 1349, single-container Docker, all 33+ tools, full database schema). Adds getting started guide and configuration reference. Updates help and settings dialogs to link to the docs site.
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
# AI engine
|
||||
|
||||
The `@stirling-image/ai` package wraps Python ML models in TypeScript functions. Each operation spawns a Python subprocess, processes the image, and returns the result. The bridge layer handles serialization and error propagation.
|
||||
|
||||
All model weights are bundled in the Docker image during the build. No downloads happen at runtime.
|
||||
|
||||
## Background removal
|
||||
|
||||
Removes the background from an image and returns a transparent PNG.
|
||||
|
||||
**Model:** BiRefNet-Lite via [rembg](https://github.com/danielgatis/rembg)
|
||||
|
||||
| Parameter | Type | Description |
|
||||
|---|---|---|
|
||||
| `model` | string | Model name. Default: `birefnet-lite`. Options include `u2net`, `isnet-general-use`, and others supported by rembg. |
|
||||
| `alphaMatting` | boolean | Use alpha matting for finer edge detail |
|
||||
| `alphaMattingForegroundThreshold` | number | Foreground threshold for alpha matting (0-255) |
|
||||
| `alphaMattingBackgroundThreshold` | number | Background threshold for alpha matting (0-255) |
|
||||
|
||||
**Python script:** `packages/ai/python/remove_bg.py`
|
||||
|
||||
## Upscaling
|
||||
|
||||
Increases image resolution using AI super-resolution.
|
||||
|
||||
**Model:** [RealESRGAN](https://github.com/xinntao/Real-ESRGAN)
|
||||
|
||||
| Parameter | Type | Description |
|
||||
|---|---|---|
|
||||
| `scale` | number | Upscale factor: `2` or `4` |
|
||||
|
||||
Returns the upscaled image along with the original and new dimensions.
|
||||
|
||||
**Python script:** `packages/ai/python/upscale.py`
|
||||
|
||||
## OCR (text recognition)
|
||||
|
||||
Extracts text from images.
|
||||
|
||||
**Model:** [PaddleOCR](https://github.com/PaddlePaddle/PaddleOCR)
|
||||
|
||||
| Parameter | Type | Description |
|
||||
|---|---|---|
|
||||
| `language` | string | Language code (e.g. `en`, `ch`, `fr`, `de`) |
|
||||
|
||||
Returns structured results with text content, bounding boxes, and confidence scores for each detected text region.
|
||||
|
||||
**Python script:** `packages/ai/python/ocr.py`
|
||||
|
||||
## Face detection and blurring
|
||||
|
||||
Detects faces in an image and applies a blur to each detected region.
|
||||
|
||||
**Model:** [MediaPipe](https://github.com/google/mediapipe) Face Detection
|
||||
|
||||
| Parameter | Type | Description |
|
||||
|---|---|---|
|
||||
| `blurStrength` | number | How strongly to blur detected faces |
|
||||
|
||||
Returns the blurred image along with metadata about each detected face region (bounding box coordinates and confidence score).
|
||||
|
||||
**Python script:** `packages/ai/python/detect_faces.py`
|
||||
|
||||
## Object erasing (inpainting)
|
||||
|
||||
Removes objects from images by filling in the area with generated content that matches the surroundings.
|
||||
|
||||
**Model:** [LaMa](https://github.com/advimman/lama) (Large Mask Inpainting)
|
||||
|
||||
Takes an image and a mask (white = area to erase, black = keep). Returns the inpainted image.
|
||||
|
||||
**Python script:** `packages/ai/python/inpaint.py`
|
||||
|
||||
## Smart crop
|
||||
|
||||
Content-aware cropping that identifies the most relevant region of an image.
|
||||
|
||||
| Parameter | Type | Description |
|
||||
|---|---|---|
|
||||
| `width` | number | Target crop width |
|
||||
| `height` | number | Target crop height |
|
||||
|
||||
Unlike regular cropping, smart crop analyzes the image content to decide where to place the crop window.
|
||||
|
||||
## How the bridge works
|
||||
|
||||
The TypeScript bridge (`packages/ai/src/bridge.ts`) does the following for each AI call:
|
||||
|
||||
1. Writes the input image to a temp file in the workspace directory.
|
||||
2. Spawns a Python subprocess with the appropriate script and arguments.
|
||||
3. Reads stdout for JSON output and stderr for error messages.
|
||||
4. Reads the output image from the filesystem.
|
||||
5. Cleans up temp files.
|
||||
|
||||
If the Python process exits with a non-zero code or writes to stderr, the bridge throws an error with the stderr content. Timeouts are handled at the API route level.
|
||||
@@ -0,0 +1,122 @@
|
||||
# Image engine
|
||||
|
||||
The `@stirling-image/image-engine` package handles all non-AI image operations. It wraps [Sharp](https://sharp.pixelplumbing.com/) and runs entirely in-process with no external dependencies.
|
||||
|
||||
## Operations
|
||||
|
||||
### resize
|
||||
|
||||
Scale an image to specific dimensions or by percentage.
|
||||
|
||||
| Parameter | Type | Description |
|
||||
|---|---|---|
|
||||
| `width` | number | Target width in pixels |
|
||||
| `height` | number | Target height in pixels |
|
||||
| `fit` | string | `cover`, `contain`, `fill`, `inside`, or `outside` |
|
||||
| `withoutEnlargement` | boolean | If true, won't upscale smaller images |
|
||||
| `percentage` | number | Scale by percentage instead of absolute dimensions |
|
||||
|
||||
You can set `width`, `height`, or both. If you only set one, the other is calculated to maintain the aspect ratio.
|
||||
|
||||
### crop
|
||||
|
||||
Cut out a rectangular region from the image.
|
||||
|
||||
| Parameter | Type | Description |
|
||||
|---|---|---|
|
||||
| `left` | number | X offset from the left edge |
|
||||
| `top` | number | Y offset from the top edge |
|
||||
| `width` | number | Width of the crop area |
|
||||
| `height` | number | Height of the crop area |
|
||||
|
||||
### rotate
|
||||
|
||||
Rotate the image by a given angle.
|
||||
|
||||
| Parameter | Type | Description |
|
||||
|---|---|---|
|
||||
| `angle` | number | Rotation angle in degrees (0-360) |
|
||||
| `background` | string | Fill color for the exposed area (default: transparent or white) |
|
||||
|
||||
### flip
|
||||
|
||||
Mirror the image horizontally or vertically.
|
||||
|
||||
| Parameter | Type | Description |
|
||||
|---|---|---|
|
||||
| `direction` | string | `horizontal` or `vertical` |
|
||||
|
||||
### convert
|
||||
|
||||
Change the image format.
|
||||
|
||||
| Parameter | Type | Description |
|
||||
|---|---|---|
|
||||
| `format` | string | Target format: `jpeg`, `png`, `webp`, `avif`, `tiff`, `gif` |
|
||||
| `quality` | number | Compression quality (1-100, applies to lossy formats) |
|
||||
|
||||
### compress
|
||||
|
||||
Reduce file size while keeping the same format.
|
||||
|
||||
| Parameter | Type | Description |
|
||||
|---|---|---|
|
||||
| `quality` | number | Target quality (1-100) |
|
||||
| `format` | string | Optional format override |
|
||||
|
||||
### strip-metadata
|
||||
|
||||
Remove EXIF, IPTC, and XMP metadata from the image. Useful for privacy before sharing photos publicly. Takes no parameters.
|
||||
|
||||
### Color adjustments
|
||||
|
||||
These operations modify the color properties of an image. Each takes a single numeric value.
|
||||
|
||||
| Operation | Parameter | Range | Description |
|
||||
|---|---|---|---|
|
||||
| `brightness` | `value` | -100 to 100 | Adjust brightness |
|
||||
| `contrast` | `value` | -100 to 100 | Adjust contrast |
|
||||
| `saturation` | `value` | -100 to 100 | Adjust color saturation |
|
||||
|
||||
### Color filters
|
||||
|
||||
These apply a fixed color transformation. They take no parameters.
|
||||
|
||||
| Operation | Description |
|
||||
|---|---|
|
||||
| `grayscale` | Convert to grayscale |
|
||||
| `sepia` | Apply a sepia tone |
|
||||
| `invert` | Invert all colors |
|
||||
|
||||
### Color channels
|
||||
|
||||
Adjust individual RGB color channels.
|
||||
|
||||
| Parameter | Type | Description |
|
||||
|---|---|---|
|
||||
| `red` | number | Red channel adjustment (-100 to 100) |
|
||||
| `green` | number | Green channel adjustment (-100 to 100) |
|
||||
| `blue` | number | Blue channel adjustment (-100 to 100) |
|
||||
|
||||
## Format detection
|
||||
|
||||
The engine detects input formats automatically from file headers, not just file extensions. This means a `.jpg` file that is actually a PNG will be handled correctly.
|
||||
|
||||
Supported input formats: JPEG, PNG, WebP, AVIF, TIFF, GIF, SVG, RAW (via libraw).
|
||||
|
||||
## Metadata extraction
|
||||
|
||||
The `info` tool returns image metadata:
|
||||
|
||||
```json
|
||||
{
|
||||
"width": 1920,
|
||||
"height": 1080,
|
||||
"format": "jpeg",
|
||||
"size": 245678,
|
||||
"channels": 3,
|
||||
"hasAlpha": false,
|
||||
"dpi": 72,
|
||||
"exif": { ... }
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,285 @@
|
||||
# REST API
|
||||
|
||||
The API server runs on port 1349 by default and serves all endpoints under `/api`. Interactive Swagger documentation is available at `/api/docs` when the server is running.
|
||||
|
||||
## Authentication
|
||||
|
||||
Requests can be authenticated in two ways:
|
||||
|
||||
1. **Session cookie** -- Log in via `POST /api/auth/login` and the server sets a session cookie.
|
||||
2. **API key** -- Pass an `Authorization: Bearer si_...` header with an API key.
|
||||
|
||||
Some endpoints (health check, login, Swagger docs) are public and don't require authentication.
|
||||
|
||||
## Tools
|
||||
|
||||
### Execute a tool
|
||||
|
||||
```
|
||||
POST /api/v1/tools/:toolId
|
||||
Content-Type: multipart/form-data
|
||||
```
|
||||
|
||||
Send a multipart request with:
|
||||
- `file` -- The image file
|
||||
- `settings` -- JSON string with tool-specific options
|
||||
|
||||
Response:
|
||||
|
||||
```json
|
||||
{
|
||||
"jobId": "abc123",
|
||||
"downloadUrl": "/api/v1/download/abc123/output.png",
|
||||
"originalSize": 245000,
|
||||
"processedSize": 180000
|
||||
}
|
||||
```
|
||||
|
||||
### Available tool IDs
|
||||
|
||||
**Image operations:** `resize`, `crop`, `rotate`, `flip`, `convert`, `compress`, `strip-metadata`, `border`
|
||||
|
||||
**Color:** `color-adjustments`, `grayscale`, `sepia`, `invert`, `color-palette`, `replace-color`
|
||||
|
||||
**Text and codes:** `watermark-text`, `watermark-image`, `text-overlay`, `qr-generate`, `barcode-read`, `ocr`
|
||||
|
||||
**Composition:** `compose`, `collage`, `split`, `image-to-pdf`
|
||||
|
||||
**Analysis:** `info`, `compare`, `find-duplicates`
|
||||
|
||||
**Conversion:** `svg-to-raster`, `vectorize`, `favicon`, `gif-tools`
|
||||
|
||||
**AI-powered:** `remove-background`, `upscale`, `blur-faces`, `erase-object`, `smart-crop`
|
||||
|
||||
**Utility:** `bulk-rename`
|
||||
|
||||
### Batch processing
|
||||
|
||||
```
|
||||
POST /api/v1/tools/:toolId/batch
|
||||
Content-Type: multipart/form-data
|
||||
```
|
||||
|
||||
Send multiple files with the same settings. Returns a ZIP file containing all processed images. The response includes an `X-Job-Id` header you can use to track progress.
|
||||
|
||||
## File management
|
||||
|
||||
### Upload files
|
||||
|
||||
```
|
||||
POST /api/v1/upload
|
||||
Content-Type: multipart/form-data
|
||||
```
|
||||
|
||||
Upload one or more images. Returns file identifiers for use with other endpoints.
|
||||
|
||||
### Download results
|
||||
|
||||
```
|
||||
GET /api/v1/download/:jobId/:filename
|
||||
```
|
||||
|
||||
Download a processed image by job ID and filename.
|
||||
|
||||
## Pipelines
|
||||
|
||||
Pipelines chain multiple tools together. The output of each step becomes the input for the next.
|
||||
|
||||
### Execute a pipeline
|
||||
|
||||
```
|
||||
POST /api/v1/pipeline/execute
|
||||
Content-Type: multipart/form-data
|
||||
```
|
||||
|
||||
Body fields:
|
||||
- `file` -- The input image
|
||||
- `steps` -- JSON array of `{ "toolId": "resize", "settings": { ... } }` objects
|
||||
|
||||
Response includes `jobId`, `downloadUrl`, and details about each completed step.
|
||||
|
||||
### Save a pipeline
|
||||
|
||||
```
|
||||
POST /api/v1/pipeline/save
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "Thumbnail generator",
|
||||
"description": "Resize and compress for web thumbnails",
|
||||
"steps": [
|
||||
{ "toolId": "resize", "settings": { "width": 200, "height": 200, "fit": "cover" } },
|
||||
{ "toolId": "compress", "settings": { "quality": 80 } },
|
||||
{ "toolId": "convert", "settings": { "format": "webp" } }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### List saved pipelines
|
||||
|
||||
```
|
||||
GET /api/v1/pipeline/list
|
||||
```
|
||||
|
||||
### Delete a pipeline
|
||||
|
||||
```
|
||||
DELETE /api/v1/pipeline/:id
|
||||
```
|
||||
|
||||
## Progress tracking
|
||||
|
||||
For long-running jobs (AI operations, batch processing), you can track progress via Server-Sent Events.
|
||||
|
||||
```
|
||||
GET /api/v1/jobs/:jobId/progress
|
||||
```
|
||||
|
||||
The stream emits `JobProgress` objects:
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "processing",
|
||||
"progress": 45,
|
||||
"completedFiles": ["image1.jpg", "image2.jpg"],
|
||||
"failedFiles": [],
|
||||
"errors": []
|
||||
}
|
||||
```
|
||||
|
||||
The connection closes automatically 5 seconds after the job completes.
|
||||
|
||||
## API keys
|
||||
|
||||
### Generate a key
|
||||
|
||||
```
|
||||
POST /api/v1/api-keys
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
```json
|
||||
{ "name": "My integration" }
|
||||
```
|
||||
|
||||
Returns the raw key (prefixed with `si_`). This is the only time the full key is shown.
|
||||
|
||||
### List keys
|
||||
|
||||
```
|
||||
GET /api/v1/api-keys
|
||||
```
|
||||
|
||||
Returns key metadata (name, prefix, creation date) but not the full key.
|
||||
|
||||
### Delete a key
|
||||
|
||||
```
|
||||
DELETE /api/v1/api-keys/:id
|
||||
```
|
||||
|
||||
## Settings
|
||||
|
||||
### Get all settings
|
||||
|
||||
```
|
||||
GET /api/v1/settings
|
||||
```
|
||||
|
||||
### Update settings
|
||||
|
||||
```
|
||||
PUT /api/v1/settings
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
Admin only. Accepts a JSON object of key-value pairs.
|
||||
|
||||
## Auth endpoints
|
||||
|
||||
### Login
|
||||
|
||||
```
|
||||
POST /api/auth/login
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
```json
|
||||
{ "username": "admin", "password": "admin" }
|
||||
```
|
||||
|
||||
Returns a session token and sets a cookie.
|
||||
|
||||
### Get current session
|
||||
|
||||
```
|
||||
GET /api/auth/session
|
||||
```
|
||||
|
||||
### Change password
|
||||
|
||||
```
|
||||
POST /api/auth/change-password
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
```json
|
||||
{ "currentPassword": "old", "newPassword": "new" }
|
||||
```
|
||||
|
||||
### List users (admin)
|
||||
|
||||
```
|
||||
GET /api/auth/users
|
||||
```
|
||||
|
||||
### Create user (admin)
|
||||
|
||||
```
|
||||
POST /api/auth/register
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
```json
|
||||
{ "username": "newuser", "password": "pass", "role": "user" }
|
||||
```
|
||||
|
||||
### Delete user (admin)
|
||||
|
||||
```
|
||||
DELETE /api/auth/users/:id
|
||||
```
|
||||
|
||||
## Health check
|
||||
|
||||
```
|
||||
GET /api/v1/health
|
||||
```
|
||||
|
||||
Returns `200 OK` if the server is running. Used by Docker's health check.
|
||||
|
||||
## Rate limiting
|
||||
|
||||
All endpoints are rate-limited to `RATE_LIMIT_PER_MIN` requests per minute per IP (default: 100). When exceeded, the server returns `429 Too Many Requests`.
|
||||
|
||||
## Error responses
|
||||
|
||||
Errors follow a consistent format:
|
||||
|
||||
```json
|
||||
{
|
||||
"statusCode": 400,
|
||||
"error": "Bad Request",
|
||||
"message": "Invalid image format"
|
||||
}
|
||||
```
|
||||
|
||||
Common status codes:
|
||||
- `400` -- Invalid input (bad format, missing required fields)
|
||||
- `401` -- Not authenticated
|
||||
- `403` -- Not authorized (e.g., non-admin trying admin endpoints)
|
||||
- `413` -- File too large (exceeds `MAX_UPLOAD_SIZE_MB`)
|
||||
- `429` -- Rate limited
|
||||
- `500` -- Server error
|
||||
Reference in New Issue
Block a user