@anvia/qdrant 0.1.4 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@ pnpm --filter @anvia/qdrant build
|
|
|
19
19
|
## Usage
|
|
20
20
|
|
|
21
21
|
```ts
|
|
22
|
-
import { embedDocuments } from "@anvia/core";
|
|
22
|
+
import { embedDocuments } from "@anvia/core/embeddings";
|
|
23
23
|
import { OpenAIClient } from "@anvia/openai";
|
|
24
24
|
import { QdrantVectorStore } from "@anvia/qdrant";
|
|
25
25
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import { VectorMetadata,
|
|
1
|
+
import { VectorMetadata, EmbeddingModel, EmbeddedDocument } from '@anvia/core/embeddings';
|
|
2
|
+
import { Tool } from '@anvia/core/tool';
|
|
3
|
+
import { VectorSearchIndex, VectorSearchRequest, VectorSearchResult, VectorSearchToolOptions, VectorFilter } from '@anvia/core/vector-store';
|
|
2
4
|
|
|
3
5
|
type QdrantDistance = "Cosine" | "Dot" | "Euclid";
|
|
4
6
|
type QdrantClientLike = {
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
2
|
import { createHash } from "crypto";
|
|
3
3
|
import {
|
|
4
|
-
createVectorSearchTool,
|
|
5
4
|
embedText
|
|
6
|
-
} from "@anvia/core";
|
|
5
|
+
} from "@anvia/core/embeddings";
|
|
6
|
+
import {
|
|
7
|
+
createVectorSearchTool
|
|
8
|
+
} from "@anvia/core/vector-store";
|
|
7
9
|
var documentIdPayloadKey = "__anvia_document_id";
|
|
8
10
|
var documentPayloadKey = "__anvia_document";
|
|
9
11
|
var reservedPayloadPrefix = "__anvia_";
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport {\n createVectorSearchTool,\n type EmbeddedDocument,\n type EmbeddingModel,\n embedText,\n type Tool,\n type VectorFilter,\n type VectorMetadata,\n type VectorSearchIndex,\n type VectorSearchRequest,\n type VectorSearchResult,\n type VectorSearchToolOptions,\n} from \"@anvia/core\";\n\nconst documentIdPayloadKey = \"__anvia_document_id\";\nconst documentPayloadKey = \"__anvia_document\";\nconst reservedPayloadPrefix = \"__anvia_\";\n\nexport type QdrantDistance = \"Cosine\" | \"Dot\" | \"Euclid\";\n\ntype QdrantClientLike = {\n getCollection(collectionName: string): Promise<unknown>;\n createCollection(collectionName: string, options: Record<string, unknown>): Promise<unknown>;\n upsert(collectionName: string, options: Record<string, unknown>): Promise<unknown>;\n search(collectionName: string, options: Record<string, unknown>): Promise<unknown>;\n};\n\nexport type QdrantVectorStoreConnectOptions = {\n client?: QdrantClientLike | undefined;\n collectionName: string;\n vectorSize: number;\n createIfMissing?: boolean | undefined;\n distance?: QdrantDistance | undefined;\n};\n\nexport class QdrantVectorStore<T, Metadata extends VectorMetadata = VectorMetadata> {\n private constructor(\n private readonly client: QdrantClientLike,\n private readonly collectionName: string,\n ) {}\n\n static async connect<T, Metadata extends VectorMetadata = VectorMetadata>(\n options: QdrantVectorStoreConnectOptions,\n ): Promise<QdrantVectorStore<T, Metadata>> {\n const client = options.client ?? (await defaultQdrantClient());\n if (options.createIfMissing === false) {\n await client.getCollection(options.collectionName);\n return new QdrantVectorStore<T, Metadata>(client, options.collectionName);\n }\n\n try {\n await client.getCollection(options.collectionName);\n } catch {\n await client.createCollection(options.collectionName, {\n vectors: {\n size: options.vectorSize,\n distance: options.distance ?? \"Cosine\",\n },\n });\n }\n return new QdrantVectorStore<T, Metadata>(client, options.collectionName);\n }\n\n async upsertDocuments(documents: Array<EmbeddedDocument<T, Metadata>>): Promise<void> {\n const points = documents.flatMap((document) => qdrantPoints(document));\n await this.client.upsert(this.collectionName, { points });\n }\n\n index(model: EmbeddingModel): QdrantVectorIndex<T, Metadata> {\n return new QdrantVectorIndex(model, this.client, this.collectionName);\n }\n}\n\nexport class QdrantVectorIndex<T, Metadata extends VectorMetadata = VectorMetadata>\n implements VectorSearchIndex<T, Metadata>\n{\n constructor(\n private readonly model: EmbeddingModel,\n private readonly client: QdrantClientLike,\n private readonly collectionName: string,\n ) {}\n\n async search(request: VectorSearchRequest): Promise<Array<VectorSearchResult<T, Metadata>>> {\n const queryEmbedding = await embedText(this.model, request.query);\n const response = await this.client.search(this.collectionName, {\n vector: queryEmbedding.vector,\n limit: request.topK,\n filter: filterToQdrantFilter(request.filter),\n with_payload: true,\n });\n return parseQueryResults<T, Metadata>(response, request.threshold);\n }\n\n async searchIds(request: VectorSearchRequest): Promise<Array<{ score: number; id: string }>> {\n return (await this.search(request)).map(({ score, id }) => ({ score, id }));\n }\n\n asTool(options: VectorSearchToolOptions): Tool<{ query: string; topK?: number }, unknown> {\n return createVectorSearchTool(this, options);\n }\n}\n\nexport function filterToQdrantFilter(filter: VectorFilter | undefined): unknown {\n if (filter === undefined) {\n return undefined;\n }\n\n switch (filter.type) {\n case \"eq\":\n return { must: [{ key: filter.key, match: { value: filter.value } }] };\n case \"gt\":\n return { must: [{ key: filter.key, range: { gt: filter.value } }] };\n case \"lt\":\n return { must: [{ key: filter.key, range: { lt: filter.value } }] };\n case \"and\":\n return { must: filter.filters.map(filterToQdrantFilter) };\n case \"or\":\n return { should: filter.filters.map(filterToQdrantFilter) };\n }\n}\n\nasync function defaultQdrantClient(): Promise<QdrantClientLike> {\n const qdrant = await import(\"@qdrant/js-client-rest\");\n return new qdrant.QdrantClient({}) as QdrantClientLike;\n}\n\nfunction qdrantPoints<T, Metadata extends VectorMetadata>(\n document: EmbeddedDocument<T, Metadata>,\n): Array<{\n id: string;\n vector: number[];\n payload: Record<string, unknown>;\n}> {\n if (document.embeddings.length === 0) {\n throw new Error(`Document ${document.id} has no embeddings`);\n }\n assertNoReservedMetadata(document.metadata);\n\n return document.embeddings.map((embedding, index) => {\n const logicalId =\n document.embeddings.length === 1 ? document.id : `${document.id}#embedding:${index}`;\n return {\n id: pointId(logicalId),\n vector: embedding.vector,\n payload: {\n [documentIdPayloadKey]: document.id,\n [documentPayloadKey]: serializeDocument(document.document),\n ...(document.metadata ?? {}),\n },\n };\n });\n}\n\nfunction assertNoReservedMetadata(metadata: VectorMetadata | undefined): void {\n for (const key of Object.keys(metadata ?? {})) {\n if (key.startsWith(reservedPayloadPrefix)) {\n throw new Error(`Metadata key ${key} is reserved for Anvia Qdrant payloads`);\n }\n }\n}\n\nfunction pointId(id: string): string {\n const hex = createHash(\"sha256\").update(id).digest(\"hex\").slice(0, 32);\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(\n 16,\n 20,\n )}-${hex.slice(20)}`;\n}\n\nfunction serializeDocument(document: unknown): string {\n return typeof document === \"string\" ? document : JSON.stringify(document);\n}\n\nfunction parseQueryResults<T, Metadata extends VectorMetadata>(\n response: unknown,\n threshold: number | undefined,\n): Array<VectorSearchResult<T, Metadata>> {\n const points = rawPoints(response);\n const byId = new Map<string, VectorSearchResult<T, Metadata>>();\n\n for (const point of points) {\n if (threshold !== undefined && point.score < threshold) {\n continue;\n }\n\n const id = String(point.payload?.[documentIdPayloadKey] ?? point.id);\n const result = {\n id,\n score: point.score,\n document: parseDocument(point.payload?.[documentPayloadKey]),\n ...metadataFromPayload<Metadata>(point.payload),\n } as VectorSearchResult<T, Metadata>;\n const current = byId.get(id);\n if (current === undefined || result.score > current.score) {\n byId.set(id, result);\n }\n }\n\n return [...byId.values()];\n}\n\nfunction rawPoints(response: unknown): Array<{\n id: string | number;\n score: number;\n payload?: Record<string, unknown> | null;\n}> {\n const raw = response as {\n points?: Array<{\n id: string | number;\n score?: number;\n payload?: Record<string, unknown> | null;\n }>;\n result?:\n | {\n points?: Array<{\n id: string | number;\n score?: number;\n payload?: Record<string, unknown> | null;\n }>;\n }\n | Array<{ id: string | number; score?: number; payload?: Record<string, unknown> | null }>;\n };\n const responseArray = Array.isArray(response)\n ? (response as Array<{\n id: string | number;\n score?: number;\n payload?: Record<string, unknown> | null;\n }>)\n : undefined;\n const points =\n responseArray ??\n (Array.isArray(raw.result)\n ? raw.result\n : Array.isArray(raw.result?.points)\n ? raw.result.points\n : raw.points);\n return (points ?? []).map((point) => ({\n id: point.id,\n score: point.score ?? 0,\n ...(point.payload === undefined ? {} : { payload: point.payload }),\n }));\n}\n\nfunction parseDocument<T>(document: unknown): T {\n if (document === null || document === undefined) {\n return \"\" as T;\n }\n if (typeof document !== \"string\") {\n return document as T;\n }\n try {\n return JSON.parse(document) as T;\n } catch {\n return document as T;\n }\n}\n\nfunction metadataFromPayload<Metadata extends VectorMetadata>(\n payload: Record<string, unknown> | null | undefined,\n): { metadata?: Metadata | undefined } {\n const metadata = Object.fromEntries(\n Object.entries(payload ?? {}).filter(([key]) => !key.startsWith(reservedPayloadPrefix)),\n ) as Metadata;\n return Object.keys(metadata).length === 0 ? {} : { metadata };\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport {\n type EmbeddedDocument,\n type EmbeddingModel,\n embedText,\n type VectorMetadata,\n} from \"@anvia/core/embeddings\";\nimport type { Tool } from \"@anvia/core/tool\";\nimport {\n createVectorSearchTool,\n type VectorFilter,\n type VectorSearchIndex,\n type VectorSearchRequest,\n type VectorSearchResult,\n type VectorSearchToolOptions,\n} from \"@anvia/core/vector-store\";\n\nconst documentIdPayloadKey = \"__anvia_document_id\";\nconst documentPayloadKey = \"__anvia_document\";\nconst reservedPayloadPrefix = \"__anvia_\";\n\nexport type QdrantDistance = \"Cosine\" | \"Dot\" | \"Euclid\";\n\ntype QdrantClientLike = {\n getCollection(collectionName: string): Promise<unknown>;\n createCollection(collectionName: string, options: Record<string, unknown>): Promise<unknown>;\n upsert(collectionName: string, options: Record<string, unknown>): Promise<unknown>;\n search(collectionName: string, options: Record<string, unknown>): Promise<unknown>;\n};\n\nexport type QdrantVectorStoreConnectOptions = {\n client?: QdrantClientLike | undefined;\n collectionName: string;\n vectorSize: number;\n createIfMissing?: boolean | undefined;\n distance?: QdrantDistance | undefined;\n};\n\nexport class QdrantVectorStore<T, Metadata extends VectorMetadata = VectorMetadata> {\n private constructor(\n private readonly client: QdrantClientLike,\n private readonly collectionName: string,\n ) {}\n\n static async connect<T, Metadata extends VectorMetadata = VectorMetadata>(\n options: QdrantVectorStoreConnectOptions,\n ): Promise<QdrantVectorStore<T, Metadata>> {\n const client = options.client ?? (await defaultQdrantClient());\n if (options.createIfMissing === false) {\n await client.getCollection(options.collectionName);\n return new QdrantVectorStore<T, Metadata>(client, options.collectionName);\n }\n\n try {\n await client.getCollection(options.collectionName);\n } catch {\n await client.createCollection(options.collectionName, {\n vectors: {\n size: options.vectorSize,\n distance: options.distance ?? \"Cosine\",\n },\n });\n }\n return new QdrantVectorStore<T, Metadata>(client, options.collectionName);\n }\n\n async upsertDocuments(documents: Array<EmbeddedDocument<T, Metadata>>): Promise<void> {\n const points = documents.flatMap((document) => qdrantPoints(document));\n await this.client.upsert(this.collectionName, { points });\n }\n\n index(model: EmbeddingModel): QdrantVectorIndex<T, Metadata> {\n return new QdrantVectorIndex(model, this.client, this.collectionName);\n }\n}\n\nexport class QdrantVectorIndex<T, Metadata extends VectorMetadata = VectorMetadata>\n implements VectorSearchIndex<T, Metadata>\n{\n constructor(\n private readonly model: EmbeddingModel,\n private readonly client: QdrantClientLike,\n private readonly collectionName: string,\n ) {}\n\n async search(request: VectorSearchRequest): Promise<Array<VectorSearchResult<T, Metadata>>> {\n const queryEmbedding = await embedText(this.model, request.query);\n const response = await this.client.search(this.collectionName, {\n vector: queryEmbedding.vector,\n limit: request.topK,\n filter: filterToQdrantFilter(request.filter),\n with_payload: true,\n });\n return parseQueryResults<T, Metadata>(response, request.threshold);\n }\n\n async searchIds(request: VectorSearchRequest): Promise<Array<{ score: number; id: string }>> {\n return (await this.search(request)).map(({ score, id }) => ({ score, id }));\n }\n\n asTool(options: VectorSearchToolOptions): Tool<{ query: string; topK?: number }, unknown> {\n return createVectorSearchTool(this, options);\n }\n}\n\nexport function filterToQdrantFilter(filter: VectorFilter | undefined): unknown {\n if (filter === undefined) {\n return undefined;\n }\n\n switch (filter.type) {\n case \"eq\":\n return { must: [{ key: filter.key, match: { value: filter.value } }] };\n case \"gt\":\n return { must: [{ key: filter.key, range: { gt: filter.value } }] };\n case \"lt\":\n return { must: [{ key: filter.key, range: { lt: filter.value } }] };\n case \"and\":\n return { must: filter.filters.map(filterToQdrantFilter) };\n case \"or\":\n return { should: filter.filters.map(filterToQdrantFilter) };\n }\n}\n\nasync function defaultQdrantClient(): Promise<QdrantClientLike> {\n const qdrant = await import(\"@qdrant/js-client-rest\");\n return new qdrant.QdrantClient({}) as QdrantClientLike;\n}\n\nfunction qdrantPoints<T, Metadata extends VectorMetadata>(\n document: EmbeddedDocument<T, Metadata>,\n): Array<{\n id: string;\n vector: number[];\n payload: Record<string, unknown>;\n}> {\n if (document.embeddings.length === 0) {\n throw new Error(`Document ${document.id} has no embeddings`);\n }\n assertNoReservedMetadata(document.metadata);\n\n return document.embeddings.map((embedding, index) => {\n const logicalId =\n document.embeddings.length === 1 ? document.id : `${document.id}#embedding:${index}`;\n return {\n id: pointId(logicalId),\n vector: embedding.vector,\n payload: {\n [documentIdPayloadKey]: document.id,\n [documentPayloadKey]: serializeDocument(document.document),\n ...(document.metadata ?? {}),\n },\n };\n });\n}\n\nfunction assertNoReservedMetadata(metadata: VectorMetadata | undefined): void {\n for (const key of Object.keys(metadata ?? {})) {\n if (key.startsWith(reservedPayloadPrefix)) {\n throw new Error(`Metadata key ${key} is reserved for Anvia Qdrant payloads`);\n }\n }\n}\n\nfunction pointId(id: string): string {\n const hex = createHash(\"sha256\").update(id).digest(\"hex\").slice(0, 32);\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(\n 16,\n 20,\n )}-${hex.slice(20)}`;\n}\n\nfunction serializeDocument(document: unknown): string {\n return typeof document === \"string\" ? document : JSON.stringify(document);\n}\n\nfunction parseQueryResults<T, Metadata extends VectorMetadata>(\n response: unknown,\n threshold: number | undefined,\n): Array<VectorSearchResult<T, Metadata>> {\n const points = rawPoints(response);\n const byId = new Map<string, VectorSearchResult<T, Metadata>>();\n\n for (const point of points) {\n if (threshold !== undefined && point.score < threshold) {\n continue;\n }\n\n const id = String(point.payload?.[documentIdPayloadKey] ?? point.id);\n const result = {\n id,\n score: point.score,\n document: parseDocument(point.payload?.[documentPayloadKey]),\n ...metadataFromPayload<Metadata>(point.payload),\n } as VectorSearchResult<T, Metadata>;\n const current = byId.get(id);\n if (current === undefined || result.score > current.score) {\n byId.set(id, result);\n }\n }\n\n return [...byId.values()];\n}\n\nfunction rawPoints(response: unknown): Array<{\n id: string | number;\n score: number;\n payload?: Record<string, unknown> | null;\n}> {\n const raw = response as {\n points?: Array<{\n id: string | number;\n score?: number;\n payload?: Record<string, unknown> | null;\n }>;\n result?:\n | {\n points?: Array<{\n id: string | number;\n score?: number;\n payload?: Record<string, unknown> | null;\n }>;\n }\n | Array<{ id: string | number; score?: number; payload?: Record<string, unknown> | null }>;\n };\n const responseArray = Array.isArray(response)\n ? (response as Array<{\n id: string | number;\n score?: number;\n payload?: Record<string, unknown> | null;\n }>)\n : undefined;\n const points =\n responseArray ??\n (Array.isArray(raw.result)\n ? raw.result\n : Array.isArray(raw.result?.points)\n ? raw.result.points\n : raw.points);\n return (points ?? []).map((point) => ({\n id: point.id,\n score: point.score ?? 0,\n ...(point.payload === undefined ? {} : { payload: point.payload }),\n }));\n}\n\nfunction parseDocument<T>(document: unknown): T {\n if (document === null || document === undefined) {\n return \"\" as T;\n }\n if (typeof document !== \"string\") {\n return document as T;\n }\n try {\n return JSON.parse(document) as T;\n } catch {\n return document as T;\n }\n}\n\nfunction metadataFromPayload<Metadata extends VectorMetadata>(\n payload: Record<string, unknown> | null | undefined,\n): { metadata?: Metadata | undefined } {\n const metadata = Object.fromEntries(\n Object.entries(payload ?? {}).filter(([key]) => !key.startsWith(reservedPayloadPrefix)),\n ) as Metadata;\n return Object.keys(metadata).length === 0 ? {} : { metadata };\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@anvia/qdrant",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Qdrant vector store adapter for Anvia.",
|
|
5
5
|
"author": "anvia",
|
|
6
6
|
"maintainer": "Indra Zulfi",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"@qdrant/js-client-rest": "^1.18.0",
|
|
30
|
-
"@anvia/core": "0.
|
|
30
|
+
"@anvia/core": "0.4.0"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"@types/node": "^24.9.1",
|