Skip to content

vu2lid/hart-web

Repository files navigation

HART Web

A local web interface and HTTP API for HART text-to-image generation. Built with Nuxt 3 / Nitro; runs inside a Docker container that inherits your existing hart-cli GPU image.


Table of contents

  1. Prerequisites
  2. Project layout
  3. Environment variables
  4. Local development
  5. Docker deployment
  6. Rebuild & restart
  7. API reference
  8. Tests

1. Prerequisites

Requirement Notes
Docker + NVIDIA Container Toolkit GPU passthrough via gpus: all
hart-cli:thor image Base image with hart-txt2img on PATH
/data/hart/ host directory Models, outputs, and caches mounted here
Node.js 20+ Only needed for local dev; not required for Docker

Verify the CLI is available inside the base image:

docker run --rm hart-cli:thor which hart-txt2img

2. Project layout

pages/
  index.vue               # Browser UI
server/
  api/
    generate.post.ts      # POST /api/generate – spawns hart-txt2img
  middleware/
    00-req-logger.ts      # Per-request ID + timing logs
  routes/
    _debug.get.ts         # GET /_debug – liveness probe
    api.get.ts            # GET /api – 404 placeholder
    files/
      [name].ts           # GET|HEAD /files/:name – serve output PNGs
  utils/
    mutex.ts              # Single-slot non-queuing lock (queue size = 1)
tests/
  _utils.ts               # h3 test server helper
  files.test.ts           # File-serving route tests
  generate.test.ts        # Generate endpoint tests
nuxt.config.ts
docker-compose.yml
Dockerfile

3. Environment variables

All variables have sensible defaults; nothing is required to change for a standard /data/hart layout.

Variable Default Description
MODEL_PATH /workspace/models/hart-0.7b-1024px/llm Path to the HART LLM
TEXT_MODEL_PATH /workspace/models/Qwen2-VL-1.5B-Instruct Path to the text encoder
OUT_DIR /workspace/outputs/hart_samples Directory where PNGs are written
MAX_PROMPT_LEN 600 Maximum prompt character length
QUEUE_SIZE 1 Concurrent generation slots (only 1 supported)
TIMEOUT_SECS 600 Generation timeout before SIGKILL
VERBOSE true Enable request/response logging
HART_PORT 3011 Host port mapped to the container
HART_UID / HART_GID $(id -u) / $(id -g) UID/GID the container process runs as (set in .env)
NUXT_APP_BASE_URL / Set if serving under a sub-path

4. Local development

cp .env.example .env   # adjust paths/ports if your layout differs
npm install
npm run dev          # starts on http://localhost:3011 (hot-reload)
npm run build        # production build → .output/
npm run start        # serve the production build
npm test             # run vitest suite

Local dev runs the Nuxt dev server directly; it still calls hart-txt2img from your host PATH, so the CLI and models must be accessible on the host.


5. Docker deployment

Images are built on top of hart-cli:thor and include Node.js 20 copied from the official slim image.

First-time setup:

# Create required host directories if they don't exist
mkdir -p /data/hart/{models,outputs/hart_samples,cache,tmp,triton}

docker compose up -d

Host volumes:

Host path Container path Mode
/data/hart/models /workspace/models read-only
/data/hart/outputs /workspace/outputs read-write
/data/hart /workspace read-write
/data/hart/cache /workspace/.cache read-write
/data/hart/tmp /workspace/.tmp read-write
/data/hart/triton /workspace/.triton read-write

The container is placed on an internal network (no outbound internet) with only the HTTP port published to the host, and all HuggingFace/W&B offline flags are set.


6. Rebuild & restart

cd hart-web
docker compose down
docker compose build --no-cache
sudo systemctl restart hart-web

7. API reference

POST /api/generate

Generate an image from a text prompt.

Request body (JSON):

{
  "prompt": "sunset drone view of a city in the Swiss Alps, 35mm, golden hour",
  "seed": 42, // optional, integer 0–2147483647, default 42
  "embedMetadata": true, // optional, embeds iTXt chunk in PNG, default true
}

Success response 200:

{
  "ok": true,
  "file": "/files/00010-42-edf1a587.png",
  "prompt": "...",
  "seed": 42,
  "embedMetadata": true,
  "duration_ms": 18423,
}

Error responses:

Status error Reason
400 bad_request Missing/invalid prompt or seed
429 busy A generation is already in progress
500 generation_failed CLI exited non-zero or no output found
504 timeout CLI exceeded TIMEOUT_SECS

GET /files/:name

Serve a generated PNG by filename. Also supports HEAD for existence checks.

  • Name must match ^[0-9]{5,}-[0-9]+-[0-9a-f]{8}\.png$
  • Returns Content-Type: image/png with a 24 h immutable cache header
  • Returns 400 for invalid names, 404 if the file is not found
curl -I "http://localhost:3011/files/00010-42-edf1a587.png"

GET /_debug

Returns ok — simple liveness check.


8. Tests

npm test

Uses Vitest with lightweight in-process h3 servers (no real GPU/CLI needed). The node:child_process spawn is mocked in generate.test.ts.

About

Local web UI and HTTP API for HART text-to-image generation, built with Nuxt 3 / Nitro - wraps a hart-cli:thor GPU container.

Topics

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors