Skip to content

Repository files navigation

AXERA Lite WebUI

A lightweight, local-first chat UI for OpenAI-compatible APIs.

It runs entirely in the browser, supports streaming responses, and stores conversations locally.

Demo

The clip below shows SD 1.5 text-to-image and image-to-image generation, then PaddleOCR performing OCR on an uploaded image — all from the same interface without any page reload or configuration change.

If the video does not play inline, click here to download / view it.

Features

  • OpenAI-compatible chat interface
  • Streaming responses
  • Markdown rendering with code highlighting and KaTeX math
  • Collapsible thinking / reasoning blocks (<think> tags)
  • Image generation (Draw mode) and image-to-image via compatible image APIs
  • Image upload and paste for vision-capable models
  • Audio transcription workflow for compatible APIs
  • Multiple API endpoints with per-endpoint model management
  • Model capability configuration (Vision, Audio, Draw) per endpoint
  • Generated images stored as data URLs — persist after backend restart
  • Local conversation history in the browser
  • Configurable context window and auto-reset threshold
  • Per-response performance metrics — TTFT and decode speed — via an optional backend interface
  • Light and dark themes

Requirements

  • Node.js 18+
  • An OpenAI-compatible API that supports:
    • GET /v1/models
    • POST /v1/chat/completions
  • Optional image generation:
    • POST /v1/images/generations or POST /v1/images/edits
  • Optional audio support:
    • POST /v1/audio/transcriptions

Quick Start

npm install
npm run dev

Open:

http://localhost:5173

First-Time Setup

  1. Open Settings.
  2. Enter your API Base URL.
  3. Enter your API Key if your provider requires one.
  4. Set Max Context Tokens to the real limit of your model.
  5. Adjust Auto-reset Threshold (%) if needed.
  6. Click Fetch Models — this saves the endpoint and fetches available models in one step.
  7. Enable the capabilities (Vision, Audio, Draw) that apply to each model.
  8. Select a model from the top bar.

Settings screen

API Base URL

Use the server root URL. Do not append /v1.

Correct:

http://127.0.0.1:8000
http://127.0.0.1:11434
https://your-api.example.com

Incorrect:

http://127.0.0.1:8000/v1
http://127.0.0.1:11434/v1

Multiple Endpoints

Add more than one endpoint in Settings to aggregate models from different servers. The model picker groups models by endpoint and switches the active endpoint automatically when you select a model.

Usage

  • Send: Enter
  • New line: Shift+Enter
  • Reset API context only: /reset
  • Clear current conversation and API context: /clean

Image Generation (Draw Mode)

  • Enable Draw for the model in Settings.
  • Click the Draw button in the input bar (auto-enabled for Draw-capable models).
  • Optionally attach a reference image for image-to-image generation.
  • Set a seed for reproducible results.
  • Click Regenerate below any generated image to redraw with a new seed.

Images

  • Upload an image with the image button, or paste an image into the input box.
  • The current model must have Vision enabled.

Audio

  • Attach an audio file from the input bar.
  • The current model must have Audio enabled.
  • Your API must support POST /v1/audio/transcriptions.

Context Badge

The ctx x/y badge in the input bar shows:

  • current estimated context usage
  • configured context window limit

When usage approaches the configured threshold, the app automatically resets API context before the next send.

Performance Metrics (TTFT, Prefill & Decode Speed)

After each streamed response, a small metrics row appears under the assistant message. It is fully data-driven: the frontend renders one pill per metric the backend reported, in a fixed order, and nothing when none are present:

⚡ TTFT 40 ms   ·   ⤴ prefill 220 tok/s   ·   ⏱ decode 36 tok/s   ·   in 43   ·   new 15   ·   out 512

This is a display UI: every number comes directly from the backend. The frontend never estimates or derives any value — client-side wall-clock timing includes network / proxy overhead and would misrepresent real inference speed (e.g. ~100 ms measured in the browser vs. ~40 ms actual prefill), and token counts are tokenizer/model-specific, not a character count. Send a field and its pill appears; omit it and the pill is not shown.

The interface

Request (already sent by the frontend). Every streaming request includes stream_options.include_usage, asking the backend to emit a final usage chunk:

POST /v1/chat/completions
{ "model": "...", "messages": [...], "stream": true,
  "stream_options": { "include_usage": true } }

Response (what the backend provides). In the final SSE chunk (before [DONE]), put the fields below on the standard usage object. Unknown fields are ignored by generic OpenAI clients, so this stays fully backward-compatible:

data: {"choices":[],"usage":{
  "prompt_tokens": 43,          // input tokens  → "in 43"   (standard field)
  "completion_tokens": 512,     // output tokens → "out 512" (standard field)
  "total_tokens": 555,          // not displayed (redundant with in/out)
  "ttft_ms": 39.96,             // ★ time to first token, milliseconds (server prefill latency)
  "prefill_tps": 220.0,         // ★ prefill throughput, tokens per second
  "decode_tps": 36.13,          // ★ decode throughput, tokens per second
  "prefill_tokens": 15          // ★ tokens actually prefilled this turn (rest reused from KV cache)
}}

data: [DONE]
Field Shown as Meaning
usage.ttft_ms TTFT Time to first token in milliseconds (server-side prefill latency)
usage.prefill_tps prefill Prefill (prompt-processing) throughput in tokens per second
usage.decode_tps decode Decode/generation throughput in tokens per second
usage.prompt_tokens in Input token count (standard OpenAI field; shown when > 0)
usage.prefill_tokens new Tokens actually prefilled this turn; shown only when < in (i.e. KV cache reused a prefix). Lets prefill_tps × prefill_time reconcile with what was really computed.
usage.completion_tokens out Output token count (standard OpenAI field; shown when > 0)

Field aliases also accepted: time_to_first_token_ms (TTFT), prefill_tokens_per_second (prefill), tokens_per_second (decode), input_tokens (in), prefilled_tokens (new), output_tokens (out). total_tokens and any other keys are ignored.

Each pill is independent, so partial data is fine — e.g. sending only ttft_ms shows just the TTFT pill. Emitting none of the recognized fields shows no metrics row at all.

Development and Deployment

Development

npm run dev

Development mode includes a built-in proxy, which is useful when your API does not allow browser CORS requests during local development.

Production Preview

npm run build
npm run preview

The production build is static. Your API must allow browser access directly, be served behind a reverse proxy, or share the same origin as the frontend.

Commands

npm run dev
npm run build
npm run preview
npm test

Data Storage

Settings, model capability overrides, theme preference, and conversations are stored in your browser with localStorage.

Generated images are converted to base64 data URLs on receipt and stored alongside the conversation, so they remain visible even after the backend is restarted or the page is reloaded.

Clearing site storage resets the app.

Troubleshooting

Fetch Models fails

  • Make sure API Base URL does not include /v1.
  • Confirm your API supports GET /v1/models.
  • If it works in npm run dev but fails in preview or production, check CORS.

Model list is empty

  • Click Fetch Models.
  • Verify the request succeeded.
  • Confirm your API returns models from GET /v1/models.

Image button is disabled

  • Enable Vision for the selected model in Settings.

Draw button is disabled

  • Enable Draw for the selected model in Settings.
  • Confirm your backend supports POST /v1/images/generations.

Audio button is disabled

  • Enable Audio for the selected model in Settings.
  • Confirm your backend supports audio transcription.

Requests fail even though the server is reachable

Make sure your backend is compatible with the OpenAI Chat Completions format, especially model, messages, and streaming responses.

About

A lightweight, local-first chat UI for OpenAI-compatible APIs.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages