generated from kgod/ai-review-template
106 lines
4.2 KiB
Python
106 lines
4.2 KiB
Python
from __future__ import annotations
|
|
|
|
from typing import Any
|
|
|
|
from app.import_parser import ImportParseOutput, OpenAIResumeImportParser
|
|
from app.resume_import_service import RuleBasedResumeImportParser
|
|
|
|
|
|
class FakeCompletion:
|
|
def __init__(self, result: ImportParseOutput | Exception) -> None:
|
|
self.result = result
|
|
self.payload: dict[str, Any] | None = None
|
|
|
|
def complete(self, **kwargs: Any) -> ImportParseOutput:
|
|
self.payload = kwargs["payload"]
|
|
if isinstance(self.result, Exception):
|
|
raise self.result
|
|
return self.result
|
|
|
|
|
|
def test_llm_parser_redacts_sensitive_content_and_builds_reviewable_sections() -> None:
|
|
completion = FakeCompletion(
|
|
ImportParseOutput.model_validate(
|
|
{
|
|
"basics": {"name": "张三", "city": "广州"},
|
|
"target": {"job_type": "校招", "position": "后端开发工程师"},
|
|
"sections": [
|
|
{
|
|
"kind": "education",
|
|
"heading": "教育经历",
|
|
"items": [
|
|
{
|
|
"fields": {
|
|
"school": "示例大学",
|
|
"major": "软件工程",
|
|
"start_date": "2022-09",
|
|
"end_date_or_present": "2026-06",
|
|
},
|
|
"evidence": ["示例大学 软件工程 2022-09 至 2026-06"],
|
|
}
|
|
],
|
|
},
|
|
{
|
|
"kind": "project_experience",
|
|
"heading": "项目经历",
|
|
"items": [
|
|
{
|
|
"fields": {
|
|
"project_name": "简历助手",
|
|
"project_role": "后端开发",
|
|
"description": "使用 FastAPI 开发简历解析接口",
|
|
},
|
|
"evidence": ["简历助手 后端开发 使用 FastAPI 开发简历解析接口"],
|
|
}
|
|
],
|
|
},
|
|
],
|
|
"skill_groups": [
|
|
{
|
|
"category": "编程语言",
|
|
"skills": ["Python", "SQL"],
|
|
"evidence": ["Python SQL"],
|
|
}
|
|
],
|
|
}
|
|
)
|
|
)
|
|
parser = OpenAIResumeImportParser(completion=completion)
|
|
|
|
draft = parser.parse(
|
|
source_name="resume.docx",
|
|
text=(
|
|
"张三 13800138000 zhang@example.com 微信: zhangsan88\n"
|
|
"示例大学 软件工程 2022-09 至 2026-06\n"
|
|
"简历助手 后端开发 使用 FastAPI 开发简历解析接口\nPython SQL"
|
|
),
|
|
)
|
|
|
|
assert completion.payload is not None
|
|
sent = completion.payload["resume_text"]
|
|
assert "13800138000" not in sent
|
|
assert "zhang@example.com" not in sent
|
|
assert "zhangsan88" not in sent
|
|
assert draft.document["basics"] == {"name": "张三", "city": "广州"}
|
|
assert [section["heading"] for section in draft.document["sections"]] == [
|
|
"教育经历",
|
|
"项目经历",
|
|
]
|
|
assert draft.document["sections"][1]["items"][0]["project_name"] == "简历助手"
|
|
assert draft.document["skill_groups"] == [{"category": "编程语言", "skills": ["Python", "SQL"]}]
|
|
assert all(review.status == "needs_review" for review in draft.field_reviews)
|
|
assert any(review.field_path == "sections[1].items[0].project_name" for review in draft.field_reviews)
|
|
assert all(review.evidence for review in draft.field_reviews)
|
|
|
|
|
|
def test_llm_parser_falls_back_to_rule_parser_when_model_is_unavailable() -> None:
|
|
parser = OpenAIResumeImportParser(
|
|
completion=FakeCompletion(RuntimeError("model gateway unavailable")),
|
|
fallback=RuleBasedResumeImportParser(),
|
|
)
|
|
|
|
draft = parser.parse(source_name="resume.docx", text="这是导入的简历正文")
|
|
|
|
assert draft.document["sections"][0]["heading"] == "导入内容"
|
|
assert draft.field_reviews[0].status == "needs_review"
|