import { useCallback, useEffect, useMemo, useState } from 'react'; import { ArrowLeft, Check, Eye, Loader2, Pencil, RefreshCw, Wrench, } from 'lucide-react'; import { useTranslation } from 'react-i18next'; import ProviderForm from '@/app/home/components/models-dialog/component/provider-form/ProviderForm'; import type { ScannedProviderModel } from '@/app/infra/entities/api'; import { httpClient } from '@/app/infra/http/HttpClient'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from '@/components/ui/card'; import { Checkbox } from '@/components/ui/checkbox'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { cn } from '@/lib/utils'; type ModelSetupMode = 'scan' | 'manual'; type ScanFallbackReason = 'failed' | 'empty' | null; export interface OwnModelSelection { source: ModelSetupMode; providerUuid: string; model: ScannedProviderModel; } interface OwnModelSetupProps { onBack: () => void; onSelectionChange: (selection: OwnModelSelection | null) => void; } export default function OwnModelSetup({ onBack, onSelectionChange, }: OwnModelSetupProps) { const { t } = useTranslation(); const [providerUuid, setProviderUuid] = useState(null); const [showProviderForm, setShowProviderForm] = useState(true); const [mode, setMode] = useState('scan'); const [models, setModels] = useState([]); const [selectedModelId, setSelectedModelId] = useState(null); const [isScanning, setIsScanning] = useState(false); const [scanFallbackReason, setScanFallbackReason] = useState(null); const [manualModelName, setManualModelName] = useState(''); const [manualContextLength, setManualContextLength] = useState(''); const [manualVision, setManualVision] = useState(false); const [manualFunctionCall, setManualFunctionCall] = useState(false); const parsedManualContextLength = useMemo(() => { if (!manualContextLength.trim()) return null; const value = Number(manualContextLength); return Number.isInteger(value) && value > 0 ? value : undefined; }, [manualContextLength]); useEffect(() => { if (mode !== 'manual' || !providerUuid) return; if (!manualModelName.trim() || parsedManualContextLength === undefined) { onSelectionChange(null); return; } const abilities = [ ...(manualVision ? ['vision'] : []), ...(manualFunctionCall ? ['func_call'] : []), ]; const modelName = manualModelName.trim(); onSelectionChange({ source: 'manual', providerUuid, model: { id: modelName, name: modelName, type: 'llm', abilities, context_length: parsedManualContextLength, already_added: false, }, }); }, [ manualFunctionCall, manualModelName, manualVision, mode, onSelectionChange, parsedManualContextLength, providerUuid, ]); const scanModels = useCallback( async (uuid: string) => { setMode('scan'); setIsScanning(true); setScanFallbackReason(null); setModels([]); setSelectedModelId(null); onSelectionChange(null); try { const response = await httpClient.scanProviderModels(uuid, 'llm'); const availableModels = response.models.filter( (model) => model.type === 'llm' && !model.already_added, ); setModels(availableModels); if (availableModels.length === 0) { setScanFallbackReason('empty'); setMode('manual'); } } catch { setScanFallbackReason('failed'); setMode('manual'); } finally { setIsScanning(false); } }, [onSelectionChange], ); const handleProviderSaved = useCallback( async (uuid: string) => { setProviderUuid(uuid); setShowProviderForm(false); await scanModels(uuid); }, [scanModels], ); const handleSelectModel = useCallback( (model: ScannedProviderModel) => { if (!providerUuid) return; setSelectedModelId(model.id); onSelectionChange({ source: 'scan', providerUuid, model }); }, [onSelectionChange, providerUuid], ); const handleModeChange = useCallback( (value: string) => { setMode(value as ModelSetupMode); setSelectedModelId(null); onSelectionChange(null); }, [onSelectionChange], ); const handleBack = useCallback(() => { onSelectionChange(null); onBack(); }, [onBack, onSelectionChange]); const handleEditProvider = useCallback(() => { setSelectedModelId(null); onSelectionChange(null); setShowProviderForm(true); }, [onSelectionChange]); return (

{t('wizard.aiEngine.ownModelSetupTitle')}

{t('wizard.aiEngine.ownModelSetupDescription')}

{showProviderForm ? ( {t('wizard.aiEngine.addProviderTitle')} {t('wizard.aiEngine.addProviderDescription')} providerUuid ? setShowProviderForm(false) : handleBack() } /> ) : (

{t('wizard.aiEngine.selectModelTitle')}

{t('wizard.aiEngine.selectScannedModelDescription')}

{t('wizard.aiEngine.scanModelMode')} {t('wizard.aiEngine.manualModelMode')} {isScanning ? (
{t('wizard.aiEngine.scanningModels')}
) : models.length > 0 ? (
{models.map((model) => { const selected = selectedModelId === model.id; return ( ); })}
) : (

{t( scanFallbackReason === 'failed' ? 'wizard.aiEngine.scanModelsFailed' : 'wizard.aiEngine.noScannedModels', )}

)}
{scanFallbackReason && (
{t( scanFallbackReason === 'failed' ? 'wizard.aiEngine.manualFallbackFailed' : 'wizard.aiEngine.manualFallbackEmpty', )}
)}
setManualModelName(event.target.value)} placeholder={t('wizard.aiEngine.manualModelIdPlaceholder')} />

{t('wizard.aiEngine.manualModelIdDescription')}

{t('wizard.aiEngine.manualModelOptions')}

setManualContextLength(event.target.value) } placeholder={t('models.contextLengthPlaceholder')} /> {parsedManualContextLength === undefined && (

{t('models.contextLengthInvalid')}

)}
setManualVision(checked === true) } />
setManualFunctionCall(checked === true) } />
)}
); }