@exulu/backend 1.49.1 → 1.50.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.
@@ -0,0 +1,140 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * CLI script for setting up the Python environment for @exulu/backend
4
+ *
5
+ * This script can be run standalone using:
6
+ * npx @exulu/backend setup-python
7
+ */
8
+
9
+ const { exec } = require('child_process');
10
+ const { promisify } = require('util');
11
+ const { existsSync } = require('fs');
12
+ const { resolve, join } = require('path');
13
+
14
+ const execAsync = promisify(exec);
15
+
16
+ // ANSI color codes
17
+ const colors = {
18
+ reset: '\x1b[0m',
19
+ green: '\x1b[32m',
20
+ yellow: '\x1b[33m',
21
+ blue: '\x1b[34m',
22
+ red: '\x1b[31m',
23
+ };
24
+
25
+ /**
26
+ * Check if Python environment already exists
27
+ */
28
+ function pythonEnvironmentExists() {
29
+ const venvPath = resolve(__dirname, '..', 'ee/python/.venv');
30
+ const pythonPath = join(venvPath, 'bin', 'python');
31
+ return existsSync(venvPath) && existsSync(pythonPath);
32
+ }
33
+
34
+ /**
35
+ * Run the Python setup script
36
+ */
37
+ async function setupPythonEnvironment(force = false) {
38
+ const setupScriptPath = resolve(__dirname, '..', 'ee/python/setup.sh');
39
+
40
+ if (!existsSync(setupScriptPath)) {
41
+ console.error(`${colors.red}✗${colors.reset} Setup script not found: ${setupScriptPath}`);
42
+ console.error('');
43
+ console.error('Make sure the @exulu/backend package is properly installed.');
44
+ process.exit(1);
45
+ }
46
+
47
+ try {
48
+ console.log(`${colors.blue}Running Python environment setup...${colors.reset}`);
49
+ console.log('');
50
+
51
+ const command = force
52
+ ? `bash "${setupScriptPath}" --force`
53
+ : `bash "${setupScriptPath}"`;
54
+
55
+ const { stdout, stderr } = await execAsync(command, {
56
+ cwd: resolve(__dirname, '..'),
57
+ timeout: 600000, // 10 minutes
58
+ maxBuffer: 10 * 1024 * 1024,
59
+ });
60
+
61
+ // Show output
62
+ if (stdout) console.log(stdout);
63
+ if (stderr) console.error(stderr);
64
+
65
+ return true;
66
+ } catch (error) {
67
+ console.error(`${colors.red}✗${colors.reset} Python setup failed:`, error.message);
68
+ if (error.stdout) console.log(error.stdout);
69
+ if (error.stderr) console.error(error.stderr);
70
+
71
+ console.log('');
72
+ console.log('Requirements:');
73
+ console.log(' - Python 3.10 or higher must be installed');
74
+ console.log(' - pip must be available');
75
+ console.log(' - venv module must be available');
76
+ console.log('');
77
+ console.log('Installation instructions:');
78
+ console.log(' macOS: brew install python@3.12');
79
+ console.log(' Ubuntu/Debian: sudo apt-get install python3.12 python3-pip python3-venv');
80
+ console.log(' Alpine Linux: apk add python3 py3-pip python3-dev');
81
+ console.log(' Windows: Download from https://www.python.org/downloads/');
82
+ console.log('');
83
+
84
+ return false;
85
+ }
86
+ }
87
+
88
+ /**
89
+ * Main CLI function
90
+ */
91
+ async function main() {
92
+ const args = process.argv.slice(2);
93
+ const force = args.includes('--force') || args.includes('-f');
94
+
95
+ console.log('');
96
+ console.log(`${colors.blue}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${colors.reset}`);
97
+ console.log(`${colors.blue} @exulu/backend - Python Setup${colors.reset}`);
98
+ console.log(`${colors.blue}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${colors.reset}`);
99
+ console.log('');
100
+
101
+ // Check if already exists (and not forcing)
102
+ if (pythonEnvironmentExists() && !force) {
103
+ console.log(`${colors.green}✓${colors.reset} Python environment already set up`);
104
+ console.log('');
105
+ console.log('To rebuild the environment, run:');
106
+ console.log(` ${colors.green}npx @exulu/backend setup-python --force${colors.reset}`);
107
+ console.log('');
108
+ console.log(`${colors.blue}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${colors.reset}`);
109
+ console.log('');
110
+ return;
111
+ }
112
+
113
+ if (force && pythonEnvironmentExists()) {
114
+ console.log(`${colors.yellow}⚠${colors.reset} Rebuilding Python environment (--force flag detected)`);
115
+ console.log('');
116
+ }
117
+
118
+ // Run setup
119
+ const success = await setupPythonEnvironment(force);
120
+
121
+ if (success) {
122
+ console.log('');
123
+ console.log(`${colors.green}✓${colors.reset} Python environment ready!`);
124
+ console.log('');
125
+ } else {
126
+ console.log('');
127
+ console.log(`${colors.red}✗${colors.reset} Setup failed`);
128
+ console.log('');
129
+ process.exit(1);
130
+ }
131
+
132
+ console.log(`${colors.blue}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${colors.reset}`);
133
+ console.log('');
134
+ }
135
+
136
+ // Run CLI
137
+ main().catch((error) => {
138
+ console.error('Error:', error.message);
139
+ process.exit(1);
140
+ });
package/dist/index.cjs CHANGED
@@ -10139,6 +10139,7 @@ var ExuluProvider = class {
10139
10139
  {item_name: <item_name>, item_id: <item_id>, context: <context_id>, chunk_id: <chunk_id>, chunk_index: <chunk_index>}
10140
10140
 
10141
10141
  IMPORTANT formatting rules:
10142
+ - Do NOT reference just chunks like "Looking at chunk_index 5 and chunk_index 0 from the search result", always use the JSON format above.
10142
10143
  - Use the exact format shown above, all on ONE line
10143
10144
  - Do NOT use quotes around field names or values
10144
10145
  - Use the context ID from the tool result
@@ -15855,7 +15856,7 @@ async function setupPythonEnvironment(options = {}) {
15855
15856
  }
15856
15857
  function getPythonSetupInstructions() {
15857
15858
  return `
15858
- Python environment not set up. Please run one of the following:
15859
+ Python environment not set up. Please run one of the following commands:
15859
15860
 
15860
15861
  Option 1 (Automatic):
15861
15862
  import { setupPythonEnvironment } from '@exulu/backend';
@@ -15867,17 +15868,26 @@ Option 2 (Manual - for package consumers):
15867
15868
  Option 3 (Manual - for contributors):
15868
15869
  npm run python:setup
15869
15870
 
15871
+ These commands will automatically create a Python virtual environment (.venv)
15872
+ in the @exulu/backend package and install all required dependencies.
15873
+
15870
15874
  Requirements:
15871
15875
  - Python 3.10 or higher must be installed
15872
15876
  - pip must be available
15877
+ - venv module must be available (for creating virtual environments)
15873
15878
 
15874
- Installing Python:
15879
+ If Python dependencies are not installed, install them first, then run one of the commands above:
15875
15880
  - macOS: brew install python@3.12
15876
- - Ubuntu/Debian: sudo apt-get install python3.12
15881
+ - Ubuntu/Debian: sudo apt-get install python3.12 python3-pip python3-venv
15882
+ - Alpine Linux: apk add python3 py3-pip python3-dev
15877
15883
  - Windows: Download from https://www.python.org/downloads/
15884
+
15885
+ Note: In Docker containers, ensure you install all three components:
15886
+ Ubuntu/Debian: apt-get install -y python3 python3-pip python3-venv
15887
+ Alpine: apk add python3 py3-pip python3-dev
15878
15888
  `.trim();
15879
15889
  }
15880
- async function validatePythonEnvironment(packageRoot) {
15890
+ async function validatePythonEnvironment(packageRoot, checkPackages = true) {
15881
15891
  const root = packageRoot ?? getPackageRoot();
15882
15892
  const venvPath = getVenvPath(root);
15883
15893
  const pythonPath = (0, import_path.join)(venvPath, "bin", "python");
@@ -15895,21 +15905,50 @@ async function validatePythonEnvironment(packageRoot) {
15895
15905
  }
15896
15906
  try {
15897
15907
  await execAsync(`"${pythonPath}" --version`, { cwd: root });
15898
- return {
15899
- valid: true,
15900
- message: "Python environment is valid"
15901
- };
15902
15908
  } catch {
15903
15909
  return {
15904
15910
  valid: false,
15905
15911
  message: "Python executable is not working. Please run:\n await setupPythonEnvironment({ force: true })"
15906
15912
  };
15907
15913
  }
15914
+ if (checkPackages) {
15915
+ const criticalPackages = ["docling", "transformers"];
15916
+ const missingPackages = [];
15917
+ for (const pkg of criticalPackages) {
15918
+ try {
15919
+ await execAsync(`"${pythonPath}" -c "import ${pkg}"`, {
15920
+ cwd: root,
15921
+ timeout: 1e4
15922
+ // 10 second timeout per import check
15923
+ });
15924
+ } catch {
15925
+ missingPackages.push(pkg);
15926
+ }
15927
+ }
15928
+ if (missingPackages.length > 0) {
15929
+ return {
15930
+ valid: false,
15931
+ message: `Python environment exists but required packages are not installed: ${missingPackages.join(", ")}
15932
+
15933
+ This usually happens when:
15934
+ 1. The .venv folder was copied but dependencies were not installed
15935
+ 2. The package was installed via npm but setup script was not run
15936
+
15937
+ Please run:
15938
+ await setupPythonEnvironment({ force: true })
15939
+
15940
+ Or manually run the setup script:
15941
+ bash ` + getSetupScriptPath(root)
15942
+ };
15943
+ }
15944
+ }
15945
+ return {
15946
+ valid: true,
15947
+ message: "Python environment is valid"
15948
+ };
15908
15949
  }
15909
15950
 
15910
15951
  // ee/python/documents/processing/doc_processor.ts
15911
- var import_child_process3 = require("child_process");
15912
- var import_util4 = require("util");
15913
15952
  var fs2 = __toESM(require("fs"), 1);
15914
15953
  var path = __toESM(require("path"), 1);
15915
15954
  var import_ai7 = require("ai");
@@ -16022,8 +16061,8 @@ async function executePythonScript(config) {
16022
16061
  // Ensure Python doesn't write bytecode files
16023
16062
  PYTHONDONTWRITEBYTECODE: "1"
16024
16063
  },
16025
- maxBuffer: 10 * 1024 * 1024
16026
- // 10MB buffer for output
16064
+ maxBuffer: 50 * 1024 * 1024
16065
+ // 50MB buffer for output (increased from 10MB)
16027
16066
  });
16028
16067
  return {
16029
16068
  stdout: stdout.trim(),
@@ -16035,8 +16074,25 @@ async function executePythonScript(config) {
16035
16074
  const stdout = error.stdout?.toString() ?? "";
16036
16075
  const stderr = error.stderr?.toString() ?? "";
16037
16076
  const exitCode = error.code ?? 1;
16077
+ let errorMessage = `Python script execution failed: ${error.message}`;
16078
+ if (stderr) {
16079
+ errorMessage += `
16080
+
16081
+ Stderr:
16082
+ ${stderr}`;
16083
+ }
16084
+ if (stdout) {
16085
+ errorMessage += `
16086
+
16087
+ Stdout:
16088
+ ${stdout}`;
16089
+ }
16090
+ errorMessage += `
16091
+
16092
+ Command executed:
16093
+ ${command}`;
16038
16094
  throw new PythonExecutionError(
16039
- `Python script execution failed: ${error.message}`,
16095
+ errorMessage,
16040
16096
  stdout,
16041
16097
  stderr,
16042
16098
  exitCode
@@ -16294,6 +16350,25 @@ async function processPdf(buffer, paths, config, verbose = false) {
16294
16350
  try {
16295
16351
  let json;
16296
16352
  if (config?.docling) {
16353
+ console.log(`[EXULU] Validating Python environment...`);
16354
+ const validation = await validatePythonEnvironment(void 0, true);
16355
+ if (!validation.valid) {
16356
+ console.log(`[EXULU] Python environment not ready, setting up automatically...`);
16357
+ console.log(`[EXULU] Reason: ${validation.message}`);
16358
+ const setupResult = await setupPythonEnvironment({
16359
+ verbose: true,
16360
+ force: false
16361
+ // Only setup if not already done
16362
+ });
16363
+ if (!setupResult.success) {
16364
+ throw new Error(`Failed to setup Python environment: ${setupResult.message}
16365
+
16366
+ ${setupResult.output || ""}`);
16367
+ }
16368
+ console.log(`[EXULU] Python environment setup completed successfully`);
16369
+ } else {
16370
+ console.log(`[EXULU] Python environment is valid`);
16371
+ }
16297
16372
  console.log(`[EXULU] Processing document with document_to_markdown.py`);
16298
16373
  const result = await executePythonScript({
16299
16374
  scriptPath: "ee/python/documents/processing/document_to_markdown.py",
package/dist/index.d.cts CHANGED
@@ -1945,6 +1945,8 @@ interface PythonSetupResult {
1945
1945
  }
1946
1946
  /**
1947
1947
  * Check if Python environment is already set up
1948
+ * Note: This only checks if the venv exists, not if packages are installed.
1949
+ * Use validatePythonEnvironment() for a more thorough check.
1948
1950
  */
1949
1951
  declare function isPythonEnvironmentSetup(packageRoot?: string): boolean;
1950
1952
  /**
@@ -1979,9 +1981,10 @@ declare function getPythonSetupInstructions(): string;
1979
1981
  * Validate Python environment and provide helpful error messages
1980
1982
  *
1981
1983
  * @param packageRoot - Package root directory
1984
+ * @param checkPackages - Whether to verify critical packages are installed
1982
1985
  * @returns Object with validation status and message
1983
1986
  */
1984
- declare function validatePythonEnvironment(packageRoot?: string): Promise<{
1987
+ declare function validatePythonEnvironment(packageRoot?: string, checkPackages?: boolean): Promise<{
1985
1988
  valid: boolean;
1986
1989
  message: string;
1987
1990
  }>;
package/dist/index.d.ts CHANGED
@@ -1945,6 +1945,8 @@ interface PythonSetupResult {
1945
1945
  }
1946
1946
  /**
1947
1947
  * Check if Python environment is already set up
1948
+ * Note: This only checks if the venv exists, not if packages are installed.
1949
+ * Use validatePythonEnvironment() for a more thorough check.
1948
1950
  */
1949
1951
  declare function isPythonEnvironmentSetup(packageRoot?: string): boolean;
1950
1952
  /**
@@ -1979,9 +1981,10 @@ declare function getPythonSetupInstructions(): string;
1979
1981
  * Validate Python environment and provide helpful error messages
1980
1982
  *
1981
1983
  * @param packageRoot - Package root directory
1984
+ * @param checkPackages - Whether to verify critical packages are installed
1982
1985
  * @returns Object with validation status and message
1983
1986
  */
1984
- declare function validatePythonEnvironment(packageRoot?: string): Promise<{
1987
+ declare function validatePythonEnvironment(packageRoot?: string, checkPackages?: boolean): Promise<{
1985
1988
  valid: boolean;
1986
1989
  message: string;
1987
1990
  }>;
package/dist/index.js CHANGED
@@ -10105,6 +10105,7 @@ var ExuluProvider = class {
10105
10105
  {item_name: <item_name>, item_id: <item_id>, context: <context_id>, chunk_id: <chunk_id>, chunk_index: <chunk_index>}
10106
10106
 
10107
10107
  IMPORTANT formatting rules:
10108
+ - Do NOT reference just chunks like "Looking at chunk_index 5 and chunk_index 0 from the search result", always use the JSON format above.
10108
10109
  - Use the exact format shown above, all on ONE line
10109
10110
  - Do NOT use quotes around field names or values
10110
10111
  - Use the context ID from the tool result
@@ -15821,7 +15822,7 @@ async function setupPythonEnvironment(options = {}) {
15821
15822
  }
15822
15823
  function getPythonSetupInstructions() {
15823
15824
  return `
15824
- Python environment not set up. Please run one of the following:
15825
+ Python environment not set up. Please run one of the following commands:
15825
15826
 
15826
15827
  Option 1 (Automatic):
15827
15828
  import { setupPythonEnvironment } from '@exulu/backend';
@@ -15833,17 +15834,26 @@ Option 2 (Manual - for package consumers):
15833
15834
  Option 3 (Manual - for contributors):
15834
15835
  npm run python:setup
15835
15836
 
15837
+ These commands will automatically create a Python virtual environment (.venv)
15838
+ in the @exulu/backend package and install all required dependencies.
15839
+
15836
15840
  Requirements:
15837
15841
  - Python 3.10 or higher must be installed
15838
15842
  - pip must be available
15843
+ - venv module must be available (for creating virtual environments)
15839
15844
 
15840
- Installing Python:
15845
+ If Python dependencies are not installed, install them first, then run one of the commands above:
15841
15846
  - macOS: brew install python@3.12
15842
- - Ubuntu/Debian: sudo apt-get install python3.12
15847
+ - Ubuntu/Debian: sudo apt-get install python3.12 python3-pip python3-venv
15848
+ - Alpine Linux: apk add python3 py3-pip python3-dev
15843
15849
  - Windows: Download from https://www.python.org/downloads/
15850
+
15851
+ Note: In Docker containers, ensure you install all three components:
15852
+ Ubuntu/Debian: apt-get install -y python3 python3-pip python3-venv
15853
+ Alpine: apk add python3 py3-pip python3-dev
15844
15854
  `.trim();
15845
15855
  }
15846
- async function validatePythonEnvironment(packageRoot) {
15856
+ async function validatePythonEnvironment(packageRoot, checkPackages = true) {
15847
15857
  const root = packageRoot ?? getPackageRoot();
15848
15858
  const venvPath = getVenvPath(root);
15849
15859
  const pythonPath = join(venvPath, "bin", "python");
@@ -15861,21 +15871,50 @@ async function validatePythonEnvironment(packageRoot) {
15861
15871
  }
15862
15872
  try {
15863
15873
  await execAsync(`"${pythonPath}" --version`, { cwd: root });
15864
- return {
15865
- valid: true,
15866
- message: "Python environment is valid"
15867
- };
15868
15874
  } catch {
15869
15875
  return {
15870
15876
  valid: false,
15871
15877
  message: "Python executable is not working. Please run:\n await setupPythonEnvironment({ force: true })"
15872
15878
  };
15873
15879
  }
15880
+ if (checkPackages) {
15881
+ const criticalPackages = ["docling", "transformers"];
15882
+ const missingPackages = [];
15883
+ for (const pkg of criticalPackages) {
15884
+ try {
15885
+ await execAsync(`"${pythonPath}" -c "import ${pkg}"`, {
15886
+ cwd: root,
15887
+ timeout: 1e4
15888
+ // 10 second timeout per import check
15889
+ });
15890
+ } catch {
15891
+ missingPackages.push(pkg);
15892
+ }
15893
+ }
15894
+ if (missingPackages.length > 0) {
15895
+ return {
15896
+ valid: false,
15897
+ message: `Python environment exists but required packages are not installed: ${missingPackages.join(", ")}
15898
+
15899
+ This usually happens when:
15900
+ 1. The .venv folder was copied but dependencies were not installed
15901
+ 2. The package was installed via npm but setup script was not run
15902
+
15903
+ Please run:
15904
+ await setupPythonEnvironment({ force: true })
15905
+
15906
+ Or manually run the setup script:
15907
+ bash ` + getSetupScriptPath(root)
15908
+ };
15909
+ }
15910
+ }
15911
+ return {
15912
+ valid: true,
15913
+ message: "Python environment is valid"
15914
+ };
15874
15915
  }
15875
15916
 
15876
15917
  // ee/python/documents/processing/doc_processor.ts
15877
- import "child_process";
15878
- import "util";
15879
15918
  import * as fs2 from "fs";
15880
15919
  import * as path from "path";
15881
15920
  import { generateText as generateText3, Output as Output2 } from "ai";
@@ -15988,8 +16027,8 @@ async function executePythonScript(config) {
15988
16027
  // Ensure Python doesn't write bytecode files
15989
16028
  PYTHONDONTWRITEBYTECODE: "1"
15990
16029
  },
15991
- maxBuffer: 10 * 1024 * 1024
15992
- // 10MB buffer for output
16030
+ maxBuffer: 50 * 1024 * 1024
16031
+ // 50MB buffer for output (increased from 10MB)
15993
16032
  });
15994
16033
  return {
15995
16034
  stdout: stdout.trim(),
@@ -16001,8 +16040,25 @@ async function executePythonScript(config) {
16001
16040
  const stdout = error.stdout?.toString() ?? "";
16002
16041
  const stderr = error.stderr?.toString() ?? "";
16003
16042
  const exitCode = error.code ?? 1;
16043
+ let errorMessage = `Python script execution failed: ${error.message}`;
16044
+ if (stderr) {
16045
+ errorMessage += `
16046
+
16047
+ Stderr:
16048
+ ${stderr}`;
16049
+ }
16050
+ if (stdout) {
16051
+ errorMessage += `
16052
+
16053
+ Stdout:
16054
+ ${stdout}`;
16055
+ }
16056
+ errorMessage += `
16057
+
16058
+ Command executed:
16059
+ ${command}`;
16004
16060
  throw new PythonExecutionError(
16005
- `Python script execution failed: ${error.message}`,
16061
+ errorMessage,
16006
16062
  stdout,
16007
16063
  stderr,
16008
16064
  exitCode
@@ -16260,6 +16316,25 @@ async function processPdf(buffer, paths, config, verbose = false) {
16260
16316
  try {
16261
16317
  let json;
16262
16318
  if (config?.docling) {
16319
+ console.log(`[EXULU] Validating Python environment...`);
16320
+ const validation = await validatePythonEnvironment(void 0, true);
16321
+ if (!validation.valid) {
16322
+ console.log(`[EXULU] Python environment not ready, setting up automatically...`);
16323
+ console.log(`[EXULU] Reason: ${validation.message}`);
16324
+ const setupResult = await setupPythonEnvironment({
16325
+ verbose: true,
16326
+ force: false
16327
+ // Only setup if not already done
16328
+ });
16329
+ if (!setupResult.success) {
16330
+ throw new Error(`Failed to setup Python environment: ${setupResult.message}
16331
+
16332
+ ${setupResult.output || ""}`);
16333
+ }
16334
+ console.log(`[EXULU] Python environment setup completed successfully`);
16335
+ } else {
16336
+ console.log(`[EXULU] Python environment is valid`);
16337
+ }
16263
16338
  console.log(`[EXULU] Processing document with document_to_markdown.py`);
16264
16339
  const result = await executePythonScript({
16265
16340
  scriptPath: "ee/python/documents/processing/document_to_markdown.py",
@@ -1,5 +1,3 @@
1
- import { exec } from 'child_process';
2
- import { promisify } from 'util';
3
1
  import * as fs from 'fs';
4
2
  import * as path from 'path';
5
3
  import { generateText, Output } from 'ai';
@@ -14,6 +12,7 @@ import WordExtractor from 'word-extractor';
14
12
  import { parseOfficeAsync } from "officeparser";
15
13
  import { checkLicense } from '@EE/entitlements';
16
14
  import { executePythonScript } from '@SRC/utils/python-executor';
15
+ import { setupPythonEnvironment, validatePythonEnvironment } from '@SRC/utils/python-setup';
17
16
 
18
17
  type DocumentProcessorConfig = {
19
18
  vlm?: {
@@ -432,6 +431,29 @@ async function processPdf(
432
431
  // Call the PDF processor script
433
432
  if (config?.docling) {
434
433
 
434
+ // Validate Python environment and setup if needed
435
+ console.log(`[EXULU] Validating Python environment...`);
436
+ const validation = await validatePythonEnvironment(undefined, true);
437
+
438
+ if (!validation.valid) {
439
+ console.log(`[EXULU] Python environment not ready, setting up automatically...`);
440
+ console.log(`[EXULU] Reason: ${validation.message}`);
441
+
442
+ const setupResult = await setupPythonEnvironment({
443
+ verbose: true,
444
+ force: false, // Only setup if not already done
445
+ });
446
+
447
+
448
+ if (!setupResult.success) {
449
+ throw new Error(`Failed to setup Python environment: ${setupResult.message}\n\n${setupResult.output || ''}`);
450
+ }
451
+
452
+ console.log(`[EXULU] Python environment setup completed successfully`);
453
+ } else {
454
+ console.log(`[EXULU] Python environment is valid`);
455
+ }
456
+
435
457
  console.log(`[EXULU] Processing document with document_to_markdown.py`);
436
458
 
437
459
  const result = await executePythonScript({
@@ -94,21 +94,59 @@ print_success "Found Python $PYTHON_VERSION at $(which $PYTHON_CMD)"
94
94
  echo ""
95
95
  echo "Step 2: Checking pip installation..."
96
96
  if ! $PYTHON_CMD -m pip --version &> /dev/null; then
97
- print_error "pip is not installed"
98
- echo ""
99
- echo "Please install pip:"
100
- echo " curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py"
101
- echo " $PYTHON_CMD get-pip.py"
102
- echo ""
103
- exit 1
97
+ print_warning "pip is not installed, attempting to bootstrap..."
98
+
99
+ # Try to use ensurepip to bootstrap pip
100
+ if $PYTHON_CMD -m ensurepip --version &> /dev/null; then
101
+ print_info "Using ensurepip to install pip..."
102
+ $PYTHON_CMD -m ensurepip --default-pip || {
103
+ print_error "Failed to bootstrap pip using ensurepip"
104
+ echo ""
105
+ echo "Please install pip manually:"
106
+ echo " Ubuntu/Debian: sudo apt-get install python3-pip"
107
+ echo " Alpine: apk add py3-pip"
108
+ echo " Or using get-pip.py:"
109
+ echo " curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py"
110
+ echo " $PYTHON_CMD get-pip.py"
111
+ echo ""
112
+ exit 1
113
+ }
114
+ print_success "pip bootstrapped successfully using ensurepip"
115
+ else
116
+ print_error "pip is not installed and ensurepip is not available"
117
+ echo ""
118
+ echo "Please install pip manually:"
119
+ echo " Ubuntu/Debian: sudo apt-get install python3-pip"
120
+ echo " Alpine: apk add py3-pip"
121
+ echo " Or using get-pip.py:"
122
+ echo " curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py"
123
+ echo " $PYTHON_CMD get-pip.py"
124
+ echo ""
125
+ exit 1
126
+ fi
104
127
  fi
105
128
 
106
129
  PIP_VERSION=$($PYTHON_CMD -m pip --version | awk '{print $2}')
107
130
  print_success "Found pip $PIP_VERSION"
108
131
 
109
- # Step 3: Create or update virtual environment
132
+ # Step 3: Check for venv module
133
+ echo ""
134
+ echo "Step 3: Checking venv module..."
135
+ if ! $PYTHON_CMD -m venv --help &> /dev/null; then
136
+ print_error "venv module is not available"
137
+ echo ""
138
+ echo "The venv module is required to create virtual environments."
139
+ echo "Please install it:"
140
+ echo " Ubuntu/Debian: sudo apt-get install python3-venv"
141
+ echo " Alpine: apk add python3-dev"
142
+ echo ""
143
+ exit 1
144
+ fi
145
+ print_success "venv module is available"
146
+
147
+ # Step 4: Create or update virtual environment
110
148
  echo ""
111
- echo "Step 3: Setting up virtual environment..."
149
+ echo "Step 4: Setting up virtual environment..."
112
150
  if [ -d "$VENV_DIR" ]; then
113
151
  # Check if virtual environment is valid
114
152
  if [ -f "$VENV_DIR/bin/activate" ] && [ -f "$VENV_DIR/bin/python" ]; then
@@ -117,18 +155,32 @@ if [ -d "$VENV_DIR" ]; then
117
155
  else
118
156
  print_warning "Virtual environment is corrupted, recreating..."
119
157
  rm -rf "$VENV_DIR"
120
- $PYTHON_CMD -m venv "$VENV_DIR"
158
+ $PYTHON_CMD -m venv "$VENV_DIR" || {
159
+ print_error "Failed to create virtual environment"
160
+ echo ""
161
+ echo "This usually means the venv module is not properly installed."
162
+ echo "Try installing: sudo apt-get install python3-venv python3-dev"
163
+ echo ""
164
+ exit 1
165
+ }
121
166
  print_success "Virtual environment created"
122
167
  fi
123
168
  else
124
169
  print_info "Creating virtual environment at $VENV_DIR"
125
- $PYTHON_CMD -m venv "$VENV_DIR"
170
+ $PYTHON_CMD -m venv "$VENV_DIR" || {
171
+ print_error "Failed to create virtual environment"
172
+ echo ""
173
+ echo "This usually means the venv module is not properly installed."
174
+ echo "Try installing: sudo apt-get install python3-venv python3-dev"
175
+ echo ""
176
+ exit 1
177
+ }
126
178
  print_success "Virtual environment created"
127
179
  fi
128
180
 
129
- # Step 4: Activate virtual environment and upgrade pip
181
+ # Step 5: Activate virtual environment and upgrade pip
130
182
  echo ""
131
- echo "Step 4: Activating virtual environment..."
183
+ echo "Step 5: Activating virtual environment..."
132
184
  source "$VENV_DIR/bin/activate"
133
185
  print_success "Virtual environment activated"
134
186
 
@@ -137,9 +189,9 @@ print_info "Upgrading pip in virtual environment..."
137
189
  pip install --upgrade pip > /dev/null 2>&1
138
190
  print_success "pip upgraded to latest version"
139
191
 
140
- # Step 5: Install dependencies
192
+ # Step 6: Install dependencies
141
193
  echo ""
142
- echo "Step 5: Installing Python dependencies..."
194
+ echo "Step 6: Installing Python dependencies..."
143
195
  if [ ! -f "$REQUIREMENTS_FILE" ]; then
144
196
  print_error "Requirements file not found: $REQUIREMENTS_FILE"
145
197
  exit 1
@@ -151,16 +203,16 @@ pip install -r "$REQUIREMENTS_FILE"
151
203
 
152
204
  print_success "All dependencies installed successfully"
153
205
 
154
- # Step 6: Validate installation
206
+ # Step 7: Validate installation
155
207
  echo ""
156
- echo "Step 6: Validating installation..."
208
+ echo "Step 7: Validating installation..."
157
209
 
158
210
  # Test critical imports
159
211
  print_info "Testing critical imports..."
160
212
  $PYTHON_CMD -c "import docling" 2>/dev/null && print_success "docling imported successfully" || print_error "Failed to import docling"
161
213
  $PYTHON_CMD -c "import transformers" 2>/dev/null && print_success "transformers imported successfully" || print_error "Failed to import transformers"
162
214
 
163
- # Step 7: Display summary
215
+ # Step 8: Display summary
164
216
  echo ""
165
217
  echo -e "${GREEN}========================================${NC}"
166
218
  echo -e "${GREEN} Setup Complete!${NC}"
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@exulu/backend",
3
3
  "author": "Qventu Bv.",
4
- "version": "1.49.1",
4
+ "version": "1.50.0",
5
5
  "main": "./dist/index.js",
6
6
  "private": false,
7
7
  "publishConfig": {
@@ -9,6 +9,9 @@
9
9
  },
10
10
  "module": "./dist/index.mjs",
11
11
  "types": "./dist/index.d.ts",
12
+ "bin": {
13
+ "setup-python": "./bin/setup-python.cjs"
14
+ },
12
15
  "homepage": "https://exulu.com",
13
16
  "engines": {
14
17
  "node": "22.18.0"
@@ -151,6 +154,7 @@
151
154
  "files": [
152
155
  "dist",
153
156
  "ee",
157
+ "bin",
154
158
  "scripts/postinstall.cjs"
155
159
  ]
156
160
  }