v3.4.0
This release adds a one-command private full-host deploy to Modal, reworks the Modal GPU offload
into a warm, reusable worker that skips the per-job cold start, warms the tokenizer and dictionary at
startup, and takes the frontend edge-to-edge on notched phones. As a v3.x release (see the
v0.1.0 note above) it includes two breaking changes, listed first
Breaking Changes
-
REST API→ The Kanji dictionary endpoints now carry the Kanji as a query parameter instead
of a path segment (/dict/kanji/{literal}→/dict/kanji?literal=..., and likewise for
/strokes,/audio, and/audio/clip). A Kanji literal is always non-ASCII, and a Modal-hosted
deploy rejects any request whose URL path holds non-ASCII bytes, so the glyph is kept out of the
path. Clients of these endpoints need to adopt the query-parameter form -
Launcher→ The local data folder (managed config, logs, cached builds, and any non-Docker
data) is no longer keyed by the app version. Earlier versions stored it under a per-version
subfolder, so every upgrade silently started from an empty folder and orphaned the previous
install's data, despite the compose comment promising data survived version bumps. From3.4.0the
folder is unversioned, so future upgrades keep your data, but the one-time move to3.4.0does not
read a pre-3.4.0versioned folder. Re-enter your keys, or import the old file with
mirumoji config import <path>. The old data is left in place, not deleted, and Docker data volumes
are unaffected
Added
-
Launcher→mirumoji modal deployhosts theentireapp (the FastAPI server and the built
React frontend) privately on your ownModalaccount, with no local Docker.
It runs as a single always-warm CPU container gated by a browser login (HTTP Basic Auth), keeps
its database and media in a persistent Modal volume, and offloads GPU transcription to the same
worker the localmodalbackend uses.modal status,modal down, andmodal download-data
inspect, tear down, and back it up. The deploy image is composed from the published backend and
frontend images, so no new artifact ships. See the newModal Host Setup
guide -
Launcher→mirumoji config showgained--raw(reveal masked secret values, for reading a
generated web password) and--json(export the config) -
Frontend→ A backend-freelive demonow runs at the docs site root. A build-time
--mode demoswaps the network layer for committed fixtures captured from a real session, so a
pre-loaded sample episode (the player, tokenized subtitles, and word breakdowns) and a curated
dictionary slice work with no server. Off-rails input (upload, free search, profile switch) is
gated, and dictionary links outside the captured set are disabled
Changed
-
Server→ The Modal GPU offload now runs a single deployed, warm worker that loads the
multi-GB Whisper model once per container and stays warm for the scaledown window, instead of
spinning up an ephemeral app per job that reloaded the model every time. Back-to-back jobs skip the
cold start, while the worker still scales to zero when idle, so an idle GPU never costs you. The
server auto-deploys it on first use (tracked by ownership tags so it is never duplicated and rolls
forward on upgrade) and stops it on shutdown -
Server→ The Japanese tokenizer (fugashi/UniDic) and the dictionary (kotobase)
are warmed during startup, so the first tokenization and lookup are fast instead of paying a
one-time cold load. Each warm-up runs in a thread and only warns on failure, so a broken language
dependency degrades only its own endpoints while transcription and file management keep working -
Frontend→ The app goes edge-to-edge on notched phones (filling the letterbox bars via
viewport-fit=cover) while respecting safe-area insets across both headers, the drawer, the hover
rail, the floating button, the player toolbar, and the task tray. Every inset resolves to zero on a
non-notched display, so desktop and portrait layouts are unchanged
Fixed
-
Server→ The/health/systemprobe runs off the event loop. It shells out tonvidia-smi
(up to a 5s timeout), which previously blocked every other request while it waited -
Frontend→ The player adapts to a phone held in landscape, reusing the desktop side-by-side
subtitle rail instead of stacking the panel below the video and splitting the short height in half.
The subtitle-style popover is also bounded to the viewport with an internal scroll so it no longer
runs off a short landscape screen -
Server+Frontend→ Non-ASCII characters are kept out of URL paths and profile ids. The
frontend gates profile names to ASCII and the server rejects a non-ASCIIX-Profile-IDheader with
a400, so a profile named with Japanese or other Unicode text no longer produces invalid URLs or
ids (which also lets the whole app run on a Modal-hosted deploy) -
Launcher→mirumoji resetprunes themirumojifolder in everyplatformdirsroot (the
cache, config, state, and log locations), so a reset cleans up uniformly on Linux, macOS, and
Windows and leaves nothing orphaned