-
Notifications
You must be signed in to change notification settings - Fork 35
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?
Changes from all commits
f32a6e8
f165c9f
bdcf4cd
1e93d3d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,3 +16,5 @@ firebase-admin | |
| a2wsgi | ||
| scikit-learn | ||
| numpy | ||
| passlib[bcrypt] | ||
| python-jose[cryptography] | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,174 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 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 (interval) clearInterval(interval); |
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.
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.
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>
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.
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.
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -34,6 +34,12 @@ const SmartScanner = React.lazy(() => import('./SmartScanner')); | |||||||||||||||||||||||||
| const GrievanceAnalysis = React.lazy(() => import('./views/GrievanceAnalysis')); | ||||||||||||||||||||||||||
| const NoiseDetector = React.lazy(() => import('./NoiseDetector')); | ||||||||||||||||||||||||||
| const CivicEyeDetector = React.lazy(() => import('./CivicEyeDetector')); | ||||||||||||||||||||||||||
| const WasteDetector = React.lazy(() => import('./WasteDetector')); | ||||||||||||||||||||||||||
| const WaterLeakDetector = React.lazy(() => import('./WaterLeakDetector')); | ||||||||||||||||||||||||||
| const CrowdDetector = React.lazy(() => import('./CrowdDetector')); | ||||||||||||||||||||||||||
| const AccessibilityDetector = React.lazy(() => import('./AccessibilityDetector')); | ||||||||||||||||||||||||||
| const TrafficSignDetector = React.lazy(() => import('./TrafficSignDetector')); | ||||||||||||||||||||||||||
| const AbandonedVehicleDetector = React.lazy(() => import('./AbandonedVehicleDetector')); | ||||||||||||||||||||||||||
| const MyReportsView = React.lazy(() => import('./views/MyReportsView')); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
|
|
@@ -42,6 +48,9 @@ import { AuthProvider } from './contexts/AuthContext'; | |||||||||||||||||||||||||
| import Login from './views/Login'; | ||||||||||||||||||||||||||
| import ProtectedRoute from './components/ProtectedRoute'; | ||||||||||||||||||||||||||
| import AdminDashboard from './views/AdminDashboard'; | ||||||||||||||||||||||||||
| import AppHeader from './components/AppHeader'; | ||||||||||||||||||||||||||
| import FloatingButtonsManager from './components/FloatingButtonsManager'; | ||||||||||||||||||||||||||
| import LoadingSpinner from './components/LoadingSpinner'; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| // Create a wrapper component to handle state management | ||||||||||||||||||||||||||
| function AppContent() { | ||||||||||||||||||||||||||
|
|
@@ -59,12 +68,12 @@ function AppContent() { | |||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| // Safe navigation helper | ||||||||||||||||||||||||||
| const navigateToView = useCallback((view) => { | ||||||||||||||||||||||||||
| const validViews = ['home', 'map', 'report', 'action', 'mh-rep', 'pothole', 'garbage', 'vandalism', 'flood', 'infrastructure', 'parking', 'streetlight', 'fire', 'animal', 'blocked', 'tree', 'pest', 'smart-scan', 'grievance-analysis', 'noise', 'safety-check', 'my-reports', 'login', 'signup']; | ||||||||||||||||||||||||||
| const validViews = ['home', 'map', 'report', 'action', 'mh-rep', 'pothole', 'garbage', 'vandalism', 'flood', 'infrastructure', 'parking', 'streetlight', 'fire', 'animal', 'blocked', 'tree', 'pest', 'smart-scan', 'grievance-analysis', 'noise', 'safety-check', 'my-reports', 'waste', 'water-leak', 'crowd', 'accessibility', 'traffic-sign', 'abandoned-vehicle', 'login', 'signup']; | ||||||||||||||||||||||||||
| if (validViews.includes(view)) { | ||||||||||||||||||||||||||
| navigate(view === 'home' ? '/' : `/${view}`); | ||||||||||||||||||||||||||
| navigate(view === 'home' ? '/home' : `/${view}`); | ||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||
| console.warn(`Attempted to navigate to invalid view: ${view}`); | ||||||||||||||||||||||||||
| navigate('/'); | ||||||||||||||||||||||||||
| navigate('/home'); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| }, [navigate]); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
|
|
@@ -191,7 +200,7 @@ function AppContent() { | |||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| <Route | ||||||||||||||||||||||||||
| path="/" | ||||||||||||||||||||||||||
| path="/home" | ||||||||||||||||||||||||||
| element={ | ||||||||||||||||||||||||||
| <Home | ||||||||||||||||||||||||||
| setView={navigateToView} | ||||||||||||||||||||||||||
|
|
@@ -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('/')} />} /> | ||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
||||||||||||||||||||||||||
| <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('/')} />} /> | ||||||||||||||||||||||||||
|
Comment on lines
+297
to
+302
|
||||||||||||||||||||||||||
| <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'.
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)
Security advisories / known issues relevant to 2025
Practical 2025 concern (compatibility, not a CVE)
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)
(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
cryptography
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:
Repository: RohanExploit/VishwaGuru
Length of output: 1049
Pin crypto dependencies to secure, compatible versions; critical CVE exposure without pinning.
Unpinned
passlib[bcrypt]andpython-jose[cryptography]expose the project to critical vulnerabilities and compatibility breaks:passlib>=1.7.4withbcrypt<5.0.0(e.g., bcrypt==4.0.1).python-jose>=3.4.0(currently 3.5.0).>=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