chore: add culvert type in model method and fix dashboard skeleton issue

This commit is contained in:
2026-03-19 09:26:19 +05:30
parent 3ffa57dd06
commit 762503cedf
3 changed files with 136 additions and 150 deletions

View File

@@ -24,22 +24,15 @@ import { cn } from '@/lib/utils';
const API_URL = process.env.NEXT_PUBLIC_API_URL;
const DETECTION_TYPES = [
{ value: 'pothole-detection', label: 'Pothole Detection' },
{ value: 'sign-board-detection', label: 'Signboard Detection' },
{ value: 'pot-sign-detection', label: 'Pothole & Signboard Detection' },
] as const;
const DETECTION_METHODS = [
{ value: 'yolo', label: 'YOLO Detection Model' },
{ value: 'yolo_vl', label: 'YOLO with Vision-Language Model' },
{ value: 'sam3', label: 'OpenAI SAM 3 Segmentation Model' },
{ value: 'yoloe', label: 'YOLOE Open-Vocabulary Detection' },
{ value: 'yoloe_trained_vl', label: 'YOLOE With Vision Language Model' },
{ value: 'culvert_detection', label: 'Culvert Detection' },
] as const;
type DetectionType = 'pothole-detection' | 'sign-board-detection' | 'pot-sign-detection';
export default function UploadPage() {
const router = useRouter();
const [session, setSession] = useState<SessionContext | null>(null);
@@ -48,8 +41,6 @@ export default function UploadPage() {
// Form states
const [file, setFile] = useState<File | null>(null);
const [jsonFile, setJsonFile] = useState<File | null>(null);
const [speed, setSpeed] = useState(30);
const [detectionType, setDetectionType] = useState<DetectionType>('pothole-detection');
const [selectMethod, setSelectMethod] = useState('yolo_vl');
// Upload states
@@ -77,9 +68,12 @@ export default function UploadPage() {
const formData = new FormData();
formData.append('file', file);
formData.append('detection_type', detectionType);
formData.append('speed_kmh', speed.toString());
formData.append('detection_mode', selectMethod);
if (session?.chainageId) {
formData.append('chainage_id', session.chainageId);
}
if (jsonFile) {
formData.append('json_file', jsonFile);
}
@@ -101,7 +95,7 @@ export default function UploadPage() {
}
}
sessionService.saveVideoData({ videoId: result.video_id, detectionType });
sessionService.saveVideoData({ videoId: result.video_id });
// Redirect to the dynamic processing page
router.push(`/upload/${result.video_id}`);
@@ -124,11 +118,7 @@ export default function UploadPage() {
router.push(ROUTES.NEW_ANALYSIS);
};
const getTitle = () => {
if (detectionType === 'pothole-detection') return 'Pothole Detection';
if (detectionType === 'sign-board-detection') return 'Signboard Detection';
return 'Pothole & Signboard Detection';
};
const getTitle = () => 'Road Analysis';
if (isLoading) {
return (
@@ -160,30 +150,33 @@ export default function UploadPage() {
<Card className="p-0 border shadow-sm overflow-hidden">
<div className="flex flex-col md:flex-row md:items-center justify-between py-4 px-6 gap-6 bg-card">
<div className="flex flex-wrap items-center gap-x-12 gap-y-4">
<div className="flex flex-col">
<span className="text-[10px] font-bold uppercase tracking-widest text-muted-foreground mb-1.5">
Project
</span>
<span className="text-base font-bold leading-tight">
{session.projectName}
</span>
</div>
<div className="flex flex-col border-l pl-12 border-border/60">
<span className="text-[10px] font-bold uppercase tracking-widest text-muted-foreground mb-1.5">
Package
</span>
<span className="text-sm font-semibold text-muted-foreground leading-tight">
{session.packageName}
</span>
</div>
<div className="flex flex-col border-l pl-12 border-border/60">
<span className="text-[10px] font-bold uppercase tracking-widest text-muted-foreground mb-1.5">
Chainage
</span>
<span className="text-sm font-semibold text-muted-foreground leading-tight">
{session.chainageName}
</span>
</div>
{[
{ label: 'Project', value: session.projectName, primary: true },
{ label: 'Package', value: session.packageName },
{ label: 'Chainage', value: session.chainageName },
].map((item, idx) => (
<div
key={item.label}
className={cn(
'flex flex-col',
idx !== 0 && 'border-l pl-12 border-border/60',
)}
>
<span className="text-[10px] font-bold uppercase tracking-widest text-muted-foreground mb-1.5">
{item.label}
</span>
<span
className={cn(
'leading-tight',
item.primary
? 'text-base font-bold'
: 'text-sm font-semibold text-muted-foreground',
)}
>
{item.value}
</span>
</div>
))}
</div>
<Button
variant="outline"
@@ -203,12 +196,12 @@ export default function UploadPage() {
<CardHeader className="pb-4">
<CardTitle className="text-xl font-bold">Upload Video</CardTitle>
<CardDescription className="text-sm">
Select video file, detection type, vehicle speed, and method for analysis
Select video file, GPS JSON file, and method for analysis
</CardDescription>
</CardHeader>
<CardContent className="pt-4 space-y-6">
<div className="grid grid-cols-1 md:grid-cols-2 gap-6 mb-4">
{/* Video File Input */}
<div className="space-y-6">
{/* Video File Input - Full Width */}
<div className="space-y-2">
<Label htmlFor="video-file" className="text-sm font-semibold">
Video File
@@ -226,84 +219,48 @@ export default function UploadPage() {
/>
</div>
{/* JSON File Input */}
<div className="space-y-2">
<Label htmlFor="json-file" className="text-sm font-semibold">
GPS JSON File
</Label>
<Input
id="json-file"
type="file"
accept=".json,application/json"
onChange={(e) => {
setJsonFile(e.target.files?.[0] || null);
setError(null);
}}
disabled={uploading}
className="h-11 bg-muted/20 file:mr-3 file:py-1.5 file:px-3 file:rounded-md file:border-0 file:bg-primary/10 file:text-primary file:font-medium file:text-xs hover:file:bg-primary/20"
/>
</div>
</div>
{/* JSON File and Method - Both in one line */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
{/* JSON File Input */}
<div className="space-y-2">
<Label htmlFor="json-file" className="text-sm font-semibold">
GPS JSON File
</Label>
<Input
id="json-file"
type="file"
accept=".json,application/json"
onChange={(e) => {
setJsonFile(e.target.files?.[0] || null);
setError(null);
}}
disabled={uploading}
className="h-11 bg-muted/20 file:mr-3 file:py-1.5 file:px-3 file:rounded-md file:border-0 file:bg-primary/10 file:text-primary file:font-medium file:text-xs hover:file:bg-primary/20"
/>
</div>
{/* Detection, Speed, and Method Row */}
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
{/* Detection Type */}
<div className="space-y-2">
<Label htmlFor="detection-type" className="text-sm font-semibold">
Detection Type
</Label>
<Select
value={detectionType}
onValueChange={(v) => setDetectionType(v as DetectionType)}
disabled={uploading}
>
<SelectTrigger id="detection-type" className="h-11">
<SelectValue placeholder="Select detection type" />
</SelectTrigger>
<SelectContent>
{DETECTION_TYPES.map((type) => (
<SelectItem key={type.value} value={type.value}>
{type.label}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
{/* Speed Input */}
<div className="space-y-2">
<Label htmlFor="speed" className="text-sm font-semibold">
Vehicle Speed (km/h)
</Label>
<Input
id="speed"
type="number"
min={1}
max={200}
value={speed}
onChange={(e) => setSpeed(Number(e.target.value))}
disabled={uploading}
className="h-11"
/>
</div>
{/* Select Method */}
<div className="space-y-2">
<Label htmlFor="select-method" className="text-sm font-semibold">
Select Method
</Label>
<Select value={selectMethod} onValueChange={setSelectMethod} disabled={uploading}>
<SelectTrigger id="select-method" className="h-11">
<SelectValue placeholder="Select method" />
</SelectTrigger>
<SelectContent>
{DETECTION_METHODS.map((method) => (
<SelectItem key={method.value} value={method.value}>
{method.label}
</SelectItem>
))}
</SelectContent>
</Select>
{/* Select Method */}
<div className="space-y-2">
<Label htmlFor="select-method" className="text-sm font-semibold">
Select Method
</Label>
<Select
value={selectMethod}
onValueChange={setSelectMethod}
disabled={uploading}
>
<SelectTrigger id="select-method" className="h-11">
<SelectValue placeholder="Select method" />
</SelectTrigger>
<SelectContent>
{DETECTION_METHODS.map((method) => (
<SelectItem key={method.value} value={method.value}>
{method.label}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
</div>
</div>