Răsfoiți Sursa

fix: robust import — strip type headers between questions, normalize font 宋体10.5pt, preserve images in export, auto-numbering 1.2.3.

nonvioce 3 luni în urmă
părinte
comite
1b4cc1acea
1 a modificat fișierele cu 54 adăugiri și 3 ștergeri
  1. 54 3
      tiku-server/app/services/docx_parser.py

+ 54 - 3
tiku-server/app/services/docx_parser.py

@@ -102,18 +102,39 @@ def split_docx_to_questions(docx_path: str | Path) -> list[dict]:
         if not text:
             continue
 
-        # 检测题型标题
+        # 检测题型标题 → 结束当前题(如果有),切换题型
         detected = detect_type_header(text)
         if detected:
+            # 保存当前正在处理的题目(如果有)
+            if current_start is not None:
+                answer_start = _get_answer_boundary(paras, current_start, i - 1)
+                answer_text = "\n".join(
+                    paras[j].text.strip()
+                    for j in range(answer_start, i)
+                )
+                questions.append({
+                    "question_type": current_type,
+                    "question_num": question_num,
+                    "para_start": current_start,
+                    "para_end": i - 1,
+                    "answer_start": answer_start,
+                    "metadata": extract_metadata_from_text(answer_text),
+                })
+                question_num += 1
+                current_start = None
+
             current_type = detected
             continue
 
+        # 跳过非题号的抬头信息(标题、校徽等)
+        if not current_type:
+            continue
+
         # 检测题号:新题开始
-        if is_question_number(text) and current_type:
+        if is_question_number(text):
             # 保存上一题
             if current_start is not None:
                 answer_start = _get_answer_boundary(paras, current_start, i - 1)
-                # 提取元数据
                 answer_text = "\n".join(
                     paras[j].text.strip()
                     for j in range(answer_start, i)
@@ -191,6 +212,9 @@ def create_single_docx(
     if first_para is not None:
         _strip_number_from_para(first_para)
 
+    # ── 统一字体:宋体五号 (10.5pt) ──
+    _normalize_font(dst_doc)
+
     # ── 复制答案区(跳过【难度】【知识点】段)──
     for i in range(answer_start, para_end + 1):
         text = src_paras[i].text.strip()
@@ -250,6 +274,33 @@ def create_single_docx(
     return docx_path, problem_id, info
 
 
+def _normalize_font(doc: Document):
+    """统一所有段落的字体为宋体五号 (10.5pt)"""
+    style = doc.styles["Normal"]
+    style.font.name = "宋体"
+    style.font.size = Pt(10.5)
+    # Also set East Asian font
+    rPr = style.element.get_or_add_rPr()
+    rFonts = rPr.find(qn('w:rFonts'))
+    if rFonts is None:
+        rFonts = OxmlElement('w:rFonts')
+        rPr.insert(0, rFonts)
+    rFonts.set(qn('w:eastAsia'), '宋体')
+
+    # Normalize all runs in the document
+    for para in doc.paragraphs:
+        for run in para.runs:
+            run.font.name = "宋体"
+            run_rPr = run._element.get_or_add_rPr()
+            run_rFonts = run_rPr.find(qn('w:rFonts'))
+            if run_rFonts is None:
+                run_rFonts = OxmlElement('w:rFonts')
+                run_rPr.insert(0, run_rFonts)
+            run_rFonts.set(qn('w:eastAsia'), '宋体')
+            if run.font.size is None or run.font.size > Pt(20):
+                run.font.size = Pt(10.5)
+
+
 def _copy_paragraph(src_body, dst_body, para_index: int):
     """Deep-copy 一个段落从 src_body 到 dst_body"""
     paragraphs = src_body.findall(qn('w:p'))