chore: update eslint and prettier configuration

This commit is contained in:
2026-06-17 16:23:28 +05:30
parent b54242cf7e
commit 4c2241ff72
140 changed files with 2270 additions and 1287 deletions

View File

@@ -1,21 +1,44 @@
'use client';
import { useMemo, useState, useCallback, useRef, useReducer, useEffect } from 'react';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import {
useMemo,
useState,
useCallback,
useRef,
useReducer,
useEffect,
} from 'react';
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from '@/components/ui/card';
import { Film } from 'lucide-react';
import { DetectionData, DetectionType, DetectionCounts, DetectionLogEntry } from '@/types';
import {
DetectionData,
DetectionType,
DetectionCounts,
DetectionLogEntry,
} from '@/types';
import { useGpsMap } from '@/hooks/use-gps-map';
import { useFrameDetectionMap } from '@/hooks/use-frame-detection-map';
import { useCumulativeCounts } from '@/hooks/use-cumulative-counts';
import { useVideoDetectionLoop } from '@/hooks/use-video-detection-loop';
import VideoCanvasPlayer, { VideoCanvasPlayerRef } from './video/video-canvas-player';
import VideoCanvasPlayer, {
VideoCanvasPlayerRef,
} from './video/video-canvas-player';
import DetectionStatsBar from './video/detection-stats-bar';
import DetectionLogs from './video/detection-logs';
import SummarySection from './video/summary-section';
import DetailedSummarySection from './video/detailed-summary-section';
import { getDetectionModeConfig, getEnabledDetectionTypes } from '@/constants/detectionModeConfig';
import {
getDetectionModeConfig,
getEnabledDetectionTypes,
} from '@/constants/detectionModeConfig';
type VideoPlayerSectionProps = {
data: DetectionData;
@@ -27,13 +50,20 @@ type VideoPlayerSectionProps = {
const MAX_LOGS = 50;
type LogAction = { type: 'ADD_LOG'; payload: DetectionLogEntry } | { type: 'CLEAR' };
type LogAction =
| { type: 'ADD_LOG'; payload: DetectionLogEntry }
| { type: 'CLEAR' };
function logsReducer(state: DetectionLogEntry[], action: LogAction): DetectionLogEntry[] {
function logsReducer(
state: DetectionLogEntry[],
action: LogAction,
): DetectionLogEntry[] {
switch (action.type) {
case 'ADD_LOG':
// Move to top if already exists, or just add to top
const filtered = state.filter((log) => log.frame !== action.payload.frame);
const filtered = state.filter(
(log) => log.frame !== action.payload.frame,
);
return [action.payload, ...filtered].slice(0, MAX_LOGS);
case 'CLEAR':
return [];
@@ -81,7 +111,8 @@ export default function VideoPlayerSection({
return counts as DetectionCounts;
}, [enabledTypes]);
const [currentFrameCounts, setCurrentFrameCounts] = useState<DetectionCounts>(initialCounts);
const [currentFrameCounts, setCurrentFrameCounts] =
useState<DetectionCounts>(initialCounts);
// Logs Reducer
const [logs, dispatchLogs] = useReducer(logsReducer, []);
@@ -95,10 +126,10 @@ export default function VideoPlayerSection({
// Synthesize frames from lists if not present (specifically for gemini_video)
// Other models like YOLO return data.frames directly
const framesMap = new Map<number, any>();
// Sort all detections by their first_detected_frame
const allDetections: any[] = [];
enabledTypes.forEach(type => {
enabledTypes.forEach((type) => {
const list = (data as any)[type.listKey];
if (list && Array.isArray(list)) {
list.forEach((item: any) => {
@@ -107,50 +138,57 @@ export default function VideoPlayerSection({
}
});
allDetections.sort((a, b) => (a.first_detected_frame || 0) - (b.first_detected_frame || 0));
allDetections.sort(
(a, b) => (a.first_detected_frame || 0) - (b.first_detected_frame || 0),
);
// Current counts for sticky stats
const currentCounts: Record<string, number> = {};
enabledTypes.forEach(t => { currentCounts[t.frameCountKey] = 0; });
enabledTypes.forEach((t) => {
currentCounts[t.frameCountKey] = 0;
});
allDetections.forEach(det => {
allDetections.forEach((det) => {
const frameId = det.first_detected_frame || det.frame_number || 0;
// Spread detection across multiple frames so it stays visible (persistence)
// Gemini detections are sparse, so showing them for ~1 second (30 frames) helps
const persistenceFrames = 30;
const persistenceFrames = 30;
for (let i = 0; i < persistenceFrames; i++) {
const targetFrame = frameId + i;
if (!framesMap.has(targetFrame)) {
framesMap.set(targetFrame, { frame_id: targetFrame, detections: [] });
}
const frameData = framesMap.get(targetFrame);
// Update cumulative counts only on the first detected frame
if (i === 0) {
const typeConfig = enabledTypes.find(t => t.id === det._detType);
const typeConfig = enabledTypes.find((t) => t.id === det._detType);
if (typeConfig) {
currentCounts[typeConfig.frameCountKey] = (currentCounts[typeConfig.frameCountKey] || 0) + 1;
currentCounts[typeConfig.frameCountKey] =
(currentCounts[typeConfig.frameCountKey] || 0) + 1;
}
}
const countCopy = { ...currentCounts };
frameData.detections.push({
...det,
type: det.type || det._detType,
detection_id: det.detection_id || det.id,
count: countCopy
count: countCopy,
});
}
});
return {
...data,
frames: Array.from(framesMap.values()).sort((a, b) => (a.frame_id || 0) - (b.frame_id || 0))
frames: Array.from(framesMap.values()).sort(
(a, b) => (a.frame_id || 0) - (b.frame_id || 0),
),
};
}, [data, enabledTypes]);
@@ -160,7 +198,9 @@ export default function VideoPlayerSection({
normalizedData,
detectionType,
);
const { getStickyCounts, sortedFrameIndices } = useCumulativeCounts(normalizedData.frames || []);
const { getStickyCounts, sortedFrameIndices } = useCumulativeCounts(
normalizedData.frames || [],
);
// Memoized video URL
const videoUrl = useMemo(() => {
@@ -193,7 +233,8 @@ export default function VideoPlayerSection({
// Logging logic
if (dets && dets.length > 0) {
const firstDetId = dets[0].pothole_id ?? dets[0].signboard_id ?? dets[0].detection_id;
const firstDetId =
dets[0].pothole_id ?? dets[0].signboard_id ?? dets[0].detection_id;
const coords = gpsMap.get(firstDetId);
if (coords) {
@@ -211,14 +252,24 @@ export default function VideoPlayerSection({
type: d.type || d._detType,
bbox: d.bbox,
confidence: d.confidence,
latitude: gpsMap.get(d.pothole_id ?? d.signboard_id ?? d.detection_id)?.lat,
longitude: gpsMap.get(d.pothole_id ?? d.signboard_id ?? d.detection_id)?.lng,
latitude: gpsMap.get(
d.pothole_id ?? d.signboard_id ?? d.detection_id,
)?.lat,
longitude: gpsMap.get(
d.pothole_id ?? d.signboard_id ?? d.detection_id,
)?.lng,
})),
},
});
}
},
[data.video_info.fps, getNearestDetections, getStickyCounts, gpsMap, sortedDetectionIndices],
[
data.video_info.fps,
getNearestDetections,
getStickyCounts,
gpsMap,
sortedDetectionIndices,
],
);
// Playback loop hook
@@ -248,9 +299,14 @@ export default function VideoPlayerSection({
const currentFrame = Math.round(video.currentTime * fps);
// Snap to the next available frame index that has detections
const nextDetectionFrame = sortedDetectionIndices.find((f) => f >= currentFrame);
const nextDetectionFrame = sortedDetectionIndices.find(
(f) => f >= currentFrame,
);
if (nextDetectionFrame !== undefined && nextDetectionFrame !== currentFrame) {
if (
nextDetectionFrame !== undefined &&
nextDetectionFrame !== currentFrame
) {
video.currentTime = nextDetectionFrame / fps;
return;
}
@@ -276,7 +332,9 @@ export default function VideoPlayerSection({
<Film className="h-5 w-5 text-primary" />
</div>
<div>
<CardTitle className="text-lg font-bold">Detection Playback</CardTitle>
<CardTitle className="text-lg font-bold">
Detection Playback
</CardTitle>
<CardDescription className="text-xs">
Real-time object detection analysis
</CardDescription>
@@ -297,7 +355,10 @@ export default function VideoPlayerSection({
onLoadedData={handleLoadedData}
onEnded={handleVideoEnded}
onSeeked={handleVideoSeeked}
currentDetections={getNearestDetections(currentFrame, sortedDetectionIndices) || []}
currentDetections={
getNearestDetections(currentFrame, sortedDetectionIndices) ||
[]
}
/>
<DetectionStatsBar
@@ -316,7 +377,11 @@ export default function VideoPlayerSection({
{showSummary && (
<div className="space-y-6 pt-4 animate-in fade-in slide-in-from-bottom-4 duration-500">
<SummarySection data={data} show={showSummary} detectionType={detectionType} />
<SummarySection
data={data}
show={showSummary}
detectionType={detectionType}
/>
<DetailedSummarySection
projectId={projectId || ''}
videoId={videoId}