New Voice Chat intent

This commit is contained in:
Enrico Ros
2024-12-30 12:03:13 -08:00
parent ff1d3686b6
commit 66572a970f
5 changed files with 68 additions and 20 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

+12
View File
@@ -66,6 +66,18 @@
"type": "image/png"
}
]
},
{
"name": "New Voice Chat",
"url": "/?newChat=voiceInput",
"description": "Start a new chat with voice input",
"icons": [
{
"src": "/icons/icon-voicechat-96x96.png",
"sizes": "96x96",
"type": "image/png"
}
]
}
]
}
+28 -18
View File
@@ -61,7 +61,8 @@ export const CHAT_NOVEL_TITLE = 'Chat';
export interface AppChatIntent {
initialConversationId: string | null;
initialConversationId?: string;
newChat?: 'voiceInput';
}
const scrollToBottomSx = {
@@ -200,23 +201,6 @@ export function AppChat() {
showNextTitleChange.current = true;
}, [navigateHistoryInFocusedPane]);
// [effect] Handle the initial conversation intent
React.useEffect(() => {
if (Release.IsNodeDevBuild && intent.initialConversationId === 'null')
return openConversationInFocusedPane(null! /* for debugging purporse */);
intent.initialConversationId && openConversationInFocusedPane(intent.initialConversationId);
}, [intent.initialConversationId, openConversationInFocusedPane]);
// [effect] Show snackbar with the focused chat title after a history navigation in focused pane
React.useEffect(() => {
if (showNextTitleChange.current) {
showNextTitleChange.current = false;
const title = (focusedChatNumber >= 0 ? `#${focusedChatNumber + 1} · ` : '') + (focusedChatTitle || 'New Chat');
const id = addSnackbar({ key: 'focused-title', message: title, type: 'center-title' });
return () => removeSnackbar(id);
}
}, [focusedChatNumber, focusedChatTitle]);
// Execution
@@ -485,6 +469,32 @@ export function AppChat() {
useSetOptimaAppMenu(focusedMenuItems, 'AppChat');
// Effects
// [effect] Handle the conversation intent
React.useEffect(() => {
// Debug: open a null chat
if (Release.IsNodeDevBuild && intent.initialConversationId === 'null')
openConversationInFocusedPane(null! /* for debugging purporse */);
// Open the initial conversation if set
else if (intent.initialConversationId)
openConversationInFocusedPane(intent.initialConversationId);
// Create a new chat if requested
else if (intent.newChat !== undefined)
handleConversationNewInFocusedPane(false, false);
}, [handleConversationNewInFocusedPane, intent.initialConversationId, intent.newChat, openConversationInFocusedPane]);
// [effect] Show snackbar with the focused chat title after a history navigation in focused pane
React.useEffect(() => {
if (showNextTitleChange.current) {
showNextTitleChange.current = false;
const title = (focusedChatNumber >= 0 ? `#${focusedChatNumber + 1} · ` : '') + (focusedChatTitle || 'New Chat');
const id = addSnackbar({ key: 'focused-title', message: title, type: 'center-title' });
return () => removeSnackbar(id);
}
}, [focusedChatNumber, focusedChatTitle]);
// Shortcuts
const handleOpenChatLlmOptions = React.useCallback(() => {
+11 -1
View File
@@ -13,6 +13,7 @@ import SendIcon from '@mui/icons-material/Send';
import StopOutlinedIcon from '@mui/icons-material/StopOutlined';
import TelegramIcon from '@mui/icons-material/Telegram';
import type { AppChatIntent } from '../../AppChat';
import { useChatAutoSuggestAttachmentPrompts, useChatMicTimeoutMsValue } from '../../store-app-chat';
import { useAgiAttachmentPrompts } from '~/modules/aifn/agiattachmentprompts/useAgiAttachmentPrompts';
@@ -36,7 +37,7 @@ import { createTextContentFragment, DMessageAttachmentFragment, DMessageContentF
import { estimateTextTokens, glueForMessageTokens, marshallWrapDocFragments } from '~/common/stores/chat/chat.tokens';
import { getConversation, isValidConversation, useChatStore } from '~/common/stores/chat/store-chats';
import { getModelParameterValueOrThrow } from '~/common/stores/llms/llms.parameters';
import { launchAppCall } from '~/common/app.routes';
import { launchAppCall, removeQueryParam, useRouterQuery } from '~/common/app.routes';
import { lineHeightTextareaMd } from '~/common/app.theme';
import { optimaOpenPreferences } from '~/common/layout/optima/useOptima';
import { platformAwareKeystrokes } from '~/common/components/KeyStroke';
@@ -125,6 +126,7 @@ export function Composer(props: {
// external state
const { showPromisedOverlay } = useOverlayComponents();
const { newChat: appChatNewChatIntent } = useRouterQuery<Partial<AppChatIntent>>();
const { labsAttachScreenCapture, labsCameraDesktop, labsShowCost, labsShowShortcutBar } = useUXLabsStore(useShallow(state => ({
labsAttachScreenCapture: state.labsAttachScreenCapture,
labsCameraDesktop: state.labsCameraDesktop,
@@ -398,6 +400,14 @@ export function Composer(props: {
});
}, [speechInterimResult]);
React.useEffect(() => {
// auto-start the microphone if appChat was created with a particular intent
if (appChatNewChatIntent === 'voiceInput') {
toggleRecognition();
void removeQueryParam('newChat');
}
}, [appChatNewChatIntent, toggleRecognition]);
// Other send actins
+17 -1
View File
@@ -79,6 +79,7 @@ export async function launchAppChat(conversationId?: DConversationId) {
pathname: ROUTE_APP_CHAT,
query: !conversationId ? undefined : {
initialConversationId: conversationId,
// newChat?: 'voiceInput',
} satisfies AppChatIntent,
},
ROUTE_APP_CHAT,
@@ -97,4 +98,19 @@ export function launchAppCall(conversationId: string, personaId: string) {
},
// ROUTE_APP_CALL,
).then();
}
}
/// Query Params utilities
export function removeQueryParam(key: string): Promise<boolean> {
const newQuery = { ...Router.query };
delete newQuery[key];
return Router.replace({ pathname: Router.pathname, query: newQuery }, undefined, { shallow: true });
}
/*export function removeQueryParams(keysToRemove: string[]): Promise<boolean> {
const newQuery = { ...Router.query };
keysToRemove.forEach(key => delete newQuery[key]);
return Router.replace({ pathname: Router.pathname, query: newQuery }, undefined, { shallow: true });
}*/