BabelDOC 0.3.40__tar.gz → 0.3.41__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.
Files changed (106) hide show
  1. {babeldoc-0.3.40 → babeldoc-0.3.41}/PKG-INFO +1 -1
  2. babeldoc-0.3.41/babeldoc/__init__.py +1 -0
  3. {babeldoc-0.3.40 → babeldoc-0.3.41}/babeldoc/const.py +1 -1
  4. {babeldoc-0.3.40 → babeldoc-0.3.41}/babeldoc/document_il/midend/il_translator.py +83 -26
  5. {babeldoc-0.3.40 → babeldoc-0.3.41}/babeldoc/document_il/midend/il_translator_llm_only.py +43 -16
  6. {babeldoc-0.3.40 → babeldoc-0.3.41}/babeldoc/document_il/translator/translator.py +6 -3
  7. {babeldoc-0.3.40 → babeldoc-0.3.41}/babeldoc/main.py +1 -1
  8. {babeldoc-0.3.40 → babeldoc-0.3.41}/pyproject.toml +2 -2
  9. {babeldoc-0.3.40 → babeldoc-0.3.41}/uv.lock +1 -1
  10. babeldoc-0.3.40/babeldoc/__init__.py +0 -1
  11. {babeldoc-0.3.40 → babeldoc-0.3.41}/.cursorignore +0 -0
  12. {babeldoc-0.3.40 → babeldoc-0.3.41}/.github/ISSUE_TEMPLATE/bug_report.yaml +0 -0
  13. {babeldoc-0.3.40 → babeldoc-0.3.41}/.github/ISSUE_TEMPLATE/feature_request.yaml +0 -0
  14. {babeldoc-0.3.40 → babeldoc-0.3.41}/.github/PULL_REQUEST_TEMPLATE/pr_form.yml +0 -0
  15. {babeldoc-0.3.40 → babeldoc-0.3.41}/.github/dependabot.yml +0 -0
  16. {babeldoc-0.3.40 → babeldoc-0.3.41}/.github/labels.yml +0 -0
  17. {babeldoc-0.3.40 → babeldoc-0.3.41}/.github/release-drafter.yml +0 -0
  18. {babeldoc-0.3.40 → babeldoc-0.3.41}/.github/workflows/codeql.yml +0 -0
  19. {babeldoc-0.3.40 → babeldoc-0.3.41}/.github/workflows/docs.yml +0 -0
  20. {babeldoc-0.3.40 → babeldoc-0.3.41}/.github/workflows/labeler.yml +0 -0
  21. {babeldoc-0.3.40 → babeldoc-0.3.41}/.github/workflows/lint.yml +0 -0
  22. {babeldoc-0.3.40 → babeldoc-0.3.41}/.github/workflows/pr-lint.yml +0 -0
  23. {babeldoc-0.3.40 → babeldoc-0.3.41}/.github/workflows/publish-to-pypi.yml +0 -0
  24. {babeldoc-0.3.40 → babeldoc-0.3.41}/.github/workflows/test.yml +0 -0
  25. {babeldoc-0.3.40 → babeldoc-0.3.41}/.gitignore +0 -0
  26. {babeldoc-0.3.40 → babeldoc-0.3.41}/.pre-commit-config.yaml +0 -0
  27. {babeldoc-0.3.40 → babeldoc-0.3.41}/LICENSE +0 -0
  28. {babeldoc-0.3.40 → babeldoc-0.3.41}/README.md +0 -0
  29. {babeldoc-0.3.40 → babeldoc-0.3.41}/babeldoc/assets/assets.py +0 -0
  30. {babeldoc-0.3.40 → babeldoc-0.3.41}/babeldoc/assets/embedding_assets_metadata.py +0 -0
  31. {babeldoc-0.3.40 → babeldoc-0.3.41}/babeldoc/asynchronize/__init__.py +0 -0
  32. {babeldoc-0.3.40 → babeldoc-0.3.41}/babeldoc/converter.py +0 -0
  33. {babeldoc-0.3.40 → babeldoc-0.3.41}/babeldoc/document_il/__init__.py +0 -0
  34. {babeldoc-0.3.40 → babeldoc-0.3.41}/babeldoc/document_il/babeldoc_exception/BabelDOCException.py +0 -0
  35. {babeldoc-0.3.40 → babeldoc-0.3.41}/babeldoc/document_il/backend/__init__.py +0 -0
  36. {babeldoc-0.3.40 → babeldoc-0.3.41}/babeldoc/document_il/backend/pdf_creater.py +0 -0
  37. {babeldoc-0.3.40 → babeldoc-0.3.41}/babeldoc/document_il/frontend/__init__.py +0 -0
  38. {babeldoc-0.3.40 → babeldoc-0.3.41}/babeldoc/document_il/frontend/il_creater.py +0 -0
  39. {babeldoc-0.3.40 → babeldoc-0.3.41}/babeldoc/document_il/il_version_1.py +0 -0
  40. {babeldoc-0.3.40 → babeldoc-0.3.41}/babeldoc/document_il/il_version_1.rnc +0 -0
  41. {babeldoc-0.3.40 → babeldoc-0.3.41}/babeldoc/document_il/il_version_1.rng +0 -0
  42. {babeldoc-0.3.40 → babeldoc-0.3.41}/babeldoc/document_il/il_version_1.xsd +0 -0
  43. {babeldoc-0.3.40 → babeldoc-0.3.41}/babeldoc/document_il/midend/__init__.py +0 -0
  44. {babeldoc-0.3.40 → babeldoc-0.3.41}/babeldoc/document_il/midend/add_debug_information.py +0 -0
  45. {babeldoc-0.3.40 → babeldoc-0.3.41}/babeldoc/document_il/midend/detect_scanned_file.py +0 -0
  46. {babeldoc-0.3.40 → babeldoc-0.3.41}/babeldoc/document_il/midend/layout_parser.py +0 -0
  47. {babeldoc-0.3.40 → babeldoc-0.3.41}/babeldoc/document_il/midend/paragraph_finder.py +0 -0
  48. {babeldoc-0.3.40 → babeldoc-0.3.41}/babeldoc/document_il/midend/remove_descent.py +0 -0
  49. {babeldoc-0.3.40 → babeldoc-0.3.41}/babeldoc/document_il/midend/styles_and_formulas.py +0 -0
  50. {babeldoc-0.3.40 → babeldoc-0.3.41}/babeldoc/document_il/midend/table_parser.py +0 -0
  51. {babeldoc-0.3.40 → babeldoc-0.3.41}/babeldoc/document_il/midend/typesetting.py +0 -0
  52. {babeldoc-0.3.40 → babeldoc-0.3.41}/babeldoc/document_il/translator/__init__.py +0 -0
  53. {babeldoc-0.3.40 → babeldoc-0.3.41}/babeldoc/document_il/translator/cache.py +0 -0
  54. {babeldoc-0.3.40 → babeldoc-0.3.41}/babeldoc/document_il/utils/atomic_integer.py +0 -0
  55. {babeldoc-0.3.40 → babeldoc-0.3.41}/babeldoc/document_il/utils/fontmap.py +0 -0
  56. {babeldoc-0.3.40 → babeldoc-0.3.41}/babeldoc/document_il/utils/layout_helper.py +0 -0
  57. {babeldoc-0.3.40 → babeldoc-0.3.41}/babeldoc/document_il/utils/paragraph_helper.py +0 -0
  58. {babeldoc-0.3.40 → babeldoc-0.3.41}/babeldoc/document_il/utils/priority_thread_pool_executor.py +0 -0
  59. {babeldoc-0.3.40 → babeldoc-0.3.41}/babeldoc/document_il/utils/style_helper.py +0 -0
  60. {babeldoc-0.3.40 → babeldoc-0.3.41}/babeldoc/document_il/utils/zstd_helper.py +0 -0
  61. {babeldoc-0.3.40 → babeldoc-0.3.41}/babeldoc/document_il/xml_converter.py +0 -0
  62. {babeldoc-0.3.40 → babeldoc-0.3.41}/babeldoc/docvision/README.md +0 -0
  63. {babeldoc-0.3.40 → babeldoc-0.3.41}/babeldoc/docvision/__init__.py +0 -0
  64. {babeldoc-0.3.40 → babeldoc-0.3.41}/babeldoc/docvision/doclayout.py +0 -0
  65. {babeldoc-0.3.40 → babeldoc-0.3.41}/babeldoc/docvision/rpc_doclayout.py +0 -0
  66. {babeldoc-0.3.40 → babeldoc-0.3.41}/babeldoc/docvision/table_detection/rapidocr.py +0 -0
  67. {babeldoc-0.3.40 → babeldoc-0.3.41}/babeldoc/format/office/__init__.py +0 -0
  68. {babeldoc-0.3.40 → babeldoc-0.3.41}/babeldoc/high_level.py +0 -0
  69. {babeldoc-0.3.40 → babeldoc-0.3.41}/babeldoc/pdfinterp.py +0 -0
  70. {babeldoc-0.3.40 → babeldoc-0.3.41}/babeldoc/progress_monitor.py +0 -0
  71. {babeldoc-0.3.40 → babeldoc-0.3.41}/babeldoc/result_merger.py +0 -0
  72. {babeldoc-0.3.40 → babeldoc-0.3.41}/babeldoc/split_manager.py +0 -0
  73. {babeldoc-0.3.40 → babeldoc-0.3.41}/babeldoc/tools/generate_font_metadata.py +0 -0
  74. {babeldoc-0.3.40 → babeldoc-0.3.41}/babeldoc/tools/italic_assistance.py +0 -0
  75. {babeldoc-0.3.40 → babeldoc-0.3.41}/babeldoc/tools/italic_recognize_tool.py +0 -0
  76. {babeldoc-0.3.40 → babeldoc-0.3.41}/babeldoc/translation_config.py +0 -0
  77. {babeldoc-0.3.40 → babeldoc-0.3.41}/docs/CODE_OF_CONDUCT.md +0 -0
  78. {babeldoc-0.3.40 → babeldoc-0.3.41}/docs/CONTRIBUTING.md +0 -0
  79. {babeldoc-0.3.40 → babeldoc-0.3.41}/docs/CONTRIBUTOR_REWARD.md +0 -0
  80. {babeldoc-0.3.40 → babeldoc-0.3.41}/docs/ImplementationDetails/AsyncTranslate/AsyncTranslate.md +0 -0
  81. {babeldoc-0.3.40 → babeldoc-0.3.41}/docs/ImplementationDetails/ILTranslator/ILTranslator.md +0 -0
  82. {babeldoc-0.3.40 → babeldoc-0.3.41}/docs/ImplementationDetails/PDFCreation/PDFCreation.md +0 -0
  83. {babeldoc-0.3.40 → babeldoc-0.3.41}/docs/ImplementationDetails/PDFParsing/PDFParsing.md +0 -0
  84. {babeldoc-0.3.40 → babeldoc-0.3.41}/docs/ImplementationDetails/ParagraphFinding/ParagraphFinding.md +0 -0
  85. {babeldoc-0.3.40 → babeldoc-0.3.41}/docs/ImplementationDetails/README.md +0 -0
  86. {babeldoc-0.3.40 → babeldoc-0.3.41}/docs/ImplementationDetails/StylesAndFormulas/StylesAndFormulas.md +0 -0
  87. {babeldoc-0.3.40 → babeldoc-0.3.41}/docs/ImplementationDetails/Typesetting/Typesetting.md +0 -0
  88. {babeldoc-0.3.40 → babeldoc-0.3.41}/docs/README.md +0 -0
  89. {babeldoc-0.3.40 → babeldoc-0.3.41}/docs/deploy.sh +0 -0
  90. {babeldoc-0.3.40 → babeldoc-0.3.41}/docs/images/babeldoc-banner.png +0 -0
  91. {babeldoc-0.3.40 → babeldoc-0.3.41}/docs/images/babeldoc-big-logo-darkmode-with-transparent-background.png +0 -0
  92. {babeldoc-0.3.40 → babeldoc-0.3.41}/docs/images/babeldoc-big-logo-darkmode-with-transparent-background.svg +0 -0
  93. {babeldoc-0.3.40 → babeldoc-0.3.41}/docs/images/babeldoc-big-logo-with-transparent-background.png +0 -0
  94. {babeldoc-0.3.40 → babeldoc-0.3.41}/docs/images/babeldoc-big-logo-with-transparent-background.svg +0 -0
  95. {babeldoc-0.3.40 → babeldoc-0.3.41}/docs/images/babeldoc-big-logo.png +0 -0
  96. {babeldoc-0.3.40 → babeldoc-0.3.41}/docs/images/babeldoc-contributor_reward_example.png +0 -0
  97. {babeldoc-0.3.40 → babeldoc-0.3.41}/docs/images/babeldoc-preview.gif +0 -0
  98. {babeldoc-0.3.40 → babeldoc-0.3.41}/docs/images/babeldoc-small-logo-with-transparent-background.png +0 -0
  99. {babeldoc-0.3.40 → babeldoc-0.3.41}/docs/images/babeldoc-small-logo-with-transparent-background.svg +0 -0
  100. {babeldoc-0.3.40 → babeldoc-0.3.41}/docs/images/babeldoc-small-logo.png +0 -0
  101. {babeldoc-0.3.40 → babeldoc-0.3.41}/docs/index.md +0 -0
  102. {babeldoc-0.3.40 → babeldoc-0.3.41}/docs/intro-to-pdf-object.md +0 -0
  103. {babeldoc-0.3.40 → babeldoc-0.3.41}/docs/requirements.txt +0 -0
  104. {babeldoc-0.3.40 → babeldoc-0.3.41}/docs/supported_languages.md +0 -0
  105. {babeldoc-0.3.40 → babeldoc-0.3.41}/mkdocs.yml +0 -0
  106. {babeldoc-0.3.40 → babeldoc-0.3.41}/tests/test_translation_config.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: BabelDOC
3
- Version: 0.3.40
3
+ Version: 0.3.41
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
@@ -0,0 +1 @@
1
+ __version__ = "0.3.41"
@@ -3,7 +3,7 @@ import shutil
3
3
  import subprocess
4
4
  from pathlib import Path
5
5
 
6
- __version__ = "0.3.40"
6
+ __version__ = "0.3.41"
7
7
 
8
8
  CACHE_FOLDER = Path.home() / ".cache" / "babeldoc"
9
9
 
@@ -39,18 +39,29 @@ class RichTextPlaceholder:
39
39
  composition: PdfSameStyleCharacters,
40
40
  left_placeholder: str,
41
41
  right_placeholder: str,
42
+ left_regex_pattern: str = None,
43
+ right_regex_pattern: str = None,
42
44
  ):
43
45
  self.id = placeholder_id
44
46
  self.composition = composition
45
47
  self.left_placeholder = left_placeholder
46
48
  self.right_placeholder = right_placeholder
49
+ self.left_regex_pattern = left_regex_pattern
50
+ self.right_regex_pattern = right_regex_pattern
47
51
 
48
52
 
49
53
  class FormulaPlaceholder:
50
- def __init__(self, placeholder_id: int, formula: PdfFormula, placeholder: str):
54
+ def __init__(
55
+ self,
56
+ placeholder_id: int,
57
+ formula: PdfFormula,
58
+ placeholder: str,
59
+ regex_pattern: str,
60
+ ):
51
61
  self.id = placeholder_id
52
62
  self.formula = formula
53
63
  self.placeholder = placeholder
64
+ self.regex_pattern = regex_pattern
54
65
 
55
66
 
56
67
  class PbarContext:
@@ -328,10 +339,14 @@ class ILTranslator:
328
339
  paragraph: PdfParagraph,
329
340
  ):
330
341
  placeholder = self.translate_engine.get_formular_placeholder(formula_id)
342
+ if isinstance(placeholder, tuple):
343
+ placeholder, regex_pattern = placeholder
344
+ else:
345
+ regex_pattern = re.escape(placeholder)
331
346
  if placeholder in paragraph.unicode:
332
347
  return self.create_formula_placeholder(formula, formula_id + 1, paragraph)
333
348
 
334
- return FormulaPlaceholder(formula_id, formula, placeholder)
349
+ return FormulaPlaceholder(formula_id, formula, placeholder, regex_pattern)
335
350
 
336
351
  def create_rich_text_placeholder(
337
352
  self,
@@ -345,6 +360,14 @@ class ILTranslator:
345
360
  right_placeholder = self.translate_engine.get_rich_text_right_placeholder(
346
361
  composition_id,
347
362
  )
363
+ if isinstance(left_placeholder, tuple):
364
+ left_placeholder, left_placeholder_regex_pattern = left_placeholder
365
+ else:
366
+ left_placeholder_regex_pattern = re.escape(left_placeholder)
367
+ if isinstance(right_placeholder, tuple):
368
+ right_placeholder, right_placeholder_regex_pattern = right_placeholder
369
+ else:
370
+ right_placeholder_regex_pattern = re.escape(right_placeholder)
348
371
  if (
349
372
  left_placeholder in paragraph.unicode
350
373
  or right_placeholder in paragraph.unicode
@@ -360,6 +383,8 @@ class ILTranslator:
360
383
  composition,
361
384
  left_placeholder,
362
385
  right_placeholder,
386
+ left_placeholder_regex_pattern,
387
+ right_placeholder_regex_pattern,
363
388
  )
364
389
 
365
390
  def get_translate_input(
@@ -550,13 +575,14 @@ class ILTranslator:
550
575
  for placeholder in input_text.placeholders:
551
576
  if isinstance(placeholder, FormulaPlaceholder):
552
577
  # 转义特殊字符
553
- pattern = re.escape(placeholder.placeholder)
578
+ # pattern = re.escape(placeholder.placeholder)
579
+ pattern = placeholder.regex_pattern
554
580
  patterns.append(f"({pattern})")
555
581
  placeholder_patterns.append(f"({pattern})")
556
582
  placeholder_map[placeholder.placeholder] = placeholder
557
583
  else:
558
- left = re.escape(placeholder.left_placeholder)
559
- right = re.escape(placeholder.right_placeholder)
584
+ left = placeholder.left_regex_pattern
585
+ right = placeholder.right_regex_pattern
560
586
  patterns.append(f"({left}.*?{right})")
561
587
  placeholder_patterns.append(f"({left})")
562
588
  placeholder_patterns.append(f"({right})")
@@ -569,6 +595,8 @@ class ILTranslator:
569
595
  if all_match:
570
596
  if llm_translate_tracker:
571
597
  llm_translate_tracker.set_placeholder_full_match()
598
+ else:
599
+ logger.debug(f"Failed to match all placeholder for {input_text.unicode}")
572
600
  # 合并所有模式
573
601
  combined_pattern = "|".join(patterns)
574
602
  combined_placeholder_pattern = "|".join(placeholder_patterns)
@@ -618,13 +646,12 @@ class ILTranslator:
618
646
  p
619
647
  for p in input_text.placeholders
620
648
  if not isinstance(p, FormulaPlaceholder)
621
- and matched_text.startswith(p.left_placeholder)
649
+ and re.match(f"^{p.left_regex_pattern}", matched_text)
622
650
  )
623
- text = matched_text[
624
- len(placeholder.left_placeholder) : -len(
625
- placeholder.right_placeholder,
626
- )
627
- ]
651
+ text = re.match(
652
+ f"^{placeholder.left_regex_pattern}(.+){placeholder.right_regex_pattern}$",
653
+ matched_text,
654
+ ).group(1)
628
655
 
629
656
  if isinstance(
630
657
  placeholder.composition,
@@ -738,39 +765,69 @@ class ILTranslator:
738
765
  llm_input = [self.translation_config.custom_system_prompt]
739
766
  else:
740
767
  llm_input = [
741
- "You are a professional, authentic machine translation engine."
768
+ f"You are a professional and reliable machine translation engine responsible for translating the input text into {self.translation_config.lang_out}."
742
769
  ]
770
+ llm_hint = []
743
771
 
744
772
  if title_paragraph:
745
- llm_input.append(
773
+ llm_hint.append(
746
774
  f"The first title in the full text: {title_paragraph.unicode}"
747
775
  )
748
776
  if (
749
777
  local_title_paragraph
750
778
  and local_title_paragraph.debug_id != title_paragraph.debug_id
751
779
  ):
752
- llm_input.append(
780
+ llm_hint.append(
753
781
  f"The most similar title in the full text: {local_title_paragraph.unicode}"
754
782
  )
755
- # Create a structured prompt template for LLM translation
756
- llm_input.append(
757
- f'Please do not translate style tags like "{self.translate_engine.get_rich_text_left_placeholder(1)}xxx{self.translate_engine.get_rich_text_right_placeholder(2)}"!'
758
- )
759
783
 
760
- llm_input.append(
761
- f'Please do not translate formula placeholders like "{self.translate_engine.get_formular_placeholder(3)}"!'
762
- )
763
784
  if self.translation_config.add_formula_placehold_hint:
764
785
  placeholders_hint = translate_input.get_placeholders_hint()
765
786
  if placeholders_hint:
766
- llm_input.append(
787
+ llm_hint.append(
767
788
  f"This is the formula placeholder hint: \n{placeholders_hint}"
768
789
  )
769
- llm_input.append(
770
- "The system will automatically replace placeholders with corresponding formulas, please do not translate the placeholders!"
771
- )
790
+
791
+ if llm_hint:
792
+ llm_input.append(
793
+ "When translating, please refer to the following information to improve translation quality:"
794
+ )
795
+ for i, line in enumerate(llm_hint):
796
+ llm_input.append(f"{i}. {line}")
797
+ llm_input.append("When translating, please follow the following rules:")
798
+
799
+ rich_text_left_placeholder = (
800
+ self.translate_engine.get_rich_text_left_placeholder(1)
801
+ )
802
+ if isinstance(rich_text_left_placeholder, tuple):
803
+ rich_text_left_placeholder = rich_text_left_placeholder[0]
804
+ rich_text_right_placeholder = (
805
+ self.translate_engine.get_rich_text_right_placeholder(2)
806
+ )
807
+ if isinstance(rich_text_right_placeholder, tuple):
808
+ rich_text_right_placeholder = rich_text_right_placeholder[0]
809
+
810
+ # Create a structured prompt template for LLM translation
811
+ llm_input.append(
812
+ f'1. Do not translate style tags, such as "{rich_text_left_placeholder}xxx{rich_text_right_placeholder}"!'
813
+ )
814
+
815
+ formula_placeholder = self.translate_engine.get_formular_placeholder(3)
816
+ if isinstance(formula_placeholder, tuple):
817
+ formula_placeholder = formula_placeholder[0]
818
+
819
+ llm_input.append(
820
+ f'2. Do not translate formula placeholders, such as "{formula_placeholder}". The system will automatically replace the placeholders with the corresponding formulas.'
821
+ )
822
+ llm_input.append(
823
+ "3. If there is no need to translate (such as proper nouns, codes, etc.), then return the original text."
824
+ )
825
+ llm_input.append(
826
+ "4. Only output the translation result without explanations and annotations."
827
+ )
828
+ llm_input.append(f"5. Translate text into {self.translation_config.lang_out}.")
772
829
  prompt_template = f"""
773
- ;; Treat next line as plain text input and translate it into {self.translation_config.lang_out}, output translation ONLY. If translation is unnecessary (e.g. proper nouns, codes, {"{{1}}, etc. "}), return the original text. NO explanations. NO notes. Input:\n\n{text}
830
+ Now, please carefully read the following text to be translated and directly output your translation.\n\n{text}
774
831
 
775
832
  """
776
833
  llm_input.append(prompt_template)
@@ -177,7 +177,7 @@ class ILTranslatorLLMOnly:
177
177
  copy.deepcopy(paragraph)
178
178
  )
179
179
 
180
- if total_token_count > 400 or len(paragraphs) > 5:
180
+ if total_token_count > 200 or len(paragraphs) > 10:
181
181
  executor.submit(
182
182
  self.translate_paragraph,
183
183
  BatchParagraph(paragraphs, tracker),
@@ -265,24 +265,57 @@ class ILTranslatorLLMOnly:
265
265
  llm_input = [self.translation_config.custom_system_prompt]
266
266
  else:
267
267
  llm_input = [
268
- "You are a professional, authentic machine translation engine."
268
+ f"You are a professional and reliable machine translation engine responsible for translating the input text into {self.translation_config.lang_out}."
269
269
  ]
270
270
 
271
+ llm_hint = []
271
272
  if title_paragraph:
272
- llm_input.append(
273
+ llm_hint.append(
273
274
  f"The first title in the full text: {title_paragraph.unicode}"
274
275
  )
275
276
  if (
276
277
  local_title_paragraph
277
278
  and local_title_paragraph.debug_id != title_paragraph.debug_id
278
279
  ):
279
- llm_input.append(
280
+ llm_hint.append(
280
281
  f"The most similar title in the full text: {local_title_paragraph.unicode}"
281
282
  )
283
+
284
+ if llm_hint:
285
+ llm_input.append(
286
+ "When translating, please refer to the following information to improve translation quality:"
287
+ )
288
+ for i, line in enumerate(llm_hint):
289
+ llm_input.append(f"{i}. {line}")
290
+ llm_input.append("When translating, please follow the following rules:")
291
+ # Create a structured prompt template for LLM translation
292
+ rich_text_left_placeholder = (
293
+ self.translate_engine.get_rich_text_left_placeholder(1)
294
+ )
295
+ if isinstance(rich_text_left_placeholder, tuple):
296
+ rich_text_left_placeholder = rich_text_left_placeholder[0]
297
+ rich_text_right_placeholder = (
298
+ self.translate_engine.get_rich_text_right_placeholder(2)
299
+ )
300
+ if isinstance(rich_text_right_placeholder, tuple):
301
+ rich_text_right_placeholder = rich_text_right_placeholder[0]
302
+ llm_input.append(
303
+ f'1. Do not translate style tags, such as "{rich_text_left_placeholder}xxx{rich_text_right_placeholder}"!'
304
+ )
305
+
306
+ formula_placeholder = self.translate_engine.get_formular_placeholder(3)
307
+ if isinstance(formula_placeholder, tuple):
308
+ formula_placeholder = formula_placeholder[0]
309
+ llm_input.append(
310
+ f'2. Do not translate formula placeholders, such as "{formula_placeholder}". The system will automatically replace the placeholders with the corresponding formulas.'
311
+ )
312
+ llm_input.append(
313
+ "3. If there is no need to translate (such as proper nouns, codes, etc.), then return the original text."
314
+ )
282
315
  # Create a structured prompt template for LLM translation
283
316
  prompt_template = (
284
317
  f"""
285
- You will be given a JSON formatted input containing entries with "id" and "input" fields.
318
+ 4. You will be given a JSON formatted input containing entries with "id" and "input" fields.
286
319
 
287
320
  For each entry in the JSON, translate the contents of the "input" field into {self.translation_config.lang_out}.
288
321
  Write the translation back into the "output" field for that entry.
@@ -318,16 +351,6 @@ class ILTranslatorLLMOnly:
318
351
  """
319
352
  )
320
353
  llm_input.append(prompt_template)
321
- llm_input.append(
322
- f'Please do not translate style tags like "{self.translate_engine.get_rich_text_left_placeholder(1)}xxx{self.translate_engine.get_rich_text_right_placeholder(2)}"!'
323
- )
324
- llm_input.append(
325
- f'Please do not translate formula placeholders like "{self.translate_engine.get_formular_placeholder(3)}"!'
326
- )
327
- if self.translation_config.add_formula_placehold_hint:
328
- llm_input.append(
329
- "The system will automatically replace placeholders with corresponding formulas, please do not translate the placeholders!"
330
- )
331
354
  llm_input.append(
332
355
  f"""Here is the input:
333
356
 
@@ -350,7 +373,10 @@ class ILTranslatorLLMOnly:
350
373
 
351
374
  parsed_output = json.loads(llm_output)
352
375
 
353
- translation_results = {item["id"]: item["output"] for item in parsed_output}
376
+ translation_results = {
377
+ item["id"]: item.get("output", item.get("input"))
378
+ for item in parsed_output
379
+ }
354
380
 
355
381
  if len(translation_results) != len(inputs):
356
382
  raise Exception(
@@ -446,6 +472,7 @@ class ILTranslatorLLMOnly:
446
472
  logger.warning(error_message)
447
473
  for llm_translate_tracker in llm_translate_trackers:
448
474
  llm_translate_tracker.set_error_message(error_message)
475
+ llm_translate_tracker.set_fallback_to_translate()
449
476
  if not should_translate_paragraph:
450
477
  should_translate_paragraph = list(
451
478
  range(len(batch_paragraph.paragraphs))
@@ -277,11 +277,14 @@ class OpenAITranslator(BaseTranslator):
277
277
  logger.exception("Error updating token count")
278
278
 
279
279
  def get_formular_placeholder(self, placeholder_id: int):
280
- return "{v" + str(placeholder_id) + "}"
280
+ return "{v" + str(placeholder_id) + "}", f"{{\\s*v\\s*{placeholder_id}\\s*}}"
281
281
  return "{{" + str(placeholder_id) + "}}"
282
282
 
283
283
  def get_rich_text_left_placeholder(self, placeholder_id: int):
284
- return f"<style id='{placeholder_id}'>"
284
+ return (
285
+ f"<style id='{placeholder_id}'>",
286
+ f"<\\s*style\\s*id\\s*=\\s*'\\s*{placeholder_id}\\s*'\\s*>",
287
+ )
285
288
 
286
289
  def get_rich_text_right_placeholder(self, placeholder_id: int):
287
- return "</style>"
290
+ return "</style>", r"<\s*\/\s*style\s*>"
@@ -23,7 +23,7 @@ from babeldoc.translation_config import TranslationConfig
23
23
  from babeldoc.translation_config import WatermarkOutputMode
24
24
 
25
25
  logger = logging.getLogger(__name__)
26
- __version__ = "0.3.40"
26
+ __version__ = "0.3.41"
27
27
 
28
28
 
29
29
  def create_parser():
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "BabelDOC"
3
- version = "0.3.40"
3
+ version = "0.3.41"
4
4
  description = "Yet Another Document Translator"
5
5
  license = "AGPL-3.0"
6
6
  readme = "README.md"
@@ -150,7 +150,7 @@ pythonpath = [".", "src"]
150
150
  testpaths = ["tests"]
151
151
 
152
152
  [bumpver]
153
- current_version = "0.3.40"
153
+ current_version = "0.3.41"
154
154
  version_pattern = "MAJOR.MINOR.PATCH[.PYTAGNUM]"
155
155
 
156
156
  [bumpver.file_patterns]
@@ -48,7 +48,7 @@ wheels = [
48
48
 
49
49
  [[package]]
50
50
  name = "babeldoc"
51
- version = "0.3.40"
51
+ version = "0.3.41"
52
52
  source = { editable = "." }
53
53
  dependencies = [
54
54
  { name = "bitstring" },
@@ -1 +0,0 @@
1
- __version__ = "0.3.40"
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