import { useEffect, useState } from "react"; import { Button } from "../ui/button"; import { Dialog, DialogContent, DialogDescription, DialogTitle } from "../ui/dialog"; import SpacesSelector from "./SpacesSelector"; import { motion } from "framer-motion"; import { AlertCircle, CheckCircle, Upload } from "lucide-react"; import Papa from "papaparse"; import { toast } from "sonner"; interface CSVUploadModalProps { isOpen: boolean; onClose: () => void; } export function CSVUploadModal({ isOpen, onClose }: CSVUploadModalProps) { const [file, setFile] = useState(null); const [urls, setUrls] = useState([]); const [isUploading, setIsUploading] = useState(false); const [progress, setProgress] = useState<{ progress: number; processed: number; total: number; succeeded: number; failed: number; status: string; } | null>(null); const [selectedSpaces, setSelectedSpaces] = useState([]); const handleFileChange = (e: React.ChangeEvent) => { const selectedFile = e.target.files?.[0]; if (selectedFile) { if (!selectedFile.name.endsWith(".csv")) { toast.error("Please upload a CSV file"); return; } setFile(selectedFile); // Parse CSV file Papa.parse(selectedFile, { complete: (results) => { // Find column containing URLs by checking first row const firstRow = results.data[0]; let urlColumnIndex = -1; // Look for a column containing URLs in the header row // @ts-expect-error - firstRow is of type unknown firstRow.forEach((cell: string, index: number) => { if ( cell?.toLowerCase().includes("url") || (cell && typeof cell === "string" && cell.trim().startsWith("http")) ) { urlColumnIndex = index; } }); // If no URL column found in header, check first data row if (urlColumnIndex === -1 && results.data[1]) { // @ts-expect-error - results.data[1] is of type unknown results.data[1].forEach((cell: string, index: number) => { if (cell && typeof cell === "string" && cell.trim().startsWith("http")) { urlColumnIndex = index; } }); } if (urlColumnIndex === -1) { toast.error("Could not find a column containing URLs"); setFile(null); return; } // Extract URLs from the identified column const validUrls = results.data .slice(1) // Skip header row .map((row: any) => row[urlColumnIndex]) .filter((url: string) => url && url.trim() && url.startsWith("http")); if (validUrls.length === 0) { toast.error("No valid URLs found in the CSV file"); setFile(null); return; } setUrls(validUrls); toast.success(`Found ${validUrls.length} valid URLs in column ${urlColumnIndex + 1}`); }, error: (error) => { toast.error("Error parsing CSV file: " + error.message); setFile(null); }, }); } }; const handleUpload = async () => { if (!file || urls.length === 0) return; setIsUploading(true); try { const response = await fetch("/backend/v1/batch-add", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ urls, spaces: selectedSpaces, }), }); if (!response.ok) { throw new Error("Failed to start batch upload"); } const reader = response.body?.getReader(); if (!reader) throw new Error("No reader available"); while (true) { const { done, value } = await reader.read(); if (done) break; const text = new TextDecoder().decode(value); const lines = text.split("\n"); for (const line of lines) { if (line.startsWith("data: ")) { try { const data = JSON.parse(line.slice(5)); setProgress(data); if (data.status === "complete") { toast.success( `Batch upload complete! ${data.succeeded} succeeded, ${data.failed} failed`, ); setTimeout(() => { onClose(); setFile(null); setUrls([]); setProgress(null); }, 2000); } } catch (e) { console.error("Error parsing SSE data:", e); } } } } } catch (error) { toast.error("Upload failed: " + (error instanceof Error ? error.message : "Unknown error")); } finally { setIsUploading(false); } }; return ( !isUploading && onClose()}> {isUploading ? (
{progress ? ( <>
{progress.progress}%
Processing URLs ({progress.processed}/{progress.total}) {progress.succeeded} succeeded, {progress.failed} failed ) : ( )}
) : (
Upload CSV File Upload a CSV file containing URLs to add to your memories. The URLs should be in the first column.
{file && ( <>
{file.name} ({urls.length} URLs found)
)}
)}
); }