diff --git a/website/public/locales/en/chat.json b/website/public/locales/en/chat.json index a5c6ef9a5c..adbf5d98d0 100644 --- a/website/public/locales/en/chat.json +++ b/website/public/locales/en/chat.json @@ -46,5 +46,7 @@ "save_preset": "Save this preset", "preset_exists_error": "A preset with this name already exists", "preset_name_placeholder": "Enter name", - "feedback_message": "Thoughts? Let us know!" + "feedback_message": "How did I do? Your feedback will make me better!", + "feedback_action_great": "Good", + "feedback_action_poor": "Could be better" } diff --git a/website/src/components/Chat/ChatConversation.tsx b/website/src/components/Chat/ChatConversation.tsx index eaff46a87d..089b2861b0 100644 --- a/website/src/components/Chat/ChatConversation.tsx +++ b/website/src/components/Chat/ChatConversation.tsx @@ -39,6 +39,8 @@ export const ChatConversation = memo(function ChatConversation({ chatId, getConf const [streamedResponse, setResponse] = useState(null); const [queueInfo, setQueueInfo] = useState(null); const [isSending, setIsSending] = useBoolean(); + const [showEncourageMessage, setShowEncourageMessage] = useBoolean(false); + const toast = useToast(); const { isLoading: isLoadingMessages } = useSWR(chatId ? API_ROUTES.GET_CHAT(chatId) : null, get, { @@ -110,8 +112,9 @@ export const ChatConversation = memo(function ChatConversation({ chatId, getConf setQueueInfo(null); setResponse(null); setIsSending.off(); + setShowEncourageMessage.on(); }, - [getConfigValues, setIsSending, toast] + [getConfigValues, setIsSending, setShowEncourageMessage, toast] ); const sendPrompterMessage = useCallback(async () => { const content = inputRef.current?.value.trim(); @@ -119,6 +122,7 @@ export const ChatConversation = memo(function ChatConversation({ chatId, getConf return; } setIsSending.on(); + setShowEncourageMessage.off(); // TODO: maybe at some point we won't need to access the rendered HTML directly, but use react state const parentId = document.getElementById(LAST_ASSISTANT_MESSAGE_ID)?.dataset.id ?? null; @@ -164,7 +168,7 @@ export const ChatConversation = memo(function ChatConversation({ chatId, getConf inputRef.current!.value = ""; // after creating the prompters message, handle the assistant's case await createAndFetchAssistantMessage({ parentId: prompter_message.id, chatId }); - }, [setIsSending, chatId, messages, createAndFetchAssistantMessage, toast, isSending]); + }, [isSending, setIsSending, setShowEncourageMessage, chatId, messages, createAndFetchAssistantMessage, toast]); const sendVote = useMessageVote(); @@ -284,6 +288,8 @@ export const ChatConversation = memo(function ChatConversation({ chatId, getConf isSending={isSending} retryingParentId={retryingParentId} onEditPromtp={handleEditPrompt} + showEncourageMessage={showEncourageMessage} + onEncourageMessageClose={setShowEncourageMessage.off} > {isSending && streamedResponse && }
diff --git a/website/src/components/Chat/ChatConversationTree.tsx b/website/src/components/Chat/ChatConversationTree.tsx index a342cbab86..a9baeb71b9 100644 --- a/website/src/components/Chat/ChatConversationTree.tsx +++ b/website/src/components/Chat/ChatConversationTree.tsx @@ -76,6 +76,7 @@ const TreeChildren = ({ message={currentTree} {...props} canRetry={isLeaf} + showEncourageMessage={props.showEncourageMessage && isLeaf} // TODO refacor away from this dirty hack id={isLeaf && currentTree.role === "assistant" ? LAST_ASSISTANT_MESSAGE_ID : undefined} data-id={currentTree.id} diff --git a/website/src/components/Chat/ChatMessageEntry.tsx b/website/src/components/Chat/ChatMessageEntry.tsx index 7095e1b3fa..53cbda7465 100644 --- a/website/src/components/Chat/ChatMessageEntry.tsx +++ b/website/src/components/Chat/ChatMessageEntry.tsx @@ -21,8 +21,8 @@ import { InferenceMessage } from "src/types/Chat"; import { BaseMessageEntry } from "../Messages/BaseMessageEntry"; import { BaseMessageEmojiButton } from "../Messages/MessageEmojiButton"; import { MessageInlineEmojiRow } from "../Messages/MessageInlineEmojiRow"; -import { WorkParametersDisplay } from "./WorkParameters"; import { EncourageMessage } from "./EncourageMessage"; +import { WorkParametersDisplay } from "./WorkParameters"; export type EditPromptParams = { parentId: string; chatId: string; content: string }; @@ -36,6 +36,8 @@ export type ChatMessageEntryProps = { canRetry?: boolean; id?: string; "data-id"?: string; + showEncourageMessage: boolean; + onEncourageMessageClose: () => void; }; export const ChatMessageEntry = memo(function ChatMessageEntry({ @@ -46,6 +48,8 @@ export const ChatMessageEntry = memo(function ChatMessageEntry({ pagingSlot, onEditPromtp, canRetry, + showEncourageMessage, + onEncourageMessageClose, ...props }: ChatMessageEntryProps) { const { t } = useTranslation("common"); @@ -114,74 +118,82 @@ export const ChatMessageEntry = memo(function ChatMessageEntry({ const { onCopy, hasCopied } = useClipboard(message.content); return ( - - {!isAssistant && parentId !== null && ( - - {isEditing ? ( - - - - - ) : ( - - )} - - )} - {isEditing && ( - - - - )} - {!isEditing && ( - - {pagingSlot} - {isAssistant && ( - - {(state === "pending" || state === "in_progress") && ( - - )} - {(state === "aborted_by_worker" || state === "cancelled" || state === "timeout") && ( - <> - - {`Error: ${state}`} - {onRetry && !isSending && } - - )} - {state === "complete" && ( - <> - - {canRetry && } - {!hasCopied ? ( - - ) : ( - - )} - - - - )} - - )} - + <> + + {!isAssistant && parentId !== null && ( + + {isEditing ? ( + + + + + ) : ( + + )} + + )} + {isEditing && ( + + + + )} + {!isEditing && ( + + {pagingSlot} + {isAssistant && ( + + {(state === "pending" || state === "in_progress") && ( + + )} + {(state === "aborted_by_worker" || state === "cancelled" || state === "timeout") && ( + <> + + {`Error: ${state}`} + {onRetry && !isSending && } + + )} + {state === "complete" && ( + <> + {canRetry && } + {!hasCopied ? ( + + ) : ( + + )} + + + + )} + + )} + + )} + {work_parameters && } + + {state === "complete" && isAssistant && showEncourageMessage && ( + )} - {work_parameters && } - + ); }); @@ -194,7 +206,7 @@ type PendingMessageEntryProps = { usedPlugin?: object; }; -const messageEntryContainerProps = { +export const messageEntryContainerProps = { maxWidth: { base: "3xl", "2xl": "4xl" }, w: "full", }; diff --git a/website/src/components/Chat/EncourageMessage.tsx b/website/src/components/Chat/EncourageMessage.tsx index 097ffd908b..79974cf2d7 100644 --- a/website/src/components/Chat/EncourageMessage.tsx +++ b/website/src/components/Chat/EncourageMessage.tsx @@ -1,11 +1,66 @@ -import { Badge } from "@chakra-ui/react"; +import { Box, Button, ButtonProps, Card, Flex } from "@chakra-ui/react"; +import { ThumbsDown, ThumbsUp, X } from "lucide-react"; import { useTranslation } from "next-i18next"; -// kept brief so that it doesnt distract/interfere with user experience -export const EncourageMessage = () => { + +import { messageEntryContainerProps } from "./ChatMessageEntry"; + +export const EncourageMessage = ({ + onClose, + onThumbsDown, + onThumbsUp, +}: { + onThumbsUp: () => void; + onThumbsDown: () => void; + onClose: () => void; +}) => { const { t } = useTranslation("chat"); + return ( - - {t("feedback_message")} - + + + {t("feedback_message")} + + } + onClick={() => { + onThumbsUp(); + onClose(); + }} + > + {t("feedback_action_great")} + + } + onClick={() => { + onThumbsDown(); + onClose(); + }} + > + {t("feedback_action_poor")} + + + + + + + ); }; + +const FeedBackButton = (props: ButtonProps) => { + return ; +};