Offline-capable mushroom identifier for Finnish species. Image classification runs entirely in the browser as a PWA. There is no backend.
The full step-by-step plan is in docs/PLAN.md (in Finnish). Each phase is also a GitHub issue in English with the same number (phase 6 = #6), with tasks, dependencies and done criteria. Known problems in the plan are sub-issues of the phase they belong to. Read the issue and the matching PLAN.md section before starting work on a phase.
| Path | What | Where it runs |
|---|---|---|
training/ |
Python (uv, PyTorch, timm): data download, training, evaluation, ONNX export | Windows 11 desktop, WSL2 Ubuntu 24.04, NVIDIA RTX 3070 (8 GB VRAM, sm_86), 32 GB RAM |
data-meta/ |
lajilista.csv, split.csv, attribution data. Small files only |
– |
species/ |
species.json, hand-curated species info and verification checks |
– |
web/ |
Vite + TypeScript PWA, onnxruntime-web | User’s browser, deployed to GitHub Pages via Actions |
web/public/models/vN/ |
model.onnx, labels.json, preprocess.json, calibration.json |
Produced by training/, read by web/ |
Hosting: GitHub Pages at https://luukalindgren.github.io/seeni/, so Vite base is '/seeni/'. Later moving to the custom domain seeni.fi.
multimedia.txt; the occurrence license is not the image license. Store license, rights holder and source URL for every image in the manifest.~/seeni-data on the WSL filesystem (never under /mnt/c). .gitignore blocks the common image, data and checkpoint formats and re-includes only: the exported model in web/public/models/vN/, images under web/, species/ and docs/ (icons, check pictures, screenshots), test fixtures in tests/fixtures/, and attribution data in data-meta/. Committed images that are not our own work (fixtures, check pictures) must be CC0/CC-BY and credited in ATTRIBUTIONS.md. The ignore list is not exhaustive, so check git status before committing.gbifID), never by image.training/ and exported to preprocess.json. The web app reads it from there and never hardcodes values. Eval transform: resize shorter side to 256 → center crop 224 → RGB / 255 → normalize with mean/std → NCHW float32.cantharellus-cibarius, genus-level cortinarius), and muu for the unknown class. An id never changes once a model has been trained with it, and a class whose taxa change gets a new id. Taxa of different classes never overlap, not even through a genus. data-meta/lajilista.csv has one row per taxon and is the source of truth for each class’s taxa, group and lookalikes. Its in_model column marks the classes that are trained. Class order comes only from labels.json, written at training time: an ordered array of { "id", "taxonKeys" } whose position is the model output index. The web app never regenerates or re-sorts it. References between classes (lookalikes, check answers) use class ids, never indices or taxonKeys.web/tests/fixtures/, and Playwright compares the browser’s top-5 against them.lajilista.csv, even without images. One that is not a model class gets a warning-only record in species.json (its id is not in labels.json) and stays an open warning until a check rules it out. An answer rules out only the classes that the check lists, but not under that answer.lajilista.csv.species.json entry needs expert review (field tarkistanut) before release. LLM-drafted content is a draft only.LICENSE). Model files and species data are licensed separately (CC BY 4.0) and documented in README and ATTRIBUTIONS.md.Training
uv sync in training/). Its Linux wheels are CUDA builds, currently CUDA 13, which needs a Windows NVIDIA driver from the R580 series or newer. Keep it on PyPI if you can: cloud agent sessions cannot reach download.pytorch.org, so a lock that needs it cannot be synced there. After upgrading torch, tests/test_torch_build.py checks that the build still runs on the RTX 3070 (sm_86, or sm_80 code).seeni.paths.data_dir(), never from a hardcoded path.Evaluation
PLAN.md phase 7.T in calibration.json.Export
keep_io_types=True.Web app
['webgpu', 'wasm'], running in a Web Worker.createImageBitmap(file, { imageOrientation: 'from-image' }).PWA
maximumFileSizeToCacheInBytes to about 50 MB so the model gets precached (the default is 2 MiB).v1, v2).main directly./code-review on the PR and fix the most critical findings (correctness, safety, hard-rule violations) in the same PR. Lesser findings may stay, with a one-line reason in the PR.Closes #N or Refs #N).