GuXiaopeng commited on
Commit
5d4217d
·
1 Parent(s): 7047168

Step 4A-6-C-R3.2.3 Translation Marker Robustness Fix (#13)

Browse files

- Step 4A-6-C-R3.2.3 Translation Marker Robustness Fix (84e30cf98ff518d15e6dbe8b1076a7a0dd750d76)

__pycache__/app.cpython-313.pyc CHANGED
Binary files a/__pycache__/app.cpython-313.pyc and b/__pycache__/app.cpython-313.pyc differ
 
__pycache__/config.cpython-313.pyc CHANGED
Binary files a/__pycache__/config.cpython-313.pyc and b/__pycache__/config.cpython-313.pyc differ
 
__pycache__/i18n.cpython-313.pyc CHANGED
Binary files a/__pycache__/i18n.cpython-313.pyc and b/__pycache__/i18n.cpython-313.pyc differ
 
__pycache__/managed_auth.cpython-313.pyc CHANGED
Binary files a/__pycache__/managed_auth.cpython-313.pyc and b/__pycache__/managed_auth.cpython-313.pyc differ
 
__pycache__/task_executor.cpython-313.pyc CHANGED
Binary files a/__pycache__/task_executor.cpython-313.pyc and b/__pycache__/task_executor.cpython-313.pyc differ
 
core/__pycache__/checkpoint_store.cpython-313.pyc CHANGED
Binary files a/core/__pycache__/checkpoint_store.cpython-313.pyc and b/core/__pycache__/checkpoint_store.cpython-313.pyc differ
 
core/__pycache__/generation_runner.cpython-313.pyc CHANGED
Binary files a/core/__pycache__/generation_runner.cpython-313.pyc and b/core/__pycache__/generation_runner.cpython-313.pyc differ
 
core/__pycache__/meta_extractor.cpython-313.pyc CHANGED
Binary files a/core/__pycache__/meta_extractor.cpython-313.pyc and b/core/__pycache__/meta_extractor.cpython-313.pyc differ
 
core/__pycache__/pipeline_agent.cpython-313.pyc CHANGED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:185a6cfe4441c00b83aab3c8b7990c30043a17525472b3d01b78350d99d8e2b7
3
- size 158928
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:576dd3905d2ec79e768e26b13790a53de0568073c16ef7e03c9dda6fcc26d5f7
3
+ size 158942
core/__pycache__/production_guard.cpython-313.pyc CHANGED
Binary files a/core/__pycache__/production_guard.cpython-313.pyc and b/core/__pycache__/production_guard.cpython-313.pyc differ
 
core/__pycache__/qualitative_engine.cpython-313.pyc CHANGED
Binary files a/core/__pycache__/qualitative_engine.cpython-313.pyc and b/core/__pycache__/qualitative_engine.cpython-313.pyc differ
 
core/__pycache__/quantitative_engine.cpython-313.pyc CHANGED
Binary files a/core/__pycache__/quantitative_engine.cpython-313.pyc and b/core/__pycache__/quantitative_engine.cpython-313.pyc differ
 
core/__pycache__/rag_engine.cpython-313.pyc CHANGED
Binary files a/core/__pycache__/rag_engine.cpython-313.pyc and b/core/__pycache__/rag_engine.cpython-313.pyc differ
 
core/pipeline_agent.py CHANGED
@@ -2074,7 +2074,6 @@ Return ONLY a valid JSON array of strings."""
2074
 
2075
  cfg = self.citation_semantic_audit
2076
  enabled = bool(cfg.get("enabled", True))
2077
- fail_closed = bool(cfg.get("fail_closed", True))
2078
  spans = self._citation_sentence_spans(text)
2079
  if not spans:
2080
  return text
@@ -2282,6 +2281,11 @@ Return exactly:
2282
  f"[{tag.upper()}]"
2283
  for tag in re.findall(r"CITE-\d+", revised, flags=re.IGNORECASE)
2284
  }
 
 
 
 
 
2285
  disallowed = revised_tags - set(record["allowed_tags"])
2286
  if disallowed:
2287
  raise DeepSeekRequestError(
@@ -2469,6 +2473,8 @@ Return exactly:
2469
  except PipelineCancelledError:
2470
  raise
2471
  except CitationAuditError as error:
 
 
2472
  logging.warning(
2473
  'Citation semantic audit technical fallback: section=%s code=%s detail=%s',
2474
  section_name,
@@ -2477,6 +2483,8 @@ Return exactly:
2477
  )
2478
  value = self._local_citation_recovery(value, section_name)
2479
  except Exception as error:
 
 
2480
  logging.warning(
2481
  'Citation semantic audit fallback: section=%s error=%s',
2482
  section_name,
@@ -2806,6 +2814,83 @@ Translate headings and terminology naturally. Preserve standard variable abbrevi
2806
  if not is_chinese and not re.search(r'[А-Яа-яЁёӘәҒғҚқҢңӨөҰұҮүҺһІі]', translated):
2807
  raise DeepSeekRequestError(f'Translation block {block_id} contains no Cyrillic target-language text.')
2808
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2809
  def translate_locked_manuscript(self, manuscript, target_lang):
2810
  value = str(manuscript or '').strip()
2811
  if not value:
@@ -2839,24 +2924,10 @@ Translate headings and terminology naturally. Preserve standard variable abbrevi
2839
  system_prompt = self._translation_prompt(target_lang) + '\nUse this terminology glossary consistently:\n' + json.dumps(glossary, ensure_ascii=False)
2840
  for batch in batches:
2841
  self._check_cancelled()
2842
- marked_source = '\n\n'.join(
2843
- f'[[SP-P{block_id}]]\n{source}' for block_id, source in batch
2844
- )
2845
- result = self.call_deepseek(
2846
- system_prompt,
2847
- marked_source,
2848
- max_tokens=max(1800, min(9000, self._count_tokens(marked_source) * 2 + 1200)),
2849
- temp=0.0,
2850
- model_role='translation',
2851
- thinking=False,
2852
- allow_fallback=False,
2853
  )
2854
- result = self._remove_ai_meta_traces(result)
2855
- parsed = self._parse_marked_translation(result, [block_id for block_id, _ in batch])
2856
- for block_id, source in batch:
2857
- translated = parsed[block_id]
2858
- self._validate_translation_block(source, translated, f'SP-P{block_id}', target_lang)
2859
- translations[block_id] = translated
2860
 
2861
  output_units = []
2862
  body_index = 0
 
2074
 
2075
  cfg = self.citation_semantic_audit
2076
  enabled = bool(cfg.get("enabled", True))
 
2077
  spans = self._citation_sentence_spans(text)
2078
  if not spans:
2079
  return text
 
2281
  f"[{tag.upper()}]"
2282
  for tag in re.findall(r"CITE-\d+", revised, flags=re.IGNORECASE)
2283
  }
2284
+ if status in {"ok", "split"} and not revised_tags:
2285
+ raise DeepSeekRequestError(
2286
+ f"Citation semantic audit removed all citation tags for {record['id']} "
2287
+ f"while status={status}."
2288
+ )
2289
  disallowed = revised_tags - set(record["allowed_tags"])
2290
  if disallowed:
2291
  raise DeepSeekRequestError(
 
2473
  except PipelineCancelledError:
2474
  raise
2475
  except CitationAuditError as error:
2476
+ if bool(self.citation_semantic_audit.get('fail_closed', False)):
2477
+ raise
2478
  logging.warning(
2479
  'Citation semantic audit technical fallback: section=%s code=%s detail=%s',
2480
  section_name,
 
2483
  )
2484
  value = self._local_citation_recovery(value, section_name)
2485
  except Exception as error:
2486
+ if bool(self.citation_semantic_audit.get('fail_closed', False)):
2487
+ raise
2488
  logging.warning(
2489
  'Citation semantic audit fallback: section=%s error=%s',
2490
  section_name,
 
2814
  if not is_chinese and not re.search(r'[А-Яа-яЁёӘәҒғҚқҢңӨөҰұҮүҺһІі]', translated):
2815
  raise DeepSeekRequestError(f'Translation block {block_id} contains no Cyrillic target-language text.')
2816
 
2817
+ def _translate_marked_batch_with_recovery(self, batch, system_prompt, target_lang):
2818
+ """Translate one marked batch with a conservative marker-recovery path.
2819
+
2820
+ A multi-block response must preserve every marker exactly. If the model
2821
+ omits or reorders markers, retry each source block independently so no
2822
+ paragraph-to-translation mapping is guessed. For a single-source retry,
2823
+ a marker-free response can be bound safely to that sole source block,
2824
+ but it must still pass the existing deterministic translation guards.
2825
+ """
2826
+ expected_ids = [block_id for block_id, _ in batch]
2827
+ marked_source = '\n\n'.join(
2828
+ f'[[SP-P{block_id}]]\n{source}' for block_id, source in batch
2829
+ )
2830
+ result = self.call_deepseek(
2831
+ system_prompt,
2832
+ marked_source,
2833
+ max_tokens=max(1800, min(9000, self._count_tokens(marked_source) * 2 + 1200)),
2834
+ temp=0.0,
2835
+ model_role='translation',
2836
+ thinking=False,
2837
+ allow_fallback=False,
2838
+ )
2839
+ result = self._remove_ai_meta_traces(result)
2840
+
2841
+ try:
2842
+ parsed = self._parse_marked_translation(result, expected_ids)
2843
+ except DeepSeekRequestError as error:
2844
+ if not str(error).startswith('Translation marker mismatch:'):
2845
+ raise
2846
+
2847
+ if len(batch) > 1:
2848
+ logging.warning(
2849
+ 'Translation marker recovery: batch_size=%s expected=%s; retrying blocks independently.',
2850
+ len(batch),
2851
+ expected_ids,
2852
+ )
2853
+ recovered = {}
2854
+ for item in batch:
2855
+ recovered.update(
2856
+ self._translate_marked_batch_with_recovery(
2857
+ [item], system_prompt, target_lang
2858
+ )
2859
+ )
2860
+ return recovered
2861
+
2862
+ block_id, source = batch[0]
2863
+ unexpected_markers = re.findall(
2864
+ r'(?m)^\[\[SP-P(\d{6})\]\]\s*$',
2865
+ str(result or ''),
2866
+ )
2867
+ if unexpected_markers:
2868
+ raise DeepSeekRequestError(
2869
+ 'Single-block translation returned an unexpected marker: '
2870
+ f'expected={block_id}, got={unexpected_markers}.'
2871
+ ) from error
2872
+
2873
+ translated = str(result or '').strip()
2874
+ if not translated:
2875
+ raise DeepSeekRequestError(
2876
+ f'Single-block translation recovery returned empty text for SP-P{block_id}.'
2877
+ ) from error
2878
+ self._validate_translation_block(
2879
+ source, translated, f'SP-P{block_id}', target_lang
2880
+ )
2881
+ logging.info(
2882
+ 'Translation marker recovery accepted marker-free single block: SP-P%s',
2883
+ block_id,
2884
+ )
2885
+ return {block_id: translated}
2886
+
2887
+ for block_id, source in batch:
2888
+ translated = parsed[block_id]
2889
+ self._validate_translation_block(
2890
+ source, translated, f'SP-P{block_id}', target_lang
2891
+ )
2892
+ return parsed
2893
+
2894
  def translate_locked_manuscript(self, manuscript, target_lang):
2895
  value = str(manuscript or '').strip()
2896
  if not value:
 
2924
  system_prompt = self._translation_prompt(target_lang) + '\nUse this terminology glossary consistently:\n' + json.dumps(glossary, ensure_ascii=False)
2925
  for batch in batches:
2926
  self._check_cancelled()
2927
+ parsed = self._translate_marked_batch_with_recovery(
2928
+ batch, system_prompt, target_lang
 
 
 
 
 
 
 
 
 
2929
  )
2930
+ translations.update(parsed)
 
 
 
 
 
2931
 
2932
  output_units = []
2933
  body_index = 0
smartpaper_restore_bridge/__pycache__/__init__.cpython-313.pyc CHANGED
Binary files a/smartpaper_restore_bridge/__pycache__/__init__.cpython-313.pyc and b/smartpaper_restore_bridge/__pycache__/__init__.cpython-313.pyc differ
 
utils/__pycache__/docx_builder.cpython-313.pyc CHANGED
Binary files a/utils/__pycache__/docx_builder.cpython-313.pyc and b/utils/__pycache__/docx_builder.cpython-313.pyc differ
 
utils/__pycache__/file_parser.cpython-313.pyc CHANGED
Binary files a/utils/__pycache__/file_parser.cpython-313.pyc and b/utils/__pycache__/file_parser.cpython-313.pyc differ