fix: 缺省匹配年度收敛最新年度 + 批量坏文件跳过 + 匹配理由据实化 + 职称档位补全(P1+P2)
This commit is contained in:
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user