-
Notifications
You must be signed in to change notification settings - Fork 39
/
pinecone.ts
131 lines (112 loc) 路 2.69 KB
/
pinecone.ts
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
import { apiCall } from '../util/apicall.js';
import type {
DBQueryRequest,
DBQueryResponse,
DBService,
DBUpsertRequest,
DBUpsertResponse
} from './types.js';
// For upsert
// type PineconeUpsertRequest = {
// id: string;
// values: readonly number[];
// metadata?: Record<string, string>;
// };
// type PineconeUpsertResponse = {
// upsertedCount: number;
// };
// For query
type PineconeQueryRequest = {
namespace?: string;
topK: number;
filter?: Record<string, string>;
includeValues: boolean;
includeMetadata: boolean;
vector: readonly number[];
id?: string;
};
type PineconeQueryResponse = {
matches: {
id: string;
score: number;
values: number[];
metadata?: Record<string, string>;
}[];
};
const createPineconeQueryRequest = (
req: Readonly<DBQueryRequest>
): PineconeQueryRequest => {
const pineconeQueryRequest: PineconeQueryRequest = {
namespace: req.namespace,
topK: req.limit || 10,
filter: {},
includeValues: true,
includeMetadata: true,
vector: req.values ?? [],
id: req.id
};
return pineconeQueryRequest;
};
export interface PineconeArgs {
apiKey: string;
host: string;
}
/**
* Pinecone: DB Service
* @export
*/
export class Pinecone implements DBService {
private apiKey: string;
private apiURL: string;
constructor({ apiKey, host }: Readonly<PineconeArgs>) {
if (!apiKey || apiKey === '') {
throw new Error('Pinecone API key not set');
}
this.apiKey = apiKey;
this.apiURL = host;
}
async upsert(req: Readonly<DBUpsertRequest>): Promise<DBUpsertResponse> {
await this.batchUpsert([req]);
return { ids: [req.id] };
}
async batchUpsert(
batchReq: Readonly<DBUpsertRequest[]>
): Promise<DBUpsertResponse> {
if (batchReq.length === 0) {
throw new Error('Batch request is empty');
}
await apiCall(
{
url: this.apiURL,
headers: { Authorization: `Bearer ${this.apiKey}` },
name: '/vectors/upsert'
},
batchReq.map(({ id, values = [], metadata }) => ({
id,
values,
metadata
}))
);
return { ids: batchReq.map(({ id }) => id) };
}
async query(req: Readonly<DBQueryRequest>): Promise<DBQueryResponse> {
if (req.text) {
throw new Error('Pinecone does not support text');
}
const res = (await apiCall(
{
url: this.apiURL,
headers: { Authorization: `Bearer ${this.apiKey}` },
name: '/query'
},
createPineconeQueryRequest(req)
)) as PineconeQueryResponse;
const matches = res.matches.map(({ id, score, values, metadata }) => ({
id,
score,
metadata,
values
}));
return { matches };
}
}