diff --git a/web/src/app/chat/ChatPage.tsx b/web/src/app/chat/ChatPage.tsx index 467a03dee76..e4fcccd9047 100644 --- a/web/src/app/chat/ChatPage.tsx +++ b/web/src/app/chat/ChatPage.tsx @@ -140,7 +140,33 @@ export function ChatPage({ const { user, isAdmin, isLoadingUser } = useUser(); const existingChatIdRaw = searchParams.get("chatId"); + const [sendOnLoad, setSendOnLoad] = useState( + searchParams.get(SEARCH_PARAM_NAMES.SEND_ON_LOAD) + ); + const currentPersonaId = searchParams.get(SEARCH_PARAM_NAMES.PERSONA_ID); + const modelVersionFromSearchParams = searchParams.get( + SEARCH_PARAM_NAMES.STRUCTURED_MODEL + ); + + // Effect to handle sendOnLoad + useEffect(() => { + if (sendOnLoad) { + const newSearchParams = new URLSearchParams(searchParams.toString()); + newSearchParams.delete(SEARCH_PARAM_NAMES.SEND_ON_LOAD); + + // Update the URL without the send-on-load parameter + router.replace(`?${newSearchParams.toString()}`, { scroll: false }); + + // Update our local state to reflect the change + setSendOnLoad(null); + + // If there's a message, submit it + if (message) { + onSubmit({ messageOverride: message }); + } + } + }, [sendOnLoad, searchParams, router]); const existingChatSessionId = existingChatIdRaw ? existingChatIdRaw : null; @@ -196,7 +222,7 @@ export function ChatPage({ }; const llmOverrideManager = useLlmOverride( - user?.preferences.default_model ?? null, + modelVersionFromSearchParams || (user?.preferences.default_model ?? null), selectedChatSession, defaultTemperature ); @@ -1853,6 +1879,9 @@ export function ChatPage({ {sharedChatSession && ( setSharedChatSession(null)} @@ -1867,6 +1896,9 @@ export function ChatPage({ )} {sharingModalVisible && chatSessionIdRef.current !== null && ( setSharingModalVisible(false)} diff --git a/web/src/app/chat/modal/ShareChatSessionModal.tsx b/web/src/app/chat/modal/ShareChatSessionModal.tsx index 1b797e77ab9..4743efdf0dc 100644 --- a/web/src/app/chat/modal/ShareChatSessionModal.tsx +++ b/web/src/app/chat/modal/ShareChatSessionModal.tsx @@ -5,6 +5,10 @@ import { Spinner } from "@/components/Spinner"; import { ChatSessionSharedStatus } from "../interfaces"; import { FiCopy } from "react-icons/fi"; import { CopyButton } from "@/components/CopyButton"; +import { SEARCH_PARAM_NAMES } from "../searchParams"; +import { usePopup } from "@/components/admin/connectors/Popup"; +import { destructureValue, structureValue } from "@/lib/llm/utils"; +import { LlmOverride } from "@/lib/hooks"; function buildShareLink(chatSessionId: string) { const baseUrl = `${window.location.protocol}//${window.location.host}`; @@ -26,6 +30,34 @@ async function generateShareLink(chatSessionId: string) { return null; } +async function generateCloneLink( + message?: string, + assistantId?: number, + modelOverride?: LlmOverride +) { + const baseUrl = `${window.location.protocol}//${window.location.host}`; + const model = modelOverride + ? structureValue( + modelOverride.name, + modelOverride.provider, + modelOverride.modelName + ) + : null; + return `${baseUrl}/chat${ + message + ? `?${SEARCH_PARAM_NAMES.USER_PROMPT}=${encodeURIComponent(message)}` + : "" + }${ + assistantId + ? `${message ? "&" : "?"}${SEARCH_PARAM_NAMES.PERSONA_ID}=${assistantId}` + : "" + }${ + model + ? `${message || assistantId ? "&" : "?"}${SEARCH_PARAM_NAMES.STRUCTURED_MODEL}=${encodeURIComponent(model)}` + : "" + }${message ? `&${SEARCH_PARAM_NAMES.SEND_ON_LOAD}=true` : ""}`; +} + async function deleteShareLink(chatSessionId: string) { const response = await fetch(`/api/chat/chat-session/${chatSessionId}`, { method: "PATCH", @@ -43,117 +75,162 @@ export function ShareChatSessionModal({ existingSharedStatus, onShare, onClose, + message, + assistantId, + modelOverride, }: { chatSessionId: string; existingSharedStatus: ChatSessionSharedStatus; onShare?: (shared: boolean) => void; onClose: () => void; + message?: string; + assistantId?: number; + modelOverride?: LlmOverride; }) { - const [linkGenerating, setLinkGenerating] = useState(false); const [shareLink, setShareLink] = useState( existingSharedStatus === ChatSessionSharedStatus.Public ? buildShareLink(chatSessionId) : "" ); + const { popup, setPopup } = usePopup(); return ( - - <> -
-

- Share link to Chat -

-
- - {linkGenerating && } - -
- {shareLink ? ( -
- - This chat session is currently shared. Anyone at your - organization can view the message history using the following - link: - - -
- - + {popup} + + <> +
+

+ Share link to Chat +

+
+ +
+ {shareLink ? ( +
+ + This chat session is currently shared. Anyone at your + organization can view the message history using the following + link: + + + + + + + + Click the button below to make the chat private again. + + +
- - - - - Click the button below to make the chat private again. - - - +
+
+ )} +
+ + +
+ + Generate a link to clone this chat session with the current query. + This allows others to start a new chat with the same initial + message and settings. + +
+
+ -
- ) : ( -
- - Ensure that all content in the chat is safe to share with the - whole organization. The content of the retrieved documents will - not be visible, but the names of cited documents as well as the - AI and human messages will be visible. - - - -
- )} -
- -
+ } catch (e) { + console.error(e); + alert("Failed to generate or copy link."); + } + }} + size="xs" + color="blue" + > + Generate and Copy Clone Link + + + + + ); } diff --git a/web/src/app/chat/searchParams.ts b/web/src/app/chat/searchParams.ts index 56bcf4e33f4..7b3dc44fe97 100644 --- a/web/src/app/chat/searchParams.ts +++ b/web/src/app/chat/searchParams.ts @@ -9,6 +9,7 @@ export const SEARCH_PARAM_NAMES = { TEMPERATURE: "temperature", MODEL_VERSION: "model-version", SYSTEM_PROMPT: "system-prompt", + STRUCTURED_MODEL: "structured-model", // user message USER_PROMPT: "user-prompt", SUBMIT_ON_LOAD: "submit-on-load", @@ -16,6 +17,7 @@ export const SEARCH_PARAM_NAMES = { TITLE: "title", // for seeding chats SEEDED: "seeded", + SEND_ON_LOAD: "send-on-load", }; export function shouldSubmitOnLoad(searchParams: ReadonlyURLSearchParams) {