"use client" import { useState, useEffect } from "react" import { useRouter } from "next/navigation" import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" import { Label } from "@/components/ui/label" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select" import { Loader2, TrendingUp } from "lucide-react" import { SidebarNavigation } from "@/components/sidebar-navigation" import { type SessionContext, loadSession, isSessionValid, saveVideoData, clearSession } from "@/lib/api" import { storeVideoFile } from "@/lib/video-storage" const API_URL = process.env.NEXT_PUBLIC_API_URL || "http://127.0.0.1:8000/api/v1" const WS_URL = process.env.NEXT_PUBLIC_WS_URL || "ws://127.0.0.1:8000/api/v1" type DetectionType = "pothole-detection" | "sign-board-detection" | "pot-sign-detection" export default function UploadPage() { const router = useRouter() const [session, setSession] = useState(null) const [isLoading, setIsLoading] = useState(true) // Form states const [file, setFile] = useState(null) const [jsonFile, setJsonFile] = useState(null) const [speed, setSpeed] = useState(30) const [detectionType, setDetectionType] = useState("pothole-detection") // Upload states const [uploading, setUploading] = useState(false) const [progress, setProgress] = useState(0) const [statusMessage, setStatusMessage] = useState("") const [error, setError] = useState(null) // Load session on mount useEffect(() => { const storedSession = loadSession() if (!isSessionValid(storedSession)) { router.replace("/new-analysis") return } setSession(storedSession) setIsLoading(false) }, [router]) const connectWebSocket = (videoId: string) => { const ws = new WebSocket(`${WS_URL}/ws/${videoId}`) ws.onmessage = async (event) => { const data = JSON.parse(event.data) if (data.type === "progress" || data.progress !== undefined) { setProgress(data.progress || 0) let message = data.message || "Processing..." if (data.unique_potholes !== undefined) { message += ` | Unique: ${data.unique_potholes} | Total: ${data.total_detections || 0}` } else if (data.unique_signboards !== undefined) { message += ` | Unique: ${data.unique_signboards} | Total: ${data.total_detections || 0}` } setStatusMessage(message) } if (data.type === "complete" || data.status === "completed") { setStatusMessage("Processing completed! Saving video...") ws.close() if (file) { try { await storeVideoFile(videoId, file) } catch (err) { console.error("Failed to store video file:", err) } } saveVideoData({ videoId, detectionType }) setStatusMessage("Redirecting to results...") setTimeout(() => router.push("/results"), 500) } if (data.type === "error") { setError("Error: " + data.message) setStatusMessage("") setUploading(false) ws.close() } } ws.onerror = () => { setStatusMessage("Connection error. Retrying...") } } const handleUpload = async () => { if (!file) { setError("Please select a video file") return } const formData = new FormData() formData.append("file", file) formData.append("detection_type", detectionType) formData.append("speed_kmh", speed.toString()) if (jsonFile) { formData.append("json_file", jsonFile) } setUploading(true) setProgress(0) setStatusMessage("Uploading...") setError(null) try { const response = await fetch(`${API_URL}/upload`, { method: "POST", headers: { "ngrok-skip-browser-warning": "true" }, body: formData }) if (!response.ok) { const errorText = await response.text() throw new Error(`Upload failed (${response.status}): ${errorText}`) } const result = await response.json() setStatusMessage("Uploaded! Starting processing...") setProgress(10) connectWebSocket(result.video_id) } catch (err) { let errorMessage = "Upload failed" if (err instanceof TypeError && err.message === "Failed to fetch") { errorMessage = "Cannot connect to server. Please check if backend is running." } else if (err instanceof Error) { errorMessage = err.message } setError(errorMessage) setStatusMessage("") setUploading(false) setProgress(0) } } const handleBackToSelection = () => { clearSession() router.push("/new-analysis") } const getTitle = () => { if (detectionType === "pothole-detection") return "Pothole Detection" if (detectionType === "sign-board-detection") return "Signboard Detection" return "Pothole & Signboard Detection" } if (isLoading) { return (
) } return (
{/* Sidebar Navigation */} {/* Main Content */}
{/* Refined Header */}

{getTitle()}

{/* Compact Session Info Bar */} {session && (
Project {session.projectName}
Package {session.packageName}
Location {session.locationName}
)} {/* Upload Card */} Upload Video Select video file, detection type, and vehicle speed for analysis
{/* Video File Input */}
{ setFile(e.target.files?.[0] || null) setError(null) }} disabled={uploading} className="h-10 bg-gray-50 dark:bg-gray-800 file:mr-3 file:py-1.5 file:px-3 file:rounded-md file:border-0 file:bg-blue-100 dark:file:bg-blue-900/50 file:text-blue-600 dark:file:text-blue-400 file:font-medium file:text-xs hover:file:bg-blue-200" />
{/* JSON File Input */}
{ setJsonFile(e.target.files?.[0] || null) setError(null) }} disabled={uploading} className="h-10 bg-gray-50 dark:bg-gray-800 file:mr-3 file:py-1.5 file:px-3 file:rounded-md file:border-0 file:bg-blue-100 dark:file:bg-blue-900/50 file:text-blue-600 dark:file:text-blue-400 file:font-medium file:text-xs hover:file:bg-blue-200" />
{/* Detection Type */}
{/* Speed Input */}
setSpeed(Number(e.target.value))} disabled={uploading} className="h-10 bg-gray-50 dark:bg-gray-800" />
{/* Error Display */} {error && (
!

{error}

)} {/* Upload Button */} {/* Progress Section */} {uploading && (
Processing Progress {progress}%
{statusMessage && (

{statusMessage}

)}
)} {/* Footer */}

Sentient Geeks Pvt. Ltd.

) }