# 劳动合同
### 一、合同期限与试用期
diff --git a/backend/app/services/contract_content_normalizer.py b/backend/app/services/contract_content_normalizer.py index 9b2571a8..e81fdd77 100644 --- a/backend/app/services/contract_content_normalizer.py +++ b/backend/app/services/contract_content_normalizer.py @@ -4,6 +4,14 @@ from html.parser import HTMLParser from typing import Any, Mapping, Optional +_MARKDOWN_CODE_FENCE_RE = re.compile(r"^\s*```[a-zA-Z0-9_-]*\s*$") +_MARKDOWN_HEADING_RE = re.compile(r"^\s{0,3}#{1,6}\s*") +_MARKDOWN_TRAILING_HEADING_RE = re.compile(r"\s+#{1,6}\s*$") +_MARKDOWN_BULLET_RE = re.compile(r"^\s*[-*+]\s+") +_MARKDOWN_BLOCKQUOTE_RE = re.compile(r"^\s*>\s?") +_MARKDOWN_TABLE_SEPARATOR_RE = re.compile(r"^\s*\|?\s*:?-{3,}:?\s*(\|\s*:?-{3,}:?\s*)+\|?\s*$") + + class ContractHTMLTextExtractor(HTMLParser): _BLOCK_TAGS = { "address", @@ -98,9 +106,9 @@ def normalize_contract_content(value: Any) -> str: if looks_like_html(text): stripped = html_to_text(text) - return stripped or text + return markdown_to_text(stripped or text) - return text + return markdown_to_text(text) def parse_contract_json_text(value: str) -> Optional[Mapping[str, Any]]: @@ -127,6 +135,28 @@ def html_to_text(value: str) -> str: return parser.get_text() +def markdown_to_text(value: str) -> str: + lines: list[str] = [] + for raw_line in str(value or "").splitlines(): + line = raw_line.strip() + if not line: + lines.append("") + continue + if _MARKDOWN_CODE_FENCE_RE.match(line) or _MARKDOWN_TABLE_SEPARATOR_RE.match(line): + continue + line = _MARKDOWN_BLOCKQUOTE_RE.sub("", line) + line = _MARKDOWN_HEADING_RE.sub("", line) + line = _MARKDOWN_TRAILING_HEADING_RE.sub("", line) + line = _MARKDOWN_BULLET_RE.sub("", line) + line = re.sub(r"(\*\*|__)(.*?)\1", r"\2", line) + line = re.sub(r"`([^`]+)`", r"\1", line) + line = line.replace("\\#", "#").strip() + lines.append(line) + text = "\n".join(lines) + text = re.sub(r"\n{3,}", "\n\n", text) + return text.strip() + + def looks_like_html(value: str) -> bool: return bool(re.search(r"?[a-zA-Z][^>]*>", str(value or ""))) diff --git a/backend/app/services/contract_generation_service.py b/backend/app/services/contract_generation_service.py index f0956dab..402c9479 100644 --- a/backend/app/services/contract_generation_service.py +++ b/backend/app/services/contract_generation_service.py @@ -244,6 +244,7 @@ class ContractGenerationService: "prompt_version": prompt_runtime_trace.get("prompt_version"), } + generated_content = normalize_contract_content(generated_content) timestamp = datetime.now().strftime('%Y%m%d_%H%M%S') file_content, file_name = self.export_service.export_contract( generated_content, @@ -3613,7 +3614,12 @@ class ContractGenerationService: related_legal_articles: List[Dict[str, Any]], ai_hints: List[Dict[str, Any]], ) -> str: - body = "".join(f"
{escape(part.strip())}
" for part in str(content or "").splitlines() if part.strip()) + paragraphs = [part.strip() for part in normalize_contract_content(content).splitlines() if part.strip()] + body_parts = [] + for part in paragraphs: + tag = "h2" if cls._looks_like_contract_heading(part) else "p" + body_parts.append(f"<{tag}>{escape(part)}{tag}>") + body = "".join(body_parts) if not body: body = "" hint_items = "".join(f"### 一、合同期限与试用期