From bb36dbc4b9f6dcb54a58995378678b799ef6bdae Mon Sep 17 00:00:00 2001 From: Enrico Ros Date: Tue, 21 Nov 2023 21:31:21 -0800 Subject: [PATCH] Removed the Labs page, removed a store --- docs/changelog.md | 2 +- pages/labs.tsx | 14 ---- .../components/applayout/ChatDrawerItems.tsx | 6 +- .../chat/components/composer/ChatModeMenu.tsx | 6 +- .../chat/components/composer/Composer.tsx | 3 +- .../persona-selector/PersonaSelector.tsx | 7 +- src/apps/labs/AppLabs.tsx | 68 ------------------- src/apps/settings-modal/UxLabsSettings.tsx | 51 +++++++------- src/common/app.routes.ts | 3 - .../components/forms/FormSwitchControl.tsx | 10 +-- src/common/components/forms/useFormRadio.tsx | 9 +-- src/common/state/store-ui.ts | 68 ++++++++----------- src/common/state/store-ux-labs.ts | 44 ++++++++++++ .../llms/vendors/openai/OpenAISourceSetup.tsx | 4 +- 14 files changed, 121 insertions(+), 174 deletions(-) delete mode 100644 pages/labs.tsx delete mode 100644 src/apps/labs/AppLabs.tsx create mode 100644 src/common/state/store-ux-labs.ts diff --git a/docs/changelog.md b/docs/changelog.md index 1b2a389a2..ea707938e 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -35,7 +35,7 @@ by release. - **Backup/Restore** - save chats, and restore them later - **[Local model support with Oobabooga server](../docs/config-local-oobabooga)** - run your own LLMs! - **Flatten conversations** - conversations summarizer with 4 modes -- **Fork conversations** - create a new chat, to experiment with different endings +- **Fork conversations** - create a new chat, to try with different endings - New commands: /s to add a System message, and /a for an Assistant message - New Chat modes: Write-only - just appends the message, without assistant response - Fix STOP generation - in sync with the Vercel team to fix a long-standing NextJS issue diff --git a/pages/labs.tsx b/pages/labs.tsx deleted file mode 100644 index 0efb28f6f..000000000 --- a/pages/labs.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import * as React from 'react'; - -import { AppLabs } from '../src/apps/labs/AppLabs'; - -import { AppLayout } from '~/common/layout/AppLayout'; - - -export default function LabsPage() { - return ( - - - - ); -} \ No newline at end of file diff --git a/src/apps/chat/components/applayout/ChatDrawerItems.tsx b/src/apps/chat/components/applayout/ChatDrawerItems.tsx index 3bc539ebc..824a4d36e 100644 --- a/src/apps/chat/components/applayout/ChatDrawerItems.tsx +++ b/src/apps/chat/components/applayout/ChatDrawerItems.tsx @@ -10,6 +10,7 @@ import { DConversationId, useChatStore } from '~/common/state/store-chats'; import { OpenAIIcon } from '~/common/components/icons/OpenAIIcon'; import { closeLayoutDrawer } from '~/common/layout/store-applayout'; import { useUIPreferencesStore } from '~/common/state/store-ui'; +import { useUXLabsStore } from '~/common/state/store-ux-labs'; import { ConversationItem } from './ConversationItem'; @@ -35,7 +36,8 @@ export function ChatDrawerItems(props: { conversationIDs: state.conversations.map(_c => _c.id), maxChatMessages: state.conversations.reduce((longest, _c) => Math.max(longest, _c.messages.length), 0), }), shallow); - const [experimentalLabs, showSymbols] = useUIPreferencesStore(state => [state.experimentalLabs, state.zenMode !== 'cleaner'], shallow); + const showSymbols = useUIPreferencesStore(state => state.zenMode !== 'cleaner'); + const labsEnhancedUI = useUXLabsStore(state => state.labsEnhancedUI); // derived state const totalConversations = conversationIDs.length; @@ -119,7 +121,7 @@ export function ChatDrawerItems(props: { conversationId={conversationId} isActive={conversationId === props.conversationId} isLonely={singleChat} - maxChatMessages={(experimentalLabs || softMaxReached) ? maxChatMessages : 0} + maxChatMessages={(labsEnhancedUI || softMaxReached) ? maxChatMessages : 0} showSymbols={showSymbols} onConversationActivate={handleConversationActivate} onConversationDelete={handleConversationDelete} diff --git a/src/apps/chat/components/composer/ChatModeMenu.tsx b/src/apps/chat/components/composer/ChatModeMenu.tsx index c5c5f5cef..018335264 100644 --- a/src/apps/chat/components/composer/ChatModeMenu.tsx +++ b/src/apps/chat/components/composer/ChatModeMenu.tsx @@ -5,6 +5,7 @@ import { Box, MenuItem, Radio, Typography } from '@mui/joy'; import { CloseableMenu } from '~/common/components/CloseableMenu'; import { KeyStroke } from '~/common/components/KeyStroke'; import { useUIPreferencesStore } from '~/common/state/store-ui'; +import { useUXLabsStore } from '~/common/state/store-ux-labs'; import { ChatModeId } from '../../AppChat'; @@ -48,10 +49,11 @@ function fixNewLineShortcut(shortcut: string, enterIsNewLine: boolean) { return shortcut; } -export function ChatModeMenu(props: { anchorEl: HTMLAnchorElement | null, onClose: () => void, experimental: boolean, chatModeId: ChatModeId, onSetChatModeId: (chatMode: ChatModeId) => void }) { +export function ChatModeMenu(props: { anchorEl: HTMLAnchorElement | null, onClose: () => void, chatModeId: ChatModeId, onSetChatModeId: (chatMode: ChatModeId) => void }) { // external state const enterIsNewline = useUIPreferencesStore(state => state.enterIsNewline); + const labsMagicDraw = useUXLabsStore(state => state.labsMagicDraw); return props.experimental || !experimental) + .filter(([, { experimental }]) => labsMagicDraw || !experimental) .map(([key, data]) => props.onSetChatModeId(key as ChatModeId)}> diff --git a/src/apps/chat/components/composer/Composer.tsx b/src/apps/chat/components/composer/Composer.tsx index 13922b643..bfe2f7d8e 100644 --- a/src/apps/chat/components/composer/Composer.tsx +++ b/src/apps/chat/components/composer/Composer.tsx @@ -137,7 +137,7 @@ export function Composer(props: { const isMobile = useIsMobile(); const [chatModeId, setChatModeId] = React.useState('immediate'); const [startupText, setStartupText] = useComposerStartupText(); - const [enterIsNewline, experimentalLabs] = useUIPreferencesStore(state => [state.enterIsNewline, state.experimentalLabs], shallow); + const enterIsNewline = useUIPreferencesStore(state => state.enterIsNewline); const { assistantTyping, systemPurposeId, tokenCount: conversationTokenCount, stopTyping } = useChatStore(state => { const conversation = state.conversations.find(_c => _c.id === props.conversationId); return { @@ -638,7 +638,6 @@ export function Composer(props: { {!!chatModeMenuAnchor && ( )} diff --git a/src/apps/chat/components/persona-selector/PersonaSelector.tsx b/src/apps/chat/components/persona-selector/PersonaSelector.tsx index 71579e29b..523e0cf8c 100644 --- a/src/apps/chat/components/persona-selector/PersonaSelector.tsx +++ b/src/apps/chat/components/persona-selector/PersonaSelector.tsx @@ -10,6 +10,7 @@ import TelegramIcon from '@mui/icons-material/Telegram'; import { DConversationId, useChatStore } from '~/common/state/store-chats'; import { Link } from '~/common/components/Link'; import { useUIPreferencesStore } from '~/common/state/store-ui'; +import { useUXLabsStore } from '~/common/state/store-ux-labs'; import { SystemPurposeId, SystemPurposes } from '../../../../data'; import { usePurposeStore } from './store-purposes'; @@ -46,6 +47,7 @@ export function PersonaSelector(props: { conversationId: DConversationId, runExa // external state const showFinder = useUIPreferencesStore(state => state.showPurposeFinder); + const labsPersonaYTCreator = useUXLabsStore(state => state.labsPersonaYTCreator); const { systemPurposeId, setSystemPurposeId } = useChatStore(state => { const conversation = state.conversations.find(conversation => conversation.id === props.conversationId); return { @@ -184,7 +186,7 @@ export function PersonaSelector(props: { conversationId: DConversationId, runExa ))} {/* Button to start the YouTube persona creator */} - + {labsPersonaYTCreator && - + } - ({ - experimentalLabs: state.experimentalLabs, setExperimentalLabs: state.setExperimentalLabs, - }), shallow); - - const handleLabsChange = (event: React.ChangeEvent) => setExperimentalLabs(event.target.checked); - - return ( - - - - - Labs - - - - - - - - - The Labs section is where we experiment with new features and ideas. - - - Features {experimentalLabs ? 'enabled' : 'disabled'}: - -
    -
  • Text tools - complete (highlight differences)
  • -
  • YouTube persona synthesizer - alpha, not persisted
  • -
  • Chat mode: follow-up/augmentation - alpha (diagrams)
  • -
  • Relative chats size - complete
  • -
- - For any questions and creative idea, please join us on Discord, and let's talk! - -
-
-
- - - -
- ); -} \ No newline at end of file diff --git a/src/apps/settings-modal/UxLabsSettings.tsx b/src/apps/settings-modal/UxLabsSettings.tsx index bbdfdd189..4a9f91745 100644 --- a/src/apps/settings-modal/UxLabsSettings.tsx +++ b/src/apps/settings-modal/UxLabsSettings.tsx @@ -1,41 +1,40 @@ import * as React from 'react'; -import { shallow } from 'zustand/shallow'; -import { Button, FormControl, Switch } from '@mui/joy'; +import { FormControl, Typography } from '@mui/joy'; import { FormLabelStart } from '~/common/components/forms/FormLabelStart'; -import { closeLayoutPreferences } from '~/common/layout/store-applayout'; -import { navigateToLabs } from '~/common/app.routes'; -import { useUIPreferencesStore } from '~/common/state/store-ui'; +import { FormSwitchControl } from '~/common/components/forms/FormSwitchControl'; +import { useUXLabsStore } from '~/common/state/store-ux-labs'; export function UxLabsSettings() { + // external state - const { - experimentalLabs, setExperimentalLabs, - } = useUIPreferencesStore(state => ({ - experimentalLabs: state.experimentalLabs, setExperimentalLabs: state.setExperimentalLabs, - }), shallow); - - const handleExperimentalLabsChange = (event: React.ChangeEvent) => setExperimentalLabs(event.target.checked); - + const { /*labsEnhancedUI,*/ labsMagicDraw, labsPersonaYTCreator, /*setLabsEnhancedUI,*/ setLabsMagicDraw, setLabsPersonaYTCreator } = useUXLabsStore(); return <> - - - - + - + {/**/} + + + + + + + Auto Diagrams · Relative chat size · Text Tools + + ; } \ No newline at end of file diff --git a/src/common/app.routes.ts b/src/common/app.routes.ts index 8d0ecd69e..d8c8bff20 100644 --- a/src/common/app.routes.ts +++ b/src/common/app.routes.ts @@ -8,7 +8,6 @@ import Router from 'next/router'; export const ROUTE_APP_CHAT = '/'; const APP_LINK_CHAT = '/link/chat/:linkId'; -const APP_LABS = '/labs'; export const getHomeLink = () => ROUTE_APP_CHAT; @@ -16,8 +15,6 @@ export const getChatLinkRelativePath = (chatLinkId: string) => APP_LINK_CHAT.rep export const navigateToChat = async () => await Router.push(ROUTE_APP_CHAT); -export const navigateToLabs = async () => await Router.push(APP_LABS); - export const navigateBack = Router.back; export interface AppCallQueryParams { diff --git a/src/common/components/forms/FormSwitchControl.tsx b/src/common/components/forms/FormSwitchControl.tsx index 51056738f..f369b885b 100644 --- a/src/common/components/forms/FormSwitchControl.tsx +++ b/src/common/components/forms/FormSwitchControl.tsx @@ -10,16 +10,18 @@ import { FormLabelStart } from './FormLabelStart'; */ export function FormSwitchControl(props: { title: string | React.JSX.Element, description?: string | React.JSX.Element, - value: boolean, onChange: (on: boolean) => void, + on?: string, off?: string, fullWidth?: boolean, + checked: boolean, onChange: (on: boolean) => void, }) { return ( props.onChange(event.target.checked)} - endDecorator={props.value ? 'Enabled' : 'Off'} - sx={{ flexGrow: 1 }} + endDecorator={props.checked ? props.on || 'On' : props.off || 'Off'} + sx={props.fullWidth ? { flexGrow: 1 } : undefined} + slotProps={{ endDecorator: { sx: { minWidth: 26 } } }} /> ); diff --git a/src/common/components/forms/useFormRadio.tsx b/src/common/components/forms/useFormRadio.tsx index 1fa857224..b6680d8d3 100644 --- a/src/common/components/forms/useFormRadio.tsx +++ b/src/common/components/forms/useFormRadio.tsx @@ -3,7 +3,7 @@ import * as React from 'react'; import { FormControl, FormLabel, Radio, RadioGroup } from '@mui/joy'; -export type FormRadioOption = { label: string, value: T, experimental?: boolean }; +export type FormRadioOption = { label: string, value: T, disabled?: boolean }; /** @@ -14,9 +14,6 @@ export function useFormRadio(initialValue: T, options: FormRad // state const [value, setValue] = React.useState(initialValue); - // external state - // const experimentalLabs = useUIPreferencesStore(state => state.experimentalLabs); - const handleChange = React.useCallback((event: React.ChangeEvent) => { setValue(event.target.value as T | null); }, []); @@ -31,10 +28,10 @@ export function useFormRadio(initialValue: T, options: FormRad value={value} onChange={handleChange} > {options.map((option) => - )} + )} , - [/*experimentalLabs,*/ handleChange, hidden, label, options, value], + [handleChange, hidden, label, options, value], ); return [value, component]; diff --git a/src/common/state/store-ui.ts b/src/common/state/store-ui.ts index 702594f38..f15d4092e 100644 --- a/src/common/state/store-ui.ts +++ b/src/common/state/store-ui.ts @@ -1,45 +1,13 @@ import { create } from 'zustand'; import { persist } from 'zustand/middleware'; -// UI Counters - -interface UICountersStore { - actionCounters: Record; - incrementActionCounter: (key: string) => void; - clearActionCounter: (key: string) => void; - clearAllActionCounters: () => void; -} - -const useUICountersStore = create()( - persist( - (set) => ({ - actionCounters: {}, - incrementActionCounter: (key: string) => - set((state) => ({ - actionCounters: { ...state.actionCounters, [key]: (state.actionCounters[key] || 0) + 1 }, - })), - clearActionCounter: (key: string) => - set((state) => ({ - actionCounters: { ...state.actionCounters, [key]: 0 }, - })), - clearAllActionCounters: () => set({ actionCounters: {} }), - }), - { - name: 'app-ui-counters', - }, - ), -); - -type UiCounterKey = 'export-share' | 'share-chat-link' | 'call-wizard'; - -export function useUICounter(key: UiCounterKey) { - const value = useUICountersStore((state) => state.actionCounters[key] || 0); - return { value, novel: !value, touch: () => useUICountersStore.getState().incrementActionCounter(key) }; -} // UI Preferences interface UIPreferencesStore { + + // UI Features + preferredLanguage: string; setPreferredLanguage: (preferredLanguage: string) => void; @@ -52,9 +20,6 @@ interface UIPreferencesStore { enterIsNewline: boolean; setEnterIsNewline: (enterIsNewline: boolean) => void; - experimentalLabs: boolean; - setExperimentalLabs: (experimentalLabs: boolean) => void; - renderMarkdown: boolean; setRenderMarkdown: (renderMarkdown: boolean) => void; @@ -64,12 +29,19 @@ interface UIPreferencesStore { zenMode: 'clean' | 'cleaner'; setZenMode: (zenMode: 'clean' | 'cleaner') => void; + // UI Counters + + actionCounters: Record; + incrementActionCounter: (key: string) => void; + } export const useUIPreferencesStore = create()( persist( (set) => ({ + // UI Features + preferredLanguage: (typeof navigator !== 'undefined') && navigator.language || 'en-US', setPreferredLanguage: (preferredLanguage: string) => set({ preferredLanguage }), @@ -82,9 +54,6 @@ export const useUIPreferencesStore = create()( enterIsNewline: false, setEnterIsNewline: (enterIsNewline: boolean) => set({ enterIsNewline }), - experimentalLabs: false, - setExperimentalLabs: (experimentalLabs: boolean) => set({ experimentalLabs }), - renderMarkdown: true, setRenderMarkdown: (renderMarkdown: boolean) => set({ renderMarkdown }), @@ -95,6 +64,14 @@ export const useUIPreferencesStore = create()( zenMode: 'clean', setZenMode: (zenMode: 'clean' | 'cleaner') => set({ zenMode }), + // UI Counters + + actionCounters: {}, + incrementActionCounter: (key: string) => + set((state) => ({ + actionCounters: { ...state.actionCounters, [key]: (state.actionCounters[key] || 0) + 1 }, + })), + }), { name: 'app-ui', @@ -113,3 +90,12 @@ export const useUIPreferencesStore = create()( }, ), ); + +export function useUICounter(key: 'export-share' | 'share-chat-link' | 'call-wizard') { + const value = useUIPreferencesStore((state) => state.actionCounters[key] || 0); + return { + value, + novel: !value, + touch: () => useUIPreferencesStore.getState().incrementActionCounter(key), + }; +} \ No newline at end of file diff --git a/src/common/state/store-ux-labs.ts b/src/common/state/store-ux-labs.ts new file mode 100644 index 000000000..8b6e8a095 --- /dev/null +++ b/src/common/state/store-ux-labs.ts @@ -0,0 +1,44 @@ +import { create } from 'zustand'; +import { persist } from 'zustand/middleware'; + + +// UX Labs Experiments + +/** + * Graduated: + * - Persona YT Creator: still under a 'true' flag, to disable it if needed + * - Text Tools: dinamically shown where applicable + * - Chat Mode: follow-ups; moved to Chat Advanced UI, itemized (Auto-title, Auto-diagram) + */ +interface UXLabsStore { + + labsEnhancedUI: boolean; + setLabsEnhancedUI: (labsEnhancedUI: boolean) => void; + + labsMagicDraw: boolean; + setLabsMagicDraw: (labsMagicDraw: boolean) => void; + + labsPersonaYTCreator: boolean; + setLabsPersonaYTCreator: (labsPersonaYTCreator: boolean) => void; + +} + +export const useUXLabsStore = create()( + persist( + (set) => ({ + + labsEnhancedUI: false, + setLabsEnhancedUI: (labsEnhancedUI: boolean) => set({ labsEnhancedUI }), + + labsMagicDraw: false, + setLabsMagicDraw: (labsMagicDraw: boolean) => set({ labsMagicDraw }), + + labsPersonaYTCreator: true, // NOTE: default to true, as it is a graduated experiment + setLabsPersonaYTCreator: (labsPersonaYTCreator: boolean) => set({ labsPersonaYTCreator }), + + }), + { + name: 'app-ux-labs', + }, + ), +); \ No newline at end of file diff --git a/src/modules/llms/vendors/openai/OpenAISourceSetup.tsx b/src/modules/llms/vendors/openai/OpenAISourceSetup.tsx index e23d93dcf..2a0ad0545 100644 --- a/src/modules/llms/vendors/openai/OpenAISourceSetup.tsx +++ b/src/modules/llms/vendors/openai/OpenAISourceSetup.tsx @@ -95,12 +95,12 @@ export function OpenAISourceSetup(props: { sourceId: DModelSourceId }) { } {advanced.on && Overview, {' '}policy } - value={moderationCheck} + checked={moderationCheck} onChange={on => updateSetup({ moderationCheck: on })} />}