Skip to content
Merged
21 changes: 0 additions & 21 deletions web/src/app/chat/input/ChatInputBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -854,27 +854,6 @@ export function ChatInputBar({
llmManager={llmManager}
requiresImageGeneration={false}
currentAssistant={selectedAssistant}
trigger={
<button
className="dark:text-white text-black focus:outline-none"
data-testid="llm-popover-trigger"
>
<ChatInputOption
minimize
toggle
flexPriority="stiff"
name={getDisplayNameForModel(
llmManager?.currentLlm.modelName || "Models"
)}
Icon={getProviderIcon(
llmManager?.currentLlm.provider || "anthropic",
llmManager?.currentLlm.modelName ||
"claude-3-5-sonnet-20240620"
)}
tooltipContent="Switch models"
/>
</button>
}
/>

{retrievalEnabled && (
Expand Down
221 changes: 85 additions & 136 deletions web/src/app/chat/input/LLMPopover.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,8 @@ import {
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover";
import { getDisplayNameForModel } from "@/lib/hooks";
import {
modelSupportsImageInput,
parseLlmDescriptor,
structureValue,
} from "@/lib/llm/utils";
import { getDisplayNameForModel, LlmDescriptor } from "@/lib/hooks";
import { modelSupportsImageInput } from "@/lib/llm/utils";
import { LLMProviderDescriptor } from "@/app/admin/configuration/llm/interfaces";
import { getProviderIcon } from "@/app/admin/configuration/llm/utils";
import { Persona } from "@/app/admin/assistants/interfaces";
Expand Down Expand Up @@ -50,70 +46,6 @@ export default function LLMPopover({
const [isOpen, setIsOpen] = useState(false);
const { user } = useUser();

// Memoize the options to prevent unnecessary recalculations
const { llmOptions, defaultProvider, defaultModelDisplayName } =
useMemo(() => {
const llmOptionsByProvider: {
[provider: string]: {
name: string;
value: string;
icon: React.FC<{ size?: number; className?: string }>;
}[];
} = {};

const uniqueModelNames = new Set<string>();

llmProviders.forEach((llmProvider) => {
if (!llmOptionsByProvider[llmProvider.provider]) {
llmOptionsByProvider[llmProvider.provider] = [];
}

llmProvider.model_configurations.forEach((modelConfiguration) => {
if (
!uniqueModelNames.has(modelConfiguration.name) &&
modelConfiguration.is_visible
) {
uniqueModelNames.add(modelConfiguration.name);
const options = llmOptionsByProvider[llmProvider.provider];
if (options) {
options.push({
name: modelConfiguration.name,
value: structureValue(
llmProvider.name,
llmProvider.provider,
modelConfiguration.name
),
icon: getProviderIcon(
llmProvider.provider,
modelConfiguration.name
),
});
}
}
});
});

const llmOptions = Object.entries(llmOptionsByProvider).flatMap(
([provider, options]) => [...options]
);

const defaultProvider = llmProviders.find(
(llmProvider) => llmProvider.is_default_provider
);

const defaultModelName = defaultProvider?.default_model_name;
const defaultModelDisplayName = defaultModelName
? getDisplayNameForModel(defaultModelName)
: null;

return {
llmOptionsByProvider,
llmOptions,
defaultProvider,
defaultModelDisplayName,
};
}, [llmProviders]);

const [localTemperature, setLocalTemperature] = useState(
llmManager.temperature ?? 0.5
);
Expand Down Expand Up @@ -153,24 +85,29 @@ export default function LLMPopover({
minimize
toggle
flexPriority="stiff"
name={getDisplayNameForModel(
llmManager?.currentLlm.modelName ||
defaultModelDisplayName ||
"Models"
)}
name={getDisplayNameForModel(llmManager.currentLlm.modelName)}
Icon={getProviderIcon(
llmManager?.currentLlm.provider ||
defaultProvider?.provider ||
"anthropic",
llmManager?.currentLlm.modelName ||
defaultProvider?.default_model_name ||
"claude-3-5-sonnet-20240620"
llmManager.currentLlm.provider,
llmManager.currentLlm.name
)}
tooltipContent="Switch models"
/>
</button>
),
[defaultModelDisplayName, defaultProvider, llmManager?.currentLlm]
[llmManager.currentLlm]
);

const llmOptionsToChooseFrom = useMemo(
() =>
llmProviders.flatMap((llmProvider) =>
llmProvider.model_configurations.map((modelConfiguration) => ({
name: llmProvider.name,
provider: llmProvider.provider,
modelName: modelConfiguration.name,
icon: getProviderIcon(llmProvider.provider, modelConfiguration.name),
}))
),
[llmProviders]
);

return (
Expand All @@ -181,61 +118,73 @@ export default function LLMPopover({
className="w-64 p-1 bg-background border border-background-200 rounded-md shadow-lg flex flex-col"
>
<div className="flex-grow max-h-[300px] default-scrollbar overflow-y-auto">
{llmOptions.map(({ name, icon, value }, index) => {
if (
!requiresImageGeneration ||
modelSupportsImageInput(llmProviders, name)
) {
return (
<button
key={index}
className={`w-full flex items-center gap-x-2 px-3 py-2 text-sm text-left hover:bg-background-100 dark:hover:bg-neutral-800 transition-colors duration-150 ${
(currentModelName || llmManager.currentLlm.modelName) ===
name
? "bg-background-100 dark:bg-neutral-900 text-text"
: "text-text-darker"
}`}
onClick={() => {
llmManager.updateCurrentLlm(parseLlmDescriptor(value));
onSelect?.(value);
setIsOpen(false);
}}
>
{icon({
size: 16,
className: "flex-none my-auto text-black",
})}
<TruncatedText text={getDisplayNameForModel(name)} />
{(() => {
if (currentAssistant?.llm_model_version_override === name) {
return (
<span className="flex-none ml-auto text-xs">
(assistant)
</span>
);
}
})()}
{llmManager.imageFilesPresent &&
!modelSupportsImageInput(llmProviders, name) && (
<TooltipProvider>
<Tooltip delayDuration={0}>
<TooltipTrigger className="my-auto flex items-center ml-auto">
<FiAlertTriangle className="text-alert" size={16} />
</TooltipTrigger>
<TooltipContent>
<p className="text-xs">
This LLM is not vision-capable and cannot process
image files present in your chat session.
</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
)}
</button>
);
{llmOptionsToChooseFrom.map(
({ modelName, provider, name, icon }, index) => {
if (
!requiresImageGeneration ||
modelSupportsImageInput(llmProviders, modelName, provider)
) {
return (
<button
key={index}
className={`w-full flex items-center gap-x-2 px-3 py-2 text-sm text-left hover:bg-background-100 dark:hover:bg-neutral-800 transition-colors duration-150 ${
(currentModelName || llmManager.currentLlm.modelName) ===
name
? "bg-background-100 dark:bg-neutral-900 text-text"
: "text-text-darker"
}`}
onClick={() => {
llmManager.updateCurrentLlm({
modelName,
provider,
name,
} as LlmDescriptor);
onSelect?.(name);
setIsOpen(false);
}}
>
{icon({
size: 16,
className: "flex-none my-auto text-black",
})}
<TruncatedText text={modelName} />
{(() => {
if (
currentAssistant?.llm_model_version_override === name
) {
return (
<span className="flex-none ml-auto text-xs">
(assistant)
</span>
);
}
})()}
{llmManager.imageFilesPresent &&
!modelSupportsImageInput(llmProviders, name) && (
<TooltipProvider>
<Tooltip delayDuration={0}>
<TooltipTrigger className="my-auto flex items-center ml-auto">
<FiAlertTriangle
className="text-alert"
size={16}
/>
</TooltipTrigger>
<TooltipContent>
<p className="text-xs">
This LLM is not vision-capable and cannot
process image files present in your chat
session.
</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
)}
</button>
);
}
return null;
}
return null;
})}
)}
</div>
{user?.preferences?.temperature_override_enabled && (
<div className="mt-2 pt-2 border-t border-background-200">
Expand Down
Loading