João Pedro Battistella Nadas 74b8877550 feat(ocr): crop + rotate modal before recognition
After picking an image, a modal opens with cropperjs's drag-handle
crop UI and Rotate left / Rotate right / Reset buttons. Cropping
to just the text region is the single biggest quality win for
OCR on phone photos — strips out logos, lighting transitions, and
background junk that bleed past the confidence filter.

- Lazy-loads cropperjs + its CSS from esm.sh on first use (no
  bundling; same pattern as Tesseract.js and CodeMirror).
- Honours EXIF orientation from phone shots (checkOrientation).
- Keyboard: Esc cancels, Enter accepts. Clicking the backdrop
  also cancels.
- Output goes through the existing preprocessForOCR pipeline
  (downscale to 1600px + Bradley adaptive threshold) before
  Tesseract sees it.
2026-06-09 19:02:51 +02:00
2026-06-09 17:22:26 +02:00

finrod

Tiny web translator backed by Ollama on radagast. Named for Finrod Felagund, Noldor loremaster of the tongues of Men.

Run

uv run uvicorn app:app --host 127.0.0.1 --port 8000 --reload

Then open http://127.0.0.1:8000.

Config

Env var Default Notes
OLLAMA_URL http://radagast.jpnadas.xyz:11434 Ollama base URL
MODEL_FILTER gemma,aya Comma-separated substrings; model matches if it contains any. Empty = show all

Models

For Pt/Nl/En translation, three worth A/B-ing:

ssh radagast 'ollama pull gemma2:9b'      # already there — big-and-broad baseline
ssh radagast 'ollama pull gemma3:4b'      # newer multilingual training, ~2-3× faster on Ivy Bridge
ssh radagast 'ollama pull aya-expanse:8b' # Cohere multilingual model, strong on Dutch

All three fit in radagast's 10 GB at Q4. Switching models in the dropdown forces Ollama to load the new weights — expect a 5-15 s pause on the first call after a switch while it reads from disk.

Build / push image

Built locally and pushed to Scaleway — no Gitea runners on the homelab yet, so there's no CI workflow.

One-time setup (host needs buildx + QEMU for cross-arch):

docker buildx create --name multi --use
docker run --privileged --rm tonistiigi/binfmt --install all
docker login rg.nl-ams.scw.cloud -u nologin -p <SCW_SECRET_KEY>

Then on every change:

./build.sh

That builds linux/amd64,linux/arm64 and pushes three tags:

  • :latest — moving pointer
  • :<git-short-sha> — immutable, traceable
  • :<pyproject-version> (e.g. :0.1.0) — semver

Deploy

Cluster manifests live in valinor/apps/finrod/ (bjw-s app-template, internal-only ingress at finrod.jpnadas.xyz). To roll out a new build, bump tag: in valinor/apps/finrod/values.yaml to the new semver on a branch → PR → merge → ArgoCD syncs.

Release workflow

This project uses Semantic Versioning and keeps a human-edited CHANGELOG.md.

To cut a release:

  1. On a branch, edit CHANGELOG.md: move accumulated [Unreleased] notes into a new ## [X.Y.Z] - YYYY-MM-DD section.
  2. Bump version in pyproject.toml to X.Y.Z.
  3. PR → merge to main.
  4. Tag the merge commit:
    git checkout main && git pull
    git tag -a vX.Y.Z -m "vX.Y.Z"
    git push origin vX.Y.Z
    
  5. ./build.sh — the image now also gets :X.Y.Z (read from pyproject.toml).
  6. In valinor, bump apps/finrod/values.yaml tag: from the previous version to X.Y.Z on a branch → PR → ArgoCD picks it up.
Description
No description provided
Readme 483 KiB
Languages
HTML 82.1%
JavaScript 7.2%
Python 6.3%
Dockerfile 2.4%
Shell 2%