Skip to content

Commit

Permalink
[front] Add analytics tab (#9823)
Browse files Browse the repository at this point in the history
* Add analytics tab

* lint

* remove label

* remove log

* block analytics for non-builder/admin

* disable feedbacks for global

* Update front/pages/api/w/[wId]/assistant/agent_configurations/[aId]/analytics.ts

Co-authored-by: Lucas Massemin <[email protected]>

* Update front/pages/api/w/[wId]/assistant/agent_configurations/[aId]/analytics.ts

Co-authored-by: Lucas Massemin <[email protected]>

* review

---------

Co-authored-by: Lucas Massemin <[email protected]>
  • Loading branch information
tdraier and overmode authored Jan 8, 2025
1 parent cc5a77d commit 10d7b94
Show file tree
Hide file tree
Showing 5 changed files with 532 additions and 40 deletions.
279 changes: 251 additions & 28 deletions front/components/assistant/AssistantDetails.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,36 @@
import {
Avatar,
BarChartIcon,
Button,
Card,
CardGrid,
ChatBubbleLeftRightIcon,
ChatBubbleThoughtIcon,
ContentMessage,
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
HandThumbDownIcon,
HandThumbUpIcon,
InformationCircleIcon,
Page,
Sheet,
SheetContainer,
SheetContent,
SheetHeader,
SheetTitle,
Tabs,
TabsList,
TabsTrigger,
Tooltip,
} from "@dust-tt/sparkle";
import type { AgentConfigurationScope, WorkspaceType } from "@dust-tt/types";
import type {
AgentConfigurationScope,
AgentConfigurationType,
WorkspaceType,
} from "@dust-tt/types";
import { removeNulls } from "@dust-tt/types";
import { useCallback, useState } from "react";

import { AssistantDetailsButtonBar } from "@app/components/assistant/AssistantDetailsButtonBar";
Expand All @@ -18,24 +39,222 @@ import { AssistantUsageSection } from "@app/components/assistant/details/Assista
import { ReadOnlyTextArea } from "@app/components/assistant/ReadOnlyTextArea";
import { SharingDropdown } from "@app/components/assistant_builder/Sharing";
import {
useAgentAnalytics,
useAgentConfiguration,
useUpdateAgentScope,
} from "@app/lib/swr/assistants";
import { classNames } from "@app/lib/utils";

const PERIODS = [
{ value: 7, label: "Last 7 days" },
{ value: 15, label: "Last 15 days" },
{ value: 30, label: "Last 30 days" },
];

type AssistantDetailsProps = {
owner: WorkspaceType;
onClose: () => void;
assistantId: string | null;
showPerformanceTab?: boolean;
};

function AssistantDetailsInfo({
agentConfiguration,
owner,
}: {
agentConfiguration: AgentConfigurationType;
owner: WorkspaceType;
}) {
return (
<>
<div className="text-sm text-foreground">
{agentConfiguration?.description}
</div>
{agentConfiguration && (
<AssistantUsageSection
agentConfiguration={agentConfiguration}
owner={owner}
/>
)}
<Page.Separator />

<AssistantActionsSection
agentConfiguration={agentConfiguration}
owner={owner}
/>

{agentConfiguration?.instructions ? (
<div className="flex flex-col gap-2">
<div className="text-lg font-bold text-element-800">Instructions</div>
<ReadOnlyTextArea content={agentConfiguration.instructions} />
</div>
) : (
"This assistant has no instructions."
)}
</>
);
}

function AssistantDetailsPerformance({
agentConfiguration,
owner,
}: {
agentConfiguration: AgentConfigurationType;
owner: WorkspaceType;
}) {
const [period, setPeriod] = useState(30);
const { agentAnalytics } = useAgentAnalytics({
workspaceId: owner.sId,
agentConfigurationId: agentConfiguration.sId,
period,
});

return (
<>
<div className="flex flex-row justify-between gap-3">
<Page.H variant="h5">Analytics</Page.H>
<div className="self-end">
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
label={PERIODS.find((p) => p.value === period)?.label}
variant="outline"
isSelect
/>
</DropdownMenuTrigger>
<DropdownMenuContent>
{PERIODS.map((p) => (
<DropdownMenuItem
key={p.value}
label={p.label}
onClick={() => {
setPeriod(p.value);
}}
/>
))}
</DropdownMenuContent>
</DropdownMenu>
</div>
</div>

<div></div>
<CardGrid>
<Card variant="primary" size="md">
<div className="flex h-24 w-full flex-col gap-1 text-sm">
<div className="flex w-full gap-1 font-medium text-foreground">
<div className="w-full">Active Users</div>
</div>
<div className="flex flex-col gap-1 text-lg font-bold">
{agentAnalytics?.users ? (
<>
<div className="truncate text-element-900">
{agentAnalytics.users.length}
</div>

<Avatar.Stack size="md" hasMagnifier={false}>
{removeNulls(agentAnalytics.users.map((top) => top.user))
.slice(0, 5)
.map((user) => (
<Tooltip
key={user.id}
trigger={
<Avatar
size="sm"
name={user.fullName}
visual={user.image}
/>
}
label={user.fullName}
/>
))}
</Avatar.Stack>
</>
) : (
"-"
)}
</div>
</div>
</Card>

<Card variant="primary" size="md">
<div className="flex h-24 w-full flex-col gap-1 text-sm">
<div className="flex w-full gap-1 font-medium text-foreground">
<div className="w-full">Reactions</div>
</div>
<div className="flex flex-row gap-2 text-lg font-bold">
{agentConfiguration.scope !== "global" &&
agentAnalytics?.feedbacks ? (
<>
<div className="flex flex-row items-center">
<div>
<HandThumbUpIcon className="h-6 w-6 pr-2 text-element-600" />
</div>
<div>{agentAnalytics.feedbacks.positiveFeedbacks}</div>
</div>
<div className="flex flex-row items-center">
<div>
<HandThumbDownIcon className="h-6 w-6 pr-2 text-element-600" />
</div>
<div>{agentAnalytics.feedbacks.negativeFeedbacks}</div>
</div>
</>
) : (
"-"
)}
</div>
</div>
</Card>
<Card variant="primary" size="md">
<div className="flex h-24 w-full flex-col gap-1 text-sm">
<div className="flex w-full gap-1 font-medium text-foreground">
<div className="w-full">Conversations</div>
</div>
<div className="flex flex-row gap-2 text-lg font-bold">
<div className="flex flex-row items-center">
<div>
<ChatBubbleLeftRightIcon className="h-6 w-6 pr-2 text-element-600" />
</div>
<div>
{agentAnalytics?.mentions
? `${agentAnalytics.mentions.conversationCount}`
: "-"}
</div>
</div>
</div>
</div>
</Card>
<Card variant="primary" size="md">
<div className="flex h-24 w-full flex-col gap-1 text-sm">
<div className="flex w-full gap-1 font-medium text-foreground">
<div className="w-full">Messages</div>
</div>
<div className="flex flex-row gap-2 text-lg font-bold">
<div className="flex flex-row items-center">
<div>
<ChatBubbleThoughtIcon className="h-6 w-6 pr-2 text-element-600" />
</div>
<div>
{agentAnalytics?.mentions
? `${agentAnalytics.mentions.messageCount}`
: "-"}
</div>
</div>
</div>
</div>
</Card>
</CardGrid>
</>
);
}

export function AssistantDetails({
assistantId,
onClose,
owner,
showPerformanceTab = false,
}: AssistantDetailsProps) {
const [isUpdatingScope, setIsUpdatingScope] = useState(false);

const [selectedTab, setSelectedTab] = useState("info");
const { agentConfiguration, isAgentConfigurationValidating } =
useAgentConfiguration({
workspaceId: owner.sId,
Expand Down Expand Up @@ -103,30 +322,9 @@ export function AssistantDetails({
It is no longer active and cannot be used.
</ContentMessage>
)}

<div className="text-sm text-foreground">
{agentConfiguration?.description}
</div>
{agentConfiguration && (
<AssistantUsageSection
agentConfiguration={agentConfiguration}
owner={owner}
/>
)}
<Page.Separator />
</div>
);

const InstructionsSection = () =>
agentConfiguration?.instructions ? (
<div className="flex flex-col gap-2">
<div className="text-lg font-bold text-element-800">Instructions</div>
<ReadOnlyTextArea content={agentConfiguration.instructions} />
</div>
) : (
"This assistant has no instructions."
);

return (
<Sheet open={!!assistantId} onOpenChange={onClose}>
<SheetContent size="lg">
Expand All @@ -137,11 +335,36 @@ export function AssistantDetails({
{agentConfiguration && (
<div className="flex flex-col gap-5 pt-6 text-sm text-foreground">
<DescriptionSection />
<AssistantActionsSection
agentConfiguration={agentConfiguration}
owner={owner}
/>
<InstructionsSection />
{showPerformanceTab && (
<Tabs value={selectedTab}>
<TabsList>
<TabsTrigger
value="info"
label="Info"
icon={InformationCircleIcon}
onClick={() => setSelectedTab("info")}
/>
<TabsTrigger
value="performance"
label="Performance"
icon={BarChartIcon}
onClick={() => setSelectedTab("performance")}
/>
</TabsList>
</Tabs>
)}
{selectedTab === "info" && (
<AssistantDetailsInfo
agentConfiguration={agentConfiguration}
owner={owner}
/>
)}
{selectedTab === "performance" && (
<AssistantDetailsPerformance
agentConfiguration={agentConfiguration}
owner={owner}
/>
)}
</div>
)}
</SheetContainer>
Expand Down
Loading

0 comments on commit 10d7b94

Please sign in to comment.