@tachu/extensions 1.0.0-beta.1
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/CHANGELOG.md +77 -0
- package/LICENSE +201 -0
- package/README.md +825 -0
- package/README_ZH.md +815 -0
- package/dist/backends/file.d.ts +18 -0
- package/dist/backends/file.d.ts.map +1 -0
- package/dist/backends/file.js +69 -0
- package/dist/backends/file.js.map +1 -0
- package/dist/backends/index.d.ts +4 -0
- package/dist/backends/index.d.ts.map +1 -0
- package/dist/backends/index.js +4 -0
- package/dist/backends/index.js.map +1 -0
- package/dist/backends/terminal.d.ts +18 -0
- package/dist/backends/terminal.d.ts.map +1 -0
- package/dist/backends/terminal.js +57 -0
- package/dist/backends/terminal.js.map +1 -0
- package/dist/backends/web.d.ts +18 -0
- package/dist/backends/web.d.ts.map +1 -0
- package/dist/backends/web.js +53 -0
- package/dist/backends/web.js.map +1 -0
- package/dist/common/net.d.ts +31 -0
- package/dist/common/net.d.ts.map +1 -0
- package/dist/common/net.js +162 -0
- package/dist/common/net.js.map +1 -0
- package/dist/common/path.d.ts +18 -0
- package/dist/common/path.d.ts.map +1 -0
- package/dist/common/path.js +34 -0
- package/dist/common/path.js.map +1 -0
- package/dist/common/process.d.ts +19 -0
- package/dist/common/process.d.ts.map +1 -0
- package/dist/common/process.js +67 -0
- package/dist/common/process.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/index.d.ts +3 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +3 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/sse-adapter.d.ts +70 -0
- package/dist/mcp/sse-adapter.d.ts.map +1 -0
- package/dist/mcp/sse-adapter.js +176 -0
- package/dist/mcp/sse-adapter.js.map +1 -0
- package/dist/mcp/stdio-adapter.d.ts +73 -0
- package/dist/mcp/stdio-adapter.d.ts.map +1 -0
- package/dist/mcp/stdio-adapter.js +178 -0
- package/dist/mcp/stdio-adapter.js.map +1 -0
- package/dist/observability/index.d.ts +3 -0
- package/dist/observability/index.d.ts.map +1 -0
- package/dist/observability/index.js +3 -0
- package/dist/observability/index.js.map +1 -0
- package/dist/observability/jsonl-emitter.d.ts +58 -0
- package/dist/observability/jsonl-emitter.d.ts.map +1 -0
- package/dist/observability/jsonl-emitter.js +96 -0
- package/dist/observability/jsonl-emitter.js.map +1 -0
- package/dist/observability/otel-emitter.d.ts +52 -0
- package/dist/observability/otel-emitter.d.ts.map +1 -0
- package/dist/observability/otel-emitter.js +143 -0
- package/dist/observability/otel-emitter.js.map +1 -0
- package/dist/providers/anthropic.d.ts +54 -0
- package/dist/providers/anthropic.d.ts.map +1 -0
- package/dist/providers/anthropic.js +298 -0
- package/dist/providers/anthropic.js.map +1 -0
- package/dist/providers/index.d.ts +4 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +4 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/mock.d.ts +38 -0
- package/dist/providers/mock.d.ts.map +1 -0
- package/dist/providers/mock.js +79 -0
- package/dist/providers/mock.js.map +1 -0
- package/dist/providers/openai.d.ts +61 -0
- package/dist/providers/openai.d.ts.map +1 -0
- package/dist/providers/openai.js +299 -0
- package/dist/providers/openai.js.map +1 -0
- package/dist/rules/index.d.ts +9 -0
- package/dist/rules/index.d.ts.map +1 -0
- package/dist/rules/index.js +15 -0
- package/dist/rules/index.js.map +1 -0
- package/dist/rules/no-hallucination.md +11 -0
- package/dist/rules/no-sensitive-output.md +11 -0
- package/dist/rules/prefer-concise-response.md +11 -0
- package/dist/rules/require-tool-verification.md +11 -0
- package/dist/tools/apply-patch/descriptor.md +27 -0
- package/dist/tools/apply-patch/executor.d.ts +19 -0
- package/dist/tools/apply-patch/executor.d.ts.map +1 -0
- package/dist/tools/apply-patch/executor.js +190 -0
- package/dist/tools/apply-patch/executor.js.map +1 -0
- package/dist/tools/fetch-url/descriptor.md +38 -0
- package/dist/tools/fetch-url/executor.d.ts +20 -0
- package/dist/tools/fetch-url/executor.d.ts.map +1 -0
- package/dist/tools/fetch-url/executor.js +34 -0
- package/dist/tools/fetch-url/executor.js.map +1 -0
- package/dist/tools/index.d.ts +12 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +191 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/list-dir/descriptor.md +29 -0
- package/dist/tools/list-dir/executor.d.ts +22 -0
- package/dist/tools/list-dir/executor.d.ts.map +1 -0
- package/dist/tools/list-dir/executor.js +46 -0
- package/dist/tools/list-dir/executor.js.map +1 -0
- package/dist/tools/read-file/descriptor.md +28 -0
- package/dist/tools/read-file/executor.d.ts +15 -0
- package/dist/tools/read-file/executor.d.ts.map +1 -0
- package/dist/tools/read-file/executor.js +22 -0
- package/dist/tools/read-file/executor.js.map +1 -0
- package/dist/tools/run-shell/descriptor.md +39 -0
- package/dist/tools/run-shell/executor.d.ts +20 -0
- package/dist/tools/run-shell/executor.d.ts.map +1 -0
- package/dist/tools/run-shell/executor.js +76 -0
- package/dist/tools/run-shell/executor.js.map +1 -0
- package/dist/tools/search-code/descriptor.md +31 -0
- package/dist/tools/search-code/executor.d.ts +23 -0
- package/dist/tools/search-code/executor.d.ts.map +1 -0
- package/dist/tools/search-code/executor.js +113 -0
- package/dist/tools/search-code/executor.js.map +1 -0
- package/dist/tools/shared.d.ts +21 -0
- package/dist/tools/shared.d.ts.map +1 -0
- package/dist/tools/shared.js +12 -0
- package/dist/tools/shared.js.map +1 -0
- package/dist/tools/write-file/descriptor.md +30 -0
- package/dist/tools/write-file/executor.d.ts +16 -0
- package/dist/tools/write-file/executor.d.ts.map +1 -0
- package/dist/tools/write-file/executor.js +18 -0
- package/dist/tools/write-file/executor.js.map +1 -0
- package/dist/transformers/document-to-text.d.ts +23 -0
- package/dist/transformers/document-to-text.d.ts.map +1 -0
- package/dist/transformers/document-to-text.js +69 -0
- package/dist/transformers/document-to-text.js.map +1 -0
- package/dist/transformers/image-to-text.d.ts +38 -0
- package/dist/transformers/image-to-text.d.ts.map +1 -0
- package/dist/transformers/image-to-text.js +81 -0
- package/dist/transformers/image-to-text.js.map +1 -0
- package/dist/transformers/index.d.ts +3 -0
- package/dist/transformers/index.d.ts.map +1 -0
- package/dist/transformers/index.js +3 -0
- package/dist/transformers/index.js.map +1 -0
- package/dist/vector/index.d.ts +3 -0
- package/dist/vector/index.d.ts.map +1 -0
- package/dist/vector/index.js +3 -0
- package/dist/vector/index.js.map +1 -0
- package/dist/vector/local-fs.d.ts +76 -0
- package/dist/vector/local-fs.d.ts.map +1 -0
- package/dist/vector/local-fs.js +153 -0
- package/dist/vector/local-fs.js.map +1 -0
- package/dist/vector/qdrant.d.ts +65 -0
- package/dist/vector/qdrant.d.ts.map +1 -0
- package/dist/vector/qdrant.js +176 -0
- package/dist/vector/qdrant.js.map +1 -0
- package/package.json +74 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { InputEnvelope, InputMetadata, InputTransformer, ModelCapabilities, ProviderAdapter } from "@tachu/core";
|
|
2
|
+
interface ImageToTextTransformerOptions {
|
|
3
|
+
provider: ProviderAdapter;
|
|
4
|
+
model?: string;
|
|
5
|
+
promptTemplate?: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* 图像转文本转换器(基于 Provider Vision 能力)。
|
|
9
|
+
*/
|
|
10
|
+
export declare class ImageToTextTransformer implements InputTransformer {
|
|
11
|
+
readonly modality = "image";
|
|
12
|
+
private readonly provider;
|
|
13
|
+
private readonly model;
|
|
14
|
+
private readonly promptTemplate;
|
|
15
|
+
/**
|
|
16
|
+
* 创建图像转换器。
|
|
17
|
+
*
|
|
18
|
+
* @param options 配置项
|
|
19
|
+
*/
|
|
20
|
+
constructor(options: ImageToTextTransformerOptions);
|
|
21
|
+
/**
|
|
22
|
+
* 判断是否需要执行降级转换。
|
|
23
|
+
*
|
|
24
|
+
* @param metadata 输入元信息
|
|
25
|
+
* @param modelCapabilities 模型能力
|
|
26
|
+
* @returns true 表示需要转换
|
|
27
|
+
*/
|
|
28
|
+
canHandle(metadata: InputMetadata, modelCapabilities: ModelCapabilities): boolean;
|
|
29
|
+
/**
|
|
30
|
+
* 将图像输入转换为文本信封。
|
|
31
|
+
*
|
|
32
|
+
* @param envelope 输入信封
|
|
33
|
+
* @returns 转换后的文本信封
|
|
34
|
+
*/
|
|
35
|
+
transform(envelope: InputEnvelope): Promise<InputEnvelope>;
|
|
36
|
+
}
|
|
37
|
+
export {};
|
|
38
|
+
//# sourceMappingURL=image-to-text.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image-to-text.d.ts","sourceRoot":"","sources":["../../src/transformers/image-to-text.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,aAAa,EACb,aAAa,EACb,gBAAgB,EAChB,iBAAiB,EACjB,eAAe,EAChB,MAAM,aAAa,CAAC;AAGrB,UAAU,6BAA6B;IACrC,QAAQ,EAAE,eAAe,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAUD;;GAEG;AACH,qBAAa,sBAAuB,YAAW,gBAAgB;IAC7D,QAAQ,CAAC,QAAQ,WAAW;IAE5B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAkB;IAC3C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IAExC;;;;OAIG;gBACS,OAAO,EAAE,6BAA6B;IAMlD;;;;;;OAMG;IACH,SAAS,CAAC,QAAQ,EAAE,aAAa,EAAE,iBAAiB,EAAE,iBAAiB,GAAG,OAAO;IAOjF;;;;;OAKG;IACG,SAAS,CAAC,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC;CA2CjE"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { ProviderError } from "@tachu/core";
|
|
2
|
+
const DEFAULT_PROMPT = "请描述图片的主要内容、关键信息和可见文本。";
|
|
3
|
+
/**
|
|
4
|
+
* 图像转文本转换器(基于 Provider Vision 能力)。
|
|
5
|
+
*/
|
|
6
|
+
export class ImageToTextTransformer {
|
|
7
|
+
modality = "image";
|
|
8
|
+
provider;
|
|
9
|
+
model;
|
|
10
|
+
promptTemplate;
|
|
11
|
+
/**
|
|
12
|
+
* 创建图像转换器。
|
|
13
|
+
*
|
|
14
|
+
* @param options 配置项
|
|
15
|
+
*/
|
|
16
|
+
constructor(options) {
|
|
17
|
+
this.provider = options.provider;
|
|
18
|
+
this.model = options.model ?? "gpt-4o";
|
|
19
|
+
this.promptTemplate = options.promptTemplate ?? DEFAULT_PROMPT;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* 判断是否需要执行降级转换。
|
|
23
|
+
*
|
|
24
|
+
* @param metadata 输入元信息
|
|
25
|
+
* @param modelCapabilities 模型能力
|
|
26
|
+
* @returns true 表示需要转换
|
|
27
|
+
*/
|
|
28
|
+
canHandle(metadata, modelCapabilities) {
|
|
29
|
+
return (metadata.modality === "image" &&
|
|
30
|
+
!modelCapabilities.supportedModalities.includes("image"));
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* 将图像输入转换为文本信封。
|
|
34
|
+
*
|
|
35
|
+
* @param envelope 输入信封
|
|
36
|
+
* @returns 转换后的文本信封
|
|
37
|
+
*/
|
|
38
|
+
async transform(envelope) {
|
|
39
|
+
const content = envelope.content;
|
|
40
|
+
const imageUrl = content.imageUrl ??
|
|
41
|
+
(content.imageBase64
|
|
42
|
+
? `data:${content.mimeType ?? "image/png"};base64,${content.imageBase64}`
|
|
43
|
+
: undefined);
|
|
44
|
+
if (!imageUrl) {
|
|
45
|
+
throw new ProviderError("PROVIDER_INVALID_INPUT", "缺少 imageUrl 或 imageBase64");
|
|
46
|
+
}
|
|
47
|
+
try {
|
|
48
|
+
const request = {
|
|
49
|
+
model: this.model,
|
|
50
|
+
messages: [
|
|
51
|
+
{
|
|
52
|
+
role: "user",
|
|
53
|
+
content: [
|
|
54
|
+
{ type: "text", text: this.promptTemplate },
|
|
55
|
+
{ type: "image_url", image_url: { url: imageUrl } },
|
|
56
|
+
],
|
|
57
|
+
},
|
|
58
|
+
],
|
|
59
|
+
};
|
|
60
|
+
const response = await this.provider.chat(request);
|
|
61
|
+
return {
|
|
62
|
+
content: response.content,
|
|
63
|
+
metadata: {
|
|
64
|
+
...envelope.metadata,
|
|
65
|
+
modality: "text",
|
|
66
|
+
mimeType: "text/plain",
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
if (error instanceof ProviderError) {
|
|
72
|
+
throw error;
|
|
73
|
+
}
|
|
74
|
+
throw new ProviderError("PROVIDER_UPSTREAM_ERROR", "图像转文本失败", {
|
|
75
|
+
cause: error,
|
|
76
|
+
retryable: true,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=image-to-text.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image-to-text.js","sourceRoot":"","sources":["../../src/transformers/image-to-text.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAc5C,MAAM,cAAc,GAAG,uBAAuB,CAAC;AAE/C;;GAEG;AACH,MAAM,OAAO,sBAAsB;IACxB,QAAQ,GAAG,OAAO,CAAC;IAEX,QAAQ,CAAkB;IAC1B,KAAK,CAAS;IACd,cAAc,CAAS;IAExC;;;;OAIG;IACH,YAAY,OAAsC;QAChD,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;QACjC,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,QAAQ,CAAC;QACvC,IAAI,CAAC,cAAc,GAAG,OAAO,CAAC,cAAc,IAAI,cAAc,CAAC;IACjE,CAAC;IAED;;;;;;OAMG;IACH,SAAS,CAAC,QAAuB,EAAE,iBAAoC;QACrE,OAAO,CACL,QAAQ,CAAC,QAAQ,KAAK,OAAO;YAC7B,CAAC,iBAAiB,CAAC,mBAAmB,CAAC,QAAQ,CAAC,OAAO,CAAC,CACzD,CAAC;IACJ,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,SAAS,CAAC,QAAuB;QACrC,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAuB,CAAC;QACjD,MAAM,QAAQ,GACZ,OAAO,CAAC,QAAQ;YAChB,CAAC,OAAO,CAAC,WAAW;gBAClB,CAAC,CAAC,QAAQ,OAAO,CAAC,QAAQ,IAAI,WAAW,WAAW,OAAO,CAAC,WAAW,EAAE;gBACzE,CAAC,CAAC,SAAS,CAAC,CAAC;QACjB,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,IAAI,aAAa,CAAC,wBAAwB,EAAE,2BAA2B,CAAC,CAAC;QACjF,CAAC;QAED,IAAI,CAAC;YACH,MAAM,OAAO,GAAG;gBACd,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,QAAQ,EAAE;oBACR;wBACE,IAAI,EAAE,MAAM;wBACZ,OAAO,EAAE;4BACP,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,cAAc,EAAE;4BAC3C,EAAE,IAAI,EAAE,WAAW,EAAE,SAAS,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,EAAE;yBACpD;qBACF;iBACF;aACwB,CAAC;YAC5B,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACnD,OAAO;gBACL,OAAO,EAAE,QAAQ,CAAC,OAAO;gBACzB,QAAQ,EAAE;oBACR,GAAG,QAAQ,CAAC,QAAQ;oBACpB,QAAQ,EAAE,MAAM;oBAChB,QAAQ,EAAE,YAAY;iBACvB;aACF,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,KAAK,YAAY,aAAa,EAAE,CAAC;gBACnC,MAAM,KAAK,CAAC;YACd,CAAC;YACD,MAAM,IAAI,aAAa,CAAC,yBAAyB,EAAE,SAAS,EAAE;gBAC5D,KAAK,EAAE,KAAK;gBACZ,SAAS,EAAE,IAAI;aAChB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/transformers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/transformers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/vector/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/vector/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { type VectorSearchResult, type VectorStore } from "@tachu/core";
|
|
2
|
+
interface LocalFsVectorStoreOptions {
|
|
3
|
+
filePath?: string;
|
|
4
|
+
persistDebounceMs?: number;
|
|
5
|
+
indexLimit?: number;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* 本地文件持久化 VectorStore(基于 InMemoryVectorStore)。
|
|
9
|
+
*/
|
|
10
|
+
export declare class LocalFsVectorStore implements VectorStore {
|
|
11
|
+
private readonly filePath;
|
|
12
|
+
private readonly lockPath;
|
|
13
|
+
private readonly persistDebounceMs;
|
|
14
|
+
private readonly store;
|
|
15
|
+
private readonly entries;
|
|
16
|
+
private readonly initPromise;
|
|
17
|
+
private persistTimer;
|
|
18
|
+
private persisting;
|
|
19
|
+
/**
|
|
20
|
+
* 创建本地向量存储。
|
|
21
|
+
*
|
|
22
|
+
* @param options 配置项
|
|
23
|
+
*/
|
|
24
|
+
constructor(options?: LocalFsVectorStoreOptions);
|
|
25
|
+
/**
|
|
26
|
+
* 文本向量化。
|
|
27
|
+
*
|
|
28
|
+
* @param texts 文本列表
|
|
29
|
+
* @returns 向量列表
|
|
30
|
+
*/
|
|
31
|
+
embed(texts: string[]): Promise<number[][]>;
|
|
32
|
+
/**
|
|
33
|
+
* 写入或更新向量条目。
|
|
34
|
+
*
|
|
35
|
+
* @param id 条目 ID
|
|
36
|
+
* @param vectorOrText 向量或文本
|
|
37
|
+
* @param metadata 元数据
|
|
38
|
+
*/
|
|
39
|
+
upsert(id: string, vectorOrText: number[] | string, metadata: Record<string, unknown>): Promise<void>;
|
|
40
|
+
/**
|
|
41
|
+
* 相似度检索。
|
|
42
|
+
*
|
|
43
|
+
* @param query 查询向量或文本
|
|
44
|
+
* @param topK 返回数量
|
|
45
|
+
* @returns 检索结果
|
|
46
|
+
*/
|
|
47
|
+
search(query: number[] | string, topK: number): Promise<VectorSearchResult[]>;
|
|
48
|
+
/**
|
|
49
|
+
* 删除条目。
|
|
50
|
+
*
|
|
51
|
+
* @param id 条目 ID
|
|
52
|
+
*/
|
|
53
|
+
delete(id: string): Promise<void>;
|
|
54
|
+
/**
|
|
55
|
+
* 清空向量库。
|
|
56
|
+
*/
|
|
57
|
+
clear(): Promise<void>;
|
|
58
|
+
/**
|
|
59
|
+
* 返回当前条目数。
|
|
60
|
+
*
|
|
61
|
+
* @returns 条目数量
|
|
62
|
+
*/
|
|
63
|
+
size(): number;
|
|
64
|
+
/**
|
|
65
|
+
* 手动导出快照文件。
|
|
66
|
+
*
|
|
67
|
+
* @param path 快照路径
|
|
68
|
+
*/
|
|
69
|
+
snapshot(path: string): Promise<void>;
|
|
70
|
+
private schedulePersist;
|
|
71
|
+
private loadFromDisk;
|
|
72
|
+
private acquireLock;
|
|
73
|
+
private persistToDisk;
|
|
74
|
+
}
|
|
75
|
+
export {};
|
|
76
|
+
//# sourceMappingURL=local-fs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-fs.d.ts","sourceRoot":"","sources":["../../src/vector/local-fs.ts"],"names":[],"mappings":"AAEA,OAAO,EAAuB,KAAK,kBAAkB,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAE7F,UAAU,yBAAyB;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAYD;;GAEG;AACH,qBAAa,kBAAmB,YAAW,WAAW;IACpD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAS;IAC3C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAsB;IAC5C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqC;IAC7D,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAgB;IAC5C,OAAO,CAAC,YAAY,CAA4C;IAChE,OAAO,CAAC,UAAU,CAAqB;IAEvC;;;;OAIG;gBACS,OAAO,GAAE,yBAA8B;IAUnD;;;;;OAKG;IACG,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;IAKjD;;;;;;OAMG;IACG,MAAM,CACV,EAAE,EAAE,MAAM,EACV,YAAY,EAAE,MAAM,EAAE,GAAG,MAAM,EAC/B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,OAAO,CAAC,IAAI,CAAC;IAShB;;;;;;OAMG;IACG,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC;IAKnF;;;;OAIG;IACG,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOvC;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAO5B;;;;OAIG;IACH,IAAI,IAAI,MAAM;IAId;;;;OAIG;IACG,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAO3C,OAAO,CAAC,eAAe;YAST,YAAY;YAYZ,WAAW;YAgBX,aAAa;CAY5B"}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { mkdir, open, readFile, rename, rm, writeFile } from "node:fs/promises";
|
|
2
|
+
import { dirname } from "node:path";
|
|
3
|
+
import { InMemoryVectorStore } from "@tachu/core";
|
|
4
|
+
/**
|
|
5
|
+
* 本地文件持久化 VectorStore(基于 InMemoryVectorStore)。
|
|
6
|
+
*/
|
|
7
|
+
export class LocalFsVectorStore {
|
|
8
|
+
filePath;
|
|
9
|
+
lockPath;
|
|
10
|
+
persistDebounceMs;
|
|
11
|
+
store;
|
|
12
|
+
entries = new Map();
|
|
13
|
+
initPromise;
|
|
14
|
+
persistTimer;
|
|
15
|
+
persisting = Promise.resolve();
|
|
16
|
+
/**
|
|
17
|
+
* 创建本地向量存储。
|
|
18
|
+
*
|
|
19
|
+
* @param options 配置项
|
|
20
|
+
*/
|
|
21
|
+
constructor(options = {}) {
|
|
22
|
+
this.filePath = options.filePath ?? ".tachu/vectors.json";
|
|
23
|
+
this.lockPath = `${this.filePath}.lock`;
|
|
24
|
+
this.persistDebounceMs = options.persistDebounceMs ?? 500;
|
|
25
|
+
this.store = new InMemoryVectorStore({
|
|
26
|
+
...(options.indexLimit !== undefined ? { indexLimit: options.indexLimit } : {}),
|
|
27
|
+
});
|
|
28
|
+
this.initPromise = this.loadFromDisk();
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* 文本向量化。
|
|
32
|
+
*
|
|
33
|
+
* @param texts 文本列表
|
|
34
|
+
* @returns 向量列表
|
|
35
|
+
*/
|
|
36
|
+
async embed(texts) {
|
|
37
|
+
await this.initPromise;
|
|
38
|
+
return this.store.embed(texts);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* 写入或更新向量条目。
|
|
42
|
+
*
|
|
43
|
+
* @param id 条目 ID
|
|
44
|
+
* @param vectorOrText 向量或文本
|
|
45
|
+
* @param metadata 元数据
|
|
46
|
+
*/
|
|
47
|
+
async upsert(id, vectorOrText, metadata) {
|
|
48
|
+
await this.initPromise;
|
|
49
|
+
const vector = typeof vectorOrText === "string" ? (await this.store.embed([vectorOrText]))[0] ?? [] : vectorOrText;
|
|
50
|
+
await this.store.upsert(id, vector, metadata);
|
|
51
|
+
this.entries.set(id, { id, vector, metadata });
|
|
52
|
+
this.schedulePersist();
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* 相似度检索。
|
|
56
|
+
*
|
|
57
|
+
* @param query 查询向量或文本
|
|
58
|
+
* @param topK 返回数量
|
|
59
|
+
* @returns 检索结果
|
|
60
|
+
*/
|
|
61
|
+
async search(query, topK) {
|
|
62
|
+
await this.initPromise;
|
|
63
|
+
return this.store.search(query, topK);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* 删除条目。
|
|
67
|
+
*
|
|
68
|
+
* @param id 条目 ID
|
|
69
|
+
*/
|
|
70
|
+
async delete(id) {
|
|
71
|
+
await this.initPromise;
|
|
72
|
+
await this.store.delete(id);
|
|
73
|
+
this.entries.delete(id);
|
|
74
|
+
this.schedulePersist();
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* 清空向量库。
|
|
78
|
+
*/
|
|
79
|
+
async clear() {
|
|
80
|
+
await this.initPromise;
|
|
81
|
+
await this.store.clear();
|
|
82
|
+
this.entries.clear();
|
|
83
|
+
this.schedulePersist();
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* 返回当前条目数。
|
|
87
|
+
*
|
|
88
|
+
* @returns 条目数量
|
|
89
|
+
*/
|
|
90
|
+
size() {
|
|
91
|
+
return this.entries.size;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* 手动导出快照文件。
|
|
95
|
+
*
|
|
96
|
+
* @param path 快照路径
|
|
97
|
+
*/
|
|
98
|
+
async snapshot(path) {
|
|
99
|
+
await this.initPromise;
|
|
100
|
+
const payload = { entries: [...this.entries.values()] };
|
|
101
|
+
await mkdir(dirname(path), { recursive: true });
|
|
102
|
+
await writeFile(path, JSON.stringify(payload, null, 2), "utf8");
|
|
103
|
+
}
|
|
104
|
+
schedulePersist() {
|
|
105
|
+
if (this.persistTimer) {
|
|
106
|
+
clearTimeout(this.persistTimer);
|
|
107
|
+
}
|
|
108
|
+
this.persistTimer = setTimeout(() => {
|
|
109
|
+
this.persisting = this.persisting.then(() => this.persistToDisk());
|
|
110
|
+
}, this.persistDebounceMs);
|
|
111
|
+
}
|
|
112
|
+
async loadFromDisk() {
|
|
113
|
+
const raw = await readFile(this.filePath, "utf8").catch(() => "");
|
|
114
|
+
if (!raw) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
const payload = JSON.parse(raw);
|
|
118
|
+
for (const entry of payload.entries ?? []) {
|
|
119
|
+
await this.store.upsert(entry.id, entry.vector, entry.metadata);
|
|
120
|
+
this.entries.set(entry.id, entry);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
async acquireLock() {
|
|
124
|
+
for (let attempt = 0; attempt < 30; attempt += 1) {
|
|
125
|
+
try {
|
|
126
|
+
await mkdir(dirname(this.lockPath), { recursive: true });
|
|
127
|
+
const handle = await open(this.lockPath, "wx");
|
|
128
|
+
return async () => {
|
|
129
|
+
await handle.close().catch(() => undefined);
|
|
130
|
+
await rm(this.lockPath, { force: true }).catch(() => undefined);
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
await new Promise((resolve) => setTimeout(resolve, 50 * (attempt + 1)));
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
throw new Error(`无法获取文件锁: ${this.lockPath}`);
|
|
138
|
+
}
|
|
139
|
+
async persistToDisk() {
|
|
140
|
+
const release = await this.acquireLock();
|
|
141
|
+
try {
|
|
142
|
+
await mkdir(dirname(this.filePath), { recursive: true });
|
|
143
|
+
const tempPath = `${this.filePath}.tmp`;
|
|
144
|
+
const payload = { entries: [...this.entries.values()] };
|
|
145
|
+
await writeFile(tempPath, JSON.stringify(payload), "utf8");
|
|
146
|
+
await rename(tempPath, this.filePath);
|
|
147
|
+
}
|
|
148
|
+
finally {
|
|
149
|
+
await release();
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
//# sourceMappingURL=local-fs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-fs.js","sourceRoot":"","sources":["../../src/vector/local-fs.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { type VectorSearchResult, type VectorStore } from "@tachu/core";
|
|
2
|
+
interface QdrantVectorStoreOptions {
|
|
3
|
+
url: string;
|
|
4
|
+
apiKey?: string;
|
|
5
|
+
collectionName: string;
|
|
6
|
+
vectorSize?: number;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Qdrant 远程向量存储适配器。
|
|
10
|
+
*/
|
|
11
|
+
export declare class QdrantVectorStore implements VectorStore {
|
|
12
|
+
private readonly client;
|
|
13
|
+
private readonly collectionName;
|
|
14
|
+
private readonly vectorSize;
|
|
15
|
+
private ensured;
|
|
16
|
+
private entryCount;
|
|
17
|
+
/**
|
|
18
|
+
* 创建 Qdrant 向量存储。
|
|
19
|
+
*
|
|
20
|
+
* @param options Qdrant 连接配置
|
|
21
|
+
*/
|
|
22
|
+
constructor(options: QdrantVectorStoreOptions);
|
|
23
|
+
/**
|
|
24
|
+
* 文本向量化(本地哈希嵌入)。
|
|
25
|
+
*
|
|
26
|
+
* @param texts 文本数组
|
|
27
|
+
* @returns 向量数组
|
|
28
|
+
*/
|
|
29
|
+
embed(texts: string[]): Promise<number[][]>;
|
|
30
|
+
/**
|
|
31
|
+
* 写入或更新向量。
|
|
32
|
+
*
|
|
33
|
+
* @param id 条目 ID
|
|
34
|
+
* @param vectorOrText 向量或文本
|
|
35
|
+
* @param metadata 元数据
|
|
36
|
+
*/
|
|
37
|
+
upsert(id: string, vectorOrText: number[] | string, metadata: Record<string, unknown>): Promise<void>;
|
|
38
|
+
/**
|
|
39
|
+
* 相似度搜索。
|
|
40
|
+
*
|
|
41
|
+
* @param query 查询向量或文本
|
|
42
|
+
* @param topK 结果数量
|
|
43
|
+
* @returns 搜索结果
|
|
44
|
+
*/
|
|
45
|
+
search(query: number[] | string, topK: number): Promise<VectorSearchResult[]>;
|
|
46
|
+
/**
|
|
47
|
+
* 删除条目。
|
|
48
|
+
*
|
|
49
|
+
* @param id 条目 ID
|
|
50
|
+
*/
|
|
51
|
+
delete(id: string): Promise<void>;
|
|
52
|
+
/**
|
|
53
|
+
* 清空集合。
|
|
54
|
+
*/
|
|
55
|
+
clear(): Promise<void>;
|
|
56
|
+
/**
|
|
57
|
+
* 返回估算条目数量。
|
|
58
|
+
*
|
|
59
|
+
* @returns 条目数
|
|
60
|
+
*/
|
|
61
|
+
size(): number;
|
|
62
|
+
private ensureCollection;
|
|
63
|
+
}
|
|
64
|
+
export {};
|
|
65
|
+
//# sourceMappingURL=qdrant.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"qdrant.d.ts","sourceRoot":"","sources":["../../src/vector/qdrant.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,kBAAkB,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAGvF,UAAU,wBAAwB;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAgCD;;GAEG;AACH,qBAAa,iBAAkB,YAAW,WAAW;IACnD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAe;IACtC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,UAAU,CAAK;IAEvB;;;;OAIG;gBACS,OAAO,EAAE,wBAAwB;IAS7C;;;;;OAKG;IACG,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;IAIjD;;;;;;OAMG;IACG,MAAM,CACV,EAAE,EAAE,MAAM,EACV,YAAY,EAAE,MAAM,EAAE,GAAG,MAAM,EAC/B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,OAAO,CAAC,IAAI,CAAC;IAkBhB;;;;;;OAMG;IACG,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC;IAsBnF;;;;OAIG;IACG,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAavC;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAiB5B;;;;OAIG;IACH,IAAI,IAAI,MAAM;YAIA,gBAAgB;CAe/B"}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { ProviderError } from "@tachu/core";
|
|
2
|
+
import { QdrantClient } from "@qdrant/js-client-rest";
|
|
3
|
+
const DEFAULT_VECTOR_SIZE = 256;
|
|
4
|
+
const hashToken = (token, size) => {
|
|
5
|
+
let hash = 0;
|
|
6
|
+
for (let index = 0; index < token.length; index += 1) {
|
|
7
|
+
hash = (hash * 31 + token.charCodeAt(index)) >>> 0;
|
|
8
|
+
}
|
|
9
|
+
return hash % size;
|
|
10
|
+
};
|
|
11
|
+
const embedText = (text, size) => {
|
|
12
|
+
const vector = new Array(size).fill(0);
|
|
13
|
+
const tokens = text
|
|
14
|
+
.toLowerCase()
|
|
15
|
+
.split(/[^a-z0-9\u4e00-\u9fa5]+/u)
|
|
16
|
+
.filter((token) => token.length > 0);
|
|
17
|
+
if (tokens.length === 0) {
|
|
18
|
+
return vector;
|
|
19
|
+
}
|
|
20
|
+
for (const token of tokens) {
|
|
21
|
+
const idx = hashToken(token, size);
|
|
22
|
+
vector[idx] += 1;
|
|
23
|
+
}
|
|
24
|
+
const norm = Math.sqrt(vector.reduce((sum, value) => sum + value * value, 0));
|
|
25
|
+
if (norm === 0) {
|
|
26
|
+
return vector;
|
|
27
|
+
}
|
|
28
|
+
return vector.map((value) => value / norm);
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Qdrant 远程向量存储适配器。
|
|
32
|
+
*/
|
|
33
|
+
export class QdrantVectorStore {
|
|
34
|
+
client;
|
|
35
|
+
collectionName;
|
|
36
|
+
vectorSize;
|
|
37
|
+
ensured = false;
|
|
38
|
+
entryCount = 0;
|
|
39
|
+
/**
|
|
40
|
+
* 创建 Qdrant 向量存储。
|
|
41
|
+
*
|
|
42
|
+
* @param options Qdrant 连接配置
|
|
43
|
+
*/
|
|
44
|
+
constructor(options) {
|
|
45
|
+
this.client = new QdrantClient({
|
|
46
|
+
url: options.url,
|
|
47
|
+
...(options.apiKey ? { apiKey: options.apiKey } : {}),
|
|
48
|
+
});
|
|
49
|
+
this.collectionName = options.collectionName;
|
|
50
|
+
this.vectorSize = options.vectorSize ?? DEFAULT_VECTOR_SIZE;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* 文本向量化(本地哈希嵌入)。
|
|
54
|
+
*
|
|
55
|
+
* @param texts 文本数组
|
|
56
|
+
* @returns 向量数组
|
|
57
|
+
*/
|
|
58
|
+
async embed(texts) {
|
|
59
|
+
return texts.map((text) => embedText(text, this.vectorSize));
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* 写入或更新向量。
|
|
63
|
+
*
|
|
64
|
+
* @param id 条目 ID
|
|
65
|
+
* @param vectorOrText 向量或文本
|
|
66
|
+
* @param metadata 元数据
|
|
67
|
+
*/
|
|
68
|
+
async upsert(id, vectorOrText, metadata) {
|
|
69
|
+
try {
|
|
70
|
+
await this.ensureCollection();
|
|
71
|
+
const vector = typeof vectorOrText === "string" ? embedText(vectorOrText, this.vectorSize) : vectorOrText;
|
|
72
|
+
await this.client.upsert(this.collectionName, {
|
|
73
|
+
wait: true,
|
|
74
|
+
points: [{ id, vector, payload: metadata }],
|
|
75
|
+
});
|
|
76
|
+
this.entryCount += 1;
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
throw new ProviderError("PROVIDER_UPSTREAM_ERROR", "Qdrant upsert 失败", {
|
|
80
|
+
cause: error,
|
|
81
|
+
retryable: true,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* 相似度搜索。
|
|
87
|
+
*
|
|
88
|
+
* @param query 查询向量或文本
|
|
89
|
+
* @param topK 结果数量
|
|
90
|
+
* @returns 搜索结果
|
|
91
|
+
*/
|
|
92
|
+
async search(query, topK) {
|
|
93
|
+
try {
|
|
94
|
+
await this.ensureCollection();
|
|
95
|
+
const vector = typeof query === "string" ? embedText(query, this.vectorSize) : query;
|
|
96
|
+
const result = await this.client.search(this.collectionName, {
|
|
97
|
+
vector,
|
|
98
|
+
limit: topK,
|
|
99
|
+
with_payload: true,
|
|
100
|
+
});
|
|
101
|
+
return result.map((item) => ({
|
|
102
|
+
id: String(item.id),
|
|
103
|
+
score: item.score,
|
|
104
|
+
metadata: (item.payload ?? {}),
|
|
105
|
+
}));
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
throw new ProviderError("PROVIDER_UPSTREAM_ERROR", "Qdrant search 失败", {
|
|
109
|
+
cause: error,
|
|
110
|
+
retryable: true,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* 删除条目。
|
|
116
|
+
*
|
|
117
|
+
* @param id 条目 ID
|
|
118
|
+
*/
|
|
119
|
+
async delete(id) {
|
|
120
|
+
try {
|
|
121
|
+
await this.ensureCollection();
|
|
122
|
+
await this.client.delete(this.collectionName, { wait: true, points: [id] });
|
|
123
|
+
this.entryCount = Math.max(0, this.entryCount - 1);
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
throw new ProviderError("PROVIDER_UPSTREAM_ERROR", "Qdrant delete 失败", {
|
|
127
|
+
cause: error,
|
|
128
|
+
retryable: true,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* 清空集合。
|
|
134
|
+
*/
|
|
135
|
+
async clear() {
|
|
136
|
+
try {
|
|
137
|
+
const exists = await this.client.collectionExists(this.collectionName);
|
|
138
|
+
if (exists.exists) {
|
|
139
|
+
await this.client.deleteCollection(this.collectionName);
|
|
140
|
+
}
|
|
141
|
+
this.ensured = false;
|
|
142
|
+
this.entryCount = 0;
|
|
143
|
+
await this.ensureCollection();
|
|
144
|
+
}
|
|
145
|
+
catch (error) {
|
|
146
|
+
throw new ProviderError("PROVIDER_UPSTREAM_ERROR", "Qdrant clear 失败", {
|
|
147
|
+
cause: error,
|
|
148
|
+
retryable: true,
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* 返回估算条目数量。
|
|
154
|
+
*
|
|
155
|
+
* @returns 条目数
|
|
156
|
+
*/
|
|
157
|
+
size() {
|
|
158
|
+
return this.entryCount;
|
|
159
|
+
}
|
|
160
|
+
async ensureCollection() {
|
|
161
|
+
if (this.ensured) {
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
const exists = await this.client.collectionExists(this.collectionName);
|
|
165
|
+
if (!exists.exists) {
|
|
166
|
+
await this.client.createCollection(this.collectionName, {
|
|
167
|
+
vectors: {
|
|
168
|
+
size: this.vectorSize,
|
|
169
|
+
distance: "Cosine",
|
|
170
|
+
},
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
this.ensured = true;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
//# sourceMappingURL=qdrant.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"qdrant.js","sourceRoot":"","sources":["../../src/vector/qdrant.ts"],"names":[],"mappings":"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"}
|