Files
RoyirinRosmontis a10442d78c CareerNexus 职联:岗位能力图谱构建与动态演化分析平台(挑战杯 XH-202621)
- 全链路:多源JD接入/清洗交叉验证/结构化抽取(星火+离线双通道)/时序知识图谱/新岗位发现/演化分析/人岗匹配/学习路径
- WebUI 五视图:驾驶舱/图谱工作台/岗位演化/匹配(单人+批量)/学习路径
- 设置中心(config.json)/Token鉴权/SQLite状态库/语义向量通道(BGE-M3本地或联网API)
- 71 个 pytest 用例;数据目录仅保留结构(.gitkeep),数据由 scripts/generate_dataset.py 复现
2026-08-03 13:15:35 +08:00

140 lines
5.0 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""CareerNexus 全链路数据模型(pydantic v2)。
覆盖:JD 原始记录、结构化抽取结果、岗位定义、图谱观察、
变更事件、人岗匹配结果、简历画像与人机协同审核记录。
"""
from __future__ import annotations
from datetime import date
from typing import Literal, Optional
from pydantic import BaseModel, Field
class JDRecord(BaseModel):
"""一条招聘 JD 原始记录。source_id 由接入层分配(文件名#行号),不可变。"""
jid: str
job_title: str
company: str
city: str = ""
salary: str = ""
industry: str = "" # 招聘平台标注的所属行业
publish_date: date
source: str = ""
url: str = ""
text: str
source_id: str = "" # 形如 batch_2023.jsonl#17
weight: float = 1.0 # 清洗阶段赋予的时间衰减权重
is_duplicate: bool = False # 近重复(抄袭)降权标记
dup_of: Optional[str] = None # 指向被保留的最早来源 jid
is_noise: bool = False # 噪声(广告/无关条款)标记
class ExtractionResult(BaseModel):
"""从单条 JD 文本抽取出的结构化岗位定义。"""
jid: str = ""
job_title: str = ""
responsibilities: list[str] = Field(default_factory=list)
required_skills: list[str] = Field(default_factory=list)
preferred_skills: list[str] = Field(default_factory=list)
scenarios: list[str] = Field(default_factory=list)
evidence: dict[str, str] = Field(default_factory=dict) # 字段 -> 证据片段
confidence: float = 0.0
extractor: str = "offline"
prompt_version: str = "offline-v1"
class JobDefinition(BaseModel):
"""聚合后的岗位定义(图谱中的 Job 节点属性)。"""
job_id: str
title: str
category: str = ""
industries: list[str] = Field(default_factory=list) # 归属行业(1-2 个)
required_skills: list[str] = Field(default_factory=list)
preferred_skills: list[str] = Field(default_factory=list)
responsibilities: list[str] = Field(default_factory=list)
scenarios: list[str] = Field(default_factory=list)
expected_years: int = 3
status: Literal["active", "pending", "rejected"] = "active"
source_count: int = 0 # 支撑 JD 数
company_count: int = 0 # 独立企业数
# 候选新岗位的支撑证据(新岗位发现时填写):支撑 JD 的 source_id 与出现季度窗口,
# 审核入库时用于生成真实的 REQUIRES 区间、来源列表与演化事件。
support_source_ids: list[str] = Field(default_factory=list)
support_windows: list[str] = Field(default_factory=list)
class GraphObservation(BaseModel):
"""一次岗位-技能关系观察(带时间窗,追加而不覆盖)。"""
job_id: str
skill: str
importance: Literal["required", "preferred"]
weight: float = 1.0
window: str = "" # 季度窗口,如 2022Q1
source_ids: list[str] = Field(default_factory=list)
class ChangeEvent(BaseModel):
"""岗位能力演化事件:新增 / 增强 / 减弱 / 退出。"""
event_id: str
job_id: str
skill: str
change_type: Literal["新增", "增强", "减弱", "退出"]
window: str
prev_weight: float = 0.0
curr_weight: float = 0.0
source_ids: list[str] = Field(default_factory=list)
description: str = ""
created_at: str = ""
class ResumeProfile(BaseModel):
"""脱敏后的简历画像。"""
name: str = ""
phone: str = ""
email: str = ""
years: float = 0.0
skills: list[str] = Field(default_factory=list)
scenarios: list[str] = Field(default_factory=list)
raw_masked_text: str = ""
# 结构化信息(规范简历模板用)
gender: str = "" # 性别(不脱敏,人口统计学字段)
education: str = "" # 最高学历(本科/硕士/博士…)
address: str = "" # 家庭住址/现居地(脱敏到城市)
photo_b64: str = "" # 证件照 base64(data URI,无照片为空)
sections: list[dict] = Field(default_factory=list) # [{title, text}] 分节正文
class MatchResult(BaseModel):
"""人岗匹配结果:总分、四维分、命中/缺失/可迁移技能与学习路径。"""
job_id: str
job_title: str = ""
total_score: float = 0.0
dimension_scores: dict[str, float] = Field(default_factory=dict)
matched_required: list[str] = Field(default_factory=list)
missing_required: list[str] = Field(default_factory=list)
matched_preferred: list[str] = Field(default_factory=list)
missing_preferred: list[str] = Field(default_factory=list)
transferable_skills: list[str] = Field(default_factory=list)
learning_path: list[dict] = Field(default_factory=list)
is_match: bool = False
class ReviewRecord(BaseModel):
"""人机协同审核留痕。"""
candidate_id: str
action: Literal["accept", "modify", "reject"]
operator: str
reason: str = ""
before: dict = Field(default_factory=dict)
after: dict = Field(default_factory=dict)
time: str = ""