Offline asr integration with all-1.4.2#400
Offline asr integration with all-1.4.2#400gouravmore wants to merge 70 commits intoSunbird-ALL:all-1.4.2-offlinefrom
Conversation
sandbox deployment
IssueId #223070 feat: Implementation & integration with current code
Task #223066 feat: Added wasm configuation and tested
IssueId #223067 feat: Load model and store it to indexdb for caching
Task #223068 Get Audio data from microphone and send it whisper cpp function
…lds in API for offline call
Task #223069 & #223071 Fuzzball js integration done and added new fields in API for offline call
issueid #223924 fix: whisper model is not loading properly in offline-model
…sovery start page
Issueid #223945 fix: When user is loggin out we are redirecting to Di…
#000 fix: gujrati language is not able to select
All 1.3 dev offline
…aspeech Vite conversion and offline english gigaspeech sherpa
…aspeech indic-wasm pkg added
WalkthroughThis update introduces comprehensive offline speech recognition capabilities, including IndexedDB model caching, offline model management, and WASM-based audio processing. New React components and hooks provide download progress feedback and offline practice logic. The codebase now supports multiple languages offline, adds new utility modules for audio and model management, and updates the UI and configuration for enhanced offline and online workflows. Changes
Sequence Diagram(s)Offline Model Loading and Assessment FlowsequenceDiagram
participant User
participant AssesmentComponent
participant OfflineModelManager
participant IndexedDB
participant WASMModule
participant UI
User->>AssesmentComponent: Selects language and mode (offline/online)
AssesmentComponent->>OfflineModelManager: openDB()
OfflineModelManager->>IndexedDB: Open/create DB
OfflineModelManager-->>AssesmentComponent: DB ready
AssesmentComponent->>OfflineModelManager: isModelStored(lang)
OfflineModelManager->>IndexedDB: Check model presence
OfflineModelManager-->>AssesmentComponent: Model found?
alt Model not found
AssesmentComponent->>OfflineModelManager: storeModel(lang, url, progressCb)
OfflineModelManager->>IndexedDB: Store model (with progress)
OfflineModelManager-->>AssesmentComponent: Model stored
end
AssesmentComponent->>OfflineModelManager: loadOfflineModelSession(lang)
OfflineModelManager->>IndexedDB: Retrieve model data
OfflineModelManager->>WASMModule: Initialize session
OfflineModelManager-->>AssesmentComponent: Session ready
AssesmentComponent->>UI: Update loading/progress indicators
User->>AssesmentComponent: Start assessment
AssesmentComponent->>WASMModule: Run audio preprocessing and decoding
WASMModule-->>AssesmentComponent: Transcription results
AssesmentComponent->>UI: Display results
Offline Practice and Reattempt LogicsequenceDiagram
participant User
participant PracticeComponent
participant WordsOrImage
participant VoiceAnalyser
participant WASMModule
participant UI
User->>PracticeComponent: Starts practice session (offline)
PracticeComponent->>WordsOrImage: Render with offilnePractice=true, setOfflineReport
WordsOrImage->>VoiceAnalyser: Record and process audio
VoiceAnalyser->>WASMModule: Transcribe (denoised & non-denoised)
WASMModule-->>VoiceAnalyser: Transcription results
VoiceAnalyser->>WordsOrImage: setOfflineReport({fluency, ...})
WordsOrImage-->>PracticeComponent: Report fluency result
PracticeComponent->>UI: Show progress
alt End of question set
PracticeComponent->>PracticeComponent: Check offlineReports for failed items
alt Failed items exist, not reattempted yet
PracticeComponent->>UI: Show reattempt dialog
PracticeComponent->>PracticeComponent: Set questions = failed items, reset index
else No failed items or already reattempted
PracticeComponent->>UI: Show success dialog
end
end
Offline Model Download Progress FeedbacksequenceDiagram
participant AssesmentComponent
participant OfflineModelManager
participant UI (ProgressOverlay/ModelLoaderIndicator)
AssesmentComponent->>OfflineModelManager: storeModel(..., setDownloadProgress)
loop During download
OfflineModelManager->>UI: setDownloadProgress(percent)
UI->>User: Update progress bar/indicator
end
OfflineModelManager-->>AssesmentComponent: Download complete
UI->>User: Hide progress overlay
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
npm error code ERESOLVE ✨ Finishing Touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
Documentation and Community
|
|
There was a problem hiding this comment.
Actionable comments posted: 36
🔭 Outside diff range comments (5)
src/services/telementryService.js (1)
13-16:⚠️ Potential issueJWT decode is not wrapped in a try/catch – malformed tokens will crash the app.
jwtDecodethrows on invalid input. Guard the call and set a fallback to keep telemetry functional for anonymous users.-let jwtToken = getLocalData("token"); -var userDetails = jwtDecode(jwtToken); +let userDetails = {}; +try { + const jwtToken = getLocalData("token"); + if (jwtToken) { + userDetails = jwtDecode(jwtToken); + } +} catch (_) { + console.warn("Invalid JWT in localStorage ‑ proceeding anonymously"); +}src/components/AssesmentEnd/AssesmentEnd.jsx (1)
85-89: 🛠️ Refactor suggestionHard-coded
true ?ternary is a dead-code smell
return true ? ( … ) : ( … );always renders the first branch and makes future intent unclear. Replace with a simplereturn (or keep a real boolean flag.- return true ? ( + return (🧰 Tools
🪛 Biome (1.9.4)
[error] 85-85: Unexpected constant condition.
(lint/correctness/noConstantCondition)
index.html (1)
1-34:⚠️ Potential issueCSP meta tag removal weakens security
The previous CSP (per diff summary) is gone. WASM & external scripts require extra directives, but dropping CSP entirely re-opens XSS vectors.
Re-introduce CSP with:<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' https://cdn.jsdelivr.net; connect-src 'self' blob:; worker-src 'self';">and extend as needed for WASM (
script-src 'self' 'wasm-unsafe-eval').
Do not leave the app without CSP in production.src/components/Mechanism/WordsOrImage.jsx (1)
1222-1263: 🛠️ Refactor suggestionPropTypes missing for new props and loosened
handleBack
- Add entries for
offlinePractice(bool) andsetOfflineReport(func).handleBackwas relaxed toPropTypes.any; unless strictly required this weakens type-safety. Usefuncand mark as optional:- handleBack: PropTypes.any, + handleBack: PropTypes.func, + offlinePractice: PropTypes.bool, + setOfflineReport: PropTypes.func,src/views/LoginPage/LoginPage.css (1)
9-18: 🛠️ Refactor suggestion
.containerclass name collides with global semantics and duplicates.loginPage__containerA generic selector like
.containerrisks unintended side-effects across the app and violates the BEM-style naming you use elsewhere (loginPage__container). Consider deleting the rule or renaming it to something page-scoped (e.g..loginPage__background).-.container { +/* .loginPage__background */
♻️ Duplicate comments (1)
src/components/Mechanism/WordsOrImage.jsx (1)
1186-1207: Prop drilling keeps the typo alive
offilnePracticeis forwarded twice toVoiceAnalyser. Fix once the prop is renamed; otherwise downstream components will still receive the wrong key.
🧹 Nitpick comments (57)
asr-utils/.gitignore (1)
1-5: Enhance ignore patterns for wasm-pack artifacts
Consider extending the.gitignoreto cover generated WebAssembly package files underpkg/(e.g.,pkg/*.js,pkg/*.d.ts,pkg/*.wasm) if those are rebuildable and shouldn’t be committed. You may also want to ignore common editor/OS files like.DS_Storeor*.swp.src/components/DiscoverSentance/DiscoverSentance.jsx (1)
3-3: Remove unused Axios import
axiosis imported but not used (the related code is commented out). Please remove this import to avoid dead code and bundle bloat, or re-enable the HTTP call if intended.src/utils/Loader.jsx (2)
1-2: React import may be redundant
If your project uses React 17+ with the automatic JSX runtime, you can removeimport React from "react";to slim the bundle.
4-15: Add accessibility attributes
Enhance the loader for screen readers by adding ARIA roles (e.g.,role="status") and a visually hidden message viaaria-live="polite"so users know a loading state is active.src/components/CommonComponent/CircularProgressOverlay.jsx (1)
1-2: React import not required with new JSX transform
With React 17+ and the automatic JSX runtime,import React from "react";can be safely removed to reduce unused dependencies.src/utils/useFFmpeg.jsx (2)
2-2: Remove the unusedfetchFileimport.
fetchFileis never referenced in this module. Keeping unused imports bloats the bundle size and will trigger lint / TS errors in stricter setups.-import { createFFmpeg, fetchFile } from "@ffmpeg/ffmpeg"; +import { createFFmpeg } from "@ffmpeg/ffmpeg";
15-19: MakecorePathconfigurable.Hard-coding the
corePathties the app to a specific CDN version. Accept a parameter or read from an env var so updates can be rolled out without code changes.- corePath: - "https://unpkg.com/@ffmpeg/core@0.11.0/dist/ffmpeg-core.js", + corePath: + import.meta.env.VITE_FFMPEG_CORE_PATH ?? + "https://unpkg.com/@ffmpeg/core@0.11.0/dist/ffmpeg-core.js",src/components/DownloadProgressModal.jsx (2)
6-10: Provide anonClosehandler to keep the modal accessible.Without
onClose, users cannot dismiss the modal with ESC or backdrop click, which harms UX and accessibility. Even if you plan to keep it non-dismissable, passonClose={() => {}}to satisfy MUI’s prop-types warning.
23-29: Coerceprogressto a number once and clamp it.
progresscould beundefinedor outside 0-100. Normalising avoids NaN rendering and out-of-range warnings:- return ( + const pct = Math.min(100, Math.max(0, Number(progress) ?? 0)); + return ( @@ - value={Number(progress)} + value={pct} @@ - <Typography variant="body1">{progress}% downloaded</Typography> + <Typography variant="body1">{pct}% downloaded</Typography>src/utils/audioImports.js (2)
22-42: Consider auto-generating the audio map to avoid manual drift.Manually listing 20+ assets is error-prone (e.g., missing
v9). A helper that glob-imports the directory or builds the mapping from a naming convention will scale better and reduce maintenance overhead.
44-45: Minor nit: freeze constant exports.Prevent accidental reassignment by freezing the exported URLs:
-export const livesAddAudio = audioFiles.livesAdd; -export const livesCutAudio = audioFiles.livesCut; +export const livesAddAudio = Object.freeze(audioFiles.livesAdd); +export const livesCutAudio = Object.freeze(audioFiles.livesCut);src/services/telementryService.js (1)
245-249: The commentedconsole.logcan be deleted outright.Leaving dead debug code clutters the file. Since you already committed the change, remove the line entirely to keep the codebase clean.
src/components/AssesmentEnd/AssesmentEnd.jsx (2)
2-13: Consolidate duplicate MUI imports
BoxandTypographyare imported from the same package in two separate statements. Merging them keeps the bundle cleaner and prevents tree-shaking surprises.-import { Box } from "@mui/material"; -… -import { Typography } from "@mui/material"; +import { Box, Typography } from "@mui/material";
102-104: Typo: “Amost” → “Almost”
Minor UI polish.- {newLevel === previousLevel ? "Amost There.!" : `Hurray.!`} + {newLevel === previousLevel ? "Almost There!" : "Hurray!"}.eslintrc.json (1)
20-23: Duplicate rule keys – only the last survives
react/react-in-jsx-scopeis declared twice with conflicting values ("warn"then"off"). JSON parsers keep the latter, so the earlier entry is dead config and may confuse future maintainers.- "react/react-in-jsx-scope": "warn", … - "react/react-in-jsx-scope": "off" + "react/react-in-jsx-scope": "off" // single authoritative entry🧰 Tools
🪛 Biome (1.9.4)
[error] 20-20: The key react/react-in-jsx-scope was already declared.
This where a duplicated key was declared again.
If a key is defined multiple times, only the last definition takes effect. Previous definitions are ignored.
(lint/suspicious/noDuplicateObjectKeys)
vite.config.js (1)
24-29: COOP / COEP headers can break dev-server assets & require a service-worker shim
Enabling"Cross-Origin-Embedder-Policy": "require-corp"together with"Cross-Origin-Opener-Policy": "same-origin"is necessary for WASM + FFmpeg, but Vite will now refuse to load any resource that isn’t served with these headers (.woff, images, etc.). In dev mode that often leads to opaque “blocked by corp” errors.Make sure either
- every static asset is served with
Cross-Origin-Resource-Policy: same-origin, or- integrate a shim like
vite-plugin-coiwhich automatically injects the required service-worker.Without that, the app may fail to start in some browsers.
vite.config.mjs (1)
1-28: Duplicate Vite configs add maintenance overhead
The repo now holdsvite.config.js,vite.config.mjs, and avite.config.ts. Vite will pick the first it finds (usually.mjs), silently ignoring the others – easy to mis-configure.Unify into one canonical config or export shared pieces from a single file to avoid divergence.
asr-utils/src/utils.rs (1)
3-13:set_panic_hookgated only ondebug_assertions
In release builds you will lose panic back-traces inside WASM, making debugging production issues painful. Consider enabling the hook under a feature flag instead ofdebug_assertions, or document the reasoning clearly.asr-utils/pkg/package.json (1)
1-20: Add standard package-metadata and tighten the bundle surface
collaboratorsis a non-standard npm field; usecontributorsinstead.- Consider adding the common metadata keys:
description,license,repository,keywords. These help consumers and tooling.- The package currently exposes all runtime files via
"files", but there is no"exports"map. Consumers doingimport { … } from 'indicasr-wasm'could accidentally traverse into internal files. Add an"exports"block that explicitly exposes only the public surface:+ "exports": { + ".": { + "import": "./indicasr_wasm.js", + "types": "./indicasr_wasm.d.ts" + } + },
"sideEffects": ["./indicasr_wasm.js","./snippets/*"]marks the main entry as having side-effects, which defeats tree-shaking. If the side-effect is only module initialisation, prefer wrapping it in an explicitinit()function that callers invoke, and set"sideEffects": false.public/sherpa.wasm/initShrepa.js (2)
3-4: Left-over debugging logRepeated
"inited!"logs will spam the console. Remove or wrap behind a debug flag.
12-17: Global leakage – expose only what is necessaryAttaching
OfflineRecognizer,createVad, and the wholeModuleobject towindowpollutes the global namespace and hinders tree-shaking. Prefer returning them fromloadSherpaModule()and letting the caller decide where to stash the handles.src/components/Mechanism/WordsOrImage.jsx (1)
1055-1057: Condition unchanged but readability can improveThe triple
level === 1 || level === 2 || level === 3would be clearer as[1,2,3].includes(level).asr-utils/README.md (6)
5-5: Hyphenate "kick-starting": Use a hyphen in "kick-starting" to align with standard English compound usage.🧰 Tools
🪛 LanguageTool
[misspelling] ~5-~5: This word is normally spelled with a hyphen.
Context: ...e A template for kick starting a Rust and WebAssembly project using <a...(EN_COMPOUNDS_KICK_STARTING)
39-42: Specify language for fenced code block: Add a language identifier (e.g.,bash) to improve syntax highlighting for the cargo generate snippet.🧰 Tools
🪛 markdownlint-cli2 (0.17.2)
39-39: Fenced code blocks should have a language specified
null(MD040, fenced-code-language)
46-48: Specify language for fenced code block: Add a language identifier (e.g.,bash) to improve syntax highlighting for the wasm-pack build snippet.🧰 Tools
🪛 markdownlint-cli2 (0.17.2)
46-46: Fenced code blocks should have a language specified
null(MD040, fenced-code-language)
52-54: Specify language for fenced code block: Add a language identifier (e.g.,bash) to improve syntax highlighting for the wasm-pack test snippet.🧰 Tools
🪛 markdownlint-cli2 (0.17.2)
52-52: Fenced code blocks should have a language specified
null(MD040, fenced-code-language)
58-61: Specify language for fenced code block: Add a language identifier (e.g.,bash) to improve syntax highlighting for the wasm-pack publish snippet.🧰 Tools
🪛 markdownlint-cli2 (0.17.2)
58-58: Fenced code blocks should have a language specified
null(MD040, fenced-code-language)
74-75: Convert bare URLs to link references: Replace raw URLs with proper Markdown link references or wrap them in angle brackets to satisfy lint rules (MD034).🧰 Tools
🪛 markdownlint-cli2 (0.17.2)
74-74: Bare URL used
null(MD034, no-bare-urls)
75-75: Bare URL used
null(MD034, no-bare-urls)
asr-utils/pkg/README.md (6)
5-5: Hyphenate "kick-starting": Use a hyphen in "kick-starting" to align with standard English compound usage.🧰 Tools
🪛 LanguageTool
[misspelling] ~5-~5: This word is normally spelled with a hyphen.
Context: ...e A template for kick starting a Rust and WebAssembly project using <a...(EN_COMPOUNDS_KICK_STARTING)
39-42: Specify language for fenced code block: Add a language identifier (e.g.,bash) to improve syntax highlighting for the cargo generate snippet.🧰 Tools
🪛 markdownlint-cli2 (0.17.2)
39-39: Fenced code blocks should have a language specified
null(MD040, fenced-code-language)
46-48: Specify language for fenced code block: Add a language identifier (e.g.,bash) to improve syntax highlighting for the wasm-pack build snippet.🧰 Tools
🪛 markdownlint-cli2 (0.17.2)
46-46: Fenced code blocks should have a language specified
null(MD040, fenced-code-language)
52-54: Specify language for fenced code block: Add a language identifier (e.g.,bash) to improve syntax highlighting for the wasm-pack test snippet.🧰 Tools
🪛 markdownlint-cli2 (0.17.2)
52-52: Fenced code blocks should have a language specified
null(MD040, fenced-code-language)
58-61: Specify language for fenced code block: Add a language identifier (e.g.,bash) to improve syntax highlighting for the wasm-pack publish snippet.🧰 Tools
🪛 markdownlint-cli2 (0.17.2)
58-58: Fenced code blocks should have a language specified
null(MD040, fenced-code-language)
74-75: Convert bare URLs to link references: Replace raw URLs with proper Markdown link references or wrap them in angle brackets to satisfy lint rules (MD034).🧰 Tools
🪛 markdownlint-cli2 (0.17.2)
74-74: Bare URL used
null(MD034, no-bare-urls)
75-75: Bare URL used
null(MD034, no-bare-urls)
asr-utils/.travis.yml (1)
15-19: DRY repeated before_script steps: The same installation commands are repeated across jobs; consider extracting common steps to a top-levelbefore_scriptto reduce duplication.Also applies to: 32-36, 54-57
src/views/LoginPage/LoginPage.css (3)
20-25: Keyframes lack vendor-prefix fall-backsAnimations are fine on evergreen browsers, but if you still support Safari < 9 / Samsung < 5, add
@-webkit-keyframesto avoid blank backgrounds.
27-36: Avoid!important– prefer increasing selector specificity
max-width: 450px!important;can make future overrides painful. A BEM-specific selector (.loginPage .loginPage__container) removes the need for!important.
42-48: Animation performance: usetransformfor shadow pulse
box-shadowis expensive to animate; if you intend continuous glow consider an::afterpseudo-element withopacitytransition instead.asr-utils/pkg/indicasr_wasm_bg.wasm.d.ts (1)
3-9: Auto-generated typings expose only numeric pointersThe d.ts is fine for low-level interop, but if you intend other TS consumers to use the package directly, add a higher-level wrapper (re-exporting the friendly API from
indicasr_wasm.d.ts).src/components/CommonComponent/ProgressOverlay.jsx (3)
28-40: Hard-coded width40%hampers small screensConsider
min(90vw, 400px)or CSS clamp to stay responsive.
51-55: Accessibility: addalttext to the GIFScreen readers will otherwise announce nothing.
- <img + <img + alt="Download in progress"
70-79: Internationalisation: Hard-coded “LOADING…” textExtract to i18n resources so non-English locales show correct copy.
asr-utils/pkg/indicasr_wasm.d.ts (1)
8-26: BroadArray<any>types erode type-safetyIf the WASM exports always return numeric arrays (e.g.,
Float32ArrayorInt32Array), declare them precisely. It improves DX and catches misuse at compile-time.src/components/ModelLoaderIndicator.jsx (3)
1-4: Unused imports (Button,keyframes) cause bundle bloat and linter noise
Remove them to keep the component lean.-import { Box, Button, Typography } from "@mui/material"; -import { styled, keyframes } from "@mui/material/styles"; +import { Box, Typography } from "@mui/material"; +import { styled } from "@mui/material/styles";
17-22: DefaultmodelLoadedrelies on global mutable stateReading
window.modelLoadeddirectly couples component to a global. Prefer a prop or context to avoid hidden dependencies and SSR hazards.
74-98: Colour semantics: red bar for loading, but same red used for errorsConsider a neutral or brand colour for “loading” to avoid implying failure.
vite.config.ts (1)
7-17: Consider using ESM imports instead of CommonJS for better Vite compatibility.The custom plugin transforms
hoist-non-react-staticsto use CommonJSrequiresyntax, which contradicts Vite's ESM-first approach. This could lead to issues with tree-shaking and optimization.Consider checking if the latest version of
hoist-non-react-staticssupports ESM natively, or use Vite's dependency pre-bundling instead:- { - name: 'handle-hoist-non-react-statics', - transform(code, id) { - if (id.includes('hoist-non-react-statics')) { - return { - code: `const hoistNonReactStatics = require('hoist-non-react-statics'); export default hoistNonReactStatics;`, - map: null - }; - } - } - }Add to
optimizeDeps.includeinstead:optimizeDeps: { + include: ['hoist-non-react-statics'], exclude: ['**/*.m4a', '**/*.mp3', '**/*.wav'] },public/sherpa.wasm/sherpa-onnx-vad.js (2)
129-130: Use null instead of 0 for cleared object handles.Setting handles to 0 instead of null or undefined can lead to type confusion and makes it harder to check if a handle has been freed.
free() { this.Module._SherpaOnnxDestroyCircularBuffer(this.handle); - this.handle = 0 + this.handle = null; }And similarly in the Vad class:
free() { this.Module._SherpaOnnxDestroyVoiceActivityDetector(this.handle); - this.handle = 0 + this.handle = null; }Also applies to: 190-190
204-204: Use strict equality operator for consistency.Using
==instead of===can lead to unexpected type coercion.- return this.Module._SherpaOnnxVoiceActivityDetectorEmpty(this.handle) == 1; + return this.Module._SherpaOnnxVoiceActivityDetectorEmpty(this.handle) === 1;- return this.Module._SherpaOnnxVoiceActivityDetectorDetected(this.handle) == - 1; + return this.Module._SherpaOnnxVoiceActivityDetectorDetected(this.handle) === 1;Also applies to: 208-209
asr-utils/src/lib.rs (2)
14-33: Remove commented out code.Large blocks of commented code should be removed as they clutter the codebase. If needed for reference, version control history can be used.
-// #[wasm_bindgen] -// extern "C" { -// fn alert(s: &str); -// #[wasm_bindgen(js_namespace = console, js_name = log)] -// fn log(b: &[u8]); -// #[wasm_bindgen(js_namespace = console, js_name = log)] -// fn log_str(s: &str); -// #[wasm_bindgen(js_namespace = console, js_name = log)] -// fn log_jsval(s: &JsValue); -// #[wasm_bindgen(js_namespace = console, js_name = log)] -// fn log_jsvecf32(s: Vec<f32>); -// #[wasm_bindgen(js_namespace = console, js_name = log)] -// fn log_jsvecusize(s: Vec<usize>); -// } - -// #[wasm_bindgen] -// pub fn greet() { -// alert("Hello, indicasr-wasm!"); -// }
139-140: Improve error message readability.The error message is extremely long and difficult to read. Consider formatting it better.
- panic!("normalize_batch with `per_feature` normalize_type received a tensor of length 1. This will result in torch.std() returning nan. Make sure your audio length has enough samples for a single feature (ex. at least `hop_length` for Mel Spectrograms).") + panic!( + "normalize_batch with `per_feature` normalize_type received a tensor of length 1. \ + This will result in torch.std() returning nan. \ + Make sure your audio length has enough samples for a single feature \ + (ex. at least `hop_length` for Mel Spectrograms)." + )src/components/OfflineModelManager.js (1)
232-232: Use optional chaining for cleaner code.The callback invocation can be simplified using optional chaining.
- callback && callback(); + callback?.();🧰 Tools
🪛 Biome (1.9.4)
[error] 232-232: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
src/utils/constants.jsx (2)
9677-9682:languagesfilter lacks null-safety for env varsIf either env var is mis-configured (e.g. undefined, a string that fails
JSON.parse), the current code will throw at start-up. Consider wrapping theJSON.parsein atry/catchor allowing simple comma-separated strings.
9742-9742: Suspicious RNNoise model path/extension
"models/cb.rnnn"has a triple-n extension. Common artefacts are.rnn,.onnxor.wasm. Please verify the filename to avoid a 404 at runtime.src/utils/VoiceAnalyser.jsx (1)
40-45: Drop unused / incorrect imports
ConstructionOutlined,set(lodash) andoriginalare imported but never referenced. They bloat bundle size and will trigger linter warnings.
Simply remove them.src/views/Practice/Practice.jsx (2)
105-107: Dead state –reattemptIndicesis never read
setReattemptIndicesis defined but the value is never consumed later.
Delete the state or wire it into the logic to avoid wasted renders and team confusion.
1623-1624: Remove noisy console log
console.log(isOffline, "isOffline");will flood production logs.
Drop or guard it behind a dev flag.
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (5)
asr-utils/pkg/indicasr_wasm_bg.wasmis excluded by!**/*.wasmpackage-lock.jsonis excluded by!**/package-lock.jsonpublic/sherpa.wasm/sherpa-onnx-wasm-main-vad-asr.wasmis excluded by!**/*.wasmsrc/assets/images/boy-running.gifis excluded by!**/*.gifyarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (53)
.eslintrc.json(1 hunks).gitattributes(1 hunks)asr-utils/.appveyor.yml(1 hunks)asr-utils/.github/dependabot.yml(1 hunks)asr-utils/.gitignore(1 hunks)asr-utils/.travis.yml(1 hunks)asr-utils/Cargo.toml(1 hunks)asr-utils/LICENSE_APACHE(1 hunks)asr-utils/LICENSE_MIT(1 hunks)asr-utils/README.md(1 hunks)asr-utils/pkg/README.md(1 hunks)asr-utils/pkg/indicasr_wasm.d.ts(1 hunks)asr-utils/pkg/indicasr_wasm.js(1 hunks)asr-utils/pkg/indicasr_wasm_bg.js(1 hunks)asr-utils/pkg/indicasr_wasm_bg.wasm.d.ts(1 hunks)asr-utils/pkg/package.json(1 hunks)asr-utils/src/lib.rs(1 hunks)asr-utils/src/utils.rs(1 hunks)asr-utils/tests/web.rs(1 hunks)index.html(1 hunks)package.json(3 hunks)public/models/kannada.vocab(1 hunks)public/models/tamil.vocab(1 hunks)public/sherpa.wasm/initShrepa.js(1 hunks)public/sherpa.wasm/sherpa-onnx-asr.js(1 hunks)public/sherpa.wasm/sherpa-onnx-vad.js(1 hunks)src/App.jsx(1 hunks)src/components/Assesment/Assesment.jsx(17 hunks)src/components/AssesmentEnd/AssesmentEnd.jsx(1 hunks)src/components/CommonComponent/CircularProgressOverlay.jsx(1 hunks)src/components/CommonComponent/ProgressOverlay.jsx(1 hunks)src/components/DiscoverSentance/DiscoverSentance.jsx(1 hunks)src/components/DownloadProgressModal.jsx(1 hunks)src/components/Layouts.jsx/MainLayout.jsx(3 hunks)src/components/Mechanism/WordsOrImage.jsx(6 hunks)src/components/ModelLoaderIndicator.jsx(1 hunks)src/components/OfflineModelManager.js(1 hunks)src/csp.js(1 hunks)src/routes/index.js(0 hunks)src/services/telementryService.js(1 hunks)src/utils/AudioCompare.jsx(1 hunks)src/utils/Loader.js(0 hunks)src/utils/Loader.jsx(1 hunks)src/utils/VoiceAnalyser.jsx(11 hunks)src/utils/audioImports.js(1 hunks)src/utils/constants.jsx(13 hunks)src/utils/useFFmpeg.jsx(1 hunks)src/views/AppContent/AppContent.jsx(0 hunks)src/views/LoginPage/LoginPage.css(1 hunks)src/views/Practice/Practice.jsx(10 hunks)vite.config.js(1 hunks)vite.config.mjs(1 hunks)vite.config.ts(1 hunks)
💤 Files with no reviewable changes (3)
- src/routes/index.js
- src/views/AppContent/AppContent.jsx
- src/utils/Loader.js
🧰 Additional context used
📓 Path-based instructions (2)
`**/*.html`: "Review the HTML code against the google html style guide and point out any mismatches. Ensure that: - The code adheres to best practices recommended by lighthouse or ...
**/*.html: "Review the HTML code against the google html style guide and point out any mismatches. Ensure that:
- The code adheres to best practices recommended by lighthouse or similar tools for performance."
index.html
`**/*.css`: "Review the CSS code against the google css style guide and point out any mismatches. Ensure that: - The code adheres to best practices associated with CSS. - The code ...
**/*.css: "Review the CSS code against the google css style guide and point out any mismatches. Ensure that:
- The code adheres to best practices associated with CSS.
- The code adheres to best practices recommended by lighthouse or similar tools for performance.
- The code adheres to similar naming conventions for classes, ids."
src/views/LoginPage/LoginPage.css
🧬 Code Graph Analysis (5)
asr-utils/pkg/indicasr_wasm.d.ts (1)
asr-utils/pkg/indicasr_wasm_bg.js (4)
run_preprocessor(202-207)decode_logprobs(232-237)offset(90-90)decode_logprobs_topk(248-253)
src/components/CommonComponent/ProgressOverlay.jsx (1)
src/components/Assesment/Assesment.jsx (1)
downloadProgress(813-813)
asr-utils/pkg/indicasr_wasm.js (1)
asr-utils/pkg/indicasr_wasm_bg.js (2)
__wbg_set_wasm(2-4)wasm(1-1)
asr-utils/pkg/indicasr_wasm_bg.wasm.d.ts (1)
asr-utils/pkg/indicasr_wasm_bg.js (3)
run_preprocessor(202-207)decode_logprobs(232-237)decode_logprobs_topk(248-253)
src/utils/VoiceAnalyser.jsx (6)
src/hooks/usePreloadAudio.jsx (1)
usePreloadAudio(3-28)src/utils/useFFmpeg.jsx (3)
useFFmpeg(7-43)ffmpeg(4-4)error(9-9)src/services/learnerAi/learnerAiService.js (6)
lang(57-57)response(27-27)response(38-41)response(60-71)response(89-101)response(111-115)src/services/telementryService.js (4)
error(191-203)error(191-203)response(100-109)response(100-109)src/utils/Badwords.js (2)
filterBadWords(16-27)filterBadWords(16-27)src/utils/constants.jsx (8)
rnnoiseModelPath(9742-9742)rnnoiseModelPath(9742-9742)i(37-37)i(9686-9686)j(9687-9687)k(9688-9688)getLocalData(5-9)getLocalData(5-9)
🪛 LanguageTool
asr-utils/pkg/README.md
[misspelling] ~5-~5: This word is normally spelled with a hyphen.
Context: ...e A template for kick starting a Rust and WebAssembly project using <a...
(EN_COMPOUNDS_KICK_STARTING)
asr-utils/README.md
[misspelling] ~5-~5: This word is normally spelled with a hyphen.
Context: ...e A template for kick starting a Rust and WebAssembly project using <a...
(EN_COMPOUNDS_KICK_STARTING)
🪛 markdownlint-cli2 (0.17.2)
asr-utils/pkg/README.md
39-39: Fenced code blocks should have a language specified
null
(MD040, fenced-code-language)
46-46: Fenced code blocks should have a language specified
null
(MD040, fenced-code-language)
52-52: Fenced code blocks should have a language specified
null
(MD040, fenced-code-language)
58-58: Fenced code blocks should have a language specified
null
(MD040, fenced-code-language)
74-74: Bare URL used
null
(MD034, no-bare-urls)
75-75: Bare URL used
null
(MD034, no-bare-urls)
asr-utils/README.md
39-39: Fenced code blocks should have a language specified
null
(MD040, fenced-code-language)
46-46: Fenced code blocks should have a language specified
null
(MD040, fenced-code-language)
52-52: Fenced code blocks should have a language specified
null
(MD040, fenced-code-language)
58-58: Fenced code blocks should have a language specified
null
(MD040, fenced-code-language)
74-74: Bare URL used
null
(MD034, no-bare-urls)
75-75: Bare URL used
null
(MD034, no-bare-urls)
🪛 Biome (1.9.4)
src/components/OfflineModelManager.js
[error] 232-232: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
🔇 Additional comments (16)
asr-utils/LICENSE_MIT (1)
1-26: MIT license file looks correct
The standard MIT text is present and properly formatted. No issues found in this license file.src/components/AssesmentEnd/AssesmentEnd.jsx (1)
32-38: HandleAudio.play()promise & autoplay restrictions
audio.play()returns a promise that can reject when autoplay is blocked. Add.catch()or feature-detect user interaction to avoid uncaught rejections in some browsers..gitattributes (1)
1-1: 👍 LFS entry looks correct
The pattern is scoped to a single large binary; filters are properly set.asr-utils/.github/dependabot.yml (1)
1-8: Dependabot config LGTM
Daily cadence and PR limit are reasonable for a Rust workspace..eslintrc.json (1)
8-10: Extending both “prettier” and “react-app” is sensible
No issues here.src/csp.js (1)
18-18: Verify that onlyconnect-srcneedsunpkg.com
If you dynamically import or execute scripts fromhttps://unpkg.com, they must also appear inscript-src. Confirm the intended fetch pattern; otherwise resources may still be blocked in production.asr-utils/pkg/indicasr_wasm.js (1)
1-4: Direct.wasmESM import relies on bundler supportNative browsers still gate-keep bare
.wasmimports behind--experimental-wasm-modules.
If you intend to ship this file unbundled, useWebAssembly.instantiateStreaming/fetchfallback or document that a bundler (Vite/Webpack/Rollup) must process it.No change required if the package is always bundled, otherwise wrap the import behind a feature-detect loader.
public/models/kannada.vocab (1)
1-258: Static asset – no actionable feedbackThis file is a pure data-only vocabulary dump. No functional or structural concerns from a code-review standpoint.
public/models/tamil.vocab (1)
1-258: Static asset – no actionable feedbackNothing to review here beyond ensuring the file is committed with the correct encoding and line-endings.
public/sherpa.wasm/initShrepa.js (1)
23-25: Un-awaited async initialiser
loadSherpaModule()is called but the returned promise is neither awaited nor handled. Consumers may attempt to use the recognizer before the WASM runtime is ready.- loadSherpaModule(); + loadSherpaModule().catch(console.error);…and ensure dependent code awaits readiness.
asr-utils/LICENSE_APACHE (1)
1-202: Standard Apache License text; no review comments necessary.asr-utils/.travis.yml (1)
1-70: CI configuration appears solid: Travis CI matrix covers beta (with wasm-pack), nightly, and beta environments with appropriate targets, browser testing, and caching.src/views/LoginPage/LoginPage.css (1)
70-84: Selector drift inside media query
.loginBoxand.textFieldare not prefixed with.loginPagehere, breaking the scoping you established above. Align selectors to avoid style leakage.src/utils/constants.jsx (1)
7853-7864: Bulk addition ofoffline: truelooks soundMarking practice items as offline appears consistent and risk-free; no functional issues spotted.
Also applies to: 7881-7895, 7910-7925, 7929-7934, 7950-7954, 7971-7983, 8027-8033, 8055-8067, 8085-8108, 8129-8139, 8157-8168, 8175-8199, 8205-8228, 8236-8259
asr-utils/pkg/indicasr_wasm_bg.js (1)
1-364: Auto-generated file – no manual review neededThe glue code is produced by wasm-bindgen; changes should come from the Rust side.
public/sherpa.wasm/sherpa-onnx-asr.js (1)
1-1143: Looks goodNo functional issues spotted in the WASM binding helpers.
| <Box | ||
| sx={{ | ||
| display: "flex", | ||
| position: "absolute", | ||
| zIndex: 999, | ||
| justifyContent: "center", | ||
| width: "100%", | ||
| alignItems: "center", | ||
| height: "100vh", | ||
| backgroundColor: "rgb(0 0 0 / 56%)", | ||
| }} |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Use position: fixed with explicit top/left
To ensure the overlay always covers the viewport, switch from position: absolute to position: fixed, and add top: 0; left: 0; in the styling. This guarantees full-screen coverage regardless of parent positioning.
🤖 Prompt for AI Agents
In src/components/CommonComponent/CircularProgressOverlay.jsx between lines 5
and 15, change the Box component's CSS position from "absolute" to "fixed" and
add "top: 0" and "left: 0" properties to ensure the overlay covers the entire
viewport consistently regardless of parent elements.
| useEffect(() => { | ||
| const loadFFmpeg = async () => { | ||
| try { | ||
| if (!ffmpeg) { | ||
| ffmpeg = createFFmpeg({ | ||
| log: false, | ||
| corePath: | ||
| "https://unpkg.com/@ffmpeg/core@0.11.0/dist/ffmpeg-core.js", | ||
| }); | ||
| } | ||
|
|
||
| if (!loadingPromise) { | ||
| loadingPromise = ffmpeg.load(); | ||
| } | ||
|
|
||
| await loadingPromise; | ||
| setLoading(false); | ||
| } catch (err) { | ||
| console.error("Error loading FFmpeg:", err); | ||
| setError(err); | ||
| setLoading(false); | ||
| } | ||
| }; | ||
|
|
||
| loadFFmpeg(); | ||
|
|
||
| return () => { | ||
| // Cleanup if needed | ||
| }; | ||
| }, []); |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Guard against state updates on an unmounted component.
If the hook’s consumer unmounts before ffmpeg.load() resolves, setLoading/setError will still run, which React flags as a memory-leak warning. Track an isMounted flag to bail out gracefully:
useEffect(() => {
+ let isMounted = true;
const loadFFmpeg = async () => {
try {
@@
- await loadingPromise;
- setLoading(false);
+ await loadingPromise;
+ if (isMounted) setLoading(false);
} catch (err) {
console.error("Error loading FFmpeg:", err);
- setError(err);
- setLoading(false);
+ if (isMounted) {
+ setError(err);
+ setLoading(false);
+ }
}
};
@@
- return () => {
- // Cleanup if needed
- };
+ return () => {
+ isMounted = false;
+ };
}, []);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| useEffect(() => { | |
| const loadFFmpeg = async () => { | |
| try { | |
| if (!ffmpeg) { | |
| ffmpeg = createFFmpeg({ | |
| log: false, | |
| corePath: | |
| "https://unpkg.com/@ffmpeg/core@0.11.0/dist/ffmpeg-core.js", | |
| }); | |
| } | |
| if (!loadingPromise) { | |
| loadingPromise = ffmpeg.load(); | |
| } | |
| await loadingPromise; | |
| setLoading(false); | |
| } catch (err) { | |
| console.error("Error loading FFmpeg:", err); | |
| setError(err); | |
| setLoading(false); | |
| } | |
| }; | |
| loadFFmpeg(); | |
| return () => { | |
| // Cleanup if needed | |
| }; | |
| }, []); | |
| useEffect(() => { | |
| let isMounted = true; | |
| const loadFFmpeg = async () => { | |
| try { | |
| if (!ffmpeg) { | |
| ffmpeg = createFFmpeg({ | |
| log: false, | |
| corePath: | |
| "https://unpkg.com/@ffmpeg/core@0.11.0/dist/ffmpeg-core.js", | |
| }); | |
| } | |
| if (!loadingPromise) { | |
| loadingPromise = ffmpeg.load(); | |
| } | |
| await loadingPromise; | |
| if (isMounted) setLoading(false); | |
| } catch (err) { | |
| console.error("Error loading FFmpeg:", err); | |
| if (isMounted) { | |
| setError(err); | |
| setLoading(false); | |
| } | |
| } | |
| }; | |
| loadFFmpeg(); | |
| return () => { | |
| isMounted = false; | |
| }; | |
| }, []); |
🤖 Prompt for AI Agents
In src/utils/useFFmpeg.jsx between lines 11 and 40, the useEffect hook updates
state with setLoading and setError after an asynchronous ffmpeg.load() call,
which can cause memory-leak warnings if the component unmounts before the
promise resolves. To fix this, introduce an isMounted flag set to true at the
start of the effect and false in the cleanup function, then check this flag
before calling setLoading or setError to avoid state updates on an unmounted
component.
| import React, { useEffect, useRef } from "react"; | ||
| import { ThemeProvider } from "@mui/material"; | ||
| import { useNavigate } from "react-router-dom"; | ||
| import { BrowserRouter as Router } from "react-router-dom"; |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Remove the unused Router import or wrap the tree with it.
Router is imported but never referenced, which will fail eslint’s no-unused-vars rule and confuses future readers. Either:
- Delete the import, or
- Wrap the returned JSX (
<StyledEngineProvider …>) with<Router>if that was the original intent.
🤖 Prompt for AI Agents
In src/App.jsx at line 4, the Router import from react-router-dom is unused,
causing an eslint no-unused-vars error. To fix this, either remove the import
statement entirely if routing is not needed, or wrap the top-level returned JSX
element (StyledEngineProvider) with the Router component to properly use the
import.
| <!-- <script type="text/javascript" src="./whisper.wasm/stream.js" defer></script> | ||
| <script type="text/javascript" src="./whisper.wasm/initWhisper.js" defer></script> --> | ||
| <script type="text/javascript" src="./sherpa.wasm/sherpa-onnx-asr.js" defer></script> | ||
| <script type="text/javascript" src="./sherpa.wasm/sherpa-onnx-vad.js" defer></script> | ||
| <script type="text/javascript" src="./sherpa.wasm/sherpa-onnx-wasm-main-vad-asr.js" defer></script> | ||
| <script type="text/javascript" src="./sherpa.wasm/initShrepa.js" defer></script> | ||
| <script src="https://cdn.jsdelivr.net/npm/canvas-confetti@1.9.2/dist/confetti.browser.min.js"></script> |
There was a problem hiding this comment.
Typo in script filename will 404
initShrepa.js looks like a miss-spelling of Sherpa → the file will not resolve and the initialisation code will never run.
- <script type="text/javascript" src="./sherpa.wasm/initShrepa.js" defer></script>
+ <script type="text/javascript" src="./sherpa.wasm/initSherpa.js" defer></script>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <!-- <script type="text/javascript" src="./whisper.wasm/stream.js" defer></script> | |
| <script type="text/javascript" src="./whisper.wasm/initWhisper.js" defer></script> --> | |
| <script type="text/javascript" src="./sherpa.wasm/sherpa-onnx-asr.js" defer></script> | |
| <script type="text/javascript" src="./sherpa.wasm/sherpa-onnx-vad.js" defer></script> | |
| <script type="text/javascript" src="./sherpa.wasm/sherpa-onnx-wasm-main-vad-asr.js" defer></script> | |
| <script type="text/javascript" src="./sherpa.wasm/initShrepa.js" defer></script> | |
| <script src="https://cdn.jsdelivr.net/npm/canvas-confetti@1.9.2/dist/confetti.browser.min.js"></script> | |
| <!-- <script type="text/javascript" src="./whisper.wasm/stream.js" defer></script> | |
| <script type="text/javascript" src="./whisper.wasm/initWhisper.js" defer></script> --> | |
| <script type="text/javascript" src="./sherpa.wasm/sherpa-onnx-asr.js" defer></script> | |
| <script type="text/javascript" src="./sherpa.wasm/sherpa-onnx-vad.js" defer></script> | |
| <script type="text/javascript" src="./sherpa.wasm/sherpa-onnx-wasm-main-vad-asr.js" defer></script> | |
| - <script type="text/javascript" src="./sherpa.wasm/initShrepa.js" defer></script> | |
| + <script type="text/javascript" src="./sherpa.wasm/initSherpa.js" defer></script> | |
| <script src="https://cdn.jsdelivr.net/npm/canvas-confetti@1.9.2/dist/confetti.browser.min.js"></script> |
🤖 Prompt for AI Agents
In index.html around lines 25 to 31, the script filename "initShrepa.js" is
misspelled and should be corrected to "initSherpa.js" to avoid a 404 error and
ensure the initialization code runs properly. Update the script tag's src
attribute to the correct filename "initSherpa.js".
| <!-- <script type="text/javascript" src="./whisper.wasm/stream.js" defer></script> | ||
| <script type="text/javascript" src="./whisper.wasm/initWhisper.js" defer></script> --> | ||
| <script type="text/javascript" src="./sherpa.wasm/sherpa-onnx-asr.js" defer></script> | ||
| <script type="text/javascript" src="./sherpa.wasm/sherpa-onnx-vad.js" defer></script> | ||
| <script type="text/javascript" src="./sherpa.wasm/sherpa-onnx-wasm-main-vad-asr.js" defer></script> | ||
| <script type="text/javascript" src="./sherpa.wasm/initShrepa.js" defer></script> | ||
| <script src="https://cdn.jsdelivr.net/npm/canvas-confetti@1.9.2/dist/confetti.browser.min.js"></script> | ||
| <script | ||
| src="https://cdn.jsdelivr.net/npm/onnxruntime-web/dist/ort.min.js" | ||
| strategy="lazyOnload"></script> |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Loading strategy & blocking risk of third-party scripts
canvas-confetti and onnxruntime-web are added without either defer or async.
They will block parsing and hurt FCP/LCP.
strategy="lazyOnload" is not a standard HTML attribute and will be ignored by browsers.
- <script src="https://cdn.jsdelivr.net/npm/canvas-confetti@1.9.2/dist/confetti.browser.min.js"></script>
+ <script src="https://cdn.jsdelivr.net/npm/canvas-confetti@1.9.2/dist/confetti.browser.min.js" defer></script>Repeat for ort.min.js, or move both tags just before </body>.
Also add Sub-Resource-Integrity to mitigate supply-chain risks.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <!-- <script type="text/javascript" src="./whisper.wasm/stream.js" defer></script> | |
| <script type="text/javascript" src="./whisper.wasm/initWhisper.js" defer></script> --> | |
| <script type="text/javascript" src="./sherpa.wasm/sherpa-onnx-asr.js" defer></script> | |
| <script type="text/javascript" src="./sherpa.wasm/sherpa-onnx-vad.js" defer></script> | |
| <script type="text/javascript" src="./sherpa.wasm/sherpa-onnx-wasm-main-vad-asr.js" defer></script> | |
| <script type="text/javascript" src="./sherpa.wasm/initShrepa.js" defer></script> | |
| <script src="https://cdn.jsdelivr.net/npm/canvas-confetti@1.9.2/dist/confetti.browser.min.js"></script> | |
| <script | |
| src="https://cdn.jsdelivr.net/npm/onnxruntime-web/dist/ort.min.js" | |
| strategy="lazyOnload"></script> | |
| <!-- <script type="text/javascript" src="./whisper.wasm/stream.js" defer></script> | |
| <script type="text/javascript" src="./whisper.wasm/initWhisper.js" defer></script> --> | |
| <script type="text/javascript" src="./sherpa.wasm/sherpa-onnx-asr.js" defer></script> | |
| <script type="text/javascript" src="./sherpa.wasm/sherpa-onnx-vad.js" defer></script> | |
| <script type="text/javascript" src="./sherpa.wasm/sherpa-onnx-wasm-main-vad-asr.js" defer></script> | |
| <script type="text/javascript" src="./sherpa.wasm/initShrepa.js" defer></script> | |
| <script src="https://cdn.jsdelivr.net/npm/canvas-confetti@1.9.2/dist/confetti.browser.min.js" defer></script> | |
| <script | |
| src="https://cdn.jsdelivr.net/npm/onnxruntime-web/dist/ort.min.js" | |
| strategy="lazyOnload"></script> |
🤖 Prompt for AI Agents
In index.html around lines 25 to 34, the script tags for canvas-confetti and
onnxruntime-web lack defer or async attributes, causing blocking of HTML parsing
and impacting performance metrics like FCP and LCP. Also, the
strategy="lazyOnload" attribute on the onnxruntime-web script is invalid and
ignored by browsers. To fix this, add defer or async attributes to these script
tags or move them just before the closing </body> tag to avoid blocking.
Additionally, add Sub-Resource-Integrity (SRI) attributes with appropriate
integrity hashes to these external scripts to enhance security against
supply-chain attacks.
| const contentLength = +response.headers.get("Content-Length"); | ||
| let receivedLength = 0; | ||
| const chunks = []; | ||
|
|
||
| while (true) { | ||
| const { done, value } = await reader.read(); | ||
| if (done) break; | ||
| chunks.push(value); | ||
| receivedLength += value.length; | ||
|
|
||
| // Update progress | ||
| const percentage = (receivedLength / contentLength) * 100; | ||
| setDownloadProgress(percentage.toFixed()); | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Progress calculation can divide by NaN
Content-Length header is optional; when missing, +response.headers.get("Content-Length") yields NaN, and the percentage math propagates NaN, breaking the UI.
Guard the header:
const total = Number(response.headers.get("Content-Length") || 0);
…
if (total) {
const percentage = (receivedLength / total) * 100;
setDownloadProgress(percentage.toFixed());
}🤖 Prompt for AI Agents
In src/components/Assesment/Assesment.jsx around lines 1080 to 1093, the code
calculates download progress using the Content-Length header without checking if
it exists, which can result in NaN and break the UI. Fix this by assigning the
content length to a variable using Number(response.headers.get("Content-Length")
|| 0) to default to 0 if missing, and update the progress calculation to only
run if this total is greater than zero.
| if (vocabURL) { | ||
| const vocabStored = await isModelStored(vacabFileName); | ||
| if (!stored) { | ||
| await storeModel(vacabFileName, vocabURL, true); | ||
| } else { | ||
| console.log(`Model ${vacabFileName} is already stored in IndexedDB`); | ||
| return; | ||
| } | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Vocabulary storage condition uses wrong flag
In loadModel you compute vocabStored but still test !stored, so the vocab file is re-downloaded unnecessarily.
-if (!stored) {
+if (!vocabStored) {
await storeModel(vacabFileName, vocabURL, true);
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (vocabURL) { | |
| const vocabStored = await isModelStored(vacabFileName); | |
| if (!stored) { | |
| await storeModel(vacabFileName, vocabURL, true); | |
| } else { | |
| console.log(`Model ${vacabFileName} is already stored in IndexedDB`); | |
| return; | |
| } | |
| } | |
| if (vocabURL) { | |
| const vocabStored = await isModelStored(vacabFileName); | |
| if (!vocabStored) { | |
| await storeModel(vacabFileName, vocabURL, true); | |
| } else { | |
| console.log(`Model ${vacabFileName} is already stored in IndexedDB`); | |
| return; | |
| } | |
| } |
🤖 Prompt for AI Agents
In src/components/Assesment/Assesment.jsx around lines 1148 to 1156, the
condition incorrectly checks the variable 'stored' instead of 'vocabStored'
after calling isModelStored. To fix this, replace the '!stored' check with
'!vocabStored' so that the code correctly uses the result of the vocabulary
storage check and avoids unnecessary re-downloads.
| onClick={async () => { | ||
| setLang(selectedLang); | ||
| setOpenLangModal(false); | ||
| if (isOfflineModel && selectedLang !== "en") { | ||
| loadModel(selectedLang); | ||
| } else { | ||
| await window.sherpaModule.loadModel(); | ||
| } | ||
| }} |
There was a problem hiding this comment.
loadModel is out-of-scope – will throw at runtime
LanguageModal calls loadModel(selectedLang) but that function is declared inside Assesment (different module scope) and is not passed in props.
Clicking “Confirm” in the modal will raise ReferenceError: loadModel is not defined.
Pass the function via props or lift loadModel to a shared util.
// parent render
<LanguageModal {...{ lang, setLang, setOpenLangModal, setLoading, setDownloadProgress, loadModel }} />
// inside LanguageModal props
export const LanguageModal = ({ … , loadModel }) => { … }Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In src/components/Assesment/Assesment.jsx around lines 376 to 384, the onClick
handler calls loadModel(selectedLang) but loadModel is not defined in the scope
of this component, causing a runtime ReferenceError. To fix this, either pass
loadModel as a prop from the parent component where it is defined or move
loadModel to a shared utility module and import it here, ensuring it is
accessible in this component's scope.
| !isShowCase && | ||
| isOffline && | ||
| localStorage.getItem("isOfflineModel") === "true", | ||
| storyLine, |
There was a problem hiding this comment.
Typo breaks prop-plumbing
Prop is spelled offilnePractice.
Unless WordsOrImage also uses the same typo, the flag will be undefined and offline flow will never activate.
- offilnePractice:
+ offlinePractice:Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In src/views/Practice/Practice.jsx around lines 1656 to 1659, the prop name
`offilnePractice` is misspelled. Correct the spelling to `offlinePractice` to
ensure the prop is passed correctly and the offline flow activates as intended.
Verify that the receiving component uses the corrected prop name as well.
| // Reset the offline reports for the next attempt. | ||
| //setOfflineReports([]); | ||
|
|
||
| // Update the state for the next set attempt to include only failed questions. | ||
| setQuestions(failedQuestions); | ||
| setCurrentQuestion(0); | ||
| setIsAttemptedOnce(true); | ||
| return; // Stop further progression; user will now reattempt failed items. | ||
| } else { | ||
| setIsReattempt(false); | ||
| setIsAttemptedOnce(false); | ||
| // Optionally clear the offlineReports for the next set. | ||
| setOfflineReports([]); | ||
| // setOpenMessageDialog({ |
There was a problem hiding this comment.
Stale reports poison second attempt
When building failedQuestions, the code comments out setOfflineReports([]).
This leaves first-attempt reports in state, so the second pass will carry over old “failed” indices and can never pass.
- // Reset the offline reports for the next attempt.
- //setOfflineReports([]);
+ // Reset reports so second attempt is evaluated on fresh data.
+ setOfflineReports([]);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // Reset the offline reports for the next attempt. | |
| //setOfflineReports([]); | |
| // Update the state for the next set attempt to include only failed questions. | |
| setQuestions(failedQuestions); | |
| setCurrentQuestion(0); | |
| setIsAttemptedOnce(true); | |
| return; // Stop further progression; user will now reattempt failed items. | |
| } else { | |
| setIsReattempt(false); | |
| setIsAttemptedOnce(false); | |
| // Optionally clear the offlineReports for the next set. | |
| setOfflineReports([]); | |
| // setOpenMessageDialog({ | |
| // Reset reports so second attempt is evaluated on fresh data. | |
| setOfflineReports([]); | |
| // Update the state for the next set attempt to include only failed questions. | |
| setQuestions(failedQuestions); | |
| setCurrentQuestion(0); | |
| setIsAttemptedOnce(true); | |
| return; // Stop further progression; user will now reattempt failed items. |
🤖 Prompt for AI Agents
In src/views/Practice/Practice.jsx around lines 926 to 939, the
setOfflineReports([]) call is commented out when resetting for the next attempt,
causing stale offline reports to persist and interfere with the second attempt.
To fix this, uncomment the setOfflineReports([]) line to clear the offline
reports state before starting the reattempt, ensuring no old failed indices
carry over.




Summary by CodeRabbit
New Features
Enhancements
Bug Fixes
Documentation
Chores
Style
Tests
Refactor