import React, { useState } from 'react'; import { Plus, Trash2, Bot, Key, Globe, ChevronDown, ChevronUp } from 'lucide-react'; import { AppConfig, ApiProvider, CustomModel } from '../../types'; import { MODELS } from '../../config'; interface ModelSectionProps { config: AppConfig; setConfig: (c: AppConfig) => void; } const ModelSection = ({ config, setConfig }: ModelSectionProps) => { const [newModelName, setNewModelName] = useState(''); const [newModelProvider, setNewModelProvider] = useState('custom'); const [newModelApiKey, setNewModelApiKey] = useState(''); const [newModelBaseUrl, setNewModelBaseUrl] = useState(''); const [expandedModelId, setExpandedModelId] = useState(null); const customModels = config.customModels || []; const handleAddModel = () => { if (!newModelName.trim()) return; const trimmedName = newModelName.trim(); // Check if model name already exists in preset models const existingPresetModel = MODELS.find(m => m.value === trimmedName); if (existingPresetModel) { alert(`Model name "${trimmedName}" already exists as a preset model. Please choose a different name.`); return; } // Check if model name already exists in custom models const existingCustomModel = customModels.find(m => m.name === trimmedName); if (existingCustomModel) { alert(`Model name "${trimmedName}" already exists. Please choose a different name.`); return; } const newModel: CustomModel = { id: `custom-${Date.now()}`, name: trimmedName, provider: newModelProvider, apiKey: newModelApiKey || undefined, baseUrl: newModelBaseUrl || undefined }; setConfig({ ...config, customModels: [...customModels, newModel] }); setNewModelName(''); setNewModelApiKey(''); setNewModelBaseUrl(''); }; const handleDeleteModel = (modelId: string) => { setConfig({ ...config, customModels: customModels.filter(m => m.id !== modelId) }); if (expandedModelId === modelId) { setExpandedModelId(null); } }; const handleUpdateModel = (modelId: string, updates: Partial) => { setConfig({ ...config, customModels: customModels.map(m => m.id === modelId ? { ...m, ...updates } : m ) }); }; return (

Custom Models

setNewModelName(e.target.value)} onKeyDown={(e) => e.key === 'Enter' && handleAddModel()} className="w-full bg-white border border-slate-200 text-slate-800 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block p-2.5 outline-none placeholder:text-slate-400" />
{(newModelProvider === 'custom' || newModelProvider === 'openai' || newModelProvider === 'anthropic' || newModelProvider === 'xai' || newModelProvider === 'mistral') && ( <>
setNewModelApiKey(e.target.value)} className="w-full bg-white border border-slate-200 text-slate-800 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block p-2.5 outline-none placeholder:text-slate-400" />
setNewModelBaseUrl(e.target.value)} className="w-full bg-white border border-slate-200 text-slate-800 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block p-2.5 outline-none placeholder:text-slate-400" />
)}
{customModels.length > 0 && (
Added Models ({customModels.length})
{customModels.map((model) => (
setExpandedModelId(expandedModelId === model.id ? null : model.id)} >
{model.name}
{model.provider} {model.apiKey && '• Configured'}
{expandedModelId === model.id ? ( ) : ( )}
{expandedModelId === model.id && (
handleUpdateModel(model.id, { apiKey: e.target.value || undefined })} className="w-full bg-white border border-slate-200 text-slate-800 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block p-2.5 outline-none placeholder:text-slate-400" />
handleUpdateModel(model.id, { baseUrl: e.target.value || undefined })} className="w-full bg-white border border-slate-200 text-slate-800 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block p-2.5 outline-none placeholder:text-slate-400" />
)}
))}
)}
); }; export default ModelSection;