@aliyunrds/ctxdb 1.0.1 → 1.0.3

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.
@@ -1,204 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- // src/lib/kb.ts
4
- import { readFileSync, existsSync, statSync } from "fs";
5
- import { basename, extname } from "path";
6
- import { homedir } from "os";
7
- import { resolve } from "path";
8
- import {
9
- buildNormalizedGraphContext,
10
- extractKnowledgeBaseIds,
11
- extractKnowledgeChunkContent,
12
- extractKnowledgeChunkSourceLabel,
13
- extractKnowledgeChunkTags,
14
- partitionKnowledgeChunks
15
- } from "@aliyunrds/ctxdb-shared";
16
- var KB_COLLECTION = "/v1/knowledge/knowledge_bases";
17
- var DOCUMENTS = "/v1/knowledge/documents";
18
- var FILES = "/v1/knowledge/files";
19
- var DOCUMENT_DETAIL = "/v1/knowledge/documents/detail";
20
- var DEFAULT_POLL_INTERVAL_MS = 1500;
21
- var DEFAULT_INGEST_TIMEOUT_MS = 3e4;
22
- var DEFAULT_FILE_INGEST_TIMEOUT_MS = 6e4;
23
- var MIME_BY_EXT = {
24
- ".pdf": "application/pdf",
25
- ".txt": "text/plain",
26
- ".md": "text/markdown",
27
- ".markdown": "text/markdown",
28
- ".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
29
- ".doc": "application/msword",
30
- ".html": "text/html",
31
- ".htm": "text/html",
32
- ".json": "application/json",
33
- ".csv": "text/csv",
34
- ".xml": "application/xml",
35
- ".rtf": "application/rtf"
36
- };
37
- async function listKnowledgeBases(client) {
38
- const resp = await client.get(KB_COLLECTION);
39
- if (Array.isArray(resp)) return resp;
40
- if (resp && typeof resp === "object") {
41
- const o = resp;
42
- return o.knowledge_bases ?? o.results ?? [];
43
- }
44
- return [];
45
- }
46
- async function createKb(client, kbName, description = "") {
47
- return client.postJson(KB_COLLECTION, { name: kbName, description: description || "" });
48
- }
49
- async function uploadText(client, kbName, docName, text, mimeType = "text/plain", filePath) {
50
- const body = {
51
- knowledge_base_name: kbName,
52
- name: docName,
53
- text,
54
- mime_type: mimeType
55
- };
56
- if (filePath !== void 0 && filePath !== "") body.file_path = filePath;
57
- return client.postJson(DOCUMENTS, body);
58
- }
59
- async function uploadFile(client, kbName, localPath, options = {}) {
60
- const MAX_UPLOAD_BYTES = 100 * 1024 * 1024;
61
- const expanded = expandHome(localPath);
62
- if (!existsSync(expanded)) throw new Error(`file not found: ${expanded}`);
63
- const stat = statSync(expanded);
64
- if (!stat.isFile()) throw new Error(`not a file: ${expanded}`);
65
- if (stat.size > MAX_UPLOAD_BYTES) {
66
- throw new Error(
67
- `file too large (${(stat.size / 1024 / 1024).toFixed(1)} MB), maximum is 100 MB`
68
- );
69
- }
70
- const filename = basename(expanded);
71
- const docName = options.docName ?? filename;
72
- const content = readFileSync(expanded);
73
- const mime = guessMime(expanded);
74
- const fields = {
75
- knowledge_base_name: kbName,
76
- name: docName
77
- };
78
- if (options.filePath !== void 0 && options.filePath !== "") {
79
- fields.file_path = options.filePath;
80
- }
81
- return client.postMultipart(
82
- FILES,
83
- fields,
84
- { file: { filename, content, mimeType: mime } },
85
- { timeoutMs: options.timeoutMs }
86
- );
87
- }
88
- function guessMime(path) {
89
- const ext = extname(path).toLowerCase();
90
- if (ext in MIME_BY_EXT) return MIME_BY_EXT[ext];
91
- return "application/octet-stream";
92
- }
93
- async function getDocument(client, kbName, docId) {
94
- return client.get(DOCUMENT_DETAIL, {
95
- knowledge_base_name: kbName,
96
- document_id: docId
97
- });
98
- }
99
- async function listDocuments(client, kbName) {
100
- const resp = await client.get(DOCUMENTS, { knowledge_base_name: kbName });
101
- if (Array.isArray(resp)) return resp;
102
- if (resp && typeof resp === "object") {
103
- const o = resp;
104
- return o.documents ?? o.results ?? [];
105
- }
106
- return [];
107
- }
108
- async function pollIngest(client, kbName, docId, options = {}) {
109
- const timeoutMs = options.timeoutMs ?? DEFAULT_INGEST_TIMEOUT_MS;
110
- const intervalMs = options.intervalMs ?? DEFAULT_POLL_INTERVAL_MS;
111
- const sleep = options.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
112
- const now = options.now ?? (() => performance.now());
113
- const deadline = now() + timeoutMs;
114
- let doc = await getDocument(client, kbName, docId);
115
- let timedOut = false;
116
- while (ingestInFlight(doc)) {
117
- if (now() >= deadline) {
118
- timedOut = true;
119
- break;
120
- }
121
- await sleep(intervalMs);
122
- try {
123
- doc = await getDocument(client, kbName, docId);
124
- } catch {
125
- break;
126
- }
127
- }
128
- if (doc && typeof doc === "object") {
129
- return { ...doc, _pollingTimedOut: timedOut };
130
- }
131
- return { _pollingTimedOut: timedOut };
132
- }
133
- function ingestInFlight(doc) {
134
- if (!doc || typeof doc !== "object") return false;
135
- const status = doc.ingest_status;
136
- return status === "processing" || status === "pending" || status === "in_progress";
137
- }
138
- function expandHome(p) {
139
- if (p.startsWith("~/") || p === "~") {
140
- return resolve(homedir(), p.slice(2));
141
- }
142
- return resolve(p);
143
- }
144
- function compactChunk(raw) {
145
- const c = raw ?? {};
146
- const content = extractKnowledgeChunkContent(raw);
147
- const doc_name = extractKnowledgeChunkSourceLabel(raw);
148
- const kb_id = extractKnowledgeBaseIds(raw)[0] ?? "";
149
- const docIdRaw = c.doc_id;
150
- const scoreRaw = c.similarity ?? c.rerank_score;
151
- const tags = extractKnowledgeChunkTags(raw);
152
- const out = {
153
- content,
154
- doc_name,
155
- kb_id,
156
- score: typeof scoreRaw === "number" ? scoreRaw : 0
157
- };
158
- if (typeof docIdRaw === "string" && docIdRaw.length > 0) {
159
- out.doc_id = docIdRaw;
160
- }
161
- if (tags.length > 0) {
162
- out.tags = tags;
163
- }
164
- return out;
165
- }
166
- function projectKbQueryResponse(raw, projectChunk, options = {}) {
167
- if (!raw || typeof raw !== "object") return { chunks: [] };
168
- const r = raw;
169
- const chunksIn = Array.isArray(r.chunks) ? r.chunks : [];
170
- const { graphChunks, documentChunks } = partitionKnowledgeChunks(chunksIn);
171
- const graphContext = buildNormalizedGraphContext(graphChunks, {
172
- verbose: options.verboseGraph
173
- });
174
- const out = {
175
- chunks: documentChunks.map(projectChunk)
176
- };
177
- if (typeof r.total === "number") out.total = r.total;
178
- if (graphContext) out.graph_context = graphContext;
179
- return out;
180
- }
181
- function compactKbQueryResponse(raw) {
182
- return projectKbQueryResponse(raw, compactChunk, { verboseGraph: true });
183
- }
184
- function minimalChunk(raw) {
185
- const c = compactChunk(raw);
186
- return { content: c.content, score: c.score };
187
- }
188
- function minimalKbQueryResponse(raw) {
189
- return projectKbQueryResponse(raw, minimalChunk);
190
- }
191
-
192
- export {
193
- DEFAULT_INGEST_TIMEOUT_MS,
194
- DEFAULT_FILE_INGEST_TIMEOUT_MS,
195
- listKnowledgeBases,
196
- createKb,
197
- uploadText,
198
- uploadFile,
199
- getDocument,
200
- listDocuments,
201
- pollIngest,
202
- compactKbQueryResponse,
203
- minimalKbQueryResponse
204
- };