bidmaster-cli/tests/unit/test_toc_generation.py

144 lines
4.6 KiB
Python

from bidmaster.nodes.base import NodeContext
from bidmaster.nodes.toc import generate_sub_chapters as gen_module
from bidmaster.nodes.toc.generate_sub_chapters import GenerateSubChaptersNode
from bidmaster.nodes.toc.user_feedback import UserFeedbackNode
from bidmaster.tools.parser import DocumentChapter, ScoringCriteria, TechnicalCategory
from bidmaster.utils.document_context import DocumentContext, DocumentContextMatch
def test_generate_sub_chapters_uses_context(monkeypatch):
captured = {}
def fake_generate(criteria_list, parent_chapter, context_snippets=None, tech_consistency_prompt=None):
captured["context"] = context_snippets
captured["consistency"] = tech_consistency_prompt
return [{"title": "示例小节", "level": 2, "score": 5, "children": []}]
class DummySearcher:
def __init__(self, *args, **kwargs):
pass
def search(self, query, top_k=None):
return [
DocumentContextMatch(
text="系统采用云边协同架构,强调稳定性。",
section="项目概述",
score=0.95,
source_type="paragraph",
metadata={},
)
]
monkeypatch.setattr(gen_module, "DocumentContextSearcher", DummySearcher)
monkeypatch.setattr(gen_module.LLMHelper, "generate_sub_chapters_ai", staticmethod(fake_generate))
chapter = DocumentChapter(
id="chapter_01_technical_solution",
title="技术方案",
level=1,
score=30,
)
criteria = [
ScoringCriteria(
item_name="系统架构先进性",
max_score=10,
description="阐述云边端协同",
category=TechnicalCategory.TECHNICAL_SOLUTION,
chapter_id="chapter_01_technical_solution",
original_index=0,
)
]
state = {
"preliminary_chapters": [chapter],
"technical_criteria": criteria,
"document_context": DocumentContext("demo.docx", "test-model", []),
"tech_consistency_prompt": "统一术语:云边端协同/边缘节点/终端设备",
}
node = GenerateSubChaptersNode()
result = node.execute(state, NodeContext())
assert result["preliminary_chapters"][0].children
assert captured["context"] and "项目概述" in captured["context"][0]
assert "统一术语" in (captured["consistency"] or "")
def test_user_feedback_auto_triggers_optimization():
chapters = [
DocumentChapter(
id="chapter_01",
title="技术方案",
level=1,
score=30,
)
]
state = {
"final_chapters": chapters,
"structure_review": {
"suggestions": [
{"description": "补充智慧运维章节", "priority": "high", "type": "add"},
{"description": "可选优化", "priority": "low", "type": "modify"},
]
},
"auto_mode": True,
"auto_toc_max_rounds": 2,
"auto_optimization_rounds": 0,
}
node = UserFeedbackNode()
result = node.execute(state, NodeContext())
assert result["needs_optimization"] is True
assert "补充" in result["user_feedback"]
assert result["auto_optimization_rounds"] == 1
assert result["pending_suggestions"] == []
def test_user_feedback_auto_skips_when_no_priority():
chapters = [
DocumentChapter(
id="chapter_02",
title="实施计划",
level=1,
score=20,
)
]
state = {
"final_chapters": chapters,
"structure_review": {"suggestions": [{"description": "微调描述", "priority": "low", "type": "modify"}]},
"auto_mode": True,
"auto_toc_max_rounds": 1,
}
node = UserFeedbackNode()
result = node.execute(state, NodeContext())
assert result["needs_optimization"] is False
assert result["user_feedback"] == ""
def test_user_feedback_auto_respects_round_limit():
chapters = [
DocumentChapter(id="chapter_03", title="服务方案", level=1, score=10)
]
state = {
"final_chapters": chapters,
"structure_review": {
"suggestions": [{"description": "增加服务考核", "priority": "high", "type": "add"}]
},
"auto_mode": True,
"auto_toc_max_rounds": 1,
"auto_optimization_rounds": 1,
"pending_suggestions": [{"description": "增加服务考核", "priority": "high", "type": "add"}],
}
node = UserFeedbackNode()
result = node.execute(state, NodeContext())
assert result["needs_optimization"] is False
assert result["pending_suggestions"] == []