This commit is contained in:
ManishMadan2882
2025-05-08 00:15:28 +05:30
parent d0a04d9801
commit ff532210f7
38 changed files with 550 additions and 495 deletions

View File

@@ -5,7 +5,10 @@ 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,7 +29,10 @@ 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';
@@ -106,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>
@@ -128,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>
@@ -137,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')}
@@ -152,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')}
@@ -192,7 +198,10 @@ const ConversationBubble = forwardRef<
const processMarkdownContent = (content: string) => {
const processedContent = preprocessLaTeX(content);
const contentSegments: Array<{type: 'text' | 'mermaid', content: string}> = [];
const contentSegments: Array<{
type: 'text' | 'mermaid';
content: string;
}> = [];
let lastIndex = 0;
const regex = /```mermaid\n([\s\S]*?)```/g;
@@ -219,7 +228,7 @@ const ConversationBubble = forwardRef<
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' ||
@@ -378,9 +387,9 @@ 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 ml-2 mr-5 flex max-w-[90vw] rounded-[28px] bg-gray-1000 px-7 py-[18px] dark:bg-gun-metal md:max-w-[70vw] lg:max-w-[50vw] ${
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'
}`}
>
@@ -397,25 +406,38 @@ const ConversationBubble = forwardRef<
rehypePlugins={[rehypeKatex]}
components={{
code(props) {
const { children, className, node, ref, ...rest } = props;
const match = /language-(\w+)/.exec(className || '');
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">
<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$/, '')}
textToCopy={String(children).replace(
/\n$/,
'',
)}
/>
</div>
<SyntaxHighlighter
{...rest}
PreTag="div"
language={language}
style={isDarkTheme ? vscDarkPlus : oneLight}
style={
isDarkTheme ? vscDarkPlus : oneLight
}
className="!mt-0"
customStyle={{
margin: 0,
@@ -461,30 +483,37 @@ const ConversationBubble = forwardRef<
},
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>
);
},
th({ children }) {
return <th className="px-6 py-3">{children}</th>;
return (
<th className="px-6 py-3">{children}</th>
);
},
td({ children }) {
return <td className="px-6 py-3">{children}</td>;
return (
<td className="px-6 py-3">{children}</td>
);
},
}}
>
{segment.content}
</ReactMarkdown>
) : (
<div className="my-4 w-full" style={{ minWidth: '100%' }}>
<div
className="my-4 w-full"
style={{ minWidth: '100%' }}
>
<MermaidRenderer
code={segment.content}
isLoading={isStreaming}
@@ -502,16 +531,14 @@ const ConversationBubble = forwardRef<
{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} />
@@ -529,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
@@ -541,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');
@@ -570,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
@@ -585,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) {
@@ -633,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) => (
@@ -674,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"
@@ -705,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>{' '}
@@ -718,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>{' '}
@@ -736,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)}
@@ -766,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"
@@ -792,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]}
@@ -804,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>
@@ -859,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>
);