deepsite-ai-coding / components /model-selector.tsx
likhonsheikh's picture
Upload folder using huggingface_hub
60e402b verified
'use client';
import { useState } from 'react';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { Badge } from '@/components/ui/badge';
import { Settings, Cpu, Zap, Brain } from 'lucide-react';
interface ModelSelectorProps {
selectedModel: string;
onModelChange: (model: string) => void;
models: string[];
}
const modelIcons: Record<string, React.ReactNode> = {
'deepseek-ai': <Brain className="w-3 h-3" />,
'Qwen': <Cpu className="w-3 h-3" />,
'moonshotai': <Zap className="w-3 h-3" />,
'zai-org': <Settings className="w-3 h-3" />,
'MiniMaxAI': <Brain className="w-3 h-3" />,
'meta-llama': <Cpu className="w-3 h-3" />,
'google': <Brain className="w-3 h-3" />,
};
const getProviderFromModel = (modelName: string): string => {
if (modelName.includes('deepseek-ai') || modelName.includes('Qwen') ||
modelName.includes('moonshotai') || modelName.includes('zai-org') ||
modelName.includes('MiniMaxAI') || modelName.includes('meta-llama') ||
modelName.includes('google')) {
return 'Hugging Face';
}
return 'Unknown';
};
const getModelCategory = (modelName: string): string => {
if (modelName.includes('DeepSeek')) return 'Reasoning';
if (modelName.includes('Coder')) return 'Code';
if (modelName.includes('VL')) return 'Vision';
if (modelName.includes('Kimi') && modelName.includes('Thinking')) return 'Reasoning';
if (modelName.includes('Kimi')) return 'General';
if (modelName.includes('GLM')) return 'General';
return 'Language';
};
const getDisplayName = (modelName: string): string => {
const parts = modelName.split('/');
const model = parts[1] || modelName;
// Clean up model names for better display
const cleanName = model
.replace('-0324', '')
.replace('-0528', '')
.replace('-0905', '')
.replace('-Instruct', '')
.replace('-A22B', '')
.replace('-A35B', '')
.replace('-VL-7B', '')
.replace('-Exp', '')
.replace('-Distill-', '-')
.replace('-Terminus', '')
.replace('DeepSeek-V3-0324', 'DeepSeek V3')
.replace('DeepSeek-R1-0528', 'DeepSeek R1')
.replace('DeepSeek-V3.1', 'DeepSeek V3.1')
.replace('DeepSeek-V3.1-Terminus', 'DeepSeek V3.1 Terminus')
.replace('DeepSeek-V3.2-Exp', 'DeepSeek V3.2 Exp')
.replace('Qwen3-Coder-480B-A35B-Instruct', 'Qwen3 Coder 480B')
.replace('Qwen2.5-VL-7B-Instruct', 'Qwen2.5 VL 7B')
.replace('Kimi-K2-Instruct', 'Kimi K2')
.replace('Kimi-K2-Instruct-0905', 'Kimi K2 0905')
.replace('Kimi-K2-Thinking', 'Kimi K2 Thinking')
.replace('GLM-4.6', 'GLM-4.6')
.replace('MiniMax-M2', 'MiniMax M2')
.replace('Llama-3.1-8B-Instruct', 'Llama 3.1 8B')
.replace('Llama-3.1-70B-Instruct', 'Llama 3.1 70B')
.replace('Llama-3.3-70B-Instruct', 'Llama 3.3 70B')
.replace('Llama-4-Scout-17B-16E-Instruct', 'Llama 4 Scout 17B')
.replace('gemma-3-27b-it', 'Gemma 3 27B');
return cleanName;
};
export function ModelSelector({ selectedModel, onModelChange, models }: ModelSelectorProps) {
const [open, setOpen] = useState(false);
const getIconForModel = (modelName: string) => {
for (const [key, icon] of Object.entries(modelIcons)) {
if (modelName.includes(key)) {
return icon;
}
}
return <Brain className="w-3 h-3" />;
};
const groupModelsByProvider = () => {
const groups: Record<string, string[]> = {};
models.forEach(model => {
const provider = getProviderFromModel(model);
if (!groups[provider]) {
groups[provider] = [];
}
groups[provider].push(model);
});
return groups;
};
const groupedModels = groupModelsByProvider();
return (
<Select
value={selectedModel}
onValueChange={onModelChange}
onOpenChange={setOpen}
>
<SelectTrigger className="w-[280px]">
<div className="flex items-center gap-2 truncate">
{getIconForModel(selectedModel)}
<div className="flex-1 min-w-0">
<div className="flex items-center gap-2">
<span className="font-medium truncate">
{getDisplayName(selectedModel)}
</span>
<Badge variant="outline" className="text-xs">
{getModelCategory(selectedModel)}
</Badge>
</div>
<div className="text-xs text-muted-foreground truncate">
{getProviderFromModel(selectedModel)}
</div>
</div>
</div>
</SelectTrigger>
<SelectContent>
{Object.entries(groupedModels).map(([provider, providerModels]) => (
<div key={provider}>
<div className="px-2 py-1.5 text-xs font-semibold text-muted-foreground border-b">
{provider}
</div>
{providerModels.map((model) => (
<SelectItem key={model} value={model}>
<div className="flex items-center gap-2 w-full">
{getIconForModel(model)}
<div className="flex-1 min-w-0">
<div className="flex items-center gap-2">
<span className="font-medium truncate">
{getDisplayName(model)}
</span>
<Badge variant="outline" className="text-xs flex-shrink-0">
{getModelCategory(model)}
</Badge>
</div>
<div className="text-xs text-muted-foreground truncate">
{model}
</div>
</div>
</div>
</SelectItem>
))}
</div>
))}
</SelectContent>
</Select>
);
}