"use client"; import { AnimatePresence, motion } from "framer-motion"; import { useEffect, useState } from "react"; import { toast } from "sonner"; import { type OnboardingVariables, useOnboardingMutation, } from "@/app/api/mutations/useOnboardingMutation"; import { useGetTasksQuery } from "@/app/api/queries/useGetTasksQuery"; import { useDoclingHealth } from "@/components/docling-health-banner"; import IBMLogo from "@/components/logo/ibm-logo"; import OllamaLogo from "@/components/logo/ollama-logo"; import OpenAILogo from "@/components/logo/openai-logo"; import { AnimatedProcessingIcon } from "@/components/ui/animated-processing-icon"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardFooter, CardHeader, } from "@/components/ui/card"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Tooltip, TooltipContent, TooltipTrigger, } from "@/components/ui/tooltip"; import { cn } from "@/lib/utils"; import { AnimatedProviderSteps } from "./animated-provider-steps"; import { IBMOnboarding } from "./ibm-onboarding"; import { OllamaOnboarding } from "./ollama-onboarding"; import { OpenAIOnboarding } from "./openai-onboarding"; interface OnboardingCardProps { onComplete: () => void; setIsLoadingModels?: (isLoading: boolean) => void; setLoadingStatus?: (status: string[]) => void; } const STEP_LIST = [ "Setting up your model provider", "Defining schema", "Configuring Langflow", "Ingesting sample data", ]; const TOTAL_PROVIDER_STEPS = STEP_LIST.length; const OnboardingCard = ({ onComplete, setIsLoadingModels: setIsLoadingModelsParent, setLoadingStatus: setLoadingStatusParent, }: OnboardingCardProps) => { const { isHealthy: isDoclingHealthy } = useDoclingHealth(); const [modelProvider, setModelProvider] = useState("openai"); const [sampleDataset, setSampleDataset] = useState(true); const [isLoadingModels, setIsLoadingModels] = useState(false); const [loadingStatus, setLoadingStatus] = useState([]); const [currentStatusIndex, setCurrentStatusIndex] = useState(0); // Pass loading state to parent useEffect(() => { setIsLoadingModelsParent?.(isLoadingModels); }, [isLoadingModels, setIsLoadingModelsParent]); useEffect(() => { setLoadingStatusParent?.(loadingStatus); }, [loadingStatus, setLoadingStatusParent]); // Cycle through loading status messages once useEffect(() => { if (!isLoadingModels || loadingStatus.length === 0) { setCurrentStatusIndex(0); return; } const interval = setInterval(() => { setCurrentStatusIndex((prev) => { const nextIndex = prev + 1; // Stop at the last message if (nextIndex >= loadingStatus.length - 1) { clearInterval(interval); return loadingStatus.length - 1; } return nextIndex; }); }, 1500); // Change status every 1.5 seconds return () => clearInterval(interval); }, [isLoadingModels, loadingStatus]); const handleSetModelProvider = (provider: string) => { setModelProvider(provider); setSettings({ model_provider: provider, embedding_model: "", llm_model: "", }); }; const [settings, setSettings] = useState({ model_provider: modelProvider, embedding_model: "", llm_model: "", }); const [currentStep, setCurrentStep] = useState(null); // Query tasks to track completion const { data: tasks } = useGetTasksQuery({ enabled: currentStep !== null, // Only poll when onboarding has started refetchInterval: currentStep !== null ? 1000 : false, // Poll every 1 second during onboarding }); // Monitor tasks and call onComplete when all tasks are done useEffect(() => { if (currentStep === null || !tasks) { return; } // Check if there are any active tasks (pending, running, or processing) const activeTasks = tasks.find( (task) => task.status === "pending" || task.status === "running" || task.status === "processing", ); // If no active tasks and we've started onboarding, complete it if ( (!activeTasks || (activeTasks.processed_files ?? 0) > 0) && tasks.length > 0 ) { // Set to final step to show "Done" setCurrentStep(TOTAL_PROVIDER_STEPS); // Wait a bit before completing setTimeout(() => { onComplete(); }, 1000); } }, [tasks, currentStep, onComplete]); // Mutations const onboardingMutation = useOnboardingMutation({ onSuccess: (data) => { console.log("Onboarding completed successfully", data); setCurrentStep(0); }, onError: (error) => { toast.error("Failed to complete onboarding", { description: error.message, }); }, }); const handleComplete = () => { if ( !settings.model_provider || !settings.llm_model || !settings.embedding_model ) { toast.error("Please complete all required fields"); return; } // Prepare onboarding data const onboardingData: OnboardingVariables = { model_provider: settings.model_provider, llm_model: settings.llm_model, embedding_model: settings.embedding_model, sample_data: sampleDataset, }; // Add API key if available if (settings.api_key) { onboardingData.api_key = settings.api_key; } // Add endpoint if available if (settings.endpoint) { onboardingData.endpoint = settings.endpoint; } // Add project_id if available if (settings.project_id) { onboardingData.project_id = settings.project_id; } onboardingMutation.mutate(onboardingData); setCurrentStep(0); }; const isComplete = !!settings.llm_model && !!settings.embedding_model && isDoclingHealthy; return ( {currentStep === null ? (
OpenAI
IBM watsonx.ai
Ollama
{!isLoadingModels && (
{!isComplete && ( {!!settings.llm_model && !!settings.embedding_model && !isDoclingHealthy ? "docling-serve must be running to continue" : "Please fill in all required fields"} )}
)}
) : ( )}
); }; export default OnboardingCard;