mirror of
https://github.com/enricoros/big-AGI.git
synced 2026-05-10 21:50:14 -07:00
React hooks for LLM/Persona selects
This commit is contained in:
@@ -1,93 +1,24 @@
|
||||
import * as React from 'react';
|
||||
import { shallow } from 'zustand/shallow';
|
||||
|
||||
import { ListItemButton, ListItemDecorator, Typography } from '@mui/joy';
|
||||
import BuildCircleIcon from '@mui/icons-material/BuildCircle';
|
||||
import SettingsIcon from '@mui/icons-material/Settings';
|
||||
|
||||
import { DLLMId, DModelSourceId } from '~/modules/llms/llm.types';
|
||||
import { SystemPurposeId, SystemPurposes } from '../../../../data';
|
||||
import { useModelsStore } from '~/modules/llms/store-llms';
|
||||
|
||||
import { AppBarDropdown, DropdownItems } from '~/common/layout/AppBarDropdown';
|
||||
import { useChatStore } from '~/common/state/store-chats';
|
||||
import { useUIPreferencesStore, useUIStateStore } from '~/common/state/store-ui';
|
||||
import { useChatLLMDropdown } from './useLLMDropdown';
|
||||
import { usePersonaIdDropdown } from './usePersonaDropdown';
|
||||
|
||||
|
||||
export function ChatDropdowns(props: {
|
||||
conversationId: string | null
|
||||
}) {
|
||||
|
||||
// external state
|
||||
const { chatLLMId, setChatLLMId, llms } = useModelsStore(state => ({
|
||||
chatLLMId: state.chatLLMId,
|
||||
setChatLLMId: state.setChatLLMId,
|
||||
llms: state.llms,
|
||||
}), shallow);
|
||||
|
||||
const { zenMode } = useUIPreferencesStore(state => ({ zenMode: state.zenMode }), shallow);
|
||||
const { systemPurposeId, setSystemPurposeId } = useChatStore(state => {
|
||||
const conversation = state.conversations.find(conversation => conversation.id === props.conversationId);
|
||||
return {
|
||||
systemPurposeId: conversation?.systemPurposeId ?? null,
|
||||
setSystemPurposeId: state.setSystemPurposeId,
|
||||
};
|
||||
}, shallow);
|
||||
const { openLLMOptions, openModelsSetup } = useUIStateStore(state => ({
|
||||
openLLMOptions: state.openLLMOptions, openModelsSetup: state.openModelsSetup,
|
||||
}), shallow);
|
||||
|
||||
const handleChatModelChange = (event: any, value: DLLMId | null) =>
|
||||
value && props.conversationId && setChatLLMId(value);
|
||||
|
||||
const handleSystemPurposeChange = (event: any, value: SystemPurposeId | null) =>
|
||||
value && props.conversationId && setSystemPurposeId(props.conversationId, value);
|
||||
|
||||
const handleOpenLLMOptions = () => chatLLMId && openLLMOptions(chatLLMId);
|
||||
|
||||
// build model menu items, filtering-out hidden models, and add Source separators
|
||||
const llmItems: DropdownItems = {};
|
||||
let prevSourceId: DModelSourceId | null = null;
|
||||
for (const llm of llms) {
|
||||
if (!llm.hidden || llm.id === chatLLMId) {
|
||||
if (!prevSourceId || llm.sId !== prevSourceId) {
|
||||
if (prevSourceId)
|
||||
llmItems[`sep-${llm.id}`] = { type: 'separator', title: llm.sId };
|
||||
prevSourceId = llm.sId;
|
||||
}
|
||||
llmItems[llm.id] = { title: llm.label };
|
||||
}
|
||||
}
|
||||
// state
|
||||
const { chatLLMDropdown } = useChatLLMDropdown();
|
||||
const { personaDropdown } = usePersonaIdDropdown(props.conversationId);
|
||||
|
||||
return <>
|
||||
|
||||
{/* Model selector */}
|
||||
<AppBarDropdown
|
||||
items={llmItems}
|
||||
value={chatLLMId} onChange={handleChatModelChange}
|
||||
placeholder='Models …'
|
||||
appendOption={<>
|
||||
|
||||
{chatLLMId && (
|
||||
<ListItemButton key='menu-opt' onClick={handleOpenLLMOptions}>
|
||||
<ListItemDecorator><SettingsIcon color='success' /></ListItemDecorator><Typography>Options</Typography>
|
||||
</ListItemButton>
|
||||
)}
|
||||
|
||||
<ListItemButton key='menu-llms' onClick={openModelsSetup}>
|
||||
<ListItemDecorator><BuildCircleIcon color='success' /></ListItemDecorator><Typography>Models</Typography>
|
||||
</ListItemButton>
|
||||
|
||||
</>}
|
||||
/>
|
||||
{chatLLMDropdown}
|
||||
|
||||
{/* Persona selector */}
|
||||
{systemPurposeId && (
|
||||
<AppBarDropdown
|
||||
items={SystemPurposes} showSymbols={zenMode !== 'cleaner'}
|
||||
value={systemPurposeId} onChange={handleSystemPurposeChange}
|
||||
/>
|
||||
)}
|
||||
{personaDropdown}
|
||||
|
||||
</>;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
import * as React from 'react';
|
||||
import { shallow } from 'zustand/shallow';
|
||||
|
||||
import { ListItemButton, ListItemDecorator } from '@mui/joy';
|
||||
import BuildCircleIcon from '@mui/icons-material/BuildCircle';
|
||||
import SettingsIcon from '@mui/icons-material/Settings';
|
||||
|
||||
import { DLLM, DLLMId, DModelSourceId } from '~/modules/llms/llm.types';
|
||||
import { useModelsStore } from '~/modules/llms/store-llms';
|
||||
|
||||
import { AppBarDropdown, DropdownItems } from '~/common/layout/AppBarDropdown';
|
||||
import { useUIStateStore } from '~/common/state/store-ui';
|
||||
|
||||
|
||||
function AppBarLLMDropdown(props: {
|
||||
llms: DLLM[],
|
||||
llmId: DLLMId | null,
|
||||
setLlmId: (llmId: DLLMId | null) => void,
|
||||
placeholder?: string,
|
||||
}) {
|
||||
|
||||
// build model menu items, filtering-out hidden models, and add Source separators
|
||||
const llmItems: DropdownItems = {};
|
||||
let prevSourceId: DModelSourceId | null = null;
|
||||
for (const llm of props.llms) {
|
||||
if (!llm.hidden || llm.id === props.llmId) {
|
||||
if (!prevSourceId || llm.sId !== prevSourceId) {
|
||||
if (prevSourceId)
|
||||
llmItems[`sep-${llm.id}`] = { type: 'separator', title: llm.sId };
|
||||
prevSourceId = llm.sId;
|
||||
}
|
||||
llmItems[llm.id] = { title: llm.label };
|
||||
}
|
||||
}
|
||||
|
||||
const handleChatLLMChange = (_event: any, value: DLLMId | null) => value && props.setLlmId(value);
|
||||
|
||||
const handleOpenLLMOptions = () => props.llmId && useUIStateStore.getState().openLLMOptions(props.llmId);
|
||||
|
||||
const handleOpenModelsSetup = () => useUIStateStore.getState().openModelsSetup();
|
||||
|
||||
return (
|
||||
<AppBarDropdown
|
||||
items={llmItems}
|
||||
value={props.llmId} onChange={handleChatLLMChange}
|
||||
placeholder={props.placeholder || 'Models …'}
|
||||
appendOption={<>
|
||||
|
||||
{props.llmId && (
|
||||
<ListItemButton key='menu-opt' onClick={handleOpenLLMOptions}>
|
||||
<ListItemDecorator><SettingsIcon color='success' /></ListItemDecorator>
|
||||
Options
|
||||
</ListItemButton>
|
||||
)}
|
||||
|
||||
<ListItemButton key='menu-llms' onClick={handleOpenModelsSetup}>
|
||||
<ListItemDecorator><BuildCircleIcon color='success' /></ListItemDecorator>
|
||||
Models
|
||||
</ListItemButton>
|
||||
|
||||
</>}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export function useChatLLMDropdown() {
|
||||
// external state
|
||||
const { llms, chatLLMId, setChatLLMId } = useModelsStore(state => ({
|
||||
llms: state.llms,
|
||||
chatLLMId: state.chatLLMId,
|
||||
setChatLLMId: state.setChatLLMId,
|
||||
}), shallow);
|
||||
|
||||
const chatLLMDropdown = React.useMemo(
|
||||
() => <AppBarLLMDropdown llms={llms} llmId={chatLLMId} setLlmId={setChatLLMId} />,
|
||||
[llms, chatLLMId, setChatLLMId],
|
||||
);
|
||||
|
||||
return { chatLLMId, chatLLMDropdown };
|
||||
}
|
||||
|
||||
export function useTempLLMDropdown(props: { initialLlmId: DLLMId | null }) {
|
||||
// local state
|
||||
const [llmId, setLlmId] = React.useState<DLLMId | null>(props.initialLlmId);
|
||||
|
||||
// external state
|
||||
const llms = useModelsStore(state => state.llms, shallow);
|
||||
|
||||
const chatLLMDropdown = React.useMemo(
|
||||
() => <AppBarLLMDropdown llms={llms} llmId={llmId} setLlmId={setLlmId} />,
|
||||
[llms, llmId, setLlmId],
|
||||
);
|
||||
|
||||
return { llmId, chatLLMDropdown };
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
import * as React from 'react';
|
||||
import { shallow } from 'zustand/shallow';
|
||||
|
||||
import { SystemPurposeId, SystemPurposes } from '../../../../data';
|
||||
|
||||
import { AppBarDropdown } from '~/common/layout/AppBarDropdown';
|
||||
import { useChatStore } from '~/common/state/store-chats';
|
||||
import { useUIPreferencesStore } from '~/common/state/store-ui';
|
||||
|
||||
|
||||
function AppBarPersonaDropdown(props: {
|
||||
systemPurposeId: SystemPurposeId | null,
|
||||
setSystemPurposeId: (systemPurposeId: SystemPurposeId | null) => void,
|
||||
}) {
|
||||
|
||||
// external state
|
||||
const { zenMode } = useUIPreferencesStore(state => ({
|
||||
zenMode: state.zenMode,
|
||||
}), shallow);
|
||||
|
||||
const handleSystemPurposeChange = (_event: any, value: SystemPurposeId | null) => props.setSystemPurposeId(value);
|
||||
|
||||
return (
|
||||
<AppBarDropdown
|
||||
items={SystemPurposes} showSymbols={zenMode !== 'cleaner'}
|
||||
value={props.systemPurposeId} onChange={handleSystemPurposeChange}
|
||||
/>
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
export function usePersonaIdDropdown(conversationId: string | null) {
|
||||
// external state
|
||||
const { systemPurposeId } = useChatStore(state => {
|
||||
const conversation = state.conversations.find(conversation => conversation.id === conversationId);
|
||||
return {
|
||||
systemPurposeId: conversation?.systemPurposeId ?? null,
|
||||
};
|
||||
}, shallow);
|
||||
|
||||
const personaDropdown = React.useMemo(() =>
|
||||
systemPurposeId ? <AppBarPersonaDropdown
|
||||
systemPurposeId={systemPurposeId}
|
||||
setSystemPurposeId={(systemPurposeId) => {
|
||||
if (conversationId && systemPurposeId)
|
||||
useChatStore.getState().setSystemPurposeId(conversationId, systemPurposeId);
|
||||
}}
|
||||
/> : null,
|
||||
[conversationId, systemPurposeId],
|
||||
);
|
||||
|
||||
return { personaDropdown };
|
||||
}
|
||||
Reference in New Issue
Block a user