"use client" import { useState, useRef } from "react" 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 { Progress } from "@/components/ui/progress" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select" import { Upload, Loader2, AlertCircle } from "lucide-react" import type { DetectionData, DetectionType } from "@/lib/types" const API_URL = process.env.NEXT_PUBLIC_API_URL const WS_URL = API_URL?.replace(/^https?:\/\//, "wss://") type UploadSectionProps = { onDetectionComplete: (data: DetectionData, videoId: string, file: File) => void onDetectionTypeChange: (type: DetectionType) => void } export function UploadSection({ onDetectionComplete, onDetectionTypeChange }: UploadSectionProps) { const [file, setFile] = useState(null) const [jsonFile, setJsonFile] = useState(null) const [speed, setSpeed] = useState(30) const [detectionType, setDetectionType] = useState("pothole-detection") const [uploading, setUploading] = useState(false) const [progress, setProgress] = useState(0) const [statusMessage, setStatusMessage] = useState("") const [error, setError] = useState(null) const fileInputRef = useRef(null) const jsonFileInputRef = useRef(null) const wsRef = useRef(null) const handleDetectionTypeChange = (value: DetectionType) => { setDetectionType(value) onDetectionTypeChange(value) } const connectWebSocket = (videoId: string) => { console.log("[Upload] Connecting WebSocket for video:", videoId) const ws = new WebSocket(`${WS_URL}/ws/${videoId}`) wsRef.current = ws ws.onopen = () => { console.log("[Upload] WebSocket connected") setError(null) } ws.onmessage = (event) => { const data = JSON.parse(event.data) console.log("[Upload] WebSocket message:", data) if (data.type === "progress" || data.progress !== undefined) { const progressValue = data.progress || 0 setProgress(progressValue) let message = data.message || "Processing..." // Handle both pothole and signboard progress messages 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! Loading results...") ws.close() setTimeout(() => loadResults(videoId), 500) } if (data.type === "error") { setError("Error: " + data.message) setStatusMessage("") setUploading(false) ws.close() } } ws.onerror = (error) => { console.error("[Upload] WebSocket error:", error) setStatusMessage("Connection error. Retrying...") } ws.onclose = () => { console.log("[Upload] WebSocket closed") } } const loadResults = async (videoId: string) => { try { console.log("[Upload] Loading results for:", videoId) const response = await fetch(`${API_URL}/results/${videoId}`, { headers: { "ngrok-skip-browser-warning": "true" } }) if (!response.ok) { throw new Error(`Failed to load results: ${response.status}`) } const detectionData: DetectionData = await response.json() console.log("[Upload] Results loaded:", detectionData) setUploading(false) setProgress(100) setStatusMessage("✓ Complete!") setError(null) // Pass detection data, video_id, and the original file if (file) { onDetectionComplete(detectionData, videoId, file) } } catch (error) { console.error("[Upload] Failed to load results:", error) setError("Failed to load results. Please try again.") setStatusMessage("") setUploading(false) } } 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()) // Add JSON file if provided if (jsonFile) { formData.append("json_file", jsonFile) } setUploading(true) setProgress(0) setStatusMessage("Uploading...") setError(null) try { console.log("[Upload] Uploading to:", `${API_URL}/upload`) console.log("[Upload] Detection type:", detectionType) console.log("[Upload] FormData contents:") console.log(" - file:", file.name) console.log(" - detection_type:", detectionType) console.log(" - speed_kmh:", speed) const response = await fetch(`${API_URL}/upload`, { method: "POST", headers: { "ngrok-skip-browser-warning": "true" }, body: formData }) console.log("[Upload] Upload response status:", response.status) if (!response.ok) { const errorText = await response.text() throw new Error(`Upload failed (${response.status}): ${errorText}`) } const result = await response.json() const videoId = result.video_id console.log("[Upload] Video uploaded successfully, ID:", videoId) console.log("[Upload] Response:", result) setStatusMessage("Uploaded! Starting processing...") setProgress(10) // Connect WebSocket for progress updates connectWebSocket(videoId) } catch (error) { console.error("[Upload] Upload error:", error) let errorMessage = "Upload failed" if (error instanceof TypeError && error.message === "Failed to fetch") { errorMessage = "Cannot connect to server. Please check:\n• Backend is running on " + API_URL + "\n• CORS is configured properly\n• No firewall blocking the connection" } else if (error instanceof Error) { errorMessage = error.message } setError(errorMessage) setStatusMessage("") setUploading(false) setProgress(0) } } return ( Upload Video Select a video file, detection type, and vehicle speed to start AI-powered analysis
{/* File Input */}
{ setFile(e.target.files?.[0] || null) setError(null) }} disabled={uploading} className="flex-1" />
{file && (

Selected: {file.name} ({(file.size / 1024 / 1024).toFixed(2)} MB)

)}
{/* JSON File Input */}
{ setJsonFile(e.target.files?.[0] || null) setError(null) }} disabled={uploading} className="flex-1" />
{jsonFile && (

Selected: {jsonFile.name} ({(jsonFile.size / 1024).toFixed(2)} KB)

)}
{/* Detection Type Selector */}
{/* Speed Input */}
setSpeed(Number(e.target.value))} disabled={uploading} />
{/* Error Display */} {error && (

{error}

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