@exulu/backend 3.3.1 → 3.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{catalog-UGTDNMDM.js → catalog-PZTI2MJZ.js} +1 -1
- package/dist/{chunk-7CCMW3IW.js → chunk-NUVMV5FC.js} +53 -6
- package/dist/{chunk-5FTX543Z.js → chunk-UIIUBZCO.js} +27 -55
- package/dist/{convert-exulu-tools-to-ai-sdk-tools-WQWYMU7G.js → convert-exulu-tools-to-ai-sdk-tools-AB4F55SD.js} +2 -2
- package/dist/index.cjs +162 -154
- package/dist/index.js +45 -62
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1233,6 +1233,53 @@ var init_table_names = __esm({
|
|
|
1233
1233
|
}
|
|
1234
1234
|
});
|
|
1235
1235
|
|
|
1236
|
+
// src/exulu/litellm/env.ts
|
|
1237
|
+
function litellmBase() {
|
|
1238
|
+
const host = process.env.LITELLM_HOST ?? "127.0.0.1";
|
|
1239
|
+
const port = process.env.LITELLM_PORT ?? "4000";
|
|
1240
|
+
const masterKey = process.env.LITELLM_MASTER_KEY;
|
|
1241
|
+
if (!masterKey) {
|
|
1242
|
+
throw new LiteLLMAdminError("LITELLM_MASTER_KEY is not configured.");
|
|
1243
|
+
}
|
|
1244
|
+
return { url: `http://${host}:${port}`, masterKey };
|
|
1245
|
+
}
|
|
1246
|
+
function resolveLiteLLMTarget() {
|
|
1247
|
+
const rawBase = process.env.LITELLM_BASE_URL;
|
|
1248
|
+
if (rawBase && rawBase.trim().length > 0) {
|
|
1249
|
+
const apiKey = process.env.EXULU_API_KEY;
|
|
1250
|
+
if (!apiKey) {
|
|
1251
|
+
throw new Error("EXULU_API_KEY is required when LITELLM_BASE_URL is set (remote LiteLLM client mode).");
|
|
1252
|
+
}
|
|
1253
|
+
return {
|
|
1254
|
+
baseUrl: rawBase.trim().replace(/\/+$/, ""),
|
|
1255
|
+
authHeaders: { "exulu-api-key": apiKey },
|
|
1256
|
+
remote: true
|
|
1257
|
+
};
|
|
1258
|
+
}
|
|
1259
|
+
const host = process.env.LITELLM_HOST ?? "127.0.0.1";
|
|
1260
|
+
const port = process.env.LITELLM_PORT ?? "4000";
|
|
1261
|
+
const masterKey = process.env.LITELLM_MASTER_KEY;
|
|
1262
|
+
return {
|
|
1263
|
+
baseUrl: `http://${host}:${port}`,
|
|
1264
|
+
authHeaders: masterKey ? { Authorization: `Bearer ${masterKey}` } : {},
|
|
1265
|
+
remote: false
|
|
1266
|
+
};
|
|
1267
|
+
}
|
|
1268
|
+
var LiteLLMAdminError;
|
|
1269
|
+
var init_env = __esm({
|
|
1270
|
+
"src/exulu/litellm/env.ts"() {
|
|
1271
|
+
"use strict";
|
|
1272
|
+
init_cjs_shims();
|
|
1273
|
+
LiteLLMAdminError = class extends Error {
|
|
1274
|
+
constructor(message, status) {
|
|
1275
|
+
super(message);
|
|
1276
|
+
this.status = status;
|
|
1277
|
+
this.name = "LiteLLMAdminError";
|
|
1278
|
+
}
|
|
1279
|
+
};
|
|
1280
|
+
}
|
|
1281
|
+
});
|
|
1282
|
+
|
|
1236
1283
|
// src/exulu/litellm/supervisor.ts
|
|
1237
1284
|
var import_node_child_process, import_node_fs3, import_node_path2, LITELLM_UI_PATH, MAX_CRASHES, INITIAL_BACKOFF_MS, MAX_BACKOFF_MS, READY_TIMEOUT_MS, WAIT_TIMEOUT_MS, READY_POLL_INTERVAL_MS, SHUTDOWN_GRACE_MS, internal, isLiteLLMEnabled, resolveConfig, log2, pollHealth, spawnLiteLLM, supervise, _packageRoot, _clientMode, setLiteLLMPackageRoot, enableLiteLLMClientMode, startLiteLLMSupervisor, waitForLiteLLMReady, stopLiteLLM, shutdownHandlersRegistered, registerShutdownHandlers, getSupervisorState;
|
|
1238
1285
|
var init_supervisor = __esm({
|
|
@@ -1242,6 +1289,7 @@ var init_supervisor = __esm({
|
|
|
1242
1289
|
import_node_child_process = require("child_process");
|
|
1243
1290
|
import_node_fs3 = require("fs");
|
|
1244
1291
|
import_node_path2 = require("path");
|
|
1292
|
+
init_env();
|
|
1245
1293
|
LITELLM_UI_PATH = "/litellm-admin";
|
|
1246
1294
|
MAX_CRASHES = 5;
|
|
1247
1295
|
INITIAL_BACKOFF_MS = 1e3;
|
|
@@ -1426,12 +1474,11 @@ var init_supervisor = __esm({
|
|
|
1426
1474
|
if (!isLiteLLMEnabled()) return;
|
|
1427
1475
|
if (_clientMode) {
|
|
1428
1476
|
if (internal.state === "ready") return;
|
|
1429
|
-
const
|
|
1430
|
-
const
|
|
1431
|
-
const url = `http://${host}:${port}/health/liveliness`;
|
|
1477
|
+
const { baseUrl, authHeaders, remote } = resolveLiteLLMTarget();
|
|
1478
|
+
const url = remote ? `${baseUrl}/v1/models` : `${baseUrl}/health/liveliness`;
|
|
1432
1479
|
let res;
|
|
1433
1480
|
try {
|
|
1434
|
-
res = await fetch(url, { method: "GET" });
|
|
1481
|
+
res = await fetch(url, { method: "GET", headers: remote ? authHeaders : {} });
|
|
1435
1482
|
} catch (err) {
|
|
1436
1483
|
throw new Error(
|
|
1437
1484
|
`LiteLLM proxy not reachable at ${url} (is the Exulu server process running?): ${err.message}`
|
|
@@ -1625,31 +1672,6 @@ var init_tags = __esm({
|
|
|
1625
1672
|
}
|
|
1626
1673
|
});
|
|
1627
1674
|
|
|
1628
|
-
// src/exulu/litellm/env.ts
|
|
1629
|
-
function litellmBase() {
|
|
1630
|
-
const host = process.env.LITELLM_HOST ?? "127.0.0.1";
|
|
1631
|
-
const port = process.env.LITELLM_PORT ?? "4000";
|
|
1632
|
-
const masterKey = process.env.LITELLM_MASTER_KEY;
|
|
1633
|
-
if (!masterKey) {
|
|
1634
|
-
throw new LiteLLMAdminError("LITELLM_MASTER_KEY is not configured.");
|
|
1635
|
-
}
|
|
1636
|
-
return { url: `http://${host}:${port}`, masterKey };
|
|
1637
|
-
}
|
|
1638
|
-
var LiteLLMAdminError;
|
|
1639
|
-
var init_env = __esm({
|
|
1640
|
-
"src/exulu/litellm/env.ts"() {
|
|
1641
|
-
"use strict";
|
|
1642
|
-
init_cjs_shims();
|
|
1643
|
-
LiteLLMAdminError = class extends Error {
|
|
1644
|
-
constructor(message, status) {
|
|
1645
|
-
super(message);
|
|
1646
|
-
this.status = status;
|
|
1647
|
-
this.name = "LiteLLMAdminError";
|
|
1648
|
-
}
|
|
1649
|
-
};
|
|
1650
|
-
}
|
|
1651
|
-
});
|
|
1652
|
-
|
|
1653
1675
|
// src/exulu/litellm/admin-client.ts
|
|
1654
1676
|
async function call(path4, body) {
|
|
1655
1677
|
const { url, masterKey } = litellmBase();
|
|
@@ -2285,6 +2307,7 @@ var init_resolve_model = __esm({
|
|
|
2285
2307
|
init_supervisor();
|
|
2286
2308
|
init_tags();
|
|
2287
2309
|
init_budget_service();
|
|
2310
|
+
init_env();
|
|
2288
2311
|
ResolveModelError = class extends Error {
|
|
2289
2312
|
constructor(code, message) {
|
|
2290
2313
|
super(message);
|
|
@@ -2300,9 +2323,7 @@ var init_resolve_model = __esm({
|
|
|
2300
2323
|
team,
|
|
2301
2324
|
routine
|
|
2302
2325
|
}) => {
|
|
2303
|
-
const
|
|
2304
|
-
const port = process.env.LITELLM_PORT ?? "4000";
|
|
2305
|
-
const masterKey = process.env.LITELLM_MASTER_KEY;
|
|
2326
|
+
const { baseUrl, authHeaders } = resolveLiteLLMTarget();
|
|
2306
2327
|
const tags = buildTags({
|
|
2307
2328
|
user_id: user?.id,
|
|
2308
2329
|
role_id: role?.id,
|
|
@@ -2317,16 +2338,13 @@ var init_resolve_model = __esm({
|
|
|
2317
2338
|
routine_id: routine?.id,
|
|
2318
2339
|
routine_name: routine?.name
|
|
2319
2340
|
});
|
|
2320
|
-
if (!masterKey) {
|
|
2321
|
-
throw new ResolveModelError(
|
|
2322
|
-
"LITELLM_NOT_CONFIGURED",
|
|
2323
|
-
"LITELLM_MASTER_KEY is required when EXULU_USE_LITELLM=true"
|
|
2324
|
-
);
|
|
2325
|
-
}
|
|
2326
2341
|
return (0, import_openai_compatible.createOpenAICompatible)({
|
|
2327
2342
|
name: "litellm",
|
|
2328
|
-
baseURL:
|
|
2329
|
-
apiKey
|
|
2343
|
+
baseURL: `${baseUrl}/v1`,
|
|
2344
|
+
// createOpenAICompatible requires a non-empty apiKey; real auth for remote mode is the
|
|
2345
|
+
// exulu-api-key header (added via `headers`). The passthrough strips/ignores Authorization.
|
|
2346
|
+
apiKey: process.env.LITELLM_MASTER_KEY ?? process.env.EXULU_API_KEY ?? "x",
|
|
2347
|
+
headers: authHeaders,
|
|
2330
2348
|
fetch: createTaggedFetch(tags),
|
|
2331
2349
|
// Without this flag the openai-compatible provider strips any
|
|
2332
2350
|
// responseFormat.schema before sending and warns
|
|
@@ -3320,6 +3338,9 @@ var init_check_item_write_access = __esm({
|
|
|
3320
3338
|
if (record.rights_mode === "private") {
|
|
3321
3339
|
return record.created_by != null && String(record.created_by) === String(user.id);
|
|
3322
3340
|
}
|
|
3341
|
+
if (record.created_by != null && String(record.created_by) === String(user.id)) {
|
|
3342
|
+
return true;
|
|
3343
|
+
}
|
|
3323
3344
|
const validRightsModes = ["users", "roles", "teams"];
|
|
3324
3345
|
if (!validRightsModes.includes(record.rights_mode)) {
|
|
3325
3346
|
return false;
|
|
@@ -4963,6 +4984,7 @@ var init_catalog = __esm({
|
|
|
4963
4984
|
"src/exulu/litellm/catalog.ts"() {
|
|
4964
4985
|
"use strict";
|
|
4965
4986
|
init_cjs_shims();
|
|
4987
|
+
init_env();
|
|
4966
4988
|
CACHE_TTL_MS = 3e4;
|
|
4967
4989
|
__resetLiteLLMCatalogCacheForTesting = () => {
|
|
4968
4990
|
_cache = void 0;
|
|
@@ -4972,14 +4994,18 @@ var init_catalog = __esm({
|
|
|
4972
4994
|
if (_cache && _cache.expiresAt > Date.now()) {
|
|
4973
4995
|
return _cache.items;
|
|
4974
4996
|
}
|
|
4975
|
-
|
|
4976
|
-
|
|
4977
|
-
|
|
4978
|
-
|
|
4997
|
+
let baseUrl;
|
|
4998
|
+
let authHeaders;
|
|
4999
|
+
try {
|
|
5000
|
+
({ baseUrl, authHeaders } = resolveLiteLLMTarget());
|
|
5001
|
+
} catch {
|
|
5002
|
+
return [];
|
|
5003
|
+
}
|
|
5004
|
+
if (Object.keys(authHeaders).length === 0) return [];
|
|
4979
5005
|
try {
|
|
4980
|
-
const res = await fetch(
|
|
5006
|
+
const res = await fetch(`${baseUrl}/model/info`, {
|
|
4981
5007
|
method: "GET",
|
|
4982
|
-
headers:
|
|
5008
|
+
headers: authHeaders
|
|
4983
5009
|
});
|
|
4984
5010
|
if (!res.ok) {
|
|
4985
5011
|
console.error(
|
|
@@ -6564,15 +6590,7 @@ async function resolveReranker(input) {
|
|
|
6564
6590
|
`LiteLLM is not ready: ${err.message}`
|
|
6565
6591
|
);
|
|
6566
6592
|
}
|
|
6567
|
-
const
|
|
6568
|
-
const port = process.env.LITELLM_PORT ?? "4000";
|
|
6569
|
-
const masterKey = process.env.LITELLM_MASTER_KEY;
|
|
6570
|
-
if (!masterKey) {
|
|
6571
|
-
throw new ResolveRerankerError(
|
|
6572
|
-
"LITELLM_NOT_CONFIGURED",
|
|
6573
|
-
"LITELLM_MASTER_KEY is required when EXULU_USE_LITELLM=true"
|
|
6574
|
-
);
|
|
6575
|
-
}
|
|
6593
|
+
const { baseUrl, authHeaders } = resolveLiteLLMTarget();
|
|
6576
6594
|
const resolvedUserId = user?.id ?? userId;
|
|
6577
6595
|
if (resolvedUserId) await provisionDefaultUserBudget(resolvedUserId);
|
|
6578
6596
|
const role = user?.role;
|
|
@@ -6592,7 +6610,7 @@ async function resolveReranker(input) {
|
|
|
6592
6610
|
routine_name: routine?.name,
|
|
6593
6611
|
context_name: contextName
|
|
6594
6612
|
});
|
|
6595
|
-
const endpoint =
|
|
6613
|
+
const endpoint = `${baseUrl}/v1/rerank`;
|
|
6596
6614
|
const rerank2 = async (query, chunks, opts) => {
|
|
6597
6615
|
try {
|
|
6598
6616
|
if (chunks.length === 0) return [];
|
|
@@ -6602,7 +6620,7 @@ async function resolveReranker(input) {
|
|
|
6602
6620
|
const res = await fetch(endpoint, {
|
|
6603
6621
|
method: "POST",
|
|
6604
6622
|
headers: {
|
|
6605
|
-
|
|
6623
|
+
...authHeaders,
|
|
6606
6624
|
"Content-Type": "application/json"
|
|
6607
6625
|
},
|
|
6608
6626
|
body: JSON.stringify({
|
|
@@ -6643,7 +6661,7 @@ async function resolveReranker(input) {
|
|
|
6643
6661
|
};
|
|
6644
6662
|
return { model, rerank: rerank2 };
|
|
6645
6663
|
}
|
|
6646
|
-
var
|
|
6664
|
+
var ResolveRerankerError;
|
|
6647
6665
|
var init_resolve_reranker = __esm({
|
|
6648
6666
|
"src/exulu/resolve-reranker.ts"() {
|
|
6649
6667
|
"use strict";
|
|
@@ -6651,7 +6669,7 @@ var init_resolve_reranker = __esm({
|
|
|
6651
6669
|
init_supervisor();
|
|
6652
6670
|
init_budget_service();
|
|
6653
6671
|
init_tags();
|
|
6654
|
-
|
|
6672
|
+
init_env();
|
|
6655
6673
|
ResolveRerankerError = class extends Error {
|
|
6656
6674
|
constructor(code, message) {
|
|
6657
6675
|
super(message);
|
|
@@ -10019,6 +10037,7 @@ init_cjs_shims();
|
|
|
10019
10037
|
init_supervisor();
|
|
10020
10038
|
init_budget_service();
|
|
10021
10039
|
init_tags();
|
|
10040
|
+
init_env();
|
|
10022
10041
|
var ResolveEmbedderError = class extends Error {
|
|
10023
10042
|
constructor(code, message) {
|
|
10024
10043
|
super(message);
|
|
@@ -10042,15 +10061,7 @@ async function resolveEmbedder(input) {
|
|
|
10042
10061
|
`LiteLLM is not ready: ${err.message}`
|
|
10043
10062
|
);
|
|
10044
10063
|
}
|
|
10045
|
-
const
|
|
10046
|
-
const port = process.env.LITELLM_PORT ?? "4000";
|
|
10047
|
-
const masterKey = process.env.LITELLM_MASTER_KEY;
|
|
10048
|
-
if (!masterKey) {
|
|
10049
|
-
throw new ResolveEmbedderError(
|
|
10050
|
-
"LITELLM_NOT_CONFIGURED",
|
|
10051
|
-
"LITELLM_MASTER_KEY is required when EXULU_USE_LITELLM=true"
|
|
10052
|
-
);
|
|
10053
|
-
}
|
|
10064
|
+
const { baseUrl, authHeaders } = resolveLiteLLMTarget();
|
|
10054
10065
|
const resolvedUserId = user?.id ?? userId;
|
|
10055
10066
|
if (resolvedUserId) await provisionDefaultUserBudget(resolvedUserId);
|
|
10056
10067
|
const { dimensionality, maxChunkSize, maxBatchSize } = getEmbeddingModelInfo(model);
|
|
@@ -10071,12 +10082,12 @@ async function resolveEmbedder(input) {
|
|
|
10071
10082
|
routine_name: routine?.name,
|
|
10072
10083
|
context_name: contextName
|
|
10073
10084
|
});
|
|
10074
|
-
const endpoint =
|
|
10085
|
+
const endpoint = `${baseUrl}/v1/embeddings`;
|
|
10075
10086
|
const embedBatch = async (batch) => {
|
|
10076
10087
|
const res = await fetch(endpoint, {
|
|
10077
10088
|
method: "POST",
|
|
10078
10089
|
headers: {
|
|
10079
|
-
|
|
10090
|
+
...authHeaders,
|
|
10080
10091
|
"Content-Type": "application/json"
|
|
10081
10092
|
},
|
|
10082
10093
|
body: JSON.stringify({
|
|
@@ -15120,20 +15131,25 @@ async function encryptString(string) {
|
|
|
15120
15131
|
const hash = await import_bcryptjs2.default.hash(string, SALT_ROUNDS);
|
|
15121
15132
|
return hash;
|
|
15122
15133
|
}
|
|
15123
|
-
var generateApiKey = async (name, email) => {
|
|
15134
|
+
var generateApiKey = async (name, email, options) => {
|
|
15124
15135
|
const { db: db2 } = await postgresClient();
|
|
15125
15136
|
email = String(email).trim().toLowerCase();
|
|
15137
|
+
const superAdmin = options?.superAdmin ?? true;
|
|
15138
|
+
const roleName = options?.roleName ?? "admin";
|
|
15139
|
+
const rolePermissions = options?.rolePermissions ?? {
|
|
15140
|
+
agents: "write",
|
|
15141
|
+
workflows: "write",
|
|
15142
|
+
variables: "write",
|
|
15143
|
+
users: "write"
|
|
15144
|
+
};
|
|
15126
15145
|
console.log("[EXULU] Inserting default user and admin role.");
|
|
15127
|
-
const existingRole = await db2.from("roles").where({ name:
|
|
15146
|
+
const existingRole = await db2.from("roles").where({ name: roleName }).first();
|
|
15128
15147
|
let roleId;
|
|
15129
15148
|
if (!existingRole) {
|
|
15130
|
-
console.log(
|
|
15149
|
+
console.log(`[EXULU] Creating default ${roleName} role.`);
|
|
15131
15150
|
const role = await db2.from("roles").insert({
|
|
15132
|
-
name:
|
|
15133
|
-
|
|
15134
|
-
workflows: "write",
|
|
15135
|
-
variables: "write",
|
|
15136
|
-
users: "write"
|
|
15151
|
+
name: roleName,
|
|
15152
|
+
...rolePermissions
|
|
15137
15153
|
}).returning("id");
|
|
15138
15154
|
roleId = role[0].id;
|
|
15139
15155
|
} else {
|
|
@@ -15149,7 +15165,7 @@ var generateApiKey = async (name, email) => {
|
|
|
15149
15165
|
await db2.from("users").insert({
|
|
15150
15166
|
name,
|
|
15151
15167
|
email,
|
|
15152
|
-
super_admin:
|
|
15168
|
+
super_admin: superAdmin,
|
|
15153
15169
|
createdAt: /* @__PURE__ */ new Date(),
|
|
15154
15170
|
updatedAt: /* @__PURE__ */ new Date(),
|
|
15155
15171
|
type: "api",
|
|
@@ -15735,6 +15751,9 @@ function createMutations(table, contexts, tools, config) {
|
|
|
15735
15751
|
}
|
|
15736
15752
|
throw new Error("Only the creator can edit this private record");
|
|
15737
15753
|
}
|
|
15754
|
+
if (record.created_by != null && String(record.created_by) === String(user.id)) {
|
|
15755
|
+
return true;
|
|
15756
|
+
}
|
|
15738
15757
|
if (record.rights_mode === "users") {
|
|
15739
15758
|
const rbacRecord = await db2.from("rbac").where({
|
|
15740
15759
|
entity: table.name.singular,
|
|
@@ -19681,7 +19700,7 @@ var mapRoutineRunRow = (row, routineById) => {
|
|
|
19681
19700
|
|
|
19682
19701
|
// src/graphql/schemas/index.ts
|
|
19683
19702
|
init_entitlements();
|
|
19684
|
-
var
|
|
19703
|
+
var import_fs2 = require("fs");
|
|
19685
19704
|
|
|
19686
19705
|
// src/exulu/transcription/service.ts
|
|
19687
19706
|
init_cjs_shims();
|
|
@@ -23636,7 +23655,7 @@ var import_utils5 = require("@apollo/utils.keyvaluecache");
|
|
|
23636
23655
|
var import_body_parser = __toESM(require("body-parser"), 1);
|
|
23637
23656
|
var import_crypto_js7 = require("crypto-js");
|
|
23638
23657
|
var import_openai = require("openai");
|
|
23639
|
-
var
|
|
23658
|
+
var import_fs3 = __toESM(require("fs"), 1);
|
|
23640
23659
|
var import_node_crypto15 = require("crypto");
|
|
23641
23660
|
var import_api2 = require("@opentelemetry/api");
|
|
23642
23661
|
var import_jszip3 = __toESM(require("jszip"), 1);
|
|
@@ -23855,6 +23874,7 @@ ${summary}` }],
|
|
|
23855
23874
|
|
|
23856
23875
|
// src/exulu/transcribe.ts
|
|
23857
23876
|
init_cjs_shims();
|
|
23877
|
+
init_env();
|
|
23858
23878
|
var TranscriptionError = class extends Error {
|
|
23859
23879
|
constructor(upstreamStatus, message) {
|
|
23860
23880
|
super(message);
|
|
@@ -23863,11 +23883,8 @@ var TranscriptionError = class extends Error {
|
|
|
23863
23883
|
}
|
|
23864
23884
|
};
|
|
23865
23885
|
async function transcribeAudio(args) {
|
|
23866
|
-
const
|
|
23867
|
-
const port = process.env.LITELLM_PORT ?? "4000";
|
|
23868
|
-
const masterKey = process.env.LITELLM_MASTER_KEY;
|
|
23886
|
+
const { baseUrl, authHeaders } = resolveLiteLLMTarget();
|
|
23869
23887
|
const model = process.env.TRANSCRIPTION_MODEL;
|
|
23870
|
-
if (!masterKey) throw new Error("LITELLM_MASTER_KEY is not set");
|
|
23871
23888
|
if (!model) throw new Error("TRANSCRIPTION_MODEL is not set");
|
|
23872
23889
|
const form = new FormData();
|
|
23873
23890
|
form.append(
|
|
@@ -23877,9 +23894,9 @@ async function transcribeAudio(args) {
|
|
|
23877
23894
|
);
|
|
23878
23895
|
form.append("model", model);
|
|
23879
23896
|
if (args.language) form.append("language", args.language);
|
|
23880
|
-
const res = await fetch(
|
|
23897
|
+
const res = await fetch(`${baseUrl}/v1/audio/transcriptions`, {
|
|
23881
23898
|
method: "POST",
|
|
23882
|
-
headers: {
|
|
23899
|
+
headers: { ...authHeaders },
|
|
23883
23900
|
body: form
|
|
23884
23901
|
});
|
|
23885
23902
|
if (!res.ok) {
|
|
@@ -23895,6 +23912,7 @@ async function transcribeAudio(args) {
|
|
|
23895
23912
|
|
|
23896
23913
|
// src/exulu/speech.ts
|
|
23897
23914
|
init_cjs_shims();
|
|
23915
|
+
init_env();
|
|
23898
23916
|
var SpeechError = class extends Error {
|
|
23899
23917
|
constructor(upstreamStatus, message) {
|
|
23900
23918
|
super(message);
|
|
@@ -23903,12 +23921,9 @@ var SpeechError = class extends Error {
|
|
|
23903
23921
|
}
|
|
23904
23922
|
};
|
|
23905
23923
|
async function synthesizeSpeech(args) {
|
|
23906
|
-
const
|
|
23907
|
-
const port = process.env.LITELLM_PORT ?? "4000";
|
|
23908
|
-
const masterKey = process.env.LITELLM_MASTER_KEY;
|
|
23924
|
+
const { baseUrl, authHeaders } = resolveLiteLLMTarget();
|
|
23909
23925
|
const model = process.env.TTS_MODEL;
|
|
23910
23926
|
const voice = process.env.TTS_VOICE;
|
|
23911
|
-
if (!masterKey) throw new Error("LITELLM_MASTER_KEY is not set");
|
|
23912
23927
|
if (!model) throw new Error("TTS_MODEL is not set");
|
|
23913
23928
|
if (!voice) throw new Error("TTS_VOICE is not set");
|
|
23914
23929
|
const body = {
|
|
@@ -23917,10 +23932,10 @@ async function synthesizeSpeech(args) {
|
|
|
23917
23932
|
voice,
|
|
23918
23933
|
response_format: "mp3"
|
|
23919
23934
|
};
|
|
23920
|
-
const res = await fetch(
|
|
23935
|
+
const res = await fetch(`${baseUrl}/v1/audio/speech`, {
|
|
23921
23936
|
method: "POST",
|
|
23922
23937
|
headers: {
|
|
23923
|
-
|
|
23938
|
+
...authHeaders,
|
|
23924
23939
|
"Content-Type": "application/json"
|
|
23925
23940
|
},
|
|
23926
23941
|
body: JSON.stringify(body)
|
|
@@ -23938,6 +23953,7 @@ async function synthesizeSpeech(args) {
|
|
|
23938
23953
|
|
|
23939
23954
|
// src/exulu/image-generation.ts
|
|
23940
23955
|
init_cjs_shims();
|
|
23956
|
+
init_env();
|
|
23941
23957
|
var ImageGenerationError = class extends Error {
|
|
23942
23958
|
constructor(upstreamStatus, message) {
|
|
23943
23959
|
super(message);
|
|
@@ -23945,13 +23961,6 @@ var ImageGenerationError = class extends Error {
|
|
|
23945
23961
|
this.name = "ImageGenerationError";
|
|
23946
23962
|
}
|
|
23947
23963
|
};
|
|
23948
|
-
var resolveProxyConfig = () => {
|
|
23949
|
-
const host = process.env.LITELLM_HOST ?? "127.0.0.1";
|
|
23950
|
-
const port = process.env.LITELLM_PORT ?? "4000";
|
|
23951
|
-
const masterKey = process.env.LITELLM_MASTER_KEY;
|
|
23952
|
-
if (!masterKey) throw new Error("LITELLM_MASTER_KEY is not set");
|
|
23953
|
-
return { host, port, masterKey };
|
|
23954
|
-
};
|
|
23955
23964
|
var normalizeDataEntries = async (data) => {
|
|
23956
23965
|
const out = [];
|
|
23957
23966
|
for (const entry of data) {
|
|
@@ -23988,7 +23997,7 @@ var normalizeDataEntries = async (data) => {
|
|
|
23988
23997
|
async function generateImage(args) {
|
|
23989
23998
|
if (!args.model) throw new Error("model is required");
|
|
23990
23999
|
if (!args.prompt) throw new Error("prompt is required");
|
|
23991
|
-
const
|
|
24000
|
+
const { baseUrl, authHeaders } = resolveLiteLLMTarget();
|
|
23992
24001
|
const body = {
|
|
23993
24002
|
model: args.model,
|
|
23994
24003
|
prompt: args.prompt
|
|
@@ -23996,10 +24005,10 @@ async function generateImage(args) {
|
|
|
23996
24005
|
if (args.size) body.size = args.size;
|
|
23997
24006
|
if (args.quality) body.quality = args.quality;
|
|
23998
24007
|
if (args.n) body.n = args.n;
|
|
23999
|
-
const res = await fetch(
|
|
24008
|
+
const res = await fetch(`${baseUrl}/v1/images/generations`, {
|
|
24000
24009
|
method: "POST",
|
|
24001
24010
|
headers: {
|
|
24002
|
-
|
|
24011
|
+
...authHeaders,
|
|
24003
24012
|
"Content-Type": "application/json"
|
|
24004
24013
|
},
|
|
24005
24014
|
body: JSON.stringify(body),
|
|
@@ -24027,7 +24036,7 @@ async function editImage(args) {
|
|
|
24027
24036
|
if (!args.references || args.references.length === 0) {
|
|
24028
24037
|
throw new Error("at least one reference image is required");
|
|
24029
24038
|
}
|
|
24030
|
-
const
|
|
24039
|
+
const { baseUrl, authHeaders } = resolveLiteLLMTarget();
|
|
24031
24040
|
const form = new FormData();
|
|
24032
24041
|
form.append("model", args.model);
|
|
24033
24042
|
form.append("prompt", args.prompt);
|
|
@@ -24049,9 +24058,9 @@ async function editImage(args) {
|
|
|
24049
24058
|
args.mask.filename
|
|
24050
24059
|
);
|
|
24051
24060
|
}
|
|
24052
|
-
const res = await fetch(
|
|
24061
|
+
const res = await fetch(`${baseUrl}/v1/images/edits`, {
|
|
24053
24062
|
method: "POST",
|
|
24054
|
-
headers: {
|
|
24063
|
+
headers: { ...authHeaders },
|
|
24055
24064
|
body: form,
|
|
24056
24065
|
signal: args.signal
|
|
24057
24066
|
});
|
|
@@ -24201,6 +24210,12 @@ var import_node_path9 = require("path");
|
|
|
24201
24210
|
init_tags();
|
|
24202
24211
|
init_admin_client();
|
|
24203
24212
|
init_env();
|
|
24213
|
+
|
|
24214
|
+
// src/exulu/litellm/passthrough-allowlist.ts
|
|
24215
|
+
init_cjs_shims();
|
|
24216
|
+
var isLiteLLMPassthroughPathAllowed = (path4) => path4.startsWith("/v1/") || path4 === "/model/info";
|
|
24217
|
+
|
|
24218
|
+
// src/exulu/routes.ts
|
|
24204
24219
|
init_activity_client();
|
|
24205
24220
|
init_budget_service();
|
|
24206
24221
|
|
|
@@ -24901,7 +24916,7 @@ var REQUEST_SIZE_LIMIT = "50mb";
|
|
|
24901
24916
|
var getExuluVersionNumber = async () => {
|
|
24902
24917
|
try {
|
|
24903
24918
|
const path4 = process.cwd();
|
|
24904
|
-
const packageJson =
|
|
24919
|
+
const packageJson = import_fs3.default.readFileSync(path4 + "/package.json", "utf8");
|
|
24905
24920
|
const packageData = JSON.parse(packageJson);
|
|
24906
24921
|
const exuluVersion = packageData.dependencies["@exulu/backend"];
|
|
24907
24922
|
console.log(`[EXULU] Installed exulu-backend version: ${exuluVersion}`);
|
|
@@ -26453,7 +26468,7 @@ ${style.markdown}` : params.prompt;
|
|
|
26453
26468
|
return;
|
|
26454
26469
|
}
|
|
26455
26470
|
const user = authenticationResult.user;
|
|
26456
|
-
if (!req.path
|
|
26471
|
+
if (!isLiteLLMPassthroughPathAllowed(req.path)) {
|
|
26457
26472
|
res.status(403).json({
|
|
26458
26473
|
detail: `Path ${req.path} is not exposed through the Exulu LiteLLM proxy.`
|
|
26459
26474
|
});
|
|
@@ -29883,7 +29898,7 @@ init_cjs_shims();
|
|
|
29883
29898
|
var import_child_process = require("child_process");
|
|
29884
29899
|
var import_util = require("util");
|
|
29885
29900
|
var import_path3 = require("path");
|
|
29886
|
-
var
|
|
29901
|
+
var import_fs4 = require("fs");
|
|
29887
29902
|
var import_url = require("url");
|
|
29888
29903
|
var execAsync4 = (0, import_util.promisify)(import_child_process.exec);
|
|
29889
29904
|
function getPackageRoot() {
|
|
@@ -29893,9 +29908,9 @@ function getPackageRoot() {
|
|
|
29893
29908
|
const maxAttempts = 10;
|
|
29894
29909
|
while (attempts < maxAttempts) {
|
|
29895
29910
|
const packageJsonPath = (0, import_path3.join)(currentDir, "package.json");
|
|
29896
|
-
if ((0,
|
|
29911
|
+
if ((0, import_fs4.existsSync)(packageJsonPath)) {
|
|
29897
29912
|
try {
|
|
29898
|
-
const packageJson = JSON.parse((0,
|
|
29913
|
+
const packageJson = JSON.parse((0, import_fs4.readFileSync)(packageJsonPath, "utf-8"));
|
|
29899
29914
|
if (packageJson.name === "@exulu/backend") {
|
|
29900
29915
|
return currentDir;
|
|
29901
29916
|
}
|
|
@@ -29922,7 +29937,7 @@ function isPythonEnvironmentSetup(packageRoot) {
|
|
|
29922
29937
|
const root = packageRoot ?? getPackageRoot();
|
|
29923
29938
|
const venvPath = getVenvPath(root);
|
|
29924
29939
|
const pythonPath = (0, import_path3.join)(venvPath, "bin", "python");
|
|
29925
|
-
return (0,
|
|
29940
|
+
return (0, import_fs4.existsSync)(venvPath) && (0, import_fs4.existsSync)(pythonPath);
|
|
29926
29941
|
}
|
|
29927
29942
|
async function setupPythonEnvironment(options = {}) {
|
|
29928
29943
|
const {
|
|
@@ -29943,7 +29958,7 @@ async function setupPythonEnvironment(options = {}) {
|
|
|
29943
29958
|
};
|
|
29944
29959
|
}
|
|
29945
29960
|
const setupScriptPath = getSetupScriptPath(packageRoot);
|
|
29946
|
-
if (!(0,
|
|
29961
|
+
if (!(0, import_fs4.existsSync)(setupScriptPath)) {
|
|
29947
29962
|
return {
|
|
29948
29963
|
success: false,
|
|
29949
29964
|
message: `Setup script not found at: ${setupScriptPath}`,
|
|
@@ -30025,13 +30040,13 @@ async function validatePythonEnvironment(packageRoot, checkPackages = true) {
|
|
|
30025
30040
|
const root = packageRoot ?? getPackageRoot();
|
|
30026
30041
|
const venvPath = getVenvPath(root);
|
|
30027
30042
|
const pythonPath = (0, import_path3.join)(venvPath, "bin", "python");
|
|
30028
|
-
if (!(0,
|
|
30043
|
+
if (!(0, import_fs4.existsSync)(venvPath)) {
|
|
30029
30044
|
return {
|
|
30030
30045
|
valid: false,
|
|
30031
30046
|
message: getPythonSetupInstructions()
|
|
30032
30047
|
};
|
|
30033
30048
|
}
|
|
30034
|
-
if (!(0,
|
|
30049
|
+
if (!(0, import_fs4.existsSync)(pythonPath)) {
|
|
30035
30050
|
return {
|
|
30036
30051
|
valid: false,
|
|
30037
30052
|
message: "Python virtual environment is corrupted. Please run:\n await setupPythonEnvironment({ force: true })"
|
|
@@ -32581,7 +32596,7 @@ var MarkdownChunker = class {
|
|
|
32581
32596
|
|
|
32582
32597
|
// ee/python/documents/processing/doc_processor.ts
|
|
32583
32598
|
init_cjs_shims();
|
|
32584
|
-
var
|
|
32599
|
+
var fs4 = __toESM(require("fs"), 1);
|
|
32585
32600
|
var path3 = __toESM(require("path"), 1);
|
|
32586
32601
|
var import_ai14 = require("ai");
|
|
32587
32602
|
var import_zod27 = require("zod");
|
|
@@ -32599,7 +32614,7 @@ init_cjs_shims();
|
|
|
32599
32614
|
var import_child_process2 = require("child_process");
|
|
32600
32615
|
var import_util3 = require("util");
|
|
32601
32616
|
var import_path4 = require("path");
|
|
32602
|
-
var
|
|
32617
|
+
var import_fs5 = require("fs");
|
|
32603
32618
|
var import_url2 = require("url");
|
|
32604
32619
|
var execAsync5 = (0, import_util3.promisify)(import_child_process2.exec);
|
|
32605
32620
|
function getPackageRoot2() {
|
|
@@ -32609,9 +32624,9 @@ function getPackageRoot2() {
|
|
|
32609
32624
|
const maxAttempts = 10;
|
|
32610
32625
|
while (attempts < maxAttempts) {
|
|
32611
32626
|
const packageJsonPath = (0, import_path4.join)(currentDir, "package.json");
|
|
32612
|
-
if ((0,
|
|
32627
|
+
if ((0, import_fs5.existsSync)(packageJsonPath)) {
|
|
32613
32628
|
try {
|
|
32614
|
-
const packageJson = JSON.parse((0,
|
|
32629
|
+
const packageJson = JSON.parse((0, import_fs5.readFileSync)(packageJsonPath, "utf-8"));
|
|
32615
32630
|
if (packageJson.name === "@exulu/backend") {
|
|
32616
32631
|
return currentDir;
|
|
32617
32632
|
}
|
|
@@ -32673,7 +32688,7 @@ async function executePythonScript(config) {
|
|
|
32673
32688
|
await validatePythonEnvironmentForExecution(packageRoot);
|
|
32674
32689
|
}
|
|
32675
32690
|
const resolvedScriptPath = (0, import_path4.resolve)(packageRoot, scriptPath);
|
|
32676
|
-
if (!(0,
|
|
32691
|
+
if (!(0, import_fs5.existsSync)(resolvedScriptPath)) {
|
|
32677
32692
|
throw new PythonExecutionError(
|
|
32678
32693
|
`Python script not found: ${resolvedScriptPath}`,
|
|
32679
32694
|
"",
|
|
@@ -32743,6 +32758,7 @@ init_cjs_shims();
|
|
|
32743
32758
|
init_supervisor();
|
|
32744
32759
|
init_budget_service();
|
|
32745
32760
|
init_tags();
|
|
32761
|
+
init_env();
|
|
32746
32762
|
var ResolveOcrError = class extends Error {
|
|
32747
32763
|
constructor(code, message) {
|
|
32748
32764
|
super(message);
|
|
@@ -32766,15 +32782,7 @@ async function resolveOcr(input) {
|
|
|
32766
32782
|
`LiteLLM is not ready: ${err.message}`
|
|
32767
32783
|
);
|
|
32768
32784
|
}
|
|
32769
|
-
const
|
|
32770
|
-
const port = process.env.LITELLM_PORT ?? "4000";
|
|
32771
|
-
const masterKey = process.env.LITELLM_MASTER_KEY;
|
|
32772
|
-
if (!masterKey) {
|
|
32773
|
-
throw new ResolveOcrError(
|
|
32774
|
-
"LITELLM_NOT_CONFIGURED",
|
|
32775
|
-
"LITELLM_MASTER_KEY is required when EXULU_USE_LITELLM=true"
|
|
32776
|
-
);
|
|
32777
|
-
}
|
|
32785
|
+
const { baseUrl, authHeaders } = resolveLiteLLMTarget();
|
|
32778
32786
|
const resolvedUserId = user?.id ?? userId;
|
|
32779
32787
|
if (resolvedUserId) await provisionDefaultUserBudget(resolvedUserId);
|
|
32780
32788
|
const role = user?.role;
|
|
@@ -32794,12 +32802,12 @@ async function resolveOcr(input) {
|
|
|
32794
32802
|
routine_name: routine?.name,
|
|
32795
32803
|
context_name: contextName
|
|
32796
32804
|
});
|
|
32797
|
-
const endpoint =
|
|
32805
|
+
const endpoint = `${baseUrl}/v1/ocr`;
|
|
32798
32806
|
const ocr = async (document2, opts) => {
|
|
32799
32807
|
const res = await fetch(endpoint, {
|
|
32800
32808
|
method: "POST",
|
|
32801
32809
|
headers: {
|
|
32802
|
-
|
|
32810
|
+
...authHeaders,
|
|
32803
32811
|
"Content-Type": "application/json"
|
|
32804
32812
|
},
|
|
32805
32813
|
body: JSON.stringify({
|
|
@@ -32877,9 +32885,9 @@ async function resolveVlmModel(config) {
|
|
|
32877
32885
|
}
|
|
32878
32886
|
async function processImage(buffer, paths, config, verbose = false) {
|
|
32879
32887
|
try {
|
|
32880
|
-
await
|
|
32888
|
+
await fs4.promises.mkdir(paths.images, { recursive: true });
|
|
32881
32889
|
const imagePath = path3.join(paths.images, "1.png");
|
|
32882
|
-
await
|
|
32890
|
+
await fs4.promises.writeFile(imagePath, buffer);
|
|
32883
32891
|
console.log(`[EXULU] Image saved to: ${imagePath}`);
|
|
32884
32892
|
let json = [{
|
|
32885
32893
|
page: 1,
|
|
@@ -32897,7 +32905,7 @@ async function processImage(buffer, paths, config, verbose = false) {
|
|
|
32897
32905
|
verbose,
|
|
32898
32906
|
config.vlm.concurrency
|
|
32899
32907
|
);
|
|
32900
|
-
await
|
|
32908
|
+
await fs4.promises.writeFile(
|
|
32901
32909
|
paths.json,
|
|
32902
32910
|
JSON.stringify(json, null, 2),
|
|
32903
32911
|
"utf-8"
|
|
@@ -32908,14 +32916,14 @@ async function processImage(buffer, paths, config, verbose = false) {
|
|
|
32908
32916
|
} else {
|
|
32909
32917
|
console.log("[EXULU] No VLM configured, image saved without content extraction");
|
|
32910
32918
|
console.log("[EXULU] Note: Enable VLM in config to extract text/content from images");
|
|
32911
|
-
await
|
|
32919
|
+
await fs4.promises.writeFile(
|
|
32912
32920
|
paths.json,
|
|
32913
32921
|
JSON.stringify(json, null, 2),
|
|
32914
32922
|
"utf-8"
|
|
32915
32923
|
);
|
|
32916
32924
|
}
|
|
32917
32925
|
const markdown = json.map((p) => p.vlm_corrected_text ?? p.content).join("\n\n\n<!-- END_OF_PAGE -->\n\n\n");
|
|
32918
|
-
await
|
|
32926
|
+
await fs4.promises.writeFile(paths.markdown, markdown, "utf-8");
|
|
32919
32927
|
return {
|
|
32920
32928
|
markdown,
|
|
32921
32929
|
json
|
|
@@ -32968,7 +32976,7 @@ function reconstructHeadings(correctedText, headingsHierarchy) {
|
|
|
32968
32976
|
return result;
|
|
32969
32977
|
}
|
|
32970
32978
|
async function validatePageWithVLM(page, imagePath, model) {
|
|
32971
|
-
const imageBuffer = await
|
|
32979
|
+
const imageBuffer = await fs4.promises.readFile(imagePath);
|
|
32972
32980
|
const imageBase64 = imageBuffer.toString("base64");
|
|
32973
32981
|
const mimeType = "image/png";
|
|
32974
32982
|
const prompt = `You are a document validation assistant. Your task is to analyze a page image and correct the output of an OCR/parsing pipeline. The content may include tables, technical diagrams, schematics, and structured text.
|
|
@@ -33303,7 +33311,7 @@ ${setupResult.output || ""}`);
|
|
|
33303
33311
|
if (!result.success) {
|
|
33304
33312
|
throw new Error(`Document processing failed: ${result.stderr}`);
|
|
33305
33313
|
}
|
|
33306
|
-
const jsonContent = await
|
|
33314
|
+
const jsonContent = await fs4.promises.readFile(paths.json, "utf-8");
|
|
33307
33315
|
json = JSON.parse(jsonContent);
|
|
33308
33316
|
} else if (config?.processor.name === "officeparser") {
|
|
33309
33317
|
const text = await (0, import_officeparser3.parseOfficeAsync)(buffer, {
|
|
@@ -33336,7 +33344,7 @@ ${setupResult.output || ""}`);
|
|
|
33336
33344
|
await new Promise((resolve8) => setImmediate(resolve8));
|
|
33337
33345
|
await new Promise((resolve8) => setTimeout(resolve8, Math.floor(Math.random() * 1e3) + 200));
|
|
33338
33346
|
console.log(`[EXULU] OCR chunk ${i + 1}/${pdfChunks.length}: pages ${chunk.start_page}\u2013${chunk.end_page - 1}`);
|
|
33339
|
-
const chunkBuffer = await
|
|
33347
|
+
const chunkBuffer = await fs4.promises.readFile(chunk.path);
|
|
33340
33348
|
const chunkBase64 = chunkBuffer.toString("base64");
|
|
33341
33349
|
const chunkResponse = await withRetry(async () => {
|
|
33342
33350
|
return await resolved.ocr({
|
|
@@ -33353,9 +33361,9 @@ ${setupResult.output || ""}`);
|
|
|
33353
33361
|
);
|
|
33354
33362
|
const parser = new import_liteparse.LiteParse();
|
|
33355
33363
|
const screenshots = await parser.screenshot(paths.source, void 0);
|
|
33356
|
-
await
|
|
33364
|
+
await fs4.promises.mkdir(paths.images, { recursive: true });
|
|
33357
33365
|
for (const screenshot of screenshots) {
|
|
33358
|
-
await
|
|
33366
|
+
await fs4.promises.writeFile(
|
|
33359
33367
|
path3.join(
|
|
33360
33368
|
paths.images,
|
|
33361
33369
|
`${screenshot.pageNum}.png`
|
|
@@ -33370,15 +33378,15 @@ ${setupResult.output || ""}`);
|
|
|
33370
33378
|
image: screenshots.find((s) => s.pageNum === page.index + 1)?.imagePath,
|
|
33371
33379
|
headings: []
|
|
33372
33380
|
}));
|
|
33373
|
-
|
|
33381
|
+
fs4.writeFileSync(paths.json, JSON.stringify(json, null, 2));
|
|
33374
33382
|
} else if (config?.processor.name === "liteparse") {
|
|
33375
33383
|
const parser = new import_liteparse.LiteParse();
|
|
33376
33384
|
const result = await parser.parse(paths.source);
|
|
33377
33385
|
const screenshots = await parser.screenshot(paths.source, void 0);
|
|
33378
33386
|
console.log(`[EXULU] Liteparse screenshots: ${JSON.stringify(screenshots)}`);
|
|
33379
|
-
await
|
|
33387
|
+
await fs4.promises.mkdir(paths.images, { recursive: true });
|
|
33380
33388
|
for (const screenshot of screenshots) {
|
|
33381
|
-
await
|
|
33389
|
+
await fs4.promises.writeFile(path3.join(paths.images, `${screenshot.pageNum}.png`), screenshot.imageBuffer);
|
|
33382
33390
|
screenshot.imagePath = path3.join(paths.images, `${screenshot.pageNum}.png`);
|
|
33383
33391
|
}
|
|
33384
33392
|
json = result.pages.map((page) => ({
|
|
@@ -33386,7 +33394,7 @@ ${setupResult.output || ""}`);
|
|
|
33386
33394
|
content: page.text,
|
|
33387
33395
|
image: screenshots.find((s) => s.pageNum === page.pageNum)?.imagePath
|
|
33388
33396
|
}));
|
|
33389
|
-
|
|
33397
|
+
fs4.writeFileSync(paths.json, JSON.stringify(json, null, 2));
|
|
33390
33398
|
}
|
|
33391
33399
|
console.log(`[EXULU]
|
|
33392
33400
|
\u2713 Document processing completed successfully`);
|
|
@@ -33418,13 +33426,13 @@ ${setupResult.output || ""}`);
|
|
|
33418
33426
|
console.log(`[EXULU] Corrected: ${page.vlm_corrected_text.substring(0, 150)}...`);
|
|
33419
33427
|
});
|
|
33420
33428
|
}
|
|
33421
|
-
await
|
|
33429
|
+
await fs4.promises.writeFile(
|
|
33422
33430
|
paths.json,
|
|
33423
33431
|
JSON.stringify(json, null, 2),
|
|
33424
33432
|
"utf-8"
|
|
33425
33433
|
);
|
|
33426
33434
|
}
|
|
33427
|
-
const markdownStream =
|
|
33435
|
+
const markdownStream = fs4.createWriteStream(paths.markdown, { encoding: "utf-8" });
|
|
33428
33436
|
for (let i = 0; i < json.length; i++) {
|
|
33429
33437
|
const p = json[i];
|
|
33430
33438
|
if (!p) continue;
|
|
@@ -33440,7 +33448,7 @@ ${setupResult.output || ""}`);
|
|
|
33440
33448
|
});
|
|
33441
33449
|
console.log(`[EXULU] Validated output saved to: ${paths.json}`);
|
|
33442
33450
|
console.log(`[EXULU] Validated markdown saved to: ${paths.markdown}`);
|
|
33443
|
-
const markdown = await
|
|
33451
|
+
const markdown = await fs4.promises.readFile(paths.markdown, "utf-8");
|
|
33444
33452
|
const processedJson = json.map((e) => {
|
|
33445
33453
|
const finalContent = e.vlm_corrected_text ?? e.content;
|
|
33446
33454
|
return {
|
|
@@ -33471,7 +33479,7 @@ var loadFile = async (file, name, tempDir) => {
|
|
|
33471
33479
|
let buffer;
|
|
33472
33480
|
if (Buffer.isBuffer(file)) {
|
|
33473
33481
|
filePath = path3.join(tempDir, `${UUID}.${fileType}`);
|
|
33474
|
-
await
|
|
33482
|
+
await fs4.promises.writeFile(filePath, file);
|
|
33475
33483
|
buffer = file;
|
|
33476
33484
|
} else {
|
|
33477
33485
|
filePath = filePath.trim();
|
|
@@ -33479,11 +33487,11 @@ var loadFile = async (file, name, tempDir) => {
|
|
|
33479
33487
|
const response = await fetch(filePath);
|
|
33480
33488
|
const array = await response.arrayBuffer();
|
|
33481
33489
|
const tempFilePath = path3.join(tempDir, `${UUID}.${fileType}`);
|
|
33482
|
-
await
|
|
33490
|
+
await fs4.promises.writeFile(tempFilePath, Buffer.from(array));
|
|
33483
33491
|
buffer = Buffer.from(array);
|
|
33484
33492
|
filePath = tempFilePath;
|
|
33485
33493
|
} else {
|
|
33486
|
-
buffer = await
|
|
33494
|
+
buffer = await fs4.promises.readFile(file);
|
|
33487
33495
|
}
|
|
33488
33496
|
}
|
|
33489
33497
|
return { filePath, fileType, buffer };
|
|
@@ -33501,9 +33509,9 @@ async function documentProcessor({
|
|
|
33501
33509
|
const tempDir = path3.join(process.cwd(), "temp", uuid);
|
|
33502
33510
|
const localFilesAndFoldersToDelete = [tempDir];
|
|
33503
33511
|
console.log(`[EXULU] Temporary directory for processing document ${name}: ${tempDir}`);
|
|
33504
|
-
await
|
|
33512
|
+
await fs4.promises.mkdir(tempDir, { recursive: true });
|
|
33505
33513
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
33506
|
-
await
|
|
33514
|
+
await fs4.promises.writeFile(path3.join(tempDir, "created_at.txt"), timestamp);
|
|
33507
33515
|
try {
|
|
33508
33516
|
const {
|
|
33509
33517
|
filePath,
|
|
@@ -33544,7 +33552,7 @@ async function documentProcessor({
|
|
|
33544
33552
|
if (config?.debugging?.deleteTempFiles !== false) {
|
|
33545
33553
|
for (const file2 of localFilesAndFoldersToDelete) {
|
|
33546
33554
|
try {
|
|
33547
|
-
await
|
|
33555
|
+
await fs4.promises.rm(file2, { recursive: true });
|
|
33548
33556
|
console.log(`[EXULU] Deleted file or folder: ${file2}`);
|
|
33549
33557
|
} catch (error) {
|
|
33550
33558
|
console.error(`[EXULU] Error deleting file or folder: ${file2}`, error);
|