fix: 缺省匹配年度收敛最新年度 + 批量坏文件跳过 + 匹配理由据实化 + 职称档位补全(P1+P2)

This commit is contained in:
chenfuqiang
2026-09-26 21:09:40 +08:00
parent e219b055b2
commit 643dae0ec4
4 changed files with 168 additions and 27 deletions

View File

@@ -28,19 +28,28 @@ TIER_NOT = "不建议"
_TIER_RANK = {TIER_NOT: 0, TIER_TRY: 1, TIER_STRONG: 2}
# 职称档位:数值越大越高职称;门槛 min_title 使用"X及以上"档位
# 职称档位:数值越大越高职称;门槛 min_title 使用"X及以上"档位。
# 助理教授按中级档从审处理(预聘制档次各校不一,宁缺勿滥);
# 未识别职称遇门槛赛道一律剔除并说明原因(审慎非激进)。
_TITLE_RANK = {
"助教": 0,
"初级": 0,
"讲师": 1,
"中级": 1,
"助理研究员": 1,
"助理教授": 1,
"工程师": 1,
"博士后": 1,
"副高及以上": 2,
"副教授": 2,
"副研究员": 2,
"高级实验师": 2,
"高级工程师": 2,
"正高及以上": 3,
"教授": 3,
"研究员": 3,
"教授级高级工程师": 3,
"正高级工程师": 3,
}
_STRONG_THRESHOLD = 80
@@ -197,7 +206,7 @@ def match_teacher(teacher: dict[str, Any], tracks: list[dict[str, Any]], season:
if min_sci > 0:
reasons.append(f"SCI一区余量:现有 {sci_q1} 篇 / 要求 {min_sci} 篇")
if not reasons:
reasons.append("与赛道方向存在部分相关性")
reasons.append("现有研究标签与该赛道需求标签暂无重合,补充研究标签后可能改善匹配")
if match_pct >= _STRONG_THRESHOLD:
tier = TIER_STRONG
@@ -346,14 +355,17 @@ def run_match(
def load_tracks(year: Optional[int] = None) -> list[dict[str, Any]]:
"""读取赛道库(缺省全部年度;可按年度筛选)。"""
"""读取赛道库(缺省取赛道库最新年度,与 actions.json 契约一致;显式传 year 按年度筛选)。"""
conn = get_conn()
try:
cur = conn.cursor()
if year:
cur.execute("SELECT * FROM guide_tracks WHERE year = ? ORDER BY id", (year,))
else:
cur.execute("SELECT * FROM guide_tracks ORDER BY year DESC, id")
if year is None:
cur.execute("SELECT MAX(year) FROM guide_tracks")
row = cur.fetchone()
if not row or row[0] is None:
return []
year = int(row[0])
cur.execute("SELECT * FROM guide_tracks WHERE year = ? ORDER BY id", (year,))
columns = [d[0] for d in cur.description]
rows = [dict(zip(columns, row)) for row in cur.fetchall()]
finally:
@@ -361,6 +373,35 @@ def load_tracks(year: Optional[int] = None) -> list[dict[str, Any]]:
return rows
def collect_input_teachers(input_dir: str) -> tuple[list[dict[str, Any]], list[dict[str, str]]]:
"""读取 input/ 目录下的教师画像 JSON;坏文件跳过并记录原因,不中断整批。
返回 (教师列表, 跳过文件列表);跳过文件形如 {"file": 名称, "reason": 原因}。
"""
import os
files = sorted(
os.path.join(input_dir, name)
for name in os.listdir(input_dir)
if name.lower().endswith(".json")
)
teachers: list[dict[str, Any]] = []
skipped_files: list[dict[str, str]] = []
for path in files:
name = os.path.basename(path)
try:
with open(path, encoding="utf-8") as f:
payload = json.load(f)
if isinstance(payload, dict):
payload = payload.get("teachers") or [payload]
if not isinstance(payload, list):
raise ValueError("内容不是教师对象数组")
teachers.extend(item for item in payload if isinstance(item, dict))
except (OSError, ValueError) as exc:
skipped_files.append({"file": name, "reason": str(exc)})
return teachers, skipped_files
def load_teachers(teacher_name: str = "") -> list[dict[str, Any]]:
"""读取教师画像(可按姓名精确筛选)。"""
conn = get_conn()