120 lines
4.1 KiB
Python
120 lines
4.1 KiB
Python
"""
|
||
import_transcripts.py - 将源目录的 10 期文稿(docx/伪docx)导入到 benchmark-set/transcripts/
|
||
用法: python scripts/import_transcripts.py
|
||
"""
|
||
|
||
import re
|
||
import sys
|
||
from pathlib import Path
|
||
from docx import Document
|
||
|
||
# ===== 配置 =====
|
||
SRC_DIR = Path(r"E:\TPS-我和顾问的便签\刘瑞桦收集")
|
||
DST_DIR = Path(__file__).parent.parent / "benchmark-set" / "transcripts"
|
||
DST_DIR.mkdir(parents=True, exist_ok=True)
|
||
|
||
# 映射表: 源文件名 → 目标文件名
|
||
# (注意:源文件名中的标点/空格与预期不同,已据实更新)
|
||
FILE_MAP = [
|
||
("硅基大脑终稿.docx", "ep03_硅基大脑.md"),
|
||
("潜艇的仿生之路.docx", "ep04_潜艇仿生.md"),
|
||
("马年军事图鉴0125.docx", "ep07_马年图鉴.md"),
|
||
("\u300a枪械射速决定论\u300b0225.docx", "ep10_射速决定论.md"),
|
||
("完稿 武器进化论\uff1a空战颠覆者.docx", "ep11_空战颠覆者.md"),
|
||
("逆袭战局的组装武器.docx", "ep12_逆袭战局.md"),
|
||
("枪械设计中的长短智慧总稿.docx", "ep13_长短智慧.md"),
|
||
("\u201cX\u201d系列新成员\uff1aX-76飞机-最终稿.docx", "ep14_X76飞机.md"),
|
||
("空中坚盾\u2014\u2014解码现代防空网.docx", "ep15_空中坚盾.md"),
|
||
# .doc 文件(改 .docx 后重试)
|
||
("舰证不凡_docx版.docx", "ep05_舰证不凡.md"),
|
||
]
|
||
# ===== 配置 =====
|
||
|
||
|
||
def is_real_docx(path: Path) -> bool:
|
||
"""通过前 4 字节判断是否为真 docx(ZIP 格式)"""
|
||
try:
|
||
with open(path, "rb") as f:
|
||
header = f.read(4)
|
||
return header == b"PK\x03\x04"
|
||
except Exception:
|
||
return False
|
||
|
||
|
||
def extract_text_real_docx(path: Path) -> str:
|
||
"""用 python-docx 提取真 docx 段落文本"""
|
||
doc = Document(str(path))
|
||
paragraphs = []
|
||
for para in doc.paragraphs:
|
||
text = para.text.strip()
|
||
if text:
|
||
paragraphs.append(text)
|
||
return "\n\n".join(paragraphs)
|
||
|
||
|
||
def extract_text_fake_docx(path: Path) -> str:
|
||
"""伪 docx(实际是 UTF-8 纯文本),直接读取"""
|
||
return path.read_text(encoding="utf-8")
|
||
|
||
|
||
def clean_text(text: str) -> str:
|
||
"""清洗文本:去掉 **Markdown 强调**,合并连续空行"""
|
||
# 去掉 ** ... ** 强调符号,保留中间文字
|
||
text = re.sub(r"\*\*(.+?)\*\*", r"\1", text)
|
||
# 去掉 * ... * 斜体(如果还有残留)
|
||
text = re.sub(r"\*(.+?)\*", r"\1", text)
|
||
# 连续 3 个以上空行合并为 2 个
|
||
text = re.sub(r"\n{3,}", "\n\n", text)
|
||
return text.strip()
|
||
|
||
|
||
def process_file(src_name: str, dst_name: str) -> tuple[bool, str]:
|
||
"""处理单个文件,返回 (是否成功, 消息)"""
|
||
src_path = SRC_DIR / src_name
|
||
if not src_path.exists():
|
||
return False, f"源文件不存在: {src_name}"
|
||
|
||
try:
|
||
if is_real_docx(src_path):
|
||
raw_text = extract_text_real_docx(src_path)
|
||
else:
|
||
raw_text = extract_text_fake_docx(src_path)
|
||
|
||
clean_text_str = clean_text(raw_text)
|
||
dst_path = DST_DIR / dst_name
|
||
dst_path.write_text(clean_text_str, encoding="utf-8")
|
||
char_count = len(clean_text_str)
|
||
return True, f"OK ({char_count} 字符)"
|
||
except Exception as e:
|
||
return False, f"解析失败: {e}"
|
||
|
||
|
||
def main():
|
||
print(f"源目录: {SRC_DIR}")
|
||
print(f"目标目录: {DST_DIR}")
|
||
print(f"待处理: {len(FILE_MAP)} 期\n")
|
||
|
||
results = []
|
||
for src_name, dst_name in FILE_MAP:
|
||
ok, msg = process_file(src_name, dst_name)
|
||
results.append((src_name, dst_name, ok, msg))
|
||
status = "[OK]" if ok else "[FAIL]"
|
||
print(f" {status} {src_name} -> {dst_name} {msg}")
|
||
|
||
# 汇总
|
||
success = sum(1 for r in results if r[2])
|
||
fail = len(results) - success
|
||
print(f"\n===== 汇总 =====")
|
||
print(f"成功: {success}/{len(results)}")
|
||
if fail > 0:
|
||
print("失败文件:")
|
||
for src, dst, ok, msg in results:
|
||
if not ok:
|
||
print(f" - {src}")
|
||
else:
|
||
print("全部成功!")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|