mirror of
https://github.com/arc53/DocsGPT.git
synced 2025-12-01 01:23:14 +00:00
Merge branch 'main' into feat/enhance-agents
This commit is contained in:
@@ -1,11 +1,14 @@
|
||||
import 'katex/dist/katex.min.css';
|
||||
|
||||
import { forwardRef, useRef, useState } from 'react';
|
||||
import { forwardRef, Fragment, useRef, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import ReactMarkdown from 'react-markdown';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
|
||||
import { oneLight, vscDarkPlus } from 'react-syntax-highlighter/dist/cjs/styles/prism';
|
||||
import {
|
||||
oneLight,
|
||||
vscDarkPlus,
|
||||
} from 'react-syntax-highlighter/dist/cjs/styles/prism';
|
||||
import rehypeKatex from 'rehype-katex';
|
||||
import remarkGfm from 'remark-gfm';
|
||||
import remarkMath from 'remark-math';
|
||||
@@ -26,10 +29,14 @@ import CopyButton from '../components/CopyButton';
|
||||
import Sidebar from '../components/Sidebar';
|
||||
import SpeakButton from '../components/TextToSpeechButton';
|
||||
import { useDarkTheme, useOutsideAlerter } from '../hooks';
|
||||
import { selectChunks, selectSelectedDocs } from '../preferences/preferenceSlice';
|
||||
import {
|
||||
selectChunks,
|
||||
selectSelectedDocs,
|
||||
} from '../preferences/preferenceSlice';
|
||||
import classes from './ConversationBubble.module.css';
|
||||
import { FEEDBACK, MESSAGE_TYPE } from './conversationModels';
|
||||
import { ToolCallsType } from './types';
|
||||
import MermaidRenderer from '../components/MermaidRenderer';
|
||||
|
||||
const DisableSourceFE = import.meta.env.VITE_DISABLE_SOURCE_FE || false;
|
||||
|
||||
@@ -46,6 +53,7 @@ const ConversationBubble = forwardRef<
|
||||
toolCalls?: ToolCallsType[];
|
||||
retryBtn?: React.ReactElement;
|
||||
questionNumber?: number;
|
||||
isStreaming?: boolean;
|
||||
handleUpdatedQuestionSubmission?: (
|
||||
updatedquestion?: string,
|
||||
updated?: boolean,
|
||||
@@ -64,6 +72,7 @@ const ConversationBubble = forwardRef<
|
||||
toolCalls,
|
||||
retryBtn,
|
||||
questionNumber,
|
||||
isStreaming,
|
||||
handleUpdatedQuestionSubmission,
|
||||
},
|
||||
ref,
|
||||
@@ -103,19 +112,19 @@ const ConversationBubble = forwardRef<
|
||||
>
|
||||
<Avatar
|
||||
size="SMALL"
|
||||
className="mt-2 text-2xl flex-shrink-0"
|
||||
className="mt-2 flex-shrink-0 text-2xl"
|
||||
avatar={
|
||||
<img className="rounded-full mr-1" width={30} src={UserIcon} />
|
||||
<img className="mr-1 rounded-full" width={30} src={UserIcon} />
|
||||
}
|
||||
/>
|
||||
{!isEditClicked && (
|
||||
<>
|
||||
<div className="flex flex-col mr-2">
|
||||
<div className="mr-2 flex flex-col">
|
||||
<div
|
||||
style={{
|
||||
wordBreak: 'break-word',
|
||||
}}
|
||||
className="text-sm sm:text-base ml-2 mr-2 flex items-center rounded-[28px] bg-gradient-to-b from-medium-purple to-slate-blue py-[14px] px-[19px] text-white max-w-full whitespace-pre-wrap leading-normal"
|
||||
className="ml-2 mr-2 flex max-w-full items-center whitespace-pre-wrap rounded-[28px] bg-gradient-to-b from-medium-purple to-slate-blue px-[19px] py-[14px] text-sm leading-normal text-white sm:text-base"
|
||||
>
|
||||
{message}
|
||||
</div>
|
||||
@@ -125,7 +134,7 @@ const ConversationBubble = forwardRef<
|
||||
setIsEditClicked(true);
|
||||
setEditInputBox(message ?? '');
|
||||
}}
|
||||
className={`flex-shrink-0 h-fit mt-3 p-2 cursor-pointer rounded-full hover:bg-light-silver dark:hover:bg-[#35363B] flex items-center ${isQuestionHovered || isEditClicked ? 'visible' : 'invisible'}`}
|
||||
className={`mt-3 flex h-fit flex-shrink-0 cursor-pointer items-center rounded-full p-2 hover:bg-light-silver dark:hover:bg-[#35363B] ${isQuestionHovered || isEditClicked ? 'visible' : 'invisible'}`}
|
||||
>
|
||||
<img src={Edit} alt="Edit" className="cursor-pointer" />
|
||||
</button>
|
||||
@@ -134,7 +143,7 @@ const ConversationBubble = forwardRef<
|
||||
{isEditClicked && (
|
||||
<div
|
||||
ref={editableQueryRef}
|
||||
className="w-full mx-auto bg-transparent p-4 rounded-lg flex flex-col gap-4"
|
||||
className="mx-auto flex w-full flex-col gap-4 rounded-lg bg-transparent p-4"
|
||||
>
|
||||
<textarea
|
||||
placeholder={t('conversation.edit.placeholder')}
|
||||
@@ -149,17 +158,17 @@ const ConversationBubble = forwardRef<
|
||||
}}
|
||||
rows={5}
|
||||
value={editInputBox}
|
||||
className="w-full resize-none border border-silver dark:border-philippine-grey rounded-3xl px-4 py-3 text-base leading-relaxed text-carbon dark:text-chinese-white dark:bg-raisin-black focus:outline-none"
|
||||
className="w-full resize-none rounded-3xl border border-silver px-4 py-3 text-base leading-relaxed text-carbon focus:outline-none dark:border-philippine-grey dark:bg-raisin-black dark:text-chinese-white"
|
||||
/>
|
||||
<div className="flex items-center justify-end gap-2">
|
||||
<button
|
||||
className="px-4 py-2 text-purple-30 text-sm font-semibold hover:text-chinese-black-2 dark:hover:text-[#B9BCBE] hover:bg-gainsboro dark:hover:bg-onyx-2 transition-colors rounded-full"
|
||||
className="rounded-full px-4 py-2 text-sm font-semibold text-purple-30 transition-colors hover:bg-gainsboro hover:text-chinese-black-2 dark:hover:bg-onyx-2 dark:hover:text-[#B9BCBE]"
|
||||
onClick={() => setIsEditClicked(false)}
|
||||
>
|
||||
{t('conversation.edit.cancel')}
|
||||
</button>
|
||||
<button
|
||||
className="rounded-full bg-purple-30 hover:bg-violets-are-blue dark:hover:bg-royal-purple px-4 py-2 text-white text-sm font-medium transition-colors"
|
||||
className="rounded-full bg-purple-30 px-4 py-2 text-sm font-medium text-white transition-colors hover:bg-violets-are-blue dark:hover:bg-royal-purple"
|
||||
onClick={handleEditClick}
|
||||
>
|
||||
{t('conversation.edit.update')}
|
||||
@@ -186,10 +195,40 @@ const ConversationBubble = forwardRef<
|
||||
|
||||
return inlineProcessedContent;
|
||||
};
|
||||
const processMarkdownContent = (content: string) => {
|
||||
const processedContent = preprocessLaTeX(content);
|
||||
|
||||
const contentSegments: Array<{
|
||||
type: 'text' | 'mermaid';
|
||||
content: string;
|
||||
}> = [];
|
||||
|
||||
let lastIndex = 0;
|
||||
const regex = /```mermaid\n([\s\S]*?)```/g;
|
||||
let match;
|
||||
|
||||
while ((match = regex.exec(processedContent)) !== null) {
|
||||
const textBefore = processedContent.substring(lastIndex, match.index);
|
||||
if (textBefore) {
|
||||
contentSegments.push({ type: 'text', content: textBefore });
|
||||
}
|
||||
|
||||
contentSegments.push({ type: 'mermaid', content: match[1].trim() });
|
||||
|
||||
lastIndex = match.index + match[0].length;
|
||||
}
|
||||
|
||||
const textAfter = processedContent.substring(lastIndex);
|
||||
if (textAfter) {
|
||||
contentSegments.push({ type: 'text', content: textAfter });
|
||||
}
|
||||
|
||||
return contentSegments;
|
||||
};
|
||||
bubble = (
|
||||
<div
|
||||
ref={ref}
|
||||
className={`flex flex-wrap self-start ${className} group flex-col dark:text-bright-gray`}
|
||||
className={`flex flex-wrap self-start ${className} group flex-col dark:text-bright-gray`}
|
||||
>
|
||||
{DisableSourceFE ||
|
||||
type === 'ERROR' ||
|
||||
@@ -331,7 +370,7 @@ const ConversationBubble = forwardRef<
|
||||
<Thought thought={thought} preprocessLaTeX={preprocessLaTeX} />
|
||||
)}
|
||||
{message && (
|
||||
<div className="flex flex-col flex-wrap items-start self-start lg:flex-nowrap">
|
||||
<div className="flex max-w-full flex-col flex-wrap items-start self-start lg:flex-nowrap">
|
||||
<div className="my-2 flex flex-row items-center justify-center gap-3">
|
||||
<Avatar
|
||||
className="h-[34px] w-[34px] text-2xl"
|
||||
@@ -348,120 +387,158 @@ const ConversationBubble = forwardRef<
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
className={`fade-in-bubble ml-2 mr-5 flex max-w-[90vw] rounded-[28px] bg-gray-1000 py-[18px] px-7 dark:bg-gun-metal md:max-w-[70vw] lg:max-w-[50vw] ${
|
||||
className={`fade-in-bubble mr-5 flex max-w-full rounded-[28px] bg-gray-1000 px-7 py-[18px] dark:bg-gun-metal ${
|
||||
type === 'ERROR'
|
||||
? 'relative flex-row items-center rounded-full border border-transparent bg-[#FFE7E7] p-2 py-5 text-sm font-normal text-red-3000 dark:border-red-2000 dark:text-white'
|
||||
? 'relative flex-row items-center rounded-full border border-transparent bg-[#FFE7E7] p-2 py-5 text-sm font-normal text-red-3000 dark:border-red-2000 dark:text-white'
|
||||
: 'flex-col rounded-3xl'
|
||||
}`}
|
||||
>
|
||||
<ReactMarkdown
|
||||
className="fade-in whitespace-pre-wrap break-words leading-normal"
|
||||
remarkPlugins={[remarkGfm, remarkMath]}
|
||||
rehypePlugins={[rehypeKatex]}
|
||||
components={{
|
||||
code(props) {
|
||||
const { children, className, node, ref, ...rest } = props;
|
||||
const match = /language-(\w+)/.exec(className || '');
|
||||
const language = match ? match[1] : '';
|
||||
{(() => {
|
||||
const contentSegments = processMarkdownContent(message);
|
||||
return (
|
||||
<>
|
||||
{contentSegments.map((segment, index) => (
|
||||
<Fragment key={index}>
|
||||
{segment.type === 'text' ? (
|
||||
<ReactMarkdown
|
||||
className="fade-in whitespace-pre-wrap break-words leading-normal"
|
||||
remarkPlugins={[remarkGfm, remarkMath]}
|
||||
rehypePlugins={[rehypeKatex]}
|
||||
components={{
|
||||
code(props) {
|
||||
const {
|
||||
children,
|
||||
className,
|
||||
node,
|
||||
ref,
|
||||
...rest
|
||||
} = props;
|
||||
const match = /language-(\w+)/.exec(
|
||||
className || '',
|
||||
);
|
||||
const language = match ? match[1] : '';
|
||||
|
||||
return match ? (
|
||||
<div className="group relative rounded-[14px] overflow-hidden border border-light-silver dark:border-raisin-black">
|
||||
<div className="flex justify-between items-center px-2 py-1 bg-platinum dark:bg-eerie-black-2">
|
||||
<span className="text-xs font-medium text-just-black dark:text-chinese-white">
|
||||
{language}
|
||||
</span>
|
||||
<CopyButton
|
||||
textToCopy={String(children).replace(/\n$/, '')}
|
||||
/>
|
||||
</div>
|
||||
<SyntaxHighlighter
|
||||
{...rest}
|
||||
PreTag="div"
|
||||
language={language}
|
||||
style={isDarkTheme ? vscDarkPlus : oneLight}
|
||||
className="!mt-0"
|
||||
customStyle={{
|
||||
margin: 0,
|
||||
borderRadius: 0,
|
||||
scrollbarWidth: 'thin',
|
||||
}}
|
||||
>
|
||||
{String(children).replace(/\n$/, '')}
|
||||
</SyntaxHighlighter>
|
||||
</div>
|
||||
) : (
|
||||
<code className="whitespace-pre-line rounded-[6px] bg-gray-200 px-[8px] py-[4px] text-xs font-normal dark:bg-independence dark:text-bright-gray">
|
||||
{children}
|
||||
</code>
|
||||
);
|
||||
},
|
||||
ul({ children }) {
|
||||
return (
|
||||
<ul
|
||||
className={`list-inside list-disc whitespace-normal pl-4 ${classes.list}`}
|
||||
>
|
||||
{children}
|
||||
</ul>
|
||||
);
|
||||
},
|
||||
ol({ children }) {
|
||||
return (
|
||||
<ol
|
||||
className={`list-inside list-decimal whitespace-normal pl-4 ${classes.list}`}
|
||||
>
|
||||
{children}
|
||||
</ol>
|
||||
);
|
||||
},
|
||||
table({ children }) {
|
||||
return (
|
||||
<div className="relative overflow-x-auto rounded-lg border border-silver/40 dark:border-silver/40">
|
||||
<table className="w-full text-left text-gray-700 dark:text-bright-gray">
|
||||
{children}
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
thead({ children }) {
|
||||
return (
|
||||
<thead className="text-xs uppercase text-gray-900 dark:text-bright-gray bg-gray-50 dark:bg-[#26272E]/50">
|
||||
{children}
|
||||
</thead>
|
||||
);
|
||||
},
|
||||
tr({ children }) {
|
||||
return (
|
||||
<tr className="border-b border-gray-200 dark:border-silver/40 odd:bg-white dark:odd:bg-[#26272E] even:bg-gray-50 dark:even:bg-[#26272E]/50">
|
||||
{children}
|
||||
</tr>
|
||||
);
|
||||
},
|
||||
th({ children }) {
|
||||
return <th className="px-6 py-3">{children}</th>;
|
||||
},
|
||||
td({ children }) {
|
||||
return <td className="px-6 py-3">{children}</td>;
|
||||
},
|
||||
}}
|
||||
>
|
||||
{preprocessLaTeX(message)}
|
||||
</ReactMarkdown>
|
||||
return match ? (
|
||||
<div className="group relative overflow-hidden rounded-[14px] border border-light-silver dark:border-raisin-black">
|
||||
<div className="flex items-center justify-between bg-platinum px-2 py-1 dark:bg-eerie-black-2">
|
||||
<span className="text-xs font-medium text-just-black dark:text-chinese-white">
|
||||
{language}
|
||||
</span>
|
||||
<CopyButton
|
||||
textToCopy={String(children).replace(
|
||||
/\n$/,
|
||||
'',
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<SyntaxHighlighter
|
||||
{...rest}
|
||||
PreTag="div"
|
||||
language={language}
|
||||
style={
|
||||
isDarkTheme ? vscDarkPlus : oneLight
|
||||
}
|
||||
className="!mt-0"
|
||||
customStyle={{
|
||||
margin: 0,
|
||||
borderRadius: 0,
|
||||
scrollbarWidth: 'thin',
|
||||
}}
|
||||
>
|
||||
{String(children).replace(/\n$/, '')}
|
||||
</SyntaxHighlighter>
|
||||
</div>
|
||||
) : (
|
||||
<code className="whitespace-pre-line rounded-[6px] bg-gray-200 px-[8px] py-[4px] text-xs font-normal dark:bg-independence dark:text-bright-gray">
|
||||
{children}
|
||||
</code>
|
||||
);
|
||||
},
|
||||
ul({ children }) {
|
||||
return (
|
||||
<ul
|
||||
className={`list-inside list-disc whitespace-normal pl-4 ${classes.list}`}
|
||||
>
|
||||
{children}
|
||||
</ul>
|
||||
);
|
||||
},
|
||||
ol({ children }) {
|
||||
return (
|
||||
<ol
|
||||
className={`list-inside list-decimal whitespace-normal pl-4 ${classes.list}`}
|
||||
>
|
||||
{children}
|
||||
</ol>
|
||||
);
|
||||
},
|
||||
table({ children }) {
|
||||
return (
|
||||
<div className="relative overflow-x-auto rounded-lg border border-silver/40 dark:border-silver/40">
|
||||
<table className="w-full text-left text-gray-700 dark:text-bright-gray">
|
||||
{children}
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
thead({ children }) {
|
||||
return (
|
||||
<thead className="bg-gray-50 text-xs uppercase text-gray-900 dark:bg-[#26272E]/50 dark:text-bright-gray">
|
||||
{children}
|
||||
</thead>
|
||||
);
|
||||
},
|
||||
tr({ children }) {
|
||||
return (
|
||||
<tr className="border-b border-gray-200 odd:bg-white even:bg-gray-50 dark:border-silver/40 dark:odd:bg-[#26272E] dark:even:bg-[#26272E]/50">
|
||||
{children}
|
||||
</tr>
|
||||
);
|
||||
},
|
||||
th({ children }) {
|
||||
return (
|
||||
<th className="px-6 py-3">{children}</th>
|
||||
);
|
||||
},
|
||||
td({ children }) {
|
||||
return (
|
||||
<td className="px-6 py-3">{children}</td>
|
||||
);
|
||||
},
|
||||
}}
|
||||
>
|
||||
{segment.content}
|
||||
</ReactMarkdown>
|
||||
) : (
|
||||
<div
|
||||
className="my-4 w-full"
|
||||
style={{ minWidth: '100%' }}
|
||||
>
|
||||
<MermaidRenderer
|
||||
code={segment.content}
|
||||
isLoading={isStreaming}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</Fragment>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
})()}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{message && (
|
||||
<div className="my-2 ml-2 flex justify-start">
|
||||
<div
|
||||
className={`relative mr-2 block items-center justify-center lg:invisible
|
||||
${type !== 'ERROR' ? 'group-hover:lg:visible' : 'hidden'}`}
|
||||
className={`relative mr-2 block items-center justify-center lg:invisible ${type !== 'ERROR' ? 'group-hover:lg:visible' : 'hidden'}`}
|
||||
>
|
||||
<div>
|
||||
<CopyButton textToCopy={message} />
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className={`relative mr-2 block items-center justify-center lg:invisible
|
||||
${type !== 'ERROR' ? 'group-hover:lg:visible' : 'hidden'}`}
|
||||
className={`relative mr-2 block items-center justify-center lg:invisible ${type !== 'ERROR' ? 'group-hover:lg:visible' : 'hidden'}`}
|
||||
>
|
||||
<div>
|
||||
<SpeakButton text={message} />
|
||||
@@ -479,8 +556,7 @@ const ConversationBubble = forwardRef<
|
||||
feedback === 'LIKE' || isLikeClicked
|
||||
? 'visible'
|
||||
: 'lg:invisible'
|
||||
} ${type !== 'ERROR' ? 'group-hover:lg:visible' : ''}
|
||||
${feedback === 'DISLIKE' && type !== 'ERROR' ? 'hidden' : ''}`}
|
||||
} ${type !== 'ERROR' ? 'group-hover:lg:visible' : ''} ${feedback === 'DISLIKE' && type !== 'ERROR' ? 'hidden' : ''}`}
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
@@ -491,12 +567,11 @@ const ConversationBubble = forwardRef<
|
||||
}`}
|
||||
>
|
||||
<Like
|
||||
className={`cursor-pointer
|
||||
${
|
||||
isLikeClicked || feedback === 'LIKE'
|
||||
? 'fill-white-3000 stroke-purple-30 dark:fill-transparent'
|
||||
: 'fill-none stroke-gray-4000'
|
||||
}`}
|
||||
className={`cursor-pointer ${
|
||||
isLikeClicked || feedback === 'LIKE'
|
||||
? 'fill-white-3000 stroke-purple-30 dark:fill-transparent'
|
||||
: 'fill-none stroke-gray-4000'
|
||||
}`}
|
||||
onClick={() => {
|
||||
if (feedback === undefined || feedback === null) {
|
||||
handleFeedback?.('LIKE');
|
||||
@@ -520,8 +595,7 @@ const ConversationBubble = forwardRef<
|
||||
feedback === 'DISLIKE' || isLikeClicked
|
||||
? 'visible'
|
||||
: 'lg:invisible'
|
||||
} ${type !== 'ERROR' ? 'group-hover:lg:visible' : ''}
|
||||
${feedback === 'LIKE' && type !== 'ERROR' ? 'hidden' : ''}`}
|
||||
} ${type !== 'ERROR' ? 'group-hover:lg:visible' : ''} ${feedback === 'LIKE' && type !== 'ERROR' ? 'hidden' : ''}`}
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
@@ -535,7 +609,7 @@ const ConversationBubble = forwardRef<
|
||||
className={`cursor-pointer ${
|
||||
isDislikeClicked || feedback === 'DISLIKE'
|
||||
? 'fill-white-3000 stroke-red-2000 dark:fill-transparent'
|
||||
: 'fill-none stroke-gray-4000'
|
||||
: 'fill-none stroke-gray-4000'
|
||||
}`}
|
||||
onClick={() => {
|
||||
if (feedback === undefined || feedback === null) {
|
||||
@@ -583,7 +657,7 @@ function AllSources(sources: AllSourcesProps) {
|
||||
<div className="h-full w-full">
|
||||
<div className="w-full">
|
||||
<p className="text-left text-xl">{`${sources.sources.length} Sources`}</p>
|
||||
<div className="mx-1 mt-2 h-[0.8px] w-full rounded-full bg-[#C4C4C4]/40 lg:w-[95%] "></div>
|
||||
<div className="mx-1 mt-2 h-[0.8px] w-full rounded-full bg-[#C4C4C4]/40 lg:w-[95%]"></div>
|
||||
</div>
|
||||
<div className="mt-6 flex h-[90%] w-60 flex-col items-center gap-4 overflow-y-auto sm:w-80">
|
||||
{sources.sources.map((source, index) => (
|
||||
@@ -624,7 +698,7 @@ export default ConversationBubble;
|
||||
function ToolCalls({ toolCalls }: { toolCalls: ToolCallsType[] }) {
|
||||
const [isToolCallsOpen, setIsToolCallsOpen] = useState(false);
|
||||
return (
|
||||
<div className="mb-4 w-full flex flex-col flex-wrap items-start self-start lg:flex-nowrap">
|
||||
<div className="mb-4 flex w-full flex-col flex-wrap items-start self-start lg:flex-nowrap">
|
||||
<div className="my-2 flex flex-row items-center justify-center gap-3">
|
||||
<Avatar
|
||||
className="h-[26px] w-[30px] text-xl"
|
||||
@@ -655,12 +729,12 @@ function ToolCalls({ toolCalls }: { toolCalls: ToolCallsType[] }) {
|
||||
<Accordion
|
||||
key={`tool-call-${index}`}
|
||||
title={`${toolCall.tool_name} - ${toolCall.action_name.substring(0, toolCall.action_name.lastIndexOf('_'))}`}
|
||||
className="w-full rounded-[20px] bg-gray-1000 dark:bg-gun-metal hover:bg-[#F1F1F1] dark:hover:bg-[#2C2E3C]"
|
||||
className="w-full rounded-[20px] bg-gray-1000 hover:bg-[#F1F1F1] dark:bg-gun-metal dark:hover:bg-[#2C2E3C]"
|
||||
titleClassName="px-6 py-2 text-sm font-semibold"
|
||||
>
|
||||
<div className="flex flex-col gap-1">
|
||||
<div className="flex flex-col border border-silver dark:border-silver/20 rounded-2xl">
|
||||
<p className="flex flex-row items-center justify-between px-2 py-1 text-sm font-semibold bg-black/10 dark:bg-[#191919] rounded-t-2xl break-words">
|
||||
<div className="flex flex-col rounded-2xl border border-silver dark:border-silver/20">
|
||||
<p className="flex flex-row items-center justify-between break-words rounded-t-2xl bg-black/10 px-2 py-1 text-sm font-semibold dark:bg-[#191919]">
|
||||
<span style={{ fontFamily: 'IBMPlexMono-Medium' }}>
|
||||
Arguments
|
||||
</span>{' '}
|
||||
@@ -668,17 +742,17 @@ function ToolCalls({ toolCalls }: { toolCalls: ToolCallsType[] }) {
|
||||
textToCopy={JSON.stringify(toolCall.arguments, null, 2)}
|
||||
/>
|
||||
</p>
|
||||
<p className="p-2 font-mono text-sm dark:tex dark:bg-[#222327] rounded-b-2xl break-words">
|
||||
<p className="dark:tex break-words rounded-b-2xl p-2 font-mono text-sm dark:bg-[#222327]">
|
||||
<span
|
||||
className="text-black dark:text-gray-400 leading-[23px]"
|
||||
className="leading-[23px] text-black dark:text-gray-400"
|
||||
style={{ fontFamily: 'IBMPlexMono-Medium' }}
|
||||
>
|
||||
{JSON.stringify(toolCall.arguments, null, 2)}
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex flex-col border border-silver dark:border-silver/20 rounded-2xl">
|
||||
<p className="flex flex-row items-center justify-between px-2 py-1 text-sm font-semibold bg-black/10 dark:bg-[#191919] rounded-t-2xl break-words">
|
||||
<div className="flex flex-col rounded-2xl border border-silver dark:border-silver/20">
|
||||
<p className="flex flex-row items-center justify-between break-words rounded-t-2xl bg-black/10 px-2 py-1 text-sm font-semibold dark:bg-[#191919]">
|
||||
<span style={{ fontFamily: 'IBMPlexMono-Medium' }}>
|
||||
Response
|
||||
</span>{' '}
|
||||
@@ -686,9 +760,9 @@ function ToolCalls({ toolCalls }: { toolCalls: ToolCallsType[] }) {
|
||||
textToCopy={JSON.stringify(toolCall.result, null, 2)}
|
||||
/>
|
||||
</p>
|
||||
<p className="p-2 font-mono text-sm dark:tex dark:bg-[#222327] rounded-b-2xl break-words">
|
||||
<p className="dark:tex break-words rounded-b-2xl p-2 font-mono text-sm dark:bg-[#222327]">
|
||||
<span
|
||||
className="text-black dark:text-gray-400 leading-[23px]"
|
||||
className="leading-[23px] text-black dark:text-gray-400"
|
||||
style={{ fontFamily: 'IBMPlexMono-Medium' }}
|
||||
>
|
||||
{JSON.stringify(toolCall.result, null, 2)}
|
||||
@@ -716,7 +790,7 @@ function Thought({
|
||||
const [isThoughtOpen, setIsThoughtOpen] = useState(true);
|
||||
|
||||
return (
|
||||
<div className="mb-4 w-full flex flex-col flex-wrap items-start self-start lg:flex-nowrap">
|
||||
<div className="mb-4 flex w-full flex-col flex-wrap items-start self-start lg:flex-nowrap">
|
||||
<div className="my-2 flex flex-row items-center justify-center gap-3">
|
||||
<Avatar
|
||||
className="h-[26px] w-[30px] text-xl"
|
||||
@@ -742,7 +816,7 @@ function Thought({
|
||||
</div>
|
||||
{isThoughtOpen && (
|
||||
<div className="fade-in ml-2 mr-5 max-w-[90vw] md:max-w-[70vw] lg:max-w-[50vw]">
|
||||
<div className="rounded-[28px] bg-gray-1000 py-[18px] px-7 dark:bg-gun-metal">
|
||||
<div className="rounded-[28px] bg-gray-1000 px-7 py-[18px] dark:bg-gun-metal">
|
||||
<ReactMarkdown
|
||||
className="fade-in whitespace-pre-wrap break-words leading-normal"
|
||||
remarkPlugins={[remarkGfm, remarkMath]}
|
||||
@@ -754,8 +828,8 @@ function Thought({
|
||||
const language = match ? match[1] : '';
|
||||
|
||||
return match ? (
|
||||
<div className="group relative rounded-[14px] overflow-hidden border border-light-silver dark:border-raisin-black">
|
||||
<div className="flex justify-between items-center px-2 py-1 bg-platinum dark:bg-eerie-black-2">
|
||||
<div className="group relative overflow-hidden rounded-[14px] border border-light-silver dark:border-raisin-black">
|
||||
<div className="flex items-center justify-between bg-platinum px-2 py-1 dark:bg-eerie-black-2">
|
||||
<span className="text-xs font-medium text-just-black dark:text-chinese-white">
|
||||
{language}
|
||||
</span>
|
||||
@@ -809,14 +883,14 @@ function Thought({
|
||||
},
|
||||
thead({ children }) {
|
||||
return (
|
||||
<thead className="text-xs uppercase text-gray-900 dark:text-bright-gray bg-gray-50 dark:bg-[#26272E]/50">
|
||||
<thead className="bg-gray-50 text-xs uppercase text-gray-900 dark:bg-[#26272E]/50 dark:text-bright-gray">
|
||||
{children}
|
||||
</thead>
|
||||
);
|
||||
},
|
||||
tr({ children }) {
|
||||
return (
|
||||
<tr className="border-b border-gray-200 dark:border-silver/40 odd:bg-white dark:odd:bg-[#26272E] even:bg-gray-50 dark:even:bg-[#26272E]/50">
|
||||
<tr className="border-b border-gray-200 odd:bg-white even:bg-gray-50 dark:border-silver/40 dark:odd:bg-[#26272E] dark:even:bg-[#26272E]/50">
|
||||
{children}
|
||||
</tr>
|
||||
);
|
||||
|
||||
@@ -64,14 +64,19 @@ export default function ConversationMessages({
|
||||
const scrollConversationToBottom = useCallback(() => {
|
||||
if (!conversationRef.current || userInterruptedScroll) return;
|
||||
|
||||
if (status === 'idle' || !queries[queries.length - 1]?.response) {
|
||||
conversationRef.current.scrollTo({
|
||||
behavior: 'smooth',
|
||||
top: conversationRef.current.scrollHeight,
|
||||
});
|
||||
} else {
|
||||
conversationRef.current.scrollTop = conversationRef.current.scrollHeight;
|
||||
}
|
||||
requestAnimationFrame(() => {
|
||||
if (!conversationRef?.current) return;
|
||||
|
||||
if (status === 'idle' || !queries[queries.length - 1]?.response) {
|
||||
conversationRef.current.scrollTo({
|
||||
behavior: 'smooth',
|
||||
top: conversationRef.current.scrollHeight,
|
||||
});
|
||||
} else {
|
||||
conversationRef.current.scrollTop =
|
||||
conversationRef.current.scrollHeight;
|
||||
}
|
||||
});
|
||||
}, [userInterruptedScroll, status, queries]);
|
||||
|
||||
const checkScrollPosition = useCallback(() => {
|
||||
@@ -127,6 +132,8 @@ export default function ConversationMessages({
|
||||
: DEFAULT_BUBBLE_MARGIN;
|
||||
|
||||
if (query.thought || query.response) {
|
||||
const isCurrentlyStreaming =
|
||||
status === 'loading' && index === queries.length - 1;
|
||||
return (
|
||||
<ConversationBubble
|
||||
className={bubbleMargin}
|
||||
@@ -137,6 +144,7 @@ export default function ConversationMessages({
|
||||
sources={query.sources}
|
||||
toolCalls={query.tool_calls}
|
||||
feedback={query.feedback}
|
||||
isStreaming={isCurrentlyStreaming}
|
||||
handleFeedback={
|
||||
handleFeedback
|
||||
? (feedback) => handleFeedback(query, feedback, index)
|
||||
@@ -195,7 +203,7 @@ export default function ConversationMessages({
|
||||
>
|
||||
<img
|
||||
src={ArrowDown}
|
||||
alt=""
|
||||
alt="arrow down"
|
||||
className="h-4 w-4 opacity-50 filter dark:invert md:h-5 md:w-5"
|
||||
/>
|
||||
</button>
|
||||
|
||||
@@ -192,7 +192,7 @@ export default function ConversationTile({
|
||||
conversationId !== conversation.id &&
|
||||
selectConversation(conversation.id);
|
||||
}}
|
||||
className={`my-auto mx-4 mt-4 flex h-9 cursor-pointer items-center justify-between pl-4 gap-4 rounded-3xl hover:bg-bright-gray dark:hover:bg-dark-charcoal ${
|
||||
className={`mx-4 my-auto mt-4 flex h-9 cursor-pointer items-center justify-between gap-4 rounded-3xl pl-4 hover:bg-bright-gray dark:hover:bg-dark-charcoal ${
|
||||
conversationId === conversation.id || isOpen || isHovered || isEdit
|
||||
? 'bg-bright-gray dark:bg-dark-charcoal'
|
||||
: ''
|
||||
|
||||
@@ -132,8 +132,8 @@ export const SharedConversation = () => {
|
||||
content="Shared conversations with DocsGPT"
|
||||
/>
|
||||
</Helmet>
|
||||
<div className="flex h-full flex-col items-center justify-between gap-2 overflow-y-hidden dark:bg-raisin-black ">
|
||||
<div className="border-b p-2 dark:border-b-silver w-full md:w-9/12 lg:w-8/12 xl:w-8/12 2xl:w-6/12 max-w-[1200px]">
|
||||
<div className="flex h-full flex-col items-center justify-between gap-2 overflow-y-hidden dark:bg-raisin-black">
|
||||
<div className="w-full max-w-[1200px] border-b p-2 dark:border-b-silver md:w-9/12 lg:w-8/12 xl:w-8/12 2xl:w-6/12">
|
||||
<h1 className="font-semi-bold text-4xl text-chinese-black dark:text-chinese-silver">
|
||||
{title}
|
||||
</h1>
|
||||
@@ -153,7 +153,7 @@ export const SharedConversation = () => {
|
||||
queries={queries}
|
||||
status={status}
|
||||
/>
|
||||
<div className="flex flex-col items-center gap-4 pb-2 w-full md:w-9/12 lg:w-8/12 xl:w-8/12 2xl:w-6/12 max-w-[1200px]">
|
||||
<div className="flex w-full max-w-[1200px] flex-col items-center gap-4 pb-2 md:w-9/12 lg:w-8/12 xl:w-8/12 2xl:w-6/12">
|
||||
{apiKey ? (
|
||||
<MessageInput
|
||||
value={input}
|
||||
@@ -164,13 +164,13 @@ export const SharedConversation = () => {
|
||||
) : (
|
||||
<button
|
||||
onClick={() => navigate('/')}
|
||||
className="w-fit rounded-full bg-purple-30 py-3 px-5 text-white shadow-xl transition-colors duration-200 hover:bg-violets-are-blue mb-14 sm:mb-0"
|
||||
className="mb-14 w-fit rounded-full bg-purple-30 px-5 py-3 text-white shadow-xl transition-colors duration-200 hover:bg-violets-are-blue sm:mb-0"
|
||||
>
|
||||
{t('sharedConv.button')}
|
||||
</button>
|
||||
)}
|
||||
|
||||
<p className="text-gray-4000 hidden w-[100vw] self-center bg-transparent py-2 text-center text-xs dark:text-sonic-silver md:inline md:w-full">
|
||||
<p className="hidden w-[100vw] self-center bg-transparent py-2 text-center text-xs text-gray-4000 dark:text-sonic-silver md:inline md:w-full">
|
||||
{t('sharedConv.meta')}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -15,7 +15,7 @@ export function handleFetchAnswer(
|
||||
token_limit: number,
|
||||
agentId?: string,
|
||||
attachments?: string[],
|
||||
save_conversation: boolean = true,
|
||||
save_conversation = true,
|
||||
): Promise<
|
||||
| {
|
||||
result: any;
|
||||
@@ -103,7 +103,7 @@ export function handleFetchAnswerSteaming(
|
||||
indx?: number,
|
||||
agentId?: string,
|
||||
attachments?: string[],
|
||||
save_conversation: boolean = true,
|
||||
save_conversation = true,
|
||||
): Promise<Answer> {
|
||||
history = history.map((item) => {
|
||||
return {
|
||||
|
||||
@@ -9,7 +9,6 @@ export interface Message {
|
||||
type: MESSAGE_TYPE;
|
||||
}
|
||||
|
||||
|
||||
export interface Attachment {
|
||||
id?: string;
|
||||
fileName: string;
|
||||
|
||||
Reference in New Issue
Block a user