Compare commits

...

6 Commits

Author SHA1 Message Date
Enrico Ros 343c89074a Support Unset System Purpose 2023-08-17 00:08:34 -07:00
Enrico Ros fc1306eb96 Remove Default (first) Conversation - useEffect instead (is this correct?) 2023-08-17 00:08:34 -07:00
Enrico Ros 5e11575b6a Remove Default SystemPurposeID 2023-08-17 00:08:34 -07:00
Enrico Ros fb8791aff4 Remove Hidden purposes (and edit stuff) 2023-08-17 00:08:34 -07:00
Enrico Ros 9353666154 Remove Custom Purposes 2023-08-17 00:08:34 -07:00
Enrico Ros bcc31d5ab9 Remove purpose Finder 2023-08-17 00:08:28 -07:00
10 changed files with 37 additions and 194 deletions
+5
View File
@@ -74,6 +74,11 @@ export function AppChat() {
};
}, shallow);
// [0 to 1] create a conversation if there's none active
React.useEffect(() => {
if (!activeConversationId)
useChatStore.getState().conversations.length === 0 && useChatStore.getState().createConversation();
}, [activeConversationId]);
const handleExecuteConversation = async (chatModeId: ChatModeId, conversationId: string, history: DMessage[]) => {
const { chatLLMId } = useModelsStore.getState();
@@ -26,10 +26,10 @@ export function ChatDropdowns(props: {
}), shallow);
const { zenMode } = useUIPreferencesStore(state => ({ zenMode: state.zenMode }), shallow);
const { systemPurposeId, setSystemPurposeId } = useChatStore(state => {
const { systemPurposeValue, setSystemPurposeId } = useChatStore(state => {
const conversation = state.conversations.find(conversation => conversation.id === props.conversationId);
return {
systemPurposeId: conversation?.systemPurposeId ?? null,
systemPurposeValue: conversation?.systemPurposeId ?? null,
setSystemPurposeId: state.setSystemPurposeId,
};
}, shallow);
@@ -82,12 +82,11 @@ export function ChatDropdowns(props: {
/>
{/* Persona selector */}
{systemPurposeId && (
<AppBarDropdown
items={SystemPurposes} showSymbols={zenMode !== 'cleaner'}
value={systemPurposeId} onChange={handleSystemPurposeChange}
/>
)}
<AppBarDropdown
items={SystemPurposes} showSymbols={zenMode !== 'cleaner'}
value={systemPurposeValue} onChange={handleSystemPurposeChange}
placeholder='Personas …'
/>
</>;
}
@@ -83,7 +83,7 @@ export function ConversationItem(props: {
const handleDeleteCancel = () => setDeleteArmed(false);
const textSymbol = SystemPurposes[systemPurposeId]?.symbol || '❓';
const textSymbol = (systemPurposeId && SystemPurposes[systemPurposeId]?.symbol) || '❓';
const buttonSx: SxProps = { ml: 1, ...(props.isActive ? { color: 'white' } : {}) };
const progress = props.maxChatMessages ? 100 * messageCount / props.maxChatMessages : 0;
@@ -1,10 +1,8 @@
import * as React from 'react';
import { shallow } from 'zustand/shallow';
import { Box, Button, Checkbox, Grid, IconButton, Input, Stack, Textarea, Typography } from '@mui/joy';
import ClearIcon from '@mui/icons-material/Clear';
import { Box, Button, Grid, IconButton, Stack, Typography } from '@mui/joy';
import ScienceIcon from '@mui/icons-material/Science';
import SearchIcon from '@mui/icons-material/Search';
import TelegramIcon from '@mui/icons-material/Telegram';
import { Link } from '~/common/components/Link';
@@ -12,7 +10,6 @@ import { useChatStore } from '~/common/state/store-chats';
import { useUIPreferencesStore } from '~/common/state/store-ui';
import { SystemPurposeId, SystemPurposes } from '../../../../data';
import { usePurposeStore } from './store-purposes';
// Constants for tile sizes / grid width - breakpoints need to be computed here to work around
@@ -40,104 +37,34 @@ const getRandomElement = <T, >(array: T[]): T | undefined =>
*/
export function PersonaSelector(props: { conversationId: string, runExample: (example: string) => void }) {
// state
const [searchQuery, setSearchQuery] = React.useState('');
const [filteredIDs, setFilteredIDs] = React.useState<SystemPurposeId[] | null>(null);
const [editMode, setEditMode] = React.useState(false);
// const [editMode, setEditMode] = React.useState(false);
const editMode = false;
// external state
const { experimentalLabs, showFinder } = useUIPreferencesStore(state => ({
const { experimentalLabs } = useUIPreferencesStore(state => ({
experimentalLabs: state.experimentalLabs,
showFinder: state.showPurposeFinder,
}), shallow);
const { systemPurposeId, setSystemPurposeId } = useChatStore(state => {
const conversation = state.conversations.find(conversation => conversation.id === props.conversationId);
return {
systemPurposeId: conversation ? conversation.systemPurposeId : null,
setSystemPurposeId: conversation ? state.setSystemPurposeId : null,
setSystemPurposeId: state.setSystemPurposeId,
};
}, shallow);
const { hiddenPurposeIDs, toggleHiddenPurposeId } = usePurposeStore(state => ({ hiddenPurposeIDs: state.hiddenPurposeIDs, toggleHiddenPurposeId: state.toggleHiddenPurposeId }), shallow);
// safety check - shouldn't happen
if (!systemPurposeId || !setSystemPurposeId)
return null;
const handleSearchClear = () => {
setSearchQuery('');
setFilteredIDs(null);
};
const handleSearchOnChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const query = e.target.value;
if (!query)
return handleSearchClear();
setSearchQuery(query);
// Filter results based on search term
const ids = Object.keys(SystemPurposes)
.filter(key => SystemPurposes.hasOwnProperty(key))
.filter(key => {
const purpose = SystemPurposes[key as SystemPurposeId];
return purpose.title.toLowerCase().includes(query.toLowerCase())
|| (typeof purpose.description === 'string' && purpose.description.toLowerCase().includes(query.toLowerCase()));
});
setFilteredIDs(ids as SystemPurposeId[]);
// If there's a search term, activate the first item
if (ids.length && !ids.includes(systemPurposeId))
handlePurposeChanged(ids[0] as SystemPurposeId);
};
const handleSearchOnKeyDown = (e: React.KeyboardEvent<HTMLInputElement>): void => {
if (e.key == 'Escape')
handleSearchClear();
};
const toggleEditMode = () => setEditMode(!editMode);
const handlePurposeChanged = (purposeId: SystemPurposeId | null) => {
if (purposeId)
setSystemPurposeId(props.conversationId, purposeId);
};
const handleCustomSystemMessageChange = (v: React.ChangeEvent<HTMLTextAreaElement>): void => {
// TODO: persist this change? Right now it's reset every time.
// maybe we shall have a "save" button just save on a state to persist between sessions
SystemPurposes['Custom'].systemMessage = v.target.value;
};
// we show them all if the filter is clear (null)
const unfilteredPurposeIDs = (filteredIDs && showFinder) ? filteredIDs : Object.keys(SystemPurposes);
const purposeIDs = editMode ? unfilteredPurposeIDs : unfilteredPurposeIDs.filter(id => !hiddenPurposeIDs.includes(id));
const purposeIDs = Object.keys(SystemPurposes);
const selectedPurpose = purposeIDs.length ? (SystemPurposes[systemPurposeId] ?? null) : null;
const selectedPurpose = (purposeIDs.length && systemPurposeId) ? (SystemPurposes[systemPurposeId] ?? null) : null;
const selectedExample = selectedPurpose?.examples && getRandomElement(selectedPurpose.examples) || null;
return <>
{showFinder && <Box sx={{ p: 2 * tileSpacing }}>
<Input
fullWidth
variant='outlined' color='neutral'
value={searchQuery} onChange={handleSearchOnChange}
onKeyDown={handleSearchOnKeyDown}
placeholder='Search for purpose…'
startDecorator={<SearchIcon />}
endDecorator={searchQuery && (
<IconButton variant='plain' color='neutral' onClick={handleSearchClear}>
<ClearIcon />
</IconButton>
)}
sx={{
boxShadow: 'sm',
}}
/>
</Box>}
<Stack direction='column' sx={{ minHeight: '60vh', justifyContent: 'center', alignItems: 'center' }}>
<Box sx={{ maxWidth: bpMaxWidth }}>
@@ -146,9 +73,9 @@ export function PersonaSelector(props: { conversationId: string, runExample: (ex
<Typography level='title-sm'>
AI Persona
</Typography>
<Button variant='plain' color='neutral' size='sm' onClick={toggleEditMode}>
{editMode ? 'Done' : 'Edit'}
</Button>
{/*<Button variant='plain' color='neutral' size='sm' onClick={toggleEditMode}>*/}
{/* {editMode ? 'Done' : 'Edit'}*/}
{/*</Button>*/}
</Box>
<Grid container spacing={tileSpacing} sx={{ justifyContent: 'flex-start' }}>
@@ -170,13 +97,13 @@ export function PersonaSelector(props: { conversationId: string, runExample: (ex
} : {}),
}}
>
{editMode && (
<Checkbox
label={<Typography level='body-sm'>show</Typography>}
checked={!hiddenPurposeIDs.includes(spId)} onChange={() => toggleHiddenPurposeId(spId)}
sx={{ alignSelf: 'flex-start' }}
/>
)}
{/*{editMode && (*/}
{/* <Checkbox*/}
{/* label={<Typography level='body-sm'>show</Typography>}*/}
{/* checked={!hiddenPurposeIDs.includes(spId)} onChange={() => toggleHiddenPurposeId(spId)}*/}
{/* sx={{ alignSelf: 'flex-start' }}*/}
{/* />*/}
{/*)}*/}
<div style={{ fontSize: '2rem' }}>
{SystemPurposes[spId as SystemPurposeId]?.symbol}
</div>
@@ -238,21 +165,6 @@ export function PersonaSelector(props: { conversationId: string, runExample: (ex
)}
</Typography>
{systemPurposeId === 'Custom' && (
<Textarea
variant='outlined' autoFocus placeholder={'Craft your custom system message here…'}
minRows={3}
defaultValue={SystemPurposes['Custom']?.systemMessage} onChange={handleCustomSystemMessageChange}
sx={{
backgroundColor: 'background.level1',
'&:focus-within': {
backgroundColor: 'background.popup',
},
lineHeight: 1.75,
mt: 1,
}} />
)}
</Box>
</Stack>
@@ -1,38 +0,0 @@
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
interface PurposeStore {
// state
hiddenPurposeIDs: string[];
// actions
toggleHiddenPurposeId: (purposeId: string) => void;
}
export const usePurposeStore = create<PurposeStore>()(
persist(
(set) => ({
// default state
hiddenPurposeIDs: ['Designer'],
toggleHiddenPurposeId: (purposeId: string) => {
set(state => {
const hiddenPurposeIDs = state.hiddenPurposeIDs.includes(purposeId)
? state.hiddenPurposeIDs.filter((id) => id !== purposeId)
: [...state.hiddenPurposeIDs, purposeId];
return {
hiddenPurposeIDs,
};
});
},
}),
{
name: 'app-purpose',
}),
);
+1 -3
View File
@@ -1,7 +1,5 @@
import { fileSave } from 'browser-fs-access';
import { defaultSystemPurposeId } from '../../../data';
import { DModelSource } from '~/modules/llms/llm.types';
import { useModelsStore } from '~/modules/llms/store-llms';
@@ -56,7 +54,7 @@ function restoreDConversationFromJson(fileName: string, part: Partial<DConversat
const restored: DConversation = {
id: part.id,
messages: part.messages,
systemPurposeId: part.systemPurposeId || defaultSystemPurposeId,
systemPurposeId: part.systemPurposeId || undefined,
...(part.userTitle && { userTitle: part.userTitle }),
...(part.autoTitle && { autoTitle: part.autoTitle }),
tokenCount: part.tokenCount || 0,
-17
View File
@@ -14,9 +14,6 @@ import { isPwa } from '~/common/util/pwaUtils';
import { useUIPreferencesStore, useUIStateStore } from '~/common/state/store-ui';
// configuration
const SHOW_PURPOSE_FINDER = false;
export function UISettings() {
// external state
@@ -26,7 +23,6 @@ export function UISettings() {
enterToSend, setEnterToSend,
experimentalLabs, setExperimentalLabs,
renderMarkdown, setRenderMarkdown,
showPurposeFinder, setShowPurposeFinder,
zenMode, setZenMode,
} = useUIPreferencesStore(state => ({
centerMode: state.centerMode, setCenterMode: state.setCenterMode,
@@ -34,7 +30,6 @@ export function UISettings() {
enterToSend: state.enterToSend, setEnterToSend: state.setEnterToSend,
experimentalLabs: state.experimentalLabs, setExperimentalLabs: state.setExperimentalLabs,
renderMarkdown: state.renderMarkdown, setRenderMarkdown: state.setRenderMarkdown,
showPurposeFinder: state.showPurposeFinder, setShowPurposeFinder: state.setShowPurposeFinder,
zenMode: state.zenMode, setZenMode: state.setZenMode,
}), shallow);
const { closeSettings } = useUIStateStore(state => ({ closeSettings: state.closeSettings }), shallow);
@@ -51,8 +46,6 @@ export function UISettings() {
const handleExperimentalLabsChange = (event: React.ChangeEvent<HTMLInputElement>) => setExperimentalLabs(event.target.checked);
const handleShowSearchBarChange = (event: React.ChangeEvent<HTMLInputElement>) => setShowPurposeFinder(event.target.checked);
return (
<Stack direction='column' sx={{ gap: settingsGap }}>
@@ -99,16 +92,6 @@ export function UISettings() {
slotProps={{ endDecorator: { sx: { minWidth: 26 } } }} />
</FormControl>
{SHOW_PURPOSE_FINDER && <FormControl orientation='horizontal' sx={{ justifyContent: 'space-between' }}>
<Box>
<FormLabel>Purpose finder</FormLabel>
<FormHelperText>{showPurposeFinder ? 'Show search bar' : 'Hide search bar'}</FormHelperText>
</Box>
<Switch checked={showPurposeFinder} onChange={handleShowSearchBarChange}
endDecorator={showPurposeFinder ? 'On' : 'Off'}
slotProps={{ endDecorator: { sx: { minWidth: 26 } } }} />
</FormControl>}
<FormControl orientation='horizontal' sx={{ alignItems: 'center', justifyContent: 'space-between' }}>
<Box>
<FormLabel>Appearance</FormLabel>
+5 -7
View File
@@ -5,8 +5,8 @@ import { v4 as uuidv4 } from 'uuid';
import { DLLMId } from '~/modules/llms/llm.types';
import { useModelsStore } from '~/modules/llms/store-llms';
import { SystemPurposeId } from '../../data';
import { countModelTokens } from '../util/token-counter';
import { defaultSystemPurposeId, SystemPurposeId } from '../../data';
// configuration
@@ -22,7 +22,7 @@ export const MAX_CONVERSATIONS = 20;
export interface DConversation {
id: string;
messages: DMessage[];
systemPurposeId: SystemPurposeId;
systemPurposeId: SystemPurposeId | undefined;
userTitle?: string;
autoTitle?: string;
tokenCount: number; // f(messages, llmId)
@@ -37,7 +37,7 @@ export function createDConversation(systemPurposeId?: SystemPurposeId): DConvers
return {
id: uuidv4(),
messages: [],
systemPurposeId: systemPurposeId || defaultSystemPurposeId,
systemPurposeId: systemPurposeId || undefined,
tokenCount: 0,
created: Date.now(),
updated: Date.now(),
@@ -46,8 +46,6 @@ export function createDConversation(systemPurposeId?: SystemPurposeId): DConvers
};
}
const defaultConversations: DConversation[] = [createDConversation()];
/**
* Message, sent or received, by humans or bots
*
@@ -148,8 +146,8 @@ export const useChatStore = create<ChatStore>()(devtools(
(set, get) => ({
// default state
conversations: defaultConversations,
activeConversationId: defaultConversations[0].id,
conversations: [],
activeConversationId: null,
createConversation: () =>
-6
View File
@@ -63,9 +63,6 @@ interface UIPreferencesStore {
renderMarkdown: boolean;
setRenderMarkdown: (renderMarkdown: boolean) => void;
showPurposeFinder: boolean;
setShowPurposeFinder: (showPurposeFinder: boolean) => void;
showSystemMessages: boolean;
setShowSystemMessages: (showSystemMessages: boolean) => void;
@@ -96,9 +93,6 @@ export const useUIPreferencesStore = create<UIPreferencesStore>()(
renderMarkdown: false,
setRenderMarkdown: (renderMarkdown: boolean) => set({ renderMarkdown }),
showPurposeFinder: false,
setShowPurposeFinder: (showPurposeFinder: boolean) => set({ showPurposeFinder }),
showSystemMessages: false,
setShowSystemMessages: (showSystemMessages: boolean) => set({ showSystemMessages }),
+1 -9
View File
@@ -1,8 +1,6 @@
import * as React from 'react';
export type SystemPurposeId = 'Catalyst' | 'Custom' | 'Designer' | 'Developer' | 'Executive' | 'Generic' | 'Scientist';
export const defaultSystemPurposeId: SystemPurposeId = 'Generic';
export type SystemPurposeId = 'Catalyst' | 'Designer' | 'Developer' | 'Executive' | 'Generic' | 'Scientist';
type SystemPurposeData = {
title: string;
@@ -58,10 +56,4 @@ export const SystemPurposes: { [key in SystemPurposeId]: SystemPurposeData } = {
symbol: '🧠',
examples: ['help me plan a trip to Japan', 'what is the meaning of life?', 'how do I get a job at OpenAI?', 'what are some healthy meal ideas?'],
},
Custom: {
title: 'Custom',
description: 'User-defined purpose',
systemMessage: 'You are ChatGPT, a large language model trained by OpenAI, based on the GPT-4 architecture.\nCurrent date: {{Today}}',
symbol: '✨',
},
};