@tradejs/infra 1.0.9 → 1.0.11
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/ai.d.mts +39 -3
- package/dist/ai.d.ts +39 -3
- package/dist/ai.js +404 -28
- package/dist/ai.mjs +372 -24
- package/dist/backtestArtifacts.d.mts +57 -0
- package/dist/backtestArtifacts.d.ts +57 -0
- package/dist/backtestArtifacts.js +255 -0
- package/dist/backtestArtifacts.mjs +211 -0
- package/dist/{chunk-KVEZORMS.mjs → chunk-RQP5VSTH.mjs} +54 -3
- package/dist/{chunk-MLVWC2I2.mjs → chunk-XZQ6COOV.mjs} +62 -5
- package/dist/ml.d.mts +1 -1
- package/dist/ml.d.ts +1 -1
- package/dist/ml.js +55 -3
- package/dist/ml.mjs +3 -1
- package/dist/{mlDatasetFile-sRGWgR_o.d.mts → mlDatasetFile-Czx__g9M.d.mts} +7 -1
- package/dist/{mlDatasetFile-sRGWgR_o.d.ts → mlDatasetFile-Czx__g9M.d.ts} +7 -1
- package/dist/redis.d.mts +23 -3
- package/dist/redis.d.ts +23 -3
- package/dist/redis.js +65 -5
- package/dist/redis.mjs +7 -1
- package/dist/timescale.d.mts +221 -5
- package/dist/timescale.d.ts +221 -5
- package/dist/timescale.js +2022 -93
- package/dist/timescale.mjs +1994 -93
- package/dist/tradingAccounts.d.mts +20 -0
- package/dist/tradingAccounts.d.ts +20 -0
- package/dist/tradingAccounts.js +558 -0
- package/dist/tradingAccounts.mjs +190 -0
- package/dist/userSettings.d.mts +2 -0
- package/dist/userSettings.d.ts +2 -0
- package/dist/userSettings.js +26 -5
- package/dist/userSettings.mjs +2 -1
- package/package.json +13 -3
package/dist/ai.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AiDatasetRow } from '@tradejs/types';
|
|
2
|
-
export { m as mergeJsonlFiles, t as toFileToken } from './mlDatasetFile-
|
|
2
|
+
export { m as mergeJsonlFiles, t as toFileToken } from './mlDatasetFile-Czx__g9M.mjs';
|
|
3
3
|
|
|
4
4
|
declare const getAiChunkFilePath: (strategyName: string, chunkId: string, outDir?: string) => string;
|
|
5
5
|
declare const appendAiDatasetRow: (params: {
|
|
@@ -14,6 +14,11 @@ declare const closeAllAiDatasetWriters: () => Promise<void>;
|
|
|
14
14
|
declare const listAiChunkFiles: (params: {
|
|
15
15
|
strategyName: string;
|
|
16
16
|
outDir?: string;
|
|
17
|
+
runId?: string;
|
|
18
|
+
}) => Promise<string[]>;
|
|
19
|
+
declare const listAiChunkRunIds: (params: {
|
|
20
|
+
strategyName: string;
|
|
21
|
+
outDir?: string;
|
|
17
22
|
}) => Promise<string[]>;
|
|
18
23
|
declare const listAiChunkStrategies: (params?: {
|
|
19
24
|
outDir?: string;
|
|
@@ -23,14 +28,45 @@ declare const mergeAiJsonlFiles: (params: {
|
|
|
23
28
|
outPath: string;
|
|
24
29
|
maxRowsInMemory?: number;
|
|
25
30
|
maxBytesInMemory?: number;
|
|
31
|
+
maxOpenRuns?: number;
|
|
32
|
+
shouldIncludeRow?: (row: AiDatasetRow) => boolean;
|
|
26
33
|
}) => Promise<void>;
|
|
27
|
-
declare const
|
|
34
|
+
declare const splitAiMergedDatasetFile: (params: {
|
|
28
35
|
filePath: string;
|
|
36
|
+
monthsPerPart?: number;
|
|
37
|
+
}) => Promise<{
|
|
38
|
+
partPaths: string[];
|
|
39
|
+
partCount: number;
|
|
40
|
+
rowCount: number;
|
|
41
|
+
splitApplied: boolean;
|
|
42
|
+
}>;
|
|
43
|
+
declare const readAiDatasetRows: (params: {
|
|
44
|
+
filePath?: string;
|
|
45
|
+
filePaths?: string[];
|
|
29
46
|
limitFromEnd?: number;
|
|
30
47
|
skipFromEnd?: number;
|
|
31
48
|
}) => Promise<{
|
|
32
49
|
rows: AiDatasetRow[];
|
|
33
50
|
totalRows: number;
|
|
34
51
|
}>;
|
|
52
|
+
declare const countAiDatasetRows: (params: {
|
|
53
|
+
filePath?: string;
|
|
54
|
+
filePaths?: string[];
|
|
55
|
+
limitFromEnd?: number;
|
|
56
|
+
skipFromEnd?: number;
|
|
57
|
+
}) => Promise<{
|
|
58
|
+
totalRows: number;
|
|
59
|
+
selectedRows: number;
|
|
60
|
+
}>;
|
|
61
|
+
declare const streamAiDatasetRows: (params: {
|
|
62
|
+
filePath?: string;
|
|
63
|
+
filePaths?: string[];
|
|
64
|
+
limitFromEnd?: number;
|
|
65
|
+
skipFromEnd?: number;
|
|
66
|
+
onRow: (row: AiDatasetRow, index: number) => Promise<void> | void;
|
|
67
|
+
}) => Promise<{
|
|
68
|
+
totalRows: number;
|
|
69
|
+
selectedRows: number;
|
|
70
|
+
}>;
|
|
35
71
|
|
|
36
|
-
export { appendAiDatasetRow, closeAiDatasetWriter, closeAllAiDatasetWriters, flushAiDatasetWriter, getAiChunkFilePath, listAiChunkFiles, listAiChunkStrategies, mergeAiJsonlFiles, readAiDatasetRows };
|
|
72
|
+
export { appendAiDatasetRow, closeAiDatasetWriter, closeAllAiDatasetWriters, countAiDatasetRows, flushAiDatasetWriter, getAiChunkFilePath, listAiChunkFiles, listAiChunkRunIds, listAiChunkStrategies, mergeAiJsonlFiles, readAiDatasetRows, splitAiMergedDatasetFile, streamAiDatasetRows };
|
package/dist/ai.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AiDatasetRow } from '@tradejs/types';
|
|
2
|
-
export { m as mergeJsonlFiles, t as toFileToken } from './mlDatasetFile-
|
|
2
|
+
export { m as mergeJsonlFiles, t as toFileToken } from './mlDatasetFile-Czx__g9M.js';
|
|
3
3
|
|
|
4
4
|
declare const getAiChunkFilePath: (strategyName: string, chunkId: string, outDir?: string) => string;
|
|
5
5
|
declare const appendAiDatasetRow: (params: {
|
|
@@ -14,6 +14,11 @@ declare const closeAllAiDatasetWriters: () => Promise<void>;
|
|
|
14
14
|
declare const listAiChunkFiles: (params: {
|
|
15
15
|
strategyName: string;
|
|
16
16
|
outDir?: string;
|
|
17
|
+
runId?: string;
|
|
18
|
+
}) => Promise<string[]>;
|
|
19
|
+
declare const listAiChunkRunIds: (params: {
|
|
20
|
+
strategyName: string;
|
|
21
|
+
outDir?: string;
|
|
17
22
|
}) => Promise<string[]>;
|
|
18
23
|
declare const listAiChunkStrategies: (params?: {
|
|
19
24
|
outDir?: string;
|
|
@@ -23,14 +28,45 @@ declare const mergeAiJsonlFiles: (params: {
|
|
|
23
28
|
outPath: string;
|
|
24
29
|
maxRowsInMemory?: number;
|
|
25
30
|
maxBytesInMemory?: number;
|
|
31
|
+
maxOpenRuns?: number;
|
|
32
|
+
shouldIncludeRow?: (row: AiDatasetRow) => boolean;
|
|
26
33
|
}) => Promise<void>;
|
|
27
|
-
declare const
|
|
34
|
+
declare const splitAiMergedDatasetFile: (params: {
|
|
28
35
|
filePath: string;
|
|
36
|
+
monthsPerPart?: number;
|
|
37
|
+
}) => Promise<{
|
|
38
|
+
partPaths: string[];
|
|
39
|
+
partCount: number;
|
|
40
|
+
rowCount: number;
|
|
41
|
+
splitApplied: boolean;
|
|
42
|
+
}>;
|
|
43
|
+
declare const readAiDatasetRows: (params: {
|
|
44
|
+
filePath?: string;
|
|
45
|
+
filePaths?: string[];
|
|
29
46
|
limitFromEnd?: number;
|
|
30
47
|
skipFromEnd?: number;
|
|
31
48
|
}) => Promise<{
|
|
32
49
|
rows: AiDatasetRow[];
|
|
33
50
|
totalRows: number;
|
|
34
51
|
}>;
|
|
52
|
+
declare const countAiDatasetRows: (params: {
|
|
53
|
+
filePath?: string;
|
|
54
|
+
filePaths?: string[];
|
|
55
|
+
limitFromEnd?: number;
|
|
56
|
+
skipFromEnd?: number;
|
|
57
|
+
}) => Promise<{
|
|
58
|
+
totalRows: number;
|
|
59
|
+
selectedRows: number;
|
|
60
|
+
}>;
|
|
61
|
+
declare const streamAiDatasetRows: (params: {
|
|
62
|
+
filePath?: string;
|
|
63
|
+
filePaths?: string[];
|
|
64
|
+
limitFromEnd?: number;
|
|
65
|
+
skipFromEnd?: number;
|
|
66
|
+
onRow: (row: AiDatasetRow, index: number) => Promise<void> | void;
|
|
67
|
+
}) => Promise<{
|
|
68
|
+
totalRows: number;
|
|
69
|
+
selectedRows: number;
|
|
70
|
+
}>;
|
|
35
71
|
|
|
36
|
-
export { appendAiDatasetRow, closeAiDatasetWriter, closeAllAiDatasetWriters, flushAiDatasetWriter, getAiChunkFilePath, listAiChunkFiles, listAiChunkStrategies, mergeAiJsonlFiles, readAiDatasetRows };
|
|
72
|
+
export { appendAiDatasetRow, closeAiDatasetWriter, closeAllAiDatasetWriters, countAiDatasetRows, flushAiDatasetWriter, getAiChunkFilePath, listAiChunkFiles, listAiChunkRunIds, listAiChunkStrategies, mergeAiJsonlFiles, readAiDatasetRows, splitAiMergedDatasetFile, streamAiDatasetRows };
|
package/dist/ai.js
CHANGED
|
@@ -33,13 +33,17 @@ __export(ai_exports, {
|
|
|
33
33
|
appendAiDatasetRow: () => appendAiDatasetRow,
|
|
34
34
|
closeAiDatasetWriter: () => closeAiDatasetWriter,
|
|
35
35
|
closeAllAiDatasetWriters: () => closeAllAiDatasetWriters,
|
|
36
|
+
countAiDatasetRows: () => countAiDatasetRows,
|
|
36
37
|
flushAiDatasetWriter: () => flushAiDatasetWriter,
|
|
37
38
|
getAiChunkFilePath: () => getAiChunkFilePath,
|
|
38
39
|
listAiChunkFiles: () => listAiChunkFiles,
|
|
40
|
+
listAiChunkRunIds: () => listAiChunkRunIds,
|
|
39
41
|
listAiChunkStrategies: () => listAiChunkStrategies,
|
|
40
42
|
mergeAiJsonlFiles: () => mergeAiJsonlFiles,
|
|
41
43
|
mergeJsonlFiles: () => mergeJsonlFiles,
|
|
42
44
|
readAiDatasetRows: () => readAiDatasetRows,
|
|
45
|
+
splitAiMergedDatasetFile: () => splitAiMergedDatasetFile,
|
|
46
|
+
streamAiDatasetRows: () => streamAiDatasetRows,
|
|
43
47
|
toFileToken: () => toFileToken
|
|
44
48
|
});
|
|
45
49
|
module.exports = __toCommonJS(ai_exports);
|
|
@@ -50,21 +54,99 @@ var import_fs2 = require("fs");
|
|
|
50
54
|
var import_promises2 = __toESM(require("fs/promises"));
|
|
51
55
|
var import_path2 = __toESM(require("path"));
|
|
52
56
|
var import_node_fs = require("fs");
|
|
53
|
-
var
|
|
57
|
+
var import_node_readline2 = __toESM(require("readline"));
|
|
58
|
+
|
|
59
|
+
// ../../node_modules/date-fns/toDate.mjs
|
|
60
|
+
function toDate(argument) {
|
|
61
|
+
const argStr = Object.prototype.toString.call(argument);
|
|
62
|
+
if (argument instanceof Date || typeof argument === "object" && argStr === "[object Date]") {
|
|
63
|
+
return new argument.constructor(+argument);
|
|
64
|
+
} else if (typeof argument === "number" || argStr === "[object Number]" || typeof argument === "string" || argStr === "[object String]") {
|
|
65
|
+
return new Date(argument);
|
|
66
|
+
} else {
|
|
67
|
+
return /* @__PURE__ */ new Date(NaN);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// ../../node_modules/date-fns/constructFrom.mjs
|
|
72
|
+
function constructFrom(date, value) {
|
|
73
|
+
if (date instanceof Date) {
|
|
74
|
+
return new date.constructor(value);
|
|
75
|
+
} else {
|
|
76
|
+
return new Date(value);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// ../../node_modules/date-fns/addMonths.mjs
|
|
81
|
+
function addMonths(date, amount) {
|
|
82
|
+
const _date = toDate(date);
|
|
83
|
+
if (isNaN(amount)) return constructFrom(date, NaN);
|
|
84
|
+
if (!amount) {
|
|
85
|
+
return _date;
|
|
86
|
+
}
|
|
87
|
+
const dayOfMonth = _date.getDate();
|
|
88
|
+
const endOfDesiredMonth = constructFrom(date, _date.getTime());
|
|
89
|
+
endOfDesiredMonth.setMonth(_date.getMonth() + amount + 1, 0);
|
|
90
|
+
const daysInMonth = endOfDesiredMonth.getDate();
|
|
91
|
+
if (dayOfMonth >= daysInMonth) {
|
|
92
|
+
return endOfDesiredMonth;
|
|
93
|
+
} else {
|
|
94
|
+
_date.setFullYear(
|
|
95
|
+
endOfDesiredMonth.getFullYear(),
|
|
96
|
+
endOfDesiredMonth.getMonth(),
|
|
97
|
+
dayOfMonth
|
|
98
|
+
);
|
|
99
|
+
return _date;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// ../../node_modules/date-fns/startOfMonth.mjs
|
|
104
|
+
function startOfMonth(date) {
|
|
105
|
+
const _date = toDate(date);
|
|
106
|
+
_date.setDate(1);
|
|
107
|
+
_date.setHours(0, 0, 0, 0);
|
|
108
|
+
return _date;
|
|
109
|
+
}
|
|
54
110
|
|
|
55
111
|
// src/mlDatasetFile.ts
|
|
56
112
|
var import_events = require("events");
|
|
57
113
|
var import_fs = require("fs");
|
|
58
114
|
var import_promises = __toESM(require("fs/promises"));
|
|
59
115
|
var import_path = __toESM(require("path"));
|
|
116
|
+
var import_node_readline = __toESM(require("readline"));
|
|
60
117
|
var toFileToken = (value) => value.trim().toLowerCase().replace(/[^a-z0-9_-]+/g, "_").replace(/^_+|_+$/g, "") || "any";
|
|
61
118
|
var mergeJsonlFiles = async (params) => {
|
|
62
|
-
const { filePaths, outPath } = params;
|
|
119
|
+
const { filePaths, outPath, shouldIncludeRow } = params;
|
|
63
120
|
await import_promises.default.mkdir(import_path.default.dirname(outPath), { recursive: true });
|
|
64
121
|
const stream = (0, import_fs.createWriteStream)(outPath, { encoding: "utf8" });
|
|
65
122
|
const done = Promise.all([(0, import_events.once)(stream, "finish"), (0, import_events.once)(stream, "close")]);
|
|
66
123
|
try {
|
|
67
124
|
for (const filePath of filePaths) {
|
|
125
|
+
if (shouldIncludeRow) {
|
|
126
|
+
const reader2 = import_node_readline.default.createInterface({
|
|
127
|
+
input: (0, import_fs.createReadStream)(filePath, { encoding: "utf8" }),
|
|
128
|
+
crlfDelay: Infinity
|
|
129
|
+
});
|
|
130
|
+
try {
|
|
131
|
+
for await (const line of reader2) {
|
|
132
|
+
const trimmed = line.trim();
|
|
133
|
+
if (!trimmed) {
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
const row = JSON.parse(trimmed);
|
|
137
|
+
if (!shouldIncludeRow(row)) {
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
if (!stream.write(`${trimmed}
|
|
141
|
+
`)) {
|
|
142
|
+
await (0, import_events.once)(stream, "drain");
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
} finally {
|
|
146
|
+
reader2.close();
|
|
147
|
+
}
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
68
150
|
const reader = (0, import_fs.createReadStream)(filePath, { encoding: "utf8" });
|
|
69
151
|
for await (const chunk of reader) {
|
|
70
152
|
if (!stream.write(chunk)) {
|
|
@@ -83,12 +165,23 @@ var DEFAULT_DIR = "data/ai/export";
|
|
|
83
165
|
var AI_DATASET_WRITE_BATCH_SIZE = 100;
|
|
84
166
|
var AI_MERGE_SORT_RUN_MAX_ROWS = 2e3;
|
|
85
167
|
var AI_MERGE_SORT_RUN_MAX_BYTES = 16 * 1024 * 1024;
|
|
168
|
+
var AI_MERGE_SORT_MAX_OPEN_RUNS = 16;
|
|
86
169
|
var AI_CHUNK_FILE_RE = /^ai-dataset-(.+)-chunk-[^.]+\.jsonl$/;
|
|
170
|
+
var BACKTEST_RUN_CHUNK_ID_RE = /^(\d{12}-[a-f0-9]{8})-/;
|
|
87
171
|
var writerByPath = /* @__PURE__ */ new Map();
|
|
88
172
|
var getAiChunkFilePath = (strategyName, chunkId, outDir = DEFAULT_DIR) => import_path2.default.join(
|
|
89
173
|
outDir,
|
|
90
174
|
`ai-dataset-${toFileToken(strategyName)}-chunk-${toFileToken(chunkId)}.jsonl`
|
|
91
175
|
);
|
|
176
|
+
var getAiChunkFilePrefix = (strategyName, runId) => `ai-dataset-${toFileToken(strategyName)}-chunk-${runId ? `${toFileToken(runId)}-` : ""}`;
|
|
177
|
+
var getRunIdFromAiChunkFileName = (strategyName, fileName) => {
|
|
178
|
+
const prefix = getAiChunkFilePrefix(strategyName);
|
|
179
|
+
if (!fileName.startsWith(prefix) || !fileName.endsWith(".jsonl")) {
|
|
180
|
+
return "";
|
|
181
|
+
}
|
|
182
|
+
const chunkToken = fileName.slice(prefix.length, -".jsonl".length);
|
|
183
|
+
return chunkToken.match(BACKTEST_RUN_CHUNK_ID_RE)?.[1] ?? "";
|
|
184
|
+
};
|
|
92
185
|
var appendAiDatasetRow = async (params) => {
|
|
93
186
|
const { strategyName, chunkId, row, outDir = DEFAULT_DIR } = params;
|
|
94
187
|
const filePath = getAiChunkFilePath(strategyName, chunkId, outDir);
|
|
@@ -164,8 +257,8 @@ var closeAllAiDatasetWriters = async () => {
|
|
|
164
257
|
}
|
|
165
258
|
};
|
|
166
259
|
var listAiChunkFiles = async (params) => {
|
|
167
|
-
const { strategyName, outDir = DEFAULT_DIR } = params;
|
|
168
|
-
const prefix =
|
|
260
|
+
const { strategyName, outDir = DEFAULT_DIR, runId } = params;
|
|
261
|
+
const prefix = getAiChunkFilePrefix(strategyName, runId);
|
|
169
262
|
let entries = [];
|
|
170
263
|
try {
|
|
171
264
|
entries = await import_promises2.default.readdir(outDir);
|
|
@@ -174,6 +267,20 @@ var listAiChunkFiles = async (params) => {
|
|
|
174
267
|
}
|
|
175
268
|
return entries.filter((name) => name.startsWith(prefix) && name.endsWith(".jsonl")).map((name) => import_path2.default.join(outDir, name)).sort();
|
|
176
269
|
};
|
|
270
|
+
var listAiChunkRunIds = async (params) => {
|
|
271
|
+
const { strategyName, outDir = DEFAULT_DIR } = params;
|
|
272
|
+
let entries = [];
|
|
273
|
+
try {
|
|
274
|
+
entries = await import_promises2.default.readdir(outDir);
|
|
275
|
+
} catch {
|
|
276
|
+
return [];
|
|
277
|
+
}
|
|
278
|
+
return [
|
|
279
|
+
...new Set(
|
|
280
|
+
entries.map((name) => getRunIdFromAiChunkFileName(strategyName, name)).filter(Boolean)
|
|
281
|
+
)
|
|
282
|
+
].sort();
|
|
283
|
+
};
|
|
177
284
|
var listAiChunkStrategies = async (params) => {
|
|
178
285
|
const outDir = params?.outDir ?? DEFAULT_DIR;
|
|
179
286
|
let entries = [];
|
|
@@ -272,7 +379,7 @@ var readNextNonEmptyLine = async (iterator) => {
|
|
|
272
379
|
}
|
|
273
380
|
}
|
|
274
381
|
};
|
|
275
|
-
var
|
|
382
|
+
var mergeSortedRunBatch = async (params) => {
|
|
276
383
|
const { runPaths, outPath } = params;
|
|
277
384
|
await import_promises2.default.mkdir(import_path2.default.dirname(outPath), { recursive: true });
|
|
278
385
|
const output = (0, import_fs2.createWriteStream)(outPath, { encoding: "utf8" });
|
|
@@ -284,7 +391,7 @@ var mergeSortedRuns = async (params) => {
|
|
|
284
391
|
try {
|
|
285
392
|
for (let runIndex = 0; runIndex < runPaths.length; runIndex += 1) {
|
|
286
393
|
const runPath = runPaths[runIndex];
|
|
287
|
-
const reader =
|
|
394
|
+
const reader = import_node_readline2.default.createInterface({
|
|
288
395
|
input: (0, import_node_fs.createReadStream)(runPath, { encoding: "utf8" }),
|
|
289
396
|
crlfDelay: Infinity
|
|
290
397
|
});
|
|
@@ -333,12 +440,58 @@ var mergeSortedRuns = async (params) => {
|
|
|
333
440
|
await outputDone;
|
|
334
441
|
}
|
|
335
442
|
};
|
|
443
|
+
var mergeSortedRuns = async (params) => {
|
|
444
|
+
const {
|
|
445
|
+
runPaths,
|
|
446
|
+
outPath,
|
|
447
|
+
tempDir,
|
|
448
|
+
maxOpenRuns = AI_MERGE_SORT_MAX_OPEN_RUNS
|
|
449
|
+
} = params;
|
|
450
|
+
const resolvedMaxOpenRuns = Math.max(2, Math.trunc(maxOpenRuns));
|
|
451
|
+
let currentRunPaths = [...runPaths];
|
|
452
|
+
let passIndex = 0;
|
|
453
|
+
while (currentRunPaths.length > resolvedMaxOpenRuns) {
|
|
454
|
+
const nextRunPaths = [];
|
|
455
|
+
for (let groupStart = 0, groupIndex = 0; groupStart < currentRunPaths.length; groupStart += resolvedMaxOpenRuns, groupIndex += 1) {
|
|
456
|
+
const groupRunPaths = currentRunPaths.slice(
|
|
457
|
+
groupStart,
|
|
458
|
+
groupStart + resolvedMaxOpenRuns
|
|
459
|
+
);
|
|
460
|
+
if (groupRunPaths.length === 1) {
|
|
461
|
+
nextRunPaths.push(groupRunPaths[0]);
|
|
462
|
+
continue;
|
|
463
|
+
}
|
|
464
|
+
const passPath = import_path2.default.join(
|
|
465
|
+
tempDir,
|
|
466
|
+
`merge-pass-${String(passIndex).padStart(3, "0")}-${String(
|
|
467
|
+
groupIndex
|
|
468
|
+
).padStart(6, "0")}.jsonl`
|
|
469
|
+
);
|
|
470
|
+
await mergeSortedRunBatch({
|
|
471
|
+
runPaths: groupRunPaths,
|
|
472
|
+
outPath: passPath
|
|
473
|
+
});
|
|
474
|
+
nextRunPaths.push(passPath);
|
|
475
|
+
await Promise.all(
|
|
476
|
+
groupRunPaths.map((runPath) => import_promises2.default.rm(runPath, { force: true }))
|
|
477
|
+
);
|
|
478
|
+
}
|
|
479
|
+
currentRunPaths = nextRunPaths;
|
|
480
|
+
passIndex += 1;
|
|
481
|
+
}
|
|
482
|
+
await mergeSortedRunBatch({
|
|
483
|
+
runPaths: currentRunPaths,
|
|
484
|
+
outPath
|
|
485
|
+
});
|
|
486
|
+
};
|
|
336
487
|
var mergeAiJsonlFiles = async (params) => {
|
|
337
488
|
const {
|
|
338
489
|
filePaths,
|
|
339
490
|
outPath,
|
|
340
491
|
maxRowsInMemory = AI_MERGE_SORT_RUN_MAX_ROWS,
|
|
341
|
-
maxBytesInMemory = AI_MERGE_SORT_RUN_MAX_BYTES
|
|
492
|
+
maxBytesInMemory = AI_MERGE_SORT_RUN_MAX_BYTES,
|
|
493
|
+
maxOpenRuns = AI_MERGE_SORT_MAX_OPEN_RUNS,
|
|
494
|
+
shouldIncludeRow
|
|
342
495
|
} = params;
|
|
343
496
|
const tempDir = import_path2.default.join(
|
|
344
497
|
import_path2.default.dirname(outPath),
|
|
@@ -367,7 +520,7 @@ var mergeAiJsonlFiles = async (params) => {
|
|
|
367
520
|
try {
|
|
368
521
|
await import_promises2.default.mkdir(tempDir, { recursive: true });
|
|
369
522
|
for (const filePath of filePaths) {
|
|
370
|
-
const reader =
|
|
523
|
+
const reader = import_node_readline2.default.createInterface({
|
|
371
524
|
input: (0, import_node_fs.createReadStream)(filePath, { encoding: "utf8" }),
|
|
372
525
|
crlfDelay: Infinity
|
|
373
526
|
});
|
|
@@ -377,9 +530,13 @@ var mergeAiJsonlFiles = async (params) => {
|
|
|
377
530
|
if (!trimmed) {
|
|
378
531
|
continue;
|
|
379
532
|
}
|
|
533
|
+
const row = parseAiDatasetLine(trimmed, filePath);
|
|
534
|
+
if (shouldIncludeRow && !shouldIncludeRow(row)) {
|
|
535
|
+
continue;
|
|
536
|
+
}
|
|
380
537
|
batch.push({
|
|
381
538
|
line: trimmed,
|
|
382
|
-
sortKey: getAiDatasetSortKey(
|
|
539
|
+
sortKey: getAiDatasetSortKey(row),
|
|
383
540
|
sourceIndex
|
|
384
541
|
});
|
|
385
542
|
sourceIndex += 1;
|
|
@@ -400,37 +557,145 @@ var mergeAiJsonlFiles = async (params) => {
|
|
|
400
557
|
}
|
|
401
558
|
await mergeSortedRuns({
|
|
402
559
|
runPaths,
|
|
403
|
-
outPath
|
|
560
|
+
outPath,
|
|
561
|
+
tempDir,
|
|
562
|
+
maxOpenRuns
|
|
404
563
|
});
|
|
405
564
|
} finally {
|
|
406
565
|
await import_promises2.default.rm(tempDir, { recursive: true, force: true });
|
|
407
566
|
}
|
|
408
567
|
};
|
|
568
|
+
var getAiDatasetPartPath = (filePath, partIndex) => {
|
|
569
|
+
const parsed = import_path2.default.parse(filePath);
|
|
570
|
+
return import_path2.default.join(parsed.dir, `${parsed.name}-part${partIndex}${parsed.ext}`);
|
|
571
|
+
};
|
|
572
|
+
var getPartWindowEndExclusive = (timestamp, monthsPerPart) => {
|
|
573
|
+
const partStart = startOfMonth(new Date(timestamp));
|
|
574
|
+
return addMonths(partStart, Math.max(1, monthsPerPart)).getTime();
|
|
575
|
+
};
|
|
576
|
+
var splitAiMergedDatasetFile = async (params) => {
|
|
577
|
+
const { filePath, monthsPerPart = 2 } = params;
|
|
578
|
+
const resolvedMonthsPerPart = Math.max(1, Math.trunc(monthsPerPart));
|
|
579
|
+
const reader = import_node_readline2.default.createInterface({
|
|
580
|
+
input: (0, import_node_fs.createReadStream)(filePath, { encoding: "utf8" }),
|
|
581
|
+
crlfDelay: Infinity
|
|
582
|
+
});
|
|
583
|
+
const partPaths = [];
|
|
584
|
+
let currentPartIndex = 0;
|
|
585
|
+
let currentPartPath = "";
|
|
586
|
+
let currentPartEndExclusive = Number.NaN;
|
|
587
|
+
let currentWriter = null;
|
|
588
|
+
let currentWriterDone = null;
|
|
589
|
+
let rowCount = 0;
|
|
590
|
+
const openPart = async (timestamp) => {
|
|
591
|
+
currentPartIndex += 1;
|
|
592
|
+
currentPartPath = getAiDatasetPartPath(filePath, currentPartIndex);
|
|
593
|
+
currentPartEndExclusive = getPartWindowEndExclusive(
|
|
594
|
+
timestamp,
|
|
595
|
+
resolvedMonthsPerPart
|
|
596
|
+
);
|
|
597
|
+
currentWriter = (0, import_fs2.createWriteStream)(currentPartPath, { encoding: "utf8" });
|
|
598
|
+
currentWriterDone = Promise.all([
|
|
599
|
+
(0, import_events2.once)(currentWriter, "finish"),
|
|
600
|
+
(0, import_events2.once)(currentWriter, "close")
|
|
601
|
+
]);
|
|
602
|
+
partPaths.push(currentPartPath);
|
|
603
|
+
};
|
|
604
|
+
const closeCurrentWriter = async () => {
|
|
605
|
+
if (!currentWriter || !currentWriterDone) {
|
|
606
|
+
return;
|
|
607
|
+
}
|
|
608
|
+
currentWriter.end();
|
|
609
|
+
await currentWriterDone;
|
|
610
|
+
currentWriter = null;
|
|
611
|
+
currentWriterDone = null;
|
|
612
|
+
};
|
|
613
|
+
const getCurrentWriter = () => {
|
|
614
|
+
if (!currentWriter) {
|
|
615
|
+
throw new Error(
|
|
616
|
+
`AI dataset part writer was not initialized for ${filePath}`
|
|
617
|
+
);
|
|
618
|
+
}
|
|
619
|
+
return currentWriter;
|
|
620
|
+
};
|
|
621
|
+
try {
|
|
622
|
+
for await (const line of reader) {
|
|
623
|
+
const trimmed = line.trim();
|
|
624
|
+
if (!trimmed) {
|
|
625
|
+
continue;
|
|
626
|
+
}
|
|
627
|
+
const row = parseAiDatasetLine(trimmed, filePath);
|
|
628
|
+
const timestamp = Number(row.timestamp);
|
|
629
|
+
const safeTimestamp = Number.isFinite(timestamp) ? timestamp : Date.now();
|
|
630
|
+
if (!currentWriter || !Number.isFinite(currentPartEndExclusive) || safeTimestamp >= currentPartEndExclusive) {
|
|
631
|
+
await closeCurrentWriter();
|
|
632
|
+
await openPart(safeTimestamp);
|
|
633
|
+
}
|
|
634
|
+
const writer = getCurrentWriter();
|
|
635
|
+
if (!writer.write(`${trimmed}
|
|
636
|
+
`)) {
|
|
637
|
+
await (0, import_events2.once)(writer, "drain");
|
|
638
|
+
}
|
|
639
|
+
rowCount += 1;
|
|
640
|
+
}
|
|
641
|
+
} finally {
|
|
642
|
+
reader.close();
|
|
643
|
+
await closeCurrentWriter();
|
|
644
|
+
}
|
|
645
|
+
if (partPaths.length <= 1) {
|
|
646
|
+
for (const partPath of partPaths) {
|
|
647
|
+
await import_promises2.default.rm(partPath, { force: true });
|
|
648
|
+
}
|
|
649
|
+
return {
|
|
650
|
+
partPaths: [filePath],
|
|
651
|
+
partCount: partPaths.length || (rowCount > 0 ? 1 : 0),
|
|
652
|
+
rowCount,
|
|
653
|
+
splitApplied: false
|
|
654
|
+
};
|
|
655
|
+
}
|
|
656
|
+
await import_promises2.default.rm(filePath, { force: true });
|
|
657
|
+
return {
|
|
658
|
+
partPaths,
|
|
659
|
+
partCount: partPaths.length,
|
|
660
|
+
rowCount,
|
|
661
|
+
splitApplied: true
|
|
662
|
+
};
|
|
663
|
+
};
|
|
409
664
|
var readAiDatasetRows = async (params) => {
|
|
410
|
-
const {
|
|
665
|
+
const { limitFromEnd = 0, skipFromEnd = 0 } = params;
|
|
666
|
+
const resolvedFilePaths = resolveAiDatasetFilePaths(params);
|
|
667
|
+
if (!resolvedFilePaths.length) {
|
|
668
|
+
return {
|
|
669
|
+
rows: [],
|
|
670
|
+
totalRows: 0
|
|
671
|
+
};
|
|
672
|
+
}
|
|
411
673
|
const rows = [];
|
|
412
674
|
const recentLines = [];
|
|
413
675
|
let totalRows = 0;
|
|
414
676
|
const recentWindowLimit = limitFromEnd > 0 ? limitFromEnd + Math.max(0, skipFromEnd) : 0;
|
|
415
|
-
const
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
const
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
if (
|
|
427
|
-
recentLines.
|
|
677
|
+
for (const currentFilePath of resolvedFilePaths) {
|
|
678
|
+
const reader = import_node_readline2.default.createInterface({
|
|
679
|
+
input: (0, import_node_fs.createReadStream)(currentFilePath, { encoding: "utf8" }),
|
|
680
|
+
crlfDelay: Infinity
|
|
681
|
+
});
|
|
682
|
+
for await (const line of reader) {
|
|
683
|
+
const trimmed = line.trim();
|
|
684
|
+
if (!trimmed) {
|
|
685
|
+
continue;
|
|
686
|
+
}
|
|
687
|
+
totalRows += 1;
|
|
688
|
+
if (limitFromEnd > 0) {
|
|
689
|
+
if (recentLines.length === recentWindowLimit) {
|
|
690
|
+
recentLines.shift();
|
|
691
|
+
}
|
|
692
|
+
recentLines.push(trimmed);
|
|
693
|
+
} else {
|
|
694
|
+
const row = JSON.parse(trimmed);
|
|
695
|
+
rows.push(row);
|
|
428
696
|
}
|
|
429
|
-
recentLines.push(trimmed);
|
|
430
|
-
} else {
|
|
431
|
-
const row = JSON.parse(trimmed);
|
|
432
|
-
rows.push(row);
|
|
433
697
|
}
|
|
698
|
+
reader.close();
|
|
434
699
|
}
|
|
435
700
|
const effectiveSkip = Math.max(0, skipFromEnd);
|
|
436
701
|
const selectedRecentLines = effectiveSkip > 0 ? recentLines.slice(0, Math.max(0, recentLines.length - effectiveSkip)) : recentLines;
|
|
@@ -440,17 +705,128 @@ var readAiDatasetRows = async (params) => {
|
|
|
440
705
|
totalRows
|
|
441
706
|
};
|
|
442
707
|
};
|
|
708
|
+
var resolveAiDatasetFilePaths = (params) => (Array.isArray(params.filePaths) && params.filePaths.length ? params.filePaths : params.filePath ? [params.filePath] : []).map((item) => import_path2.default.resolve(item));
|
|
709
|
+
var countNonEmptyAiDatasetRows = async (filePath) => {
|
|
710
|
+
let totalRows = 0;
|
|
711
|
+
const reader = import_node_readline2.default.createInterface({
|
|
712
|
+
input: (0, import_node_fs.createReadStream)(filePath, { encoding: "utf8" }),
|
|
713
|
+
crlfDelay: Infinity
|
|
714
|
+
});
|
|
715
|
+
for await (const line of reader) {
|
|
716
|
+
if (line.trim()) {
|
|
717
|
+
totalRows += 1;
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
reader.close();
|
|
721
|
+
return totalRows;
|
|
722
|
+
};
|
|
723
|
+
var countAiDatasetRows = async (params) => {
|
|
724
|
+
const { limitFromEnd = 0, skipFromEnd = 0 } = params;
|
|
725
|
+
const resolvedFilePaths = resolveAiDatasetFilePaths(params);
|
|
726
|
+
let totalRows = 0;
|
|
727
|
+
for (const filePath of resolvedFilePaths) {
|
|
728
|
+
totalRows += await countNonEmptyAiDatasetRows(filePath);
|
|
729
|
+
}
|
|
730
|
+
const effectiveSkip = Math.max(0, skipFromEnd);
|
|
731
|
+
const selectedRows = limitFromEnd > 0 ? Math.min(limitFromEnd, Math.max(0, totalRows - effectiveSkip)) : Math.max(0, totalRows - effectiveSkip);
|
|
732
|
+
return {
|
|
733
|
+
totalRows,
|
|
734
|
+
selectedRows
|
|
735
|
+
};
|
|
736
|
+
};
|
|
737
|
+
var streamAiDatasetRows = async (params) => {
|
|
738
|
+
const { limitFromEnd = 0, skipFromEnd = 0, onRow } = params;
|
|
739
|
+
const resolvedFilePaths = resolveAiDatasetFilePaths(params);
|
|
740
|
+
if (!resolvedFilePaths.length) {
|
|
741
|
+
return {
|
|
742
|
+
totalRows: 0,
|
|
743
|
+
selectedRows: 0
|
|
744
|
+
};
|
|
745
|
+
}
|
|
746
|
+
const effectiveSkip = Math.max(0, skipFromEnd);
|
|
747
|
+
let totalRows = 0;
|
|
748
|
+
let selectedRows = 0;
|
|
749
|
+
if (limitFromEnd > 0) {
|
|
750
|
+
const recentLines = [];
|
|
751
|
+
const recentWindowLimit = limitFromEnd + effectiveSkip;
|
|
752
|
+
for (const currentFilePath of resolvedFilePaths) {
|
|
753
|
+
const reader = import_node_readline2.default.createInterface({
|
|
754
|
+
input: (0, import_node_fs.createReadStream)(currentFilePath, { encoding: "utf8" }),
|
|
755
|
+
crlfDelay: Infinity
|
|
756
|
+
});
|
|
757
|
+
for await (const line of reader) {
|
|
758
|
+
const trimmed = line.trim();
|
|
759
|
+
if (!trimmed) {
|
|
760
|
+
continue;
|
|
761
|
+
}
|
|
762
|
+
totalRows += 1;
|
|
763
|
+
if (recentLines.length === recentWindowLimit) {
|
|
764
|
+
recentLines.shift();
|
|
765
|
+
}
|
|
766
|
+
recentLines.push(trimmed);
|
|
767
|
+
}
|
|
768
|
+
reader.close();
|
|
769
|
+
}
|
|
770
|
+
const selectedRecentLines = effectiveSkip > 0 ? recentLines.slice(0, Math.max(0, recentLines.length - effectiveSkip)) : recentLines;
|
|
771
|
+
for (const line of selectedRecentLines) {
|
|
772
|
+
await onRow(JSON.parse(line), selectedRows);
|
|
773
|
+
selectedRows += 1;
|
|
774
|
+
}
|
|
775
|
+
return {
|
|
776
|
+
totalRows,
|
|
777
|
+
selectedRows
|
|
778
|
+
};
|
|
779
|
+
}
|
|
780
|
+
const trailingSkipBuffer = [];
|
|
781
|
+
for (const currentFilePath of resolvedFilePaths) {
|
|
782
|
+
const reader = import_node_readline2.default.createInterface({
|
|
783
|
+
input: (0, import_node_fs.createReadStream)(currentFilePath, { encoding: "utf8" }),
|
|
784
|
+
crlfDelay: Infinity
|
|
785
|
+
});
|
|
786
|
+
for await (const line of reader) {
|
|
787
|
+
const trimmed = line.trim();
|
|
788
|
+
if (!trimmed) {
|
|
789
|
+
continue;
|
|
790
|
+
}
|
|
791
|
+
totalRows += 1;
|
|
792
|
+
if (effectiveSkip > 0) {
|
|
793
|
+
trailingSkipBuffer.push(trimmed);
|
|
794
|
+
if (trailingSkipBuffer.length <= effectiveSkip) {
|
|
795
|
+
continue;
|
|
796
|
+
}
|
|
797
|
+
const selectedLine = trailingSkipBuffer.shift();
|
|
798
|
+
if (!selectedLine) {
|
|
799
|
+
continue;
|
|
800
|
+
}
|
|
801
|
+
await onRow(JSON.parse(selectedLine), selectedRows);
|
|
802
|
+
selectedRows += 1;
|
|
803
|
+
continue;
|
|
804
|
+
}
|
|
805
|
+
await onRow(JSON.parse(trimmed), selectedRows);
|
|
806
|
+
selectedRows += 1;
|
|
807
|
+
}
|
|
808
|
+
reader.close();
|
|
809
|
+
}
|
|
810
|
+
return {
|
|
811
|
+
totalRows,
|
|
812
|
+
selectedRows
|
|
813
|
+
};
|
|
814
|
+
};
|
|
443
815
|
// Annotate the CommonJS export names for ESM import in node:
|
|
444
816
|
0 && (module.exports = {
|
|
445
817
|
appendAiDatasetRow,
|
|
446
818
|
closeAiDatasetWriter,
|
|
447
819
|
closeAllAiDatasetWriters,
|
|
820
|
+
countAiDatasetRows,
|
|
448
821
|
flushAiDatasetWriter,
|
|
449
822
|
getAiChunkFilePath,
|
|
450
823
|
listAiChunkFiles,
|
|
824
|
+
listAiChunkRunIds,
|
|
451
825
|
listAiChunkStrategies,
|
|
452
826
|
mergeAiJsonlFiles,
|
|
453
827
|
mergeJsonlFiles,
|
|
454
828
|
readAiDatasetRows,
|
|
829
|
+
splitAiMergedDatasetFile,
|
|
830
|
+
streamAiDatasetRows,
|
|
455
831
|
toFileToken
|
|
456
832
|
});
|