Skip to content

Commit

Permalink
Merge pull request #212 from amosproj/204-query-and-display-multiple-…
Browse files Browse the repository at this point in the history
…llm-responses-simultaneously---frontend

Multiple llm selection menu & chat UI integration  
Wrong linting comes from code that is not ours
  • Loading branch information
eloinoel authored Jun 25, 2024
2 parents 72a1d7b + 1d6fc71 commit 11e0b9f
Show file tree
Hide file tree
Showing 23 changed files with 405 additions and 281 deletions.
Binary file not shown.
Binary file not shown.
14 changes: 8 additions & 6 deletions src/frontend/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { PaperProvider } from 'react-native-paper';
import { SafeAreaProvider, SafeAreaView } from 'react-native-safe-area-context';
import Toast from 'react-native-toast-message';
import AwesomeIcon from 'react-native-vector-icons/FontAwesome5';
import { FirebaseProvider, UpdateApp } from './components';
import { ActiveChatProvider, FirebaseProvider, UpdateApp } from './components';
import { Fonts, LightTheme } from './helpers';
import { AppRoutes } from './routes';

Expand Down Expand Up @@ -43,11 +43,13 @@ export function App() {
theme={LightTheme}
settings={{ icon: (props) => <AwesomeIcon {...props} /> }}
>
<FirebaseProvider>
<AppRoutes />
<Toast />
<UpdateApp />
</FirebaseProvider>
<ActiveChatProvider>
<FirebaseProvider>
<AppRoutes />
<Toast />
<UpdateApp />
</FirebaseProvider>
</ActiveChatProvider>
</PaperProvider>
</GestureHandlerRootView>
</SafeAreaView>
Expand Down
9 changes: 0 additions & 9 deletions src/frontend/TO INTEGRATE - Chat UI/app/_layout.tsx

This file was deleted.

31 changes: 0 additions & 31 deletions src/frontend/TO INTEGRATE - Chat UI/app/index.tsx

This file was deleted.

103 changes: 0 additions & 103 deletions src/frontend/TO INTEGRATE - Chat UI/components/ChatUI.tsx

This file was deleted.

33 changes: 33 additions & 0 deletions src/frontend/components/ActiveChatProvider/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React, { type ReactNode, createContext, useState, useContext, type Dispatch, type SetStateAction } from 'react';

// Define the shape of the context value
interface ChatContextValue {
activeChatId: string;
setActiveChatId: Dispatch<SetStateAction<string>>;
}

// Define the default context value
const defaultContextValue: ChatContextValue = {
activeChatId: 'default',
setActiveChatId: () => {},
};

// Create a context with the default value
export const ChatContext = createContext<ChatContextValue>(defaultContextValue);

type ActiveChatProviderProps = {
children: ReactNode;
};

// Create a provider component
export const ActiveChatProvider = (props: ActiveChatProviderProps ) => {
const [activeChatId, setActiveChatId] = useState<string>('default'); // initial active chat id is -1
const { children } = props;

return (
<ChatContext.Provider value={{ activeChatId, setActiveChatId }}>
{children}
</ChatContext.Provider>
);
};

12 changes: 8 additions & 4 deletions src/frontend/components/ChatItem/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,20 @@ import React, { useEffect, useState } from 'react';
import { Keyboard, View } from 'react-native';
import { Button, Menu, Text } from 'react-native-paper';
import { Screens } from 'src/frontend/helpers';
import { useDeleteChat, useGetChat } from 'src/frontend/hooks';
import { useDeleteChat, useGetChat, useActiveChatId } from 'src/frontend/hooks';
import type { AppRoutesParams } from 'src/frontend/routes';

type ChatItemProps = {
export type ChatItemProps = {
id: string;
title: string;
};

export function ChatItem(props: ChatItemProps) {
const { activeChatId, setActiveChatId } = useActiveChatId();
const { id, title } = props;
//const { chat } = useGetChat(id);
const [isMenuVisible, setMenuVisible] = useState(false);
const drawerStatus = useDrawerStatus();
const { chat } = useGetChat(id);
const { handleDelete } = useDeleteChat(id);
const { navigate } = useNavigation<NativeStackNavigationProp<AppRoutesParams>>();

Expand All @@ -39,7 +40,10 @@ export function ChatItem(props: ChatItemProps) {
anchor={
<Button
textColor='black'
onPress={() => navigate('Main', { screen: Screens.Chat, params: { chatId: id } })}
onPress={() => {
setActiveChatId(id)
navigate('Main', { screen: Screens.Chat, params: { chatId: id } })
}}
onLongPress={() => setMenuVisible(true)}
style={{}}
contentStyle={{ justifyContent: 'flex-start', paddingLeft: 16 }}
Expand Down
108 changes: 62 additions & 46 deletions src/frontend/components/DropdownMenu/index.tsx
Original file line number Diff line number Diff line change
@@ -1,62 +1,78 @@
import { type RouteProp, useRoute } from '@react-navigation/native';
import React, { useMemo, useState } from 'react';
import { Button, Menu } from 'react-native-paper';
import { useGetChat, useUpdateChat } from 'src/frontend/hooks';
import React, { useEffect, useState } from 'react';
import { Button, Menu, Checkbox, List } from 'react-native-paper';
import type { MainDrawerParams } from 'src/frontend/routes/MainRoutes';
import { useLLMs } from 'src/frontend/hooks/useLLMs';
import { View } from 'react-native';
import { Style } from './style';
import { useActiveChatId, useGetAllChat, useGetChat} from 'src/frontend/hooks';
import type { Chat } from 'src/frontend/types';
import type { ChatItemProps } from 'src/frontend/components/ChatItem'


export const DropdownMenu = () => {
const router = useRoute<RouteProp<MainDrawerParams>>();
const chatId = router.params?.chatId;
// get chatID after opening app copilot help
const route = useRoute<RouteProp<MainDrawerParams>>();
const chatId = route.params?.chatId;
const [isVisible, setIsVisible] = useState(false);
const { chat, status } = useGetChat(chatId || 'default');
const { updateChat, isUpdating } = useUpdateChat(chatId || 'default');
const { activeLLMs, toggleLLM } = useLLMs(chatId || 'default');

const { activeChatId, setActiveChatId } = useActiveChatId();
const { chat, status, error } = useGetChat(activeChatId);

const activeLLMsCount = Object.values(activeLLMs).filter(llm => llm.active).length;
const activeLLMsNames = Object.values(activeLLMs).filter(llm => llm.active).map(llm => llm.name);
let buttonLabel = activeLLMsCount === 1 ? activeLLMsNames[0] : `${activeLLMsCount} LLMs`;

const llmModels: { [key: string]: string } = useMemo(() => {
return {
'gpt-4': 'OpenAi',
'google-gemini': 'Gemini',
'mistral-ai': 'Mistral',
'claude-ai': 'Claude'
};
}, []);
// If no chatId is selected, set button label to "SELECT"
if (chat === undefined) {
buttonLabel = "";
}

const handleLLMModelChange = async (model: string) => {
setIsVisible(false);
try {
await updateChat({ model: model });
} catch (error) {
console.error(error);
}
};
// Determine if the button should be disabled
const isButtonDisabled = chat === undefined || activeLLMsCount === 0;

return (
<Menu
visible={isVisible}
onDismiss={() => setIsVisible(false)}
anchorPosition='bottom'
anchor={
<Button
mode='outlined'
onPress={() => setIsVisible(true)}
icon={'brain'}
loading={status === 'loading' || isUpdating}
>
{llmModels[chat?.model || 'gpt-4']}
</Button>
}
>
{Object.entries(llmModels).map((model) => {
const [key, value] = model;
return (
<Menu
visible={isVisible}
onDismiss={() => setIsVisible(false)}
anchor={
<Button
mode="outlined"
onPress={() => setIsVisible(true)}
icon="brain"
loading={status === 'loading'}
disabled={isButtonDisabled}
>
{buttonLabel}
</Button>
}
>
<List.Section>
{Object.entries(activeLLMs).map(([key, llm]) => (
<Menu.Item
key={key}
onPress={async () => {
await handleLLMModelChange(key);
onPress={() => {
if (activeLLMsCount > 1 || !llm.active) {
toggleLLM(key);
}
}}
title={value}
title={
<View style={Style.menuItem}>
<List.Item
title={llm.name}
style={{ flex: 1 }}
/>
<Checkbox
status={llm.active ? 'checked' : 'unchecked'}
disabled={activeLLMsCount === 1 && llm.active}
/>
</View>
}
/>
);
})}
))}
</List.Section>
</Menu>
);
};
Loading

0 comments on commit 11e0b9f

Please sign in to comment.