import React, { useState, useEffect } from 'react'; import { FiChevronDown, FiChevronUp, FiInfo, FiRefreshCw, } from 'react-icons/fi'; import { ModelInfo, getModelsByProvider, getModelDisplayInfo, } from '../../lib/models'; import { useOpenRouterModels } from '../../hooks/useOpenRouterModels'; import Typography from './Typography'; import { Badge } from './badge'; import { Tooltip, TooltipTrigger, TooltipContent } from './tooltip'; import { Button } from './Button'; interface ModelSelectorProps { provider: 'openai' | 'anthropic'; selectedModel: string; onModelChange: (model: string) => void; className?: string; useOpenRouter?: boolean; } interface ModelCardProps { model: ModelInfo; isSelected: boolean; onSelect: (modelId: string) => void; } const ModelCard: React.FC = ({ model, isSelected, onSelect, }) => { const displayInfo = getModelDisplayInfo(model.id); return (
onSelect(model.id)} className={`cursor-pointer border rounded-lg p-4 transition-all hover:shadow-md ${ isSelected ? 'border-brand-blue bg-brand-blue/5 dark:bg-brand-blue/10' : 'border-gray-200 dark:border-gray-700 hover:border-gray-300 dark:hover:border-gray-600' }`} >
{model.name}
{displayInfo?.badges.map((badge) => ( { if (badge === 'Recommended') return 'default'; if (badge === 'New') return 'secondary'; return 'outline'; })()} className='text-xs' > {badge} ))}
View detailed information
{model.description}
Context Window {model.contextWindow}
Input Cost {model.inputCost}
{model.bestFor && model.bestFor.length > 0 && (
Best For:
{model.bestFor.slice(0, 3).map((use) => ( {use} ))}
)}
{model.supportsVision && ( 👁️ Vision )} {model.supportsFunctionCalling && ( 🔧 Functions )}
Output: {model.outputCost}
); }; export const ModelSelectorWithOpenRouter: React.FC = ({ provider, selectedModel, onModelChange, className = '', useOpenRouter = false, }) => { const [isExpanded, setIsExpanded] = useState(false); const [showLiveData, setShowLiveData] = useState(useOpenRouter); const { models: openRouterModels, isLoading, error, refetch, } = useOpenRouterModels({ provider, autoLoad: showLiveData, }); const staticModels = getModelsByProvider(provider); const models = showLiveData && openRouterModels.length > 0 ? openRouterModels : staticModels; const selectedModelInfo = models.find((m) => m.id === selectedModel); const recommendedModels = models.filter((m) => m.isRecommended); const otherModels = models.filter((m) => !m.isRecommended); if (!isExpanded) { return (
AI Model Choose the AI model that best fits your needs and budget
setIsExpanded(true)} className='cursor-pointer border border-gray-300 dark:border-gray-600 rounded-md p-3 bg-white dark:bg-gray-800 hover:border-gray-400 dark:hover:border-gray-500 transition-colors' >
{selectedModelInfo?.name || 'Select a model'} {selectedModelInfo && ( {selectedModelInfo.description} )}
); } return (
Select AI Model {showLiveData ? 'Live pricing from OpenRouter' : 'Choose the model that best fits your use case'}
{useOpenRouter && (
{showLiveData && ( )}
)}
{error && (
Failed to load live model data: {error}
)} {isLoading ? (
) : ( <> {recommendedModels.length > 0 && (
⭐ Recommended Models
{recommendedModels.map((model) => ( ))}
)} {otherModels.length > 0 && (
Other Models
{otherModels.map((model) => ( ))}
)} )}
); };