CareerNexus 职联:岗位能力图谱构建与动态演化分析平台(挑战杯 XH-202621)

- 全链路:多源JD接入/清洗交叉验证/结构化抽取(星火+离线双通道)/时序知识图谱/新岗位发现/演化分析/人岗匹配/学习路径
- WebUI 五视图:驾驶舱/图谱工作台/岗位演化/匹配(单人+批量)/学习路径
- 设置中心(config.json)/Token鉴权/SQLite状态库/语义向量通道(BGE-M3本地或联网API)
- 71 个 pytest 用例;数据目录仅保留结构(.gitkeep),数据由 scripts/generate_dataset.py 复现
This commit is contained in:
RoyirinRosmontis
2026-08-03 13:15:35 +08:00
commit a10442d78c
78 changed files with 12860 additions and 0 deletions
+68
View File
@@ -0,0 +1,68 @@
"""端到端冒烟:生成数据(若缺失)→ 跑 pipeline → 打印图谱规模、演化事件数、一个匹配示例。
不需要启动服务,用于快速验证全链路可用。
"""
from __future__ import annotations
import json
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT))
from app.config import load_config, resolve # noqa: E402
from app.graph.tkg import TemporalKG # noqa: E402
from app.match.engine import MatchEngine # noqa: E402
from app.match.resume import parse_resume # noqa: E402
from app.models import ResumeProfile # noqa: E402
from app.services.pipeline import run_pipeline # noqa: E402
from app.extract.base import load_lexicon # noqa: E402
def main() -> None:
if not (ROOT / "data" / "jd_raw").exists():
print("数据不存在,先生成数据集……")
import subprocess
subprocess.run([sys.executable, str(ROOT / "scripts" / "generate_dataset.py")],
check=True)
print("=" * 56)
print("步骤 1/3:端到端 pipeline(导入→清洗→抽取→图谱→演化→发现)")
print("=" * 56)
stats = run_pipeline(load_config())
print(json.dumps(stats["stages"], ensure_ascii=False, indent=2))
print("\n步骤 2/3:图谱规模与演化事件")
kg = TemporalKG.load(resolve(load_config(), "graph_path"))
print("图谱统计:", kg.stats())
java_id = "job_Java开发工程师"
java_events = kg.events_of(java_id)
print(f"Java开发工程师 演化事件 {len(java_events)} 条,示例:")
for ev in java_events[:4]:
print(" -", ev.description)
snap_2020 = kg.snapshot(java_id, "2020-06-01")
snap_2025 = kg.snapshot(java_id, "2025-06-01")
print("2020 时点技能:", sorted(s["skill"] for s in snap_2020["skills"])[:8])
print("2025 时点技能:", sorted(s["skill"] for s in snap_2025["skills"])[:8])
print("\n步骤 3/3:人岗匹配示例(resume_full.txt vs Java开发工程师)")
text = (ROOT / "data" / "resumes" / "resume_full.txt").read_text(encoding="utf-8")
profile = parse_resume(text)
job = kg.jobs[java_id]
result = MatchEngine(load_lexicon()).match(profile, job)
print(f"脱敏后姓名: {profile.name} 手机: {profile.phone} 邮箱: {profile.email}")
print(f"总分 {result.total_score},维度 {result.dimension_scores},是否匹配 {result.is_match}")
print("缺失必备技能:", result.missing_required)
for stage in result.learning_path:
print(" ", stage["goal"])
# 断言冒烟通过的关键指标
assert kg.stats()["jobs"] >= 15, "岗位节点数量异常"
assert kg.stats()["events"] > 0, "未产生演化事件"
assert result.total_score >= 60, "完整简历应匹配 Java 岗位"
print("\n冒烟测试通过 [OK]")
if __name__ == "__main__":
main()