-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathroute.ts
More file actions
134 lines (125 loc) · 3.88 KB
/
Copy pathroute.ts
File metadata and controls
134 lines (125 loc) · 3.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
import { NextResponse, NextRequest } from "next/server";
import type { PostgrestResponse } from "@supabase/supabase-js";
import { createClient } from "~/utils/supabase/server";
import { asPostgrestFailure } from "@repo/database/lib/contextFunctions";
import {
createApiResponse,
handleRouteError,
defaultOptionsHandler,
} from "~/utils/supabase/apiUtils";
import {
processAndInsertBatch,
KNOWN_EMBEDDING_TABLES,
} from "~/utils/supabase/dbUtils";
import {
type ApiInputEmbeddingItem,
type ApiOutputEmbeddingRecord,
embeddingInputProcessing,
embeddingOutputProcessing,
} from "~/utils/supabase/validators";
const DEFAULT_MODEL = "openai_text_embedding_3_small_1536";
const batchInsertEmbeddingsProcess = async (
supabase: Awaited<ReturnType<typeof createClient>>,
embeddingItems: ApiInputEmbeddingItem[],
): Promise<PostgrestResponse<ApiOutputEmbeddingRecord>> => {
// groupBy is node21 only, we are using 20. Group by model, by hand.
// Note: This means that later index values may be totally wrong.
// Note2: The key is a ModelName, but I cannot use an enum as a key.
const byModel: { [key: string]: ApiInputEmbeddingItem[] } = {};
try {
embeddingItems.reduce((acc, item) => {
const model = item?.model || DEFAULT_MODEL;
if (acc[model] === undefined) {
acc[model] = [];
}
acc[model].push(item);
return acc;
}, byModel);
} catch (error) {
if (error instanceof Error) {
return asPostgrestFailure(error.message, "exception");
}
throw error;
}
const globalResults: ApiOutputEmbeddingRecord[] = [];
const partialErrors: string[] = [];
let created = false,
count = 0,
has_400 = false;
for (const modelName of Object.keys(byModel)) {
const embeddingItemsSet = byModel[modelName];
if (embeddingItemsSet === undefined) continue;
const tableData = KNOWN_EMBEDDING_TABLES[modelName];
if (tableData === undefined) continue;
const results = await processAndInsertBatch<
// any ContentEmbedding table for type checking purposes only
"ContentEmbedding_openai_text_embedding_3_small_1536",
ApiInputEmbeddingItem,
ApiOutputEmbeddingRecord
>({
supabase,
items: embeddingItemsSet,
tableName: tableData.tableName,
inputProcessor: embeddingInputProcessing,
outputProcessor: embeddingOutputProcessing,
});
if (results.data) {
count += results.data.length;
globalResults.push(...results.data);
created = created || results.status === 201;
} else {
partialErrors.push(results.error.message);
if (results.status === 400) has_400 = true;
}
}
if (count > 0) {
if (partialErrors.length > 0) {
return {
data: globalResults,
error: null,
success: true,
status: has_400 ? 400 : 500,
count,
statusText: partialErrors.join("; "),
};
} else
return {
data: globalResults,
error: null,
success: true,
status: created ? 201 : 200,
count,
statusText: created ? "created" : "success",
};
} else {
return asPostgrestFailure(
partialErrors.join("; "),
"multiple",
has_400 ? 400 : 500,
);
}
};
export const POST = async (request: NextRequest): Promise<NextResponse> => {
const supabase = await createClient();
try {
const body: ApiInputEmbeddingItem[] = await request.json();
if (!Array.isArray(body)) {
return createApiResponse(
request,
asPostgrestFailure(
"Request body must be an array of embedding items.",
"empty",
),
);
}
const result = await batchInsertEmbeddingsProcess(supabase, body);
return createApiResponse(request, result);
} catch (e: unknown) {
return handleRouteError(
request,
e,
`/api/supabase/content-embedding/batch`,
);
}
};
export const OPTIONS = defaultOptionsHandler;