Skip to content

Latest commit

 

History

History
367 lines (292 loc) · 14 KB

File metadata and controls

367 lines (292 loc) · 14 KB

smallFactory Web UI

A modern, clean web interface for the smallFactory Git-native PLM system.

Features

  • Dashboard: Inventory overview with quick stats and recent items
  • Inventory:
    • List and view items with per-location breakdown
    • Quick Adjust page at /inventory/adjust (GET, POST) with QR-scanning
    • Adjust quantities by location
    • Note: Deleting inventory items is not supported in the journal model. Use negative adjustments instead.
  • Entities (PLM):
    • Create, list, and view canonical entities (SFIDs)
    • Inline editing on the entity view page (separate Edit page is deprecated)
    • Build events: timeline-style notes/tests/files for b_* entities
    • Revisions: bump and release; released pointer at entities/<sfid>/refs/released
    • BOM: add, remove, set lines, and manage alternates; rev: released resolves via pointer
    • Files working area: manage under entities/<sfid>/files/ (list, mkdir, upload, move, delete)
  • Stickers: Batch PDF generation of QR code labels for multiple SFIDs
  • Vision (Ollama/OpenRouter): Generic image Q&A and invoice part extraction
  • Modern UI: Clean, responsive Tailwind CSS design
  • Git-native: Core APIs commit on writes; web can optionally autopush

Quick Start

  1. Install dependencies:

    pip3 install -r web/requirements.txt
  2. Ensure smallFactory is configured:

    # Make sure you have a data repository set up
    python3 sf.py init
  3. Start the web server:

    # from project root
    python3 sf.py web --port 8080
    # development mode with auto-reload
    FLASK_ENV=development python3 sf.py web --port 8080 --debug
  4. Access the interface: Open your browser to http://localhost:8080

  5. (Optional) Connect AI clients via MCP:

    • MCP endpoint (streamable HTTP): http://localhost:8080/mcp
    • See detailed client setup examples: docs/users/mcp.md

Development

To run in development mode with auto-reload:

FLASK_ENV=development python3 sf.py web --port 8080 --debug

Configuration

  • SF_WEB_SECRET: Flask secret key. Defaults to an insecure dev value.
  • PORT / --port: Port for the web server (default 8080).
  • FLASK_ENV / --debug: Set development or pass --debug for auto-reload.
  • SF_VISION_PROVIDER: Vision provider. Supported values: ollama (default) or openrouter.
  • SF_VISION_MODEL: Vision model identifier. For Ollama, defaults to qwen2.5vl:3b. For OpenRouter, set to a provider-qualified name (e.g., google/gemma-3-12b-it:free).
  • If using Ollama: SF_OLLAMA_BASE_URL (default http://localhost:11434).
  • If using OpenRouter: SF_OPENROUTER_API_KEY (required), SF_OPENROUTER_BASE_URL (default https://openrouter.ai/api/v1).
  • Optional: SF_REPO to point to a specific data repository path (follows the same resolution as the CLI).

Proxy-auth user identity for Git commits (web only)

When the web UI performs write operations, it will use proxy-provided headers to attribute Git commits to the active user. If headers are absent, behavior falls back to existing Git config/environment (no change for CLI).

  • Default header names checked (first match wins):
    • User: X-Forwarded-User, X-Auth-Request-User
    • Email: X-Forwarded-Email, X-Auth-Request-Email
  • Override header names via env (comma-separated list allowed):
    • SF_WEB_IDENTITY_HEADER_NAME (e.g., SF_WEB_IDENTITY_HEADER_NAME=X-Forwarded-Preferred-User)
    • SF_WEB_IDENTITY_HEADER_EMAIL
  • If only an email-like value is present, the display name is derived from the local part (e.g., jane.doe -> Jane Doe).
  • Applies only to web requests; the CLI continues to use the caller's local Git identity.

Architecture

The web UI is built as a Flask application that uses the smallFactory core v1 API:

  • app.py: Main Flask application with routes
  • templates/: Jinja2 HTML templates
    • base.html: Base template with navigation and common elements
    • index.html: Dashboard page
    • inventory/: Inventory pages
    • entities/: Entity list/view/build and related pages
    • stickers/: Batch stickers UI
    • vision.html: Mobile-friendly camera/upload page for Vision
  • static/: Static assets (CSS, images, JS)
  • sf.py web: CLI entrypoint to run the development server

API Integration

The web UI directly imports the smallFactory core v1 API:

from smallfactory.core.v1.inventory import inventory_onhand_readonly, inventory_post
from smallfactory.core.v1.entities import (
    get_entity, create_entity, update_entity_fields,
    get_revisions, bump_revision, release_revision,
    append_build_event, update_build_event, update_build_event_tags, add_build_event_file_link,
    bom_list, bom_add_line, bom_remove_line, bom_set_line, bom_alt_add, bom_alt_remove,
)
from smallfactory.core.v1.files import list_files, mkdir, rmdir, upload_file, delete_file, move_file, move_dir
from smallfactory.core.v1.stickers import generate_sticker_for_entity
from smallfactory.core.v1.vision import ask_image, extract_invoice_part

This ensures feature parity with the CLI while keeping storage Git-native and YAML-based. The working area root for entity files is files/.

GET endpoints are pure (no side effects)

  • All HTTP GET routes must be side-effect free: no cache writes and no Git mutations.
  • Inventory reads in GET paths use the read-only helper inventory_onhand_readonly() to avoid writing onhand caches.
  • Mutations happen only via POST routes, which are wrapped in a transaction helper that can optionally push.
  • CLI parity: use sf inventory onhand --readonly to compute on-hand without writing caches from the command line.

Future Extensions

The UI is designed to be extensible for additional PLM modules:

  • Project tracking
  • Supplier management
  • Approval/change control workflows
  • Reporting and analytics

Each new module can follow the same pattern with its own template directory and routes.

Vision (configurable provider: Ollama or OpenRouter)

The web UI can call a local or remote Visual LLM (VLM) via either:

  • Ollama (self-hosted, local inference)
  • OpenRouter (hosted API compatible with OpenAI chat API)

We recommend qwen2.5vl:3b on Ollama for a lightweight, high-quality local model; or a vision-capable model on OpenRouter such as google/gemma-3-12b-it:free.

1) Start Ollama and pull the model

macOS (Homebrew):

brew install ollama
ollama serve &
ollama pull qwen2.5vl:3b

Linux: install from https://ollama.com/download, then:

ollama serve &
ollama pull qwen2.5vl:3b

Verify the API:

curl http://localhost:11434/api/tags

2a) Configure smallFactory to use Ollama

Defaults assume a local Ollama at http://localhost:11434. To override, set:

export SF_VISION_PROVIDER=ollama
export SF_OLLAMA_BASE_URL=http://<ollama-host>:11434
export SF_VISION_MODEL=qwen2.5vl:3b

### 2b) Configure smallFactory to use OpenRouter

Sign up and obtain an API key at https://openrouter.ai/

```bash
export SF_VISION_PROVIDER=openrouter
export SF_OPENROUTER_API_KEY=sk-or-...
# Optional override; defaults to https://openrouter.ai/api/v1
export SF_OPENROUTER_BASE_URL=https://openrouter.ai/api/v1
# Choose a model identifier supported by OpenRouter
export SF_VISION_MODEL=google/gemma-3-12b-it:free

### 3) Install web deps and run

```bash
pip3 install -r requirements.txt
python3 sf.py web --port 8080

4) Use the Vision API

  • Generic ask (prompt + image):
curl -s -X POST http://localhost:8080/api/vision/ask \
  -F "prompt=Summarize the contents of this image in 1-2 sentences." \
  -F "file=@/path/to/invoice.jpg" | jq
  • Extract part fields from an invoice:
curl -s -X POST http://localhost:8080/api/vision/extract/part \
  -F "file=@/path/to/invoice.jpg" | jq

If you see an error, ensure the provider is correctly configured:

  • For Ollama: verify the service is running and the model is pulled.
  • For OpenRouter: verify SF_OPENROUTER_API_KEY is set and the model id is valid.

You can also open the Vision page at /vision for a camera/upload UI.

Troubleshooting: Vision

  • Missing prompt (400)

    • Error: Missing prompt
    • Fix: Include -F "prompt=..." in the form when calling /api/vision/ask.
  • No image or wrong field (400)

    • Error: No image file uploaded under field 'file'.
    • Fix: Send the image as -F "file=@/path/to/image.jpg".
  • Unsupported file type (400)

    • Error: Unsupported file type; expected an image.
    • Fix: Upload a valid image (jpg/png). The server re-encodes to PNG.
  • Image too large (400)

    • Error: Image too large (max 10MB).
    • Fix: Reduce the image size below 10MB.
  • Provider not configured / runtime error (500)

    • If using Ollama:
      • Start Ollama: ollama serve
      • Pull model: ollama pull qwen2.5vl:3b
      • Verify: curl http://localhost:11434/api/tags
      • Remote host: export SF_OLLAMA_BASE_URL=http://<host>:11434
      • Model name: set/confirm SF_VISION_MODEL (default qwen2.5vl:3b).
    • If using OpenRouter:
      • Ensure API key is set: export SF_OPENROUTER_API_KEY=...
      • Confirm base URL (optional): export SF_OPENROUTER_BASE_URL=https://openrouter.ai/api/v1
      • Choose a valid model id (e.g., google/gemma-3-12b-it:free) via SF_VISION_MODEL

Container

The web UI can run in Docker for easy deployment.

  • Build

    docker build -t smallfactory-web:latest .
  • Run (init new repo)

    docker run --rm -p 8080:8080 \
      -e SF_WEB_SECRET=replace-me \
      -v $PWD/datarepo:/datarepo \
      smallfactory-web:latest
  • Run (clone existing datarepo)

    docker run --rm -p 8080:8080 \
      -e SF_WEB_SECRET=replace-me \
      -e SF_REPO_GIT_URL=https://github.com/you/your-datarepo.git \
      -v $PWD/datarepo:/datarepo \
      smallfactory-web:latest
  • Environment variables

    • PORT (default 8080)
    • SF_REPO_PATH (default /datarepo) – container-side path to the data repo
    • SF_REPO_GIT_URL – if set and the repo path is empty, the container will git clone here
    • SF_REPO_NAME – name used when initializing a new repo (default datarepo)
    • SF_WEB_SECRET – Flask secret key (required for non-dev)
    • SF_WEB_AUTOPUSH, SF_WEB_AUTOPUSH_ASYNC, SF_GIT_PUSH_TTL_SEC, SF_GIT_PULL_ALLOW_UNTRACKED – Git orchestration knobs
    • SF_OLLAMA_BASE_URL, SF_VISION_MODEL – Vision integration
  • docker-compose.yml (example)

    services:
      web:
        image: smallfactory-web:latest
        build: .
        ports:
          - "8080:8080"
        environment:
          SF_WEB_SECRET: change-me
          SF_OLLAMA_BASE_URL: http://ollama:11434
        volumes:
          - datarepo:/datarepo
        healthcheck:
          test: ["CMD", "curl", "-fsS", "http://127.0.0.1:8080/"]
          interval: 30s
          timeout: 5s
          retries: 3
          start_period: 10s
    volumes:
      datarepo:

Notes:

  • The container entrypoint writes .smallfactory.yml setting default_datarepo: /datarepo and prepares the repo (clone or init).
  • Mount /datarepo as a persistent volume in production.

Routes and API Reference

  • UI Routes
  • / — Dashboard
  • /vision — Vision camera/upload page
  • /inventory — Inventory list
  • /inventory/<item_id> — Inventory item view
  • /inventory/adjust — Quick adjust (GET, POST)
  • /inventory/<item_id>/edit — Edit inventory item (GET, POST)
  • /entities — Entities list
  • /entities/<sfid> — Entity view (inline editing)
  • /entities/add — Create entity (GET, POST)
  • /entities/<sfid>/edit — Deprecated; use inline editing
  • /entities/<sfid>/retire — Retire entity (POST)
  • /entities/<sfid>/build — Build flow (GET, POST)
  • /entities/<sfid>/build/create-revision — Create next draft revision (POST)
  • /stickers — Redirect to batch stickers UI
  • /stickers/batch — Batch stickers UI (GET, POST)

Note: The legacy POST route /inventory/<item_id>/adjust has been removed in favor of the unified Quick Adjust flow at /inventory/adjust.

  • API Endpoints
    • /api/inventory — Inventory API (GET)
    • /api/inventory/<item_id> — Inventory item (GET)
    • /api/entities — Entities API (GET)
    • /api/entities/<sfid> — Entity (GET)
    • /api/entities/<sfid>/update — Update entity fields (POST)
    • /api/entities/<sfid>/events — List build events (GET; b_* only)
    • /api/entities/<sfid>/events/append — Append build event (POST; b_* only)
    • /api/entities/<sfid>/events/<event_id>/update — Update build event (POST; b_* only)
    • /api/entities/<sfid>/events/<event_id>/tags — Replace build event tags (POST; b_* only)
    • /api/entities/<sfid>/events/<event_id>/files/link — Link existing files/ path to event (POST; b_* only)
    • /api/entities/<sfid>/revisions — Get revisions and released pointer (GET)
    • /api/entities/<sfid>/revisions/bump — Cut and release a revision (POST; optional rev in body, otherwise next numeric)
    • /api/entities/<sfid>/revisions/<rev>/release — Release a specific revision (POST)
    • /api/entities/<sfid>/revisions/<rev>/download — Download released revision tarball (GET)
    • /api/entities/<sfid>/bom — BOM list (GET)
    • /api/entities/<sfid>/bom/deep — Resolved BOM tree (GET)
    • /api/entities/<sfid>/bom/add — Add BOM line (POST)
    • /api/entities/<sfid>/bom/remove — Remove BOM line(s) (POST)
    • /api/entities/<sfid>/bom/set — Update BOM line (POST)
    • /api/entities/<sfid>/bom/alt-add — Add alternate part (POST)
    • /api/entities/<sfid>/bom/alt-remove — Remove alternate part (POST)
    • /api/entities/<sfid>/files — List working files (GET)
    • /api/entities/<sfid>/files/mkdir — Create folder (POST)
    • /api/entities/<sfid>/files/rmdir — Remove folder (POST)
    • /api/entities/<sfid>/files/upload — Upload file (POST)
    • /api/entities/<sfid>/files/delete — Delete file (POST)
    • /api/entities/<sfid>/files/move — Move file/folder (POST)
    • /api/entities/<sfid>/files/download — Download file (GET)
    • /api/entities/specs/<sfid> — Entity specs (GET)
    • /api/vision/ask — Vision ask (POST)
    • /api/vision/extract/part — Extract part fields (POST)