Files

94 lines
3.1 KiB
TypeScript

'use client';
import { useState } from 'react';
import { RiArrowDownSLine, RiCheckLine } from '@remixicon/react';
import {
ModelSelector,
ModelSelectorContent,
ModelSelectorEmpty,
ModelSelectorGroup,
ModelSelectorInput,
ModelSelectorItem,
ModelSelectorList,
ModelSelectorName,
ModelSelectorTrigger,
} from '@/components/ai-elements/model-selector';
import { Button } from '@/components/ui/button';
import { openRouterModels, type OpenRouterModelId } from '@/lib/openrouter';
const providers: Record<string, string> = {
anthropic: 'Anthropic',
openai: 'OpenAI',
google: 'Google',
'x-ai': 'SpaceXAI',
'z-ai': 'Z.ai',
moonshotai: 'MoonshotAI',
minimax: 'MiniMax',
deepseek: 'DeepSeek',
meta: 'Meta',
qwen: 'Qwen',
};
const modelGroups = Object.entries(providers).map(([id, name]) => ({
name,
models: openRouterModels.filter((model) => model.id.startsWith(`${id}/`)),
}));
interface ChatModelSelectorProps {
value: OpenRouterModelId;
onChange: (modelId: OpenRouterModelId) => void;
disabled?: boolean;
}
export function ChatModelSelector({ value, onChange, disabled }: ChatModelSelectorProps) {
const [open, setOpen] = useState(false);
const selectedModel = openRouterModels.find((model) => model.id === value);
return (
<ModelSelector open={open} onOpenChange={setOpen}>
<ModelSelectorTrigger asChild>
<Button
type="button"
variant="ghost"
size="sm"
className="min-w-0 max-w-[min(16rem,calc(100vw-10rem))] text-muted-foreground"
aria-label={`Select model, current model: ${selectedModel?.name}`}
disabled={disabled}
>
<ModelSelectorName>{selectedModel?.name}</ModelSelectorName>
<RiArrowDownSLine className="size-4 shrink-0" aria-hidden="true" />
</Button>
</ModelSelectorTrigger>
<ModelSelectorContent title="Choose a model" className="max-w-[calc(100%-2rem)] sm:max-w-lg">
<ModelSelectorInput placeholder="Search models..." aria-label="Search models" className="pr-10" />
<ModelSelectorList className="max-h-[min(24rem,60dvh)]">
<ModelSelectorEmpty>No models found.</ModelSelectorEmpty>
{modelGroups.map((group) => (
<ModelSelectorGroup heading={group.name} key={group.name}>
{group.models.map((model) => (
<ModelSelectorItem
key={model.id}
value={model.id}
keywords={[model.name, group.name]}
onSelect={() => {
onChange(model.id);
setOpen(false);
}}
>
<ModelSelectorName>{model.name}</ModelSelectorName>
{model.id === value && (
<>
<RiCheckLine className="ml-auto size-4" aria-hidden="true" />
<span className="sr-only">Selected</span>
</>
)}
</ModelSelectorItem>
))}
</ModelSelectorGroup>
))}
</ModelSelectorList>
</ModelSelectorContent>
</ModelSelector>
);
}