langfuse

Форк
0
144 строки · 4.9 Кб
1
import { GroupedScoreBadges } from "@/src/components/grouped-score-badge";
2
import Header from "@/src/components/layouts/header";
3
import { NoAccessError } from "@/src/components/no-access";
4
import { PublishSessionSwitch } from "@/src/components/publish-object-switch";
5
import { StarSessionToggle } from "@/src/components/star-toggle";
6
import { IOPreview } from "@/src/components/trace/IOPreview";
7
import { Badge } from "@/src/components/ui/badge";
8
import { Card } from "@/src/components/ui/card";
9
import { ManualScoreButton } from "@/src/features/manual-scoring/components/ManualScoreButton";
10
import { DetailPageNav } from "@/src/features/navigate-detail-pages/DetailPageNav";
11
import { useDetailPageLists } from "@/src/features/navigate-detail-pages/context";
12
import { api } from "@/src/utils/api";
13
import { usdFormatter } from "@/src/utils/numbers";
14
import Link from "next/link";
15
import { useEffect } from "react";
16

17
export const SessionPage: React.FC<{
18
  sessionId: string;
19
  projectId: string;
20
}> = ({ sessionId, projectId }) => {
21
  const { setDetailPageList } = useDetailPageLists();
22
  const session = api.sessions.byId.useQuery(
23
    {
24
      sessionId,
25
      projectId: projectId,
26
    },
27
    {
28
      retry(failureCount, error) {
29
        if (error.data?.code === "UNAUTHORIZED") return false;
30
        return failureCount < 3;
31
      },
32
    },
33
  );
34
  useEffect(() => {
35
    if (session.isSuccess) {
36
      setDetailPageList(
37
        "traces",
38
        session.data.traces.map((t) => t.id),
39
      );
40
    }
41
    // eslint-disable-next-line react-hooks/exhaustive-deps
42
  }, [session.isSuccess, session.data]);
43

44
  if (session.error?.data?.code === "UNAUTHORIZED") return <NoAccessError />;
45

46
  return (
47
    <div className="flex flex-col overflow-hidden xl:container">
48
      <Header
49
        title="Session"
50
        breadcrumb={[
51
          {
52
            name: "Sessions",
53
            href: `/project/${projectId}/sessions`,
54
          },
55
          { name: sessionId },
56
        ]}
57
        actionButtons={[
58
          <StarSessionToggle
59
            key="star"
60
            projectId={projectId}
61
            sessionId={sessionId}
62
            value={session.data?.bookmarked ?? false}
63
          />,
64
          <PublishSessionSwitch
65
            projectId={projectId}
66
            sessionId={sessionId}
67
            isPublic={session.data?.public ?? false}
68
            key="publish"
69
          />,
70
          <DetailPageNav
71
            key="nav"
72
            currentId={encodeURIComponent(sessionId)}
73
            path={(id) =>
74
              `/project/${projectId}/sessions/${encodeURIComponent(id)}`
75
            }
76
            listKey="sessions"
77
          />,
78
        ]}
79
      />
80
      <div className="flex flex-wrap gap-2">
81
        {session.data?.users.filter(Boolean).map((userId) => (
82
          <Link
83
            key={userId}
84
            href={`/project/${projectId}/users/${encodeURIComponent(
85
              userId ?? "",
86
            )}`}
87
          >
88
            <Badge>User ID: {userId}</Badge>
89
          </Link>
90
        ))}
91
        <Badge variant="outline">Traces: {session.data?.traces.length}</Badge>
92
        {session.data && (
93
          <Badge variant="outline">
94
            Total cost: {usdFormatter(session.data.totalCost, 2, 2)}
95
          </Badge>
96
        )}
97
      </div>
98
      <div className="mt-5 flex flex-col gap-2 border-t pt-5">
99
        {session.data?.traces.map((trace) => (
100
          <Card
101
            className="border-border-gray-150 group grid gap-3 p-2 shadow-none hover:border-gray-300 md:grid-cols-3"
102
            key={trace.id}
103
          >
104
            <div className="col-span-2 flex flex-col gap-2 p-0">
105
              {trace.input || trace.output ? (
106
                <IOPreview
107
                  key={trace.id}
108
                  input={trace.input}
109
                  output={trace.output}
110
                  hideIfNull
111
                />
112
              ) : (
113
                <div className="p-2 text-xs text-gray-500">
114
                  This trace has no input or output.
115
                </div>
116
              )}
117
            </div>
118
            <div className="-mt-1 p-1 opacity-50 transition-opacity group-hover:opacity-100">
119
              <Link
120
                href={`/project/${projectId}/traces/${trace.id}`}
121
                className="text-xs hover:underline"
122
              >
123
                Trace: {trace.name} ({trace.id})&nbsp;↗
124
              </Link>
125
              <div className="text-xs text-gray-500">
126
                {trace.timestamp.toLocaleString()}
127
              </div>
128
              <div className="mb-1 mt-2 text-xs text-gray-500">Scores</div>
129
              <div className="flex flex-wrap content-start items-start gap-1">
130
                <GroupedScoreBadges scores={trace.scores} />
131
              </div>
132
              <ManualScoreButton
133
                projectId={projectId}
134
                traceId={trace.id}
135
                scores={trace.scores}
136
                variant="badge"
137
              />
138
            </div>
139
          </Card>
140
        ))}
141
      </div>
142
    </div>
143
  );
144
};
145

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.