from app.analyzer import LLMClient, build_analysis_prompt, select_relevant_skills from app.config import ProviderConfig from app.docx_parser import ParsedDocument from app.skill_loader import Skill class DummyResponse: def raise_for_status(self) -> None: return None def json(self) -> dict: return {"choices": [{"message": {"content": "分析结果"}}]} class DummySession: def __init__(self) -> None: self.calls = [] def post(self, url: str, **kwargs): self.calls.append((url, kwargs)) return DummyResponse() def test_select_relevant_skills_prefers_matching_text() -> None: parsed = ParsedDocument( filename="srs.docx", text="软件需求规格说明 CSCI 能力需求 接口需求 合格性规定", paragraphs=[], headings=[], tables=[], ) skills = [ Skill("requirements", "软件需求规格说明", "需求文档", "编写软件需求", "需求能力接口", None), Skill("deployment", "部署准备", "部署文档", "软件部署交付", "安装部署", None), ] selected = select_relevant_skills(parsed, skills, max_skills=1) assert [skill.slug for skill in selected] == ["requirements"] def test_llm_client_posts_openai_compatible_payload() -> None: provider = ProviderConfig( api_key="secret", base_url="https://api.deepseek.com/v1/chat/completions", max_tokens=99, model="deepseek-chat", temperature=0.1, ) session = DummySession() client = LLMClient(provider, session=session) content = client.complete("检查文档") assert content == "分析结果" url, kwargs = session.calls[0] assert url == "https://api.deepseek.com/v1/chat/completions" assert kwargs["headers"]["Authorization"] == "Bearer secret" assert kwargs["json"]["model"] == "deepseek-chat" assert kwargs["json"]["messages"][0]["content"] == "检查文档" def test_build_analysis_prompt_contains_document_and_skill() -> None: parsed = ParsedDocument("a.docx", "正文", [], [], []) skill = Skill("s1", "技能一", "描述", "使用条件", "规范内容", None) prompt = build_analysis_prompt(parsed, [skill]) assert "a.docx" in prompt assert "技能一" in prompt assert "符合项" in prompt