Skip to content

Commit dc90484

Browse files
committed
Enhance Lightspeed Chatbot with file attachment support and conversation management
- Introduced file attachment functionality, allowing users to attach multiple files (up to 5) with size validation. - Implemented conversation loading and deletion features, enabling users to fetch and manage conversation history. - Updated the chatbot UI to accommodate file drop zones and alerts for file upload status. - Refactored state management in the `useChatbot` hook to handle attachments and conversations more effectively. - Enhanced message handling to include attached files in user messages. - Improved helper functions for searching conversations based on user input.
1 parent 22f938f commit dc90484

File tree

6 files changed

+407
-90
lines changed

6 files changed

+407
-90
lines changed

src/app/LightspeedChatbot/LightspeedChatbot.tsx

Lines changed: 71 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React from 'react';
22
import { useDocumentTitle } from '@app/utils/useDocumentTitle';
3-
import { Bullseye, DropdownGroup, DropdownItem, DropdownList, Title, TitleSizes } from '@patternfly/react-core';
3+
import { Bullseye, DropdownGroup, DropdownItem, DropdownList, Flex, FlexItem, Title, TitleSizes } from '@patternfly/react-core';
44

55
// Chatbot components
66
import ChatbotToggle from '@patternfly/chatbot/dist/dynamic/ChatbotToggle';
@@ -20,6 +20,9 @@ import ChatbotHeader, {
2020
ChatbotHeaderSelectorDropdown,
2121
ChatbotHeaderTitle
2222
} from '@patternfly/chatbot/dist/dynamic/ChatbotHeader';
23+
import FileDropZone from '@patternfly/chatbot/dist/dynamic/FileDropZone';
24+
import FileDetailsLabel from '@patternfly/chatbot/dist/dynamic/FileDetailsLabel';
25+
import ChatbotAlert from '@patternfly/chatbot/dist/dynamic/ChatbotAlert';
2326

2427
// Icons
2528
import ExpandIcon from '@patternfly/react-icons/dist/esm/icons/expand-icon';
@@ -29,9 +32,7 @@ import OutlinedWindowRestoreIcon from '@patternfly/react-icons/dist/esm/icons/ou
2932
// Local imports
3033
import { useChatbot } from './hooks/useChatbot';
3134
import { ToolExecutionCards } from './components/ToolExecutionCards';
32-
import { FOOTNOTE_PROPS, INITIAL_CONVERSATIONS, INITIAL_WELCOME_PROMPTS } from './constants';
33-
import { findMatchingItems } from './utils/helpers';
34-
import { Conversation } from '@patternfly/chatbot/dist/dynamic/ChatbotConversationHistoryNav';
35+
import { FOOTNOTE_PROPS, INITIAL_WELCOME_PROMPTS } from './constants';
3536

3637
/**
3738
* Main Lightspeed Chatbot Component
@@ -40,13 +41,13 @@ import { Conversation } from '@patternfly/chatbot/dist/dynamic/ChatbotConversati
4041
* - Model selection
4142
* - Streaming responses
4243
* - Tool execution tracking
44+
* - File attachments
4345
* - Conversation history
4446
* - Multiple display modes (overlay, docked, fullscreen)
4547
*/
4648
const LightspeedChatbot: React.FunctionComponent = () => {
4749
useDocumentTitle('Lightspeed Chatbot');
4850

49-
// Use the custom hook for all chatbot logic
5051
const {
5152
chatbotVisible,
5253
displayMode,
@@ -56,18 +57,30 @@ const LightspeedChatbot: React.FunctionComponent = () => {
5657
isSendButtonDisabled,
5758
isDrawerOpen,
5859
conversations,
60+
currentConversationId,
5961
announcement,
6062
toolExecutions,
6163
scrollToBottomRef,
64+
attachedFiles,
65+
isLoadingFile,
66+
fileError,
67+
showFileAlert,
6268
onSelectModel,
6369
onSelectDisplayMode,
6470
handleSend,
71+
handleAttach,
72+
handleFileDrop,
73+
onAttachmentClose,
74+
onCloseFileAlert,
75+
handleTextInputChange,
76+
handleConversationSelect,
6577
setChatbotVisible,
6678
setMessages,
67-
setConversations,
6879
setCurrentConversationId,
6980
setIsDrawerOpen
70-
} = useChatbot();
81+
} = useChatbot();
82+
83+
7184

7285
// Enhanced message rendering with tool execution support
7386
const renderMessages = () => {
@@ -113,29 +126,23 @@ const LightspeedChatbot: React.FunctionComponent = () => {
113126
displayMode={displayMode}
114127
onDrawerToggle={() => {
115128
setIsDrawerOpen(!isDrawerOpen);
116-
setConversations(INITIAL_CONVERSATIONS);
117129
}}
118130
isDrawerOpen={isDrawerOpen}
119131
setIsDrawerOpen={setIsDrawerOpen}
120-
activeItemId="1"
121-
// eslint-disable-next-line no-console
122-
onSelectActiveItem={(e, selectedItem) => console.log(`Selected history item with id ${selectedItem}`)}
132+
activeItemId={currentConversationId}
133+
onSelectActiveItem={(e, selectedItem) => {
134+
console.log(`Selected history item with id ${selectedItem}`);
135+
if (typeof selectedItem === 'string') {
136+
handleConversationSelect(selectedItem);
137+
}
138+
}}
123139
conversations={conversations}
124140
onNewChat={() => {
125141
setIsDrawerOpen(!isDrawerOpen);
126142
setMessages([]);
127-
setConversations(INITIAL_CONVERSATIONS);
128143
setCurrentConversationId('');
129144
}}
130-
handleTextInputChange={(value: string) => {
131-
if (value === '') {
132-
setConversations(INITIAL_CONVERSATIONS);
133-
}
134-
// this is where you would perform search on the items in the drawer
135-
// and update the state
136-
const newConversations: { [key: string]: Conversation[] } = findMatchingItems(value);
137-
setConversations(newConversations);
138-
}}
145+
handleTextInputChange={handleTextInputChange}
139146
drawerContent={
140147
<>
141148
<ChatbotHeader>
@@ -145,7 +152,7 @@ const LightspeedChatbot: React.FunctionComponent = () => {
145152
displayMode={displayMode}
146153
showOnFullScreen={horizontalLogo}
147154
showOnDefault={iconLogo}
148-
></ChatbotHeaderTitle>
155+
/>
149156
</ChatbotHeaderMain>
150157
<ChatbotHeaderActions>
151158
<ChatbotHeaderSelectorDropdown value={selectedModel} onSelect={onSelectModel}>
@@ -196,32 +203,58 @@ const LightspeedChatbot: React.FunctionComponent = () => {
196203
</ChatbotHeaderOptionsDropdown>
197204
</ChatbotHeaderActions>
198205
</ChatbotHeader>
199-
<ChatbotContent>
200-
{/* Update the announcement prop on MessageBox whenever a new message is sent
201-
so that users of assistive devices receive sufficient context */}
202-
<MessageBox announcement={announcement}>
203-
<ChatbotWelcomePrompt
204-
title="Hello, Lightspeed User"
205-
description="How may I help you today?"
206-
prompts={INITIAL_WELCOME_PROMPTS}
207-
/>
208-
{/* Display all messages */}
209-
{renderMessages()}
210-
{/* Scroll reference at the bottom of all messages for proper streaming behavior */}
211-
<div ref={scrollToBottomRef}/>
212-
</MessageBox>
213-
</ChatbotContent>
206+
<FileDropZone onFileDrop={handleFileDrop} displayMode={displayMode}>
207+
<ChatbotContent>
208+
<MessageBox announcement={announcement}>
209+
{showFileAlert && (
210+
<ChatbotAlert
211+
variant="danger"
212+
onClose={onCloseFileAlert}
213+
title="File upload failed"
214+
>
215+
{fileError}
216+
</ChatbotAlert>
217+
)}
218+
<ChatbotWelcomePrompt
219+
title="Hello, Lightspeed User"
220+
description="How may I help you today?"
221+
prompts={INITIAL_WELCOME_PROMPTS}
222+
/>
223+
{renderMessages()}
224+
<div ref={scrollToBottomRef}/>
225+
</MessageBox>
226+
</ChatbotContent>
227+
</FileDropZone>
214228
<ChatbotFooter>
229+
<Flex
230+
direction={{ default: 'row' }}
231+
flexWrap={{ default: 'nowrap' }}
232+
spaceItems={{ default: 'spaceItemsSm' }}
233+
style={{ overflowX: 'auto', overflowY: 'hidden', paddingBottom: '8px' }}
234+
>
235+
{attachedFiles.map((file, index) => (
236+
<FlexItem key={index} flex={{ default: 'flexNone' }}>
237+
<FileDetailsLabel
238+
key={index}
239+
fileName={file.name}
240+
isLoading={isLoadingFile && index === attachedFiles.length - 1}
241+
onClose={() => onAttachmentClose(index)}
242+
/>
243+
</FlexItem>
244+
))}
245+
</Flex>
215246
<MessageBar
216247
onSendMessage={handleSend}
248+
handleAttach={handleAttach}
249+
hasAttachButton
217250
hasMicrophoneButton
218251
isSendButtonDisabled={isSendButtonDisabled}
219252
/>
220253
<ChatbotFootnote {...FOOTNOTE_PROPS} />
221254
</ChatbotFooter>
222255
</>
223256
}
224-
></ChatbotConversationHistoryNav>
257+
/>
225258
</Chatbot>
226259
</>
227260
);

src/app/LightspeedChatbot/constants.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { MessageProps } from '@patternfly/chatbot/dist/dynamic/Message';
22
import { WelcomePrompt } from '@patternfly/chatbot/dist/dynamic/ChatbotWelcomePrompt';
3+
import { Conversation } from '@patternfly/chatbot/dist/dynamic/ChatbotConversationHistoryNav';
34

45
// API Configuration
56
export const API_BASE_URL = 'http://localhost:8080';
@@ -13,7 +14,7 @@ export const BOT_AVATAR =
1314
// Initial states
1415
export const INITIAL_MESSAGES: MessageProps[] = [];
1516
export const INITIAL_WELCOME_PROMPTS: WelcomePrompt[] = [];
16-
export const INITIAL_CONVERSATIONS = {};
17+
export const INITIAL_CONVERSATIONS: Conversation[] = [];
1718

1819
// Default system prompt
1920
export const DEFAULT_SYSTEM_PROMPT = 'You are a helpful assistant.';

0 commit comments

Comments
 (0)