import type { Dispatch, SetStateAction } from "react"; import { useEffect, useState } from "react"; import OllamaLogo from "@/components/icons/ollama-logo"; import { LabelInput } from "@/components/label-input"; import { LabelWrapper } from "@/components/label-wrapper"; import { useDebouncedValue } from "@/lib/debounce"; import type { OnboardingVariables } from "../../api/mutations/useOnboardingMutation"; import { useGetOllamaModelsQuery } from "../../api/queries/useGetModelsQuery"; import { useModelSelection } from "../_hooks/useModelSelection"; import { useUpdateSettings } from "../_hooks/useUpdateSettings"; import { ModelSelector } from "./model-selector"; export function OllamaOnboarding({ setSettings, sampleDataset, setSampleDataset, setIsLoadingModels, isEmbedding = false, alreadyConfigured = false, existingEndpoint, }: { setSettings: Dispatch>; sampleDataset: boolean; setSampleDataset: (dataset: boolean) => void; setIsLoadingModels?: (isLoading: boolean) => void; isEmbedding?: boolean; alreadyConfigured?: boolean; existingEndpoint?: string; }) { const [endpoint, setEndpoint] = useState( alreadyConfigured ? undefined : existingEndpoint || `http://localhost:11434`, ); const [showConnecting, setShowConnecting] = useState(false); const debouncedEndpoint = useDebouncedValue(endpoint, 500); // Fetch models from API when endpoint is provided (debounced) const { data: modelsData, isLoading: isLoadingModels, error: modelsError, } = useGetOllamaModelsQuery( debouncedEndpoint ? { endpoint: debouncedEndpoint } : undefined, { enabled: !!debouncedEndpoint || alreadyConfigured || alreadyConfigured }, ); // Use custom hook for model selection logic const { languageModel, embeddingModel, setLanguageModel, setEmbeddingModel, languageModels, embeddingModels, } = useModelSelection(modelsData, isEmbedding); // Handle delayed display of connecting state useEffect(() => { let timeoutId: NodeJS.Timeout; if (debouncedEndpoint && isLoadingModels) { timeoutId = setTimeout(() => { setIsLoadingModels?.(true); setShowConnecting(true); }, 500); } else { setShowConnecting(false); setIsLoadingModels?.(false); } return () => { if (timeoutId) { clearTimeout(timeoutId); } }; }, [debouncedEndpoint, isLoadingModels, setIsLoadingModels]); // Update settings when values change useUpdateSettings( "ollama", { endpoint, languageModel, embeddingModel, }, setSettings, isEmbedding, ); // Check validation state based on models query const hasConnectionError = debouncedEndpoint && modelsError; const hasNoModels = modelsData && !modelsData.language_models?.length && !modelsData.embedding_models?.length; return (
setEndpoint(e.target.value)} disabled={alreadyConfigured} /> {alreadyConfigured && (

Reusing endpoint from model provider selection.

)} {showConnecting && (

Connecting to Ollama server...

)} {hasConnectionError && (

Can't reach Ollama at {debouncedEndpoint}. Update the base URL or start the server.

)} {hasNoModels && (

No models found. Install embedding and agent models on your Ollama server.

)}
{isEmbedding && setEmbeddingModel && ( } noOptionsPlaceholder={ isLoadingModels ? "Loading models..." : "No embedding models detected. Install an embedding model to continue." } value={embeddingModel} onValueChange={setEmbeddingModel} /> )} {!isEmbedding && setLanguageModel && ( } noOptionsPlaceholder={ isLoadingModels ? "Loading models..." : "No language models detected. Install a language model to continue." } value={languageModel} onValueChange={setLanguageModel} /> )}
); }