"""
CoT 数据清洗脚本
功能:
1. 自动识别 think 模式新数据 / 旧数据两种格式
- 新数据 (think 模式): [草稿] Ref-Delta
→ 丢弃草稿,将 Ref-Delta 包入
- 旧数据: [Ref-Delta] (保持原逻辑)
2. 处理重复 标签
3. 验证必要字段完整性
4. 输出清洗报告
用法:
python clean_cot_data.py input.jsonl -o output.jsonl
python clean_cot_data.py input.jsonl # 覆盖原文件
"""
import re
import sys
import json
import argparse
from pathlib import Path
def clean_response(response: str, gt_answer: str = "") -> tuple[str, list[str]]:
"""清洗单条 response,返回 (清洗后文本, 修复记录列表)"""
fixes = []
# ---- 1. 保护 和 块 ----
answer_match = re.search(r"(.*?)", response, re.DOTALL)
answer_block = answer_match.group(0).strip() if answer_match else ""
kf_match = re.search(r"(.*?)", response, re.DOTALL)
kf_block = kf_match.group(0).strip() if kf_match else ""
# ---- 2. 识别格式:新(think模式) vs 旧 ----
# 新格式特征:Ref-Delta 在 之后(草稿在 内部)
# 旧格式特征:Ref-Delta 在 内部
think_match = re.search(r"(.*?)(.*)", response, re.DOTALL)
is_new_format = False
if think_match:
after_think = think_match.group(2)
if "Reference frame at" in after_think or "" in after_think:
is_new_format = True
if is_new_format:
# 新格式:丢弃 内的草稿,取 之后的 Ref-Delta 作为内容
after_think = think_match.group(2)
content = re.sub(r".*?", "", after_think, flags=re.DOTALL)
content = re.sub(r".*?", "", content, flags=re.DOTALL)
content = content.strip()
fixes.append("think模式新格式: 去除内部草稿,保留Ref-Delta")
n_think_open = n_think_close = 1
else:
# 旧格式:去掉所有 标签,内容原样保留
body = response
body = re.sub(r".*?", "", body, flags=re.DOTALL)
body = re.sub(r".*?", "", body, flags=re.DOTALL)
n_think_open = len(re.findall(r"", body))
n_think_close = len(re.findall(r"", body))
content = re.sub(r"?think>", "", body).strip()
# ---- 3. 清理 think 内容 ----
# 3a. 把 bullet list 转为散文 (去掉行首 - • * 符号)
if re.search(r"^\s*[-•*]\s", content, re.MULTILINE):
lines = content.split("\n")
cleaned_lines = []
for line in lines:
stripped = re.sub(r"^\s*[-•*]\s+", "", line)
if stripped != line:
fixes.append(f"去除bullet: {line.strip()[:60]}")
cleaned_lines.append(stripped)
content = "\n".join(cleaned_lines)
# 3b. 把 "At