fix: WebGPU CPU fallback, Gemma 3 1B registry, HTML mobile dedup (#97 #165 #170)#302
Conversation
- fix(#97): detect WebGPU availability in TransformersEngineWrapper; fall back to CPU/WASM when navigator.gpu is absent or adapter request fails — Whisper and TTS now load in non-WebGPU browsers automatically - feat(#170): add gemma-3-1b-it to MLC model registry (Q4 quantizations, 32K context, shader-f16 required) alongside existing gemma-2b-it - fix(#165): add removeHiddenAndDuplicateElements() to HTMLCleaner; prunes aria-hidden=true, inline display:none/visibility:hidden, and responsive class-name heuristics (mobile-only, desktop-hidden, etc.) before text extraction — eliminates mobile/desktop content duplication
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
✅ Files skipped from review due to trivial changes (1)
📝 WalkthroughWalkthroughAdds Gemma 3 1B instruction-tuned model config with quantizations, integrates removal of hidden/duplicate HTML elements early in the cleaning pipeline, and implements async device detection that prefers WebGPU but falls back to CPU/WASM when WebGPU is unavailable. Changes
Sequence Diagram(s)sequenceDiagram
participant Client as Browser
participant Wrapper as TransformersEngineWrapper
participant WebGPU as WebGPU Adapter
participant CPU as CPU/WASM Runtime
Client->>Wrapper: request loadModel(options?)
Wrapper->>WebGPU: check navigator.gpu && requestAdapter()
alt adapter obtained
WebGPU-->>Wrapper: adapter
Wrapper->>Wrapper: return 'webgpu' device
Wrapper->>WebGPU: initialize model using WebGPU
else no adapter
WebGPU-->>Wrapper: fail / undefined
Wrapper->>CPU: choose 'cpu' / WASM
Wrapper->>CPU: initialize model in CPU/WASM
end
Wrapper-->>Client: model loaded
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
src/core/agent/html-cleaner.ts (1)
63-98: Add regression tests for the new pruning heuristic.This path is high-impact and currently untested in the provided suite. Please add focused cases for
aria-hidden, inline hidden styles, responsive hidden classes, and non-hidden responsive classes to prevent accidental content drops.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/core/agent/html-cleaner.ts` around lines 63 - 98, Add regression tests for removeHiddenAndDuplicateElements: create unit tests that (1) assert elements with aria-hidden="true" are removed, (2) assert elements with inline style display:none or visibility:hidden are removed, (3) assert elements whose className matches the RESPONSIVE_PATTERN (e.g., "mobile-only", "desktop-hidden", "show-on-tablet", "hidden-xs") are removed, and (4) assert elements with similar but non-matching responsive class names are kept; call the removeHiddenAndDuplicateElements method on a constructed DOM root and verify removed vs retained nodes to prevent future regressions.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/core/agent/html-cleaner.ts`:
- Around line 56-57: The cleanup currently treats responsive classes containing
utility words including "show" and "visible" as duplicates and removes those
elements; update the class-matching logic in src/core/agent/html-cleaner.ts so
that the responsive-utility list/regex no longer includes "show" and "visible"
(leave "hidden", "only", "hide", etc.), i.e., remove "show" and "visible" from
the array/regex that detects responsive hide/show classes and adjust any logic
in the function that prunes responsive duplicate nodes to skip elements matched
only by "show"/"visible" variants; run or add tests covering cases like
"show-on-tablet" and "visible-desktop" to ensure they are preserved.
In `@src/engines/transformer-engine-wrapper.ts`:
- Around line 16-28: Prettier flagged formatting in
src/engines/transformer-engine-wrapper.ts; run the project's Prettier formatter
on this file (or run the formatter task/IDE integration) to reformat
detectBestDevice and surrounding code; specifically locate the detectBestDevice
function and apply Prettier so spacing/line breaks and semicolons match repo
style and CI will pass.
- Around line 68-73: The engine wrapper's auto-detection is bypassed because
callers are hardcoding options.device; remove the hardcoded device in the caller
(textToSpeech in src/core/llm/index.ts) so that TransformerEngineWrapper code
(the options.device check and detectBestDevice call inside
transformer-engine-wrapper.ts) can run; specifically, stop passing device:
'webgpu' from textToSpeech and instead pass no device (or forward undefined) so
TransformerEngineWrapper's logic using detectBestDevice() can pick the best
device at runtime.
---
Nitpick comments:
In `@src/core/agent/html-cleaner.ts`:
- Around line 63-98: Add regression tests for removeHiddenAndDuplicateElements:
create unit tests that (1) assert elements with aria-hidden="true" are removed,
(2) assert elements with inline style display:none or visibility:hidden are
removed, (3) assert elements whose className matches the RESPONSIVE_PATTERN
(e.g., "mobile-only", "desktop-hidden", "show-on-tablet", "hidden-xs") are
removed, and (4) assert elements with similar but non-matching responsive class
names are kept; call the removeHiddenAndDuplicateElements method on a
constructed DOM root and verify removed vs retained nodes to prevent future
regressions.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 1dd5e013-fb36-4e60-9d69-83a52f94a3f5
📒 Files selected for processing (3)
src/config/models/mlc-models.jsonsrc/core/agent/html-cleaner.tssrc/engines/transformer-engine-wrapper.ts
| * 3. CSS class names containing "mobile", "desktop", "tablet" combined with common | ||
| * hide/show utility words ("hidden", "only", "show", "hide", "visible") — a heuristic |
There was a problem hiding this comment.
Do not prune show/visible responsive classes as duplicates.
Line [67] removes elements matching show/visible responsive classes (e.g., show-on-tablet, visible-desktop). That can delete the only intended content variant and cause downstream content loss.
Proposed fix
- const RESPONSIVE_PATTERN =
- /\b(mobile|desktop|tablet|phone|sm|md|lg|xl)\b.{0,10}\b(only|hidden|hide|show|visible|invisible)\b|\b(hidden|hide|show|visible|invisible)\b.{0,10}\b(mobile|desktop|tablet|phone|sm|md|lg|xl)\b/i;
+ const RESPONSIVE_HIDDEN_PATTERN =
+ /\b(mobile|desktop|tablet|phone|xs|sm|md|lg|xl)\b.{0,10}\b(hidden|hide|invisible|only)\b|\b(hidden|hide|invisible|only)\b.{0,10}\b(mobile|desktop|tablet|phone|xs|sm|md|lg|xl)\b/i;
@@
- if (typeof className === 'string' && RESPONSIVE_PATTERN.test(className)) {
+ if (typeof className === 'string' && RESPONSIVE_HIDDEN_PATTERN.test(className)) {
toRemove.push(el);
}Also applies to: 67-90
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/core/agent/html-cleaner.ts` around lines 56 - 57, The cleanup currently
treats responsive classes containing utility words including "show" and
"visible" as duplicates and removes those elements; update the class-matching
logic in src/core/agent/html-cleaner.ts so that the responsive-utility
list/regex no longer includes "show" and "visible" (leave "hidden", "only",
"hide", etc.), i.e., remove "show" and "visible" from the array/regex that
detects responsive hide/show classes and adjust any logic in the function that
prunes responsive duplicate nodes to skip elements matched only by
"show"/"visible" variants; run or add tests covering cases like "show-on-tablet"
and "visible-desktop" to ensure they are preserved.
| if (!options.device) { | ||
| options.device = await detectBestDevice(); | ||
| if (options.device === 'cpu') { | ||
| console.info('[Transformers] WebGPU unavailable — falling back to CPU/WASM inference'); | ||
| } | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify default call sites that hard-code WebGPU and bypass auto-fallback.
rg -n -C3 "textToSpeech\(" src/core/llm/index.ts
rg -n -C3 "device:\s*'webgpu'" src/core/llm/index.ts src/engines/transformer-engine-wrapper.ts
rg -n -C3 "if \(!options\.device\)" src/engines/transformer-engine-wrapper.tsRepository: sauravpanda/BrowserAI
Length of output: 1139
Remove hardcoded device: 'webgpu' to allow the engine's auto-detection fallback to run.
At Line 68 of src/engines/transformer-engine-wrapper.ts, the auto-detection only executes when options.device is unset. However, textToSpeech() in src/core/llm/index.ts (Line 197) hardcodes device: 'webgpu', bypassing this fallback and breaking on non-WebGPU browsers.
Suggested fix
- await this.engine.loadModel(MODEL_CONFIG['kokoro-tts'], {
- quantized: true,
- device: 'webgpu',
- ...options,
- });
+ await this.engine.loadModel(MODEL_CONFIG['kokoro-tts'], {
+ quantized: true,
+ ...options,
+ });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/engines/transformer-engine-wrapper.ts` around lines 68 - 73, The engine
wrapper's auto-detection is bypassed because callers are hardcoding
options.device; remove the hardcoded device in the caller (textToSpeech in
src/core/llm/index.ts) so that TransformerEngineWrapper code (the options.device
check and detectBestDevice call inside transformer-engine-wrapper.ts) can run;
specifically, stop passing device: 'webgpu' from textToSpeech and instead pass
no device (or forward undefined) so TransformerEngineWrapper's logic using
detectBestDevice() can pick the best device at runtime.
CI was rejecting the PR branch on a prettier format check in the WebGPU fallback code path. Pure formatting, no logic change. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Summary
Three independent fixes across the BrowserAI library.
Closes #97, #165, #170.
Fix #97 — WebGPU fallback to CPU/WASM in Transformers engine
Problem:
TransformersEngineWrapperunconditionally setdevice = 'webgpu', causing Whisper transcription and TTS to fail silently in Firefox and browsers without WebGPU support.Fix: Added
detectBestDevice()which probesnavigator.gpu.requestAdapter()before loading a model. Falls back to'cpu'(ONNX WASM backend) automatically. Callers can still override by passingoptions.deviceexplicitly.Fix #165 — Remove mobile/desktop duplicate content during HTML cleaning
Problem: Many websites serve the same text twice — once for mobile and once for desktop layout — controlled by CSS. Since
DOMParserruns without stylesheets, both copies ended up in the cleaned output.Fix: Added
removeHiddenAndDuplicateElements()called before text extraction inclean(),cleanSemantic(), andpreserveSemanticHierarchy(). It removes:aria-hidden="true"(explicitly hidden from AT, almost always decorative duplicates)display:noneorvisibility:hiddenmobile-only,desktop-hidden,show-on-tablet)Fix #170 — Add Gemma 3 1B Instruct to model registry
Problem: Only Gemma 2B was registered; no 1B Gemma model was available.
Fix: Added
gemma-3-1b-ittomlc-models.jsonfollowing the same pattern asgemma-2b-it:mlc-ai/gemma-3-1b-it-{quantization}-MLCq4f16_1,q4f32_1shader-f16featureTest plan
npm run buildsucceedsnpm test— 22/22 tests passai.loadModel('gemma-3-1b-it')loads correctlySummary by CodeRabbit