-
Notifications
You must be signed in to change notification settings - Fork 30
Add new AI detectors and modernize UI #355
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Add new AI detectors and modernize UI #355
Conversation
- Added Traffic Sign, Abandoned Vehicle, Water Leak, Crowd Density, and Accessibility detectors. - Updated Home.jsx with Quick Actions grid and new categories. - Configured backend (hf_api_service.py, requirements-render.txt) for lightweight API-based detection. - Verified deployment configuration for Render (backend) and Netlify (frontend). - Wired frontend API calls to backend endpoints. Co-authored-by: RohanExploit <178623867+RohanExploit@users.noreply.github.com>
|
👋 Jules, reporting for duty! I'm here to lend a hand with this pull request. When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down. I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job! For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with New to Jules? Learn more at jules.google/docs. For security, I will only act on instructions from the user who triggered this task. |
❌ Deploy Preview for fixmybharat failed. Why did it fail? →
|
🙏 Thank you for your contribution, @RohanExploit!PR Details:
Quality Checklist:
Review Process:
Note: The maintainers will monitor code quality and ensure the overall project flow isn't broken. |
📝 WalkthroughWalkthroughAdds backend auth libraries to requirements, several new frontend detector components and detector API endpoints, updates app routing and Home quick-actions, introduces shared UI components, tweaks auth API to return full responses, and adds a Playwright verification script. Changes
Sequence Diagram(s)sequenceDiagram
actor User
participant Frontend as Frontend App
participant Camera as Browser Camera
participant Canvas as Canvas Overlay
participant API as detectorsApi
participant Backend as Backend Detector
User->>Frontend: Click "Start Detection"
Frontend->>Camera: request getUserMedia
Camera-->>Frontend: video stream
loop every 2s while active
Frontend->>Canvas: draw current video frame
Canvas->>Frontend: export JPEG blob
Frontend->>API: POST blob to /api/detect-*
API->>Backend: forward request
Backend-->>API: detection results (boxes/labels)
API-->>Frontend: return detections
Frontend->>Canvas: render boxes/labels
end
User->>Frontend: Click "Stop"
Frontend->>Camera: stop media tracks
Frontend->>Canvas: clear overlay
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related PRs
Suggested labels
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR integrates additional “HF-powered” detector views into the React app and updates navigation/UI scaffolding (header + floating widget manager), alongside a small Render deployment dependency update.
Changes:
- Added routes and lazy-loaded components for multiple new detector views (e.g., traffic sign, abandoned vehicle, water leak, crowd, accessibility).
- Updated Home view UI to surface new “Quick Actions” entries.
- Added new UI components (AppHeader, LoadingSpinner, FloatingButtonsManager) and updated auth client import usage.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| verification/check_home.py | Adds a Playwright-based home-page verification script. |
| frontend/src/views/Home.jsx | Adds new detector entries/buttons in the Home UI. |
| frontend/src/components/LoadingSpinner.jsx | Introduces a reusable loading spinner component. |
| frontend/src/components/FloatingButtonsManager.jsx | Adds a wrapper for floating UI widgets (currently ChatWidget). |
| frontend/src/components/AppHeader.jsx | Adds a sticky app header. |
| frontend/src/api/detectors.js | Registers additional detector API endpoints. |
| frontend/src/api/auth.js | Updates auth API to use the shared apiClient import/export style. |
| frontend/src/TrafficSignDetector.jsx | Adds live camera-based traffic sign detection view. |
| frontend/src/App.jsx | Wires new detectors into routing and changes Home path to /home. |
| frontend/src/AbandonedVehicleDetector.jsx | Adds live camera-based abandoned vehicle detection view. |
| backend/requirements-render.txt | Adds missing auth dependencies for Render deployments. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| def test_home_page(): | ||
| with sync_playwright() as p: | ||
| browser = p.chromium.launch() | ||
| page = browser.new_page() |
Copilot
AI
Feb 8, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
test_home_page is named like a pytest test and sits in a regular Python module, so pytest will likely auto-discover and attempt to run it (requiring a running dev server + Playwright). Consider renaming the function/file (e.g., run_check_home) or placing it under a non-test path/pattern to avoid breaking automated test runs.
| page.on("pageerror", lambda err: print(f"Page Error: {err}")) | ||
|
|
||
| try: | ||
| page.goto("http://localhost:5173") |
Copilot
AI
Feb 8, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This script navigates to http://localhost:5173, but the app’s Home route is now /home (with / used for the landing page). If the intent is to verify the Home UI, update the URL to hit /home to avoid taking a screenshot of the landing page instead.
| page.goto("http://localhost:5173") | |
| page.goto("http://localhost:5173/home") |
| <Route path="/waste" element={<WasteDetector onBack={() => navigate('/')} />} /> | ||
| <Route path="/water-leak" element={<WaterLeakDetector onBack={() => navigate('/')} />} /> | ||
| <Route path="/crowd" element={<CrowdDetector onBack={() => navigate('/')} />} /> | ||
| <Route path="/accessibility" element={<AccessibilityDetector onBack={() => navigate('/')} />} /> | ||
| <Route path="/traffic-sign" element={<TrafficSignDetector onBack={() => navigate('/')} />} /> | ||
| <Route path="/abandoned-vehicle" element={<AbandonedVehicleDetector onBack={() => navigate('/')} />} /> |
Copilot
AI
Feb 8, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The newly added detector routes pass onBack={() => navigate('/')}. Since / now renders the Landing page and Home is /home, these “Back to Home” actions will take users to the landing screen instead of the home dashboard. Update these callbacks to navigate to /home (or reuse navigateToView('home')).
| import { useTranslation } from 'react-i18next'; | ||
|
|
||
| const AppHeader = () => { | ||
| const { t } = useTranslation(); |
Copilot
AI
Feb 8, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
useTranslation() is imported and t is destructured but never used, which will trigger unused-variable linting and adds unnecessary bundle/code. Remove the unused useTranslation/t until the header actually renders translated strings.
| import { useTranslation } from 'react-i18next'; | |
| const AppHeader = () => { | |
| const { t } = useTranslation(); | |
| const AppHeader = () => { |
| import React from 'react'; | ||
| import ChatWidget from './ChatWidget'; | ||
|
|
||
| const FloatingButtonsManager = ({ setView }) => { |
Copilot
AI
Feb 8, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FloatingButtonsManager accepts setView but never uses it. This creates dead props and can fail strict lint rules; either remove the prop or actually use it (or rename to _setView) depending on intended future behavior.
| const FloatingButtonsManager = ({ setView }) => { | |
| const FloatingButtonsManager = ({ _setView }) => { |
| const colorClasses = { | ||
| primary: 'border-blue-500', | ||
| white: 'border-white', | ||
| }; | ||
|
|
||
| return ( | ||
| <div className={`rounded-full border-2 border-transparent border-t-current animate-spin ${sizeClasses[size]} ${colorClasses[variant] === 'border-blue-500' ? 'text-blue-500' : 'text-white'}`}></div> |
Copilot
AI
Feb 8, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
colorClasses is computed but never applied; the code instead hard-codes a comparison to decide text-blue-500 vs text-white. This is brittle and makes variants hard to extend. Prefer mapping variants directly to the final class (e.g., text color) and using a safe fallback when an unknown size/variant is provided.
| const colorClasses = { | |
| primary: 'border-blue-500', | |
| white: 'border-white', | |
| }; | |
| return ( | |
| <div className={`rounded-full border-2 border-transparent border-t-current animate-spin ${sizeClasses[size]} ${colorClasses[variant] === 'border-blue-500' ? 'text-blue-500' : 'text-white'}`}></div> | |
| const variantClasses = { | |
| primary: 'text-blue-500', | |
| white: 'text-white', | |
| }; | |
| const sizeClass = sizeClasses[size] || sizeClasses.md; | |
| const variantClass = variantClasses[variant] || variantClasses.primary; | |
| return ( | |
| <div className={`rounded-full border-2 border-transparent border-t-current animate-spin ${sizeClass} ${variantClass}`}></div> |
| interval = setInterval(detectFrame, 2000); // Check every 2 seconds | ||
| } else { | ||
| stopCamera(); | ||
| if (interval) clearInterval(interval); |
Copilot
AI
Feb 8, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This use of variable 'interval' always evaluates to false.
| if (interval) clearInterval(interval); |
| interval = setInterval(detectFrame, 2000); // Check every 2 seconds | ||
| } else { | ||
| stopCamera(); | ||
| if (interval) clearInterval(interval); |
Copilot
AI
Feb 8, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This use of variable 'interval' always evaluates to false.
- Explicitly set `base = "."` to ensure build runs from root context. - Simplified `netlify.toml` by removing potentially conflicting header rules. - Confirmed `publish` directory points to `frontend/dist`. - Verified local build succeeds with `cd frontend && npm install && npm run build`. Co-authored-by: RohanExploit <178623867+RohanExploit@users.noreply.github.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
5 issues found across 11 files
Prompt for AI agents (all issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="frontend/src/AbandonedVehicleDetector.jsx">
<violation number="1" location="frontend/src/AbandonedVehicleDetector.jsx:104">
P1: Drawing the video frame to the visible overlay canvas freezes the live video feed during the API call (which awaits the response). The user will see a stuttering or frozen image instead of a smooth video stream with overlay.
Use an off-screen canvas to capture the frame for detection.</violation>
</file>
<file name="frontend/src/TrafficSignDetector.jsx">
<violation number="1" location="frontend/src/TrafficSignDetector.jsx:15">
P2: Multiple zero-shot detections will render on top of each other, making the text unreadable.
The backend `detect_traffic_sign_clip` returns an empty `box` array for detections (as it uses CLIP). The `else` block handles this by drawing text at the fixed coordinates `(20, 40)`. If multiple labels are detected in the same frame (e.g., "damaged traffic sign" and "faded sign"), their text will overlap perfectly.
Use the loop index to offset the Y-coordinate for each detection.</violation>
<violation number="2" location="frontend/src/TrafficSignDetector.jsx:97">
P2: Capturing the video frame to the visible canvas causes the UI to "freeze" or stutter.
When `detectFrame` runs, it draws the current video frame onto the visible canvas (`canvasRef`). This static image obscures the live `<video>` element underneath it while the async API call is in progress (potentially for several seconds). The user sees a frozen frame instead of the live camera feed during this time.
Use an off-screen canvas to capture the image data for the API, keeping the visible canvas clear for bounding box overlays.</violation>
</file>
<file name="frontend/src/components/FloatingButtonsManager.jsx">
<violation number="1" location="frontend/src/components/FloatingButtonsManager.jsx:4">
P3: The setView prop is unused, which adds dead API surface and may indicate missing behavior. Remove it if unnecessary or wire it into the component.</violation>
</file>
<file name="frontend/src/App.jsx">
<violation number="1" location="frontend/src/App.jsx:297">
P2: The new detector routes still navigate back to "/", but the app’s home route was moved to "/home". This sends users to the landing page instead of the main home screen after exiting these detectors. Update the onBack navigation to "/home" (and keep it consistent across all new detector routes).</violation>
</file>
Since this is your first cubic review, here's how it works:
- cubic automatically reviews your code and comments on bugs and improvements
- Teach cubic by replying to its comments. cubic learns from your replies and gets better over time
- Ask questions if you need clarification on any suggestion
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
| canvas.height = video.videoHeight; | ||
| } | ||
|
|
||
| context.drawImage(video, 0, 0, canvas.width, canvas.height); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P1: Drawing the video frame to the visible overlay canvas freezes the live video feed during the API call (which awaits the response). The user will see a stuttering or frozen image instead of a smooth video stream with overlay.
Use an off-screen canvas to capture the frame for detection.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At frontend/src/AbandonedVehicleDetector.jsx, line 104:
<comment>Drawing the video frame to the visible overlay canvas freezes the live video feed during the API call (which awaits the response). The user will see a stuttering or frozen image instead of a smooth video stream with overlay.
Use an off-screen canvas to capture the frame for detection.</comment>
<file context>
@@ -0,0 +1,174 @@
+ canvas.height = video.videoHeight;
+ }
+
+ context.drawImage(video, 0, 0, canvas.width, canvas.height);
+
+ canvas.toBlob(async (blob) => {
</file context>
| if (isDetecting) { | ||
| startCamera(); | ||
| interval = setInterval(detectFrame, 2000); // Check every 2 seconds | ||
| } else { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: Multiple zero-shot detections will render on top of each other, making the text unreadable.
The backend detect_traffic_sign_clip returns an empty box array for detections (as it uses CLIP). The else block handles this by drawing text at the fixed coordinates (20, 40). If multiple labels are detected in the same frame (e.g., "damaged traffic sign" and "faded sign"), their text will overlap perfectly.
Use the loop index to offset the Y-coordinate for each detection.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At frontend/src/TrafficSignDetector.jsx, line 15:
<comment>Multiple zero-shot detections will render on top of each other, making the text unreadable.
The backend `detect_traffic_sign_clip` returns an empty `box` array for detections (as it uses CLIP). The `else` block handles this by drawing text at the fixed coordinates `(20, 40)`. If multiple labels are detected in the same frame (e.g., "damaged traffic sign" and "faded sign"), their text will overlap perfectly.
Use the loop index to offset the Y-coordinate for each detection.</comment>
<file context>
@@ -0,0 +1,175 @@
+ if (isDetecting) {
+ startCamera();
+ interval = setInterval(detectFrame, 2000); // Check every 2 seconds
+ } else {
+ stopCamera();
+ if (interval) clearInterval(interval);
</file context>
| const video = videoRef.current; | ||
| if (video.readyState !== 4) return; | ||
|
|
||
| const canvas = canvasRef.current; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: Capturing the video frame to the visible canvas causes the UI to "freeze" or stutter.
When detectFrame runs, it draws the current video frame onto the visible canvas (canvasRef). This static image obscures the live <video> element underneath it while the async API call is in progress (potentially for several seconds). The user sees a frozen frame instead of the live camera feed during this time.
Use an off-screen canvas to capture the image data for the API, keeping the visible canvas clear for bounding box overlays.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At frontend/src/TrafficSignDetector.jsx, line 97:
<comment>Capturing the video frame to the visible canvas causes the UI to "freeze" or stutter.
When `detectFrame` runs, it draws the current video frame onto the visible canvas (`canvasRef`). This static image obscures the live `<video>` element underneath it while the async API call is in progress (potentially for several seconds). The user sees a frozen frame instead of the live camera feed during this time.
Use an off-screen canvas to capture the image data for the API, keeping the visible canvas clear for bounding box overlays.</comment>
<file context>
@@ -0,0 +1,175 @@
+ const video = videoRef.current;
+ if (video.readyState !== 4) return;
+
+ const canvas = canvasRef.current;
+ const context = canvas.getContext('2d');
+
</file context>
| <Route path="/smart-scan" element={<SmartScanner onBack={() => navigate('/')} />} /> | ||
| <Route path="/grievance-analysis" element={<GrievanceAnalysis onBack={() => navigate('/')} />} /> | ||
| <Route path="/noise" element={<NoiseDetector onBack={() => navigate('/')} />} /> | ||
| <Route path="/waste" element={<WasteDetector onBack={() => navigate('/')} />} /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: The new detector routes still navigate back to "/", but the app’s home route was moved to "/home". This sends users to the landing page instead of the main home screen after exiting these detectors. Update the onBack navigation to "/home" (and keep it consistent across all new detector routes).
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At frontend/src/App.jsx, line 297:
<comment>The new detector routes still navigate back to "/", but the app’s home route was moved to "/home". This sends users to the landing page instead of the main home screen after exiting these detectors. Update the onBack navigation to "/home" (and keep it consistent across all new detector routes).</comment>
<file context>
@@ -285,6 +294,12 @@ function AppContent() {
<Route path="/smart-scan" element={<SmartScanner onBack={() => navigate('/')} />} />
<Route path="/grievance-analysis" element={<GrievanceAnalysis onBack={() => navigate('/')} />} />
<Route path="/noise" element={<NoiseDetector onBack={() => navigate('/')} />} />
+ <Route path="/waste" element={<WasteDetector onBack={() => navigate('/')} />} />
+ <Route path="/water-leak" element={<WaterLeakDetector onBack={() => navigate('/')} />} />
+ <Route path="/crowd" element={<CrowdDetector onBack={() => navigate('/')} />} />
</file context>
| import React from 'react'; | ||
| import ChatWidget from './ChatWidget'; | ||
|
|
||
| const FloatingButtonsManager = ({ setView }) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P3: The setView prop is unused, which adds dead API surface and may indicate missing behavior. Remove it if unnecessary or wire it into the component.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At frontend/src/components/FloatingButtonsManager.jsx, line 4:
<comment>The setView prop is unused, which adds dead API surface and may indicate missing behavior. Remove it if unnecessary or wire it into the component.</comment>
<file context>
@@ -0,0 +1,12 @@
+import React from 'react';
+import ChatWidget from './ChatWidget';
+
+const FloatingButtonsManager = ({ setView }) => {
+ return (
+ <>
</file context>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 9
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
frontend/src/views/Home.jsx (1)
99-103:⚠️ Potential issue | 🟡 MinorHardcoded labels bypass i18n.
Lines 99–103 use raw strings (
"Noise","Crowd","Water Leak","Waste Sorter","Accessibility") while all surrounding items uset('home.issues.…'). These won't be translated.♻️ Suggested fix
- { id: 'noise', label: "Noise", icon: <Volume2 size={24} />, color: 'text-purple-600', bg: 'bg-purple-50' }, - { id: 'crowd', label: "Crowd", icon: <Users size={24} />, color: 'text-red-500', bg: 'bg-red-50' }, - { id: 'water-leak', label: "Water Leak", icon: <Waves size={24} />, color: 'text-blue-500', bg: 'bg-blue-50' }, - { id: 'waste', label: "Waste Sorter", icon: <Recycle size={24} />, color: 'text-emerald-600', bg: 'bg-emerald-50' }, - { id: 'accessibility', label: "Accessibility", icon: <Accessibility size={24} />, color: 'text-purple-600', bg: 'bg-purple-50' }, + { id: 'noise', label: t('home.issues.noise'), icon: <Volume2 size={24} />, color: 'text-purple-600', bg: 'bg-purple-50' }, + { id: 'crowd', label: t('home.issues.crowd'), icon: <Users size={24} />, color: 'text-red-500', bg: 'bg-red-50' }, + { id: 'water-leak', label: t('home.issues.waterLeak'), icon: <Waves size={24} />, color: 'text-blue-500', bg: 'bg-blue-50' }, + { id: 'waste', label: t('home.issues.wasteSorter'), icon: <Recycle size={24} />, color: 'text-emerald-600', bg: 'bg-emerald-50' }, + { id: 'accessibility', label: t('home.issues.accessibility'), icon: <Accessibility size={24} />, color: 'text-purple-600', bg: 'bg-purple-50' },Don't forget to add the corresponding keys to your i18n translation files.
frontend/src/App.jsx (1)
202-212:⚠️ Potential issue | 🔴 CriticalMissing props passed to
Home—loadMoreIssues,hasMore, andloadingMoreare not provided.
Home(Line 55 in Home.jsx) destructuresloadMoreIssues,hasMore, andloadingMorefrom props and uses them to render the "Load More Activity" button (Home.jsx Lines 460–477). These props are not passed here, soloadMoreIssueswill beundefined— clicking "Load More Activity" will throw at runtime, and the button visibility check (hasMore) will be falsy so users can never paginate the activity feed.🐛 Proposed fix
<Home setView={navigateToView} fetchResponsibilityMap={fetchResponsibilityMap} recentIssues={recentIssues} handleUpvote={handleUpvote} + loadMoreIssues={loadMoreIssues} + hasMore={hasMore} + loadingMore={loadingMore} />
🤖 Fix all issues with AI agents
In `@backend/requirements-render.txt`:
- Around line 19-20: Update requirements-render.txt to pin the crypto-related
packages: replace the unpinned entries `passlib[bcrypt]` and
`python-jose[cryptography]` with pinned versions (e.g., `passlib>=1.7.4` and
`bcrypt==4.0.1` to ensure bcrypt <5.0.0 compatibility, and `python-jose>=3.4.0`
(preferably 3.5.0) plus `cryptography>=44.0.1`) so that `passlib`, `bcrypt`,
`python-jose`, and `cryptography` are fixed to secure, compatible releases; also
add a note or start a follow-up to add a locked dependency file
(pip-compile/Poetry/Pipenv) to lock transitive dependencies.
In `@frontend/src/AbandonedVehicleDetector.jsx`:
- Around line 1-172: AbandonedVehicleDetector and TrafficSignDetector share
camera, detection loop and canvas overlay logic; extract a reusable LiveDetector
component that contains startCamera, stopCamera, detectFrame, drawDetections,
videoRef and canvasRef, and the useEffect hook, and parameterize it with props:
title, description, detectApi (e.g., detectorsApi.abandonedVehicle),
overlayColor, and onBack; then rewrite AbandonedVehicleDetector and
TrafficSignDetector to be thin wrappers that pass the specific detectApi,
overlayColor and text into LiveDetector, preserving behavior (blob upload,
FormData, canvas sizing and drawing) and ensuring hook dependencies and error
handling remain intact.
- Around line 65-87: The else branch inside detections.forEach currently draws
all no-box labels at fixed coordinates (20,40), causing overlap; modify the loop
to accept the index (e.g., detections.forEach((det, i) => { ... })) and compute
a vertical offset for each label (for example labelY = 40 + i * <spacing>) and
use that y coordinate instead of the hardcoded 40 so each no-box detection
(rendered in the else branch) is drawn on its own line; ensure you update the
fillText/fillRect positions accordingly and keep spacing consistent with text
height.
- Around line 90-121: detectFrame currently draws the video into the overlay
canvasRef (causing doubled visuals) and allows overlapping requests; change it
to draw the video into a separate offscreen canvas (create a local
offscreenCanvas sized to video.videoWidth/video.videoHeight and use its 2D
context to call toBlob) so canvasRef is used only for annotations via
drawDetections, and add an in-flight guard (e.g., a boolean or ref like
inFlightRef/isRequestInFlight checked at the start of detectFrame and set true
before awaiting detectorsApi.abandonedVehicle(formData) and false in finally) to
skip starting a new API call while one is pending; ensure you still resize
offscreenCanvas to the video dimensions and pass the blob from the offscreen
canvas to detectorsApi.abandonedVehicle, and only drawDetections onto
canvasRef's context.
- Around line 10-28: The else branch in the useEffect contains a dead
clearInterval and the detectFrame closure captures a stale isDetecting; change
to store the interval id and detection state in refs (e.g., detectionIntervalRef
and isDetectingRef), update useEffect to set isDetectingRef.current when
isDetecting changes, assign the interval id to detectionIntervalRef.current
inside the if (isDetecting) block and clear it only from the cleanup using
clearInterval(detectionIntervalRef.current), remove the redundant clearInterval
in the else branch, and modify detectFrame to read isDetectingRef.current
instead of the captured isDetecting; keep existing startCamera/stopCamera and
canvasRef clear logic but rely on the cleanup function to clear the interval.
In `@frontend/src/App.jsx`:
- Around line 297-302: The onBack handlers for the detector routes in App.jsx
currently call navigate('/') which sends users to the Landing page; update each
detector route's onBack prop (e.g., WasteDetector, WaterLeakDetector,
CrowdDetector, AccessibilityDetector, TrafficSignDetector,
AbandonedVehicleDetector and also the earlier detectors at lines ~259–296) to
call navigate('/home') instead so the Back button returns to the Home route;
locate the Route elements that pass onBack={() => navigate('/')} and replace the
path string with '/home'.
In `@frontend/src/components/AppHeader.jsx`:
- Line 7: The header element in the AppHeader component currently has
conflicting Tailwind classes ("bg-white" and "bg-white/80"); remove the solid
"bg-white" class from the header's className so the translucent "bg-white/80"
and "backdrop-blur-md" glassmorphism effect can take effect (i.e., update the
header JSX in AppHeader.jsx to drop "bg-white" while keeping "bg-white/80" and
the blur/positioning classes).
In `@frontend/src/components/FloatingButtonsManager.jsx`:
- Around line 4-10: FloatingButtonsManager currently destructures the unused
prop setView and wraps a single child in an unnecessary fragment; either remove
setView from the parameter list and return the single child directly (replace
the fragment with just <ChatWidget />) or, if setView is intended to be used,
pass it through to ChatWidget (e.g., <ChatWidget setView={setView} />) and
implement handling in ChatWidget; update the FloatingButtonsManager declaration
(function params) and its returned JSX accordingly.
In `@verification/check_home.py`:
- Around line 3-20: test_home_page currently only screenshots and prints but
never fails; change it to read the base URL from an environment variable (e.g.,
os.environ.get("BASE_URL", "http://localhost:5173")) instead of the hardcoded
string and add assertions so the test can fail: assert the page loaded
successfully after page.goto (e.g., check response status or wait_for_load_state
and assert page.title() contains expected text) and fail if any console "error"
or pageerror events occurred (collect console/pageerror messages in a list and
assert it is empty). Update references in the function test_home_page
(page.goto, page.on handlers, and the final assertion logic) so the test runner
will correctly surface failures.
🧹 Nitpick comments (3)
frontend/src/api/detectors.js (1)
4-32: Consider cleaning up the stream-of-consciousness comments increateDetectorApi.Lines 9–30 are internal design deliberation notes left in production code. Both the
ifandelsebranches do the exact same thing (apiClient.postForm), making the 20+ lines of rationale comments confusing for future readers. Consider trimming to a one-liner or removing the deadifbranch entirely.♻️ Suggested simplification
const createDetectorApi = (endpoint) => async (data) => { - // If data is a FormData object (checking if it has append method is a heuristic) - if (data instanceof FormData) { - return await apiClient.postForm(endpoint, data); - } - // If data contains an image property that is a base64 string, - // the current backend implementation for infrastructure/vandalism/etc expects BYTES. - // However, sending JSON with base64 encoded image is standard for JSON APIs. - // BUT the backend endpoint defines `image: UploadFile = File(...)`. - // This means it EXPECTS multipart/form-data. - - // So if the input is NOT FormData, we should probably wrap it or assume the caller creates FormData. - // To be safe and consistent, let's assume the caller passes FormData or we convert it if possible. - // If the caller passes { image: base64 }, we can't easily convert to File without logic. - - // Let's enforce that the caller must pass FormData for file upload endpoints. - // Or we provide a helper to convert base64 to FormData. - - // But wait, my previous implementation of createDetectorApi was: - // apiClient.post(endpoint, { image: imageSrc }); - // This sends JSON. - // The backend `UploadFile = File(...)` will fail with 422 Unprocessable Entity if it receives JSON. - - // So createDetectorApi MUST use postForm and the caller MUST provide FormData. - // OR we convert here. - - // Let's change createDetectorApi to expect FormData. - return await apiClient.postForm(endpoint, data); + // Callers must pass FormData for file upload endpoints. + return await apiClient.postForm(endpoint, data); };frontend/src/components/AppHeader.jsx (1)
5-5:useTranslationhook is called buttis never used.The title is hardcoded as "VishwaGuru". Either use
t('appTitle')(or similar key) to make the header translatable, or remove the unused hook import to avoid unnecessary overhead.frontend/src/components/LoadingSpinner.jsx (1)
9-15:colorClassesmap is never applied — it's used as an indirect string comparison to pick text color.
colorClasses[variant]resolves to a border class string (e.g.,'border-blue-500'), but that string is never added toclassName. Instead, it's compared to'border-blue-500'to decide betweentext-blue-500andtext-white. This is fragile and misleading — if anyone changes the map value, the comparison silently breaks. Also, passing an unsupportedsizeorvariantrenders"undefined"in the class string.♻️ Simplified and robust version
const LoadingSpinner = ({ size = 'md', variant = 'primary' }) => { const sizeClasses = { sm: 'w-4 h-4', md: 'w-8 h-8', xl: 'w-12 h-12', }; - const colorClasses = { - primary: 'border-blue-500', - white: 'border-white', - }; + const textColorClasses = { + primary: 'text-blue-500', + white: 'text-white', + }; return ( - <div className={`rounded-full border-2 border-transparent border-t-current animate-spin ${sizeClasses[size]} ${colorClasses[variant] === 'border-blue-500' ? 'text-blue-500' : 'text-white'}`}></div> + <div className={`rounded-full border-2 border-transparent border-t-current animate-spin ${sizeClasses[size] ?? 'w-8 h-8'} ${textColorClasses[variant] ?? 'text-blue-500'}`}></div> ); };
| passlib[bcrypt] | ||
| python-jose[cryptography] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🌐 Web query:
passlib bcrypt latest stable version 2025 security advisories
💡 Result:
Latest stable versions (as of 2025)
- passlib (PyPI): 1.7.4 — released Oct 8, 2020 (still the latest on PyPI in 2025). [1]
- bcrypt (pyca/bcrypt on PyPI): 5.0.0 — released Sep 25, 2025. [2]
Security advisories / known issues relevant to 2025
- passlib: No known direct vulnerabilities reported for the latest release 1.7.4 in Snyk’s DB, but older versions (<1.7.3) are flagged for a cryptographic weakness (unsalted SHA-256 “prehash” used with bcrypt, enabling breach-correlation). Upgrade guidance: use passlib ≥ 1.7.3 (1.7.4 satisfies this). [3][4]
- bcrypt (Python package): Snyk and Safety DB report no known direct vulnerabilities affecting bcrypt 5.0.0. [5][6]
Practical 2025 concern (compatibility, not a CVE)
- passlib + bcrypt compatibility: bcrypt releases have explicitly had compatibility friction with passlib (e.g., bcrypt 4.1.0 was yanked due to “incompatibility with assumptions made by passlib”). [2]
- Community reports indicate bcrypt 5.0.0 can break passlib-based workflows (e.g., Ansible users reporting failures and proposing patches, noting passlib maintenance concerns). [7]
Sources: passlib on PyPI [1], bcrypt on PyPI [2], Snyk passlib advisory details [3][4], Snyk bcrypt status [5], Safety DB bcrypt status [6], Ansible community thread on bcrypt 5.0.0 breakage with passlib [7].
🌐 Web query:
python-jose cryptography latest stable version 2025 security advisories CVE
💡 Result:
Latest stable versions (as released in 2025)
- python-jose: 3.5.0 (released May 28, 2025) [1]
- cryptography (pyca/cryptography): 46.0.3 (released Oct 15, 2025) [2]
(Note: cryptography 46.0.4 was released Jan 28, 2026, i.e., after 2025.) [2]
Security advisories / CVEs relevant to 2025 (published or updated in 2025)
python-jose
- CVE-2025-61152 — “alg=none” JWT acceptance / signature-bypass risk (GitHub Advisory Database entry; unreviewed) [3]
- CVE-2024-33664 — DoS via highly-compressed JWE (“JWT bomb”); affects python-jose < 3.4.0, patched in 3.4.0 (advisory updated Feb 18, 2025) [4]
- CVE-2024-29370 — DoS via compressed JWE content; fixed in 3.4.0 (listed as a duplicate/withdrawn advisory, but points to the same underlying issue/fix) [5]
cryptography
- CVE-2024-12797 — cryptography wheels bundled a vulnerable OpenSSL; affects cryptography >= 42.0.0, < 44.0.1, patched in 44.0.1 (published Feb 11, 2025) [6]
Sources: [1] python-jose PyPI release history; [2] cryptography PyPI release history; [3] GHSA entry for CVE-2025-61152; [4] GHSA entry for CVE-2024-33664; [5] GitLab advisory note for CVE-2024-29370 (duplicate); [6] GHSA entry for CVE-2024-12797.
🏁 Script executed:
#!/bin/bash
# Check requirements management in the project
echo "=== Requirements files in the repository ==="
find . -name "requirements*.txt" -o -name "Pipfile*" -o -name "poetry.lock" -o -name "pyproject.toml" | head -20
echo -e "\n=== Contents of backend/requirements-render.txt ==="
cat -n backend/requirements-render.txt
echo -e "\n=== Check for version pinning patterns ==="
rg -A 2 -B 2 "passlib|python-jose" --type txtRepository: RohanExploit/VishwaGuru
Length of output: 1049
Pin crypto dependencies to secure, compatible versions; critical CVE exposure without pinning.
Unpinned passlib[bcrypt] and python-jose[cryptography] expose the project to critical vulnerabilities and compatibility breaks:
- passlib[bcrypt]: Unpinned constraint will pull bcrypt 5.0.0 (latest), which is incompatible with passlib—causing runtime failures. Pin to
passlib>=1.7.4withbcrypt<5.0.0(e.g., bcrypt==4.0.1). - python-jose[cryptography]: Unpinned constraint risks pulling python-jose < 3.4.0, which is vulnerable to CVE-2024-33664 (DoS via compressed JWE). Pin to
python-jose>=3.4.0(currently 3.5.0). - cryptography: Pin to
>=44.0.1to avoid CVE-2024-12797 (vulnerable OpenSSL bundled in wheels, patched Feb 2025).
Also consider adopting a lockfile (e.g., pip-compile, Poetry, or Pipenv) to lock all transitive dependencies.
🤖 Prompt for AI Agents
In `@backend/requirements-render.txt` around lines 19 - 20, Update
requirements-render.txt to pin the crypto-related packages: replace the unpinned
entries `passlib[bcrypt]` and `python-jose[cryptography]` with pinned versions
(e.g., `passlib>=1.7.4` and `bcrypt==4.0.1` to ensure bcrypt <5.0.0
compatibility, and `python-jose>=3.4.0` (preferably 3.5.0) plus
`cryptography>=44.0.1`) so that `passlib`, `bcrypt`, `python-jose`, and
`cryptography` are fixed to secure, compatible releases; also add a note or
start a follow-up to add a locked dependency file (pip-compile/Poetry/Pipenv) to
lock transitive dependencies.
| import React, { useRef, useState, useEffect } from 'react'; | ||
| import { detectorsApi } from './api'; | ||
|
|
||
| const AbandonedVehicleDetector = ({ onBack }) => { | ||
| const videoRef = useRef(null); | ||
| const canvasRef = useRef(null); | ||
| const [isDetecting, setIsDetecting] = useState(false); | ||
| const [error, setError] = useState(null); | ||
|
|
||
| useEffect(() => { | ||
| let interval; | ||
| if (isDetecting) { | ||
| startCamera(); | ||
| interval = setInterval(detectFrame, 2000); // Check every 2 seconds | ||
| } else { | ||
| stopCamera(); | ||
| if (interval) clearInterval(interval); | ||
| if (canvasRef.current) { | ||
| const ctx = canvasRef.current.getContext('2d'); | ||
| ctx.clearRect(0, 0, canvasRef.current.width, canvasRef.current.height); | ||
| } | ||
| } | ||
| return () => { | ||
| stopCamera(); | ||
| if (interval) clearInterval(interval); | ||
| }; | ||
| // eslint-disable-next-line react-hooks/exhaustive-deps | ||
| }, [isDetecting]); | ||
|
|
||
| const startCamera = async () => { | ||
| setError(null); | ||
| try { | ||
| const stream = await navigator.mediaDevices.getUserMedia({ | ||
| video: { | ||
| facingMode: 'environment', | ||
| width: { ideal: 640 }, | ||
| height: { ideal: 480 } | ||
| } | ||
| }); | ||
| if (videoRef.current) { | ||
| videoRef.current.srcObject = stream; | ||
| } | ||
| } catch (err) { | ||
| setError("Could not access camera: " + err.message); | ||
| setIsDetecting(false); | ||
| } | ||
| }; | ||
|
|
||
| const stopCamera = () => { | ||
| if (videoRef.current && videoRef.current.srcObject) { | ||
| const tracks = videoRef.current.srcObject.getTracks(); | ||
| tracks.forEach(track => track.stop()); | ||
| videoRef.current.srcObject = null; | ||
| } | ||
| }; | ||
|
|
||
| const drawDetections = (detections, context) => { | ||
| context.clearRect(0, 0, context.canvas.width, context.canvas.height); | ||
|
|
||
| context.lineWidth = 4; | ||
| context.font = 'bold 18px Arial'; | ||
|
|
||
| if (!detections || detections.length === 0) return; | ||
|
|
||
| detections.forEach(det => { | ||
| const { label, confidence, box } = det; | ||
|
|
||
| // For Abandoned Vehicle (likely zero-shot, no box) | ||
| // But if we had box... | ||
| if (box && box.length === 4) { | ||
| const [x1, y1, x2, y2] = box; | ||
| context.strokeStyle = '#A9A9A9'; // DarkGray | ||
| context.strokeRect(x1, y1, x2 - x1, y2 - y1); | ||
|
|
||
| context.fillStyle = 'rgba(0,0,0,0.5)'; | ||
| const text = `${label} ${(confidence * 100).toFixed(0)}%`; | ||
| const textWidth = context.measureText(text).width; | ||
| context.fillRect(x1, y1 > 20 ? y1 - 25 : y1, textWidth + 10, 25); | ||
|
|
||
| context.fillStyle = '#FFFFFF'; | ||
| context.fillText(text, x1 + 5, y1 > 20 ? y1 - 7 : y1 + 18); | ||
| } else { | ||
| context.fillStyle = 'rgba(169, 169, 169, 0.8)'; // DarkGray | ||
| const text = `${label} ${(confidence * 100).toFixed(0)}%`; | ||
| context.fillText(text, 20, 40); | ||
| } | ||
| }); | ||
| }; | ||
|
|
||
| const detectFrame = async () => { | ||
| if (!videoRef.current || !canvasRef.current || !isDetecting) return; | ||
|
|
||
| const video = videoRef.current; | ||
| if (video.readyState !== 4) return; | ||
|
|
||
| const canvas = canvasRef.current; | ||
| const context = canvas.getContext('2d'); | ||
|
|
||
| if (canvas.width !== video.videoWidth || canvas.height !== video.videoHeight) { | ||
| canvas.width = video.videoWidth; | ||
| canvas.height = video.videoHeight; | ||
| } | ||
|
|
||
| context.drawImage(video, 0, 0, canvas.width, canvas.height); | ||
|
|
||
| canvas.toBlob(async (blob) => { | ||
| if (!blob) return; | ||
|
|
||
| const formData = new FormData(); | ||
| formData.append('image', blob, 'frame.jpg'); | ||
|
|
||
| try { | ||
| const data = await detectorsApi.abandonedVehicle(formData); | ||
| if (data && data.detections) { | ||
| drawDetections(data.detections, context); | ||
| } | ||
| } catch (err) { | ||
| console.error("Detection error:", err); | ||
| } | ||
| }, 'image/jpeg', 0.8); | ||
| }; | ||
|
|
||
| return ( | ||
| <div className="mt-6 flex flex-col items-center w-full"> | ||
| <h2 className="text-xl font-semibold mb-4 text-center">Abandoned Vehicle Detector</h2> | ||
|
|
||
| {error && <div className="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded mb-4">{error}</div>} | ||
|
|
||
| <div className="relative w-full max-w-md bg-black rounded-lg overflow-hidden shadow-lg mb-6"> | ||
| <div className="relative"> | ||
| <video | ||
| ref={videoRef} | ||
| autoPlay | ||
| playsInline | ||
| muted | ||
| className="w-full h-auto block" | ||
| style={{ opacity: isDetecting ? 1 : 0.5 }} | ||
| /> | ||
| <canvas | ||
| ref={canvasRef} | ||
| className="absolute top-0 left-0 w-full h-full pointer-events-none" | ||
| /> | ||
| {!isDetecting && ( | ||
| <div className="absolute inset-0 flex items-center justify-center"> | ||
| <p className="text-white font-medium bg-black bg-opacity-50 px-4 py-2 rounded"> | ||
| Camera Paused | ||
| </p> | ||
| </div> | ||
| )} | ||
| </div> | ||
| </div> | ||
|
|
||
| <button | ||
| onClick={() => setIsDetecting(!isDetecting)} | ||
| className={`w-full max-w-md py-3 px-4 rounded-lg text-white font-medium shadow-md transition transform active:scale-95 ${isDetecting ? 'bg-red-600 hover:bg-red-700' : 'bg-blue-600 hover:bg-blue-700'}`} | ||
| > | ||
| {isDetecting ? 'Stop Detection' : 'Start Live Detection'} | ||
| </button> | ||
|
|
||
| <p className="text-sm text-gray-500 mt-2 text-center max-w-md"> | ||
| Identifies abandoned, rusted, or wrecked vehicles. | ||
| </p> | ||
|
|
||
| <button | ||
| onClick={onBack} | ||
| className="mt-6 text-gray-600 hover:text-gray-900 underline" | ||
| > | ||
| Back to Home | ||
| </button> | ||
| </div> | ||
| ); | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
This component is nearly identical to TrafficSignDetector.jsx — extract a shared LiveDetector component.
AbandonedVehicleDetector and TrafficSignDetector share ~95% of their code (camera management, detection loop, canvas overlay, UI layout). The only differences are the API endpoint, title, description text, and overlay colors. This is a textbook case for a reusable component parameterized by those differences.
♻️ Sketch of a shared component
// LiveDetector.jsx
const LiveDetector = ({ title, description, detectApi, overlayColor, onBack }) => {
// All the shared camera, detection, canvas, and UI logic here
// Use detectApi, overlayColor, title, description as parameters
};
// AbandonedVehicleDetector.jsx
const AbandonedVehicleDetector = ({ onBack }) => (
<LiveDetector
title="Abandoned Vehicle Detector"
description="Identifies abandoned, rusted, or wrecked vehicles."
detectApi={detectorsApi.abandonedVehicle}
overlayColor="#A9A9A9"
onBack={onBack}
/>
);🧰 Tools
🪛 Biome (2.3.13)
[error] 52-52: This callback passed to forEach() iterable method should not return a value.
Either remove this return or remove the returned value.
(lint/suspicious/useIterableCallbackReturn)
🤖 Prompt for AI Agents
In `@frontend/src/AbandonedVehicleDetector.jsx` around lines 1 - 172,
AbandonedVehicleDetector and TrafficSignDetector share camera, detection loop
and canvas overlay logic; extract a reusable LiveDetector component that
contains startCamera, stopCamera, detectFrame, drawDetections, videoRef and
canvasRef, and the useEffect hook, and parameterize it with props: title,
description, detectApi (e.g., detectorsApi.abandonedVehicle), overlayColor, and
onBack; then rewrite AbandonedVehicleDetector and TrafficSignDetector to be thin
wrappers that pass the specific detectApi, overlayColor and text into
LiveDetector, preserving behavior (blob upload, FormData, canvas sizing and
drawing) and ensuring hook dependencies and error handling remain intact.
| useEffect(() => { | ||
| let interval; | ||
| if (isDetecting) { | ||
| startCamera(); | ||
| interval = setInterval(detectFrame, 2000); // Check every 2 seconds | ||
| } else { | ||
| stopCamera(); | ||
| if (interval) clearInterval(interval); | ||
| if (canvasRef.current) { | ||
| const ctx = canvasRef.current.getContext('2d'); | ||
| ctx.clearRect(0, 0, canvasRef.current.width, canvasRef.current.height); | ||
| } | ||
| } | ||
| return () => { | ||
| stopCamera(); | ||
| if (interval) clearInterval(interval); | ||
| }; | ||
| // eslint-disable-next-line react-hooks/exhaustive-deps | ||
| }, [isDetecting]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dead clearInterval in the else branch and stale closure on isDetecting.
On Line 17, interval is always undefined in the else branch because it's only assigned inside if (isDetecting). This clearInterval call is dead code — the cleanup happens correctly in the return function (Line 25).
Additionally, detectFrame (Line 91) checks !isDetecting, but it's captured in a closure where isDetecting was true at the time the interval was created, so this guard never triggers. Consider using a ref to track detection state if you need a reliable guard.
💡 Suggested approach using a ref
+ const isDetectingRef = useRef(false);
+
useEffect(() => {
let interval;
if (isDetecting) {
+ isDetectingRef.current = true;
startCamera();
interval = setInterval(detectFrame, 2000);
} else {
+ isDetectingRef.current = false;
stopCamera();
- if (interval) clearInterval(interval);
if (canvasRef.current) {
const ctx = canvasRef.current.getContext('2d');
ctx.clearRect(0, 0, canvasRef.current.width, canvasRef.current.height);
}
}Then in detectFrame:
- if (!videoRef.current || !canvasRef.current || !isDetecting) return;
+ if (!videoRef.current || !canvasRef.current || !isDetectingRef.current) return;🤖 Prompt for AI Agents
In `@frontend/src/AbandonedVehicleDetector.jsx` around lines 10 - 28, The else
branch in the useEffect contains a dead clearInterval and the detectFrame
closure captures a stale isDetecting; change to store the interval id and
detection state in refs (e.g., detectionIntervalRef and isDetectingRef), update
useEffect to set isDetectingRef.current when isDetecting changes, assign the
interval id to detectionIntervalRef.current inside the if (isDetecting) block
and clear it only from the cleanup using
clearInterval(detectionIntervalRef.current), remove the redundant clearInterval
in the else branch, and modify detectFrame to read isDetectingRef.current
instead of the captured isDetecting; keep existing startCamera/stopCamera and
canvasRef clear logic but rely on the cleanup function to clear the interval.
| detections.forEach(det => { | ||
| const { label, confidence, box } = det; | ||
|
|
||
| // For Abandoned Vehicle (likely zero-shot, no box) | ||
| // But if we had box... | ||
| if (box && box.length === 4) { | ||
| const [x1, y1, x2, y2] = box; | ||
| context.strokeStyle = '#A9A9A9'; // DarkGray | ||
| context.strokeRect(x1, y1, x2 - x1, y2 - y1); | ||
|
|
||
| context.fillStyle = 'rgba(0,0,0,0.5)'; | ||
| const text = `${label} ${(confidence * 100).toFixed(0)}%`; | ||
| const textWidth = context.measureText(text).width; | ||
| context.fillRect(x1, y1 > 20 ? y1 - 25 : y1, textWidth + 10, 25); | ||
|
|
||
| context.fillStyle = '#FFFFFF'; | ||
| context.fillText(text, x1 + 5, y1 > 20 ? y1 - 7 : y1 + 18); | ||
| } else { | ||
| context.fillStyle = 'rgba(169, 169, 169, 0.8)'; // DarkGray | ||
| const text = `${label} ${(confidence * 100).toFixed(0)}%`; | ||
| context.fillText(text, 20, 40); | ||
| } | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Multiple no-box detections render at the same fixed position, overlapping each other.
In the else branch (Line 85), all detections without a bounding box are drawn at coordinates (20, 40), stacking on top of each other. Offset each label vertically using the loop index.
🐛 Fix overlapping labels
- detections.forEach(det => {
+ detections.forEach((det, index) => {
const { label, confidence, box } = det;
// ...
} else {
context.fillStyle = 'rgba(169, 169, 169, 0.8)';
const text = `${label} ${(confidence * 100).toFixed(0)}%`;
- context.fillText(text, 20, 40);
+ context.fillText(text, 20, 40 + index * 28);
}
});📝 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.
| detections.forEach(det => { | |
| const { label, confidence, box } = det; | |
| // For Abandoned Vehicle (likely zero-shot, no box) | |
| // But if we had box... | |
| if (box && box.length === 4) { | |
| const [x1, y1, x2, y2] = box; | |
| context.strokeStyle = '#A9A9A9'; // DarkGray | |
| context.strokeRect(x1, y1, x2 - x1, y2 - y1); | |
| context.fillStyle = 'rgba(0,0,0,0.5)'; | |
| const text = `${label} ${(confidence * 100).toFixed(0)}%`; | |
| const textWidth = context.measureText(text).width; | |
| context.fillRect(x1, y1 > 20 ? y1 - 25 : y1, textWidth + 10, 25); | |
| context.fillStyle = '#FFFFFF'; | |
| context.fillText(text, x1 + 5, y1 > 20 ? y1 - 7 : y1 + 18); | |
| } else { | |
| context.fillStyle = 'rgba(169, 169, 169, 0.8)'; // DarkGray | |
| const text = `${label} ${(confidence * 100).toFixed(0)}%`; | |
| context.fillText(text, 20, 40); | |
| } | |
| }); | |
| detections.forEach((det, index) => { | |
| const { label, confidence, box } = det; | |
| // For Abandoned Vehicle (likely zero-shot, no box) | |
| // But if we had box... | |
| if (box && box.length === 4) { | |
| const [x1, y1, x2, y2] = box; | |
| context.strokeStyle = '#A9A9A9'; // DarkGray | |
| context.strokeRect(x1, y1, x2 - x1, y2 - y1); | |
| context.fillStyle = 'rgba(0,0,0,0.5)'; | |
| const text = `${label} ${(confidence * 100).toFixed(0)}%`; | |
| const textWidth = context.measureText(text).width; | |
| context.fillRect(x1, y1 > 20 ? y1 - 25 : y1, textWidth + 10, 25); | |
| context.fillStyle = '#FFFFFF'; | |
| context.fillText(text, x1 + 5, y1 > 20 ? y1 - 7 : y1 + 18); | |
| } else { | |
| context.fillStyle = 'rgba(169, 169, 169, 0.8)'; // DarkGray | |
| const text = `${label} ${(confidence * 100).toFixed(0)}%`; | |
| context.fillText(text, 20, 40 + index * 28); | |
| } | |
| }); |
🤖 Prompt for AI Agents
In `@frontend/src/AbandonedVehicleDetector.jsx` around lines 65 - 87, The else
branch inside detections.forEach currently draws all no-box labels at fixed
coordinates (20,40), causing overlap; modify the loop to accept the index (e.g.,
detections.forEach((det, i) => { ... })) and compute a vertical offset for each
label (for example labelY = 40 + i * <spacing>) and use that y coordinate
instead of the hardcoded 40 so each no-box detection (rendered in the else
branch) is drawn on its own line; ensure you update the fillText/fillRect
positions accordingly and keep spacing consistent with text height.
| const detectFrame = async () => { | ||
| if (!videoRef.current || !canvasRef.current || !isDetecting) return; | ||
|
|
||
| const video = videoRef.current; | ||
| if (video.readyState !== 4) return; | ||
|
|
||
| const canvas = canvasRef.current; | ||
| const context = canvas.getContext('2d'); | ||
|
|
||
| if (canvas.width !== video.videoWidth || canvas.height !== video.videoHeight) { | ||
| canvas.width = video.videoWidth; | ||
| canvas.height = video.videoHeight; | ||
| } | ||
|
|
||
| context.drawImage(video, 0, 0, canvas.width, canvas.height); | ||
|
|
||
| canvas.toBlob(async (blob) => { | ||
| if (!blob) return; | ||
|
|
||
| const formData = new FormData(); | ||
| formData.append('image', blob, 'frame.jpg'); | ||
|
|
||
| try { | ||
| const data = await detectorsApi.abandonedVehicle(formData); | ||
| if (data && data.detections) { | ||
| drawDetections(data.detections, context); | ||
| } | ||
| } catch (err) { | ||
| console.error("Detection error:", err); | ||
| } | ||
| }, 'image/jpeg', 0.8); | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Drawing video frame onto the overlay canvas causes visual doubling and concurrent request pileup.
Two issues in detectFrame:
-
Visual doubling (Line 104):
context.drawImage(video, ...)paints the video frame ontocanvasRef, which is the transparent overlay canvas positioned on top of the<video>element. This produces a doubled image. The video frame should be drawn to a separate offscreen canvas for blob capture, keepingcanvasRefexclusively for detection annotations. -
No in-flight guard: If the API takes >2s,
setIntervalfires again and queues another request. Multiple overlapping calls can cause flickering detections and unnecessary load. Track whether a request is in-flight and skip if so.
🐛 Proposed fix — use offscreen canvas + in-flight guard
const detectFrame = async () => {
- if (!videoRef.current || !canvasRef.current || !isDetecting) return;
+ if (!videoRef.current || !canvasRef.current) return;
const video = videoRef.current;
if (video.readyState !== 4) return;
- const canvas = canvasRef.current;
- const context = canvas.getContext('2d');
+ const overlayCanvas = canvasRef.current;
+ const overlayCtx = overlayCanvas.getContext('2d');
- if (canvas.width !== video.videoWidth || canvas.height !== video.videoHeight) {
- canvas.width = video.videoWidth;
- canvas.height = video.videoHeight;
+ if (overlayCanvas.width !== video.videoWidth || overlayCanvas.height !== video.videoHeight) {
+ overlayCanvas.width = video.videoWidth;
+ overlayCanvas.height = video.videoHeight;
}
- context.drawImage(video, 0, 0, canvas.width, canvas.height);
-
- canvas.toBlob(async (blob) => {
+ // Use an offscreen canvas for frame capture
+ const offscreen = document.createElement('canvas');
+ offscreen.width = video.videoWidth;
+ offscreen.height = video.videoHeight;
+ offscreen.getContext('2d').drawImage(video, 0, 0, offscreen.width, offscreen.height);
+
+ offscreen.toBlob(async (blob) => {
if (!blob) return;
const formData = new FormData();
formData.append('image', blob, 'frame.jpg');
try {
const data = await detectorsApi.abandonedVehicle(formData);
if (data && data.detections) {
- drawDetections(data.detections, context);
+ drawDetections(data.detections, overlayCtx);
}
} catch (err) {
console.error("Detection error:", err);
}
}, 'image/jpeg', 0.8);
};🤖 Prompt for AI Agents
In `@frontend/src/AbandonedVehicleDetector.jsx` around lines 90 - 121, detectFrame
currently draws the video into the overlay canvasRef (causing doubled visuals)
and allows overlapping requests; change it to draw the video into a separate
offscreen canvas (create a local offscreenCanvas sized to
video.videoWidth/video.videoHeight and use its 2D context to call toBlob) so
canvasRef is used only for annotations via drawDetections, and add an in-flight
guard (e.g., a boolean or ref like inFlightRef/isRequestInFlight checked at the
start of detectFrame and set true before awaiting
detectorsApi.abandonedVehicle(formData) and false in finally) to skip starting a
new API call while one is pending; ensure you still resize offscreenCanvas to
the video dimensions and pass the blob from the offscreen canvas to
detectorsApi.abandonedVehicle, and only drawDetections onto canvasRef's context.
| <Route path="/waste" element={<WasteDetector onBack={() => navigate('/')} />} /> | ||
| <Route path="/water-leak" element={<WaterLeakDetector onBack={() => navigate('/')} />} /> | ||
| <Route path="/crowd" element={<CrowdDetector onBack={() => navigate('/')} />} /> | ||
| <Route path="/accessibility" element={<AccessibilityDetector onBack={() => navigate('/')} />} /> | ||
| <Route path="/traffic-sign" element={<TrafficSignDetector onBack={() => navigate('/')} />} /> | ||
| <Route path="/abandoned-vehicle" element={<AbandonedVehicleDetector onBack={() => navigate('/')} />} /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
onBack navigates to / (Landing) instead of /home — broken "Back" button on all new detectors.
The Home route was moved to /home (Line 203), but onBack callbacks here still use navigate('/'), which resolves to the Landing page. Users pressing "Back" from any detector will land on the Landing page instead of Home.
Note: this same issue exists on Lines 259–296 for the pre-existing detectors, but at minimum the newly added routes should be correct.
🐛 Proposed fix for new routes
- <Route path="/waste" element={<WasteDetector onBack={() => navigate('/')} />} />
- <Route path="/water-leak" element={<WaterLeakDetector onBack={() => navigate('/')} />} />
- <Route path="/crowd" element={<CrowdDetector onBack={() => navigate('/')} />} />
- <Route path="/accessibility" element={<AccessibilityDetector onBack={() => navigate('/')} />} />
- <Route path="/traffic-sign" element={<TrafficSignDetector onBack={() => navigate('/')} />} />
- <Route path="/abandoned-vehicle" element={<AbandonedVehicleDetector onBack={() => navigate('/')} />} />
+ <Route path="/waste" element={<WasteDetector onBack={() => navigate('/home')} />} />
+ <Route path="/water-leak" element={<WaterLeakDetector onBack={() => navigate('/home')} />} />
+ <Route path="/crowd" element={<CrowdDetector onBack={() => navigate('/home')} />} />
+ <Route path="/accessibility" element={<AccessibilityDetector onBack={() => navigate('/home')} />} />
+ <Route path="/traffic-sign" element={<TrafficSignDetector onBack={() => navigate('/home')} />} />
+ <Route path="/abandoned-vehicle" element={<AbandonedVehicleDetector onBack={() => navigate('/home')} />} />Consider also fixing Lines 259–296 for the existing detectors in the same pass.
📝 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.
| <Route path="/waste" element={<WasteDetector onBack={() => navigate('/')} />} /> | |
| <Route path="/water-leak" element={<WaterLeakDetector onBack={() => navigate('/')} />} /> | |
| <Route path="/crowd" element={<CrowdDetector onBack={() => navigate('/')} />} /> | |
| <Route path="/accessibility" element={<AccessibilityDetector onBack={() => navigate('/')} />} /> | |
| <Route path="/traffic-sign" element={<TrafficSignDetector onBack={() => navigate('/')} />} /> | |
| <Route path="/abandoned-vehicle" element={<AbandonedVehicleDetector onBack={() => navigate('/')} />} /> | |
| <Route path="/waste" element={<WasteDetector onBack={() => navigate('/home')} />} /> | |
| <Route path="/water-leak" element={<WaterLeakDetector onBack={() => navigate('/home')} />} /> | |
| <Route path="/crowd" element={<CrowdDetector onBack={() => navigate('/home')} />} /> | |
| <Route path="/accessibility" element={<AccessibilityDetector onBack={() => navigate('/home')} />} /> | |
| <Route path="/traffic-sign" element={<TrafficSignDetector onBack={() => navigate('/home')} />} /> | |
| <Route path="/abandoned-vehicle" element={<AbandonedVehicleDetector onBack={() => navigate('/home')} />} /> |
🤖 Prompt for AI Agents
In `@frontend/src/App.jsx` around lines 297 - 302, The onBack handlers for the
detector routes in App.jsx currently call navigate('/') which sends users to the
Landing page; update each detector route's onBack prop (e.g., WasteDetector,
WaterLeakDetector, CrowdDetector, AccessibilityDetector, TrafficSignDetector,
AbandonedVehicleDetector and also the earlier detectors at lines ~259–296) to
call navigate('/home') instead so the Back button returns to the Home route;
locate the Route elements that pass onBack={() => navigate('/')} and replace the
path string with '/home'.
| const AppHeader = () => { | ||
| const { t } = useTranslation(); | ||
| return ( | ||
| <header className="bg-white shadow-sm p-4 sticky top-0 z-50 flex justify-between items-center backdrop-blur-md bg-white/80"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Conflicting Tailwind background classes: bg-white and bg-white/80.
Both are applied to the same element. bg-white sets full opacity background, which undermines the bg-white/80 + backdrop-blur-md glassmorphism effect you likely intend. Remove bg-white to let the translucent background work with the blur.
🐛 Fix
- <header className="bg-white shadow-sm p-4 sticky top-0 z-50 flex justify-between items-center backdrop-blur-md bg-white/80">
+ <header className="shadow-sm p-4 sticky top-0 z-50 flex justify-between items-center backdrop-blur-md bg-white/80">📝 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.
| <header className="bg-white shadow-sm p-4 sticky top-0 z-50 flex justify-between items-center backdrop-blur-md bg-white/80"> | |
| <header className="shadow-sm p-4 sticky top-0 z-50 flex justify-between items-center backdrop-blur-md bg-white/80"> |
🤖 Prompt for AI Agents
In `@frontend/src/components/AppHeader.jsx` at line 7, The header element in the
AppHeader component currently has conflicting Tailwind classes ("bg-white" and
"bg-white/80"); remove the solid "bg-white" class from the header's className so
the translucent "bg-white/80" and "backdrop-blur-md" glassmorphism effect can
take effect (i.e., update the header JSX in AppHeader.jsx to drop "bg-white"
while keeping "bg-white/80" and the blur/positioning classes).
| const FloatingButtonsManager = ({ setView }) => { | ||
| return ( | ||
| <> | ||
| <ChatWidget /> | ||
| </> | ||
| ); | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Search for all usages of FloatingButtonsManager
rg "FloatingButtonsManager" --type=js --type=jsx -C 3Repository: RohanExploit/VishwaGuru
Length of output: 94
🏁 Script executed:
#!/bin/bash
# Find the file and check its current contents
fd "FloatingButtonsManager" --type fRepository: RohanExploit/VishwaGuru
Length of output: 117
🏁 Script executed:
#!/bin/bash
# Also search for any references to setView being passed to FloatingButtonsManager
rg "FloatingButtonsManager.*setView|setView.*FloatingButtonsManager" --type=js --type=jsxRepository: RohanExploit/VishwaGuru
Length of output: 94
🏁 Script executed:
#!/bin/bash
# Read the actual file contents
cat -n frontend/src/components/FloatingButtonsManager.jsxRepository: RohanExploit/VishwaGuru
Length of output: 362
🏁 Script executed:
#!/bin/bash
# Search for FloatingButtonsManager usages with pattern matching
rg "FloatingButtonsManager" -C 3Repository: RohanExploit/VishwaGuru
Length of output: 1765
🏁 Script executed:
#!/bin/bash
# Search for setView being passed
rg "setView\s*=" -C 2Repository: RohanExploit/VishwaGuru
Length of output: 4201
🏁 Script executed:
#!/bin/bash
# Check ChatWidget to see if it accepts setView prop
cat -n frontend/src/components/ChatWidget.jsxRepository: RohanExploit/VishwaGuru
Length of output: 6324
🏁 Script executed:
#!/bin/bash
# Also check if ChatWidget is used elsewhere and whether it uses setView
rg "ChatWidget" -C 2Repository: RohanExploit/VishwaGuru
Length of output: 26729
setView prop is accepted but never used.
The component destructures setView from props but doesn't use it or pass it to ChatWidget. This indicates incomplete integration. If it's not needed yet, remove it to avoid confusion. Additionally, the fragment wrapper is unnecessary with a single child.
♻️ Suggested refactor
-const FloatingButtonsManager = ({ setView }) => {
+const FloatingButtonsManager = () => {
return (
- <>
- <ChatWidget />
- </>
+ <ChatWidget />
);
};📝 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.
| const FloatingButtonsManager = ({ setView }) => { | |
| return ( | |
| <> | |
| <ChatWidget /> | |
| </> | |
| ); | |
| }; | |
| const FloatingButtonsManager = () => { | |
| return ( | |
| <ChatWidget /> | |
| ); | |
| }; |
🤖 Prompt for AI Agents
In `@frontend/src/components/FloatingButtonsManager.jsx` around lines 4 - 10,
FloatingButtonsManager currently destructures the unused prop setView and wraps
a single child in an unnecessary fragment; either remove setView from the
parameter list and return the single child directly (replace the fragment with
just <ChatWidget />) or, if setView is intended to be used, pass it through to
ChatWidget (e.g., <ChatWidget setView={setView} />) and implement handling in
ChatWidget; update the FloatingButtonsManager declaration (function params) and
its returned JSX accordingly.
| def test_home_page(): | ||
| with sync_playwright() as p: | ||
| browser = p.chromium.launch() | ||
| page = browser.new_page() | ||
|
|
||
| # Listen for console messages | ||
| page.on("console", lambda msg: print(f"Console: {msg.text}")) | ||
| page.on("pageerror", lambda err: print(f"Page Error: {err}")) | ||
|
|
||
| try: | ||
| page.goto("http://localhost:5173") | ||
| page.wait_for_timeout(5000) | ||
| page.screenshot(path="verification_home.png") | ||
| print("Home screenshot taken") | ||
| except Exception as e: | ||
| print(f"Error: {e}") | ||
| finally: | ||
| browser.close() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Verification script has no assertions — it will never fail.
test_home_page() captures a screenshot and prints console messages but never asserts anything. If a test runner picks this up (the test_ prefix is pytest-discoverable), it will always pass regardless of page state. Consider adding at least a basic assertion (e.g., checking the page title or that the page loaded without errors).
Also, the hardcoded http://localhost:5173 URL makes this non-portable across environments. Consider using an environment variable.
💡 Suggested improvements
+import os
from playwright.sync_api import sync_playwright
def test_home_page():
+ base_url = os.environ.get("TEST_BASE_URL", "http://localhost:5173")
with sync_playwright() as p:
browser = p.chromium.launch()
page = browser.new_page()
+ errors = []
# Listen for console messages
page.on("console", lambda msg: print(f"Console: {msg.text}"))
- page.on("pageerror", lambda err: print(f"Page Error: {err}"))
+ page.on("pageerror", lambda err: errors.append(str(err)))
try:
- page.goto("http://localhost:5173")
- page.wait_for_timeout(5000)
+ page.goto(base_url)
+ page.wait_for_load_state("networkidle")
page.screenshot(path="verification_home.png")
print("Home screenshot taken")
+ assert len(errors) == 0, f"Page errors encountered: {errors}"
except Exception as e:
print(f"Error: {e}")
+ raise
finally:
browser.close()🧰 Tools
🪛 Ruff (0.14.14)
[warning] 17-17: Do not catch blind exception: Exception
(BLE001)
🤖 Prompt for AI Agents
In `@verification/check_home.py` around lines 3 - 20, test_home_page currently
only screenshots and prints but never fails; change it to read the base URL from
an environment variable (e.g., os.environ.get("BASE_URL",
"http://localhost:5173")) instead of the hardcoded string and add assertions so
the test can fail: assert the page loaded successfully after page.goto (e.g.,
check response status or wait_for_load_state and assert page.title() contains
expected text) and fail if any console "error" or pageerror events occurred
(collect console/pageerror messages in a list and assert it is empty). Update
references in the function test_home_page (page.goto, page.on handlers, and the
final assertion logic) so the test runner will correctly surface failures.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@netlify.toml`:
- Around line 12-16: Netlify config removed security response headers; restore a
headers block in netlify.toml (near the existing [[redirects]] section) that
sets X-Frame-Options, X-Content-Type-Options, Referrer-Policy,
Content-Security-Policy (or a reasonable default), and Strict-Transport-Security
for the site; add the headers under a [[headers]] or [[headers]] for "/*"
(matching the redirect glob) and ensure values are appropriate for your app's
auth/API flows and CSP does not break legitimate resource loading.
| # Redirects for SPA | ||
| [[redirects]] | ||
| from = "/*" | ||
| to = "/index.html" | ||
| status = 200 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Security headers were removed — consider restoring them.
The previous configuration included security headers (e.g., X-Frame-Options, X-Content-Type-Options, Content-Security-Policy, etc.) which have been entirely dropped. For an application with authentication and API integrations, these headers are important for defense-in-depth against clickjacking, MIME-sniffing, and XSS.
If the old headers were causing deployment issues, consider adding back at minimum:
🛡️ Suggested headers block
# Redirects for SPA
[[redirects]]
from = "/*"
to = "/index.html"
status = 200
+
+[[headers]]
+ for = "/*"
+ [headers.values]
+ X-Frame-Options = "DENY"
+ X-Content-Type-Options = "nosniff"
+ Referrer-Policy = "strict-origin-when-cross-origin"
+ Permissions-Policy = "camera=(), microphone=(), geolocation=()"📝 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.
| # Redirects for SPA | |
| [[redirects]] | |
| from = "/*" | |
| to = "/index.html" | |
| status = 200 | |
| # Redirects for SPA | |
| [[redirects]] | |
| from = "/*" | |
| to = "/index.html" | |
| status = 200 | |
| [[headers]] | |
| for = "/*" | |
| [headers.values] | |
| X-Frame-Options = "DENY" | |
| X-Content-Type-Options = "nosniff" | |
| Referrer-Policy = "strict-origin-when-cross-origin" | |
| Permissions-Policy = "camera=(), microphone=(), geolocation=()" |
🤖 Prompt for AI Agents
In `@netlify.toml` around lines 12 - 16, Netlify config removed security response
headers; restore a headers block in netlify.toml (near the existing
[[redirects]] section) that sets X-Frame-Options, X-Content-Type-Options,
Referrer-Policy, Content-Security-Policy (or a reasonable default), and
Strict-Transport-Security for the site; add the headers under a [[headers]] or
[[headers]] for "/*" (matching the redirect glob) and ensure values are
appropriate for your app's auth/API flows and CSP does not break legitimate
resource loading.
- Removed `base = "."` to prevent path resolution conflicts. - Updated build command to explicitly remove `frontend/package-lock.json` before install to ensure clean dependency resolution. - Kept `publish = "frontend/dist"` as the output directory. - This configuration aligns with previously successful patterns documented in memory. Co-authored-by: RohanExploit <178623867+RohanExploit@users.noreply.github.com>
🔍 Quality Reminder |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
1 issue found across 1 file (changes from recent commits).
Prompt for AI agents (all issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="netlify.toml">
<violation number="1" location="netlify.toml:6">
P2: Removing package-lock.json during builds makes dependency resolution non-deterministic and can cause unexpected version changes across deploys. Keep the lockfile to ensure reproducible Netlify builds.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
- Set `base = "frontend"` to ensure build context is correct. - Updated `publish = "dist"` to be relative to the base directory. - Simplified `command` to `npm install && npm run build` as it now runs inside `frontend`. - This resolves path resolution issues in the monorepo structure. Co-authored-by: RohanExploit <178623867+RohanExploit@users.noreply.github.com>
Added 5 new Hugging Face powered detectors: Traffic Sign, Abandoned Vehicle, Water Leak, Crowd Density, Accessibility. Updated UI with modern "Quick Actions" grid and verified deployment configuration for Netlify/Render. Optimized for resource efficiency using API-based detection.
PR created automatically by Jules for task 14048211725915844699 started by @RohanExploit
Summary by cubic
Added five new detectors and refreshed the Home with Quick Actions and live camera overlays. Switched the default route to /home, added a Home screenshot check, and fixed Netlify builds by setting base=frontend with publish=dist.
New Features
Migration
Written for commit 1e93d3d. Summary will update on new commits.
Summary by CodeRabbit
New Features
Chores
Tests