chatlab-cli 0.29.0 → 0.30.1-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/dist/{chat-command-JKG3FY5B.mjs → chat-command-VBDMWOKL.mjs} +8 -8
- package/dist/{chunk-6FPEP2ZX.mjs → chunk-326OCJOT.mjs} +2 -2
- package/dist/{chunk-QQK7MLCR.mjs → chunk-36JGKW6K.mjs} +710 -282
- package/dist/chunk-36JGKW6K.mjs.map +1 -0
- package/dist/{chunk-SKUG5XVD.mjs → chunk-5EE2EFPE.mjs} +5 -4
- package/dist/{chunk-KL2NGIMQ.mjs → chunk-D3DPCDII.mjs} +444 -274
- package/dist/chunk-D3DPCDII.mjs.map +1 -0
- package/dist/{chunk-I35WHWA6.mjs → chunk-KBSAVUFV.mjs} +7 -4
- package/dist/chunk-KBSAVUFV.mjs.map +1 -0
- package/dist/{chunk-WPI6YSAR.mjs → chunk-LVEJHB3X.mjs} +4570 -4412
- package/dist/chunk-LVEJHB3X.mjs.map +1 -0
- package/dist/chunk-M2PXDX4G.mjs +2325 -0
- package/dist/chunk-M2PXDX4G.mjs.map +1 -0
- package/dist/{chunk-CIB23U32.mjs → chunk-TCZHG3G7.mjs} +101 -41
- package/dist/chunk-TCZHG3G7.mjs.map +1 -0
- package/dist/{chunk-D4WTE7LV.mjs → chunk-TEX44HNL.mjs} +16 -12
- package/dist/chunk-TEX44HNL.mjs.map +1 -0
- package/dist/{chunk-7RW4CQAO.mjs → chunk-ULNRUS55.mjs} +5 -3
- package/dist/chunk-ULNRUS55.mjs.map +1 -0
- package/dist/{chunk-2MZ6G4AC.mjs → chunk-WV5GSRQM.mjs} +2 -2
- package/dist/cli.mjs +7 -7
- package/dist/contacts-worker.mjs +2 -2
- package/dist/{http-5E7ARYFW.mjs → http-L4AMELPZ.mjs} +11 -11
- package/dist/{import-3KG6VK6O.mjs → import-WWCSXGVS.mjs} +7 -7
- package/dist/index.mjs +11 -11
- package/dist/{mcp-JBI4CUQT.mjs → mcp-A4M3LT5O.mjs} +8 -8
- package/dist/people-relationships-worker.mjs +2 -2
- package/dist/semantic-index-worker.mjs +1 -1
- package/dist/{src-UTBQAOJ3.mjs → src-MPNBTFOE.mjs} +14 -6
- package/dist/{stream-import-7HZ4IRYJ.mjs → stream-import-HIE7PNL4.mjs} +7 -7
- package/dist/{worker-runtime-ALS4MR2A.mjs → worker-runtime-BJXO24XX.mjs} +5 -5
- package/dist-web/assets/{BufferResource-MsqP5sq3.js → BufferResource-DPkMC1wo.js} +1 -1
- package/dist-web/assets/CanvasRenderer-DokMtSX9.js +1 -0
- package/dist-web/assets/DebugToolsPanel.vue_vue_type_script_setup_true_lang-Ceg-0WOD.js +110 -0
- package/dist-web/assets/{Filter-wRJtdXx9.js → Filter-Bo_p3BVX.js} +1 -1
- package/dist-web/assets/LoadingState.vue_vue_type_script_setup_true_lang-D_dJuLWJ.js +1 -0
- package/dist-web/assets/{MessageExportModal-BCrMf5Kw.js → MessageExportModal-Ch0tqQix.js} +1 -1
- package/dist-web/assets/{PageHeader-C_yw54le.js → PageHeader-CRlmZoKw.js} +1 -1
- package/dist-web/assets/{RelationshipGalaxyCanvas-DTzJq7q7.js → RelationshipGalaxyCanvas-W_6XfPOG.js} +3 -3
- package/dist-web/assets/{RelationshipGalaxyThreeCanvas-DIE-0_iM.js → RelationshipGalaxyThreeCanvas-bB1nCwQ_.js} +1 -1
- package/dist-web/assets/{RenderTargetSystem-BSAQFamI.js → RenderTargetSystem-obRi6fMT.js} +1 -1
- package/dist-web/assets/{WebGLRenderer-lfzmCZNT.js → WebGLRenderer-xcDlnrCZ.js} +1 -1
- package/dist-web/assets/{WebGPURenderer-BnEdfdr_.js → WebGPURenderer-DbAOiiYr.js} +1 -1
- package/dist-web/assets/{browserAll-gRNfDyPu.js → browserAll-DVRJimO8.js} +1 -1
- package/dist-web/assets/electron-BSGRuxX9.js +1 -0
- package/dist-web/assets/{fetch-BW3aO7PS.js → fetch-7UN4YW3A.js} +1 -1
- package/dist-web/assets/{fetch-CQt-gb-f.js → fetch-B2alAySK.js} +1 -1
- package/dist-web/assets/fetch-B2rVTMYY.js +17 -0
- package/dist-web/assets/{fetch-C1fI_KOX.js → fetch-BSShKcMt.js} +1 -1
- package/dist-web/assets/{fetch-mFlEBZyB.js → fetch-BmxMf3I6.js} +1 -1
- package/dist-web/assets/{fetch-BwF5hNuF.js → fetch-CR5UDFW7.js} +1 -1
- package/dist-web/assets/{fetch-CFRoSIAn.js → fetch-ChAsglT5.js} +1 -1
- package/dist-web/assets/{fetch-CN91TIwV.js → fetch-DWEjTdcP.js} +1 -1
- package/dist-web/assets/{fetch-DPCJ-1l-.js → fetch-DfoxedXR.js} +1 -1
- package/dist-web/assets/{fetch-gMB4wuBd.js → fetch-t0WsRKHW.js} +1 -1
- package/dist-web/assets/index-B4l3rHie.css +1 -0
- package/dist-web/assets/{index-ZdCB7xcf.js → index-BVUTV9_w.js} +4 -4
- package/dist-web/assets/index-BmXNdMV5.js +2 -0
- package/dist-web/assets/index-BsXljrlg.js +22 -0
- package/dist-web/assets/{index-MBRD3wPd.css → index-C1p9CbmN.css} +1 -1
- package/dist-web/assets/index-COpza1A4.css +1 -0
- package/dist-web/assets/index-CQ5lRCHt.js +173 -0
- package/dist-web/assets/index-CZv0ZOID.js +2 -0
- package/dist-web/assets/{index-DveHdPfK.js → index-CfgDqd_z.js} +1 -1
- package/dist-web/assets/{index-Bg4GGPXv.js → index-CtVR_KuP.js} +1 -1
- package/dist-web/assets/index-DT0Bu8mH.js +64 -0
- package/dist-web/assets/index-DjcWJv4b.js +1 -0
- package/dist-web/assets/{vendor-nuxt-ui-Dr2T8_OZ.js → vendor-nuxt-ui-DaLxYaC4.js} +1 -1
- package/dist-web/assets/{web-BakeV58u.js → web-knHSvvNj.js} +1 -1
- package/dist-web/assets/{webworkerAll-D_6PgURS.js → webworkerAll-CMKoykfD.js} +1 -1
- package/dist-web/index.html +3 -3
- package/package.json +1 -1
- package/dist/chunk-7RW4CQAO.mjs.map +0 -1
- package/dist/chunk-ARZM6HBX.mjs +0 -542
- package/dist/chunk-ARZM6HBX.mjs.map +0 -1
- package/dist/chunk-CIB23U32.mjs.map +0 -1
- package/dist/chunk-D4WTE7LV.mjs.map +0 -1
- package/dist/chunk-I35WHWA6.mjs.map +0 -1
- package/dist/chunk-KL2NGIMQ.mjs.map +0 -1
- package/dist/chunk-QQK7MLCR.mjs.map +0 -1
- package/dist/chunk-WPI6YSAR.mjs.map +0 -1
- package/dist-web/assets/CanvasRenderer-BKCvcc2p.js +0 -1
- package/dist-web/assets/DebugToolsPanel.vue_vue_type_script_setup_true_lang-HGJb0Et1.js +0 -110
- package/dist-web/assets/electron-BHaEaaZP.js +0 -1
- package/dist-web/assets/fetch-CBZbgZqk.js +0 -17
- package/dist-web/assets/index--6C0sK6a.css +0 -1
- package/dist-web/assets/index-B6wEGata.js +0 -173
- package/dist-web/assets/index-BgVbj5qX.js +0 -12
- package/dist-web/assets/index-BkoXaBV_.js +0 -64
- package/dist-web/assets/index-C56IuV5U.css +0 -1
- package/dist-web/assets/index-CLRaKwpT.js +0 -2
- package/dist-web/assets/index-Dj1BSD7O.js +0 -1
- package/dist-web/assets/index-RoDgJcHU.js +0 -2
- package/dist-web/assets/index-aljYO5ms.js +0 -1
- /package/dist/{chat-command-JKG3FY5B.mjs.map → chat-command-VBDMWOKL.mjs.map} +0 -0
- /package/dist/{chunk-6FPEP2ZX.mjs.map → chunk-326OCJOT.mjs.map} +0 -0
- /package/dist/{chunk-SKUG5XVD.mjs.map → chunk-5EE2EFPE.mjs.map} +0 -0
- /package/dist/{chunk-2MZ6G4AC.mjs.map → chunk-WV5GSRQM.mjs.map} +0 -0
- /package/dist/{http-5E7ARYFW.mjs.map → http-L4AMELPZ.mjs.map} +0 -0
- /package/dist/{import-3KG6VK6O.mjs.map → import-WWCSXGVS.mjs.map} +0 -0
- /package/dist/{mcp-JBI4CUQT.mjs.map → mcp-A4M3LT5O.mjs.map} +0 -0
- /package/dist/{src-UTBQAOJ3.mjs.map → src-MPNBTFOE.mjs.map} +0 -0
- /package/dist/{stream-import-7HZ4IRYJ.mjs.map → stream-import-HIE7PNL4.mjs.map} +0 -0
- /package/dist/{worker-runtime-ALS4MR2A.mjs.map → worker-runtime-BJXO24XX.mjs.map} +0 -0
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
createEmptyContactsDiagnostics,
|
|
10
10
|
normalizeContactsTimeRangePreset,
|
|
11
11
|
resolveContactsTimeRange
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-TEX44HNL.mjs";
|
|
13
13
|
import {
|
|
14
14
|
PEOPLE_RELATIONSHIPS_ALGORITHM_VERSION,
|
|
15
15
|
buildPeopleRelationshipsNeighborhoodGraph,
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
computePeopleRelationshipsSnapshot,
|
|
19
19
|
normalizePeopleRelationshipsTimeRangePreset,
|
|
20
20
|
resolvePeopleRelationshipsTimeRange
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-WV5GSRQM.mjs";
|
|
22
22
|
import {
|
|
23
23
|
BUILTIN_MODELS,
|
|
24
24
|
BUILTIN_PROVIDERS,
|
|
@@ -32,6 +32,7 @@ import {
|
|
|
32
32
|
appLogger,
|
|
33
33
|
batchSegmentChineseWithStats,
|
|
34
34
|
batchSegmentWithFrequency,
|
|
35
|
+
buildExcludeKeywordsConditions,
|
|
35
36
|
buildSessionInfo,
|
|
36
37
|
clearJiebaInstance,
|
|
37
38
|
clearSessionIndex,
|
|
@@ -79,7 +80,7 @@ import {
|
|
|
79
80
|
updateMemberAliases,
|
|
80
81
|
updateSessionOwnerId,
|
|
81
82
|
writeAuthProfile
|
|
82
|
-
} from "./chunk-
|
|
83
|
+
} from "./chunk-LVEJHB3X.mjs";
|
|
83
84
|
import {
|
|
84
85
|
__commonJS,
|
|
85
86
|
__export,
|
|
@@ -2836,128 +2837,29 @@ function writeParseResultToDb(db, meta, members, messages) {
|
|
|
2836
2837
|
return { messageCount, memberCount: members.length, skippedCount };
|
|
2837
2838
|
}
|
|
2838
2839
|
|
|
2839
|
-
// ../../packages/node-runtime/src/import/perf-logger.ts
|
|
2840
|
-
import * as fs from "fs";
|
|
2841
|
-
import * as path from "path";
|
|
2842
|
-
var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
|
|
2843
|
-
LogLevel2["ERROR"] = "ERROR";
|
|
2844
|
-
LogLevel2["INFO"] = "INFO";
|
|
2845
|
-
return LogLevel2;
|
|
2846
|
-
})(LogLevel || {});
|
|
2847
|
-
var lastLogTime = Date.now();
|
|
2848
|
-
var lastMessageCount = 0;
|
|
2849
|
-
var currentLogFile = null;
|
|
2850
|
-
var errorCount = 0;
|
|
2851
|
-
function initPerfLog(sessionId, logDir) {
|
|
2852
|
-
try {
|
|
2853
|
-
if (!fs.existsSync(logDir)) {
|
|
2854
|
-
fs.mkdirSync(logDir, { recursive: true });
|
|
2855
|
-
}
|
|
2856
|
-
currentLogFile = path.join(logDir, `import_${sessionId}_${Date.now()}.log`);
|
|
2857
|
-
fs.writeFileSync(currentLogFile, `=== Import Log ===
|
|
2858
|
-
Start time: ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
2859
|
-
|
|
2860
|
-
`, "utf-8");
|
|
2861
|
-
} catch {
|
|
2862
|
-
}
|
|
2863
|
-
}
|
|
2864
|
-
function logPerf(event, messagesProcessed, batchSize) {
|
|
2865
|
-
const now = Date.now();
|
|
2866
|
-
const duration = now - lastLogTime;
|
|
2867
|
-
const messagesDelta = messagesProcessed - lastMessageCount;
|
|
2868
|
-
const speed = duration > 0 ? Math.round(messagesDelta / duration * 1e3) : 0;
|
|
2869
|
-
let memory = 0;
|
|
2870
|
-
try {
|
|
2871
|
-
const used = process.memoryUsage();
|
|
2872
|
-
memory = Math.round(used.heapUsed / 1024 / 1024);
|
|
2873
|
-
} catch {
|
|
2874
|
-
}
|
|
2875
|
-
const logLine = `[${(/* @__PURE__ */ new Date()).toISOString()}] ${event} | messages: ${messagesProcessed.toLocaleString()} | elapsed: ${duration}ms | speed: ${speed.toLocaleString()}/s | memory: ${memory}MB` + (batchSize ? ` | batch: ${batchSize}` : "") + "\n";
|
|
2876
|
-
if (currentLogFile) {
|
|
2877
|
-
try {
|
|
2878
|
-
fs.appendFileSync(currentLogFile, logLine, "utf-8");
|
|
2879
|
-
} catch {
|
|
2880
|
-
}
|
|
2881
|
-
}
|
|
2882
|
-
lastLogTime = now;
|
|
2883
|
-
lastMessageCount = messagesProcessed;
|
|
2884
|
-
}
|
|
2885
|
-
function logPerfDetail(detail) {
|
|
2886
|
-
if (currentLogFile) {
|
|
2887
|
-
try {
|
|
2888
|
-
fs.appendFileSync(currentLogFile, ` ${detail}
|
|
2889
|
-
`, "utf-8");
|
|
2890
|
-
} catch {
|
|
2891
|
-
}
|
|
2892
|
-
}
|
|
2893
|
-
}
|
|
2894
|
-
function resetPerfLog() {
|
|
2895
|
-
lastLogTime = Date.now();
|
|
2896
|
-
lastMessageCount = 0;
|
|
2897
|
-
currentLogFile = null;
|
|
2898
|
-
errorCount = 0;
|
|
2899
|
-
}
|
|
2900
|
-
function getCurrentLogFile() {
|
|
2901
|
-
return currentLogFile;
|
|
2902
|
-
}
|
|
2903
|
-
function writeLogLine(level, message) {
|
|
2904
|
-
if (!currentLogFile) return;
|
|
2905
|
-
const logLine = `[${(/* @__PURE__ */ new Date()).toISOString()}] [${level}] ${message}
|
|
2906
|
-
`;
|
|
2907
|
-
try {
|
|
2908
|
-
fs.appendFileSync(currentLogFile, logLine, "utf-8");
|
|
2909
|
-
} catch {
|
|
2910
|
-
}
|
|
2911
|
-
}
|
|
2912
|
-
function logError(message, error) {
|
|
2913
|
-
errorCount++;
|
|
2914
|
-
const errorDetail = error ? `: ${error.message}` : "";
|
|
2915
|
-
writeLogLine("ERROR" /* ERROR */, `${message}${errorDetail}`);
|
|
2916
|
-
}
|
|
2917
|
-
function logInfo(message) {
|
|
2918
|
-
writeLogLine("INFO" /* INFO */, message);
|
|
2919
|
-
}
|
|
2920
|
-
function getErrorCount() {
|
|
2921
|
-
return errorCount;
|
|
2922
|
-
}
|
|
2923
|
-
function logSummary(totalMessages, totalMembers) {
|
|
2924
|
-
if (!currentLogFile) return;
|
|
2925
|
-
const summary = `
|
|
2926
|
-
=== Import Summary ===
|
|
2927
|
-
End time: ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
2928
|
-
Total messages: ${totalMessages.toLocaleString()}
|
|
2929
|
-
Total members: ${totalMembers.toLocaleString()}
|
|
2930
|
-
Errors: ${errorCount}
|
|
2931
|
-
`;
|
|
2932
|
-
try {
|
|
2933
|
-
fs.appendFileSync(currentLogFile, summary, "utf-8");
|
|
2934
|
-
} catch {
|
|
2935
|
-
}
|
|
2936
|
-
}
|
|
2937
|
-
|
|
2938
2840
|
// ../../packages/parser/src/index.ts
|
|
2939
|
-
import * as
|
|
2940
|
-
import * as
|
|
2841
|
+
import * as fs17 from "fs";
|
|
2842
|
+
import * as path13 from "path";
|
|
2941
2843
|
|
|
2942
2844
|
// ../../packages/parser/src/sniffer.ts
|
|
2943
|
-
import * as
|
|
2944
|
-
import * as
|
|
2845
|
+
import * as fs from "fs";
|
|
2846
|
+
import * as path from "path";
|
|
2945
2847
|
var HEAD_SIZE = 64 * 1024;
|
|
2946
2848
|
function readFileHead(filePath, size = HEAD_SIZE) {
|
|
2947
|
-
const fd =
|
|
2849
|
+
const fd = fs.openSync(filePath, "r");
|
|
2948
2850
|
const buffer = Buffer.alloc(size);
|
|
2949
|
-
const bytesRead =
|
|
2950
|
-
|
|
2851
|
+
const bytesRead = fs.readSync(fd, buffer, 0, size, 0);
|
|
2852
|
+
fs.closeSync(fd);
|
|
2951
2853
|
return buffer.slice(0, bytesRead).toString("utf-8");
|
|
2952
2854
|
}
|
|
2953
2855
|
function getExtension(filePath) {
|
|
2954
|
-
return
|
|
2856
|
+
return path.extname(filePath).toLowerCase();
|
|
2955
2857
|
}
|
|
2956
2858
|
function matchHeadSignatures(headContent, patterns) {
|
|
2957
2859
|
return patterns.some((pattern) => pattern.test(headContent));
|
|
2958
2860
|
}
|
|
2959
2861
|
function matchFilenameSignatures(filePath, patterns) {
|
|
2960
|
-
const filename =
|
|
2862
|
+
const filename = path.basename(filePath);
|
|
2961
2863
|
return patterns.some((pattern) => pattern.test(filename));
|
|
2962
2864
|
}
|
|
2963
2865
|
function matchRequiredFields(headContent, fields) {
|
|
@@ -3105,18 +3007,18 @@ var import_stream_json = __toESM(require_stream_json(), 1);
|
|
|
3105
3007
|
var import_Pick = __toESM(require_Pick(), 1);
|
|
3106
3008
|
var import_StreamValues = __toESM(require_StreamValues(), 1);
|
|
3107
3009
|
var import_stream_chain = __toESM(require_stream_chain(), 1);
|
|
3108
|
-
import * as
|
|
3010
|
+
import * as fs3 from "fs";
|
|
3109
3011
|
|
|
3110
3012
|
// ../../packages/parser/src/utils.ts
|
|
3111
|
-
import * as
|
|
3013
|
+
import * as fs2 from "fs";
|
|
3112
3014
|
function getFileSize(filePath) {
|
|
3113
|
-
return
|
|
3015
|
+
return fs2.statSync(filePath).size;
|
|
3114
3016
|
}
|
|
3115
3017
|
function readFileHeadBytes(filePath, size) {
|
|
3116
|
-
const fd =
|
|
3018
|
+
const fd = fs2.openSync(filePath, "r");
|
|
3117
3019
|
const buffer = Buffer.alloc(size);
|
|
3118
|
-
const bytesRead =
|
|
3119
|
-
|
|
3020
|
+
const bytesRead = fs2.readSync(fd, buffer, 0, size, 0);
|
|
3021
|
+
fs2.closeSync(fd);
|
|
3120
3022
|
return buffer.slice(0, bytesRead).toString("utf-8");
|
|
3121
3023
|
}
|
|
3122
3024
|
var createProgress = (stage, bytesRead, totalBytes, messagesProcessed, message) => {
|
|
@@ -3146,13 +3048,185 @@ function isValidYear(timestampSeconds) {
|
|
|
3146
3048
|
}
|
|
3147
3049
|
|
|
3148
3050
|
// ../../packages/parser/src/formats/chatlab.ts
|
|
3149
|
-
import * as
|
|
3051
|
+
import * as path2 from "path";
|
|
3052
|
+
|
|
3053
|
+
// ../../packages/parser/src/native/loader.ts
|
|
3054
|
+
import { createRequire } from "module";
|
|
3055
|
+
var cachedModule;
|
|
3056
|
+
var cachedLoadError;
|
|
3057
|
+
function isNativeDisabled() {
|
|
3058
|
+
return process.env.CHATLAB_DISABLE_NATIVE_PERF === "1";
|
|
3059
|
+
}
|
|
3060
|
+
function isNativeParserModule(value) {
|
|
3061
|
+
return typeof value?.NativeParser === "function";
|
|
3062
|
+
}
|
|
3063
|
+
function requireNativeModule() {
|
|
3064
|
+
const requireFn = createRequire(import.meta.url);
|
|
3065
|
+
const module = requireFn("@openchatlab/parser-native");
|
|
3066
|
+
if (!isNativeParserModule(module)) {
|
|
3067
|
+
throw new Error("Native parser module missing NativeParser export");
|
|
3068
|
+
}
|
|
3069
|
+
return module;
|
|
3070
|
+
}
|
|
3071
|
+
function loadNativeParser() {
|
|
3072
|
+
if (isNativeDisabled()) return null;
|
|
3073
|
+
if (cachedModule !== void 0) return cachedModule;
|
|
3074
|
+
try {
|
|
3075
|
+
cachedModule = requireNativeModule();
|
|
3076
|
+
} catch (error) {
|
|
3077
|
+
cachedModule = null;
|
|
3078
|
+
cachedLoadError = error instanceof Error ? error.message : String(error);
|
|
3079
|
+
}
|
|
3080
|
+
return cachedModule;
|
|
3081
|
+
}
|
|
3082
|
+
function getNativeParserStatus() {
|
|
3083
|
+
if (isNativeDisabled()) return { available: false, disabled: true };
|
|
3084
|
+
const module = loadNativeParser();
|
|
3085
|
+
return { available: module !== null, disabled: false, error: module ? void 0 : cachedLoadError };
|
|
3086
|
+
}
|
|
3087
|
+
|
|
3088
|
+
// ../../packages/parser/src/native/create-native-parser.ts
|
|
3089
|
+
var PROGRESS_POLL_INTERVAL_MS = 200;
|
|
3090
|
+
async function* pumpNativeParser(adapter, options2, parser11, fallback) {
|
|
3091
|
+
const { filePath, batchSize = 5e3, onProgress, onLog } = options2;
|
|
3092
|
+
const totalBytes = getFileSize(filePath);
|
|
3093
|
+
const initialProgress = createProgress("parsing", 0, totalBytes, 0, "");
|
|
3094
|
+
yield { type: "progress", data: initialProgress };
|
|
3095
|
+
onProgress?.(initialProgress);
|
|
3096
|
+
onLog?.(
|
|
3097
|
+
"info",
|
|
3098
|
+
`[NativeParser] Parsing ${adapter.label} with Rust kernel, size: ${(totalBytes / 1024 / 1024).toFixed(2)} MB`
|
|
3099
|
+
);
|
|
3100
|
+
const progressTimer = setInterval(() => {
|
|
3101
|
+
const progress = parser11.progress();
|
|
3102
|
+
onProgress?.(
|
|
3103
|
+
createProgress(
|
|
3104
|
+
"parsing",
|
|
3105
|
+
progress.bytesRead,
|
|
3106
|
+
totalBytes,
|
|
3107
|
+
progress.messagesProcessed,
|
|
3108
|
+
`\u5DF2\u5904\u7406 ${progress.messagesProcessed} \u6761\u6D88\u606F...`
|
|
3109
|
+
)
|
|
3110
|
+
);
|
|
3111
|
+
}, PROGRESS_POLL_INTERVAL_MS);
|
|
3112
|
+
try {
|
|
3113
|
+
await parser11.parse();
|
|
3114
|
+
} catch (error) {
|
|
3115
|
+
onLog?.(
|
|
3116
|
+
"warn",
|
|
3117
|
+
`[NativeParser] Rust parse failed, falling back to TS parser: ${error instanceof Error ? error.message : String(error)}`
|
|
3118
|
+
);
|
|
3119
|
+
yield* fallback(options2);
|
|
3120
|
+
return;
|
|
3121
|
+
} finally {
|
|
3122
|
+
clearInterval(progressTimer);
|
|
3123
|
+
}
|
|
3124
|
+
const metaJson = JSON.parse(parser11.metaJson());
|
|
3125
|
+
yield { type: "meta", data: adapter.mapMeta(metaJson) };
|
|
3126
|
+
const members = adapter.mapMembers(parser11.takeMembers(), metaJson);
|
|
3127
|
+
yield { type: "members", data: members };
|
|
3128
|
+
let messagesProcessed = 0;
|
|
3129
|
+
while (true) {
|
|
3130
|
+
const batch = parser11.takeBatch(batchSize);
|
|
3131
|
+
if (!batch) break;
|
|
3132
|
+
messagesProcessed += batch.length;
|
|
3133
|
+
yield { type: "messages", data: batch.map((message) => adapter.mapMessage(message, metaJson)) };
|
|
3134
|
+
await new Promise((resolve2) => setImmediate(resolve2));
|
|
3135
|
+
}
|
|
3136
|
+
const doneProgress = createProgress("done", totalBytes, totalBytes, messagesProcessed, "");
|
|
3137
|
+
yield { type: "progress", data: doneProgress };
|
|
3138
|
+
onProgress?.(doneProgress);
|
|
3139
|
+
onLog?.("info", `\u89E3\u6790\u5B8C\u6210: ${messagesProcessed} \u6761\u6D88\u606F, ${members.length} \u4E2A\u6210\u5458`);
|
|
3140
|
+
yield { type: "done", data: { messageCount: messagesProcessed, memberCount: members.length } };
|
|
3141
|
+
}
|
|
3142
|
+
function createNativeFirstParser(adapter, fallback) {
|
|
3143
|
+
return async function* (options2) {
|
|
3144
|
+
const native = loadNativeParser();
|
|
3145
|
+
if (!native) {
|
|
3146
|
+
yield* fallback(options2);
|
|
3147
|
+
return;
|
|
3148
|
+
}
|
|
3149
|
+
let parser11;
|
|
3150
|
+
try {
|
|
3151
|
+
parser11 = new native.NativeParser(
|
|
3152
|
+
adapter.formatId,
|
|
3153
|
+
options2.filePath,
|
|
3154
|
+
options2.formatOptions ? JSON.stringify(options2.formatOptions) : void 0
|
|
3155
|
+
);
|
|
3156
|
+
} catch (error) {
|
|
3157
|
+
options2.onLog?.(
|
|
3158
|
+
"warn",
|
|
3159
|
+
`[NativeParser] Failed to create Rust parser, falling back to TS parser: ${error instanceof Error ? error.message : String(error)}`
|
|
3160
|
+
);
|
|
3161
|
+
yield* fallback(options2);
|
|
3162
|
+
return;
|
|
3163
|
+
}
|
|
3164
|
+
yield* pumpNativeParser(adapter, options2, parser11, fallback);
|
|
3165
|
+
};
|
|
3166
|
+
}
|
|
3167
|
+
|
|
3168
|
+
// ../../packages/parser/src/native/chatlab-native.ts
|
|
3169
|
+
function toParsedMember(member, fromHead) {
|
|
3170
|
+
if (!fromHead) {
|
|
3171
|
+
return {
|
|
3172
|
+
platformId: member.platformId,
|
|
3173
|
+
accountName: member.accountName,
|
|
3174
|
+
groupNickname: member.groupNickname
|
|
3175
|
+
};
|
|
3176
|
+
}
|
|
3177
|
+
return {
|
|
3178
|
+
platformId: member.platformId,
|
|
3179
|
+
accountName: member.accountName,
|
|
3180
|
+
groupNickname: member.groupNickname,
|
|
3181
|
+
avatar: member.avatar,
|
|
3182
|
+
// Role objects pass through with their original key set ({id} or {id, name}).
|
|
3183
|
+
roles: member.roles?.map((role) => role.name !== void 0 ? { id: role.id, name: role.name } : { id: role.id })
|
|
3184
|
+
};
|
|
3185
|
+
}
|
|
3186
|
+
var chatlabAdapter = {
|
|
3187
|
+
formatId: "chatlab",
|
|
3188
|
+
label: "ChatLab JSON",
|
|
3189
|
+
mapMeta(metaJson) {
|
|
3190
|
+
const meta = metaJson;
|
|
3191
|
+
return {
|
|
3192
|
+
name: meta.name,
|
|
3193
|
+
platform: meta.platform,
|
|
3194
|
+
type: meta.chatType,
|
|
3195
|
+
groupId: meta.groupId ?? void 0,
|
|
3196
|
+
groupAvatar: meta.groupAvatar ?? void 0
|
|
3197
|
+
};
|
|
3198
|
+
},
|
|
3199
|
+
mapMembers(members, metaJson) {
|
|
3200
|
+
const fromHead = metaJson.membersFromHead;
|
|
3201
|
+
return members.map((member) => toParsedMember(member, fromHead));
|
|
3202
|
+
},
|
|
3203
|
+
mapMessage(message) {
|
|
3204
|
+
return {
|
|
3205
|
+
senderPlatformId: message.senderPlatformId,
|
|
3206
|
+
senderAccountName: message.senderAccountName,
|
|
3207
|
+
senderGroupNickname: message.senderGroupNickname,
|
|
3208
|
+
// The kernel rejects non-number timestamps, so this is always set.
|
|
3209
|
+
timestamp: message.timestamp,
|
|
3210
|
+
type: message.messageType,
|
|
3211
|
+
// The kernel rejects a missing content key, so undefined here always
|
|
3212
|
+
// means the source value was JSON null.
|
|
3213
|
+
content: message.content ?? null,
|
|
3214
|
+
platformMessageId: message.platformMessageId,
|
|
3215
|
+
replyToMessageId: message.replyToMessageId
|
|
3216
|
+
};
|
|
3217
|
+
}
|
|
3218
|
+
};
|
|
3219
|
+
function withNativeChatlab(fallback) {
|
|
3220
|
+
return createNativeFirstParser(chatlabAdapter, fallback);
|
|
3221
|
+
}
|
|
3222
|
+
|
|
3223
|
+
// ../../packages/parser/src/formats/chatlab.ts
|
|
3150
3224
|
var { parser } = import_stream_json.default;
|
|
3151
3225
|
var { pick } = import_Pick.default;
|
|
3152
3226
|
var { streamValues } = import_StreamValues.default;
|
|
3153
3227
|
var { chain } = import_stream_chain.default;
|
|
3154
3228
|
function extractNameFromFilePath(filePath) {
|
|
3155
|
-
const basename13 =
|
|
3229
|
+
const basename13 = path2.basename(filePath);
|
|
3156
3230
|
const name = basename13.replace(/\.json$/i, "");
|
|
3157
3231
|
return name || "\u672A\u77E5\u7FA4\u804A";
|
|
3158
3232
|
}
|
|
@@ -3241,7 +3315,7 @@ async function* parseChatLab(options2) {
|
|
|
3241
3315
|
const memberMapFromMessages = /* @__PURE__ */ new Map();
|
|
3242
3316
|
const messageBatch = [];
|
|
3243
3317
|
await new Promise((resolve2, reject) => {
|
|
3244
|
-
const readStream =
|
|
3318
|
+
const readStream = fs3.createReadStream(filePath, { encoding: "utf-8" });
|
|
3245
3319
|
readStream.on("data", (chunk) => {
|
|
3246
3320
|
bytesRead += typeof chunk === "string" ? Buffer.byteLength(chunk) : chunk.length;
|
|
3247
3321
|
});
|
|
@@ -3310,9 +3384,10 @@ async function* parseChatLab(options2) {
|
|
|
3310
3384
|
}
|
|
3311
3385
|
};
|
|
3312
3386
|
}
|
|
3387
|
+
var parseChatLabAccelerated = withNativeChatlab(parseChatLab);
|
|
3313
3388
|
var parser_ = {
|
|
3314
3389
|
feature,
|
|
3315
|
-
parse:
|
|
3390
|
+
parse: parseChatLabAccelerated
|
|
3316
3391
|
};
|
|
3317
3392
|
var module_ = {
|
|
3318
3393
|
feature,
|
|
@@ -3321,11 +3396,11 @@ var module_ = {
|
|
|
3321
3396
|
var chatlab_default = module_;
|
|
3322
3397
|
|
|
3323
3398
|
// ../../packages/parser/src/formats/chatlab-jsonl.ts
|
|
3324
|
-
import * as
|
|
3399
|
+
import * as fs4 from "fs";
|
|
3325
3400
|
import * as readline from "readline";
|
|
3326
|
-
import * as
|
|
3401
|
+
import * as path3 from "path";
|
|
3327
3402
|
function extractNameFromFilePath2(filePath) {
|
|
3328
|
-
const basename13 =
|
|
3403
|
+
const basename13 = path3.basename(filePath);
|
|
3329
3404
|
const name = basename13.replace(/\.jsonl$/i, "");
|
|
3330
3405
|
return name || "\u672A\u77E5\u7FA4\u804A";
|
|
3331
3406
|
}
|
|
@@ -3366,7 +3441,7 @@ async function* parseChatLabJsonl(options2) {
|
|
|
3366
3441
|
const messageBatch = [];
|
|
3367
3442
|
let meta = null;
|
|
3368
3443
|
let headerParsed = false;
|
|
3369
|
-
const fileStream =
|
|
3444
|
+
const fileStream = fs4.createReadStream(filePath, { encoding: "utf-8" });
|
|
3370
3445
|
const rl = readline.createInterface({
|
|
3371
3446
|
input: fileStream,
|
|
3372
3447
|
crlfDelay: Infinity
|
|
@@ -3489,16 +3564,16 @@ var import_stream_json3 = __toESM(require_stream_json(), 1);
|
|
|
3489
3564
|
var import_Pick3 = __toESM(require_Pick(), 1);
|
|
3490
3565
|
var import_StreamValues3 = __toESM(require_StreamValues(), 1);
|
|
3491
3566
|
var import_stream_chain3 = __toESM(require_stream_chain(), 1);
|
|
3492
|
-
import * as
|
|
3493
|
-
import * as
|
|
3567
|
+
import * as fs6 from "fs";
|
|
3568
|
+
import * as path5 from "path";
|
|
3494
3569
|
|
|
3495
3570
|
// ../../packages/parser/src/formats/shuakami-qq-preprocessor.ts
|
|
3496
3571
|
var import_stream_json2 = __toESM(require_stream_json(), 1);
|
|
3497
3572
|
var import_Pick2 = __toESM(require_Pick(), 1);
|
|
3498
3573
|
var import_StreamValues2 = __toESM(require_StreamValues(), 1);
|
|
3499
3574
|
var import_stream_chain2 = __toESM(require_stream_chain(), 1);
|
|
3500
|
-
import * as
|
|
3501
|
-
import * as
|
|
3575
|
+
import * as fs5 from "fs";
|
|
3576
|
+
import * as path4 from "path";
|
|
3502
3577
|
import * as os from "os";
|
|
3503
3578
|
var { parser: parser3 } = import_stream_json2.default;
|
|
3504
3579
|
var { pick: pick2 } = import_Pick2.default;
|
|
@@ -3506,11 +3581,11 @@ var { streamValues: streamValues2 } = import_StreamValues2.default;
|
|
|
3506
3581
|
var { chain: chain2 } = import_stream_chain2.default;
|
|
3507
3582
|
var PREPROCESS_THRESHOLD = 50 * 1024 * 1024;
|
|
3508
3583
|
function getTempDir() {
|
|
3509
|
-
return
|
|
3584
|
+
return path4.join(os.tmpdir(), "chatlab");
|
|
3510
3585
|
}
|
|
3511
3586
|
function ensureDir(dir) {
|
|
3512
|
-
if (!
|
|
3513
|
-
|
|
3587
|
+
if (!fs5.existsSync(dir)) {
|
|
3588
|
+
fs5.mkdirSync(dir, { recursive: true });
|
|
3514
3589
|
}
|
|
3515
3590
|
}
|
|
3516
3591
|
function extractJsonObject(content, key) {
|
|
@@ -3552,12 +3627,12 @@ function extractJsonObject(content, key) {
|
|
|
3552
3627
|
}
|
|
3553
3628
|
function readAvatarsFromFile(filePath) {
|
|
3554
3629
|
try {
|
|
3555
|
-
const stats =
|
|
3630
|
+
const stats = fs5.statSync(filePath);
|
|
3556
3631
|
const tailSize = Math.min(stats.size, 5e6);
|
|
3557
|
-
const fd =
|
|
3632
|
+
const fd = fs5.openSync(filePath, "r");
|
|
3558
3633
|
const buffer = Buffer.alloc(tailSize);
|
|
3559
|
-
|
|
3560
|
-
|
|
3634
|
+
fs5.readSync(fd, buffer, 0, tailSize, stats.size - tailSize);
|
|
3635
|
+
fs5.closeSync(fd);
|
|
3561
3636
|
const tailContent = buffer.toString("utf-8");
|
|
3562
3637
|
return extractJsonObject(tailContent, "avatars");
|
|
3563
3638
|
} catch {
|
|
@@ -3616,15 +3691,15 @@ async function preprocessQQJson(inputPath, onProgress) {
|
|
|
3616
3691
|
let messagesProcessed = 0;
|
|
3617
3692
|
const tempDir = getTempDir();
|
|
3618
3693
|
ensureDir(tempDir);
|
|
3619
|
-
const outputFilename = `slim_${Date.now()}_${
|
|
3620
|
-
const outputPath =
|
|
3694
|
+
const outputFilename = `slim_${Date.now()}_${path4.basename(inputPath)}`;
|
|
3695
|
+
const outputPath = path4.join(tempDir, outputFilename);
|
|
3621
3696
|
onProgress?.(createProgress("parsing", 0, totalBytes, 0, ""));
|
|
3622
3697
|
const avatarsStr = readAvatarsFromFile(inputPath);
|
|
3623
3698
|
return new Promise((resolve2, reject) => {
|
|
3624
3699
|
const headChunks = [];
|
|
3625
3700
|
let headSize = 0;
|
|
3626
3701
|
const maxHeadSize = 1e5;
|
|
3627
|
-
const headStream =
|
|
3702
|
+
const headStream = fs5.createReadStream(inputPath, { encoding: "utf-8" });
|
|
3628
3703
|
let chatInfo = { name: "\u672A\u77E5\u7FA4\u804A", type: "group" };
|
|
3629
3704
|
let metadata;
|
|
3630
3705
|
let statistics;
|
|
@@ -3661,8 +3736,8 @@ async function preprocessQQJson(inputPath, onProgress) {
|
|
|
3661
3736
|
} catch {
|
|
3662
3737
|
}
|
|
3663
3738
|
onProgress?.(createProgress("parsing", 0, totalBytes, 0, ""));
|
|
3664
|
-
const readStream =
|
|
3665
|
-
const writeStream =
|
|
3739
|
+
const readStream = fs5.createReadStream(inputPath, { encoding: "utf-8" });
|
|
3740
|
+
const writeStream = fs5.createWriteStream(outputPath, { encoding: "utf-8" });
|
|
3666
3741
|
readStream.on("data", (chunk) => {
|
|
3667
3742
|
bytesRead += typeof chunk === "string" ? Buffer.byteLength(chunk) : chunk.length;
|
|
3668
3743
|
});
|
|
@@ -3707,8 +3782,8 @@ async function preprocessQQJson(inputPath, onProgress) {
|
|
|
3707
3782
|
});
|
|
3708
3783
|
pipeline2.on("error", (err) => {
|
|
3709
3784
|
writeStream.destroy();
|
|
3710
|
-
if (
|
|
3711
|
-
|
|
3785
|
+
if (fs5.existsSync(outputPath)) {
|
|
3786
|
+
fs5.unlinkSync(outputPath);
|
|
3712
3787
|
}
|
|
3713
3788
|
onProgress?.(createProgress("error", bytesRead, totalBytes, messagesProcessed, err.message));
|
|
3714
3789
|
reject(err);
|
|
@@ -3719,8 +3794,8 @@ async function preprocessQQJson(inputPath, onProgress) {
|
|
|
3719
3794
|
}
|
|
3720
3795
|
function cleanupTempFile(filePath) {
|
|
3721
3796
|
try {
|
|
3722
|
-
if (
|
|
3723
|
-
|
|
3797
|
+
if (fs5.existsSync(filePath) && filePath.includes(getTempDir())) {
|
|
3798
|
+
fs5.unlinkSync(filePath);
|
|
3724
3799
|
}
|
|
3725
3800
|
} catch {
|
|
3726
3801
|
}
|
|
@@ -3787,7 +3862,7 @@ function extractJsonObject2(content, key) {
|
|
|
3787
3862
|
return null;
|
|
3788
3863
|
}
|
|
3789
3864
|
function extractNameFromFilePath3(filePath) {
|
|
3790
|
-
const basename13 =
|
|
3865
|
+
const basename13 = path5.basename(filePath);
|
|
3791
3866
|
return basename13.replace(/\.json$/i, "") || "\u672A\u77E5\u7FA4\u804A";
|
|
3792
3867
|
}
|
|
3793
3868
|
function countSenders(content) {
|
|
@@ -3872,7 +3947,7 @@ async function* parseV4(options2) {
|
|
|
3872
3947
|
const memberMap = /* @__PURE__ */ new Map();
|
|
3873
3948
|
const messageBatch = [];
|
|
3874
3949
|
await new Promise((resolve2, reject) => {
|
|
3875
|
-
const readStream =
|
|
3950
|
+
const readStream = fs6.createReadStream(filePath, { encoding: "utf-8" });
|
|
3876
3951
|
readStream.on("data", (chunk) => {
|
|
3877
3952
|
bytesRead += typeof chunk === "string" ? Buffer.byteLength(chunk) : chunk.length;
|
|
3878
3953
|
});
|
|
@@ -3930,12 +4005,12 @@ async function* parseV4(options2) {
|
|
|
3930
4005
|
});
|
|
3931
4006
|
const avatarsMap = /* @__PURE__ */ new Map();
|
|
3932
4007
|
try {
|
|
3933
|
-
const stats =
|
|
4008
|
+
const stats = fs6.statSync(filePath);
|
|
3934
4009
|
const tailSize = Math.min(stats.size, 5e6);
|
|
3935
|
-
const fd =
|
|
4010
|
+
const fd = fs6.openSync(filePath, "r");
|
|
3936
4011
|
const buffer = Buffer.alloc(tailSize);
|
|
3937
|
-
|
|
3938
|
-
|
|
4012
|
+
fs6.readSync(fd, buffer, 0, tailSize, stats.size - tailSize);
|
|
4013
|
+
fs6.closeSync(fd);
|
|
3939
4014
|
const tailContent = buffer.toString("utf-8");
|
|
3940
4015
|
const avatarsStr = extractJsonObject2(tailContent, "avatars");
|
|
3941
4016
|
if (avatarsStr) {
|
|
@@ -3987,8 +4062,8 @@ var module_3 = {
|
|
|
3987
4062
|
var shuakami_qq_exporter_default = module_3;
|
|
3988
4063
|
|
|
3989
4064
|
// ../../packages/parser/src/formats/shuakami-qq-exporter-chunked.ts
|
|
3990
|
-
import * as
|
|
3991
|
-
import * as
|
|
4065
|
+
import * as fs7 from "fs";
|
|
4066
|
+
import * as path6 from "path";
|
|
3992
4067
|
import * as readline2 from "readline";
|
|
3993
4068
|
var feature4 = {
|
|
3994
4069
|
id: "shuakami-qq-exporter-chunked",
|
|
@@ -4037,7 +4112,7 @@ function convertMessageType2(msgType, content, isRecalled) {
|
|
|
4037
4112
|
return 0 /* TEXT */;
|
|
4038
4113
|
}
|
|
4039
4114
|
function readManifest(manifestPath) {
|
|
4040
|
-
const content =
|
|
4115
|
+
const content = fs7.readFileSync(manifestPath, "utf-8");
|
|
4041
4116
|
return JSON.parse(content);
|
|
4042
4117
|
}
|
|
4043
4118
|
function getChunkRelativePath(chunk) {
|
|
@@ -4055,9 +4130,9 @@ function calculateTotalBytes(manifest, baseDir) {
|
|
|
4055
4130
|
let total = 0;
|
|
4056
4131
|
for (const chunk of manifest.chunked.chunks) {
|
|
4057
4132
|
const relativePath = getChunkRelativePath(chunk);
|
|
4058
|
-
const chunkPath =
|
|
4059
|
-
if (
|
|
4060
|
-
total +=
|
|
4133
|
+
const chunkPath = path6.join(baseDir, relativePath);
|
|
4134
|
+
if (fs7.existsSync(chunkPath)) {
|
|
4135
|
+
total += fs7.statSync(chunkPath).size;
|
|
4061
4136
|
}
|
|
4062
4137
|
}
|
|
4063
4138
|
return total;
|
|
@@ -4065,10 +4140,10 @@ function calculateTotalBytes(manifest, baseDir) {
|
|
|
4065
4140
|
function readAvatars(baseDir, avatarsInfo) {
|
|
4066
4141
|
const avatarsMap = /* @__PURE__ */ new Map();
|
|
4067
4142
|
if (!avatarsInfo?.file) return avatarsMap;
|
|
4068
|
-
const avatarsPath =
|
|
4069
|
-
if (!
|
|
4143
|
+
const avatarsPath = path6.join(baseDir, avatarsInfo.file);
|
|
4144
|
+
if (!fs7.existsSync(avatarsPath)) return avatarsMap;
|
|
4070
4145
|
try {
|
|
4071
|
-
const content =
|
|
4146
|
+
const content = fs7.readFileSync(avatarsPath, "utf-8");
|
|
4072
4147
|
const avatars = JSON.parse(content);
|
|
4073
4148
|
for (const [uin, avatar] of Object.entries(avatars)) {
|
|
4074
4149
|
if (avatar && typeof avatar === "string" && avatar.startsWith("data:image/")) {
|
|
@@ -4086,7 +4161,7 @@ async function* readJsonlFile(filePath, onParseError) {
|
|
|
4086
4161
|
let parseErrorCount = 0;
|
|
4087
4162
|
const MAX_PARSE_ERRORS_TO_LOG = 10;
|
|
4088
4163
|
try {
|
|
4089
|
-
fileStream =
|
|
4164
|
+
fileStream = fs7.createReadStream(filePath, { encoding: "utf-8" });
|
|
4090
4165
|
rl = readline2.createInterface({
|
|
4091
4166
|
input: fileStream,
|
|
4092
4167
|
crlfDelay: Infinity
|
|
@@ -4117,7 +4192,7 @@ async function* readJsonlFile(filePath, onParseError) {
|
|
|
4117
4192
|
async function* parseChunkedJsonl(options2) {
|
|
4118
4193
|
const { filePath, batchSize = 5e3, onProgress, onLog } = options2;
|
|
4119
4194
|
const manifestPath = filePath;
|
|
4120
|
-
const baseDir =
|
|
4195
|
+
const baseDir = path6.dirname(manifestPath);
|
|
4121
4196
|
onLog?.("info", `\u5F00\u59CB\u89E3\u6790 manifest: ${manifestPath}`);
|
|
4122
4197
|
onLog?.("info", `\u57FA\u7840\u76EE\u5F55: ${baseDir}`);
|
|
4123
4198
|
let manifest;
|
|
@@ -4171,13 +4246,13 @@ async function* parseChunkedJsonl(options2) {
|
|
|
4171
4246
|
for (let chunkIndex = 0; chunkIndex < manifest.chunked.chunks.length; chunkIndex++) {
|
|
4172
4247
|
const chunkInfo = manifest.chunked.chunks[chunkIndex];
|
|
4173
4248
|
const relativePath = getChunkRelativePath(chunkInfo);
|
|
4174
|
-
const chunkPath =
|
|
4249
|
+
const chunkPath = path6.join(baseDir, relativePath);
|
|
4175
4250
|
const chunkMessageCount = getChunkMessageCount(chunkInfo);
|
|
4176
|
-
if (!
|
|
4251
|
+
if (!fs7.existsSync(chunkPath)) {
|
|
4177
4252
|
onLog?.("error", `\u5206\u5757\u6587\u4EF6\u4E0D\u5B58\u5728: ${chunkPath}`);
|
|
4178
4253
|
continue;
|
|
4179
4254
|
}
|
|
4180
|
-
const chunkSize =
|
|
4255
|
+
const chunkSize = fs7.statSync(chunkPath).size;
|
|
4181
4256
|
let chunkMessagesRead = 0;
|
|
4182
4257
|
let chunkParseErrors = 0;
|
|
4183
4258
|
onLog?.(
|
|
@@ -4299,8 +4374,49 @@ var import_stream_json4 = __toESM(require_stream_json(), 1);
|
|
|
4299
4374
|
var import_Pick4 = __toESM(require_Pick(), 1);
|
|
4300
4375
|
var import_StreamValues4 = __toESM(require_StreamValues(), 1);
|
|
4301
4376
|
var import_stream_chain4 = __toESM(require_stream_chain(), 1);
|
|
4302
|
-
import * as
|
|
4303
|
-
import * as
|
|
4377
|
+
import * as fs8 from "fs";
|
|
4378
|
+
import * as path7 from "path";
|
|
4379
|
+
|
|
4380
|
+
// ../../packages/parser/src/native/weflow-native.ts
|
|
4381
|
+
var weflowAdapter = {
|
|
4382
|
+
formatId: "weflow",
|
|
4383
|
+
label: "WeFlow export",
|
|
4384
|
+
mapMeta(metaJson) {
|
|
4385
|
+
const meta = metaJson;
|
|
4386
|
+
return {
|
|
4387
|
+
name: meta.name,
|
|
4388
|
+
platform: KNOWN_PLATFORMS.WECHAT,
|
|
4389
|
+
type: meta.chatType === "private" ? "private" /* PRIVATE */ : "group" /* GROUP */,
|
|
4390
|
+
groupId: meta.groupId ?? void 0,
|
|
4391
|
+
groupAvatar: meta.groupAvatar ?? void 0,
|
|
4392
|
+
ownerId: meta.ownerId ?? void 0
|
|
4393
|
+
};
|
|
4394
|
+
},
|
|
4395
|
+
mapMembers(members) {
|
|
4396
|
+
return members.map((member) => ({
|
|
4397
|
+
platformId: member.platformId,
|
|
4398
|
+
accountName: member.accountName,
|
|
4399
|
+
avatar: member.avatar
|
|
4400
|
+
}));
|
|
4401
|
+
},
|
|
4402
|
+
mapMessage(message) {
|
|
4403
|
+
return {
|
|
4404
|
+
// The kernel always emits an id string (String(localId), JS semantics).
|
|
4405
|
+
platformMessageId: message.platformMessageId,
|
|
4406
|
+
senderPlatformId: message.senderPlatformId,
|
|
4407
|
+
senderAccountName: message.senderAccountName,
|
|
4408
|
+
// WeFlow has no separate group nickname field (same as the TS parser).
|
|
4409
|
+
senderGroupNickname: void 0,
|
|
4410
|
+
// The TS parser passes createTime through as-is, including null.
|
|
4411
|
+
timestamp: message.timestamp ?? null,
|
|
4412
|
+
type: message.messageType,
|
|
4413
|
+
content: message.content ?? null
|
|
4414
|
+
};
|
|
4415
|
+
}
|
|
4416
|
+
};
|
|
4417
|
+
function withNativeWeflow(fallback) {
|
|
4418
|
+
return createNativeFirstParser(weflowAdapter, fallback);
|
|
4419
|
+
}
|
|
4304
4420
|
|
|
4305
4421
|
// ../../packages/parser/src/formats/weflow-preprocessor.ts
|
|
4306
4422
|
var weflowPreprocessor = {
|
|
@@ -4332,7 +4448,7 @@ var { pick: pick4 } = import_Pick4.default;
|
|
|
4332
4448
|
var { streamValues: streamValues4 } = import_StreamValues4.default;
|
|
4333
4449
|
var { chain: chain4 } = import_stream_chain4.default;
|
|
4334
4450
|
function extractNameFromFilePath4(filePath) {
|
|
4335
|
-
const basename13 =
|
|
4451
|
+
const basename13 = path7.basename(filePath);
|
|
4336
4452
|
const name = basename13.replace(/\.json$/i, "");
|
|
4337
4453
|
return name || "\u672A\u77E5\u804A\u5929";
|
|
4338
4454
|
}
|
|
@@ -4401,7 +4517,7 @@ async function* parseWeFlow(options2) {
|
|
|
4401
4517
|
let session = null;
|
|
4402
4518
|
try {
|
|
4403
4519
|
await new Promise((resolve2) => {
|
|
4404
|
-
const sessionStream =
|
|
4520
|
+
const sessionStream = fs8.createReadStream(filePath, { encoding: "utf-8" });
|
|
4405
4521
|
let sessionContent = "";
|
|
4406
4522
|
let inSession = false;
|
|
4407
4523
|
let braceDepth = 0;
|
|
@@ -4524,7 +4640,7 @@ async function* parseWeFlow(options2) {
|
|
|
4524
4640
|
if (avatarsMap.size === 0) {
|
|
4525
4641
|
try {
|
|
4526
4642
|
await new Promise((resolve2) => {
|
|
4527
|
-
const avatarStream =
|
|
4643
|
+
const avatarStream = fs8.createReadStream(filePath, { encoding: "utf-8" });
|
|
4528
4644
|
let avatarsContent = "";
|
|
4529
4645
|
let inAvatars = false;
|
|
4530
4646
|
let braceDepth = 0;
|
|
@@ -4591,7 +4707,7 @@ async function* parseWeFlow(options2) {
|
|
|
4591
4707
|
let ownerId;
|
|
4592
4708
|
try {
|
|
4593
4709
|
await new Promise((resolve2) => {
|
|
4594
|
-
const scanStream =
|
|
4710
|
+
const scanStream = fs8.createReadStream(filePath, { encoding: "utf-8" });
|
|
4595
4711
|
const scanPipeline = chain4([scanStream, parser5(), pick4({ filter: /^messages\.\d+$/ }), streamValues4()]);
|
|
4596
4712
|
scanPipeline.on("data", ({ value }) => {
|
|
4597
4713
|
if (value.isSend === 1 && value.senderUsername && !value.senderUsername.endsWith("@chatroom")) {
|
|
@@ -4617,7 +4733,7 @@ async function* parseWeFlow(options2) {
|
|
|
4617
4733
|
const memberMap = /* @__PURE__ */ new Map();
|
|
4618
4734
|
const messageBatch = [];
|
|
4619
4735
|
await new Promise((resolve2, reject) => {
|
|
4620
|
-
const readStream =
|
|
4736
|
+
const readStream = fs8.createReadStream(filePath, { encoding: "utf-8" });
|
|
4621
4737
|
readStream.on("data", (chunk) => {
|
|
4622
4738
|
bytesRead += typeof chunk === "string" ? Buffer.byteLength(chunk) : chunk.length;
|
|
4623
4739
|
});
|
|
@@ -4712,9 +4828,10 @@ async function* parseWeFlow(options2) {
|
|
|
4712
4828
|
data: { messageCount: messagesProcessed, memberCount: memberMap.size }
|
|
4713
4829
|
};
|
|
4714
4830
|
}
|
|
4831
|
+
var parseWeFlowAccelerated = withNativeWeflow(parseWeFlow);
|
|
4715
4832
|
var parser_4 = {
|
|
4716
4833
|
feature: feature5,
|
|
4717
|
-
parse:
|
|
4834
|
+
parse: parseWeFlowAccelerated
|
|
4718
4835
|
};
|
|
4719
4836
|
var module_5 = {
|
|
4720
4837
|
feature: feature5,
|
|
@@ -4739,7 +4856,7 @@ var feature6 = {
|
|
|
4739
4856
|
};
|
|
4740
4857
|
var parser_5 = {
|
|
4741
4858
|
feature: feature6,
|
|
4742
|
-
parse:
|
|
4859
|
+
parse: parseWeFlowAccelerated
|
|
4743
4860
|
};
|
|
4744
4861
|
var module_6 = {
|
|
4745
4862
|
feature: feature6,
|
|
@@ -4753,7 +4870,7 @@ var import_stream_json5 = __toESM(require_stream_json(), 1);
|
|
|
4753
4870
|
var import_Pick5 = __toESM(require_Pick(), 1);
|
|
4754
4871
|
var import_StreamValues5 = __toESM(require_StreamValues(), 1);
|
|
4755
4872
|
var import_stream_chain5 = __toESM(require_stream_chain(), 1);
|
|
4756
|
-
import * as
|
|
4873
|
+
import * as fs9 from "fs";
|
|
4757
4874
|
var { parser: parser6 } = import_stream_json5.default;
|
|
4758
4875
|
var { pick: pick5 } = import_Pick5.default;
|
|
4759
4876
|
var { streamValues: streamValues5 } = import_StreamValues5.default;
|
|
@@ -4903,7 +5020,7 @@ async function* parseDiscordExporter(options2) {
|
|
|
4903
5020
|
const memberMap = /* @__PURE__ */ new Map();
|
|
4904
5021
|
const messageBatch = [];
|
|
4905
5022
|
await new Promise((resolve2, reject) => {
|
|
4906
|
-
const readStream =
|
|
5023
|
+
const readStream = fs9.createReadStream(filePath, { encoding: "utf-8" });
|
|
4907
5024
|
readStream.on("data", (chunk) => {
|
|
4908
5025
|
bytesRead += typeof chunk === "string" ? Buffer.byteLength(chunk) : chunk.length;
|
|
4909
5026
|
});
|
|
@@ -5019,7 +5136,7 @@ var import_stream_chain6 = __toESM(require_stream_chain(), 1);
|
|
|
5019
5136
|
var import_stream_json6 = __toESM(require_stream_json(), 1);
|
|
5020
5137
|
var import_Pick6 = __toESM(require_Pick(), 1);
|
|
5021
5138
|
var import_StreamValues6 = __toESM(require_StreamValues(), 1);
|
|
5022
|
-
import * as
|
|
5139
|
+
import * as fs10 from "fs";
|
|
5023
5140
|
|
|
5024
5141
|
// ../../packages/parser/src/formats/utils/telegram-utils.ts
|
|
5025
5142
|
function mapChatType(telegramType) {
|
|
@@ -5105,7 +5222,7 @@ var feature8 = {
|
|
|
5105
5222
|
async function scanChats(filePath) {
|
|
5106
5223
|
const chats = [];
|
|
5107
5224
|
return new Promise((resolve2, reject) => {
|
|
5108
|
-
const readStream =
|
|
5225
|
+
const readStream = fs10.createReadStream(filePath, { encoding: "utf-8" });
|
|
5109
5226
|
const pipeline2 = chain6([readStream, parser7(), pick6({ filter: /^chats\.list\.\d+$/ }), streamValues6()]);
|
|
5110
5227
|
pipeline2.on("data", ({ value }) => {
|
|
5111
5228
|
const chat = value;
|
|
@@ -5138,7 +5255,7 @@ async function* parseTelegram(options2) {
|
|
|
5138
5255
|
onLog?.("info", `\u76EE\u6807\u804A\u5929\u7D22\u5F15: ${chatIndex}`);
|
|
5139
5256
|
const chatPathFilter = `chats.list.${chatIndex}`;
|
|
5140
5257
|
const chatData = await new Promise((resolve2, reject) => {
|
|
5141
|
-
const readStream =
|
|
5258
|
+
const readStream = fs10.createReadStream(filePath, { encoding: "utf-8" });
|
|
5142
5259
|
readStream.on("data", (chunk) => {
|
|
5143
5260
|
bytesRead += typeof chunk === "string" ? Buffer.byteLength(chunk) : chunk.length;
|
|
5144
5261
|
});
|
|
@@ -5246,7 +5363,7 @@ var telegram_native_default = module_8;
|
|
|
5246
5363
|
var import_stream_chain7 = __toESM(require_stream_chain(), 1);
|
|
5247
5364
|
var import_stream_json7 = __toESM(require_stream_json(), 1);
|
|
5248
5365
|
var import_StreamValues7 = __toESM(require_StreamValues(), 1);
|
|
5249
|
-
import * as
|
|
5366
|
+
import * as fs11 from "fs";
|
|
5250
5367
|
var { chain: chain7 } = import_stream_chain7.default;
|
|
5251
5368
|
var { parser: parser8 } = import_stream_json7.default;
|
|
5252
5369
|
var { streamValues: streamValues7 } = import_StreamValues7.default;
|
|
@@ -5276,7 +5393,7 @@ async function* parseTelegramSingle(options2) {
|
|
|
5276
5393
|
onProgress?.(initialProgress);
|
|
5277
5394
|
onLog?.("info", `\u5F00\u59CB\u89E3\u6790 Telegram \u5355\u804A\u5929 JSON \u6587\u4EF6\uFF0C\u5927\u5C0F: ${(totalBytes / 1024 / 1024).toFixed(2)} MB`);
|
|
5278
5395
|
const chatData = await new Promise((resolve2, reject) => {
|
|
5279
|
-
const readStream =
|
|
5396
|
+
const readStream = fs11.createReadStream(filePath, { encoding: "utf-8" });
|
|
5280
5397
|
const pipeline2 = chain7([readStream, parser8(), streamValues7()]);
|
|
5281
5398
|
let found = false;
|
|
5282
5399
|
pipeline2.on("data", ({ value }) => {
|
|
@@ -5374,11 +5491,11 @@ var module_9 = {
|
|
|
5374
5491
|
var telegram_native_single_default = module_9;
|
|
5375
5492
|
|
|
5376
5493
|
// ../../packages/parser/src/formats/whatsapp-native-txt.ts
|
|
5377
|
-
import * as
|
|
5378
|
-
import * as
|
|
5494
|
+
import * as fs12 from "fs";
|
|
5495
|
+
import * as path8 from "path";
|
|
5379
5496
|
import * as readline3 from "readline";
|
|
5380
5497
|
function extractNameFromFilePath5(filePath) {
|
|
5381
|
-
const basename13 =
|
|
5498
|
+
const basename13 = path8.basename(filePath);
|
|
5382
5499
|
const matchZhCn = basename13.match(/^与(.+?)的\s*WhatsApp\s*聊天\.txt$/i);
|
|
5383
5500
|
if (matchZhCn) return matchZhCn[1].trim();
|
|
5384
5501
|
const matchZhTw = basename13.match(/^與(.+?)的\s*WhatsApp\s*對話\.txt$/i);
|
|
@@ -5582,7 +5699,7 @@ async function* parseWhatsApp(options2) {
|
|
|
5582
5699
|
messagesProcessed++;
|
|
5583
5700
|
}
|
|
5584
5701
|
};
|
|
5585
|
-
const fileStream =
|
|
5702
|
+
const fileStream = fs12.createReadStream(filePath, { encoding: "utf-8" });
|
|
5586
5703
|
const rl = readline3.createInterface({
|
|
5587
5704
|
input: fileStream,
|
|
5588
5705
|
crlfDelay: Infinity
|
|
@@ -5702,11 +5819,11 @@ var module_10 = {
|
|
|
5702
5819
|
var whatsapp_native_txt_default = module_10;
|
|
5703
5820
|
|
|
5704
5821
|
// ../../packages/parser/src/formats/qq-native-txt.ts
|
|
5705
|
-
import * as
|
|
5706
|
-
import * as
|
|
5822
|
+
import * as fs13 from "fs";
|
|
5823
|
+
import * as path9 from "path";
|
|
5707
5824
|
import * as readline4 from "readline";
|
|
5708
5825
|
function extractNameFromFilePath6(filePath) {
|
|
5709
|
-
const basename13 =
|
|
5826
|
+
const basename13 = path9.basename(filePath);
|
|
5710
5827
|
const name = basename13.replace(/\.txt$/i, "");
|
|
5711
5828
|
return name || "\u672A\u77E5\u7FA4\u804A";
|
|
5712
5829
|
}
|
|
@@ -5788,7 +5905,7 @@ async function* parseTxt(options2) {
|
|
|
5788
5905
|
messagesProcessed++;
|
|
5789
5906
|
}
|
|
5790
5907
|
};
|
|
5791
|
-
const fileStream =
|
|
5908
|
+
const fileStream = fs13.createReadStream(filePath, { encoding: "utf-8" });
|
|
5792
5909
|
const rl = readline4.createInterface({
|
|
5793
5910
|
input: fileStream,
|
|
5794
5911
|
crlfDelay: Infinity
|
|
@@ -5888,8 +6005,8 @@ var module_11 = {
|
|
|
5888
6005
|
var qq_native_txt_default = module_11;
|
|
5889
6006
|
|
|
5890
6007
|
// ../../packages/parser/src/formats/instagram-native.ts
|
|
5891
|
-
import * as
|
|
5892
|
-
import * as
|
|
6008
|
+
import * as fs14 from "fs";
|
|
6009
|
+
import * as path10 from "path";
|
|
5893
6010
|
var feature12 = {
|
|
5894
6011
|
id: "instagram-native",
|
|
5895
6012
|
name: "Instagram \u5B98\u65B9\u5BFC\u51FA",
|
|
@@ -5915,7 +6032,7 @@ function decodeInstagramText(text) {
|
|
|
5915
6032
|
}
|
|
5916
6033
|
}
|
|
5917
6034
|
function extractNameFromFilePath7(filePath) {
|
|
5918
|
-
const basename13 =
|
|
6035
|
+
const basename13 = path10.basename(filePath);
|
|
5919
6036
|
return basename13.replace(/\.json$/i, "") || "\u672A\u77E5\u5BF9\u8BDD";
|
|
5920
6037
|
}
|
|
5921
6038
|
function isSystemMessage2(content) {
|
|
@@ -5984,7 +6101,7 @@ async function* parseInstagram(options2) {
|
|
|
5984
6101
|
onLog?.("info", `\u5F00\u59CB\u89E3\u6790 Instagram \u804A\u5929\u8BB0\u5F55\uFF0C\u5927\u5C0F: ${(totalBytes / 1024 / 1024).toFixed(2)} MB`);
|
|
5985
6102
|
let data;
|
|
5986
6103
|
try {
|
|
5987
|
-
const content =
|
|
6104
|
+
const content = fs14.readFileSync(filePath, "utf-8");
|
|
5988
6105
|
data = JSON.parse(content);
|
|
5989
6106
|
} catch (error) {
|
|
5990
6107
|
const err = new Error(`\u65E0\u6CD5\u89E3\u6790 Instagram JSON \u6587\u4EF6: ${error}`);
|
|
@@ -6079,8 +6196,8 @@ var import_stream_chain8 = __toESM(require_stream_chain(), 1);
|
|
|
6079
6196
|
var import_stream_json8 = __toESM(require_stream_json(), 1);
|
|
6080
6197
|
var import_Pick7 = __toESM(require_Pick(), 1);
|
|
6081
6198
|
var import_StreamValues8 = __toESM(require_StreamValues(), 1);
|
|
6082
|
-
import * as
|
|
6083
|
-
import * as
|
|
6199
|
+
import * as fs15 from "fs";
|
|
6200
|
+
import * as path11 from "path";
|
|
6084
6201
|
var { chain: chain8 } = import_stream_chain8.default;
|
|
6085
6202
|
var { parser: parser9 } = import_stream_json8.default;
|
|
6086
6203
|
var { pick: pick7 } = import_Pick7.default;
|
|
@@ -6163,12 +6280,12 @@ function normalizeIdentity(user) {
|
|
|
6163
6280
|
};
|
|
6164
6281
|
}
|
|
6165
6282
|
function readJson(filePath) {
|
|
6166
|
-
return JSON.parse(
|
|
6283
|
+
return JSON.parse(fs15.readFileSync(filePath, "utf8"));
|
|
6167
6284
|
}
|
|
6168
6285
|
function resolveManifestFile(manifestDir, relativePath) {
|
|
6169
|
-
const resolved =
|
|
6170
|
-
const relative2 =
|
|
6171
|
-
if (relative2.startsWith("..") ||
|
|
6286
|
+
const resolved = path11.resolve(manifestDir, relativePath);
|
|
6287
|
+
const relative2 = path11.relative(manifestDir, resolved);
|
|
6288
|
+
if (relative2.startsWith("..") || path11.isAbsolute(relative2)) {
|
|
6172
6289
|
throw new Error(`Google Chat manifest path escapes its directory: ${relativePath}`);
|
|
6173
6290
|
}
|
|
6174
6291
|
return resolved;
|
|
@@ -6181,7 +6298,7 @@ function readManifest2(filePath) {
|
|
|
6181
6298
|
if (manifest.chatType !== "private" && manifest.chatType !== "group") {
|
|
6182
6299
|
throw new Error("Invalid Google Chat chat type");
|
|
6183
6300
|
}
|
|
6184
|
-
const manifestDir =
|
|
6301
|
+
const manifestDir = path11.dirname(filePath);
|
|
6185
6302
|
return {
|
|
6186
6303
|
manifest,
|
|
6187
6304
|
userInfoPath: resolveManifestFile(manifestDir, manifest.userInfoFile),
|
|
@@ -6259,7 +6376,7 @@ async function* parseGoogleChat(options2) {
|
|
|
6259
6376
|
});
|
|
6260
6377
|
}
|
|
6261
6378
|
yield { type: "members", data: Array.from(memberMap.values()) };
|
|
6262
|
-
const readStream =
|
|
6379
|
+
const readStream = fs15.createReadStream(messagesPath, { encoding: "utf8" });
|
|
6263
6380
|
let bytesRead = 0;
|
|
6264
6381
|
let messagesProcessed = 0;
|
|
6265
6382
|
readStream.on("data", (chunk) => {
|
|
@@ -6312,8 +6429,8 @@ var module_13 = {
|
|
|
6312
6429
|
var google_chat_takeout_default = module_13;
|
|
6313
6430
|
|
|
6314
6431
|
// ../../packages/parser/src/formats/line-native-txt.ts
|
|
6315
|
-
import * as
|
|
6316
|
-
import * as
|
|
6432
|
+
import * as fs16 from "fs";
|
|
6433
|
+
import * as path12 from "path";
|
|
6317
6434
|
var feature14 = {
|
|
6318
6435
|
id: "line-native-txt",
|
|
6319
6436
|
name: "LINE \u5B98\u65B9\u5BFC\u51FA TXT",
|
|
@@ -6341,7 +6458,7 @@ var feature14 = {
|
|
|
6341
6458
|
}
|
|
6342
6459
|
};
|
|
6343
6460
|
function extractNameFromFilePath8(filePath) {
|
|
6344
|
-
const basename13 =
|
|
6461
|
+
const basename13 = path12.basename(filePath, ".txt");
|
|
6345
6462
|
const name = basename13.replace(/^\[LINE\]\s*/i, "").trim();
|
|
6346
6463
|
return name || "\u672A\u77E5\u804A\u5929";
|
|
6347
6464
|
}
|
|
@@ -6521,7 +6638,7 @@ async function* parseLINE(options2) {
|
|
|
6521
6638
|
yield { type: "progress", data: initialProgress };
|
|
6522
6639
|
onProgress?.(initialProgress);
|
|
6523
6640
|
onLog?.("info", `\u5F00\u59CB\u89E3\u6790 LINE \u5BFC\u51FA\u6587\u4EF6\uFF0C\u5927\u5C0F: ${(totalBytes / 1024 / 1024).toFixed(2)} MB`);
|
|
6524
|
-
const content =
|
|
6641
|
+
const content = fs16.readFileSync(filePath, "utf-8");
|
|
6525
6642
|
const lines = content.split("\n").map((line) => line.replace(/\r$/, ""));
|
|
6526
6643
|
let currentDate = null;
|
|
6527
6644
|
let chatName = extractNameFromFilePath8(filePath);
|
|
@@ -6829,12 +6946,12 @@ function findEntryFileInDirectory(dirPath, maxDepth = 1) {
|
|
|
6829
6946
|
if (depth > maxDepth) return null;
|
|
6830
6947
|
let entries;
|
|
6831
6948
|
try {
|
|
6832
|
-
entries =
|
|
6949
|
+
entries = fs17.readdirSync(current, { withFileTypes: true });
|
|
6833
6950
|
} catch {
|
|
6834
6951
|
return null;
|
|
6835
6952
|
}
|
|
6836
6953
|
for (const entry of entries) {
|
|
6837
|
-
const full =
|
|
6954
|
+
const full = path13.join(current, entry.name);
|
|
6838
6955
|
if (entry.isFile() && entry.name.endsWith(".json")) {
|
|
6839
6956
|
const format = detectFormat(full);
|
|
6840
6957
|
if (format) return full;
|
|
@@ -6842,7 +6959,7 @@ function findEntryFileInDirectory(dirPath, maxDepth = 1) {
|
|
|
6842
6959
|
}
|
|
6843
6960
|
for (const entry of entries) {
|
|
6844
6961
|
if (entry.isDirectory()) {
|
|
6845
|
-
const found = walk(
|
|
6962
|
+
const found = walk(path13.join(current, entry.name), depth + 1);
|
|
6846
6963
|
if (found) return found;
|
|
6847
6964
|
}
|
|
6848
6965
|
}
|
|
@@ -6873,8 +6990,124 @@ async function streamParseFile(filePath, callbacks, formatId) {
|
|
|
6873
6990
|
}
|
|
6874
6991
|
}
|
|
6875
6992
|
|
|
6993
|
+
// ../../packages/node-runtime/src/import/native-parser-status.ts
|
|
6994
|
+
var logged = false;
|
|
6995
|
+
function logNativeParserStatus() {
|
|
6996
|
+
if (logged) return;
|
|
6997
|
+
logged = true;
|
|
6998
|
+
const status = getNativeParserStatus();
|
|
6999
|
+
if (status.available) {
|
|
7000
|
+
appLogger.info("import", "Native parser kernels available (Rust module loaded)");
|
|
7001
|
+
} else if (status.disabled) {
|
|
7002
|
+
appLogger.info("import", "Native parser kernels disabled via CHATLAB_DISABLE_NATIVE_PERF=1; using TS parsers");
|
|
7003
|
+
} else {
|
|
7004
|
+
appLogger.warn("import", "Native parser kernels unavailable; imports fall back to TS parsers", {
|
|
7005
|
+
reason: status.error ?? "unknown"
|
|
7006
|
+
});
|
|
7007
|
+
}
|
|
7008
|
+
}
|
|
7009
|
+
|
|
7010
|
+
// ../../packages/node-runtime/src/import/perf-logger.ts
|
|
7011
|
+
import * as fs18 from "fs";
|
|
7012
|
+
import * as path14 from "path";
|
|
7013
|
+
var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
|
|
7014
|
+
LogLevel2["ERROR"] = "ERROR";
|
|
7015
|
+
LogLevel2["INFO"] = "INFO";
|
|
7016
|
+
return LogLevel2;
|
|
7017
|
+
})(LogLevel || {});
|
|
7018
|
+
var lastLogTime = Date.now();
|
|
7019
|
+
var lastMessageCount = 0;
|
|
7020
|
+
var currentLogFile = null;
|
|
7021
|
+
var errorCount = 0;
|
|
7022
|
+
function initPerfLog(sessionId, logDir) {
|
|
7023
|
+
try {
|
|
7024
|
+
if (!fs18.existsSync(logDir)) {
|
|
7025
|
+
fs18.mkdirSync(logDir, { recursive: true });
|
|
7026
|
+
}
|
|
7027
|
+
currentLogFile = path14.join(logDir, `import_${sessionId}_${Date.now()}.log`);
|
|
7028
|
+
fs18.writeFileSync(currentLogFile, `=== Import Log ===
|
|
7029
|
+
Start time: ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
7030
|
+
|
|
7031
|
+
`, "utf-8");
|
|
7032
|
+
} catch {
|
|
7033
|
+
}
|
|
7034
|
+
}
|
|
7035
|
+
function logPerf(event, messagesProcessed, batchSize) {
|
|
7036
|
+
const now = Date.now();
|
|
7037
|
+
const duration = now - lastLogTime;
|
|
7038
|
+
const messagesDelta = messagesProcessed - lastMessageCount;
|
|
7039
|
+
const speed = duration > 0 ? Math.round(messagesDelta / duration * 1e3) : 0;
|
|
7040
|
+
let memory = 0;
|
|
7041
|
+
try {
|
|
7042
|
+
const used = process.memoryUsage();
|
|
7043
|
+
memory = Math.round(used.heapUsed / 1024 / 1024);
|
|
7044
|
+
} catch {
|
|
7045
|
+
}
|
|
7046
|
+
const logLine = `[${(/* @__PURE__ */ new Date()).toISOString()}] ${event} | messages: ${messagesProcessed.toLocaleString()} | elapsed: ${duration}ms | speed: ${speed.toLocaleString()}/s | memory: ${memory}MB` + (batchSize ? ` | batch: ${batchSize}` : "") + "\n";
|
|
7047
|
+
if (currentLogFile) {
|
|
7048
|
+
try {
|
|
7049
|
+
fs18.appendFileSync(currentLogFile, logLine, "utf-8");
|
|
7050
|
+
} catch {
|
|
7051
|
+
}
|
|
7052
|
+
}
|
|
7053
|
+
lastLogTime = now;
|
|
7054
|
+
lastMessageCount = messagesProcessed;
|
|
7055
|
+
}
|
|
7056
|
+
function logPerfDetail(detail) {
|
|
7057
|
+
if (currentLogFile) {
|
|
7058
|
+
try {
|
|
7059
|
+
fs18.appendFileSync(currentLogFile, ` ${detail}
|
|
7060
|
+
`, "utf-8");
|
|
7061
|
+
} catch {
|
|
7062
|
+
}
|
|
7063
|
+
}
|
|
7064
|
+
}
|
|
7065
|
+
function resetPerfLog() {
|
|
7066
|
+
lastLogTime = Date.now();
|
|
7067
|
+
lastMessageCount = 0;
|
|
7068
|
+
currentLogFile = null;
|
|
7069
|
+
errorCount = 0;
|
|
7070
|
+
}
|
|
7071
|
+
function getCurrentLogFile() {
|
|
7072
|
+
return currentLogFile;
|
|
7073
|
+
}
|
|
7074
|
+
function writeLogLine(level, message) {
|
|
7075
|
+
if (!currentLogFile) return;
|
|
7076
|
+
const logLine = `[${(/* @__PURE__ */ new Date()).toISOString()}] [${level}] ${message}
|
|
7077
|
+
`;
|
|
7078
|
+
try {
|
|
7079
|
+
fs18.appendFileSync(currentLogFile, logLine, "utf-8");
|
|
7080
|
+
} catch {
|
|
7081
|
+
}
|
|
7082
|
+
}
|
|
7083
|
+
function logError(message, error) {
|
|
7084
|
+
errorCount++;
|
|
7085
|
+
const errorDetail = error ? `: ${error.message}` : "";
|
|
7086
|
+
writeLogLine("ERROR" /* ERROR */, `${message}${errorDetail}`);
|
|
7087
|
+
}
|
|
7088
|
+
function logInfo(message) {
|
|
7089
|
+
writeLogLine("INFO" /* INFO */, message);
|
|
7090
|
+
}
|
|
7091
|
+
function getErrorCount() {
|
|
7092
|
+
return errorCount;
|
|
7093
|
+
}
|
|
7094
|
+
function logSummary(totalMessages, totalMembers) {
|
|
7095
|
+
if (!currentLogFile) return;
|
|
7096
|
+
const summary = `
|
|
7097
|
+
=== Import Summary ===
|
|
7098
|
+
End time: ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
7099
|
+
Total messages: ${totalMessages.toLocaleString()}
|
|
7100
|
+
Total members: ${totalMembers.toLocaleString()}
|
|
7101
|
+
Errors: ${errorCount}
|
|
7102
|
+
`;
|
|
7103
|
+
try {
|
|
7104
|
+
fs18.appendFileSync(currentLogFile, summary, "utf-8");
|
|
7105
|
+
} catch {
|
|
7106
|
+
}
|
|
7107
|
+
}
|
|
7108
|
+
|
|
6876
7109
|
// ../../packages/node-runtime/src/nlp/word-frequency.ts
|
|
6877
|
-
function buildMessageQuery(timeFilter, memberId) {
|
|
7110
|
+
function buildMessageQuery(timeFilter, memberId, excludeKeywords) {
|
|
6878
7111
|
const conditions = [];
|
|
6879
7112
|
const params = [];
|
|
6880
7113
|
if (timeFilter?.startTs !== void 0) {
|
|
@@ -6889,6 +7122,11 @@ function buildMessageQuery(timeFilter, memberId) {
|
|
|
6889
7122
|
conditions.push("msg.sender_id = ?");
|
|
6890
7123
|
params.push(memberId);
|
|
6891
7124
|
}
|
|
7125
|
+
if (excludeKeywords && excludeKeywords.length > 0) {
|
|
7126
|
+
const exclude = buildExcludeKeywordsConditions(excludeKeywords);
|
|
7127
|
+
conditions.push(...exclude.conditions);
|
|
7128
|
+
params.push(...exclude.params);
|
|
7129
|
+
}
|
|
6892
7130
|
conditions.push("COALESCE(m.account_name, '') != '\u7CFB\u7EDF\u6D88\u606F'");
|
|
6893
7131
|
conditions.push("msg.type = 0");
|
|
6894
7132
|
conditions.push("msg.content IS NOT NULL");
|
|
@@ -6910,9 +7148,10 @@ function computeWordFrequency(db, params) {
|
|
|
6910
7148
|
customPosTags,
|
|
6911
7149
|
enableStopwords = true,
|
|
6912
7150
|
dictType = "default",
|
|
6913
|
-
excludeWords
|
|
7151
|
+
excludeWords,
|
|
7152
|
+
excludeKeywords
|
|
6914
7153
|
} = params;
|
|
6915
|
-
const { clause, params: filterParams } = buildMessageQuery(timeFilter, memberId);
|
|
7154
|
+
const { clause, params: filterParams } = buildMessageQuery(timeFilter, memberId, excludeKeywords);
|
|
6916
7155
|
const messages = db.prepare(`SELECT msg.content FROM message msg JOIN member m ON msg.sender_id = m.id${clause}`).all(...filterParams);
|
|
6917
7156
|
if (messages.length === 0) {
|
|
6918
7157
|
return { words: [], totalWords: 0, totalMessages: 0, uniqueWords: 0 };
|
|
@@ -7173,6 +7412,7 @@ function searchByFts(db, keywords, limit = 1e3, offset = 0) {
|
|
|
7173
7412
|
import * as fs20 from "fs";
|
|
7174
7413
|
var BATCH_COMMIT_SIZE = 5e4;
|
|
7175
7414
|
var CHECKPOINT_INTERVAL = 2e5;
|
|
7415
|
+
var yieldToEventLoop = () => new Promise((resolve2) => setImmediate(resolve2));
|
|
7176
7416
|
function defaultGenerateSessionId() {
|
|
7177
7417
|
const ts = Date.now();
|
|
7178
7418
|
const rand = Math.random().toString(36).substring(2, 8);
|
|
@@ -7254,7 +7494,13 @@ async function streamImportSingle(filePath, deps, formatFeature, formatOptions,
|
|
|
7254
7494
|
`INSERT INTO meta (name, platform, type, imported_at, group_id, group_avatar, owner_id) VALUES (?, ?, ?, ?, ?, ?, ?)`
|
|
7255
7495
|
);
|
|
7256
7496
|
const insertMember = db.prepare(
|
|
7257
|
-
`INSERT
|
|
7497
|
+
`INSERT INTO member (platform_id, account_name, group_nickname, avatar, roles)
|
|
7498
|
+
VALUES (?, ?, ?, ?, ?)
|
|
7499
|
+
ON CONFLICT(platform_id) DO UPDATE SET
|
|
7500
|
+
account_name = COALESCE(NULLIF(excluded.account_name, ''), account_name),
|
|
7501
|
+
group_nickname = COALESCE(NULLIF(excluded.group_nickname, ''), group_nickname),
|
|
7502
|
+
avatar = COALESCE(NULLIF(excluded.avatar, ''), avatar),
|
|
7503
|
+
roles = CASE WHEN excluded.roles != '[]' THEN excluded.roles ELSE roles END`
|
|
7258
7504
|
);
|
|
7259
7505
|
const getMemberId = db.prepare(`SELECT id FROM member WHERE platform_id = ?`);
|
|
7260
7506
|
const insertMessage = db.prepare(
|
|
@@ -7297,7 +7543,7 @@ async function streamImportSingle(filePath, deps, formatFeature, formatOptions,
|
|
|
7297
7543
|
lastCheckpointCount = totalMessageCount;
|
|
7298
7544
|
}
|
|
7299
7545
|
onProgress({
|
|
7300
|
-
stage: "
|
|
7546
|
+
stage: "saving",
|
|
7301
7547
|
bytesRead: 0,
|
|
7302
7548
|
totalBytes: 0,
|
|
7303
7549
|
messagesProcessed: totalMessageCount,
|
|
@@ -7469,13 +7715,14 @@ async function streamImportSingle(filePath, deps, formatFeature, formatOptions,
|
|
|
7469
7715
|
inTransaction = false;
|
|
7470
7716
|
}
|
|
7471
7717
|
onProgress({
|
|
7472
|
-
stage: "
|
|
7718
|
+
stage: "saving",
|
|
7473
7719
|
bytesRead: 0,
|
|
7474
7720
|
totalBytes: 0,
|
|
7475
7721
|
messagesProcessed: totalMessageCount,
|
|
7476
7722
|
percentage: 100,
|
|
7477
7723
|
message: ""
|
|
7478
7724
|
});
|
|
7725
|
+
await yieldToEventLoop();
|
|
7479
7726
|
logger?.perf("Writing nickname history", totalMessageCount);
|
|
7480
7727
|
db.exec("BEGIN TRANSACTION");
|
|
7481
7728
|
let historyCount = 0;
|
|
@@ -7491,13 +7738,14 @@ async function streamImportSingle(filePath, deps, formatFeature, formatOptions,
|
|
|
7491
7738
|
db.exec("COMMIT");
|
|
7492
7739
|
logger?.perf(`Nickname history written (${historyCount} entries)`, totalMessageCount);
|
|
7493
7740
|
onProgress({
|
|
7494
|
-
stage: "
|
|
7741
|
+
stage: "indexing",
|
|
7495
7742
|
bytesRead: 0,
|
|
7496
7743
|
totalBytes: 0,
|
|
7497
7744
|
messagesProcessed: totalMessageCount,
|
|
7498
7745
|
percentage: 100,
|
|
7499
7746
|
message: ""
|
|
7500
7747
|
});
|
|
7748
|
+
await yieldToEventLoop();
|
|
7501
7749
|
logger?.perf("Creating indexes", totalMessageCount);
|
|
7502
7750
|
db.exec(CHAT_DB_INDEXES);
|
|
7503
7751
|
logger?.perf("Indexes created", totalMessageCount);
|
|
@@ -7508,13 +7756,14 @@ async function streamImportSingle(filePath, deps, formatFeature, formatOptions,
|
|
|
7508
7756
|
logger?.error("FTS index build failed (non-fatal)", ftsError instanceof Error ? ftsError : void 0);
|
|
7509
7757
|
}
|
|
7510
7758
|
onProgress({
|
|
7511
|
-
stage: "
|
|
7759
|
+
stage: "indexing",
|
|
7512
7760
|
bytesRead: 0,
|
|
7513
7761
|
totalBytes: 0,
|
|
7514
7762
|
messagesProcessed: totalMessageCount,
|
|
7515
7763
|
percentage: 100,
|
|
7516
7764
|
message: ""
|
|
7517
7765
|
});
|
|
7766
|
+
await yieldToEventLoop();
|
|
7518
7767
|
doCheckpoint();
|
|
7519
7768
|
logger?.perf("WAL checkpoint done", totalMessageCount);
|
|
7520
7769
|
try {
|
|
@@ -10550,45 +10799,65 @@ var defaultLogger4 = {
|
|
|
10550
10799
|
warn: () => {
|
|
10551
10800
|
}
|
|
10552
10801
|
};
|
|
10802
|
+
function emptyStats(count) {
|
|
10803
|
+
return {
|
|
10804
|
+
input: count,
|
|
10805
|
+
output: count,
|
|
10806
|
+
cleaned: 0,
|
|
10807
|
+
blacklistRemoved: 0,
|
|
10808
|
+
denoiseRemoved: 0,
|
|
10809
|
+
mergeCombined: 0,
|
|
10810
|
+
desensitizeRulesApplied: 0
|
|
10811
|
+
};
|
|
10812
|
+
}
|
|
10553
10813
|
function preprocessMessages(messages, config, logger = defaultLogger4) {
|
|
10554
|
-
|
|
10555
|
-
|
|
10556
|
-
|
|
10814
|
+
return preprocessMessagesWithStats(messages, config, logger).messages;
|
|
10815
|
+
}
|
|
10816
|
+
function preprocessMessagesWithStats(messages, config, logger = defaultLogger4) {
|
|
10817
|
+
if (!config || !hasAnyEnabled(config)) return { messages, stats: emptyStats(messages.length) };
|
|
10818
|
+
if (messages.length === 0) return { messages, stats: emptyStats(0) };
|
|
10819
|
+
const stats = emptyStats(messages.length);
|
|
10557
10820
|
let result = [...messages];
|
|
10558
10821
|
const applied = [];
|
|
10559
10822
|
if (config.dataCleaning !== false) {
|
|
10560
10823
|
const cleaned = applyDataCleaning(result);
|
|
10561
10824
|
if (cleaned.changed > 0) {
|
|
10562
10825
|
result = cleaned.messages;
|
|
10826
|
+
stats.cleaned = cleaned.changed;
|
|
10563
10827
|
applied.push(`dataCleaning: ${cleaned.changed} messages cleaned`);
|
|
10564
10828
|
}
|
|
10565
10829
|
}
|
|
10566
10830
|
if (config.blacklistKeywords.length > 0) {
|
|
10567
10831
|
const before = result.length;
|
|
10568
10832
|
result = applyBlacklistFilter(result, config.blacklistKeywords);
|
|
10833
|
+
stats.blacklistRemoved = before - result.length;
|
|
10569
10834
|
applied.push(`blacklist: ${before} \u2192 ${result.length} (-${before - result.length})`);
|
|
10570
10835
|
}
|
|
10571
10836
|
if (config.denoise) {
|
|
10572
10837
|
const before = result.length;
|
|
10573
10838
|
result = applyDenoise(result);
|
|
10839
|
+
stats.denoiseRemoved = before - result.length;
|
|
10574
10840
|
applied.push(`denoise: ${before} \u2192 ${result.length} (-${before - result.length})`);
|
|
10575
10841
|
}
|
|
10576
10842
|
if (config.mergeConsecutive) {
|
|
10577
10843
|
const before = result.length;
|
|
10578
10844
|
result = applyMergeConsecutive(result, config.mergeWindowSeconds ?? MERGE_WINDOW_DEFAULT);
|
|
10845
|
+
stats.mergeCombined = before - result.length;
|
|
10579
10846
|
applied.push(`merge: ${before} \u2192 ${result.length} (-${before - result.length})`);
|
|
10580
10847
|
}
|
|
10581
10848
|
if (config.desensitize) {
|
|
10582
10849
|
const enabledRules = (config.desensitizeRules || []).filter((r) => r.enabled);
|
|
10583
10850
|
if (enabledRules.length > 0) {
|
|
10584
10851
|
result = applyDesensitize(result, enabledRules, logger);
|
|
10852
|
+
stats.desensitizeRulesApplied = enabledRules.length;
|
|
10585
10853
|
applied.push(`desensitize: ${enabledRules.length} rules applied`);
|
|
10586
10854
|
}
|
|
10587
10855
|
}
|
|
10588
|
-
|
|
10856
|
+
stats.output = result.length;
|
|
10857
|
+
logger.info("Preprocess", `Pipeline: ${stats.input} \u2192 ${result.length} messages`, {
|
|
10589
10858
|
strategies: applied
|
|
10590
10859
|
});
|
|
10591
|
-
return result;
|
|
10860
|
+
return { messages: result, stats };
|
|
10592
10861
|
}
|
|
10593
10862
|
function hasAnyEnabled(config) {
|
|
10594
10863
|
return config.dataCleaning !== false || config.mergeConsecutive || config.blacklistKeywords.length > 0 || config.denoise || config.desensitize;
|
|
@@ -10683,9 +10952,16 @@ function applyMergeConsecutive(messages, windowSeconds) {
|
|
|
10683
10952
|
const sameSender = isSameSender(current, msg);
|
|
10684
10953
|
const withinWindow = Math.abs(msg.timestamp - current.timestamp) <= windowSeconds;
|
|
10685
10954
|
if (sameSender && withinWindow) {
|
|
10955
|
+
const mergedIds = [
|
|
10956
|
+
...current.mergedIds ?? (current.id != null ? [current.id] : []),
|
|
10957
|
+
...msg.mergedIds ?? (msg.id != null ? [msg.id] : [])
|
|
10958
|
+
];
|
|
10686
10959
|
current = {
|
|
10687
10960
|
...current,
|
|
10688
|
-
content: [current.content, msg.content].filter(Boolean).join("\n")
|
|
10961
|
+
content: [current.content, msg.content].filter(Boolean).join("\n"),
|
|
10962
|
+
// keep first message's id, track last id for [#start-end] range citations
|
|
10963
|
+
mergedEndId: msg.id ?? current.mergedEndId,
|
|
10964
|
+
...mergedIds.length > 0 ? { mergedIds } : {}
|
|
10689
10965
|
};
|
|
10690
10966
|
} else {
|
|
10691
10967
|
merged.push(current);
|
|
@@ -10706,15 +10982,29 @@ function applyDesensitize(messages, rules, logger) {
|
|
|
10706
10982
|
if (compiledRules.length === 0) return messages;
|
|
10707
10983
|
return messages.map((msg) => {
|
|
10708
10984
|
if (!msg.content) return msg;
|
|
10709
|
-
|
|
10710
|
-
for (const { regex, replacement } of compiledRules) {
|
|
10711
|
-
regex.lastIndex = 0;
|
|
10712
|
-
content = content.replace(regex, replacement);
|
|
10713
|
-
}
|
|
10985
|
+
const content = applyCompiledRules(msg.content, compiledRules);
|
|
10714
10986
|
if (content === msg.content) return msg;
|
|
10715
10987
|
return { ...msg, content };
|
|
10716
10988
|
});
|
|
10717
10989
|
}
|
|
10990
|
+
function applyCompiledRules(text, compiledRules) {
|
|
10991
|
+
let result = text;
|
|
10992
|
+
for (const { regex, replacement } of compiledRules) {
|
|
10993
|
+
regex.lastIndex = 0;
|
|
10994
|
+
result = result.replace(regex, replacement);
|
|
10995
|
+
}
|
|
10996
|
+
return result;
|
|
10997
|
+
}
|
|
10998
|
+
function desensitizeText(text, rules, logger = defaultLogger4) {
|
|
10999
|
+
const enabledRules = rules.filter((r) => r.enabled);
|
|
11000
|
+
if (enabledRules.length === 0 || !text) return text;
|
|
11001
|
+
return applyCompiledRules(text, compileRules(enabledRules, logger));
|
|
11002
|
+
}
|
|
11003
|
+
function matchesBlacklist(text, keywords) {
|
|
11004
|
+
if (keywords.length === 0 || !text) return false;
|
|
11005
|
+
const lower = text.toLowerCase();
|
|
11006
|
+
return keywords.some((kw) => lower.includes(kw.toLowerCase()));
|
|
11007
|
+
}
|
|
10718
11008
|
var regexCache = /* @__PURE__ */ new Map();
|
|
10719
11009
|
function compileRules(rules, logger) {
|
|
10720
11010
|
const result = [];
|
|
@@ -11040,14 +11330,26 @@ function t(key, locale) {
|
|
|
11040
11330
|
return "";
|
|
11041
11331
|
}
|
|
11042
11332
|
var MAX_MESSAGE_CONTENT_LENGTH = 200;
|
|
11043
|
-
function formatMessageCompact(msg, locale) {
|
|
11333
|
+
function formatMessageCompact(msg, locale, options2) {
|
|
11044
11334
|
const localeStr = isChineseLocale(locale) ? "zh-CN" : "en-US";
|
|
11045
11335
|
const time = new Date(msg.timestamp * 1e3).toLocaleString(localeStr);
|
|
11046
11336
|
let content = msg.content || t("noContent", locale);
|
|
11047
|
-
|
|
11048
|
-
|
|
11337
|
+
const maxLength = options2?.maxContentLength ?? MAX_MESSAGE_CONTENT_LENGTH;
|
|
11338
|
+
if (maxLength > 0 && content.length > maxLength) {
|
|
11339
|
+
content = content.slice(0, maxLength) + "...";
|
|
11340
|
+
}
|
|
11341
|
+
let idPrefix = "";
|
|
11342
|
+
if (options2?.includeMessageId && msg.id != null) {
|
|
11343
|
+
const range = msg.mergedEndId != null && msg.mergedEndId !== msg.id ? `${msg.id}-${msg.mergedEndId}` : `${msg.id}`;
|
|
11344
|
+
const hitMark = isHitMessage(msg, options2.hitIds) ? "*" : "";
|
|
11345
|
+
idPrefix = `[#${range}${hitMark}] `;
|
|
11049
11346
|
}
|
|
11050
|
-
return `${time} ${msg.senderName}: ${content}`;
|
|
11347
|
+
return `${idPrefix}${time} ${msg.senderName}: ${content}`;
|
|
11348
|
+
}
|
|
11349
|
+
function isHitMessage(msg, hitIds) {
|
|
11350
|
+
if (!hitIds) return false;
|
|
11351
|
+
if (msg.id != null && hitIds.has(msg.id)) return true;
|
|
11352
|
+
return msg.mergedIds?.some((id) => hitIds.has(id)) ?? false;
|
|
11051
11353
|
}
|
|
11052
11354
|
function formatTimeRange(timeFilter, locale) {
|
|
11053
11355
|
if (!timeFilter) return t("allTime", locale);
|
|
@@ -11081,16 +11383,19 @@ function formatToolResultAsText(details) {
|
|
|
11081
11383
|
lines.push("");
|
|
11082
11384
|
let lastDate = "";
|
|
11083
11385
|
for (const msg of messages) {
|
|
11084
|
-
const
|
|
11085
|
-
const
|
|
11386
|
+
const prefixMatch = /^(\[#[^\]]+\] )/.exec(msg);
|
|
11387
|
+
const prefix = prefixMatch ? prefixMatch[1] : "";
|
|
11388
|
+
const body = prefix ? msg.slice(prefix.length) : msg;
|
|
11389
|
+
const spaceIdx = body.indexOf(" ");
|
|
11390
|
+
const secondSpaceIdx = body.indexOf(" ", spaceIdx + 1);
|
|
11086
11391
|
if (spaceIdx > 0 && secondSpaceIdx > 0) {
|
|
11087
|
-
const date =
|
|
11088
|
-
const rest =
|
|
11392
|
+
const date = body.slice(0, spaceIdx);
|
|
11393
|
+
const rest = body.slice(spaceIdx + 1);
|
|
11089
11394
|
if (date !== lastDate) {
|
|
11090
11395
|
lines.push(`--- ${date} ---`);
|
|
11091
11396
|
lastDate = date;
|
|
11092
11397
|
}
|
|
11093
|
-
lines.push(rest);
|
|
11398
|
+
lines.push(prefix + rest);
|
|
11094
11399
|
} else {
|
|
11095
11400
|
lines.push(msg);
|
|
11096
11401
|
}
|
|
@@ -11163,14 +11468,26 @@ function applyPreprocessingPipeline(options2) {
|
|
|
11163
11468
|
maxToolResultTokens,
|
|
11164
11469
|
truncationStrategy = "keep_last",
|
|
11165
11470
|
extraDetails = {},
|
|
11166
|
-
logger
|
|
11471
|
+
logger,
|
|
11472
|
+
includeMessageIds = false,
|
|
11473
|
+
hitIds,
|
|
11474
|
+
maxContentChars
|
|
11167
11475
|
} = options2;
|
|
11168
|
-
const processed =
|
|
11476
|
+
const { messages: processed, stats: preprocessStats } = preprocessMessagesWithStats(
|
|
11477
|
+
rawMessages,
|
|
11478
|
+
preprocessConfig,
|
|
11479
|
+
logger
|
|
11480
|
+
);
|
|
11169
11481
|
let nameMapLine = "";
|
|
11170
11482
|
if (anonymizeNames) {
|
|
11171
11483
|
nameMapLine = anonymizeMessageNames(processed, ownerPlatformId);
|
|
11172
11484
|
}
|
|
11173
|
-
|
|
11485
|
+
const formatOptions = includeMessageIds || maxContentChars != null ? {
|
|
11486
|
+
includeMessageId: includeMessageIds,
|
|
11487
|
+
hitIds: hitIds ? new Set(hitIds) : void 0,
|
|
11488
|
+
maxContentLength: maxContentChars
|
|
11489
|
+
} : void 0;
|
|
11490
|
+
let formatted = processed.map((m) => formatMessageCompact(m, locale, formatOptions));
|
|
11174
11491
|
let wasTruncated = false;
|
|
11175
11492
|
const originalCount = formatted.length;
|
|
11176
11493
|
if (maxToolResultTokens && maxToolResultTokens > 0) {
|
|
@@ -11190,7 +11507,12 @@ function applyPreprocessingPipeline(options2) {
|
|
|
11190
11507
|
if (nameMapLine) {
|
|
11191
11508
|
textContent = nameMapLine + "\n" + textContent;
|
|
11192
11509
|
}
|
|
11193
|
-
|
|
11510
|
+
const stats = {
|
|
11511
|
+
...preprocessStats,
|
|
11512
|
+
renderedBlocks: formatted.length,
|
|
11513
|
+
truncated: wasTruncated
|
|
11514
|
+
};
|
|
11515
|
+
return { text: textContent, details: finalDetails, stats };
|
|
11194
11516
|
}
|
|
11195
11517
|
|
|
11196
11518
|
// ../../packages/node-runtime/src/ai/agent/constants.ts
|
|
@@ -16731,6 +17053,7 @@ __export(relationships_exports, {
|
|
|
16731
17053
|
// ../../packages/node-runtime/src/semantic-index/config.ts
|
|
16732
17054
|
import fs30 from "fs";
|
|
16733
17055
|
import path27 from "path";
|
|
17056
|
+
var DEFAULT_SEMANTIC_INDEX_MODEL_DOWNLOAD_SOURCE = "huggingface";
|
|
16734
17057
|
var SEMANTIC_INDEX_CONFIG_VERSION = 1;
|
|
16735
17058
|
var SEARCH_MAX_RESULTS_DEFAULT = 10;
|
|
16736
17059
|
var SEARCH_MAX_RESULTS_MIN = 5;
|
|
@@ -16745,7 +17068,7 @@ function defaultSemanticIndexConfig() {
|
|
|
16745
17068
|
version: SEMANTIC_INDEX_CONFIG_VERSION,
|
|
16746
17069
|
enabled: true,
|
|
16747
17070
|
mode: "local",
|
|
16748
|
-
local: { modelId: "" },
|
|
17071
|
+
local: { modelId: "", downloadSource: DEFAULT_SEMANTIC_INDEX_MODEL_DOWNLOAD_SOURCE },
|
|
16749
17072
|
api: null,
|
|
16750
17073
|
searchMaxResults: SEARCH_MAX_RESULTS_DEFAULT
|
|
16751
17074
|
};
|
|
@@ -16790,7 +17113,10 @@ function normalizeConfig(raw) {
|
|
|
16790
17113
|
// 旧配置无 enabled 字段时默认开启,保证既有用户功能不被意外关闭
|
|
16791
17114
|
enabled: raw.enabled ?? true,
|
|
16792
17115
|
mode,
|
|
16793
|
-
local: {
|
|
17116
|
+
local: {
|
|
17117
|
+
modelId: raw.local?.modelId ?? base.local.modelId,
|
|
17118
|
+
downloadSource: raw.local?.downloadSource === "hf-mirror" ? "hf-mirror" : DEFAULT_SEMANTIC_INDEX_MODEL_DOWNLOAD_SOURCE
|
|
17119
|
+
},
|
|
16794
17120
|
api,
|
|
16795
17121
|
searchMaxResults: SEARCH_MAX_RESULTS_DEFAULT
|
|
16796
17122
|
};
|
|
@@ -16840,7 +17166,7 @@ import path28 from "path";
|
|
|
16840
17166
|
|
|
16841
17167
|
// ../../packages/node-runtime/src/semantic-index/chunker-config.ts
|
|
16842
17168
|
import { createHash as createHash2 } from "crypto";
|
|
16843
|
-
var CHUNKER_VERSION = "v1.
|
|
17169
|
+
var CHUNKER_VERSION = "v1.3";
|
|
16844
17170
|
var STRATEGY_ID = "balanced";
|
|
16845
17171
|
var DEFAULT_CHUNKER_CONFIG = {
|
|
16846
17172
|
parentGapSeconds: 1800,
|
|
@@ -16888,6 +17214,44 @@ function parseParentBounds(parentId) {
|
|
|
16888
17214
|
return { startMessageId, endMessageId };
|
|
16889
17215
|
}
|
|
16890
17216
|
|
|
17217
|
+
// ../../packages/node-runtime/src/semantic-index/tokens.ts
|
|
17218
|
+
import { Buffer as Buffer2 } from "buffer";
|
|
17219
|
+
var UTF8_BYTES_PER_ESTIMATED_TOKEN = 4;
|
|
17220
|
+
function isCjkCharacter(char) {
|
|
17221
|
+
return /[\u3400-\u9fff\uf900-\ufaff]/u.test(char);
|
|
17222
|
+
}
|
|
17223
|
+
function estimateTokens2(text) {
|
|
17224
|
+
let cjk = 0;
|
|
17225
|
+
let other = 0;
|
|
17226
|
+
for (const ch of text) {
|
|
17227
|
+
if (isCjkCharacter(ch)) cjk++;
|
|
17228
|
+
else other++;
|
|
17229
|
+
}
|
|
17230
|
+
return cjk + Math.ceil(other / 4);
|
|
17231
|
+
}
|
|
17232
|
+
function clampEstimatedTokens(text, maxTokens) {
|
|
17233
|
+
const limit = Math.max(0, Math.floor(maxTokens));
|
|
17234
|
+
if (limit === 0) return "";
|
|
17235
|
+
const byteLimit = limit * UTF8_BYTES_PER_ESTIMATED_TOKEN;
|
|
17236
|
+
if (estimateTokens2(text) <= limit && Buffer2.byteLength(text, "utf8") <= byteLimit) return text;
|
|
17237
|
+
let cjk = 0;
|
|
17238
|
+
let other = 0;
|
|
17239
|
+
let bytes = 0;
|
|
17240
|
+
let end = 0;
|
|
17241
|
+
for (const char of text) {
|
|
17242
|
+
const isCjk = isCjkCharacter(char);
|
|
17243
|
+
const nextCjk = cjk + (isCjk ? 1 : 0);
|
|
17244
|
+
const nextOther = other + (isCjk ? 0 : 1);
|
|
17245
|
+
const nextBytes = bytes + Buffer2.byteLength(char, "utf8");
|
|
17246
|
+
if (nextCjk + Math.ceil(nextOther / 4) > limit || nextBytes > byteLimit) break;
|
|
17247
|
+
cjk = nextCjk;
|
|
17248
|
+
other = nextOther;
|
|
17249
|
+
bytes = nextBytes;
|
|
17250
|
+
end += char.length;
|
|
17251
|
+
}
|
|
17252
|
+
return text.slice(0, end);
|
|
17253
|
+
}
|
|
17254
|
+
|
|
16891
17255
|
// ../../packages/node-runtime/src/semantic-index/embedding/api.ts
|
|
16892
17256
|
var API_DOCUMENT_BATCH_SIZE = 8;
|
|
16893
17257
|
var defaultFetchFn = (url, init) => fetch(url, init);
|
|
@@ -16927,7 +17291,19 @@ var OpenAICompatibleEmbeddingProvider = class {
|
|
|
16927
17291
|
});
|
|
16928
17292
|
if (!response.ok) {
|
|
16929
17293
|
await response.text().catch(() => "");
|
|
16930
|
-
|
|
17294
|
+
const estimatedTokens = texts.map(estimateTokens2);
|
|
17295
|
+
const traceId = response.headers?.get("x-siliconcloud-trace-id")?.trim();
|
|
17296
|
+
const diagnostics = [
|
|
17297
|
+
`model=${this.config.model}`,
|
|
17298
|
+
`batchSize=${texts.length}`,
|
|
17299
|
+
`maxInputTokens=${Math.max(...estimatedTokens)}`,
|
|
17300
|
+
`totalInputTokens=${estimatedTokens.reduce((sum, count) => sum + count, 0)}`,
|
|
17301
|
+
`maxInputChars=${Math.max(...texts.map((text) => text.length))}`
|
|
17302
|
+
];
|
|
17303
|
+
if (traceId) diagnostics.push(`traceId=${traceId}`);
|
|
17304
|
+
const error = new Error(`Embedding API request failed: ${response.status} (${diagnostics.join(", ")})`);
|
|
17305
|
+
appLogger.error("semantic-index", "embedding API request failed", error);
|
|
17306
|
+
throw error;
|
|
16931
17307
|
}
|
|
16932
17308
|
const payload = await response.json();
|
|
16933
17309
|
const sorted = [...payload.data].sort((a, b) => a.index - b.index);
|
|
@@ -16959,6 +17335,11 @@ function clampTextChars(text, maxChars) {
|
|
|
16959
17335
|
// ../../packages/node-runtime/src/semantic-index/embedding/local.ts
|
|
16960
17336
|
var SOCKS_PROXY_PROTOCOLS = /* @__PURE__ */ new Set(["socks:", "socks4:", "socks5:"]);
|
|
16961
17337
|
var LOCAL_ONNX_SESSION_OPTIONS = { intraOpNumThreads: 1, interOpNumThreads: 1 };
|
|
17338
|
+
var HUGGING_FACE_MODEL_HOST = "https://huggingface.co/";
|
|
17339
|
+
var HF_MIRROR_MODEL_HOST = "https://hf-mirror.com/";
|
|
17340
|
+
function resolveModelDownloadRemoteHost(source) {
|
|
17341
|
+
return source === "hf-mirror" ? HF_MIRROR_MODEL_HOST : HUGGING_FACE_MODEL_HOST;
|
|
17342
|
+
}
|
|
16962
17343
|
async function createProxyFetch(proxyUrl) {
|
|
16963
17344
|
const parsed = new URL(proxyUrl);
|
|
16964
17345
|
if (SOCKS_PROXY_PROTOCOLS.has(parsed.protocol)) {
|
|
@@ -16973,8 +17354,15 @@ async function createProxyFetch(proxyUrl) {
|
|
|
16973
17354
|
return undiciFetch(input, nextInit);
|
|
16974
17355
|
});
|
|
16975
17356
|
}
|
|
16976
|
-
var defaultPipelineFactory = async ({
|
|
17357
|
+
var defaultPipelineFactory = async ({
|
|
17358
|
+
modelId,
|
|
17359
|
+
dtype,
|
|
17360
|
+
cacheDir,
|
|
17361
|
+
modelDownloadProxyUrl,
|
|
17362
|
+
modelDownloadSource
|
|
17363
|
+
}) => {
|
|
16977
17364
|
const transformers = await import("./transformers.node-PUMHAODN.mjs");
|
|
17365
|
+
transformers.env.remoteHost = resolveModelDownloadRemoteHost(modelDownloadSource);
|
|
16978
17366
|
if (cacheDir) {
|
|
16979
17367
|
transformers.env.cacheDir = cacheDir;
|
|
16980
17368
|
transformers.env.allowRemoteModels = true;
|
|
@@ -17015,6 +17403,7 @@ var LocalEmbeddingProvider = class {
|
|
|
17015
17403
|
dtype: this.profile.dtype,
|
|
17016
17404
|
cacheDir: this.options.cacheDir,
|
|
17017
17405
|
modelDownloadProxyUrl: this.options.modelDownloadProxyUrl,
|
|
17406
|
+
modelDownloadSource: this.options.modelDownloadSource,
|
|
17018
17407
|
sessionOptions: LOCAL_ONNX_SESSION_OPTIONS
|
|
17019
17408
|
}).catch((error) => {
|
|
17020
17409
|
this.extractorPromise = null;
|
|
@@ -17108,6 +17497,7 @@ function createEmbedder(config, deps = {}) {
|
|
|
17108
17497
|
return new LocalEmbeddingProvider(profile, {
|
|
17109
17498
|
cacheDir: deps.modelsCacheDir,
|
|
17110
17499
|
modelDownloadProxyUrl: deps.modelDownloadProxyUrl,
|
|
17500
|
+
modelDownloadSource: config.local.downloadSource,
|
|
17111
17501
|
pipelineFactory: deps.localPipelineFactory
|
|
17112
17502
|
});
|
|
17113
17503
|
}
|
|
@@ -17659,19 +18049,6 @@ var SemanticIndexJobQueue = class {
|
|
|
17659
18049
|
|
|
17660
18050
|
// ../../packages/node-runtime/src/semantic-index/chunker.ts
|
|
17661
18051
|
import { createHash as createHash3 } from "crypto";
|
|
17662
|
-
|
|
17663
|
-
// ../../packages/node-runtime/src/semantic-index/tokens.ts
|
|
17664
|
-
function estimateTokens2(text) {
|
|
17665
|
-
let cjk = 0;
|
|
17666
|
-
let other = 0;
|
|
17667
|
-
for (const ch of text) {
|
|
17668
|
-
if (/[\u3400-\u9fff\uf900-\ufaff]/u.test(ch)) cjk++;
|
|
17669
|
-
else other++;
|
|
17670
|
-
}
|
|
17671
|
-
return cjk + Math.ceil(other / 4);
|
|
17672
|
-
}
|
|
17673
|
-
|
|
17674
|
-
// ../../packages/node-runtime/src/semantic-index/chunker.ts
|
|
17675
18052
|
var VOID_MESSAGE_TYPES = /* @__PURE__ */ new Set([
|
|
17676
18053
|
1 /* IMAGE */,
|
|
17677
18054
|
2 /* VOICE */,
|
|
@@ -17756,6 +18133,9 @@ function sumEffectiveChars(messages) {
|
|
|
17756
18133
|
function sha256Hex2(input) {
|
|
17757
18134
|
return createHash3("sha256").update(input, "utf-8").digest("hex");
|
|
17758
18135
|
}
|
|
18136
|
+
var EMBEDDING_HEADER_BUDGET_RATIO = 0.25;
|
|
18137
|
+
var SOURCE_TITLE_HEADER_SHARE = 1 / 3;
|
|
18138
|
+
var SENDER_NAMES_BODY_BUDGET_RATIO = 0.1;
|
|
17759
18139
|
function pad2(n) {
|
|
17760
18140
|
return String(n).padStart(2, "0");
|
|
17761
18141
|
}
|
|
@@ -17773,23 +18153,51 @@ function formatTimeRange2(startTs, endTs) {
|
|
|
17773
18153
|
const sameDay = start.getFullYear() === end.getFullYear() && start.getMonth() === end.getMonth() && start.getDate() === end.getDate();
|
|
17774
18154
|
return `${formatDateTime(startTs)} - ${sameDay ? formatTime2(endTs) : formatDateTime(endTs)}`;
|
|
17775
18155
|
}
|
|
17776
|
-
function
|
|
18156
|
+
function resolveSenderNameTokenCap(nameTokenCounts, totalLimit) {
|
|
18157
|
+
const total = nameTokenCounts.reduce((sum, count) => sum + count, 0);
|
|
18158
|
+
if (total <= totalLimit) return null;
|
|
18159
|
+
const sorted = [...nameTokenCounts].sort((a, b) => a - b);
|
|
18160
|
+
let consumed = 0;
|
|
18161
|
+
for (let i = 0; i < sorted.length; i++) {
|
|
18162
|
+
const cap = Math.floor((totalLimit - consumed) / (sorted.length - i));
|
|
18163
|
+
if (sorted[i] > cap) return cap;
|
|
18164
|
+
consumed += sorted[i];
|
|
18165
|
+
}
|
|
18166
|
+
return null;
|
|
18167
|
+
}
|
|
18168
|
+
function buildEmbeddingInput(source, messages, maxTokens) {
|
|
18169
|
+
const limit = Math.max(0, Math.floor(maxTokens));
|
|
18170
|
+
if (limit === 0) return "";
|
|
17777
18171
|
const effective = messages.filter((m) => !isSemanticVoid(m));
|
|
17778
18172
|
const startTs = messages[0].ts;
|
|
17779
18173
|
const endTs = messages[messages.length - 1].ts;
|
|
17780
|
-
const
|
|
18174
|
+
const headerLimit = Math.max(1, Math.floor(limit * EMBEDDING_HEADER_BUDGET_RATIO));
|
|
18175
|
+
const bodyFloor = Math.max(1, limit - headerLimit);
|
|
18176
|
+
const sourceTitleLimit = Math.max(1, Math.floor(headerLimit * SOURCE_TITLE_HEADER_SHARE));
|
|
18177
|
+
const senderNamesTotalLimit = Math.floor(bodyFloor * SENDER_NAMES_BODY_BUDGET_RATIO);
|
|
18178
|
+
const bodySenderNameCap = resolveSenderNameTokenCap(
|
|
18179
|
+
effective.map((m) => estimateTokens2(m.senderName)),
|
|
18180
|
+
senderNamesTotalLimit
|
|
18181
|
+
);
|
|
18182
|
+
const clampHeaderSenderName = (name) => clampEstimatedTokens(name, sourceTitleLimit);
|
|
18183
|
+
const clampBodySenderName = (name) => bodySenderNameCap === null ? name : clampEstimatedTokens(name, bodySenderNameCap);
|
|
18184
|
+
const headerLines = [];
|
|
17781
18185
|
const kindLabel = source.kind === "group" ? "\u7FA4\u804A" : "\u79C1\u804A";
|
|
17782
|
-
|
|
17783
|
-
|
|
18186
|
+
headerLines.push(`[\u6765\u6E90] ${clampEstimatedTokens(source.title, sourceTitleLimit)}\uFF08${kindLabel}\uFF09`);
|
|
18187
|
+
headerLines.push(`[\u65F6\u95F4\u8303\u56F4] ${formatTimeRange2(startTs, endTs)}`);
|
|
17784
18188
|
if (source.kind === "group") {
|
|
17785
|
-
const participants = [...new Set(effective.map((m) => m.senderName))];
|
|
17786
|
-
|
|
17787
|
-
}
|
|
17788
|
-
|
|
17789
|
-
|
|
17790
|
-
|
|
17791
|
-
|
|
17792
|
-
|
|
18189
|
+
const participants = [...new Set(effective.map((m) => clampHeaderSenderName(m.senderName)))];
|
|
18190
|
+
headerLines.push(`[\u53C2\u4E0E\u8005] ${participants.join("\u3001")}`);
|
|
18191
|
+
}
|
|
18192
|
+
const header = clampEstimatedTokens(headerLines.join("\n"), headerLimit);
|
|
18193
|
+
const separator = "\n\n";
|
|
18194
|
+
const remaining = Math.max(0, limit - estimateTokens2(header) - estimateTokens2(separator));
|
|
18195
|
+
const body = clampEstimatedTokens(
|
|
18196
|
+
effective.map((m) => `${clampBodySenderName(m.senderName)}: ${(m.content ?? "").trim()}`).join("\n"),
|
|
18197
|
+
remaining
|
|
18198
|
+
);
|
|
18199
|
+
const combined = body ? `${header}${separator}${body}` : header;
|
|
18200
|
+
return clampEstimatedTokens(combined, limit);
|
|
17793
18201
|
}
|
|
17794
18202
|
function rawContentHashOf(messages) {
|
|
17795
18203
|
return sha256Hex2(messages.map((m) => `${m.id}:${m.content ?? ""}`).join("\n"));
|
|
@@ -17864,7 +18272,7 @@ function chunkMessages(input) {
|
|
|
17864
18272
|
}
|
|
17865
18273
|
const startMessageId = draft[0].id;
|
|
17866
18274
|
const endMessageId = draft[draft.length - 1].id;
|
|
17867
|
-
const embeddingInput = buildEmbeddingInput(input.source, draft);
|
|
18275
|
+
const embeddingInput = buildEmbeddingInput(input.source, draft, config.childHardMaxTokens);
|
|
17868
18276
|
chunks.push({
|
|
17869
18277
|
localChunkId: `${parentId}#${startMessageId}-${endMessageId}`,
|
|
17870
18278
|
parentId,
|
|
@@ -18312,6 +18720,7 @@ var SemanticIndexService = class {
|
|
|
18312
18720
|
embedder = null;
|
|
18313
18721
|
embedderModelId = null;
|
|
18314
18722
|
modelPreloadStatus = "idle";
|
|
18723
|
+
modelPreloadGeneration = 0;
|
|
18315
18724
|
/** 当前激活的 chunker 身份(version + 参数 hash),随索引记录用于重建判定 */
|
|
18316
18725
|
chunkerVersion = CHUNKER_VERSION;
|
|
18317
18726
|
chunkerConfigHash = computeChunkerConfigHash(DEFAULT_CHUNKER_CONFIG);
|
|
@@ -18360,6 +18769,7 @@ var SemanticIndexService = class {
|
|
|
18360
18769
|
apiKey: options2?.apiKey,
|
|
18361
18770
|
writeAuthProfile: this.options.writeAuthProfile
|
|
18362
18771
|
});
|
|
18772
|
+
const preloadGeneration = ++this.modelPreloadGeneration;
|
|
18363
18773
|
this.embedder = null;
|
|
18364
18774
|
this.embedderModelId = null;
|
|
18365
18775
|
this.modelPreloadStatus = "idle";
|
|
@@ -18368,15 +18778,26 @@ var SemanticIndexService = class {
|
|
|
18368
18778
|
}
|
|
18369
18779
|
if (saved.enabled && isSemanticIndexConfigured(saved) && saved.mode === "local") {
|
|
18370
18780
|
const modelId = saved.local.modelId;
|
|
18781
|
+
const downloadSource = saved.local.downloadSource ?? DEFAULT_SEMANTIC_INDEX_MODEL_DOWNLOAD_SOURCE;
|
|
18371
18782
|
const cacheDir = this.options.modelsCacheDir;
|
|
18372
18783
|
this.modelPreloadStatus = "downloading";
|
|
18373
|
-
appLogger.info("semantic-index", "local embedding model preload started", { modelId, cacheDir });
|
|
18784
|
+
appLogger.info("semantic-index", "local embedding model preload started", { modelId, downloadSource, cacheDir });
|
|
18374
18785
|
void this.getEmbedder().preload?.().then(() => {
|
|
18786
|
+
if (preloadGeneration !== this.modelPreloadGeneration) return;
|
|
18375
18787
|
this.modelPreloadStatus = "ready";
|
|
18376
|
-
appLogger.info("semantic-index", "local embedding model preload completed", {
|
|
18788
|
+
appLogger.info("semantic-index", "local embedding model preload completed", {
|
|
18789
|
+
modelId,
|
|
18790
|
+
downloadSource,
|
|
18791
|
+
cacheDir
|
|
18792
|
+
});
|
|
18377
18793
|
}).catch((error) => {
|
|
18794
|
+
if (preloadGeneration !== this.modelPreloadGeneration) return;
|
|
18378
18795
|
this.modelPreloadStatus = "error";
|
|
18379
|
-
appLogger.error(
|
|
18796
|
+
appLogger.error(
|
|
18797
|
+
"semantic-index",
|
|
18798
|
+
`local embedding model preload failed: ${modelId} via ${downloadSource}`,
|
|
18799
|
+
error
|
|
18800
|
+
);
|
|
18380
18801
|
});
|
|
18381
18802
|
}
|
|
18382
18803
|
return saved;
|
|
@@ -18805,7 +19226,9 @@ ${text}`;
|
|
|
18805
19226
|
checkStop
|
|
18806
19227
|
});
|
|
18807
19228
|
const currentConfig = this.configStore.get();
|
|
18808
|
-
|
|
19229
|
+
const jobDownloadSource = jobConfig.mode === "local" ? jobConfig.local.downloadSource ?? DEFAULT_SEMANTIC_INDEX_MODEL_DOWNLOAD_SOURCE : null;
|
|
19230
|
+
const currentDownloadSource = currentConfig.mode === "local" ? currentConfig.local.downloadSource ?? DEFAULT_SEMANTIC_INDEX_MODEL_DOWNLOAD_SOURCE : null;
|
|
19231
|
+
if (result.status === "completed" && result.chunksWritten > 0 && jobConfig.mode === "local" && currentConfig.mode === "local" && currentConfig.local.modelId === jobConfig.local.modelId && currentDownloadSource === jobDownloadSource) {
|
|
18809
19232
|
this.modelPreloadStatus = "ready";
|
|
18810
19233
|
}
|
|
18811
19234
|
appLogger.info("semantic-index", "warmup job finished", {
|
|
@@ -19245,6 +19668,13 @@ async function pushImport(dbManager, sessionId, payload) {
|
|
|
19245
19668
|
|
|
19246
19669
|
export {
|
|
19247
19670
|
writeParseResultToDb,
|
|
19671
|
+
detectFormat,
|
|
19672
|
+
detectAllFormats,
|
|
19673
|
+
getSupportedFormats,
|
|
19674
|
+
getFormatFeatureById,
|
|
19675
|
+
scanMultiChatFile,
|
|
19676
|
+
findEntryFileInDirectory,
|
|
19677
|
+
logNativeParserStatus,
|
|
19248
19678
|
LogLevel,
|
|
19249
19679
|
initPerfLog,
|
|
19250
19680
|
logPerf,
|
|
@@ -19255,12 +19685,6 @@ export {
|
|
|
19255
19685
|
logInfo,
|
|
19256
19686
|
getErrorCount,
|
|
19257
19687
|
logSummary,
|
|
19258
|
-
detectFormat,
|
|
19259
|
-
detectAllFormats,
|
|
19260
|
-
getSupportedFormats,
|
|
19261
|
-
getFormatFeatureById,
|
|
19262
|
-
scanMultiChatFile,
|
|
19263
|
-
findEntryFileInDirectory,
|
|
19264
19688
|
computeWordFrequency,
|
|
19265
19689
|
segmentText,
|
|
19266
19690
|
isDictDownloaded,
|
|
@@ -19316,6 +19740,9 @@ export {
|
|
|
19316
19740
|
manualCompress,
|
|
19317
19741
|
createCompressionLlmAdapter,
|
|
19318
19742
|
preprocessMessages,
|
|
19743
|
+
preprocessMessagesWithStats,
|
|
19744
|
+
desensitizeText,
|
|
19745
|
+
matchesBlacklist,
|
|
19319
19746
|
DESENSITIZE_RULES_SCHEMA_VERSION,
|
|
19320
19747
|
BUILTIN_DESENSITIZE_RULES,
|
|
19321
19748
|
getDefaultRulesForLocale,
|
|
@@ -19399,6 +19826,7 @@ export {
|
|
|
19399
19826
|
deriveParentId,
|
|
19400
19827
|
parseParentBounds,
|
|
19401
19828
|
estimateTokens2 as estimateTokens,
|
|
19829
|
+
DEFAULT_SEMANTIC_INDEX_MODEL_DOWNLOAD_SOURCE,
|
|
19402
19830
|
SEMANTIC_INDEX_CONFIG_VERSION,
|
|
19403
19831
|
SEARCH_MAX_RESULTS_DEFAULT,
|
|
19404
19832
|
SEARCH_MAX_RESULTS_MIN,
|
|
@@ -19440,4 +19868,4 @@ export {
|
|
|
19440
19868
|
MergeSessionCache,
|
|
19441
19869
|
pushImport
|
|
19442
19870
|
};
|
|
19443
|
-
//# sourceMappingURL=chunk-
|
|
19871
|
+
//# sourceMappingURL=chunk-36JGKW6K.mjs.map
|