import React, { useState } from "react"; import { ApiService } from "../utils/apiService"; import { debugLog } from "../utils/config"; import DataViewer from "./DataViewer"; const Step4 = ({ apiKey, s3Link, config: generationConfig, fileMetadata, generatedDataLink, setGeneratedDataLink, stepNumber, stepTitle, stepIcon, enabled = true, }) => { const [isGenerating, setIsGenerating] = useState(false); const [generationStatus, setGenerationStatus] = useState(""); const [generationProgress, setGenerationProgress] = useState(0); const [hasError, setHasError] = useState(false); const [errorMessage, setErrorMessage] = useState(""); const generateSyntheticData = async () => { // Prevent action if step is disabled if (!enabled) { debugLog("Generation attempted but step is disabled"); return; } setIsGenerating(true); setGenerationStatus("Initializing generation..."); setGenerationProgress(0); setHasError(false); setErrorMessage(""); try { debugLog("Starting synthetic data generation", { s3Link, config: generationConfig, fileMetadata, apiKeyPrefix: apiKey.substring(0, 8) + "...", }); // Use the ApiService with retry logic const result = await ApiService.retryRequest(async () => { // Update progress during API call setGenerationStatus("Sending request to AI model..."); setGenerationProgress(10); return await ApiService.generateSyntheticData(apiKey, s3Link, { ...generationConfig, fileSizeBytes: fileMetadata?.fileSizeBytes || 0, sourceFileRows: fileMetadata?.sourceFileRows || 0, }); }); // If the API returns progress updates, handle them if (result.jobId) { // For now, simulate progress since polling is not implemented await simulateProgress(); // In a real implementation, you would poll for job status here setGeneratedDataLink( result.data?.fileUrl || result.fileUrl || result.download_link || result.link || result.s3_url ); } else { // Simulate progress for immediate results await simulateProgress(); // Handle the specific response format: { "status": "success", "data": { "fileUrl": "..." } } const dataLink = result.data?.fileUrl || result.fileUrl || result.s3_url || result.download_link || result.link; if (!dataLink) { throw new Error( "No download link received from the API. The generation may have failed on the server side." ); } setGeneratedDataLink(dataLink); } setGenerationStatus("Generation completed successfully!"); setGenerationProgress(100); debugLog("Synthetic data generation completed", { downloadLink: result.data?.fileUrl || result.fileUrl || result.s3_url || result.download_link || result.link, status: result.status, message: result.message, fullResult: result, }); } catch (error) { debugLog("Synthetic data generation failed", error); setHasError(true); setGenerationProgress(0); // Create a user-friendly error message let friendlyErrorMessage = "An error occurred during generation."; if (error.message.includes("403") || error.message.includes("401")) { friendlyErrorMessage = "Authentication failed. Please check your API key and try again."; } else if (error.message.includes("404")) { friendlyErrorMessage = "Generation service not found. Please try again later."; } else if (error.message.includes("500")) { friendlyErrorMessage = "Server error occurred. The service may be temporarily unavailable."; } else if ( error.message.includes("timeout") || error.message.includes("TimeoutError") ) { friendlyErrorMessage = "Request timed out. The generation process may take longer than expected. Please try again."; } else if ( error.message.includes("Network") || error.message.includes("fetch") ) { friendlyErrorMessage = "Network error. Please check your internet connection and try again."; } else if (error.message.includes("No download link")) { friendlyErrorMessage = "Generation completed but no download link was provided. Please try generating again."; } else if (error.message) { friendlyErrorMessage = error.message; } setErrorMessage(friendlyErrorMessage); setGenerationStatus(`❌ Generation failed: ${friendlyErrorMessage}`); } finally { setIsGenerating(false); } }; const simulateProgress = async () => { const steps = [ { progress: 25, message: "Analyzing data structure..." }, { progress: 50, message: "Training AI model..." }, { progress: 75, message: "Generating synthetic data..." }, { progress: 90, message: "Finalizing output..." }, ]; for (const step of steps) { setGenerationProgress(step.progress); setGenerationStatus(step.message); await new Promise((resolve) => setTimeout(resolve, 1500)); } }; const handleDownload = () => { if (generatedDataLink) { debugLog("Downloading generated data", { link: generatedDataLink }); // Open in new tab so user can see if download works const newWindow = window.open(generatedDataLink, "_blank"); // If popup blocked, provide fallback if (!newWindow) { // Fallback: create a temporary download link const link = document.createElement("a"); link.href = generatedDataLink; link.download = `synthetic_data_${Date.now()}.csv`; document.body.appendChild(link); link.click(); document.body.removeChild(link); } } }; const handleCopyLink = async () => { if (generatedDataLink) { try { await navigator.clipboard.writeText(generatedDataLink); // You could add a toast notification here debugLog("Link copied to clipboard"); } catch (error) { debugLog("Failed to copy link:", error); // Fallback for older browsers const textArea = document.createElement("textarea"); textArea.value = generatedDataLink; document.body.appendChild(textArea); textArea.select(); document.execCommand("copy"); document.body.removeChild(textArea); } } }; const isReadyForGeneration = apiKey && s3Link && generationConfig.targetColumn && generationConfig.numRows; return (
Generate high-quality synthetic data based on your configuration
Please complete all previous steps before generating data.
)}There was an error generating your synthetic data.
Successfully generated {generationConfig.numRows} rows of synthetic data targeting the{" "} {generationConfig.targetColumn} column.