Skip to content

Commit

Permalink
coral-web: update the starter card options (#73)
Browse files Browse the repository at this point in the history
* add new start options

* set start option prompts

* clean up

* remove welcome message

* remove notification message

* visual nits

* center start options, fade out when convo is populated

* remove streaming message check
  • Loading branch information
misspia-cohere authored May 1, 2024
1 parent 8886432 commit 00b6ed1
Show file tree
Hide file tree
Showing 16 changed files with 269 additions and 362 deletions.
4 changes: 1 addition & 3 deletions src/interfaces/coral_web/src/components/Avatar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ type Props = {

export const Avatar: React.FC<Props> = ({ message }) => {
const isUser = message.type === MessageType.USER;
const isBot = message.type === MessageType.BOT || message.type === MessageType.WELCOME;
const isWelcome = message.type === MessageType.WELCOME;
const isBot = message.type === MessageType.BOT;
const isLoading = isBot && message.state === BotState.LOADING;
const isTyping = isBot && message.state === BotState.TYPING;
const isErrored = isBot && message.state === BotState.ERROR;
Expand All @@ -37,7 +36,6 @@ export const Avatar: React.FC<Props> = ({ message }) => {
'h-7 w-7 md:h-9 md:w-9',
{
'bg-volcanic-500': isErroredOrAborted,
'bg-primary-900': isWelcome,
'bg-quartz-700': isUser,
},
isGroundingOn
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,9 @@ const ToolSection = () => {
})}
disabled={disabled}
/>
{(description || error_message) && <Tooltip label={description ?? error_message} />}
{(description || error_message) && (
<Tooltip label={description ?? error_message} />
)}
</div>
);
})}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,34 +5,25 @@ import ScrollToBottom, { useScrollToBottom, useSticky } from 'react-scroll-to-bo

import { CitationPanel } from '@/components/Citations/CitationPanel';
import MessageRow from '@/components/MessageRow';
import Notification from '@/components/Messages/Notification';
import WelcomeMessage from '@/components/Messages/Welcome';
import { StartOptionKey } from '@/components/Messages/Welcome/StartOptions';
import { Button } from '@/components/Shared';
import { PromptOption, StartModes } from '@/components/StartModes';
import { ReservedClasses } from '@/constants';
import { MESSAGE_LIST_CONTAINER_ID, useCalculateCitationStyles } from '@/hooks/citations';
import { useFixCopyBug } from '@/hooks/fixCopyBug';
import { useCitationsStore } from '@/stores';
import {
ChatMessage,
MessageType,
StreamingMessage,
isFulfilledMessage,
isNotificationMessage,
} from '@/types/message';
import { ChatMessage, MessageType, StreamingMessage, isFulfilledMessage } from '@/types/message';
import { cn } from '@/utils';

type Props = {
isStreaming: boolean;
welcomeMessageEnabled: boolean;
startOptionsEnabled: boolean;
messages: ChatMessage[];
streamingMessage: StreamingMessage | null;
startOption: StartOptionKey;
onStartOptionChange: (option: StartOptionKey) => void;
onRetry: VoidFunction;
composer: ReactNode;
conversationId?: string;
scrollViewClassName?: string;
onPromptSelected?: (option: PromptOption) => void;
};

/**
Expand Down Expand Up @@ -64,8 +55,7 @@ export default memo(MessagingContainer);
* In order to access the state hooks for the scroll to bottom component, we need to wrap the content in a component.
*/
const Content: React.FC<Props> = (props) => {
const { isStreaming, messages, composer, streamingMessage, startOption, onStartOptionChange } =
props;
const { isStreaming, messages, composer, streamingMessage, onPromptSelected } = props;
const scrollToBottom = useScrollToBottom();
const {
citations: { hasCitations },
Expand Down Expand Up @@ -114,12 +104,7 @@ const Content: React.FC<Props> = (props) => {
return (
<div className="flex h-max min-h-full w-full">
<div id={MESSAGE_LIST_CONTAINER_ID} className={cn('flex h-auto min-w-0 flex-1 flex-col')}>
<Messages
{...props}
ref={messageContainerDivRef}
startOption={startOption}
onStartOptionChange={onStartOptionChange}
/>
<Messages {...props} ref={messageContainerDivRef} onPromptSelected={onPromptSelected} />
{/* Composer container */}
<div
className={cn('sticky bottom-0 px-4 pb-4', 'bg-marble-100')}
Expand Down Expand Up @@ -166,36 +151,26 @@ const Content: React.FC<Props> = (props) => {
);
};

type MessagesProps = Props & { welcomeMessageEnabled: boolean };
type MessagesProps = Props & { startOptionsEnabled: boolean };
/**
* This component is in charge of rendering the messages.
*/
const Messages = forwardRef<HTMLDivElement, MessagesProps>(function MessagesInternal(
{ welcomeMessageEnabled, onRetry, messages, streamingMessage, startOption, onStartOptionChange },
{ startOptionsEnabled, onRetry, messages, streamingMessage, onPromptSelected },
ref
) {
const lastMessage = messages[messages.length - 1];

const isConversationEmpty = messages.length === 0;
return (
<div className="mt-auto flex flex-col gap-y-4 px-4 py-6 md:gap-y-6" ref={ref}>
<WelcomeMessage
show={
welcomeMessageEnabled && messages.filter((m) => !isNotificationMessage(m)).length === 0
}
startOption={startOption}
onStartOptionChange={onStartOptionChange}
/>

{messages.map((m, i) => {
const isLastInList = i === messages.length - 1;
<div className="flex h-full flex-col gap-y-4 px-4 py-6 md:gap-y-6" ref={ref}>
{startOptionsEnabled && (
<div className="flex h-full w-full flex-col justify-center p-4">
<StartModes show={isConversationEmpty} onPromptSelected={onPromptSelected} />
</div>
)}

if (isNotificationMessage(m) && isLastInList) {
// If the last message is a notification, render it after the streaming message if it exists.
// The latest status is always shown at the bottom of the chat.
return null;
} else if (isNotificationMessage(m) && !isLastInList) {
return <Notification key={i} message={m.text} show={m.show} />;
} else {
<div className="mt-auto flex flex-col gap-y-4 md:gap-y-6">
{messages.map((m, i) => {
const isLastInList = i === messages.length - 1;
return (
<MessageRow
key={i}
Expand All @@ -214,16 +189,12 @@ const Messages = forwardRef<HTMLDivElement, MessagesProps>(function MessagesInte
onRetry={onRetry}
/>
);
}
})}
})}
</div>

{streamingMessage && (
<MessageRow message={streamingMessage} isLast={true} onRetry={onRetry} />
)}

{lastMessage && isNotificationMessage(lastMessage) && messages.length > 1 && (
<Notification message={lastMessage.text} show={lastMessage.show} shouldAnimate />
)}
</div>
);
});
34 changes: 12 additions & 22 deletions src/interfaces/coral_web/src/components/Conversation/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@ import { FILE_TOOL_CATEGORY, Tool } from '@/cohere-client';
import Composer from '@/components/Conversation/Composer';
import { Header } from '@/components/Conversation/Header';
import MessagingContainer from '@/components/Conversation/MessagingContainer';
import { StartOptionKey } from '@/components/Messages/Welcome/StartOptions';
import { DragDropFileInput, Spinner } from '@/components/Shared';
import { HotKeysProvider } from '@/components/Shared/HotKeys';
import { PromptOption } from '@/components/StartModes';
import { WelcomeGuideTooltip } from '@/components/WelcomeGuideTooltip';
import { ACCEPTED_FILE_TYPES, ReservedClasses } from '@/constants';
import { useChatHotKeys } from '@/hooks/actions';
import { useFocusComposer } from '@/hooks/actions';
import { useChat } from '@/hooks/chat';
import { useFileActions, useFilesInConversation } from '@/hooks/files';
import { WelcomeGuideStep, useWelcomeGuideState } from '@/hooks/ftux';
Expand All @@ -27,7 +28,7 @@ import { ChatMessage } from '@/types/message';
import { cn } from '@/utils';

type Props = {
welcomeMessageEnabled?: boolean;
startOptionsEnabled?: boolean;
conversationId?: string;
history?: ChatMessage[];
};
Expand All @@ -36,7 +37,7 @@ type Props = {
* @description Renders the entire conversation pane, which includes the header, messages,
* composer, and the citation panel.
*/
const Conversation: React.FC<Props> = ({ conversationId, welcomeMessageEnabled = false }) => {
const Conversation: React.FC<Props> = ({ conversationId, startOptionsEnabled = false }) => {
const [isDragDropInputActive, setIsDragDropInputActive] = useState(false);
const chatHotKeys = useChatHotKeys();

Expand Down Expand Up @@ -76,16 +77,7 @@ const Conversation: React.FC<Props> = ({ conversationId, welcomeMessageEnabled =
}
},
});
const getSelectedOption = (): StartOptionKey => {
if (tools && tools.length > 0) {
return StartOptionKey.WEB_SEARCH;
} else if (params.fileIds && params.fileIds.length > 0) {
return StartOptionKey.DOCUMENTS;
} else {
return StartOptionKey.UNGROUNDED;
}
};
const [startOption, setStartOption] = useState<StartOptionKey>(() => getSelectedOption());
const { focusComposer } = useFocusComposer();

// Returns the first visible file loader tool from tools list
const defaultFileLoaderTool = useMemo(
Expand Down Expand Up @@ -153,9 +145,6 @@ const Conversation: React.FC<Props> = ({ conversationId, welcomeMessageEnabled =
const handleUploadFile = async (e: React.ChangeEvent<HTMLInputElement>) => {
const newFileIds = await uploadFile(e.target.files?.[0]);
if (!newFileIds) return;
if (startOption !== StartOptionKey.DOCUMENTS) {
setStartOption(StartOptionKey.DOCUMENTS);
}
enableDefaultFileLoaderTool();
};

Expand All @@ -167,15 +156,17 @@ const Conversation: React.FC<Props> = ({ conversationId, welcomeMessageEnabled =
...(enableFileLoaderTool ? [{ name: defaultFileLoaderTool.name }] : []),
];

if (startOption !== StartOptionKey.DOCUMENTS) {
setStartOption(StartOptionKey.DOCUMENTS);
}
if (filesExist) {
enableDefaultFileLoaderTool();
}
send({ suggestedMessage: msg }, { tools: chatOverrideTools });
};

const handlePromptSelected = (option: PromptOption) => {
focusComposer();
setUserMessage(option.prompt);
};

return (
<div className="flex h-full w-full flex-col">
<HotKeysProvider customHotKeys={chatHotKeys} />
Expand Down Expand Up @@ -208,13 +199,12 @@ const Conversation: React.FC<Props> = ({ conversationId, welcomeMessageEnabled =
/>
<MessagingContainer
conversationId={conversationId}
welcomeMessageEnabled={welcomeMessageEnabled}
startOptionsEnabled={startOptionsEnabled}
isStreaming={isStreaming}
onRetry={handleRetry}
messages={messages}
streamingMessage={streamingMessage}
startOption={startOption}
onStartOptionChange={setStartOption}
onPromptSelected={handlePromptSelected}
composer={
<>
<WelcomeGuideTooltip step={3} className="absolute bottom-full mb-4" />
Expand Down
3 changes: 1 addition & 2 deletions src/interfaces/coral_web/src/components/MessageContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ const BOT_ERROR_MESSAGE = 'Unable to generate a response since an error was enco

export const MessageContent: React.FC<Props> = ({ isLast, message, onRetry }) => {
const isUser = message.type === MessageType.USER;
const isWelcome = message.type === MessageType.WELCOME;
const isLoading = isLoadingMessage(message);
const isBotError = isErroredMessage(message);
const isUserError = isUser && message.error;
Expand Down Expand Up @@ -105,7 +104,7 @@ export const MessageContent: React.FC<Props> = ({ isLast, message, onRetry }) =>
<>
<Markdown
className={cn({
'text-volcanic-700': isWelcome || isAborted,
'text-volcanic-700': isAborted,
})}
text={message.text}
customComponents={{
Expand Down
45 changes: 0 additions & 45 deletions src/interfaces/coral_web/src/components/Messages/Notification.tsx

This file was deleted.

This file was deleted.

Loading

0 comments on commit 00b6ed1

Please sign in to comment.