yanmengs-rag-package 0.1.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/dist/index.d.mts +203 -0
- package/dist/index.d.ts +203 -0
- package/dist/index.js +427 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +402 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +41 -0
- package/readme.md +233 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var axios = require('axios');
|
|
4
|
+
var qiniu = require('qiniu-js');
|
|
5
|
+
|
|
6
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
7
|
+
|
|
8
|
+
function _interopNamespace(e) {
|
|
9
|
+
if (e && e.__esModule) return e;
|
|
10
|
+
var n = Object.create(null);
|
|
11
|
+
if (e) {
|
|
12
|
+
Object.keys(e).forEach(function (k) {
|
|
13
|
+
if (k !== 'default') {
|
|
14
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
15
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
16
|
+
enumerable: true,
|
|
17
|
+
get: function () { return e[k]; }
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
n.default = e;
|
|
23
|
+
return Object.freeze(n);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
var axios__default = /*#__PURE__*/_interopDefault(axios);
|
|
27
|
+
var qiniu__namespace = /*#__PURE__*/_interopNamespace(qiniu);
|
|
28
|
+
|
|
29
|
+
// src/client.ts
|
|
30
|
+
function createHttpClient(baseURL, appKey) {
|
|
31
|
+
const instance = axios__default.default.create({ baseURL });
|
|
32
|
+
instance.interceptors.request.use((config) => {
|
|
33
|
+
config.headers["app-key"] = appKey;
|
|
34
|
+
return config;
|
|
35
|
+
});
|
|
36
|
+
return instance;
|
|
37
|
+
}
|
|
38
|
+
var REGION_MAP = {
|
|
39
|
+
z0: qiniu__namespace.region.z0,
|
|
40
|
+
z1: qiniu__namespace.region.z1,
|
|
41
|
+
z2: qiniu__namespace.region.z2,
|
|
42
|
+
na0: qiniu__namespace.region.na0,
|
|
43
|
+
as0: qiniu__namespace.region.as0
|
|
44
|
+
};
|
|
45
|
+
function createQiniuModule() {
|
|
46
|
+
const uploadList = [];
|
|
47
|
+
async function resolveToken(token, getToken) {
|
|
48
|
+
if (token) return token;
|
|
49
|
+
if (getToken) return await getToken();
|
|
50
|
+
throw new Error("[yanmengs-rag] \u5FC5\u987B\u63D0\u4F9B token \u6216 getToken");
|
|
51
|
+
}
|
|
52
|
+
function upload2(options) {
|
|
53
|
+
const {
|
|
54
|
+
file,
|
|
55
|
+
key,
|
|
56
|
+
token,
|
|
57
|
+
getToken,
|
|
58
|
+
region: region2 = "z2",
|
|
59
|
+
onProgress,
|
|
60
|
+
onSuccess,
|
|
61
|
+
onError
|
|
62
|
+
} = options;
|
|
63
|
+
const id = Math.random().toString(36).substring(2, 15);
|
|
64
|
+
const item = {
|
|
65
|
+
id,
|
|
66
|
+
file,
|
|
67
|
+
name: file.name || key.split("/").pop() || "unknown",
|
|
68
|
+
percent: 0,
|
|
69
|
+
status: "pending",
|
|
70
|
+
key
|
|
71
|
+
};
|
|
72
|
+
uploadList.push(item);
|
|
73
|
+
doUpload(item, token, getToken, region2, onProgress, onSuccess, onError);
|
|
74
|
+
}
|
|
75
|
+
async function doUpload(item, token, getToken, region2 = "z2", onProgress, onSuccess, onError) {
|
|
76
|
+
item.status = "uploading";
|
|
77
|
+
try {
|
|
78
|
+
const uploadToken = await resolveToken(token, getToken);
|
|
79
|
+
const config = {
|
|
80
|
+
useCdnDomain: true,
|
|
81
|
+
region: REGION_MAP[region2] || qiniu__namespace.region.z2
|
|
82
|
+
};
|
|
83
|
+
const putExtra = {
|
|
84
|
+
fname: item.name,
|
|
85
|
+
params: {},
|
|
86
|
+
mimeType: void 0
|
|
87
|
+
};
|
|
88
|
+
const observable = qiniu__namespace.upload(
|
|
89
|
+
item.file,
|
|
90
|
+
item.key,
|
|
91
|
+
uploadToken,
|
|
92
|
+
putExtra,
|
|
93
|
+
config
|
|
94
|
+
);
|
|
95
|
+
observable.subscribe({
|
|
96
|
+
next: (res) => {
|
|
97
|
+
item.percent = res.total.percent;
|
|
98
|
+
onProgress?.(item.percent);
|
|
99
|
+
},
|
|
100
|
+
error: (err) => {
|
|
101
|
+
item.status = "error";
|
|
102
|
+
item.error = err.message;
|
|
103
|
+
onError?.(new Error(err.message));
|
|
104
|
+
removeItem(item.id);
|
|
105
|
+
},
|
|
106
|
+
complete: (res) => {
|
|
107
|
+
item.status = "success";
|
|
108
|
+
item.percent = 100;
|
|
109
|
+
onSuccess?.(res);
|
|
110
|
+
removeItem(item.id);
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
} catch (error) {
|
|
114
|
+
item.status = "error";
|
|
115
|
+
item.error = error.message || "\u4E0A\u4F20\u5931\u8D25";
|
|
116
|
+
onError?.(
|
|
117
|
+
error instanceof Error ? error : new Error(error.message || "\u4E0A\u4F20\u5931\u8D25")
|
|
118
|
+
);
|
|
119
|
+
removeItem(item.id);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
function batchUpload(options) {
|
|
123
|
+
const {
|
|
124
|
+
files,
|
|
125
|
+
token,
|
|
126
|
+
getToken,
|
|
127
|
+
maxConcurrency = 3,
|
|
128
|
+
region: region2 = "z2",
|
|
129
|
+
onItemProgress,
|
|
130
|
+
onItemSuccess,
|
|
131
|
+
onItemError,
|
|
132
|
+
onAllComplete
|
|
133
|
+
} = options;
|
|
134
|
+
let completedCount = 0;
|
|
135
|
+
const totalCount = files.length;
|
|
136
|
+
const batchQueue = files.map((f) => {
|
|
137
|
+
const id = Math.random().toString(36).substring(2, 15);
|
|
138
|
+
const item = {
|
|
139
|
+
id,
|
|
140
|
+
file: f.file,
|
|
141
|
+
name: f.file.name || f.key.split("/").pop() || "unknown",
|
|
142
|
+
percent: 0,
|
|
143
|
+
status: "pending",
|
|
144
|
+
key: f.key
|
|
145
|
+
};
|
|
146
|
+
uploadList.push(item);
|
|
147
|
+
return item;
|
|
148
|
+
});
|
|
149
|
+
let batchActiveCount = 0;
|
|
150
|
+
const pending = [...batchQueue];
|
|
151
|
+
function processNext() {
|
|
152
|
+
if (batchActiveCount >= maxConcurrency || pending.length === 0) return;
|
|
153
|
+
const item = pending.shift();
|
|
154
|
+
batchActiveCount++;
|
|
155
|
+
doUpload(
|
|
156
|
+
item,
|
|
157
|
+
token,
|
|
158
|
+
getToken,
|
|
159
|
+
region2,
|
|
160
|
+
// onProgress
|
|
161
|
+
(percent) => onItemProgress?.(item.key, percent),
|
|
162
|
+
// onSuccess
|
|
163
|
+
(res) => {
|
|
164
|
+
batchActiveCount--;
|
|
165
|
+
completedCount++;
|
|
166
|
+
onItemSuccess?.(item.key, res);
|
|
167
|
+
if (completedCount === totalCount) {
|
|
168
|
+
onAllComplete?.();
|
|
169
|
+
} else {
|
|
170
|
+
processNext();
|
|
171
|
+
}
|
|
172
|
+
},
|
|
173
|
+
// onError
|
|
174
|
+
(err) => {
|
|
175
|
+
batchActiveCount--;
|
|
176
|
+
completedCount++;
|
|
177
|
+
onItemError?.(item.key, err);
|
|
178
|
+
if (completedCount === totalCount) {
|
|
179
|
+
onAllComplete?.();
|
|
180
|
+
} else {
|
|
181
|
+
processNext();
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
);
|
|
185
|
+
processNext();
|
|
186
|
+
}
|
|
187
|
+
processNext();
|
|
188
|
+
}
|
|
189
|
+
function getUploadList() {
|
|
190
|
+
return [...uploadList];
|
|
191
|
+
}
|
|
192
|
+
function removeItem(id, delay = 2e3) {
|
|
193
|
+
setTimeout(() => {
|
|
194
|
+
const index = uploadList.findIndex((i) => i.id === id);
|
|
195
|
+
if (index !== -1) {
|
|
196
|
+
uploadList.splice(index, 1);
|
|
197
|
+
}
|
|
198
|
+
}, delay);
|
|
199
|
+
}
|
|
200
|
+
return {
|
|
201
|
+
upload: upload2,
|
|
202
|
+
batchUpload,
|
|
203
|
+
getUploadList
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// src/knowledge/index.ts
|
|
208
|
+
function createKnowledgeModule(http) {
|
|
209
|
+
async function processUrl(params) {
|
|
210
|
+
const { fileID, ...body } = params;
|
|
211
|
+
const queryParams = {};
|
|
212
|
+
if (fileID) {
|
|
213
|
+
queryParams.id = fileID;
|
|
214
|
+
}
|
|
215
|
+
const res = await http.post(
|
|
216
|
+
"/documents/process-url",
|
|
217
|
+
{
|
|
218
|
+
userID: body.userID,
|
|
219
|
+
file_url: body.fileUrl
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
params: queryParams
|
|
223
|
+
}
|
|
224
|
+
);
|
|
225
|
+
return res.data;
|
|
226
|
+
}
|
|
227
|
+
async function uploadDocument(params) {
|
|
228
|
+
const formData = new FormData();
|
|
229
|
+
formData.append("user_id", params.userID);
|
|
230
|
+
formData.append("file", params.file);
|
|
231
|
+
const res = await http.post(
|
|
232
|
+
"/documents/upload",
|
|
233
|
+
formData,
|
|
234
|
+
{
|
|
235
|
+
headers: {
|
|
236
|
+
"Content-Type": "multipart/form-data"
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
);
|
|
240
|
+
return res.data;
|
|
241
|
+
}
|
|
242
|
+
async function deleteDocument(params) {
|
|
243
|
+
await http.post("/documents/delete", {
|
|
244
|
+
userID: params.userID,
|
|
245
|
+
fileID: params.fileID,
|
|
246
|
+
filename: params.filename
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
return {
|
|
250
|
+
processUrl,
|
|
251
|
+
uploadDocument,
|
|
252
|
+
deleteDocument
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// src/chat/index.ts
|
|
257
|
+
function createChatModule(http, ragServerUrl, appKey) {
|
|
258
|
+
async function askStream(options) {
|
|
259
|
+
const { userId, query, topK = 3, onChunk, onDone, onError } = options;
|
|
260
|
+
try {
|
|
261
|
+
const response = await fetch(`${ragServerUrl}/chat/ask`, {
|
|
262
|
+
method: "POST",
|
|
263
|
+
headers: {
|
|
264
|
+
"Content-Type": "application/json",
|
|
265
|
+
"app-key": appKey
|
|
266
|
+
},
|
|
267
|
+
body: JSON.stringify({
|
|
268
|
+
user_id: userId,
|
|
269
|
+
query,
|
|
270
|
+
top_k: topK
|
|
271
|
+
})
|
|
272
|
+
});
|
|
273
|
+
if (!response.ok) {
|
|
274
|
+
throw new Error(`\u8BF7\u6C42\u5931\u8D25: ${response.status} ${response.statusText}`);
|
|
275
|
+
}
|
|
276
|
+
const reader = response.body?.getReader();
|
|
277
|
+
if (!reader) {
|
|
278
|
+
throw new Error("\u65E0\u6CD5\u83B7\u53D6\u54CD\u5E94\u6D41");
|
|
279
|
+
}
|
|
280
|
+
const decoder = new TextDecoder();
|
|
281
|
+
let fullAnswer = "";
|
|
282
|
+
while (true) {
|
|
283
|
+
const { done, value } = await reader.read();
|
|
284
|
+
if (done) break;
|
|
285
|
+
const text = decoder.decode(value, { stream: true });
|
|
286
|
+
const lines = text.split("\n");
|
|
287
|
+
for (const line of lines) {
|
|
288
|
+
const trimmed = line.trim();
|
|
289
|
+
if (!trimmed) continue;
|
|
290
|
+
if (trimmed.startsWith("data: ")) {
|
|
291
|
+
const data = trimmed.slice(6);
|
|
292
|
+
if (data === "[DONE]") continue;
|
|
293
|
+
try {
|
|
294
|
+
const parsed = JSON.parse(data);
|
|
295
|
+
const chunk = parsed.content || parsed.answer || data;
|
|
296
|
+
fullAnswer += chunk;
|
|
297
|
+
onChunk(chunk);
|
|
298
|
+
} catch {
|
|
299
|
+
fullAnswer += data;
|
|
300
|
+
onChunk(data);
|
|
301
|
+
}
|
|
302
|
+
} else {
|
|
303
|
+
fullAnswer += trimmed;
|
|
304
|
+
onChunk(trimmed);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
onDone?.(fullAnswer);
|
|
309
|
+
} catch (error) {
|
|
310
|
+
const err = error instanceof Error ? error : new Error(error.message || "\u95EE\u7B54\u8BF7\u6C42\u5931\u8D25");
|
|
311
|
+
onError?.(err);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
async function ask(params) {
|
|
315
|
+
const res = await http.post("/chat/ask", {
|
|
316
|
+
user_id: params.userId,
|
|
317
|
+
query: params.query,
|
|
318
|
+
top_k: params.topK ?? 3
|
|
319
|
+
});
|
|
320
|
+
return res.data;
|
|
321
|
+
}
|
|
322
|
+
return {
|
|
323
|
+
askStream,
|
|
324
|
+
ask
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// src/tts/index.ts
|
|
329
|
+
function createTtsModule(ragServerUrl, appKey) {
|
|
330
|
+
async function stream(params) {
|
|
331
|
+
const fetchOptions = {
|
|
332
|
+
method: "POST",
|
|
333
|
+
headers: {
|
|
334
|
+
"Content-Type": "application/json",
|
|
335
|
+
"app-key": appKey
|
|
336
|
+
},
|
|
337
|
+
body: JSON.stringify({ text: params.text })
|
|
338
|
+
};
|
|
339
|
+
if (params.signal) {
|
|
340
|
+
fetchOptions.signal = params.signal;
|
|
341
|
+
}
|
|
342
|
+
const response = await fetch(`${ragServerUrl}/tts/stream`, fetchOptions);
|
|
343
|
+
if (!response.ok) {
|
|
344
|
+
throw new Error(
|
|
345
|
+
`TTS \u8BF7\u6C42\u5931\u8D25: ${response.status} ${response.statusText}`
|
|
346
|
+
);
|
|
347
|
+
}
|
|
348
|
+
return response;
|
|
349
|
+
}
|
|
350
|
+
return {
|
|
351
|
+
stream
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// src/asr/index.ts
|
|
356
|
+
function createAsrModule(http) {
|
|
357
|
+
async function transcribe(file) {
|
|
358
|
+
const formData = new FormData();
|
|
359
|
+
formData.append("file", file);
|
|
360
|
+
const res = await http.post("/asr/transcribe", formData, {
|
|
361
|
+
headers: {
|
|
362
|
+
"Content-Type": "multipart/form-data"
|
|
363
|
+
}
|
|
364
|
+
});
|
|
365
|
+
return res.data;
|
|
366
|
+
}
|
|
367
|
+
return {
|
|
368
|
+
transcribe
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
function createAppModule(ragServerUrl) {
|
|
372
|
+
async function generateKey(appName) {
|
|
373
|
+
const res = await axios__default.default.post(
|
|
374
|
+
`${ragServerUrl}/application/generate_key`,
|
|
375
|
+
{ app_name: appName }
|
|
376
|
+
);
|
|
377
|
+
return res.data;
|
|
378
|
+
}
|
|
379
|
+
return {
|
|
380
|
+
generateKey
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// src/oss/index.ts
|
|
385
|
+
function createOssModule(http) {
|
|
386
|
+
async function getUploadCode() {
|
|
387
|
+
const res = await http.get("/oss/code");
|
|
388
|
+
return res.data;
|
|
389
|
+
}
|
|
390
|
+
async function getPutPolicy() {
|
|
391
|
+
const res = await http.get("/oss/putPolicy");
|
|
392
|
+
return res.data;
|
|
393
|
+
}
|
|
394
|
+
return {
|
|
395
|
+
getUploadCode,
|
|
396
|
+
getPutPolicy
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// config.ts
|
|
401
|
+
var RAG_SERVER_URL = "http://yanmengsss.xyz";
|
|
402
|
+
|
|
403
|
+
// src/index.ts
|
|
404
|
+
function createRagClient(config = { appKey: "" }) {
|
|
405
|
+
const { ragServerUrl = RAG_SERVER_URL, appKey = "" } = config;
|
|
406
|
+
const http = createHttpClient(ragServerUrl, appKey);
|
|
407
|
+
return {
|
|
408
|
+
/**七牛上传依赖的凭证接口模块 */
|
|
409
|
+
oss: createOssModule(http),
|
|
410
|
+
/** 七牛上传模块 */
|
|
411
|
+
qiniu: createQiniuModule(),
|
|
412
|
+
/** 知识库模块 */
|
|
413
|
+
knowledge: createKnowledgeModule(http),
|
|
414
|
+
/** AI 问答模块(支持 SSE 流式) */
|
|
415
|
+
chat: createChatModule(http, ragServerUrl, appKey),
|
|
416
|
+
/** TTS 语音合成模块 */
|
|
417
|
+
tts: createTtsModule(ragServerUrl, appKey),
|
|
418
|
+
/** ASR 语音转写模块 */
|
|
419
|
+
asr: createAsrModule(http),
|
|
420
|
+
/** 应用管理模块 */
|
|
421
|
+
app: createAppModule(ragServerUrl)
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
exports.createRagClient = createRagClient;
|
|
426
|
+
//# sourceMappingURL=index.js.map
|
|
427
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/client.ts","../src/qiniu/uploader.ts","../src/knowledge/index.ts","../src/chat/index.ts","../src/tts/index.ts","../src/asr/index.ts","../src/app/index.ts","../src/oss/index.ts","../config.ts","../src/index.ts"],"names":["axios","qiniu","upload","region"],"mappings":"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","file":"index.js","sourcesContent":["import axios, { AxiosInstance } from \"axios\";\r\n\r\n/**\r\n * 创建内部使用的 axios 实例,自动注入 app-key 到请求头\r\n */\r\nexport function createHttpClient(\r\n baseURL: string,\r\n appKey: string,\r\n): AxiosInstance {\r\n const instance = axios.create({ baseURL });\r\n\r\n instance.interceptors.request.use((config) => {\r\n config.headers[\"app-key\"] = appKey;\r\n return config;\r\n });\r\n\r\n return instance;\r\n}\r\n","import * as qiniu from \"qiniu-js\";\r\nimport type {\r\n QiniuUploadOptions,\r\n QiniuBatchUploadOptions,\r\n UploadItem,\r\n} from \"../types\";\r\n\r\n/** 区域映射 */\r\nconst REGION_MAP: Record<string, any> = {\r\n z0: qiniu.region.z0,\r\n z1: qiniu.region.z1,\r\n z2: qiniu.region.z2,\r\n na0: qiniu.region.na0,\r\n as0: qiniu.region.as0,\r\n};\r\n\r\n/**\r\n * 七牛上传模块\r\n * 提供单文件上传、批量并发上传、上传队列状态查询\r\n */\r\nexport function createQiniuModule() {\r\n const uploadList: UploadItem[] = [];\r\n const queue: UploadItem[] = [];\r\n let activeCount = 0;\r\n\r\n /**\r\n * 解析上传 token:直接传入或通过 getToken 函数获取\r\n */\r\n async function resolveToken(\r\n token?: string,\r\n getToken?: () => Promise<string>,\r\n ): Promise<string> {\r\n if (token) return token;\r\n if (getToken) return await getToken();\r\n throw new Error(\"[yanmengs-rag] 必须提供 token 或 getToken\");\r\n }\r\n\r\n /**\r\n * 单文件上传\r\n */\r\n function upload(options: QiniuUploadOptions): void {\r\n const {\r\n file,\r\n key,\r\n token,\r\n getToken,\r\n region = \"z2\",\r\n onProgress,\r\n onSuccess,\r\n onError,\r\n } = options;\r\n\r\n const id = Math.random().toString(36).substring(2, 15);\r\n const item: UploadItem = {\r\n id,\r\n file,\r\n name: (file as File).name || key.split(\"/\").pop() || \"unknown\",\r\n percent: 0,\r\n status: \"pending\",\r\n key,\r\n };\r\n\r\n uploadList.push(item);\r\n\r\n // 立即开始上传\r\n doUpload(item, token, getToken, region, onProgress, onSuccess, onError);\r\n }\r\n\r\n /**\r\n * 执行单个上传任务\r\n */\r\n async function doUpload(\r\n item: UploadItem,\r\n token?: string,\r\n getToken?: () => Promise<string>,\r\n region: string = \"z2\",\r\n onProgress?: (percent: number) => void,\r\n onSuccess?: (res: any) => void,\r\n onError?: (err: Error) => void,\r\n ): Promise<void> {\r\n item.status = \"uploading\";\r\n\r\n try {\r\n const uploadToken = await resolveToken(token, getToken);\r\n\r\n const config = {\r\n useCdnDomain: true,\r\n region: REGION_MAP[region] || qiniu.region.z2,\r\n };\r\n\r\n const putExtra = {\r\n fname: item.name,\r\n params: {},\r\n mimeType: undefined as any,\r\n };\r\n\r\n const observable = qiniu.upload(\r\n item.file as any,\r\n item.key,\r\n uploadToken,\r\n putExtra,\r\n config,\r\n );\r\n\r\n observable.subscribe({\r\n next: (res) => {\r\n item.percent = res.total.percent;\r\n onProgress?.(item.percent);\r\n },\r\n error: (err) => {\r\n item.status = \"error\";\r\n item.error = err.message;\r\n onError?.(new Error(err.message));\r\n // 清理\r\n removeItem(item.id);\r\n },\r\n complete: (res) => {\r\n item.status = \"success\";\r\n item.percent = 100;\r\n onSuccess?.(res);\r\n // 清理\r\n removeItem(item.id);\r\n },\r\n });\r\n } catch (error: any) {\r\n item.status = \"error\";\r\n item.error = error.message || \"上传失败\";\r\n onError?.(\r\n error instanceof Error ? error : new Error(error.message || \"上传失败\"),\r\n );\r\n removeItem(item.id);\r\n }\r\n }\r\n\r\n /**\r\n * 批量并发上传\r\n */\r\n function batchUpload(options: QiniuBatchUploadOptions): void {\r\n const {\r\n files,\r\n token,\r\n getToken,\r\n maxConcurrency = 3,\r\n region = \"z2\",\r\n onItemProgress,\r\n onItemSuccess,\r\n onItemError,\r\n onAllComplete,\r\n } = options;\r\n\r\n let completedCount = 0;\r\n const totalCount = files.length;\r\n\r\n // 构建队列\r\n const batchQueue = files.map((f) => {\r\n const id = Math.random().toString(36).substring(2, 15);\r\n const item: UploadItem = {\r\n id,\r\n file: f.file,\r\n name: (f.file as File).name || f.key.split(\"/\").pop() || \"unknown\",\r\n percent: 0,\r\n status: \"pending\",\r\n key: f.key,\r\n };\r\n uploadList.push(item);\r\n return item;\r\n });\r\n\r\n let batchActiveCount = 0;\r\n const pending = [...batchQueue];\r\n\r\n function processNext() {\r\n if (batchActiveCount >= maxConcurrency || pending.length === 0) return;\r\n\r\n const item = pending.shift()!;\r\n batchActiveCount++;\r\n\r\n doUpload(\r\n item,\r\n token,\r\n getToken,\r\n region,\r\n // onProgress\r\n (percent) => onItemProgress?.(item.key, percent),\r\n // onSuccess\r\n (res) => {\r\n batchActiveCount--;\r\n completedCount++;\r\n onItemSuccess?.(item.key, res);\r\n if (completedCount === totalCount) {\r\n onAllComplete?.();\r\n } else {\r\n processNext();\r\n }\r\n },\r\n // onError\r\n (err) => {\r\n batchActiveCount--;\r\n completedCount++;\r\n onItemError?.(item.key, err);\r\n if (completedCount === totalCount) {\r\n onAllComplete?.();\r\n } else {\r\n processNext();\r\n }\r\n },\r\n );\r\n\r\n // 尝试继续填充并发槽\r\n processNext();\r\n }\r\n\r\n // 启动\r\n processNext();\r\n }\r\n\r\n /**\r\n * 获取当前上传队列状态\r\n */\r\n function getUploadList(): UploadItem[] {\r\n return [...uploadList];\r\n }\r\n\r\n /**\r\n * 从列表中移除已完成/失败的项\r\n */\r\n function removeItem(id: string, delay: number = 2000): void {\r\n setTimeout(() => {\r\n const index = uploadList.findIndex((i) => i.id === id);\r\n if (index !== -1) {\r\n uploadList.splice(index, 1);\r\n }\r\n }, delay);\r\n }\r\n\r\n return {\r\n upload,\r\n batchUpload,\r\n getUploadList,\r\n };\r\n}\r\n","import type { AxiosInstance } from \"axios\";\r\nimport type {\r\n ProcessUrlParams,\r\n ProcessUrlResult,\r\n UploadDocumentParams,\r\n UploadDocumentResult,\r\n DeleteDocumentParams,\r\n} from \"../types\";\r\n\r\n/**\r\n * 知识库模块\r\n * 封装文档上传(URL / 直传)、文档删除\r\n */\r\nexport function createKnowledgeModule(http: AxiosInstance) {\r\n /**\r\n * 通过 URL 注入知识文档\r\n * POST /documents/process-url\r\n */\r\n async function processUrl(\r\n params: ProcessUrlParams,\r\n ): Promise<ProcessUrlResult> {\r\n const { fileID, ...body } = params;\r\n const queryParams: Record<string, string> = {};\r\n if (fileID) {\r\n queryParams.id = fileID;\r\n }\r\n\r\n const res = await http.post<ProcessUrlResult>(\r\n \"/documents/process-url\",\r\n {\r\n userID: body.userID,\r\n file_url: body.fileUrl,\r\n },\r\n {\r\n params: queryParams,\r\n },\r\n );\r\n\r\n return res.data;\r\n }\r\n\r\n /**\r\n * 直传文件上传到知识库\r\n * POST /documents/upload (multipart/form-data)\r\n */\r\n async function uploadDocument(\r\n params: UploadDocumentParams,\r\n ): Promise<UploadDocumentResult> {\r\n const formData = new FormData();\r\n formData.append(\"user_id\", params.userID);\r\n formData.append(\"file\", params.file);\r\n\r\n const res = await http.post<UploadDocumentResult>(\r\n \"/documents/upload\",\r\n formData,\r\n {\r\n headers: {\r\n \"Content-Type\": \"multipart/form-data\",\r\n },\r\n },\r\n );\r\n\r\n return res.data;\r\n }\r\n\r\n /**\r\n * 删除知识库文档\r\n * POST /documents/delete\r\n */\r\n async function deleteDocument(params: DeleteDocumentParams): Promise<void> {\r\n await http.post(\"/documents/delete\", {\r\n userID: params.userID,\r\n fileID: params.fileID,\r\n filename: params.filename,\r\n });\r\n }\r\n\r\n return {\r\n processUrl,\r\n uploadDocument,\r\n deleteDocument,\r\n };\r\n}\r\n","import type { AxiosInstance } from \"axios\";\r\nimport type { AskParams, AskResult, AskStreamOptions } from \"../types\";\r\n\r\n/**\r\n * AI 问答模块\r\n * 提供 SSE 流式问答(fetch)和非流式问答(axios)\r\n */\r\nexport function createChatModule(\r\n http: AxiosInstance,\r\n ragServerUrl: string,\r\n appKey: string,\r\n) {\r\n /**\r\n * SSE 流式问答\r\n * 使用 fetch 发起请求,逐块读取流式返回\r\n */\r\n async function askStream(options: AskStreamOptions): Promise<void> {\r\n const { userId, query, topK = 3, onChunk, onDone, onError } = options;\r\n\r\n try {\r\n const response = await fetch(`${ragServerUrl}/chat/ask`, {\r\n method: \"POST\",\r\n headers: {\r\n \"Content-Type\": \"application/json\",\r\n \"app-key\": appKey,\r\n },\r\n body: JSON.stringify({\r\n user_id: userId,\r\n query,\r\n top_k: topK,\r\n }),\r\n });\r\n\r\n if (!response.ok) {\r\n throw new Error(`请求失败: ${response.status} ${response.statusText}`);\r\n }\r\n\r\n const reader = response.body?.getReader();\r\n if (!reader) {\r\n throw new Error(\"无法获取响应流\");\r\n }\r\n\r\n const decoder = new TextDecoder();\r\n let fullAnswer = \"\";\r\n\r\n while (true) {\r\n const { done, value } = await reader.read();\r\n if (done) break;\r\n\r\n const text = decoder.decode(value, { stream: true });\r\n\r\n // 解析 SSE 格式:每行以 \"data: \" 开头\r\n const lines = text.split(\"\\n\");\r\n for (const line of lines) {\r\n const trimmed = line.trim();\r\n if (!trimmed) continue;\r\n\r\n if (trimmed.startsWith(\"data: \")) {\r\n const data = trimmed.slice(6);\r\n if (data === \"[DONE]\") continue;\r\n\r\n try {\r\n const parsed = JSON.parse(data);\r\n const chunk = parsed.content || parsed.answer || data;\r\n fullAnswer += chunk;\r\n onChunk(chunk);\r\n } catch {\r\n // 不是 JSON,直接当纯文本\r\n fullAnswer += data;\r\n onChunk(data);\r\n }\r\n } else {\r\n // 非 SSE 格式,也回调\r\n fullAnswer += trimmed;\r\n onChunk(trimmed);\r\n }\r\n }\r\n }\r\n\r\n onDone?.(fullAnswer);\r\n } catch (error: any) {\r\n const err =\r\n error instanceof Error\r\n ? error\r\n : new Error(error.message || \"问答请求失败\");\r\n onError?.(err);\r\n }\r\n }\r\n\r\n /**\r\n * 非流式问答(一次性返回完整结果)\r\n */\r\n async function ask(params: AskParams): Promise<AskResult> {\r\n const res = await http.post<AskResult>(\"/chat/ask\", {\r\n user_id: params.userId,\r\n query: params.query,\r\n top_k: params.topK ?? 3,\r\n });\r\n\r\n return res.data;\r\n }\r\n\r\n return {\r\n askStream,\r\n ask,\r\n };\r\n}\r\n","import type { TtsStreamParams } from \"../types\";\r\n\r\n/**\r\n * TTS 模块\r\n * 使用 fetch 流式获取音频数据\r\n */\r\nexport function createTtsModule(ragServerUrl: string, appKey: string) {\r\n /**\r\n * 流式语音合成\r\n * POST /tts/stream\r\n * 返回原始 Response,调用方可通过 response.body 获取 ReadableStream 流式播放\r\n */\r\n async function stream(params: TtsStreamParams): Promise<Response> {\r\n const fetchOptions: RequestInit = {\r\n method: \"POST\",\r\n headers: {\r\n \"Content-Type\": \"application/json\",\r\n \"app-key\": appKey,\r\n },\r\n body: JSON.stringify({ text: params.text }),\r\n };\r\n\r\n if (params.signal) {\r\n fetchOptions.signal = params.signal;\r\n }\r\n\r\n const response = await fetch(`${ragServerUrl}/tts/stream`, fetchOptions);\r\n\r\n if (!response.ok) {\r\n throw new Error(\r\n `TTS 请求失败: ${response.status} ${response.statusText}`,\r\n );\r\n }\r\n\r\n return response;\r\n }\r\n\r\n return {\r\n stream,\r\n };\r\n}\r\n","import type { AxiosInstance } from \"axios\";\r\nimport type { TranscribeResult } from \"../types\";\r\n\r\n/**\r\n * ASR 模块\r\n * 语音转文字\r\n */\r\nexport function createAsrModule(http: AxiosInstance) {\r\n /**\r\n * 语音转写\r\n * POST /asr/transcribe (multipart/form-data)\r\n */\r\n async function transcribe(file: File | Blob): Promise<TranscribeResult> {\r\n const formData = new FormData();\r\n formData.append(\"file\", file);\r\n\r\n const res = await http.post<TranscribeResult>(\"/asr/transcribe\", formData, {\r\n headers: {\r\n \"Content-Type\": \"multipart/form-data\",\r\n },\r\n });\r\n\r\n return res.data;\r\n }\r\n\r\n return {\r\n transcribe,\r\n };\r\n}\r\n","import axios from \"axios\";\r\nimport type { GenerateKeyResult } from \"../types\";\r\n\r\n/**\r\n * 应用管理模块\r\n * 生成 App Key(此接口不需要鉴权)\r\n */\r\nexport function createAppModule(ragServerUrl: string) {\r\n /**\r\n * 生成 App Key\r\n * POST /application/generate_key\r\n */\r\n async function generateKey(appName: string): Promise<GenerateKeyResult> {\r\n const res = await axios.post<GenerateKeyResult>(\r\n `${ragServerUrl}/application/generate_key`,\r\n { app_name: appName },\r\n );\r\n\r\n return res.data;\r\n }\r\n\r\n return {\r\n generateKey,\r\n };\r\n}\r\n","import type { AxiosInstance } from \"axios\";\r\nimport type { OssTokenResult } from \"../types\";\r\n\r\n/**\r\n * OSS 模块\r\n * 用于获取存储服务的上传凭证(如七牛 Token)\r\n */\r\nexport function createOssModule(http: AxiosInstance) {\r\n /**\r\n * 获取短期(10 分钟)七牛上传凭证\r\n * GET /oss/code\r\n */\r\n async function getUploadCode(): Promise<OssTokenResult> {\r\n const res = await http.get<OssTokenResult>(\"/oss/code\");\r\n return res.data;\r\n }\r\n\r\n /**\r\n * 获取长期(6 小时)七牛上传凭证\r\n * GET /oss/putPolicy\r\n */\r\n async function getPutPolicy(): Promise<OssTokenResult> {\r\n const res = await http.get<OssTokenResult>(\"/oss/putPolicy\");\r\n return res.data;\r\n }\r\n\r\n return {\r\n getUploadCode,\r\n getPutPolicy,\r\n };\r\n}\r\n","export const RAG_SERVER_URL = \"http://yanmengsss.xyz\";","import { createHttpClient } from \"./client\";\r\nimport { createQiniuModule } from \"./qiniu\";\r\nimport { createKnowledgeModule } from \"./knowledge\";\r\nimport { createChatModule } from \"./chat\";\r\nimport { createTtsModule } from \"./tts\";\r\nimport { createAsrModule } from \"./asr\";\r\nimport { createAppModule } from \"./app\";\r\nimport { createOssModule } from \"./oss\";\r\nimport { RAG_SERVER_URL } from \"../config\";\r\nimport type { RagClientConfig } from \"./types\";\r\n\r\n// 导出所有类型\r\nexport type {\r\n RagClientConfig,\r\n OssTokenResult,\r\n QiniuUploadOptions,\r\n QiniuBatchUploadOptions,\r\n UploadItem,\r\n ProcessUrlParams,\r\n ProcessUrlResult,\r\n UploadDocumentParams,\r\n UploadDocumentResult,\r\n DeleteDocumentParams,\r\n AskParams,\r\n AskStreamOptions,\r\n AskResult,\r\n TtsStreamParams,\r\n TranscribeResult,\r\n GenerateKeyResult,\r\n} from \"./types\";\r\n\r\n/**\r\n * 创建 RAG 客户端实例\r\n *\r\n * @example\r\n * ```ts\r\n * import { createRagClient } from 'yanmengs-rag-package';\r\n *\r\n * const rag = createRagClient({\r\n * ragServerUrl: 'http://localhost:7100',\r\n * appKey: 'your_app_key',\r\n * });\r\n *\r\n * // 获取七牛上传 Token\r\n * const tokenRes = await rag.oss.getPutPolicy();\r\n *\r\n * // 七牛上传\r\n * rag.qiniu.upload({ file, key: 'xxx.pdf', token: tokenRes.data.token, onSuccess: (res) => {} });\r\n *\r\n * // 知识库\r\n * await rag.knowledge.processUrl({ userID: 'u1', fileUrl: 'https://...' });\r\n *\r\n * // AI 问答(SSE 流式)\r\n * rag.chat.askStream({ userId: 'u1', query: '...', onChunk: (c) => console.log(c) });\r\n *\r\n * // TTS\r\n * const audioRes = await rag.tts.stream({ text: '...' });\r\n *\r\n * const result = await rag.asr.transcribe(audioFile);\r\n * ```\r\n */\r\nexport function createRagClient(config: RagClientConfig = { appKey: \"\" }) {\r\n const { ragServerUrl = RAG_SERVER_URL, appKey = \"\" } = config;\r\n\r\n // 创建内部 HTTP 客户端(自动注入 app-key)\r\n const http = createHttpClient(ragServerUrl, appKey);\r\n\r\n return {\r\n /**七牛上传依赖的凭证接口模块 */\r\n oss: createOssModule(http),\r\n /** 七牛上传模块 */\r\n qiniu: createQiniuModule(),\r\n /** 知识库模块 */\r\n knowledge: createKnowledgeModule(http),\r\n /** AI 问答模块(支持 SSE 流式) */\r\n chat: createChatModule(http, ragServerUrl, appKey),\r\n /** TTS 语音合成模块 */\r\n tts: createTtsModule(ragServerUrl, appKey),\r\n /** ASR 语音转写模块 */\r\n asr: createAsrModule(http),\r\n /** 应用管理模块 */\r\n app: createAppModule(ragServerUrl),\r\n };\r\n}\r\n"]}
|