CoT_box_upload / model /parser.py
BingoG's picture
Upload model files
aa975a2 verified
Raw
History Blame Contribute Delete
4.97 kB
# parser.py
# -*- coding: utf-8 -*-
"""
Step5 解析器(稳健版)
- 兼容中文全角/半角、圆括号/方括号、中文/英文逗号
- 抽取:增强后的指令 + 逐帧 bbox(与采样 t 序列对齐)
- 校验:0<=x1<x2<=1, 0<=y1<y2<=1;不合法则记为 None
"""
import re
from typing import Dict, List, Tuple
CN2NUM = {
"一": 1, "二": 2, "三": 3, "四": 4, "五": 5,
"六": 6, "七": 7, "八": 8, "九": 9, "十": 10
}
# 全角到半角的基础归一化(冒号/逗号/括号等)
FULL2HALF_MAP = str.maketrans({
"(": "(", ")": ")", "【": "[", "】": "]", "[": "[", "]": "]",
",": ",", ":": ":", ";": ";", "。": ".", "、": ",", "|": "|",
})
def _normalize_text(s: str) -> str:
s = (s or "").strip().replace("\u00A0", " ").replace("\t", " ")
# 去多空格
s = re.sub(r"[ ]{2,}", " ", s)
return s.translate(FULL2HALF_MAP)
def _extract_enhanced_instruction(step5_line: str) -> str:
"""
支持两种写法:
1) 修改后的编辑指令:{ ... },任务一boxing序列:
2) 修改后的编辑指令:...,任务一boxing序列:
同时兼容中文/英文逗号,冒号,花括号可选
"""
# 先尝试「有花括号」版本
m = re.search(r"修改后的编辑指令[::]\s*\{(?P<inst>.+?)\}\s*[,,]", step5_line)
if m:
return m.group("inst").strip()
# 再尝试「无花括号」版本:取到 “任务一boxing序列:”/“任务1boxing序列:” 之前
m = re.search(
r"修改后的编辑指令[::]\s*(?P<inst>.+?)\s*[,,]\s*任务\s*[一二三四五六七八九十\d]+\s*boxing序列[::]",
step5_line
)
return m.group("inst").strip() if m else ""
def _task_key_to_idx(tok: str) -> int:
# "任务一"/"任务1"
m = re.search(r"任务\s*([一二三四五六七八九十\d]+)", tok)
if not m:
return 1
key = m.group(1)
return CN2NUM.get(key, int(key) if key.isdigit() else 1)
def parse_step5(step5_line: str, t_list: List[int]) -> Tuple[str, Dict[str, List[Dict]]]:
"""
返回 (enhanced_instruction, tasks_json)
tasks_json 结构:
{
"任务一": [{"t": t0, "bbox":[x1,y1,x2,y2] or None}, ...],
...
}
"""
s = _normalize_text(step5_line)
enhanced = _extract_enhanced_instruction(s)
# 按任务切分:“…任务一boxing序列:[...],任务二boxing序列:[...]…”
# ⚠️ 兼容半角/全角冒号(归一化后为半角 ":",但正则也允许全角)
parts = re.split(r"(任务[一二三四五六七八九十\d]+\s*boxing序列[::])", s)
tasks_json: Dict[str, List[Dict]] = {}
def parse_seq(seq_txt: str) -> List[Dict]:
"""
解析形如:
[(t=0,[(0.64,0.68,0.71,0.78)]);(t=1,[(0.64,0.68,0.71,0.78)])]
允许 () 或 [] 包围 bbox,允许中文逗号/空格。
"""
seq_txt = (seq_txt or "").strip()
# 拆帧项,分隔符 ; 或 ;(也容忍多余空格)
items = re.split(r"[;;]+", seq_txt.strip("[] "))
out = []
for it in items:
it = it.strip()
if not it:
continue
# 抓 t 值
mt = re.search(r"t\s*=\s*(\d+)", it)
if not mt:
continue
t = int(mt.group(1))
# 抓 bbox:先定位一对括号内容,兼容 [] 或 ()
mb = re.search(r"\[\s*([\d\.\s,,]+)\s*\]|\(\s*([\d\.\s,,]+)\s*\)", it)
if not mb:
out.append({"t": t, "bbox": None})
continue
nums_str = (mb.group(1) or mb.group(2) or "").replace(",", ",")
nums = [x for x in re.split(r"\s*,\s*", nums_str) if x]
if len(nums) != 4:
out.append({"t": t, "bbox": None})
continue
try:
x1, y1, x2, y2 = map(float, nums)
except Exception:
out.append({"t": t, "bbox": None})
continue
ok = (0.0 <= x1 < x2 <= 1.0) and (0.0 <= y1 < y2 <= 1.0)
out.append({"t": t, "bbox": [x1, y1, x2, y2]} if ok else {"t": t, "bbox": None})
return out
# 从第二个元素开始,成对读取:"任务Xboxing序列:" + 下一段(括号体)
for i in range(1, len(parts), 2):
head = parts[i]
body = parts[i + 1] if i + 1 < len(parts) else ""
idx = _task_key_to_idx(head)
key = f"任务{idx}"
tasks_json[key] = parse_seq(body)
# 与 t_list 对齐(以采样顺序为准),缺失帧用 bbox=None 占位
def align(seq: List[Dict]) -> List[Dict]:
by_t = {e["t"]: e for e in seq}
aligned = []
for t in t_list:
e = by_t.get(t)
aligned.append(e if e else {"t": t, "bbox": None})
return aligned
tasks_json = {k: align(v) for k, v in tasks_json.items()}
return enhanced, tasks_json