The dictation module provides in-app voice input for Bihar Police officers writing Hindi letters and FIR diaries. It is implemented as a pure state-machine engine with no DOM dependency — all UI concerns are handled separately byDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/arverma/Bihar-Police-Notebook/llms.txt
Use this file to discover all available pages before exploring further.
dictation-ui.js. The engine communicates exclusively through callbacks and is designed to survive language-pack discovery, cloud consent flows, and recognition interruptions without losing the active session.
The dictation FAB is hidden on screens ≤ 768 px via CSS and
syncFabVisibility(). Mobile users should use their device keyboard’s built-in microphone instead.Constants
LANGS
hi-IN is Hindi (India); en-IN is English (India).
DEFAULT_LANG
Spoken Punctuation — applyVoiceEdits(text)
onFinal result before it is inserted into the editor.
| Spoken phrase | Inserted character |
|---|---|
नया पैराग्राफ | \n\n (new paragraph) |
नई लाइन | \n (new line) |
पूर्ण विराम | । (Hindi full stop / danda) |
अल्पविराम | , (comma) |
प्रश्न चिह्न | ? (question mark) |
new paragraph | \n\n |
new line | \n |
full stop | । |
question mark | ? |
comma | , |
Raw transcript string from
SpeechRecognitionResult. Returns an empty string when falsy.Device and Permission Probes
isDictationSupported()
true if SpeechRecognition or webkitSpeechRecognition is available on window. Used to gate the FAB render in dictation-ui.js.
probePackAvailability(lang)
SpeechRecognition.available()) to determine whether a language pack is installed. Tries 'dictation' quality first, then 'command', then no-quality as a fallback. Returns 'unsupported' when the static available() method does not exist (non-Chrome or older browser).
Language pack is installed and ready for on-device recognition.
Pack can be installed by calling
installLanguagePack.Pack is currently being downloaded.
Pack is not available for this language on this device.
The
SpeechRecognition.available() API is not present.installLanguagePack(lang)
lang. Must be called from a user gesture. Tries 'dictation' and 'command' quality tiers before attempting a generic install. Returns false if the SpeechRecognition.install() API is unavailable; returns true when the install succeeds.
queryMicPermission()
microphone permission without prompting the user. Falls back to 'unknown' when the Permissions API is unavailable or rejects the microphone name (as some browsers do).
Cloud Consent
The engine gates cloud-based recognition behind an explicit per-language user consent to make the privacy boundary clear. Consent is stored inlocalStorage via prefs.js.
hasCloudConsent(lang)
true if the user has previously consented to cloud speech for the given language BCP-47 tag.
setCloudConsent(lang, bool)
continueWithCloud() after the user approves the cloud consent sheet in dictation-ui.js.
Engine — createDictationEngine(callbacks)
Callbacks
Fired on every status transition.
detail may carry { lang } for needs-consent or { code } for error.Fired with the partial (non-final) transcript during active recognition. Called with
'' to clear the interim display.Fired with the final transcript after
applyVoiceEdits has been applied. dictation-ui.js passes this to main.js’s insertDictatedText.Fired when the recognition mode changes between on-device (
true) and cloud (false).Fired on each animation frame with a normalised audio level
[0, 1] derived from an AnalyserNode. Used to animate the FAB’s audio meter.Fired for
SpeechRecognitionError codes other than no-speech and aborted (which are silently ignored).Fired when the engine transitions to
needs-consent, passing the language that requires approval.Engine Status Values
| Status | Meaning |
|---|---|
idle | No session running |
listening | Recognition active, microphone open |
paused | Session suspended; mic released |
needs-consent | On-device pack unavailable, waiting for cloud consent |
error | Unrecoverable error (e.g. mic denied) |
Engine Methods
start(opts?)
forceCloud is set), and starts SpeechRecognition. If on-device is unavailable and no cloud consent exists, transitions to needs-consent and returns false. Returns true on successful start.
pause()
SpeechRecognition instance and releases the audio level loop. The session remains sessionActive so resume() can restart it. The microphone stream is kept open.
resume()
SpeechRecognition instance and resumes the audio level loop. Transitions status from paused back to listening.
stop()
idle.
toggle()
listening, resumes when paused, starts when idle. Returns a string describing the action taken.
setLanguage(lang)
listening, restarts recognition immediately in the new language (with a consent check for cloud). If paused, the new language is adopted on the next resume().
continueWithCloud()
setCloudConsent, then calls start({ forceCloud: true }). Called from the consent sheet in dictation-ui.js.
requestMic()
Engine Getters
| Method | Returns |
|---|---|
getStatus() | Current DictationStatus string |
getLang() | Current language BCP-47 tag |
isOnDevice() | true when the current session uses on-device recognition |
isSessionActive() | true when the session is listening or paused |
Engine Internals
Audio Level Metering
The engine creates anAudioContext and AnalyserNode from the microphone MediaStream. On each animation frame, it computes the RMS amplitude of the time-domain waveform and emits a normalised [0, 1] level via callbacks.onLevel:
listening.
Auto-Restart on onend
Chrome’s SpeechRecognition fires onend after a few seconds of silence. The engine restarts the recogniser after a 100 ms delay:
2-Minute Idle Timeout
If the session runs for two minutes without anyonresult event, stop() is called automatically:
bumpIdleWatch() resets this timer on every recognition result.
On-Device → Cloud Fallback
When theSpeechRecognition fires onerror with language-not-supported during an on-device session, the engine checks hasCloudConsent. If consent exists, it falls back to cloud recognition in place without interrupting the session. If consent is missing, it transitions to needs-consent.
dictation-ui.js
dictation-ui.js provides the FAB DOM and wires it to the engine created in main.js.
FAB rendering
Renders a floating action button with an audio-level ring. Visible only on screens wider than 768 px;
syncFabVisibility() enforces this on resize.Draggable FAB
The FAB is draggable so officers can reposition it away from content they are reading. Position is not persisted across page reloads.
Keyboard shortcut
Ctrl+Shift+D toggles the dictation session from anywhere in the editor.Esc to end
Pressing
Esc during an active session calls stop() and dismisses any interim transcript. Handled in the capture phase so it fires before other keydown handlers.