Skip to content

Commit

Permalink
Merge pull request #11 from rebeccaalpert/compare
Browse files Browse the repository at this point in the history
First pass at compare
  • Loading branch information
rebeccaalpert authored Nov 6, 2024
2 parents ad55394 + f078f15 commit 508d220
Show file tree
Hide file tree
Showing 11 changed files with 739 additions and 160 deletions.
68 changes: 34 additions & 34 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,10 @@
"webpack-merge": "^5.10.0"
},
"dependencies": {
"@patternfly/react-core": "^6.0.0-prerelease.21",
"@patternfly/react-icons": "^6.0.0-prerelease.7",
"@patternfly/react-styles": "^6.0.0-prerelease.6",
"@patternfly/virtual-assistant": "^2.0.0-alpha.61",
"@patternfly/react-core": "^6.0.0",
"@patternfly/react-icons": "^6.0.0",
"@patternfly/react-styles": "^6.0.0",
"@patternfly/virtual-assistant": "^2.1.0-prerelease.8",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"sirv-cli": "^2.0.2"
Expand Down
3 changes: 2 additions & 1 deletion src/app/AppLayout/AppLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const AppLayout: React.FunctionComponent = () => {
const [sidebarOpen, setSidebarOpen] = React.useState(true);

const masthead = (
<Masthead>
<Masthead display={{ default: 'inline' }}>
<MastheadMain>
<MastheadToggle>
<Button
Expand Down Expand Up @@ -110,6 +110,7 @@ const AppLayout: React.FunctionComponent = () => {

return (
<Page
className="chatbot-ui-page"
mainContainerId={pageId}
masthead={masthead}
sidebar={sidebarOpen && Sidebar}
Expand Down
136 changes: 32 additions & 104 deletions src/app/BaseChatbot/BaseChatbot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,37 +16,13 @@ import {
} from '@patternfly/virtual-assistant';
import { useLoaderData } from 'react-router-dom';
import { CannedChatbot } from '../types/CannedChatbot';
import {
Dropdown,
DropdownItem,
DropdownList,
MenuSearch,
MenuSearchInput,
MenuToggle,
MenuToggleElement,
SearchInput,
} from '@patternfly/react-core';
import { HeaderDropdown } from '@app/HeaderDropdown/HeaderDropdown';
import { ERROR_TITLE, getId } from '@app/utils/utils';
import { Button } from '@patternfly/react-core';
interface Source {
link: string;
}

const getChatbots = () => {
const url = process.env.REACT_APP_INFO_URL ?? '';
return fetch(url)
.then((res) => res.json())
.then((data: CannedChatbot[]) => {
return data;
})
.catch((e) => {
throw new Response(e.message, { status: 404 });
});
};

export async function loader() {
const chatbots = await getChatbots();
return { chatbots };
}

const BaseChatbot: React.FunctionComponent = () => {
const { chatbots } = useLoaderData() as { chatbots: CannedChatbot[] };
const [messages, setMessages] = React.useState<MessageProps[]>([]);
Expand All @@ -57,9 +33,8 @@ const BaseChatbot: React.FunctionComponent = () => {
const [error, setError] = React.useState<{ title: string; body: string }>();
const [announcement, setAnnouncement] = React.useState<string>();
const [currentChatbot, setCurrentChatbot] = React.useState<CannedChatbot>(chatbots[0]);
const [isOpen, setIsOpen] = React.useState(false);
const [visibleAssistants, setVisibleAssistants] = React.useState<CannedChatbot[]>(chatbots);
const [controller, setController] = React.useState<AbortController>();
const [currentDate, setCurrentDate] = React.useState<Date>();

React.useEffect(() => {
document.title = `Red Hat Composer AI Studio | ${currentChatbot?.name}`;
Expand All @@ -85,20 +60,21 @@ const BaseChatbot: React.FunctionComponent = () => {

const url = process.env.REACT_APP_ROUTER_URL ?? '';

const ERROR_TITLE = {
'Error: 404': '404: Network error',
'Error: 500': 'Server error',
'Error: Other': 'Error',
};

const ERROR_BODY = {
'Error: 404': `${currentChatbot?.displayName} is currently unavailable. Use a different assistant or try again later.`,
'Error: 500': `${currentChatbot?.displayName} has encountered an error and is unable to answer your question. Use a different assistant or try again later.`,
'Error: Other': `${currentChatbot?.displayName} has encountered an error and is unable to answer your question. Use a different assistant or try again later.`,
};

const handleError = (e) => {
const newError = { title: ERROR_TITLE[e], body: ERROR_BODY[e] };
const title = ERROR_TITLE;
const body = ERROR_BODY;
let newError;
if (title && body) {
newError = { title: ERROR_TITLE[e], body: ERROR_BODY[e] };
} else {
newError = { title: 'Error', body: e.message };
}
setError(newError);
// make announcement to assistive devices that there was an error
setAnnouncement(`Error: ${newError.title} ${newError.body}`);
Expand Down Expand Up @@ -185,13 +161,9 @@ const BaseChatbot: React.FunctionComponent = () => {
}
}

const getId = () => {
const date = Date.now() + Math.random();
return date.toString();
};

const handleSend = async (input: string) => {
setIsSendButtonDisabled(true);
const date = new Date();
const newMessages = structuredClone(messages);
if (currentMessage.length > 0) {
newMessages.push({
Expand All @@ -200,12 +172,23 @@ const BaseChatbot: React.FunctionComponent = () => {
role: 'bot',
content: currentMessage.join(''),
...(currentSources && { sources: { sources: currentSources } }),
timestamp: currentDate
? `${currentDate.toLocaleDateString()} ${currentDate.toLocaleTimeString()}`
: `${date?.toLocaleDateString} ${date?.toLocaleTimeString}`,
});
setCurrentMessage([]);
setCurrentSources(undefined);
setCurrentDate(undefined);
}
newMessages.push({ id: getId(), name: 'You', role: 'user', content: input });
newMessages.push({
id: getId(),
name: 'You',
role: 'user',
content: input,
timestamp: `${date.toLocaleDateString()} ${date.toLocaleTimeString()}`,
});
setMessages(newMessages);
setCurrentDate(date);
// make announcement to assistive devices that new messages have been added
setAnnouncement(`Message from You: ${input}. Message from Chatbot is loading.`);

Expand All @@ -226,7 +209,6 @@ const BaseChatbot: React.FunctionComponent = () => {
}
setController(undefined);
setCurrentChatbot(value);
setIsOpen(false);
setMessages([]);
setCurrentMessage([]);
setCurrentSources(undefined);
Expand All @@ -235,72 +217,17 @@ const BaseChatbot: React.FunctionComponent = () => {
setIsSendButtonDisabled(false);
};

const onToggleClick = () => {
setIsOpen(!isOpen);
};

const findMatchingElements = (chatbots: CannedChatbot[], targetValue: string) => {
const matchingElements = chatbots.filter((chatbot) =>
chatbot.displayName.toLowerCase().includes(targetValue.toLowerCase()),
);
return matchingElements;
};

const onTextInputChange = (value: string) => {
if (value === '') {
setVisibleAssistants(chatbots);
return;
}
const newVisibleAssistants = findMatchingElements(chatbots, value);
setVisibleAssistants(newVisibleAssistants);
};

return (
<Chatbot displayMode={displayMode}>
<ChatbotHeader>
<ChatbotHeaderMain>
<Dropdown
className="assistant-selector-menu"
isOpen={isOpen}
// @ts-expect-error PatternFly limits us to strings or numbers; we need an object
onSelect={onSelect}
onOpenChange={(isOpen: boolean) => setIsOpen(isOpen)}
ouiaId="BasicDropdown"
shouldFocusToggleOnSelect
onOpenChangeKeys={['Escape']}
toggle={(toggleRef: React.Ref<MenuToggleElement>) => (
<MenuToggle ref={toggleRef} onClick={onToggleClick} isExpanded={isOpen}>
Red Hat AI Assistant
</MenuToggle>
)}
popperProps={{ appendTo: 'inline' }}
>
<MenuSearch>
<MenuSearchInput>
<SearchInput
aria-label="Search assistants..."
onChange={(_event, value) => onTextInputChange(value)}
placeholder="Search assistants..."
/>
</MenuSearchInput>
</MenuSearch>
<DropdownList>
{visibleAssistants && visibleAssistants?.length > 0 ? (
visibleAssistants?.map((chatbot) => (
<DropdownItem
key={chatbot.displayName}
value={chatbot}
isSelected={currentChatbot?.displayName === chatbot.displayName}
>
{chatbot.displayName}
</DropdownItem>
))
) : (
<DropdownItem key="no-items">No results found</DropdownItem>
)}
</DropdownList>
</Dropdown>
<HeaderDropdown selectedChatbot={currentChatbot} chatbots={chatbots} onSelect={onSelect} />
</ChatbotHeaderMain>
{chatbots.length >= 2 && (
<Button component="a" href={`/compare?assistants=${chatbots[0].name}%2C${chatbots[1].name}`}>
Compare
</Button>
)}
</ChatbotHeader>
<ChatbotContent>
<MessageBox announcement={announcement}>
Expand All @@ -327,6 +254,7 @@ const BaseChatbot: React.FunctionComponent = () => {
role="bot"
content={currentMessage.join('')}
{...(currentSources && { sources: { sources: currentSources } })}
timestamp={`${currentDate?.toLocaleDateString()} ${currentDate?.toLocaleTimeString()}`}
/>
)}
<div ref={scrollToBottomRef}></div>
Expand Down
Loading

0 comments on commit 508d220

Please sign in to comment.