Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 16 additions & 3 deletions echo/frontend/src/components/chat/ChatContextProgress.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { t } from "@lingui/core/macro";
import { useProjectChatContext } from "@/lib/query";
import { capitalize } from "@/lib/utils";
import { Box, Progress, Skeleton, Tooltip } from "@mantine/core";
import { AUTO_SELECT_ENABLED } from "@/config";

export const ChatContextProgress = ({ chatId }: { chatId: string }) => {
const chatContextQuery = useProjectChatContext(chatId);
Expand All @@ -17,6 +18,10 @@ export const ChatContextProgress = ({ chatId }: { chatId: string }) => {
);
}

if (AUTO_SELECT_ENABLED && chatContextQuery.data?.auto_select_bool && chatContextQuery.data?.conversations.length === 0) {
return null;
}

const conversationsAlreadyAdded = chatContextQuery.data?.conversations
.filter((c) => c.locked)
.sort((a, b) => b.token_usage - a.token_usage);
Expand All @@ -25,6 +30,14 @@ export const ChatContextProgress = ({ chatId }: { chatId: string }) => {
.filter((c) => !c.locked)
.sort((a, b) => b.token_usage - a.token_usage);

const getColor = (baseColor: string) => {
if(AUTO_SELECT_ENABLED && chatContextQuery.data?.auto_select_bool){
return "green.6";
}

return baseColor;
};

return (
<Box>
<Progress.Root size={8}>
Expand All @@ -37,7 +50,7 @@ export const ChatContextProgress = ({ chatId }: { chatId: string }) => {
>
<Progress.Section
value={m.token_usage * 100}
color="blue.6"
color={getColor("blue.6")}
mr="1px"
/>
</Tooltip>
Expand All @@ -52,7 +65,7 @@ export const ChatContextProgress = ({ chatId }: { chatId: string }) => {
>
<Progress.Section
value={m.token_usage * 100}
color="blue.3"
color={getColor("blue.3")}
mr="1px"
/>
</Tooltip>
Expand All @@ -69,4 +82,4 @@ export const ChatContextProgress = ({ chatId }: { chatId: string }) => {
</Progress.Root>
</Box>
);
};
};
13 changes: 12 additions & 1 deletion echo/frontend/src/components/chat/ChatHistoryMessage.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { Trans } from "@lingui/react/macro";
import { ChatMessage } from "@/components/chat/ChatMessage";
import { Group, Text } from "@mantine/core";
import { Box, Group, Text } from "@mantine/core";
import { Markdown } from "@/components/common/Markdown";
import React from "react";
import { formatDate } from "date-fns";
import { cn } from "@/lib/utils";
import { CopyRichTextIconButton } from "@/components/common/CopyRichTextIconButton";
import { ConversationLinks } from "@/components/conversation/ConversationLinks";
import SourcesSearched from "./SourcesSearched";

export const ChatHistoryMessage = ({
message,
Expand Down Expand Up @@ -43,6 +44,16 @@ export const ChatHistoryMessage = ({
);
}

if (message.role === "dembrane") {
if (message.content === "searched") {
return (
<Box className="flex justify-start">
<SourcesSearched />
</Box>
);
}
}

if (message._original.added_conversations?.length > 0) {
return (
<ChatMessage key={message.id} role="dembrane" section={section}>
Expand Down
49 changes: 49 additions & 0 deletions echo/frontend/src/components/chat/Citations.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { Trans } from "@lingui/react/macro";
import { Box, Group, Text } from "@mantine/core";
import { IconCheck } from "@tabler/icons-react";

type CitationsProps = {
sources: string[];
};

const Citations = ({ sources }: CitationsProps) => {
const maxToShow = 3;
const visibleSources = sources.slice(0, maxToShow);
const remainingCount = sources.length - visibleSources.length;

return (
<>
<Box className="rounded-bl-0 w-fit rounded-br-[0.75rem] rounded-tl-[0.75rem] rounded-tr-[0.75rem] border border-green-500 px-4 py-3">
<Group>
<Box className="rounded-full bg-green-500 p-1">
<IconCheck size={16} color="white" />
</Box>
<Text size="sm">
<Trans>Searched through the most relevant sources</Trans>
</Text>
</Group>
</Box>

<Box className="mt-2">
<Text size="sm" fw={500}>
<Trans>Citing the following sources</Trans>
</Text>

<Group gap="xs" mt="sm">
{visibleSources.map((source, idx) => (
<Box key={idx} className="mr-2 rounded bg-gray-100 p-2">
<Text size="xs">{source}</Text>
</Box>
))}
{remainingCount > 0 && (
<Box className="rounded bg-gray-100 p-2">
<Text size="xs">+{remainingCount} more</Text>
</Box>
)}
</Group>
</Box>
</>
);
};

export default Citations;
20 changes: 20 additions & 0 deletions echo/frontend/src/components/chat/SourcesSearch.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Trans } from "@lingui/react/macro";
import { Box, Progress, Text } from "@mantine/core";


type SourcesSearchProps = {
progressValue: number;
};

const SourcesSearch = ({ progressValue }: SourcesSearchProps) => {
return (
<Box className="rounded-bl-0 w-fit rounded-br-[0.75rem] rounded-tl-[0.75rem] rounded-tr-[0.75rem] border border-green-500 px-4 py-3">
<Text size="sm" className="mb-2 text-center">
<Trans>Searching through the most relevant sources</Trans>
</Text>
<Progress value={progressValue} color="green" size="sm" />
</Box>
);
};

export default SourcesSearch;
20 changes: 20 additions & 0 deletions echo/frontend/src/components/chat/SourcesSearched.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Trans } from "@lingui/react/macro";
import { Box, Group, Text } from "@mantine/core";
import { IconCheck } from "@tabler/icons-react";

const SourcesSearched = () => {
return (
<Box className="rounded-bl-0 w-fit rounded-br-[0.75rem] rounded-tl-[0.75rem] rounded-tr-[0.75rem] border border-green-500 px-4 py-3">
<Group>
<Box className="rounded-full bg-green-500 p-1">
<IconCheck size={16} color="white" />
</Box>
<Text size="sm">
<Trans>Searched through the most relevant sources</Trans>
</Text>
</Group>
</Box>
);
};

export default SourcesSearched;
4 changes: 3 additions & 1 deletion echo/frontend/src/components/common/NavigationButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { LoadingSpinner } from "./LoadingSpinner";

type Props = {
to?: string;
borderColor?: string;
rightIcon?: React.ReactNode;
rightSection?: React.ReactNode;
active?: boolean;
Expand All @@ -28,6 +29,7 @@ type Props = {
export const NavigationButton = ({
children,
to,
borderColor,
rightSection,
rightIcon,
active,
Expand All @@ -54,7 +56,7 @@ export const NavigationButton = ({
active ? "border-primary-500" : "",
disabled || loading
? "opacity-60 hover:border-gray-300"
: "hover:border-primary-500",
: borderColor ? `hover:${borderColor}` : "hover:border-primary-500",
props.className,
)}
>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { useAddChatContextMutation, useDeleteChatContextMutation, useProjectChatContext } from "@/lib/query";
import { Trans } from "@lingui/react/macro";
import { Box, Checkbox, Group, Stack, Text } from "@mantine/core";
import { useParams } from "react-router-dom";

export const AutoSelectConversations = () => {
const { chatId } = useParams();
const projectChatContextQuery = useProjectChatContext(chatId ?? "");
const addChatContextMutation = useAddChatContextMutation();
const deleteChatContextMutation = useDeleteChatContextMutation();
// Get the auto_select_bool value from the chat context
const autoSelect = projectChatContextQuery.data?.auto_select_bool ?? false;
const handleCheckboxChange = (checked: boolean) => {
if (checked) {
addChatContextMutation.mutate({
chatId: chatId ?? "",
auto_select_bool: true
});
} else {
deleteChatContextMutation.mutate({
chatId: chatId ?? "",
auto_select_bool: false
});
}
};
return (
<Box
className="cursor-pointer border border-gray-200 hover:bg-gray-50"
>
<Group justify="space-between" p="md" wrap="nowrap">
<Stack gap="xs">
<Text className="font-medium">
<Trans>Auto-select</Trans>
</Text>
<Text size="xs" c="gray.6">
<Trans>Auto-select sources to add to the chat</Trans>
</Text>
</Stack>
<Checkbox
size="md"
checked={autoSelect}
color="green"
onClick={(e) => e.stopPropagation()}
onChange={(e) => handleCheckboxChange(e.currentTarget.checked)}
/>
</Group>
</Box>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ import { useDisclosure } from "@mantine/hooks";
import { useIntersection } from "@mantine/hooks";
import { useForm, Controller } from "react-hook-form";
import { FormLabel } from "@/components/form/FormLabel";
import { AutoSelectConversations } from "./AutoSelectConversations";
import { AUTO_SELECT_ENABLED } from "@/config";

type SortOption = {
label: string;
Expand Down Expand Up @@ -108,6 +110,8 @@ const ConversationAccordionLabelChatSelection = ({
(c) => c.conversation_id === conversation.id && c.locked,
);

const isAutoSelectEnabled = projectChatContextQuery.data?.auto_select_bool ?? false;

const handleSelectChat = () => {
if (!isSelected) {
addChatContextMutation.mutate({
Expand Down Expand Up @@ -135,6 +139,7 @@ const ConversationAccordionLabelChatSelection = ({
checked={isSelected}
disabled={isLocked}
onChange={handleSelectChat}
color={AUTO_SELECT_ENABLED && isAutoSelectEnabled ? "green" : undefined}
/>
</Tooltip>
);
Expand Down Expand Up @@ -335,10 +340,13 @@ const ConversationAccordionItem = ({
(c) => c.conversation_id === conversation.id && c.locked,
);

const isAutoSelectEnabled = chatContextQuery.data?.auto_select_bool ?? false;

return (
<NavigationButton
to={`/projects/${conversation.project_id}/conversation/${conversation.id}/overview`}
active={highlight}
borderColor={AUTO_SELECT_ENABLED && isAutoSelectEnabled ? "border-green-500" : undefined}
className={cn("w-full", {
"!bg-primary-50": isLocked,
})}
Expand Down Expand Up @@ -437,6 +445,8 @@ export const ConversationAccordion = ({ projectId }: { projectId: string }) => {
{ label: t`Shortest First`, value: "duration" },
];

const location = useLocation();
const inChatMode = location.pathname.includes("/chats/");
// Temporarily disabled source filters
// const FILTER_OPTIONS = [
// { label: t`Conversations from QR Code`, value: "PORTAL_AUDIO" },
Expand Down Expand Up @@ -617,6 +627,13 @@ export const ConversationAccordion = ({ projectId }: { projectId: string }) => {

<Accordion.Panel>
<Stack ref={parent2} className="relative">
{inChatMode && AUTO_SELECT_ENABLED && conversationsQuery.data?.length !== 0 && (
<Stack gap="xs" className="relative">
<LoadingOverlay visible={conversationsQuery.isLoading} />
<AutoSelectConversations />
</Stack>
)}

{!(
conversationsQuery.data &&
conversationsQuery.data.length === 0 &&
Expand Down Expand Up @@ -751,4 +768,4 @@ export const ConversationAccordion = ({ projectId }: { projectId: string }) => {
</Accordion.Panel>
</Accordion.Item>
);
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import { I18nLink } from "@/components/common/i18nLink";

export const ConversationLinks = ({
conversations,
color,
}: {
conversations: Conversation[];
color?: string;
}) => {
const { projectId } = useParams();

Expand All @@ -16,7 +18,7 @@ export const ConversationLinks = ({
key={conversation.id}
to={`/projects/${projectId}/conversation/${conversation.id}/overview`}
>
<Anchor size="xs">{conversation.participant_name}</Anchor>
<Anchor size="xs" c={color}>{conversation.participant_name}</Anchor>
</I18nLink>
)) ?? null}
</Group>
Expand Down
1 change: 0 additions & 1 deletion echo/frontend/src/components/project/ProjectSidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ export const ProjectSidebar = () => {
const { projectId, conversationId } = useParams();

const projectQuery = useProjectById({ projectId: projectId ?? "" });

const { pathname } = useLocation();

// const { isCollapsed, toggleSidebar } = useSidebarCollapsed();
Expand Down
2 changes: 2 additions & 0 deletions echo/frontend/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,5 @@ export const SUPPORTED_LANGUAGES = [

export const PRIVACY_POLICY_URL =
"https://dembrane.notion.site/Privacy-statements-all-languages-fa97a183f9d841f7a1089079e77ffb52" as const;

export const AUTO_SELECT_ENABLED = import.meta.env.VITE_AUTO_SELECT_ENABLED === "1";
4 changes: 4 additions & 0 deletions echo/frontend/src/lib/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -718,23 +718,27 @@ export const getProjectChatContext = async (chatId: string) => {
export const addChatContext = async (
chatId: string,
conversationId?: string,
auto_select_bool?: boolean,
) => {
return api.post<unknown, TProjectChatContext>(
`/chats/${chatId}/add-context`,
{
conversation_id: conversationId,
auto_select_bool: auto_select_bool,
},
);
};

export const deleteChatContext = async (
chatId: string,
conversationId?: string,
auto_select_bool?: boolean,
) => {
return api.post<unknown, TProjectChatContext>(
`/chats/${chatId}/delete-context`,
{
conversation_id: conversationId,
auto_select_bool: auto_select_bool,
},
);
};
Expand Down
Loading