'use client'; import { Cpu, Loader2, Search } from 'lucide-react'; import { cn } from '@/lib/utils'; import { Popover, PopoverButton, PopoverPanel, Transition, } from '@headlessui/react'; import { Fragment, useEffect, useState } from 'react'; import { MinimalProvider } from '@/lib/models/types'; const ModelSelector = () => { const [providers, setProviders] = useState([]); const [isLoading, setIsLoading] = useState(true); const [searchQuery, setSearchQuery] = useState(''); const [selectedModel, setSelectedModel] = useState<{ providerId: string; modelKey: string; } | null>(null); useEffect(() => { const loadProviders = async () => { try { setIsLoading(true); const res = await fetch('/api/providers'); if (!res.ok) { throw new Error('Failed to fetch providers'); } const data = await res.json(); setProviders(data.providers || []); const savedProviderId = localStorage.getItem('chatModelProviderId'); const savedModelKey = localStorage.getItem('chatModelKey'); if (savedProviderId && savedModelKey) { setSelectedModel({ providerId: savedProviderId, modelKey: savedModelKey, }); } else if (data.providers && data.providers.length > 0) { const firstProvider = data.providers.find( (p: MinimalProvider) => p.chatModels.length > 0, ); if (firstProvider && firstProvider.chatModels[0]) { setSelectedModel({ providerId: firstProvider.id, modelKey: firstProvider.chatModels[0].key, }); } } } catch (error) { console.error('Error loading providers:', error); } finally { setIsLoading(false); } }; loadProviders(); }, []); const handleModelSelect = (providerId: string, modelKey: string) => { setSelectedModel({ providerId, modelKey }); localStorage.setItem('chatModelProviderId', providerId); localStorage.setItem('chatModelKey', modelKey); }; const filteredProviders = providers .map((provider) => ({ ...provider, chatModels: provider.chatModels.filter( (model) => model.name.toLowerCase().includes(searchQuery.toLowerCase()) || provider.name.toLowerCase().includes(searchQuery.toLowerCase()), ), })) .filter((provider) => provider.chatModels.length > 0); return (
setSearchQuery(e.target.value)} className="w-full pl-9 pr-3 py-2 bg-light-secondary dark:bg-dark-secondary rounded-lg placeholder:text-sm text-sm text-black dark:text-white placeholder:text-black/40 dark:placeholder:text-white/40 focus:outline-none focus:ring-2 focus:ring-sky-500/20 border border-transparent focus:border-sky-500/30 transition duration-200" />
{isLoading ? (
) : filteredProviders.length === 0 ? (
{searchQuery ? 'No models found' : 'No chat models configured'}
) : (
{filteredProviders.map((provider, providerIndex) => (

{provider.name}

{provider.chatModels.map((model) => ( handleModelSelect(provider.id, model.key) } className={cn( 'px-3 py-2 flex items-center justify-between text-start duration-200 cursor-pointer transition rounded-lg group', selectedModel?.providerId === provider.id && selectedModel?.modelKey === model.key ? 'bg-light-secondary dark:bg-dark-secondary' : 'hover:bg-light-secondary dark:hover:bg-dark-secondary', )} >

{model.name}

))}
{providerIndex < filteredProviders.length - 1 && (
)}
))}
)}
); }; export default ModelSelector;