feat(dashboard): add interactive gradcam heatmap overlay#105
Conversation
|
@Deepak06-v is attempting to deploy a commit to the karan3431's projects Team on Vercel. A member of the Team first needs to authorize it. |
|
Warning
|
| Layer / File(s) | Summary |
|---|---|
Scan image persistence to sessionStorage src/pages/ScannerPage.tsx, src/pages/AnalysisDashboard.tsx |
After storing lastScanId, ScannerPage reads the scanned blob with FileReader and writes the base64 data URL to sessionStorage as lastScanImage. AnalysisDashboard imports are extended with useRef, useCallback, and additional Lucide icons to support the new overlay component. |
FishImageOverlay component src/pages/AnalysisDashboard.tsx |
New non-exported component that fetches the Grad-CAM heatmap via api.getGradcam, using the sessionStorage cached image or falling back to a direct fetch of the photo URL. Manages loading/error states, renders a slider mode with clipPath-based drag (mouse and touch) and a toggle mode with opacity transitions, and shows a heat-intensity legend. |
Two-column dashboard layout src/pages/AnalysisDashboard.tsx |
Replaces the single-row score/species layout with a responsive two-column grid: FishImageOverlay on the left, grade/freshness card and species panel stacked on the right. Card padding and sizing classes are updated to match. |
Sequence Diagram
sequenceDiagram
participant ScannerPage
participant sessionStorage
participant FishImageOverlay
participant api
ScannerPage->>sessionStorage: store lastScanImage (base64)
Note over ScannerPage,sessionStorage: On successful scan submit
FishImageOverlay->>sessionStorage: read lastScanImage
alt base64 cached
sessionStorage-->>FishImageOverlay: base64 data URL → Blob
else not cached
FishImageOverlay->>FishImageOverlay: fetch(photoUrl) → Blob
end
FishImageOverlay->>api: getGradcam(blob)
api-->>FishImageOverlay: heatmap blob URL
FishImageOverlay->>FishImageOverlay: render slider / toggle overlay
Estimated code review effort
🎯 4 (Complex) | ⏱️ ~45 minutes
Poem
🐟 Hop hop, the rabbit peers through the lens,
A heatmap glows where freshness bends.
Slider left, slider right — the colors reveal,
Grad-CAM whispers what only fish feel.
Base64 cached in sessionStorage's burrow,
The dashboard shines, clear and thorough! 🌈
🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
| Check name | Status | Explanation | Resolution |
|---|---|---|---|
| Docstring Coverage | Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. | Write docstrings for the functions missing them to satisfy the coverage threshold. |
✅ Passed checks (4 passed)
| Check name | Status | Explanation |
|---|---|---|
| Title check | ✅ Passed | The title 'feat(dashboard): add interactive gradcam heatmap overlay' directly matches the main change in the changeset: introducing a Grad-CAM heatmap overlay component with interactive visualization modes. |
| Linked Issues check | ✅ Passed | Check skipped because no linked issues were found for this pull request. |
| Out of Scope Changes check | ✅ Passed | Check skipped because no linked issues were found for this pull request. |
| Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled. |
✏️ Tip: You can configure your own custom pre-merge checks in the settings.
✨ Finishing Touches
🧪 Generate unit tests (beta)
- Create PR with unit tests
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 @coderabbitai help to get the list of available commands and usage tips.
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/pages/AnalysisDashboard.tsx`:
- Around line 41-72: The fetchHeatmap effect does not cancel previous inflight
requests when the scanId changes, allowing stale responses to overwrite newer
data. Add an AbortController to the fetchHeatmap function to track the request,
pass the abort signal to the fetch call, and implement a cleanup function in
useEffect that aborts the previous request when dependencies change. Before
setting state with the response (setHeatmapSrc, setOriginalSrc), check if the
request was aborted to ensure stale responses don't overwrite data from the
current scan.
In `@src/pages/ScannerPage.tsx`:
- Around line 76-85: The issue is that sessionStorage.setItem for lastScanId is
called synchronously before the FileReader asynchronously updates lastScanImage,
creating a race condition where AnalysisDashboard could pair a new scan ID with
a stale image. To fix this, first clear any stale lastScanImage from
sessionStorage before creating the FileReader, then move the
sessionStorage.setItem call for lastScanId inside the reader.onload callback to
ensure both lastScanImage and lastScanId are updated atomically only after the
blob has been fully serialized to base64.
🪄 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: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 76db203e-1d7f-40e4-8c81-a6b992906e12
📒 Files selected for processing (2)
src/pages/AnalysisDashboard.tsxsrc/pages/ScannerPage.tsx
| useEffect(() => { | ||
| async function fetchHeatmap() { | ||
| let imgSrc = photoUrl; | ||
| const lastScanId = sessionStorage.getItem('lastScanId'); | ||
| const lastScanImage = sessionStorage.getItem('lastScanImage'); | ||
| if (lastScanId === scanId && lastScanImage) { | ||
| imgSrc = lastScanImage; | ||
| } | ||
|
|
||
| if (!imgSrc) { | ||
| return; | ||
| } | ||
|
|
||
| setOriginalSrc(imgSrc); | ||
| setLoading(true); | ||
| setError(null); | ||
|
|
||
| try { | ||
| const response = await fetch(imgSrc); | ||
| const blob = await response.blob(); | ||
| const res = await api.getGradcam(blob); | ||
| setHeatmapSrc(res.gradcam_image); | ||
| } catch (err: unknown) { | ||
| console.error('Failed to load GradCAM overlay:', err); | ||
| setError(err instanceof Error ? err.message : 'Failed to generate heatmap.'); | ||
| } finally { | ||
| setLoading(false); | ||
| } | ||
| } | ||
|
|
||
| fetchHeatmap(); | ||
| }, [photoUrl, scanId]); |
There was a problem hiding this comment.
Reset and cancel overlay state when the scan changes.
This effect keeps the previous originalSrc/heatmapSrc until the next request finishes, and an older async response can still win the race and overwrite the newer scan. When the dashboard switches to a different scanId, that can leave scan B’s metrics beside scan A’s image or heatmap.
Suggested fix
useEffect(() => {
+ let cancelled = false;
+
async function fetchHeatmap() {
let imgSrc = photoUrl;
const lastScanId = sessionStorage.getItem('lastScanId');
const lastScanImage = sessionStorage.getItem('lastScanImage');
if (lastScanId === scanId && lastScanImage) {
imgSrc = lastScanImage;
}
+ setOriginalSrc(imgSrc ?? null);
+ setHeatmapSrc(null);
+ setError(null);
+
if (!imgSrc) {
+ setLoading(false);
return;
}
- setOriginalSrc(imgSrc);
setLoading(true);
- setError(null);
try {
const response = await fetch(imgSrc);
+ if (!response.ok) {
+ throw new Error('Failed to load source image.');
+ }
const blob = await response.blob();
const res = await api.getGradcam(blob);
- setHeatmapSrc(res.gradcam_image);
+ if (!cancelled) {
+ setHeatmapSrc(res.gradcam_image);
+ }
} catch (err: unknown) {
- console.error('Failed to load GradCAM overlay:', err);
- setError(err instanceof Error ? err.message : 'Failed to generate heatmap.');
+ if (!cancelled) {
+ console.error('Failed to load GradCAM overlay:', err);
+ setError(err instanceof Error ? err.message : 'Failed to generate heatmap.');
+ }
} finally {
- setLoading(false);
+ if (!cancelled) {
+ setLoading(false);
+ }
}
}
fetchHeatmap();
+ return () => {
+ cancelled = true;
+ };
}, [photoUrl, scanId]);🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/pages/AnalysisDashboard.tsx` around lines 41 - 72, The fetchHeatmap
effect does not cancel previous inflight requests when the scanId changes,
allowing stale responses to overwrite newer data. Add an AbortController to the
fetchHeatmap function to track the request, pass the abort signal to the fetch
call, and implement a cleanup function in useEffect that aborts the previous
request when dependencies change. Before setting state with the response
(setHeatmapSrc, setOriginalSrc), check if the request was aborted to ensure
stale responses don't overwrite data from the current scan.
Description
Checklist
npm run lintpasses with no errorsnpm run buildcompiles without TypeScript errorspython -m pytestpasses (including new tests I added).envfiles, API keys, secrets, model weights, or__pycache__in this diffmain, not mergedSummary by CodeRabbit
New Features
Improvements