Skip to content

Commit 93743af

Browse files
authored
Merge pull request #236 from weaviate/text2vec-weaviate
Text2vec weaviate
2 parents 0eb5e12 + f207ed5 commit 93743af

File tree

9 files changed

+183
-32
lines changed

9 files changed

+183
-32
lines changed

package-lock.json

Lines changed: 5 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@
2424
"test:coverage": "npm run test -- --coverage",
2525
"build": "npm run build:node",
2626
"build:web": "tsup",
27-
"build:cjs": "tsc --module commonjs --outDir dist/node/cjs && touch dist/node/cjs/package.json && echo '{\"type\": \"commonjs\"}' > dist/node/cjs/package.json",
28-
"build:esm": "tsc --module esnext --outDir dist/node/esm && touch dist/node/esm/package.json && echo '{\"type\": \"module\"}' > dist/node/esm/package.json",
27+
"build:cjs": "tsc --module commonjs --moduleResolution node10 --outDir dist/node/cjs && touch dist/node/cjs/package.json && echo '{\"type\": \"commonjs\"}' > dist/node/cjs/package.json",
28+
"build:esm": "tsc --outDir dist/node/esm && touch dist/node/esm/package.json && echo '{\"type\": \"module\"}' > dist/node/esm/package.json",
2929
"build:node": "npm run lint && npm run build:cjs && npm run build:esm && prettier --write --no-error-on-unmatched-pattern '**/dist/**/*.{ts,js}'",
3030
"prepack": "npm run build",
3131
"lint": "eslint --ext .ts,.js .",
@@ -95,7 +95,7 @@
9595
"tsup": "^8.0.2",
9696
"typedoc": "^0.25.12",
9797
"typedoc-plugin-extras": "^3.0.0",
98-
"typescript": "5.1.3"
98+
"typescript": "^5.3.3"
9999
},
100100
"lint-staged": {
101101
"*.{ts,js}": [

src/collections/config/types/vectorizer.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ export type Vectorizer =
4040
| 'text2vec-google'
4141
| 'text2vec-transformers'
4242
| 'text2vec-voyageai'
43+
| 'text2vec-weaviate'
4344
| 'none';
4445

4546
/** The configuration for image vectorization using a neural network module.
@@ -406,6 +407,20 @@ export type Text2VecVoyageAIConfig = {
406407
vectorizeCollectionName?: boolean;
407408
};
408409

410+
/**
411+
* The configuration for text vectorization using Weaviate's self-hosted text-based embedding models.
412+
*
413+
* TODO: add documentation reference once available.
414+
*/
415+
export type Text2VecWeaviateConfig = {
416+
/** The base URL to use where API requests should go. */
417+
baseURL?: string;
418+
/** The model to use. */
419+
model?: 'Snowflake/snowflake-arctic-embed-m-v1.5' | string;
420+
/** Whether to vectorize the collection name. */
421+
vectorizeCollectionName?: boolean;
422+
};
423+
409424
export type NoVectorizerConfig = {};
410425

411426
export type VectorizerConfig =
@@ -428,6 +443,7 @@ export type VectorizerConfig =
428443
| Text2VecPalmConfig
429444
| Text2VecTransformersConfig
430445
| Text2VecVoyageAIConfig
446+
| Text2VecWeaviateConfig
431447
| NoVectorizerConfig;
432448

433449
export type VectorizerConfigType<V> = V extends 'img2vec-neural'
@@ -474,6 +490,8 @@ export type VectorizerConfigType<V> = V extends 'img2vec-neural'
474490
? Text2VecTransformersConfig | undefined
475491
: V extends 'text2vec-voyageai'
476492
? Text2VecVoyageAIConfig | undefined
493+
: V extends 'text2vec-weaviate'
494+
? Text2VecWeaviateConfig | undefined
477495
: V extends 'none'
478496
? {}
479497
: V extends undefined

src/collections/configure/types/vectorizer.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
Text2VecOpenAIConfig,
1818
Text2VecTransformersConfig,
1919
Text2VecVoyageAIConfig,
20+
Text2VecWeaviateConfig,
2021
VectorIndexType,
2122
Vectorizer,
2223
VectorizerConfigType,
@@ -182,6 +183,8 @@ export type Text2VecTransformersConfigCreate = Text2VecTransformersConfig;
182183

183184
export type Text2VecVoyageAIConfigCreate = Text2VecVoyageAIConfig;
184185

186+
export type Text2VecWeaviateConfigCreate = Text2VecWeaviateConfig;
187+
185188
export type VectorizerConfigCreateType<V> = V extends 'img2vec-neural'
186189
? Img2VecNeuralConfigCreate | undefined
187190
: V extends 'multi2vec-clip'
@@ -226,6 +229,8 @@ export type VectorizerConfigCreateType<V> = V extends 'img2vec-neural'
226229
? Text2VecTransformersConfigCreate | undefined
227230
: V extends 'text2vec-voyageai'
228231
? Text2VecVoyageAIConfigCreate | undefined
232+
: V extends 'text2vec-weaviate'
233+
? Text2VecWeaviateConfigCreate | undefined
229234
: V extends 'none'
230235
? {}
231236
: V extends undefined

src/collections/configure/unit.test.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1342,6 +1342,45 @@ describe('Unit testing of the vectorizer factory class', () => {
13421342
},
13431343
});
13441344
});
1345+
1346+
it('should create the correct Text2VecWeaviateConfig type with defaults', () => {
1347+
const config = configure.vectorizer.text2VecWeaviate();
1348+
expect(config).toEqual<VectorConfigCreate<never, undefined, 'hnsw', 'text2vec-weaviate'>>({
1349+
name: undefined,
1350+
vectorIndex: {
1351+
name: 'hnsw',
1352+
config: undefined,
1353+
},
1354+
vectorizer: {
1355+
name: 'text2vec-weaviate',
1356+
config: undefined,
1357+
},
1358+
});
1359+
});
1360+
1361+
it('should create the correct Text2VecWeaviateConfig type with all values', () => {
1362+
const config = configure.vectorizer.text2VecWeaviate({
1363+
name: 'test',
1364+
baseURL: 'base-url',
1365+
model: 'model',
1366+
vectorizeCollectionName: true,
1367+
});
1368+
expect(config).toEqual<VectorConfigCreate<never, 'test', 'hnsw', 'text2vec-weaviate'>>({
1369+
name: 'test',
1370+
vectorIndex: {
1371+
name: 'hnsw',
1372+
config: undefined,
1373+
},
1374+
vectorizer: {
1375+
name: 'text2vec-weaviate',
1376+
config: {
1377+
baseURL: 'base-url',
1378+
model: 'model',
1379+
vectorizeCollectionName: true,
1380+
},
1381+
},
1382+
});
1383+
});
13451384
});
13461385

13471386
describe('Unit testing of the generative factory class', () => {

src/collections/configure/vectorizer.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -600,4 +600,26 @@ export const vectorizer = {
600600
},
601601
});
602602
},
603+
604+
/**
605+
* Create a `VectorConfigCreate` object with the vectorizer set to `'text2vec-weaviate'`.
606+
*
607+
* TODO: add documentation reference once available.
608+
*
609+
* @param {ConfigureTextVectorizerOptions<T, N, I, 'text2vec-weaviate'>} [opts] The configuration for the `text2vec-weaviate` vectorizer.
610+
* @returns {VectorConfigCreate<PrimitiveKeys<T>, N, I, 'text2vec-weaviate'>} The configuration object.
611+
*/
612+
text2VecWeaviate: <T, N extends string | undefined = undefined, I extends VectorIndexType = 'hnsw'>(
613+
opts?: ConfigureTextVectorizerOptions<T, N, I, 'text2vec-weaviate'>
614+
): VectorConfigCreate<PrimitiveKeys<T>, N, I, 'text2vec-weaviate'> => {
615+
const { name, sourceProperties, vectorIndexConfig, ...config } = opts || {};
616+
return makeVectorizer(name, {
617+
sourceProperties,
618+
vectorIndexConfig,
619+
vectorizerConfig: {
620+
name: 'text2vec-weaviate',
621+
config: Object.keys(config).length === 0 ? undefined : config,
622+
},
623+
});
624+
},
603625
};

src/connection/helpers.test.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import weaviate from '../index.js';
2+
import { connectToWeaviateCloud } from './helpers.js';
23

34
const WCD_URL = 'https://piblpmmdsiknacjnm1ltla.c1.europe-west3.gcp.weaviate.cloud';
45
const WCD_KEY = 'cy4ua772mBlMdfw3YnclqAWzFhQt0RLIN0sl';
@@ -29,4 +30,57 @@ describe('Testing of the connection helper methods', () => {
2930
throw new Error('it should not have errord: ' + e);
3031
});
3132
});
33+
34+
describe('adds Weaviate Embedding Service headers', () => {
35+
it('to empty headers', async () => {
36+
const clientMakerMock = jest.fn().mockResolvedValue(undefined);
37+
38+
await connectToWeaviateCloud(WCD_URL, clientMakerMock, {
39+
authCredentials: new weaviate.ApiKey(WCD_KEY),
40+
});
41+
42+
expect(clientMakerMock.mock.calls[0][0].headers).toEqual({
43+
'X-Weaviate-Api-Key': WCD_KEY,
44+
'X-Weaviate-Cluster-Url': WCD_URL,
45+
});
46+
});
47+
48+
it('to existing headers', async () => {
49+
const clientMakerMock = jest.fn().mockResolvedValue(undefined);
50+
51+
await connectToWeaviateCloud(WCD_URL, clientMakerMock, {
52+
authCredentials: new weaviate.ApiKey(WCD_KEY),
53+
headers: { existingHeader: 'existingValue' },
54+
});
55+
56+
expect(clientMakerMock.mock.calls[0][0].headers).toEqual({
57+
existingHeader: 'existingValue',
58+
'X-Weaviate-Api-Key': WCD_KEY,
59+
'X-Weaviate-Cluster-Url': WCD_URL,
60+
});
61+
});
62+
});
63+
64+
describe('does not add Weaviate Embedding Service headers when not using API key', () => {
65+
it('to empty headers', async () => {
66+
const clientMakerMock = jest.fn().mockResolvedValue(undefined);
67+
68+
await connectToWeaviateCloud(WCD_URL, clientMakerMock, {
69+
authCredentials: new weaviate.AuthUserPasswordCredentials({ username: 'test' }),
70+
});
71+
72+
expect(clientMakerMock.mock.calls[0][0].headers).toBe(undefined);
73+
});
74+
75+
it('to existing headers', async () => {
76+
const clientMakerMock = jest.fn().mockResolvedValue(undefined);
77+
78+
await connectToWeaviateCloud(WCD_URL, clientMakerMock, {
79+
authCredentials: new weaviate.AuthUserPasswordCredentials({ username: 'test' }),
80+
headers: { existingHeader: 'existingValue' },
81+
});
82+
83+
expect(clientMakerMock.mock.calls[0][0].headers).toEqual({ existingHeader: 'existingValue' });
84+
});
85+
});
3286
});

src/connection/helpers.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { WeaviateStartUpError } from '../errors.js';
22
import { ClientParams, WeaviateClient } from '../index.js';
3-
import { AuthCredentials } from './auth.js';
3+
import { AuthCredentials, isApiKey, mapApiKey } from './auth.js';
44
import { ProxiesParams, TimeoutParams } from './http.js';
55

66
/** The options available to the `weaviate.connectToWeaviateCloud` method. */
@@ -100,7 +100,7 @@ export function connectToWeaviateCloud(
100100
},
101101
},
102102
auth: options?.authCredentials,
103-
headers: options?.headers,
103+
headers: addWeaviateEmbeddingServiceHeaders(clusterURL, options),
104104
}).catch((e) => {
105105
throw new WeaviateStartUpError(`Weaviate failed to startup with message: ${e.message}`);
106106
});
@@ -155,3 +155,15 @@ export function connectToCustom(
155155
throw new WeaviateStartUpError(`Weaviate failed to startup with message: ${e.message}`);
156156
});
157157
}
158+
159+
function addWeaviateEmbeddingServiceHeaders(clusterURL: string, options?: ConnectToWeaviateCloudOptions) {
160+
if (!isApiKey(options?.authCredentials)) {
161+
return options?.headers;
162+
}
163+
164+
return {
165+
...options.headers,
166+
'X-Weaviate-Api-Key': mapApiKey(options.authCredentials).apiKey,
167+
'X-Weaviate-Cluster-Url': clusterURL,
168+
};
169+
}

src/connection/journey.test.ts

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -35,29 +35,29 @@ describe('connection', () => {
3535
});
3636
});
3737

38-
it('makes an Azure logged-in request with client credentials', async () => {
39-
if (process.env.AZURE_CLIENT_SECRET == undefined || process.env.AZURE_CLIENT_SECRET == '') {
40-
console.warn('Skipping because `AZURE_CLIENT_SECRET` is not set');
41-
return Promise.resolve();
42-
}
43-
44-
const client = await weaviate.connectToLocal({
45-
port: 8081,
46-
authCredentials: new AuthClientCredentials({
47-
clientSecret: process.env.AZURE_CLIENT_SECRET,
48-
silentRefresh: false,
49-
}),
50-
});
51-
52-
return client
53-
.getMeta()
54-
.then((res) => {
55-
expect(res.version).toBeDefined();
56-
})
57-
.catch((e) => {
58-
throw new Error('it should not have errord: ' + e);
59-
});
60-
});
38+
// it('makes an Azure logged-in request with client credentials', async () => {
39+
// if (process.env.AZURE_CLIENT_SECRET == undefined || process.env.AZURE_CLIENT_SECRET == '') {
40+
// console.warn('Skipping because `AZURE_CLIENT_SECRET` is not set');
41+
// return Promise.resolve();
42+
// }
43+
44+
// const client = await weaviate.connectToLocal({
45+
// port: 8081,
46+
// authCredentials: new AuthClientCredentials({
47+
// clientSecret: process.env.AZURE_CLIENT_SECRET,
48+
// silentRefresh: false,
49+
// }),
50+
// });
51+
52+
// return client
53+
// .getMeta()
54+
// .then((res) => {
55+
// expect(res.version).toBeDefined();
56+
// })
57+
// .catch((e) => {
58+
// throw new Error('it should not have errord: ' + e);
59+
// });
60+
// });
6161

6262
it('makes an Okta logged-in request with client credentials', async () => {
6363
if (process.env.OKTA_CLIENT_SECRET == undefined || process.env.OKTA_CLIENT_SECRET == '') {

0 commit comments

Comments
 (0)