BabelDOC 0.1.14__tar.gz → 0.1.16__tar.gz
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.
- {babeldoc-0.1.14 → babeldoc-0.1.16}/PKG-INFO +2 -1
- babeldoc-0.1.16/babeldoc/__init__.py +1 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/babeldoc/const.py +1 -1
- {babeldoc-0.1.14 → babeldoc-0.1.16}/babeldoc/document_il/backend/pdf_creater.py +191 -2
- {babeldoc-0.1.14 → babeldoc-0.1.16}/babeldoc/docvision/rpc_doclayout.py +56 -45
- {babeldoc-0.1.14 → babeldoc-0.1.16}/babeldoc/main.py +1 -1
- {babeldoc-0.1.14 → babeldoc-0.1.16}/pyproject.toml +4 -3
- {babeldoc-0.1.14 → babeldoc-0.1.16}/uv.lock +12 -1
- babeldoc-0.1.14/babeldoc/__init__.py +0 -1
- {babeldoc-0.1.14 → babeldoc-0.1.16}/.cursorignore +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/.github/ISSUE_TEMPLATE/bug_report.yaml +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/.github/ISSUE_TEMPLATE/feature_request.yaml +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/.github/dependabot.yml +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/.github/labels.yml +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/.github/release-drafter.yml +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/.github/workflows/codeql.yml +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/.github/workflows/docs.yml +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/.github/workflows/labeler.yml +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/.github/workflows/publish-to-pypi.yml +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/.github/workflows/test.yml +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/.gitignore +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/.pre-commit-config.yaml +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/LICENSE +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/README.md +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/babeldoc/asynchronize/__init__.py +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/babeldoc/converter.py +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/babeldoc/document_il/__init__.py +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/babeldoc/document_il/backend/__init__.py +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/babeldoc/document_il/frontend/__init__.py +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/babeldoc/document_il/frontend/il_creater.py +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/babeldoc/document_il/il_version_1.py +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/babeldoc/document_il/il_version_1.rnc +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/babeldoc/document_il/il_version_1.rng +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/babeldoc/document_il/il_version_1.xsd +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/babeldoc/document_il/midend/__init__.py +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/babeldoc/document_il/midend/add_debug_information.py +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/babeldoc/document_il/midend/il_translator.py +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/babeldoc/document_il/midend/layout_parser.py +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/babeldoc/document_il/midend/paragraph_finder.py +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/babeldoc/document_il/midend/remove_descent.py +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/babeldoc/document_il/midend/styles_and_formulas.py +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/babeldoc/document_il/midend/typesetting.py +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/babeldoc/document_il/translator/__init__.py +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/babeldoc/document_il/translator/cache.py +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/babeldoc/document_il/translator/translator.py +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/babeldoc/document_il/utils/fontmap.py +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/babeldoc/document_il/utils/layout_helper.py +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/babeldoc/document_il/utils/style_helper.py +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/babeldoc/document_il/xml_converter.py +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/babeldoc/docvision/README.md +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/babeldoc/docvision/__init__.py +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/babeldoc/docvision/doclayout.py +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/babeldoc/high_level.py +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/babeldoc/pdfinterp.py +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/babeldoc/progress_monitor.py +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/babeldoc/translation_config.py +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/docs/CODE_OF_CONDUCT.md +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/docs/CONTRIBUTING.md +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/docs/CONTRIBUTOR_REWARD.md +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/docs/ImplementationDetails/AsyncTranslate/AsyncTranslate.md +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/docs/ImplementationDetails/ILTranslator/ILTranslator.md +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/docs/ImplementationDetails/PDFCreation/PDFCreation.md +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/docs/ImplementationDetails/PDFParsing/PDFParsing.md +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/docs/ImplementationDetails/ParagraphFinding/ParagraphFinding.md +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/docs/ImplementationDetails/README.md +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/docs/ImplementationDetails/StylesAndFormulas/StylesAndFormulas.md +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/docs/ImplementationDetails/Typesetting/Typesetting.md +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/docs/README.md +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/docs/deploy.sh +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/docs/images/babeldoc-banner.png +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/docs/images/babeldoc-contributor_reward_example.png +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/docs/images/babeldoc-preview.gif +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/docs/index.md +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/docs/intro-to-pdf-object.md +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/docs/requirements.txt +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/mkdocs.yml +0 -0
- {babeldoc-0.1.14 → babeldoc-0.1.16}/tests/test_translation_config.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: BabelDOC
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.16
|
|
4
4
|
Summary: Yet Another Document Translator
|
|
5
5
|
Project-URL: Homepage, https://github.com/funstory-ai/BabelDOC
|
|
6
6
|
Project-URL: Issues, https://github.com/funstory-ai/BabelDOC/issues
|
|
@@ -26,6 +26,7 @@ Requires-Dist: peewee>=3.17.8
|
|
|
26
26
|
Requires-Dist: pydantic>=2.10.6
|
|
27
27
|
Requires-Dist: pymupdf>=1.25.1
|
|
28
28
|
Requires-Dist: rich>=13.9.4
|
|
29
|
+
Requires-Dist: tenacity>=9.0.0
|
|
29
30
|
Requires-Dist: toml>=0.10.2
|
|
30
31
|
Requires-Dist: tqdm>=4.67.1
|
|
31
32
|
Requires-Dist: xsdata[cli,lxml,soap]>=24.12
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.1.16"
|
|
@@ -38,6 +38,44 @@ def _subset_fonts_process(pdf_path, output_path):
|
|
|
38
38
|
os._exit(1)
|
|
39
39
|
|
|
40
40
|
|
|
41
|
+
def _save_pdf_clean_process(
|
|
42
|
+
pdf_path,
|
|
43
|
+
output_path,
|
|
44
|
+
garbage=1,
|
|
45
|
+
deflate=True,
|
|
46
|
+
clean=True,
|
|
47
|
+
deflate_fonts=True,
|
|
48
|
+
linear=False,
|
|
49
|
+
):
|
|
50
|
+
"""Function to run in subprocess for saving PDF with clean=True which can be time-consuming.
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
pdf_path: Path to the PDF file to save
|
|
54
|
+
output_path: Path where to save the result
|
|
55
|
+
garbage: Garbage collection level (0, 1, 2, 3, 4)
|
|
56
|
+
deflate: Whether to deflate the PDF
|
|
57
|
+
clean: Whether to clean the PDF
|
|
58
|
+
deflate_fonts: Whether to deflate fonts
|
|
59
|
+
linear: Whether to linearize the PDF
|
|
60
|
+
"""
|
|
61
|
+
try:
|
|
62
|
+
pdf = pymupdf.open(pdf_path)
|
|
63
|
+
pdf.save(
|
|
64
|
+
output_path,
|
|
65
|
+
garbage=garbage,
|
|
66
|
+
deflate=deflate,
|
|
67
|
+
clean=clean,
|
|
68
|
+
deflate_fonts=deflate_fonts,
|
|
69
|
+
linear=linear,
|
|
70
|
+
)
|
|
71
|
+
# 返回0表示成功
|
|
72
|
+
os._exit(0)
|
|
73
|
+
except Exception as e:
|
|
74
|
+
logger.error(f"Error in save PDF with clean=True subprocess: {e}")
|
|
75
|
+
# 返回1表示失败
|
|
76
|
+
os._exit(1)
|
|
77
|
+
|
|
78
|
+
|
|
41
79
|
class PDFCreater:
|
|
42
80
|
stage_name = "Generate drawing instructions"
|
|
43
81
|
|
|
@@ -425,6 +463,11 @@ class PDFCreater:
|
|
|
425
463
|
if process.is_alive():
|
|
426
464
|
logger.warning("Subprocess did not terminate, killing it")
|
|
427
465
|
process.kill()
|
|
466
|
+
process.terminate()
|
|
467
|
+
process.kill()
|
|
468
|
+
process.terminate()
|
|
469
|
+
process.kill()
|
|
470
|
+
process.terminate()
|
|
428
471
|
except Exception as e:
|
|
429
472
|
logger.error(f"Error terminating font subsetting process: {e}")
|
|
430
473
|
|
|
@@ -450,6 +493,148 @@ class PDFCreater:
|
|
|
450
493
|
)
|
|
451
494
|
return original_pdf
|
|
452
495
|
|
|
496
|
+
def save_pdf_with_timeout(
|
|
497
|
+
self,
|
|
498
|
+
pdf: pymupdf.Document,
|
|
499
|
+
output_path: str,
|
|
500
|
+
translation_config: TranslationConfig,
|
|
501
|
+
garbage: int = 1,
|
|
502
|
+
deflate: bool = True,
|
|
503
|
+
clean: bool = True,
|
|
504
|
+
deflate_fonts: bool = True,
|
|
505
|
+
linear: bool = False,
|
|
506
|
+
timeout: int = 120,
|
|
507
|
+
) -> bool:
|
|
508
|
+
"""Save a PDF document with a timeout for the clean=True operation.
|
|
509
|
+
|
|
510
|
+
Args:
|
|
511
|
+
pdf: The PDF document object
|
|
512
|
+
output_path: Path where to save the PDF
|
|
513
|
+
translation_config: Translation configuration
|
|
514
|
+
garbage: Garbage collection level (0, 1, 2, 3, 4)
|
|
515
|
+
deflate: Whether to deflate the PDF
|
|
516
|
+
clean: Whether to clean the PDF
|
|
517
|
+
deflate_fonts: Whether to deflate fonts
|
|
518
|
+
linear: Whether to linearize the PDF
|
|
519
|
+
timeout: Timeout in seconds (default: 2 minutes)
|
|
520
|
+
|
|
521
|
+
Returns:
|
|
522
|
+
True if saved with clean=True successfully, False if fallback to clean=False was used
|
|
523
|
+
"""
|
|
524
|
+
# Create temporary file paths
|
|
525
|
+
temp_input = str(
|
|
526
|
+
translation_config.get_working_file_path(
|
|
527
|
+
f"temp_save_input_{int(time.time())}.pdf"
|
|
528
|
+
)
|
|
529
|
+
)
|
|
530
|
+
temp_output = str(
|
|
531
|
+
translation_config.get_working_file_path(
|
|
532
|
+
f"temp_save_output_{int(time.time())}.pdf"
|
|
533
|
+
)
|
|
534
|
+
)
|
|
535
|
+
|
|
536
|
+
# Save PDF to temporary file first
|
|
537
|
+
pdf.save(temp_input)
|
|
538
|
+
|
|
539
|
+
# Try to save with clean=True in a subprocess
|
|
540
|
+
process = Process(
|
|
541
|
+
target=_save_pdf_clean_process,
|
|
542
|
+
args=(
|
|
543
|
+
temp_input,
|
|
544
|
+
temp_output,
|
|
545
|
+
garbage,
|
|
546
|
+
deflate,
|
|
547
|
+
clean,
|
|
548
|
+
deflate_fonts,
|
|
549
|
+
linear,
|
|
550
|
+
),
|
|
551
|
+
)
|
|
552
|
+
process.start()
|
|
553
|
+
|
|
554
|
+
# Wait for subprocess with timeout
|
|
555
|
+
start_time = time.time()
|
|
556
|
+
|
|
557
|
+
while process.is_alive():
|
|
558
|
+
if time.time() - start_time > timeout:
|
|
559
|
+
logger.warning(
|
|
560
|
+
f"PDF save with clean=True timeout after {timeout} seconds, terminating subprocess"
|
|
561
|
+
)
|
|
562
|
+
process.terminate()
|
|
563
|
+
try:
|
|
564
|
+
process.join(5) # Give it 5 seconds to clean up
|
|
565
|
+
if process.is_alive():
|
|
566
|
+
logger.warning("Subprocess did not terminate, killing it")
|
|
567
|
+
process.kill()
|
|
568
|
+
process.terminate()
|
|
569
|
+
process.kill()
|
|
570
|
+
process.terminate()
|
|
571
|
+
process.kill()
|
|
572
|
+
process.terminate()
|
|
573
|
+
except Exception as e:
|
|
574
|
+
logger.error(f"Error terminating PDF save process: {e}")
|
|
575
|
+
|
|
576
|
+
# Fallback to save without clean parameter
|
|
577
|
+
logger.info("Falling back to save without clean=True")
|
|
578
|
+
try:
|
|
579
|
+
pdf.save(
|
|
580
|
+
output_path,
|
|
581
|
+
garbage=garbage,
|
|
582
|
+
deflate=deflate,
|
|
583
|
+
clean=False,
|
|
584
|
+
deflate_fonts=deflate_fonts,
|
|
585
|
+
linear=linear,
|
|
586
|
+
)
|
|
587
|
+
return False
|
|
588
|
+
except Exception as e:
|
|
589
|
+
logger.error(f"Error in fallback save: {e}")
|
|
590
|
+
# Last resort: basic save
|
|
591
|
+
pdf.save(output_path)
|
|
592
|
+
return False
|
|
593
|
+
|
|
594
|
+
time.sleep(0.5) # Check every half second
|
|
595
|
+
|
|
596
|
+
# Process completed, check exit code
|
|
597
|
+
exit_code = process.exitcode
|
|
598
|
+
success = exit_code == 0
|
|
599
|
+
|
|
600
|
+
# Check if save was successful
|
|
601
|
+
if (
|
|
602
|
+
success
|
|
603
|
+
and Path(temp_output).exists()
|
|
604
|
+
and Path(temp_output).stat().st_size > 0
|
|
605
|
+
):
|
|
606
|
+
logger.info("PDF save with clean=True completed successfully")
|
|
607
|
+
# Copy the successfully created file to the target path
|
|
608
|
+
try:
|
|
609
|
+
import shutil
|
|
610
|
+
|
|
611
|
+
shutil.copy2(temp_output, output_path)
|
|
612
|
+
return True
|
|
613
|
+
except Exception as e:
|
|
614
|
+
logger.error(f"Error copying saved PDF: {e}")
|
|
615
|
+
pdf.save(output_path) # Fallback to direct save
|
|
616
|
+
return False
|
|
617
|
+
else:
|
|
618
|
+
logger.warning(
|
|
619
|
+
f"PDF save with clean=True failed with exit code {exit_code} or produced empty file"
|
|
620
|
+
)
|
|
621
|
+
# Fallback to save without clean parameter
|
|
622
|
+
try:
|
|
623
|
+
pdf.save(
|
|
624
|
+
output_path,
|
|
625
|
+
garbage=garbage,
|
|
626
|
+
deflate=deflate,
|
|
627
|
+
clean=False,
|
|
628
|
+
deflate_fonts=deflate_fonts,
|
|
629
|
+
linear=linear,
|
|
630
|
+
)
|
|
631
|
+
except Exception as e:
|
|
632
|
+
logger.error(f"Error in fallback save: {e}")
|
|
633
|
+
# Last resort: basic save
|
|
634
|
+
pdf.save(output_path)
|
|
635
|
+
|
|
636
|
+
return False
|
|
637
|
+
|
|
453
638
|
def write(self, translation_config: TranslationConfig) -> TranslateResult:
|
|
454
639
|
basename = Path(translation_config.input_file).stem
|
|
455
640
|
debug_suffix = ".debug" if translation_config.debug else ""
|
|
@@ -579,8 +764,10 @@ class PDFCreater:
|
|
|
579
764
|
pretty=True,
|
|
580
765
|
)
|
|
581
766
|
translation_config.raise_if_cancelled()
|
|
582
|
-
|
|
767
|
+
self.save_pdf_with_timeout(
|
|
768
|
+
pdf,
|
|
583
769
|
mono_out_path,
|
|
770
|
+
translation_config,
|
|
584
771
|
garbage=1,
|
|
585
772
|
deflate=True,
|
|
586
773
|
clean=not translation_config.skip_clean,
|
|
@@ -627,8 +814,10 @@ class PDFCreater:
|
|
|
627
814
|
exc_info=True,
|
|
628
815
|
)
|
|
629
816
|
|
|
630
|
-
|
|
817
|
+
self.save_pdf_with_timeout(
|
|
818
|
+
dual,
|
|
631
819
|
dual_out_path,
|
|
820
|
+
translation_config,
|
|
632
821
|
garbage=1,
|
|
633
822
|
deflate=True,
|
|
634
823
|
clean=not translation_config.skip_clean,
|
|
@@ -5,6 +5,10 @@ import cv2
|
|
|
5
5
|
import httpx
|
|
6
6
|
import msgpack
|
|
7
7
|
import numpy as np
|
|
8
|
+
from tenacity import retry
|
|
9
|
+
from tenacity import retry_if_exception_type
|
|
10
|
+
from tenacity import stop_after_attempt
|
|
11
|
+
from tenacity import wait_exponential
|
|
8
12
|
|
|
9
13
|
from babeldoc.docvision.doclayout import DocLayoutModel
|
|
10
14
|
from babeldoc.docvision.doclayout import YoloBox
|
|
@@ -34,6 +38,17 @@ def encode_image(image) -> bytes:
|
|
|
34
38
|
return encoded
|
|
35
39
|
|
|
36
40
|
|
|
41
|
+
@retry(
|
|
42
|
+
stop=stop_after_attempt(3), # 最多重试3次
|
|
43
|
+
wait=wait_exponential(
|
|
44
|
+
multiplier=1, min=1, max=10
|
|
45
|
+
), # 指数退避策略,初始1秒,最大10秒
|
|
46
|
+
retry=retry_if_exception_type((httpx.HTTPError, Exception)), # 针对哪些异常重试
|
|
47
|
+
before_sleep=lambda retry_state: logger.warning(
|
|
48
|
+
f"Request failed, retrying in {retry_state.next_action.sleep} seconds... "
|
|
49
|
+
f"(Attempt {retry_state.attempt_number}/3)"
|
|
50
|
+
),
|
|
51
|
+
)
|
|
37
52
|
def predict_layout(
|
|
38
53
|
image,
|
|
39
54
|
host: str = "http://localhost:8000",
|
|
@@ -50,53 +65,49 @@ def predict_layout(
|
|
|
50
65
|
Returns:
|
|
51
66
|
List of predictions containing bounding boxes and classes
|
|
52
67
|
"""
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
68
|
+
# Prepare request data
|
|
69
|
+
if not isinstance(image, list):
|
|
70
|
+
image = [image]
|
|
71
|
+
image_data = [encode_image(image) for image in image]
|
|
72
|
+
data = {
|
|
73
|
+
"image": image_data,
|
|
74
|
+
"imgsz": imgsz,
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
# Pack data using msgpack
|
|
78
|
+
packed_data = msgpack.packb(data, use_bin_type=True)
|
|
79
|
+
logger.debug(f"Packed data size: {len(packed_data)} bytes")
|
|
80
|
+
|
|
81
|
+
# Send request
|
|
82
|
+
logger.debug(f"Sending request to {host}/inference")
|
|
83
|
+
response = httpx.post(
|
|
84
|
+
f"{host}/inference",
|
|
85
|
+
data=packed_data,
|
|
86
|
+
headers={
|
|
87
|
+
"Content-Type": "application/msgpack",
|
|
88
|
+
"Accept": "application/msgpack",
|
|
89
|
+
},
|
|
90
|
+
timeout=300,
|
|
91
|
+
follow_redirects=True,
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
logger.debug(f"Response status: {response.status_code}")
|
|
95
|
+
logger.debug(f"Response headers: {response.headers}")
|
|
96
|
+
|
|
97
|
+
if response.status_code == 200:
|
|
98
|
+
try:
|
|
99
|
+
result = msgpack.unpackb(response.content, raw=False)
|
|
100
|
+
return result
|
|
101
|
+
except Exception as e:
|
|
102
|
+
logger.exception(f"Failed to unpack response: {e!s}")
|
|
103
|
+
raise
|
|
104
|
+
else:
|
|
105
|
+
logger.error(f"Request failed with status {response.status_code}")
|
|
106
|
+
logger.error(f"Response content: {response.content}")
|
|
107
|
+
raise Exception(
|
|
108
|
+
f"Request failed with status {response.status_code}: {response.text}",
|
|
78
109
|
)
|
|
79
110
|
|
|
80
|
-
logger.debug(f"Response status: {response.status_code}")
|
|
81
|
-
logger.debug(f"Response headers: {response.headers}")
|
|
82
|
-
|
|
83
|
-
if response.status_code == 200:
|
|
84
|
-
try:
|
|
85
|
-
result = msgpack.unpackb(response.content, raw=False)
|
|
86
|
-
return result
|
|
87
|
-
except Exception as e:
|
|
88
|
-
logger.exception(f"Failed to unpack response: {e!s}")
|
|
89
|
-
raise
|
|
90
|
-
else:
|
|
91
|
-
logger.error(f"Request failed with status {response.status_code}")
|
|
92
|
-
logger.error(f"Response content: {response.content}")
|
|
93
|
-
raise Exception(
|
|
94
|
-
f"Request failed with status {response.status_code}: {response.text}",
|
|
95
|
-
)
|
|
96
|
-
except Exception as e:
|
|
97
|
-
logger.exception(f"Unexpected error: {e!s}")
|
|
98
|
-
raise
|
|
99
|
-
|
|
100
111
|
|
|
101
112
|
class RpcDocLayoutModel(DocLayoutModel):
|
|
102
113
|
"""DocLayoutModel implementation that uses RPC service."""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "BabelDOC"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.16"
|
|
4
4
|
description = "Yet Another Document Translator"
|
|
5
5
|
license = "AGPL-3.0"
|
|
6
6
|
readme = "README.md"
|
|
@@ -30,6 +30,7 @@ dependencies = [
|
|
|
30
30
|
"xsdata[cli,lxml,soap]>=24.12",
|
|
31
31
|
"msgpack>=1.1.0",
|
|
32
32
|
"pydantic>=2.10.6",
|
|
33
|
+
"tenacity>=9.0.0",
|
|
33
34
|
]
|
|
34
35
|
|
|
35
36
|
[project.urls]
|
|
@@ -131,7 +132,7 @@ pythonpath = [".", "src"]
|
|
|
131
132
|
testpaths = ["tests"]
|
|
132
133
|
|
|
133
134
|
[bumpver]
|
|
134
|
-
current_version = "0.1.
|
|
135
|
+
current_version = "0.1.16"
|
|
135
136
|
version_pattern = "MAJOR.MINOR.PATCH[.PYTAGNUM]"
|
|
136
137
|
|
|
137
138
|
[bumpver.file_patterns]
|
|
@@ -147,4 +148,4 @@ version_pattern = "MAJOR.MINOR.PATCH[.PYTAGNUM]"
|
|
|
147
148
|
]
|
|
148
149
|
"babeldoc/const.py" = [
|
|
149
150
|
'__version__ = "{version}"'
|
|
150
|
-
]
|
|
151
|
+
]
|
|
@@ -48,7 +48,7 @@ wheels = [
|
|
|
48
48
|
|
|
49
49
|
[[package]]
|
|
50
50
|
name = "babeldoc"
|
|
51
|
-
version = "0.1.
|
|
51
|
+
version = "0.1.16"
|
|
52
52
|
source = { editable = "." }
|
|
53
53
|
dependencies = [
|
|
54
54
|
{ name = "bitstring" },
|
|
@@ -67,6 +67,7 @@ dependencies = [
|
|
|
67
67
|
{ name = "pydantic" },
|
|
68
68
|
{ name = "pymupdf" },
|
|
69
69
|
{ name = "rich" },
|
|
70
|
+
{ name = "tenacity" },
|
|
70
71
|
{ name = "toml" },
|
|
71
72
|
{ name = "tqdm" },
|
|
72
73
|
{ name = "xsdata", extra = ["cli", "lxml", "soap"] },
|
|
@@ -105,6 +106,7 @@ requires-dist = [
|
|
|
105
106
|
{ name = "pydantic", specifier = ">=2.10.6" },
|
|
106
107
|
{ name = "pymupdf", specifier = ">=1.25.1" },
|
|
107
108
|
{ name = "rich", specifier = ">=13.9.4" },
|
|
109
|
+
{ name = "tenacity", specifier = ">=9.0.0" },
|
|
108
110
|
{ name = "toml", specifier = ">=0.10.2" },
|
|
109
111
|
{ name = "tqdm", specifier = ">=4.67.1" },
|
|
110
112
|
{ name = "xsdata", extras = ["cli", "lxml", "soap"], specifier = ">=24.12" },
|
|
@@ -1753,6 +1755,15 @@ wheels = [
|
|
|
1753
1755
|
{ url = "https://files.pythonhosted.org/packages/99/ff/c87e0622b1dadea79d2fb0b25ade9ed98954c9033722eb707053d310d4f3/sympy-1.13.3-py3-none-any.whl", hash = "sha256:54612cf55a62755ee71824ce692986f23c88ffa77207b30c1368eda4a7060f73", size = 6189483 },
|
|
1754
1756
|
]
|
|
1755
1757
|
|
|
1758
|
+
[[package]]
|
|
1759
|
+
name = "tenacity"
|
|
1760
|
+
version = "9.0.0"
|
|
1761
|
+
source = { registry = "https://pypi.org/simple" }
|
|
1762
|
+
sdist = { url = "https://files.pythonhosted.org/packages/cd/94/91fccdb4b8110642462e653d5dcb27e7b674742ad68efd146367da7bdb10/tenacity-9.0.0.tar.gz", hash = "sha256:807f37ca97d62aa361264d497b0e31e92b8027044942bfa756160d908320d73b", size = 47421 }
|
|
1763
|
+
wheels = [
|
|
1764
|
+
{ url = "https://files.pythonhosted.org/packages/b6/cb/b86984bed139586d01532a587464b5805f12e397594f19f931c4c2fbfa61/tenacity-9.0.0-py3-none-any.whl", hash = "sha256:93de0c98785b27fcf659856aa9f54bfbd399e29969b0621bc7f762bd441b4539", size = 28169 },
|
|
1765
|
+
]
|
|
1766
|
+
|
|
1756
1767
|
[[package]]
|
|
1757
1768
|
name = "toml"
|
|
1758
1769
|
version = "0.10.2"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.1.14"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{babeldoc-0.1.14 → babeldoc-0.1.16}/docs/ImplementationDetails/AsyncTranslate/AsyncTranslate.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{babeldoc-0.1.14 → babeldoc-0.1.16}/docs/ImplementationDetails/ParagraphFinding/ParagraphFinding.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|