@heripo/pdf-parser 0.1.24 → 0.1.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +121 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.js +121 -12
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.cjs
CHANGED
|
@@ -736,14 +736,32 @@ function validatePythonVersion(version, context = "system") {
|
|
|
736
736
|
}
|
|
737
737
|
|
|
738
738
|
// src/environment/python-environment.ts
|
|
739
|
+
var DOCLING_SERVE_PACKAGE = "docling-serve==1.16.1";
|
|
739
740
|
var DOCLING_RUNTIME_PACKAGES = [
|
|
740
|
-
"docling-
|
|
741
|
-
"docling
|
|
742
|
-
"docling==2.
|
|
743
|
-
"docling-core==2.74.0",
|
|
741
|
+
"docling-jobkit==1.16.0",
|
|
742
|
+
"docling==2.88.0",
|
|
743
|
+
"docling-core==2.73.0",
|
|
744
744
|
"docling-ibm-models==3.13.0",
|
|
745
745
|
"docling-parse==5.9.0"
|
|
746
746
|
];
|
|
747
|
+
var DOCLING_SERVE_RUNTIME_PACKAGES = [
|
|
748
|
+
"fastapi[standard]<0.130.0",
|
|
749
|
+
"httpx~=0.28",
|
|
750
|
+
"pydantic~=2.10",
|
|
751
|
+
"pydantic-settings~=2.4",
|
|
752
|
+
"python-multipart<0.1.0,>=0.0.14",
|
|
753
|
+
"typer~=0.12",
|
|
754
|
+
"uvicorn[standard]<1.0.0,>=0.29.0",
|
|
755
|
+
"websockets<17.0,>=14.0",
|
|
756
|
+
"scalar-fastapi>=1.0.3",
|
|
757
|
+
"docling-mcp>=1.0.0",
|
|
758
|
+
"opentelemetry-api==1.36.0",
|
|
759
|
+
"opentelemetry-sdk==1.36.0",
|
|
760
|
+
"opentelemetry-exporter-otlp==1.36.0",
|
|
761
|
+
"opentelemetry-instrumentation-fastapi==0.57b0",
|
|
762
|
+
"opentelemetry-exporter-prometheus==0.57b0",
|
|
763
|
+
"prometheus-client>=0.21.0"
|
|
764
|
+
];
|
|
747
765
|
var PythonEnvironment = class {
|
|
748
766
|
constructor(logger, venvPath) {
|
|
749
767
|
this.logger = logger;
|
|
@@ -755,6 +773,8 @@ var PythonEnvironment = class {
|
|
|
755
773
|
await this.upgradePip();
|
|
756
774
|
await this.installSetuptools();
|
|
757
775
|
await this.installPyArrow();
|
|
776
|
+
await this.installDoclingRuntimePackages();
|
|
777
|
+
await this.installDoclingServeRuntimePackages();
|
|
758
778
|
await this.installDoclingServe();
|
|
759
779
|
}
|
|
760
780
|
async checkPythonVersion() {
|
|
@@ -848,13 +868,31 @@ var PythonEnvironment = class {
|
|
|
848
868
|
throw new Error(`Failed to install pyarrow. Exit code: ${result.code}`);
|
|
849
869
|
}
|
|
850
870
|
}
|
|
851
|
-
async
|
|
871
|
+
async installDoclingRuntimePackages() {
|
|
852
872
|
const pipPath = (0, import_node_path2.join)(this.venvPath, "bin", "pip");
|
|
853
873
|
const result = await spawnAsync(pipPath, [
|
|
854
874
|
"install",
|
|
855
875
|
"--upgrade",
|
|
856
876
|
...DOCLING_RUNTIME_PACKAGES
|
|
857
877
|
]);
|
|
878
|
+
if (result.code !== 0) {
|
|
879
|
+
this.logger.error(
|
|
880
|
+
"[DoclingEnvironment] Failed to install docling runtime packages:",
|
|
881
|
+
result.stderr
|
|
882
|
+
);
|
|
883
|
+
throw new Error(
|
|
884
|
+
`Failed to install docling runtime packages. Exit code: ${result.code}`
|
|
885
|
+
);
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
async installDoclingServe() {
|
|
889
|
+
const pipPath = (0, import_node_path2.join)(this.venvPath, "bin", "pip");
|
|
890
|
+
const result = await spawnAsync(pipPath, [
|
|
891
|
+
"install",
|
|
892
|
+
"--upgrade",
|
|
893
|
+
"--no-deps",
|
|
894
|
+
DOCLING_SERVE_PACKAGE
|
|
895
|
+
]);
|
|
858
896
|
if (result.code !== 0) {
|
|
859
897
|
this.logger.error(
|
|
860
898
|
"[DoclingEnvironment] Failed to install docling-serve:",
|
|
@@ -865,6 +903,23 @@ var PythonEnvironment = class {
|
|
|
865
903
|
);
|
|
866
904
|
}
|
|
867
905
|
}
|
|
906
|
+
async installDoclingServeRuntimePackages() {
|
|
907
|
+
const pipPath = (0, import_node_path2.join)(this.venvPath, "bin", "pip");
|
|
908
|
+
const result = await spawnAsync(pipPath, [
|
|
909
|
+
"install",
|
|
910
|
+
"--upgrade",
|
|
911
|
+
...DOCLING_SERVE_RUNTIME_PACKAGES
|
|
912
|
+
]);
|
|
913
|
+
if (result.code !== 0) {
|
|
914
|
+
this.logger.error(
|
|
915
|
+
"[DoclingEnvironment] Failed to install docling-serve runtime packages:",
|
|
916
|
+
result.stderr
|
|
917
|
+
);
|
|
918
|
+
throw new Error(
|
|
919
|
+
`Failed to install docling-serve runtime packages. Exit code: ${result.code}`
|
|
920
|
+
);
|
|
921
|
+
}
|
|
922
|
+
}
|
|
868
923
|
};
|
|
869
924
|
|
|
870
925
|
// src/environment/docling-environment.ts
|
|
@@ -1078,7 +1133,7 @@ var import_zod = require("zod");
|
|
|
1078
1133
|
var InvalidDocumentTypeError = class extends Error {
|
|
1079
1134
|
constructor(reason) {
|
|
1080
1135
|
super(
|
|
1081
|
-
`The uploaded PDF does not appear to be
|
|
1136
|
+
`The uploaded PDF does not appear to be an archaeological investigation report. Reason: ${reason}`
|
|
1082
1137
|
);
|
|
1083
1138
|
this.reason = reason;
|
|
1084
1139
|
}
|
|
@@ -3567,7 +3622,7 @@ var PDFConverter = class {
|
|
|
3567
3622
|
}
|
|
3568
3623
|
documentTypeValidated = false;
|
|
3569
3624
|
/**
|
|
3570
|
-
* Validate that the PDF is
|
|
3625
|
+
* Validate that the PDF is an archaeological investigation report.
|
|
3571
3626
|
* Skipped when no documentValidationModel is configured or for non-local URLs.
|
|
3572
3627
|
* Only runs once per converter instance (flag prevents duplicate checks on recursive calls).
|
|
3573
3628
|
*/
|
|
@@ -3856,6 +3911,7 @@ var PDFParser = class {
|
|
|
3856
3911
|
enableImagePdfFallback;
|
|
3857
3912
|
client = null;
|
|
3858
3913
|
environment;
|
|
3914
|
+
recoveryPromise = null;
|
|
3859
3915
|
constructor(options) {
|
|
3860
3916
|
const {
|
|
3861
3917
|
logger,
|
|
@@ -3940,15 +3996,30 @@ var PDFParser = class {
|
|
|
3940
3996
|
*/
|
|
3941
3997
|
isConnectionRefusedError(error) {
|
|
3942
3998
|
if (error instanceof Error) {
|
|
3999
|
+
const errorWithMetadata = error;
|
|
3943
4000
|
if (error.message.includes("ECONNREFUSED")) {
|
|
3944
4001
|
return true;
|
|
3945
4002
|
}
|
|
3946
|
-
if (
|
|
4003
|
+
if (errorWithMetadata.code === "ECONNREFUSED") {
|
|
3947
4004
|
return true;
|
|
3948
4005
|
}
|
|
4006
|
+
return this.isConnectionRefusedError(errorWithMetadata.cause);
|
|
4007
|
+
}
|
|
4008
|
+
if (typeof error === "object" && error !== null) {
|
|
4009
|
+
const errorLike = error;
|
|
4010
|
+
if (errorLike.code === "ECONNREFUSED") {
|
|
4011
|
+
return true;
|
|
4012
|
+
}
|
|
4013
|
+
if (typeof errorLike.message === "string" && errorLike.message.includes("ECONNREFUSED")) {
|
|
4014
|
+
return true;
|
|
4015
|
+
}
|
|
4016
|
+
return this.isConnectionRefusedError(errorLike.cause);
|
|
3949
4017
|
}
|
|
3950
4018
|
return false;
|
|
3951
4019
|
}
|
|
4020
|
+
canRecoverLocalServer() {
|
|
4021
|
+
return !this.baseUrl && this.port !== void 0;
|
|
4022
|
+
}
|
|
3952
4023
|
/**
|
|
3953
4024
|
* Restart the Docling server after it has crashed.
|
|
3954
4025
|
* This kills any existing process on the port, starts a new server,
|
|
@@ -3978,6 +4049,46 @@ var PDFParser = class {
|
|
|
3978
4049
|
await this.waitForServerReady();
|
|
3979
4050
|
this.logger.info("[PDFParser] Server restarted successfully");
|
|
3980
4051
|
}
|
|
4052
|
+
async recoverServer(message) {
|
|
4053
|
+
this.logger.warn(message);
|
|
4054
|
+
if (!this.recoveryPromise) {
|
|
4055
|
+
this.recoveryPromise = this.restartServer().finally(() => {
|
|
4056
|
+
this.recoveryPromise = null;
|
|
4057
|
+
});
|
|
4058
|
+
} else {
|
|
4059
|
+
this.logger.warn("[PDFParser] Server recovery already in progress...");
|
|
4060
|
+
}
|
|
4061
|
+
await this.recoveryPromise;
|
|
4062
|
+
}
|
|
4063
|
+
async isReady() {
|
|
4064
|
+
if (!this.client) {
|
|
4065
|
+
return false;
|
|
4066
|
+
}
|
|
4067
|
+
try {
|
|
4068
|
+
await this.client.health();
|
|
4069
|
+
return true;
|
|
4070
|
+
} catch {
|
|
4071
|
+
return false;
|
|
4072
|
+
}
|
|
4073
|
+
}
|
|
4074
|
+
async ensureReady() {
|
|
4075
|
+
if (!this.client) {
|
|
4076
|
+
throw new Error(
|
|
4077
|
+
"PDFParser is not initialized. Call init() before checking readiness"
|
|
4078
|
+
);
|
|
4079
|
+
}
|
|
4080
|
+
try {
|
|
4081
|
+
await this.client.health();
|
|
4082
|
+
} catch (error) {
|
|
4083
|
+
if (this.canRecoverLocalServer()) {
|
|
4084
|
+
await this.recoverServer(
|
|
4085
|
+
"[PDFParser] Health check failed, attempting server recovery..."
|
|
4086
|
+
);
|
|
4087
|
+
return;
|
|
4088
|
+
}
|
|
4089
|
+
throw error;
|
|
4090
|
+
}
|
|
4091
|
+
}
|
|
3981
4092
|
async waitForServerReady() {
|
|
3982
4093
|
const maxAttempts = PDF_PARSER.MAX_HEALTH_CHECK_ATTEMPTS;
|
|
3983
4094
|
const checkInterval = PDF_PARSER.HEALTH_CHECK_INTERVAL_MS;
|
|
@@ -4061,18 +4172,16 @@ var PDFParser = class {
|
|
|
4061
4172
|
* Recovery is only attempted in local server mode (no baseUrl, port defined).
|
|
4062
4173
|
*/
|
|
4063
4174
|
async executeWithRecovery(fn, abortSignal) {
|
|
4064
|
-
const canRecover = !this.baseUrl && this.port !== void 0;
|
|
4065
4175
|
const maxAttempts = PDF_PARSER.MAX_SERVER_RECOVERY_ATTEMPTS;
|
|
4066
4176
|
const tryExecute = async (attempt) => {
|
|
4067
4177
|
try {
|
|
4068
4178
|
return await fn();
|
|
4069
4179
|
} catch (error) {
|
|
4070
4180
|
if (abortSignal?.aborted) throw error;
|
|
4071
|
-
if (
|
|
4072
|
-
this.
|
|
4181
|
+
if (this.canRecoverLocalServer() && this.isConnectionRefusedError(error) && attempt < maxAttempts) {
|
|
4182
|
+
await this.recoverServer(
|
|
4073
4183
|
"[PDFParser] Connection refused, attempting server recovery..."
|
|
4074
4184
|
);
|
|
4075
|
-
await this.restartServer();
|
|
4076
4185
|
return tryExecute(attempt + 1);
|
|
4077
4186
|
}
|
|
4078
4187
|
throw error;
|