feat: hide flagged scientific review captions
This commit is contained in:
@@ -110,7 +110,8 @@ This produces a separate reviewed translation set and JSON/Markdown report;
|
||||
the initial translations remain unchanged. Evidence-backed terminology or
|
||||
semantic corrections are applied, while uncertain source-caption, numeric,
|
||||
unit, drug, gene, protein, vector, strain, or model-name issues are preserved
|
||||
and flagged rather than guessed. Unresolved high-risk flags do not block the
|
||||
and flagged rather than guessed. Flagged cue pairs stay in the review report
|
||||
but are omitted from rendered subtitles. Unresolved high-risk flags do not block the
|
||||
ordinary internal-use workflow, but must be disclosed in the final handoff.
|
||||
|
||||
Render only the reviewed translation set and bind its exact review report:
|
||||
|
||||
@@ -113,7 +113,9 @@ Use the statuses conservatively:
|
||||
scientific or semantic error. Do not use it for preference-only rewriting.
|
||||
- `flagged`: preserve the initial translation exactly and record a medium/high
|
||||
unresolved concern. Never guess a correction to a suspected source-caption
|
||||
error, drug, gene, protein, vector, strain, model, dose, or unit.
|
||||
error, drug, gene, protein, vector, strain, model, dose, or unit. Flagged
|
||||
cue pairs remain in the report but are excluded from the rendered bilingual
|
||||
subtitles, so uncertainty markers such as “(听不清)” never appear in the MP4.
|
||||
|
||||
Numbers and scientific names are protected. The validator rejects a correction
|
||||
that changes them; use `flagged` when such a change may be necessary. Preserve
|
||||
|
||||
@@ -392,6 +392,9 @@ def finalize(
|
||||
if [item["id"] for item in all_reviews] != [item["id"] for item in items]:
|
||||
raise ReviewError("scientific reviews do not cover every subtitle segment exactly once")
|
||||
reviewed = {record["id"]: record["translation"] for record in all_reviews}
|
||||
suppressed_segment_ids = [
|
||||
record["id"] for record in all_reviews if record["status"] == "flagged"
|
||||
]
|
||||
reviewed_dir = review_dir / REVIEWED_DIR_NAME
|
||||
reviewed_dir.mkdir(parents=True, exist_ok=True)
|
||||
reviewed_path = reviewed_dir / "translations.json"
|
||||
@@ -423,6 +426,7 @@ def finalize(
|
||||
"initial_translation_sha256": _sha256_json(initial),
|
||||
"reviewed_translation_sha256": _sha256_json(reviewed),
|
||||
"reviewed_translations_dir": str(reviewed_dir.resolve()),
|
||||
"suppressed_segment_ids": suppressed_segment_ids,
|
||||
"profile": profile,
|
||||
"counts": {
|
||||
"total": len(all_reviews),
|
||||
|
||||
@@ -1001,7 +1001,8 @@ def _ass_layout(manifest: dict[str, Any]) -> dict[str, int]:
|
||||
|
||||
|
||||
def _render_ass(
|
||||
manifest: dict[str, Any], translations: dict[str, str], font: str
|
||||
manifest: dict[str, Any], translations: dict[str, str], font: str,
|
||||
suppressed_segment_ids: set[str] | None = None,
|
||||
) -> str:
|
||||
font = _validate_font(font)
|
||||
cue_by_id = _cue_map(manifest)
|
||||
@@ -1035,6 +1036,10 @@ Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
|
||||
target_language = str(manifest.get("target_language") or DEFAULT_TARGET_LANGUAGE)
|
||||
dialogue: list[str] = []
|
||||
for segment in _render_segments(manifest):
|
||||
if suppressed_segment_ids and any(
|
||||
segment_id in suppressed_segment_ids for segment_id in segment["cue_ids"]
|
||||
):
|
||||
continue
|
||||
source_exact = _segment_source_text(segment, cue_by_id)
|
||||
target_exact = normalize_target_caption(
|
||||
_display_translation(manifest, segment, translations), target_language
|
||||
@@ -1070,7 +1075,8 @@ def _target_srt_name(manifest: dict[str, Any]) -> str:
|
||||
|
||||
|
||||
def _expected_outputs(
|
||||
manifest: dict[str, Any], translations: dict[str, str], font: str
|
||||
manifest: dict[str, Any], translations: dict[str, str], font: str,
|
||||
suppressed_segment_ids: set[str] | None = None,
|
||||
) -> dict[str, bytes]:
|
||||
cue_by_id = _cue_map(manifest)
|
||||
layout = _ass_layout(manifest)
|
||||
@@ -1079,6 +1085,10 @@ def _expected_outputs(
|
||||
target_entries: list[tuple[int, int, str]] = []
|
||||
bilingual_entries: list[tuple[int, int, str]] = []
|
||||
for segment in _render_segments(manifest):
|
||||
if suppressed_segment_ids and any(
|
||||
segment_id in suppressed_segment_ids for segment_id in segment["cue_ids"]
|
||||
):
|
||||
continue
|
||||
source_exact = _segment_source_text(segment, cue_by_id)
|
||||
source_chunks = wrap_layout_chunks(source_exact, layout["source_columns"])
|
||||
if "".join(source_chunks) != source_exact:
|
||||
@@ -1099,7 +1109,9 @@ def _expected_outputs(
|
||||
"source.srt": _render_srt(source_entries).encode("utf-8"),
|
||||
_target_srt_name(manifest): _render_srt(target_entries).encode("utf-8"),
|
||||
"bilingual.srt": _render_srt(bilingual_entries).encode("utf-8"),
|
||||
"bilingual.ass": _render_ass(manifest, translations, font).encode("utf-8"),
|
||||
"bilingual.ass": _render_ass(
|
||||
manifest, translations, font, suppressed_segment_ids
|
||||
).encode("utf-8"),
|
||||
}
|
||||
|
||||
|
||||
@@ -1155,6 +1167,9 @@ def _scientific_review_binding(
|
||||
counts = value.get("counts")
|
||||
if not isinstance(counts, dict) or counts.get("total") != len(translations):
|
||||
raise PipelineError("scientific review report segment count is invalid")
|
||||
suppressed = value.get("suppressed_segment_ids", [])
|
||||
if not isinstance(suppressed, list) or not all(isinstance(segment_id, str) for segment_id in suppressed):
|
||||
raise PipelineError("scientific review suppression list is malformed")
|
||||
return {
|
||||
"report_path": str(review_report),
|
||||
"report_sha256": _sha256_bytes(review_report.read_bytes()),
|
||||
@@ -1162,6 +1177,7 @@ def _scientific_review_binding(
|
||||
"human_expert_reviewed": False,
|
||||
"counts": counts,
|
||||
"disclosure": value.get("disclosure"),
|
||||
"suppressed_segment_ids": suppressed,
|
||||
}
|
||||
|
||||
|
||||
@@ -1211,7 +1227,21 @@ def render(
|
||||
scientific_review = _scientific_review_binding(
|
||||
scientific_review_report, manifest_path, translations_dir, translations
|
||||
)
|
||||
expected = _expected_outputs(manifest, translations, font)
|
||||
suppressed_cue_ids = None
|
||||
if scientific_review:
|
||||
suppressed_review_ids = set(scientific_review.get("suppressed_segment_ids", []))
|
||||
suppressed_cue_ids = {
|
||||
cue_id
|
||||
for translation_segment in manifest["segments"]
|
||||
if translation_segment["id"] in suppressed_review_ids
|
||||
for cue_id in translation_segment["cue_ids"]
|
||||
}
|
||||
expected = _expected_outputs(
|
||||
manifest,
|
||||
translations,
|
||||
font,
|
||||
suppressed_cue_ids,
|
||||
)
|
||||
output_dir.mkdir(parents=True, exist_ok=True)
|
||||
for name, data in expected.items():
|
||||
_atomic_write(output_dir / name, data)
|
||||
|
||||
@@ -133,6 +133,7 @@ class ScientificReviewTests(unittest.TestCase):
|
||||
target = (self.root / "rendered" / "zh-CN.srt").read_text(encoding="utf-8")
|
||||
self.assertIn("暴露上方巩膜", target)
|
||||
self.assertNotIn("暴露上方巩膜组织", target)
|
||||
self.assertNotIn(items[2]["translation"], target)
|
||||
|
||||
def test_correction_cannot_change_protected_number_or_scientific_name(self) -> None:
|
||||
self.write_profile()
|
||||
|
||||
Reference in New Issue
Block a user