diff --git a/frontend/src/components/DefaultChat/index.jsx b/frontend/src/components/DefaultChat/index.jsx index 4340adaeafe..9519aacf70d 100644 --- a/frontend/src/components/DefaultChat/index.jsx +++ b/frontend/src/components/DefaultChat/index.jsx @@ -18,8 +18,10 @@ import { userFromStorage } from "@/utils/request"; import useUser from "@/hooks/useUser"; import { useTranslation, Trans } from "react-i18next"; import Appearance from "@/models/appearance"; +import { useChatMessageAlignment } from "@/hooks/useChatMessageAlignment"; export default function DefaultChatContainer() { + const { getMessageAlignment } = useChatMessageAlignment(); const { showScrollbar } = Appearance.getSettings(); const [mockMsgs, setMockMessages] = useState([]); const { user } = useUser(); @@ -43,7 +45,7 @@ export default function DefaultChatContainer() { const MESSAGES = [ - + {t("welcomeMessage.part1")} @@ -52,7 +54,7 @@ export default function DefaultChatContainer() { - + {t("welcomeMessage.part2")} @@ -61,7 +63,7 @@ export default function DefaultChatContainer() { - +
{t("welcomeMessage.part3")} @@ -81,7 +83,7 @@ export default function DefaultChatContainer() { - + {t("welcomeMessage.user1")} @@ -90,7 +92,7 @@ export default function DefaultChatContainer() { - +
{t("welcomeMessage.part4")} @@ -111,7 +113,7 @@ export default function DefaultChatContainer() { - + {t("welcomeMessage.user2")} @@ -120,7 +122,7 @@ export default function DefaultChatContainer() { - + - + {t("welcomeMessage.user3")} @@ -146,7 +148,7 @@ export default function DefaultChatContainer() { - +
{t("welcomeMessage.part6")} @@ -242,8 +244,8 @@ function MessageContainer({ children }) { ); } -function MessageContent({ children }) { - return
{children}
; +function MessageContent({ children, alignmentCls = "" }) { + return
{children}
; } function MessageText({ children }) { diff --git a/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/HistoricalMessage/Actions/index.jsx b/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/HistoricalMessage/Actions/index.jsx index 0b05576008b..70236ee9dd0 100644 --- a/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/HistoricalMessage/Actions/index.jsx +++ b/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/HistoricalMessage/Actions/index.jsx @@ -17,6 +17,7 @@ const Actions = ({ isEditing, role, metrics = {}, + alignmentCls = "", }) => { const [selectedFeedback, setSelectedFeedback] = useState(feedbackScore); const handleFeedback = async (newFeedback) => { @@ -27,7 +28,7 @@ const Actions = ({ }; return ( -
+
diff --git a/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/HistoricalMessage/index.jsx b/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/HistoricalMessage/index.jsx index 5a5454bb283..7a913b96277 100644 --- a/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/HistoricalMessage/index.jsx +++ b/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/HistoricalMessage/index.jsx @@ -32,6 +32,7 @@ const HistoricalMessage = ({ saveEditedMessage, forkThread, metrics = {}, + alignmentCls = "", }) => { const { isEditing } = useEditMessage({ chatId, role }); const { isDeleted, completeDelete, onEndAnimation } = useWatchDeleteMessage({ @@ -51,7 +52,7 @@ const HistoricalMessage = ({ className={`flex justify-center items-end w-full bg-theme-bg-chat`} >
-
+
@@ -69,6 +70,7 @@ const HistoricalMessage = ({ } if (completeDelete) return null; + return (
-
+
@@ -123,6 +125,7 @@ const HistoricalMessage = ({ role={role} forkThread={forkThread} metrics={metrics} + alignmentCls={alignmentCls} />
{role === "assistant" && } diff --git a/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/index.jsx b/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/index.jsx index c78a8f21aeb..373660230eb 100644 --- a/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/index.jsx +++ b/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/index.jsx @@ -14,6 +14,7 @@ import paths from "@/utils/paths"; import Appearance from "@/models/appearance"; import useTextSize from "@/hooks/useTextSize"; import { v4 } from "uuid"; +import { useChatMessageAlignment } from "@/hooks/useChatMessageAlignment"; export default function ChatHistory({ history = [], @@ -33,6 +34,7 @@ export default function ChatHistory({ const isStreaming = history[history.length - 1]?.animate; const { showScrollbar } = Appearance.getSettings(); const { textSizeClass } = useTextSize(); + const { getMessageAlignment } = useChatMessageAlignment(); useEffect(() => { if (!isUserScrolling && (isAtBottom || isStreaming)) { @@ -146,6 +148,7 @@ export default function ChatHistory({ regenerateAssistantMessage, saveEditedMessage, forkThread, + getMessageAlignment, }), [ workspace, @@ -282,6 +285,7 @@ function WorkspaceChatSuggestions({ suggestions = [], sendSuggestion }) { * @param {Function} param0.regenerateAssistantMessage - The function to regenerate the assistant message. * @param {Function} param0.saveEditedMessage - The function to save the edited message. * @param {Function} param0.forkThread - The function to fork the thread. + * @param {Function} param0.getMessageAlignment - The function to get the alignment of the message (returns class). * @returns {Array} The compiled history of messages. */ function buildMessages({ @@ -290,6 +294,7 @@ function buildMessages({ regenerateAssistantMessage, saveEditedMessage, forkThread, + getMessageAlignment, }) { return history.reduce((acc, props, index) => { const isLastBotReply = @@ -338,6 +343,7 @@ function buildMessages({ saveEditedMessage={saveEditedMessage} forkThread={forkThread} metrics={props.metrics} + alignmentCls={getMessageAlignment?.(props.role)} /> ); } diff --git a/frontend/src/hooks/useChatMessageAlignment.js b/frontend/src/hooks/useChatMessageAlignment.js new file mode 100644 index 00000000000..60668832fc4 --- /dev/null +++ b/frontend/src/hooks/useChatMessageAlignment.js @@ -0,0 +1,30 @@ +import { useState, useEffect, useCallback } from "react"; +const ALIGNMENT_STORAGE_KEY = "anythingllm-chat-message-alignment"; + +/** + * Store the message alignment in localStorage as well as provide a function to get the alignment of a message via role. + * @returns {{msgDirection: 'left'|'left_right', setMsgDirection: (direction: string) => void, getMessageAlignment: (role: string) => string}} - The message direction and the class name for the direction. + */ +export function useChatMessageAlignment() { + const [msgDirection, setMsgDirection] = useState( + () => localStorage.getItem(ALIGNMENT_STORAGE_KEY) ?? "left" + ); + + useEffect(() => { + if (msgDirection) localStorage.setItem(ALIGNMENT_STORAGE_KEY, msgDirection); + }, [msgDirection]); + + const getMessageAlignment = useCallback( + (role) => { + const isLeftToRight = role === "user" && msgDirection === "left_right"; + return isLeftToRight ? "flex-row-reverse" : ""; + }, + [msgDirection] + ); + + return { + msgDirection, + setMsgDirection, + getMessageAlignment, + }; +} diff --git a/frontend/src/pages/GeneralSettings/Appearance/MessageDirection/index.jsx b/frontend/src/pages/GeneralSettings/Appearance/MessageDirection/index.jsx new file mode 100644 index 00000000000..79998fb1388 --- /dev/null +++ b/frontend/src/pages/GeneralSettings/Appearance/MessageDirection/index.jsx @@ -0,0 +1,67 @@ +import { useChatMessageAlignment } from "@/hooks/useChatMessageAlignment"; +import { Tooltip } from "react-tooltip"; + +export function MessageDirection() { + const { msgDirection, setMsgDirection } = useChatMessageAlignment(); + + return ( +
+

+ Message Chat Alignment +

+

+ Select the message alignment mode when using the chat interface. +

+
+ { + setMsgDirection("left"); + }} + /> + { + setMsgDirection("left_right"); + }} + /> +
+ +
+ ); +} + +function ItemDirection({ active, reverse, onSelect, msg }) { + return ( + + ); +} diff --git a/frontend/src/pages/GeneralSettings/Appearance/index.jsx b/frontend/src/pages/GeneralSettings/Appearance/index.jsx index 00a415bb2d5..0ff55aa39b8 100644 --- a/frontend/src/pages/GeneralSettings/Appearance/index.jsx +++ b/frontend/src/pages/GeneralSettings/Appearance/index.jsx @@ -10,6 +10,7 @@ import LanguagePreference from "./LanguagePreference"; import CustomSiteSettings from "./CustomSiteSettings"; import ShowScrollbar from "./ShowScrollbar"; import ThemePreference from "./ThemePreference"; +import { MessageDirection } from "./MessageDirection"; export default function Appearance() { const { t } = useTranslation(); @@ -34,6 +35,7 @@ export default function Appearance() {
+