Skip to content

Offline asr integration with all-1.4.2#400

Open
gouravmore wants to merge 70 commits intoSunbird-ALL:all-1.4.2-offlinefrom
gouravmore:offline-asr
Open

Offline asr integration with all-1.4.2#400
gouravmore wants to merge 70 commits intoSunbird-ALL:all-1.4.2-offlinefrom
gouravmore:offline-asr

Conversation

@gouravmore
Copy link
Copy Markdown
Member

@gouravmore gouravmore commented Jun 12, 2025

Summary by CodeRabbit

  • New Features

    • Added comprehensive offline AI language model support, including IndexedDB caching, download progress tracking, and offline vocabulary/model management for English, Kannada, and Tamil.
    • Introduced offline speech recognition and denoising using WASM-based models, with local fluency scoring and reattempt logic in practice sessions.
    • Added new UI components for download progress, model loading indicators, and animated loading overlays.
    • Enabled new audio asset management and centralized audio imports.
    • Integrated FFmpeg WebAssembly for audio processing and denoising.
  • Enhancements

    • Updated language and content configurations to distinguish between online and offline modes.
    • Improved language selection UI to toggle offline/online models and persist user choices.
    • Refined practice flow to support reattempts of failed items in offline mode.
    • Upgraded dependencies and added support for new libraries (FFmpeg, fuzzball, hoist-non-react-statics).
  • Bug Fixes

    • Fixed import paths for dependencies to use direct package imports.
    • Addressed issues with model file existence checks and error handling during offline model loading.
  • Documentation

    • Added detailed README files for new WASM modules and packages.
    • Included license files (MIT and Apache 2.0) for open-source compliance.
  • Chores

    • Introduced CI configurations for Rust/WASM modules (Travis CI, AppVeyor, Dependabot).
    • Updated ESLint configuration and .gitignore rules.
    • Added and configured new Vite build files and asset handling for audio and WASM.
  • Style

    • Enhanced login page with animated gradient backgrounds and improved visual effects.
  • Tests

    • Added browser-based test suite for WebAssembly modules.
  • Refactor

    • Reorganized and extended constants and language metadata for better offline/online separation.
    • Replaced and improved loader components and progress overlays.

gouravmore and others added 30 commits June 25, 2024 15:37
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
Task #223069 & #223071 Fuzzball js integration done and added new fields in API for offline call
ajinkyapandetekdi and others added 27 commits July 26, 2024 12:44
issueid #223924 fix: whisper model is not loading properly in offline-model
Issueid #223945 fix: When user is loggin out we are redirecting to Di…
#000 fix: gujrati language is not able to select
…aspeech

Vite conversion and offline english gigaspeech sherpa
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Jun 12, 2025

Walkthrough

This 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

Files / Groups Change Summary
.eslintrc.json, package.json Updated ESLint config to include "react-app"; upgraded and added dependencies, including WASM and audio libraries.
.gitattributes Added LFS tracking for a WASM data file.
asr-utils/ (all new files: .appveyor.yml, .github/dependabot.yml, .gitignore, .travis.yml, Cargo.toml, LICENSE_APACHE, LICENSE_MIT, README.md, pkg/README.md, pkg/indicasr_wasm.d.ts, pkg/indicasr_wasm.js, pkg/indicasr_wasm_bg.js, pkg/indicasr_wasm_bg.wasm.d.ts, pkg/package.json, src/lib.rs, src/utils.rs, tests/web.rs) Added Rust WASM speech recognition utility with build/test configs, licensing, JS/WASM glue code, TypeScript types, and documentation.
index.html, public/sherpa.wasm/initShrepa.js, public/sherpa.wasm/sherpa-onnx-asr.js, public/sherpa.wasm/sherpa-onnx-vad.js Replaced Whisper WASM scripts with Sherpa WASM scripts; added new JS modules for Sherpa ASR and VAD initialization and management.
public/models/kannada.vocab, public/models/tamil.vocab Added new vocabulary files for Kannada and Tamil languages.
src/App.jsx, src/components/AssesmentEnd/AssesmentEnd.jsx, src/components/DiscoverSentance/DiscoverSentance.jsx, src/routes/index.js, src/services/telementryService.js, src/views/AppContent/AppContent.jsx Minor import path changes and removal of unused/commented code.
src/components/Assesment/Assesment.jsx Implemented offline model management, IndexedDB caching, and conditional model loading logic for assessment flow.
src/components/CommonComponent/CircularProgressOverlay.jsx, src/components/CommonComponent/ProgressOverlay.jsx, src/components/DownloadProgressModal.jsx, src/components/ModelLoaderIndicator.jsx Added new UI components for circular and linear progress overlays, download progress modal, and model loading indicator.
src/components/Layouts.jsx/MainLayout.jsx Integrated download progress tracking and modal display in main layout.
src/components/Mechanism/WordsOrImage.jsx Added offline practice props and logic; updated prop types.
src/components/OfflineModelManager.js New module for IndexedDB-based offline model and vocabulary management, including background loading and session creation.
src/csp.js, vite.config.js, vite.config.mjs, vite.config.ts Updated CSP and dev server headers; added/updated Vite configs for WASM, audio assets, and security.
src/utils/AudioCompare.jsx, src/utils/Loader.js, src/utils/Loader.jsx, src/utils/constants.jsx, src/utils/audioImports.js, src/utils/useFFmpeg.jsx Updated Loader to JSX; added centralized audio imports; introduced useFFmpeg hook; standardized and expanded offline language/model metadata and constants.
src/utils/VoiceAnalyser.jsx Enhanced with offline audio processing, denoising, WASM-based transcription, fluency scoring, and reporting logic.
src/views/LoginPage/LoginPage.css Redesigned login page with animated gradient background and updated styling.
src/views/Practice/Practice.jsx Added offline practice flow, fluency report collection, and reattempt logic for failed items.

Sequence Diagram(s)

Offline Model Loading and Assessment Flow

sequenceDiagram
    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
Loading

Offline Practice and Reattempt Logic

sequenceDiagram
    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
Loading

Offline Model Download Progress Feedback

sequenceDiagram
    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
Loading

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

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

npm error code ERESOLVE
npm error ERESOLVE could not resolve
npm error
npm error While resolving: @mui/styles@5.16.7
npm error Found: react@18.3.1
npm error node_modules/react
npm error dev react@"^18.2.0" from the root project
npm error peer react@">=16.8.0" from @emotion/react@11.14.0
npm error node_modules/@emotion/react
npm error dev @emotion/react@"^11.14.0" from the root project
npm error peer @emotion/react@"^11.0.0-rc.0" from @emotion/styled@11.14.0
npm error node_modules/@emotion/styled
npm error dev @emotion/styled@"^11.14.0" from the root project
npm error 3 more (@mui/material, @mui/styled-engine, @mui/system)
npm error 3 more (@mui/material, @mui/styled-engine, @mui/system)
npm error 30 more (@emotion/styled, ...)
npm error
npm error Could not resolve dependency:
npm error peer react@"^17.0.0" from @mui/styles@5.16.7
npm error node_modules/@mui/styles
npm error dev @mui/styles@"^5.15.10" from the root project
npm error
npm error Conflicting peer dependency: react@17.0.2
npm error node_modules/react
npm error peer react@"^17.0.0" from @mui/styles@5.16.7
npm error node_modules/@mui/styles
npm error dev @mui/styles@"^5.15.10" from the root project
npm error
npm error Fix the upstream dependency conflict, or retry
npm error this command with --force or --legacy-peer-deps
npm error to accept an incorrect (and potentially broken) dependency resolution.
npm error
npm error
npm error For a full report see:
npm error /.npm/_logs/2025-06-12T11_29_01_943Z-eresolve-report.txt
npm error A complete log of this run can be found in: /.npm/_logs/2025-06-12T11_29_01_943Z-debug-0.log

✨ Finishing Touches
  • 📝 Generate Docstrings

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.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need 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)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@sonarqubecloud
Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
5 Security Hotspots
C Reliability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 36

🔭 Outside diff range comments (5)
src/services/telementryService.js (1)

13-16: ⚠️ Potential issue

JWT decode is not wrapped in a try/catch – malformed tokens will crash the app.

jwtDecode throws 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 suggestion

Hard-coded true ? ternary is a dead-code smell
return true ? ( … ) : ( … ); always renders the first branch and makes future intent unclear. Replace with a simple return ( 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 issue

CSP 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 suggestion

PropTypes missing for new props and loosened handleBack

  1. Add entries for offlinePractice (bool) and setOfflineReport (func).
  2. handleBack was relaxed to PropTypes.any; unless strictly required this weakens type-safety. Use func and 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

.container class name collides with global semantics and duplicates .loginPage__container

A generic selector like .container risks 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

offilnePractice is forwarded twice to VoiceAnalyser. 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 .gitignore to cover generated WebAssembly package files under pkg/ (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_Store or *.swp.

src/components/DiscoverSentance/DiscoverSentance.jsx (1)

3-3: Remove unused Axios import
axios is 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 remove import 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 via aria-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 unused fetchFile import.

fetchFile is 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: Make corePath configurable.

Hard-coding the corePath ties 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 an onClose handler 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, pass onClose={() => {}} to satisfy MUI’s prop-types warning.


23-29: Coerce progress to a number once and clamp it.

progress could be undefined or 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 commented console.log can 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
Box and Typography are 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-scope is 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

  1. every static asset is served with Cross-Origin-Resource-Policy: same-origin, or
  2. integrate a shim like vite-plugin-coi which 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 holds vite.config.js, vite.config.mjs, and a vite.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_hook gated only on debug_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 of debug_assertions, or document the reasoning clearly.

asr-utils/pkg/package.json (1)

1-20: Add standard package-metadata and tighten the bundle surface

  1. collaborators is a non-standard npm field; use contributors instead.
  2. Consider adding the common metadata keys: description, license, repository, keywords. These help consumers and tooling.
  3. The package currently exposes all runtime files via "files", but there is no "exports" map. Consumers doing import { … } 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"
+    }
+  },
  1. "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 explicit init() function that callers invoke, and set "sideEffects": false.
public/sherpa.wasm/initShrepa.js (2)

3-4: Left-over debugging log

Repeated "inited!" logs will spam the console. Remove or wrap behind a debug flag.


12-17: Global leakage – expose only what is necessary

Attaching OfflineRecognizer, createVad, and the whole Module object to window pollutes the global namespace and hinders tree-shaking. Prefer returning them from loadSherpaModule() and letting the caller decide where to stash the handles.

src/components/Mechanism/WordsOrImage.jsx (1)

1055-1057: Condition unchanged but readability can improve

The triple level === 1 || level === 2 || level === 3 would 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-level before_script to reduce duplication.

Also applies to: 32-36, 54-57

src/views/LoginPage/LoginPage.css (3)

20-25: Keyframes lack vendor-prefix fall-backs

Animations are fine on evergreen browsers, but if you still support Safari < 9 / Samsung < 5, add @-webkit-keyframes to 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: use transform for shadow pulse

box-shadow is expensive to animate; if you intend continuous glow consider an ::after pseudo-element with opacity transition instead.

asr-utils/pkg/indicasr_wasm_bg.wasm.d.ts (1)

3-9: Auto-generated typings expose only numeric pointers

The 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 width 40% hampers small screens

Consider min(90vw, 400px) or CSS clamp to stay responsive.


51-55: Accessibility: add alt text to the GIF

Screen readers will otherwise announce nothing.

-  <img
+  <img
+    alt="Download in progress"

70-79: Internationalisation: Hard-coded “LOADING…” text

Extract to i18n resources so non-English locales show correct copy.

asr-utils/pkg/indicasr_wasm.d.ts (1)

8-26: Broad Array<any> types erode type-safety

If the WASM exports always return numeric arrays (e.g., Float32Array or Int32Array), 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: Default modelLoaded relies on global mutable state

Reading window.modelLoaded directly 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 errors

Consider 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-statics to use CommonJS require syntax, 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-statics supports 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.include instead:

  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: languages filter lacks null-safety for env vars

If 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 the JSON.parse in a try/catch or allowing simple comma-separated strings.


9742-9742: Suspicious RNNoise model path/extension

"models/cb.rnnn" has a triple-n extension. Common artefacts are .rnn, .onnx or .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) and original are 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 – reattemptIndices is never read

setReattemptIndices is 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

📥 Commits

Reviewing files that changed from the base of the PR and between 1d4191e and 762702e.

⛔ Files ignored due to path filters (5)
  • asr-utils/pkg/indicasr_wasm_bg.wasm is excluded by !**/*.wasm
  • package-lock.json is excluded by !**/package-lock.json
  • public/sherpa.wasm/sherpa-onnx-wasm-main-vad-asr.wasm is excluded by !**/*.wasm
  • src/assets/images/boy-running.gif is excluded by !**/*.gif
  • yarn.lock is 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: Handle Audio.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 only connect-src needs unpkg.com
If you dynamically import or execute scripts from https://unpkg.com, they must also appear in script-src. Confirm the intended fetch pattern; otherwise resources may still be blocked in production.

asr-utils/pkg/indicasr_wasm.js (1)

1-4: Direct .wasm ESM import relies on bundler support

Native browsers still gate-keep bare .wasm imports behind --experimental-wasm-modules.
If you intend to ship this file unbundled, use WebAssembly.instantiateStreaming / fetch fallback 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 feedback

This 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 feedback

Nothing 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

.loginBox and .textField are not prefixed with .loginPage here, breaking the scoping you established above. Align selectors to avoid style leakage.

src/utils/constants.jsx (1)

7853-7864: Bulk addition of offline: true looks sound

Marking 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 needed

The 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 good

No functional issues spotted in the WASM binding helpers.

Comment on lines +5 to +15
<Box
sx={{
display: "flex",
position: "absolute",
zIndex: 999,
justifyContent: "center",
width: "100%",
alignItems: "center",
height: "100vh",
backgroundColor: "rgb(0 0 0 / 56%)",
}}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ 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.

Comment on lines +11 to +40
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
};
}, []);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ 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.

Suggested change
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";
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ 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:

  1. Delete the import, or
  2. 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.

Comment on lines +25 to +31
<!-- <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>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

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.

Suggested change
<!-- <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".

Comment on lines +25 to +34
<!-- <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>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ 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.

Suggested change
<!-- <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.

Comment on lines +1080 to +1093
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());
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ 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.

Comment on lines +1148 to +1156
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;
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ 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.

Suggested change
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.

Comment on lines +376 to 384
onClick={async () => {
setLang(selectedLang);
setOpenLangModal(false);
if (isOfflineModel && selectedLang !== "en") {
loadModel(selectedLang);
} else {
await window.sherpaModule.loadModel();
}
}}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

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.

Comment on lines +1656 to 1659
!isShowCase &&
isOffline &&
localStorage.getItem("isOfflineModel") === "true",
storyLine,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

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.

Comment on lines +926 to +939
// 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({
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

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.

Suggested change
// 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants