Skip to content

Commit

Permalink
Add: option to view plaintext chat message. Issue/2508 (#3496)
Browse files Browse the repository at this point in the history
Fixes: #2508 

Rendered by suspense
<img width="537" alt="image"
src="https://github.com/LAION-AI/Open-Assistant/assets/61619422/b259d0ad-44bb-4d80-9590-8a7fb9964c66">

Plain text
<img width="587" alt="image"
src="https://github.com/LAION-AI/Open-Assistant/assets/61619422/723600ec-cca2-4716-8abf-fde3ea2e63db">

I am not sure whether using memo on isPlainText has any performance
gain. I need your opinions.

---------

Co-authored-by: notmd <notmd1811@gmail.com>
  • Loading branch information
CertifiedJoon and notmd authored Jun 21, 2023
1 parent b2c7836 commit 4f1b1eb
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 7 deletions.
1 change: 1 addition & 0 deletions website/public/locales/en/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"no": "No",
"output": "Output",
"parameters": "Parameters",
"plain_text": "Plain Text",
"privacy_policy": "Privacy Policy",
"prompt": "Prompt",
"report_a_bug": "Report a Bug",
Expand Down
16 changes: 14 additions & 2 deletions website/src/components/Chat/ChatMessageEntry.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@ import { Check, Copy, Edit, RotateCcw, ThumbsUp, X, XCircle } from "lucide-react
import { ThumbsDown } from "lucide-react";
import { useSession } from "next-auth/react";
import { useTranslation } from "next-i18next";
import { forwardRef, KeyboardEvent, memo, ReactNode, useCallback, useMemo, useRef } from "react";
import { forwardRef, KeyboardEvent, memo, ReactNode, useCallback, useMemo, useRef, useState } from "react";
import { InferenceMessage } from "src/types/Chat";

import { MarkdownIcon } from "../icons/Markdown";
import { MarkdownOffIcon } from "../icons/MarkdownOff";
import { BaseMessageEntry } from "../Messages/BaseMessageEntry";
import { BaseMessageEmojiButton } from "../Messages/MessageEmojiButton";
import { MessageInlineEmojiRow } from "../Messages/MessageInlineEmojiRow";
Expand Down Expand Up @@ -92,6 +94,7 @@ export const ChatMessageEntry = memo(function ChatMessageEntry({

const isAssistant = message.role === "assistant";
const [isEditing, setIsEditing] = useBoolean(false);
const [isPlainText, setIsPlainText] = useState<boolean>(false);
const inputRef = useRef<HTMLTextAreaElement>(null);

const handleEditSubmit = useCallback(() => {
Expand Down Expand Up @@ -130,6 +133,7 @@ export const ChatMessageEntry = memo(function ChatMessageEntry({
isAssistant={isAssistant}
usedPlugin={used_plugin}
content={isEditing ? "" : content!}
isPlainText={isPlainText}
>
{!isAssistant && parentId !== null && (
<Box position="absolute" top={{ base: "4", md: 0 }} style={{ insetInlineEnd: `0.5rem` }}>
Expand Down Expand Up @@ -175,6 +179,12 @@ export const ChatMessageEntry = memo(function ChatMessageEntry({
)}
{state === "complete" && (
<>
<BaseMessageEmojiButton
emoji={isPlainText ? MarkdownIcon : MarkdownOffIcon}
onClick={() => setIsPlainText(!isPlainText)}
label={t("plain_text")}
/>

{canRetry && <BaseMessageEmojiButton emoji={RotateCcw} onClick={handleRetry} label={t("retry")} />}
{!hasCopied ? (
<BaseMessageEmojiButton emoji={Copy} onClick={onCopy} label={t("copy")} />
Expand Down Expand Up @@ -213,6 +223,7 @@ type PendingMessageEntryProps = {
id?: string;
"data-id"?: string;
usedPlugin?: object;
isPlainText?: boolean;
};

export const messageEntryContainerProps = {
Expand All @@ -221,7 +232,7 @@ export const messageEntryContainerProps = {
};

export const PendingMessageEntry = forwardRef<HTMLDivElement, PendingMessageEntryProps>(function PendingMessageEntry(
{ content, isAssistant, children, usedPlugin, ...props },
{ content, isAssistant, children, usedPlugin, isPlainText, ...props },
ref
) {
const bgUser = "transparent";
Expand All @@ -245,6 +256,7 @@ export const PendingMessageEntry = forwardRef<HTMLDivElement, PendingMessageEntr
isAssistant={isAssistant}
maxWidth={messageEntryContainerProps.maxWidth}
containerProps={messageEntryContainerProps}
isPlainText={isPlainText}
{...props}
>
{children}
Expand Down
15 changes: 10 additions & 5 deletions website/src/components/Messages/BaseMessageEntry.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@ export type BaseMessageEntryProps = StrictOmit<BoxProps, "bg" | "backgroundColor
usedPlugin?: object;
isAssistant?: boolean;
containerProps?: BoxProps;
isPlainText?: boolean;
};

export const BaseMessageEntry = forwardRef<HTMLDivElement, BaseMessageEntryProps>(function BaseMessageEntry(
{ content, avatarProps, children, highlight, usedPlugin, isAssistant, containerProps, ...props },
{ content, avatarProps, children, highlight, usedPlugin, isAssistant, containerProps, isPlainText, ...props },
ref
) {
const bg = useColorModeValue("#DFE8F1", "#42536B");
Expand Down Expand Up @@ -63,10 +64,14 @@ export const BaseMessageEntry = forwardRef<HTMLDivElement, BaseMessageEntryProps
{...props}
_dark={{ outlineColor: { md: colors.dark.active }, ...props._dark }}
>
<Suspense fallback={content}>
{isAssistant ? <PluginUsageDetails usedPlugin={usedPlugin} /> : null}
<RenderedMarkdown markdown={content} disallowedElements={[]}></RenderedMarkdown>
</Suspense>
{!isPlainText ? (
<Suspense fallback={content}>
{isAssistant ? <PluginUsageDetails usedPlugin={usedPlugin} /> : null}
<RenderedMarkdown markdown={content} disallowedElements={[]}></RenderedMarkdown>
</Suspense>
) : (
content
)}
{children}
</Box>
</Flex>
Expand Down
24 changes: 24 additions & 0 deletions website/src/components/icons/Markdown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { LucideProps } from "lucide-react";

export const MarkdownIcon = (props: LucideProps) => {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
className="icon icon-tabler icon-tabler-markdown"
width={24}
height={24}
viewBox="0 0 24 24"
strokeWidth="2"
stroke="currentColor"
fill="none"
strokeLinecap="round"
strokeLinejoin="round"
{...props}
>
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M3 5m0 2a2 2 0 0 1 2 -2h14a2 2 0 0 1 2 2v10a2 2 0 0 1 -2 2h-14a2 2 0 0 1 -2 -2z"></path>
<path d="M7 15v-6l2 2l2 -2v6"></path>
<path d="M14 13l2 2l2 -2m-2 2v-6"></path>
</svg>
);
};
26 changes: 26 additions & 0 deletions website/src/components/icons/MarkdownOff.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { LucideProps } from "lucide-react";

export const MarkdownOffIcon = (props: LucideProps) => {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
className="icon icon-tabler icon-tabler-markdown-off"
width={24}
height={24}
viewBox="0 0 24 24"
strokeWidth="2"
stroke="currentColor"
fill="none"
strokeLinecap="round"
strokeLinejoin="round"
{...props}
>
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M9 5h10a2 2 0 0 1 2 2v10"></path>
<path d="M19 19h-14a2 2 0 0 1 -2 -2v-10a2 2 0 0 1 1.85 -2"></path>
<path d="M7 15v-6l2 2l1 -1m1 1v4"></path>
<path d="M17.5 13.5l.5 -.5m-2 -1v-3"></path>
<path d="M3 3l18 18"></path>
</svg>
);
};

0 comments on commit 4f1b1eb

Please sign in to comment.