New "Scan image" button in the input pane header: - Opens the phone's rear camera (capture=environment) or a desktop file picker via a hidden <input type="file">. - On image selected, lazy-imports tesseract.js from esm.sh — no bundling, no Docker image growth. - Language follows the "From" dropdown (ISO 639-2 mapping for the 30 currently-supported languages). "Auto-detect" loads the eng+por+deu+nld pack and lets tesseract pick. - Progress status renders below the input (engine load → OCR percentage → "done in Xs"). - Result replaces the editor contents; existing vim bindings, Shift-H/L nav, Ctrl-Enter translate all keep working. First scan triggers a ~5 MB Tesseract WASM download plus the chosen language pack (~3-10 MB). Cached by the browser after.
48 lines
3.3 KiB
Markdown
48 lines
3.3 KiB
Markdown
# Changelog
|
|
|
|
All notable changes to finrod are documented here.
|
|
|
|
Format: [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
Versioning: [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
|
## [Unreleased]
|
|
|
|
### Added
|
|
- "Scan image" button next to the input pane: opens the phone's rear camera (or a file picker on desktop), runs OCR locally in the browser via Tesseract.js (loaded from esm.sh on first use), and replaces the editor contents with the recognised text. Language follows the "From" dropdown via an ISO 639-2 mapping; "Auto-detect" loads a common European set (`eng+por+deu+nld`). Progress status shows beneath the input ("Loading OCR engine…" → "OCR 40%" → "OCR done in 3.2s"). Zero image-size cost — same CDN pattern as CodeMirror.
|
|
|
|
## [0.2.0] - 2026-06-09
|
|
|
|
### Added
|
|
- Vim bindings in the input via CodeMirror 6 + `@replit/codemirror-vim` (loaded from esm.sh, no build step). Supports `i`/`Esc`, `hjkl`, word/line motions, `dd`/`yy`/`p` (vim's internal register), undo/redo, `/` search, `:` command line. Auto-disabled on touch devices (detected via `(pointer: coarse)`) where modal editing fights the virtual keyboard.
|
|
- `Shift-H` / `Shift-L` cycle focus across the page controls (source → target → model → editor → button) like `Shift-Tab` / `Tab`. Also overridden in vim normal mode (replacing vim's viewport-top/bottom default) so the same shortcut works to leave the editor.
|
|
- On page load, the model dropdown defaults to whichever model Ollama already has hot — skips the 5-15 s disk-reload pain on the first translation. After load it follows the user's manual selection.
|
|
|
|
### Changed
|
|
- Editor font-size pinned to `1rem` to match the output pane (CodeMirror 6 ships smaller by default).
|
|
|
|
## [0.1.0] - 2026-06-09
|
|
|
|
First release. Stateless translator UI that proxies streaming requests to
|
|
Ollama on radagast.
|
|
|
|
### Added
|
|
- FastAPI backend with three endpoints:
|
|
- `GET /api/models` — filtered (`gemma,aya` by default) list from Ollama's `/api/tags`
|
|
- `POST /api/translate` — streams Ollama's NDJSON `/api/generate` response back to the browser
|
|
- `GET /api/loaded` — proxies Ollama's `/api/ps` for the currently-loaded model
|
|
- `GET /healthz` — for Kubernetes probes
|
|
- Single-page UI:
|
|
- Source / target / model dropdowns (30+ languages, "Auto-detect" source)
|
|
- Token-by-token streaming into the output pane with a blinking caret
|
|
- Live status line: spinner while waiting for first token, pulsing dot during streaming, elapsed time and token count
|
|
- Glowing border on the output pane during streaming
|
|
- Loaded-model indicator (`● ` prefix in dropdown, "Hot: … — unloads in Xm" status line); refreshes on page load, on translation completion, and 500 ms after typing pauses
|
|
- ⌘/Ctrl-Enter to translate from the input
|
|
- Dark mode, inline SVG favicon (Star of Fëanor)
|
|
- Dockerfile: two-stage `uv` build, slim Python 3.13 runtime
|
|
- `build.sh`: multi-arch (amd64 + arm64) manual push to Scaleway, tags `:latest`, `:<git-short-sha>`, and `:<pyproject-version>`
|
|
- Cluster deploy via the `valinor` repo at `apps/finrod/` (bjw-s app-template, internal-only ingress at `finrod.jpnadas.xyz`)
|
|
|
|
### Fixed
|
|
- Lock against public PyPI explicitly — the workstation's global `uv` config had pointed `uv.lock` sources at the dexterenergy private artifact registry, which 401'd inside Docker
|