Skip to content

Commit 215fce9

Browse files
Fixes for chat eval layout and auto-scroll
Signed-off-by: Jeffrey Phillips <[email protected]>
1 parent bf512ae commit 215fce9

24 files changed

+977
-1280
lines changed

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
"lint": "next lint",
1414
"type-check": "tsc --noEmit",
1515
"lint:fix": "npx eslint --fix 'src/**/*.{js,jsx,ts,tsx}'",
16-
"pretty": "prettier --write 'src/**/*.{js,jsx,ts,tsx,css,md}'",
16+
"pretty": "prettier --write 'src/**/*.{js,jsx,ts,tsx,css,scss,md}'",
1717
"test:e2e": "npx playwright test"
1818
},
1919
"dependencies": {

src/app/experimental/chat-eval/page.tsx

+5-5
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@
44
import * as React from 'react';
55
import '@patternfly/react-core/dist/styles/base.css';
66
import { AppLayout } from '@/components/AppLayout';
7-
import ChatModelEval from '@/components/Experimental/ChatEval/ChatEval';
7+
import ChatEval from '@/components/Experimental/ChatEval/ChatEval';
88

9-
const ChatEval: React.FunctionComponent = () => {
9+
const ChatEvalPage: React.FunctionComponent = () => {
1010
return (
11-
<AppLayout className="chat-eval-page">
12-
<ChatModelEval />
11+
<AppLayout className="chatBotPage">
12+
<ChatEval />
1313
</AppLayout>
1414
);
1515
};
1616

17-
export default ChatEval;
17+
export default ChatEvalPage;

src/components/AppLayout.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,8 @@ const AppLayout: React.FunctionComponent<IAppLayout> = ({ children, className })
110110
path: '/experimental',
111111
label: 'Experimental Features',
112112
children: [
113-
{ path: '/experimental/fine-tune/', label: 'Fine-tuning' },
114-
{ path: '/experimental/chat-eval/', label: 'Model Chat Eval' }
113+
{ path: '/experimental/fine-tune', label: 'Fine-tuning' },
114+
{ path: '/experimental/chat-eval', label: 'Model Chat Eval' }
115115
]
116116
}
117117
].filter(Boolean) as Route[];

src/components/Chat/ChatBotComponent.tsx

+16-36
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,11 @@ import {
3030
MessageProps
3131
} from '@patternfly/chatbot';
3232
import { Model } from '@/types';
33-
import { modelFetcher } from '@/components/Chat/modelService';
33+
import { modelFetcher } from '@/services/modelService';
3434
const botAvatar = '/bot-icon-chat-32x32.svg';
3535

3636
import { EllipsisVIcon, TimesIcon } from '@patternfly/react-icons';
37-
import styles from '@/components/Chat/chat.module.css';
3837
import { ModelsContext } from '@/components/Chat/ModelsContext';
39-
import { useSession } from 'next-auth/react';
40-
import { useEffect, useState } from 'react';
4138

4239
export const getId = () => {
4340
const date = Date.now() + Math.random();
@@ -46,20 +43,22 @@ export const getId = () => {
4643

4744
type ChatbotComponentProps = {
4845
model: Model;
46+
userName: string;
4947
messages: MessageProps[];
5048
setMessages: React.Dispatch<React.SetStateAction<MessageProps[]>>;
5149
showCompare: boolean;
5250
onCompare: () => void;
5351
onChangeModel: (model: Model) => void;
5452
onClose?: () => void;
55-
submittedMessage?: string;
53+
submittedMessage?: MessageProps;
5654
setFetching: (fetching: boolean) => void;
5755
setStopCallback: (stopFn: () => void) => void;
5856
setController: (controller: AbortController) => void;
5957
};
6058

6159
const ChatBotComponent: React.FunctionComponent<ChatbotComponentProps> = ({
6260
model,
61+
userName,
6362
messages,
6463
setMessages,
6564
showCompare,
@@ -71,7 +70,6 @@ const ChatBotComponent: React.FunctionComponent<ChatbotComponentProps> = ({
7170
setStopCallback,
7271
setController
7372
}) => {
74-
const { data: session } = useSession();
7573
const { availableModels } = React.useContext(ModelsContext);
7674
const [isLoading, setIsLoading] = React.useState(false);
7775
const [isSelectOpen, setIsSelectOpen] = React.useState(false);
@@ -81,18 +79,7 @@ const ChatBotComponent: React.FunctionComponent<ChatbotComponentProps> = ({
8179
const [announcement, setAnnouncement] = React.useState<string>();
8280
const [isActionsOpen, setActionsOpen] = React.useState<boolean>(false);
8381
const stopped = React.useRef<boolean>(false);
84-
const [userName, setUserName] = useState<string>('');
85-
const [userImage, setUserImage] = useState<string>('');
86-
87-
useEffect(() => {
88-
if (session?.user?.name === 'Admin') {
89-
setUserName(session?.user?.name);
90-
setUserImage('/default-avatar.png');
91-
} else {
92-
setUserName(session?.user?.name ?? '');
93-
setUserImage(session?.user?.image || '');
94-
}
95-
}, [session?.user?.name, session?.user?.image]);
82+
const lastQuestionRef = React.useRef<string>();
9683

9784
React.useEffect(() => {
9885
setStopCallback(() => {
@@ -103,32 +90,24 @@ const ChatBotComponent: React.FunctionComponent<ChatbotComponentProps> = ({
10390
}, []);
10491

10592
const handleSubmit = React.useCallback(
106-
async (input: string) => {
93+
async (message: MessageProps) => {
10794
if (!model) {
10895
setShowNoModelAlert(true);
10996
return;
11097
}
111-
if (!input.trim()) {
98+
if (!message.content?.trim()) {
11299
setShowNoQuestionAlert(true);
113100
return;
114101
}
115102

116103
const date = new Date();
117104

118105
setMessages((prevMessages) => {
119-
const newMessage: MessageProps = {
120-
avatar: userImage,
121-
id: getId(),
122-
name: userName,
123-
role: 'user',
124-
content: input,
125-
timestamp: `${date.toLocaleDateString()} ${date.toLocaleTimeString()}`
126-
};
127-
return [...prevMessages, newMessage];
106+
return [...prevMessages, message];
128107
});
129108

130109
// make announcement to assistive devices that new messages have been added
131-
setAnnouncement(`Message from You: ${input}. Message from Chatbot is loading.`);
110+
setAnnouncement(`Message from You: ${message.content}. Message from Chatbot is loading.`);
132111

133112
setIsLoading(true);
134113
setFetching(true);
@@ -154,24 +133,25 @@ const ChatBotComponent: React.FunctionComponent<ChatbotComponentProps> = ({
154133

155134
stopped.current = false;
156135
try {
157-
await modelFetcher(model, input, setCurrentMessage, setController);
136+
await modelFetcher(model, message.content, setCurrentMessage, setController);
158137
} catch (e) {
159138
console.error(`Model fetch failed: `, e);
160139
}
161140

162141
setIsLoading(false);
163142
setFetching(false);
164143
},
165-
[model, setController, setFetching, setMessages, userImage, userName]
144+
[model, setController, setFetching, setMessages]
166145
);
167146

168147
React.useEffect(() => {
169-
if (submittedMessage) {
148+
if (submittedMessage && submittedMessage.id !== lastQuestionRef.current) {
149+
lastQuestionRef.current = submittedMessage.id;
170150
handleSubmit(submittedMessage);
171151
}
172152
// Do not update when handleSubmit changes
173153
// eslint-disable-next-line react-hooks/exhaustive-deps
174-
}, [submittedMessage]);
154+
}, [submittedMessage, handleSubmit]);
175155

176156
const onToggleClick = () => {
177157
setIsSelectOpen(!isSelectOpen);
@@ -218,7 +198,7 @@ const ChatBotComponent: React.FunctionComponent<ChatbotComponentProps> = ({
218198

219199
return (
220200
<Chatbot displayMode={ChatbotDisplayMode.embedded}>
221-
<ChatbotHeader className={styles.chatHeader}>
201+
<ChatbotHeader>
222202
<ChatbotHeaderMain>
223203
<Select
224204
id="single-select"
@@ -264,7 +244,7 @@ const ChatBotComponent: React.FunctionComponent<ChatbotComponentProps> = ({
264244
</ChatbotHeaderActions>
265245
</ChatbotHeader>
266246
<ChatbotContent>
267-
<MessageBox announcement={announcement} className={styles.chatBotMessage}>
247+
<MessageBox announcement={announcement}>
268248
<ChatbotWelcomePrompt title={`Hello, ${userName}`} description="Go ahead and ask me a question." />
269249
{messages.map((message) => (
270250
<Message key={message.id} {...message} />

src/components/Chat/ChatBotContainer.tsx

+33-10
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ import { useRouter, useSearchParams } from 'next/navigation';
66
import { ChatbotFooter, ChatbotFootnote, Compare, MessageBar, MessageProps } from '@patternfly/chatbot';
77
import { Model } from '@/types';
88
import { ModelsContext } from './ModelsContext';
9-
import { ChatBotComponent } from './ChatBotComponent';
9+
import { ChatBotComponent, getId } from './ChatBotComponent';
10+
import { useUserInfo } from '@/hooks/useUserInfo';
1011

11-
import '@patternfly/chatbot/dist/css/main.css';
1212
import styles from './chat.module.css';
1313

1414
const MAX_COMPARES = 2;
@@ -21,7 +21,9 @@ const ChatBotContainer: React.FC = () => {
2121
() => searchParams.get('models')?.split(',') ?? [availableModels[0]?.name],
2222
[searchParams, availableModels]
2323
);
24-
const [submittedMessage, setSubmittedMessage] = React.useState<string>();
24+
const [submittedMessage, setSubmittedMessage] = React.useState<MessageProps>();
25+
const { userName, userImage } = useUserInfo();
26+
const [question, setQuestion] = React.useState<string>('');
2527

2628
const [mainChatMessages, setMainChatMessages] = React.useState<MessageProps[]>([]);
2729
const [mainChatFetching, setMainChatFetching] = React.useState<boolean>();
@@ -45,6 +47,24 @@ const ChatBotContainer: React.FC = () => {
4547
[modelNames, availableModels]
4648
);
4749

50+
const onSubmitMessage = React.useCallback(
51+
(message: string | number) => {
52+
const date = new Date();
53+
54+
const newMessage: MessageProps = {
55+
avatar: userImage,
56+
id: getId(),
57+
name: userName,
58+
role: 'user',
59+
content: typeof message === 'string' ? message : String(message),
60+
timestamp: `${date.toLocaleDateString()} ${date.toLocaleTimeString()}`
61+
};
62+
63+
setSubmittedMessage(newMessage);
64+
},
65+
[userImage, userName]
66+
);
67+
4868
const onCloseChat = (indexToRemove: number) => {
4969
const remaining = [...modelNames.slice(0, indexToRemove), ...modelNames.slice(indexToRemove + 1)];
5070

@@ -87,7 +107,8 @@ const ChatBotContainer: React.FC = () => {
87107
const mainChat = (
88108
<ChatBotComponent
89109
model={selectedModels[0]}
90-
showCompare={selectedModels.length < MAX_COMPARES}
110+
userName={userName}
111+
showCompare={selectedModels.length < MAX_COMPARES && availableModels.length > 1}
91112
onCompare={onCompare}
92113
messages={mainChatMessages}
93114
setMessages={setMainChatMessages}
@@ -106,6 +127,7 @@ const ChatBotContainer: React.FC = () => {
106127
selectedModels.length > 1 ? (
107128
<ChatBotComponent
108129
model={selectedModels[1]}
130+
userName={userName}
109131
showCompare={false}
110132
onCompare={onCompare}
111133
messages={altChatMessages}
@@ -124,7 +146,7 @@ const ChatBotContainer: React.FC = () => {
124146
return (
125147
<>
126148
{altChat ? (
127-
<div className="pf-chatbot__compare-container">
149+
<div className="pf-chatbot__compare-container m-is-unified">
128150
<Compare
129151
firstChild={mainChat}
130152
secondChild={altChat}
@@ -137,13 +159,14 @@ const ChatBotContainer: React.FC = () => {
137159
)}
138160
<ChatbotFooter>
139161
<MessageBar
140-
className={styles.chatBotMessageBar}
141-
onSendMessage={(message) => {
142-
setSubmittedMessage(typeof message === 'string' ? message : String(message));
143-
}}
162+
onSendMessage={onSubmitMessage}
144163
hasMicrophoneButton
145164
hasAttachButton={false}
146-
isSendButtonDisabled={mainChatFetching || altChatFetching}
165+
onChange={(_, val) => {
166+
setQuestion(typeof val === 'string' ? val : String(val));
167+
}}
168+
alwayShowSendButton
169+
isSendButtonDisabled={!question.trim() || mainChatFetching || altChatFetching}
147170
hasStopButton={mainChatFetching || altChatFetching}
148171
handleStopButton={handleStopButton}
149172
/>

src/components/Chat/chat.module.css

-7
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,4 @@
11
/* Chat Bot Container */
2-
.chatHeader {
3-
border-top: 1px solid var(--pf-t--global--border--color--100);
4-
border-bottom: 1px solid var(--pf-t--global--border--color--100);
5-
}
6-
.chatBotMessageBar {
7-
border: 1px solid var(--pf-t--global--border--color--100);
8-
}
92
.chatBotContainer {
103
flex: 1;
114
overflow-y: hidden;

src/components/Contribute/Knowledge/FileConversionModal.tsx

+1-2
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,6 @@ export const FileConversionModal: React.FunctionComponent<Props> = ({ filesToCon
7979

8080
if (!res.ok) {
8181
// Check if it's a 503 => offline service
82-
console.log(res);
8382
if (res.status === 503) {
8483
console.error('Conversion service offline, only .md files accepted');
8584
throw new Error('The file conversion service is offline. Only Markdown file type can be accepted until service is restored.');
@@ -158,7 +157,7 @@ export const FileConversionModal: React.FunctionComponent<Props> = ({ filesToCon
158157
return () => {
159158
canceled = true;
160159
};
161-
}, [convertToMarkdownIfNeeded, filesToConvert, isUploading, onConverted, onError]);
160+
}, [convertToMarkdownIfNeeded, currentFiles, filesToConvert, isUploading, onConverted, onError]);
162161

163162
return (
164163
<Modal isOpen title="Upload in progress" variant="small" aria-label="uploading" aria-labelledby="upload-modal-title" disableFocusTrap>
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
.chat-eval__chatbots-container {
1+
.chat-loading-container {
22
display: flex;
3-
flex-direction: column;
4-
gap: 0.25rem;
5-
margin-left: 1rem;
6-
margin-right: 1rem;
7-
@media (min-width: 1695px) {
8-
flex-direction: row;
9-
}
3+
gap: 0.5rem;
4+
font-size: medium !important;
5+
justify-content: center;
6+
width: 50%;
7+
}
8+
9+
.pf-chatbot__compare-toggle .pf-v6-c-toggle-group__button {
10+
height: 100%;
1011
}

0 commit comments

Comments
 (0)