3
import { v4 as uuidv4 } from "uuid";
5
import { makeAPICall, pruneDatabase } from "@/src/__tests__/test-utils";
6
import { ModelUsageUnit } from "@/src/constants";
7
import { prisma } from "@/src/server/db";
8
import { type ObservationView } from "@prisma/client";
10
describe("/api/public/observations API Endpoint", () => {
11
beforeEach(async () => await pruneDatabase());
12
afterEach(async () => await pruneDatabase());
14
it("should fetch all observations", async () => {
15
await pruneDatabase();
17
const traceId = uuidv4();
19
await prisma.trace.create({
24
projectId: "7a88fb47-b4e2-43b8-a06c-a5ce950dc53a",
25
metadata: { key: "value" },
31
const model = await prisma.model.create({
34
modelName: "gpt-3.5-turbo",
35
inputPrice: "0.0000010",
36
outputPrice: "0.0000020",
38
matchPattern: "(.*)(gpt-)(35|3.5)(-turbo)?(.*)",
40
unit: ModelUsageUnit.Tokens,
44
await prisma.observation.create({
48
name: "generation-name",
49
startTime: new Date("2021-01-01T00:00:00.000Z"),
50
endTime: new Date("2021-01-01T00:00:00.000Z"),
51
model: "gpt-3.5-turbo",
52
modelParameters: { key: "value" },
53
input: { key: "input" },
54
output: { key: "output" },
61
connect: { id: "7a88fb47-b4e2-43b8-a06c-a5ce950dc53a" },
63
internalModel: "gpt-3.5-turbo",
64
unit: ModelUsageUnit.Tokens,
68
const fetchedObservations = await makeAPICall(
70
"/api/public/observations",
74
expect(fetchedObservations.status).toBe(200);
76
if (!isObservationList(fetchedObservations.body)) {
78
"Expected body to be an array of observations" +
79
JSON.stringify(fetchedObservations.body),
83
expect(fetchedObservations.body.data.length).toBe(1);
84
expect(fetchedObservations.body.data[0]?.traceId).toBe(traceId);
85
expect(fetchedObservations.body.data[0]?.input).toEqual({ key: "input" });
86
expect(fetchedObservations.body.data[0]?.output).toEqual({ key: "output" });
87
expect(fetchedObservations.body.data[0]?.model).toEqual("gpt-3.5-turbo");
88
expect(fetchedObservations.body.data[0]?.modelId).toEqual(model.id);
90
fetchedObservations.body.data[0]?.calculatedInputCost,
93
fetchedObservations.body.data[0]?.calculatedOutputCost,
96
fetchedObservations.body.data[0]?.calculatedTotalCost,
99
it("should fetch all observations, filtered by generations", async () => {
100
await pruneDatabase();
102
const traceId = uuidv4();
104
await prisma.trace.create({
109
projectId: "7a88fb47-b4e2-43b8-a06c-a5ce950dc53a",
110
metadata: { key: "value" },
116
await prisma.model.create({
119
modelName: "gpt-3.5-turbo",
120
inputPrice: "0.0000010",
121
outputPrice: "0.0000020",
123
matchPattern: "(.*)(gpt-)(35|3.5)(-turbo)?(.*)",
125
unit: ModelUsageUnit.Tokens,
129
await prisma.observation.create({
133
name: "generation-name",
134
startTime: new Date("2021-01-01T00:00:00.000Z"),
135
endTime: new Date("2021-01-01T00:00:00.000Z"),
136
model: "gpt-3.5-turbo",
137
internalModel: "gpt-3.5-turbo",
138
modelParameters: { key: "value" },
139
input: { key: "input" },
140
output: { key: "output" },
142
completionTokens: 20,
145
unit: ModelUsageUnit.Tokens,
148
connect: { id: "7a88fb47-b4e2-43b8-a06c-a5ce950dc53a" },
153
await prisma.observation.create({
157
name: "generation-name",
158
startTime: new Date("2021-01-01T00:00:00.000Z"),
159
endTime: new Date("2021-01-01T00:00:00.000Z"),
160
modelParameters: { key: "value" },
161
input: { key: "input" },
162
output: { key: "output" },
166
connect: { id: "7a88fb47-b4e2-43b8-a06c-a5ce950dc53a" },
171
const fetchedObservations = await makeAPICall(
173
"/api/public/observations?type=GENERATION",
177
console.log(fetchedObservations.body);
179
expect(fetchedObservations.status).toBe(200);
181
if (!isObservationList(fetchedObservations.body)) {
182
throw new Error("Expected body to be an array of observations");
185
expect(fetchedObservations.body.data.length).toBe(1);
186
expect(fetchedObservations.body.data[0]?.traceId).toBe(traceId);
187
expect(fetchedObservations.body.data[0]?.input).toEqual({ key: "input" });
188
expect(fetchedObservations.body.data[0]?.output).toEqual({ key: "output" });
189
expect(fetchedObservations.body.data[0]?.type).toEqual("GENERATION");
193
const isObservationList = (val: unknown): val is ObservationResponse => {
195
typeof val === "object" &&
198
Array.isArray(val.data) &&
201
typeof element === "object" &&
204
"traceId" in element &&
206
"startTime" in element &&
207
"endTime" in element &&
208
"model" in element &&
209
"input" in element &&
210
"output" in element &&
211
"metadata" in element &&
212
"version" in element &&
213
"modelId" in element &&
214
"inputPrice" in element &&
215
"outputPrice" in element &&
216
"totalPrice" in element &&
217
"calculatedInputCost" in element &&
218
"calculatedOutputCost" in element &&
219
"calculatedTotalCost" in element,
224
type ObservationResponse = {
225
data: ObservationView[];