135 lines
4.9 KiB
Python
135 lines
4.9 KiB
Python
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
import io
|
||
|
|
import json
|
||
|
|
from typing import Any, Dict, Iterable, List
|
||
|
|
|
||
|
|
|
||
|
|
def normalize_result_dicts(results: Iterable[Any]) -> List[Dict[str, Any]]:
|
||
|
|
normalized: List[Dict[str, Any]] = []
|
||
|
|
for item in results:
|
||
|
|
if hasattr(item, "to_dict"):
|
||
|
|
normalized.append(item.to_dict())
|
||
|
|
elif isinstance(item, dict):
|
||
|
|
normalized.append(item)
|
||
|
|
else:
|
||
|
|
normalized.append(
|
||
|
|
{
|
||
|
|
"requirement_uid": getattr(item, "requirement_uid", ""),
|
||
|
|
"verdict": getattr(item, "verdict", ""),
|
||
|
|
"coverage_score": getattr(item, "coverage_score", 0.0),
|
||
|
|
"confidence": getattr(item, "confidence", 0.0),
|
||
|
|
"matched_functions": getattr(item, "matched_functions", []),
|
||
|
|
"covered_points": getattr(item, "covered_points", []),
|
||
|
|
"missing_points": getattr(item, "missing_points", []),
|
||
|
|
"conflict_points": getattr(item, "conflict_points", []),
|
||
|
|
"call_chain_evidence": getattr(item, "call_chain_evidence", []),
|
||
|
|
"suggestion": getattr(item, "suggestion", ""),
|
||
|
|
"raw_judgment": getattr(item, "raw_judgment", {}),
|
||
|
|
}
|
||
|
|
)
|
||
|
|
return normalized
|
||
|
|
|
||
|
|
|
||
|
|
def export_json(results: Iterable[Any]) -> bytes:
|
||
|
|
return json.dumps(
|
||
|
|
{"results": normalize_result_dicts(results)},
|
||
|
|
ensure_ascii=False,
|
||
|
|
indent=2,
|
||
|
|
).encode("utf-8")
|
||
|
|
|
||
|
|
|
||
|
|
def export_markdown(results: Iterable[Any]) -> str:
|
||
|
|
rows = normalize_result_dicts(results)
|
||
|
|
lines = [
|
||
|
|
"# 需求代码一致性比对报告",
|
||
|
|
"",
|
||
|
|
"| 需求 ID | 判定 | 覆盖分 | 置信度 | 匹配函数 | 缺失点 | 建议 |",
|
||
|
|
"| --- | --- | ---: | ---: | ---: | ---: | --- |",
|
||
|
|
]
|
||
|
|
for item in rows:
|
||
|
|
lines.append(
|
||
|
|
"| {uid} | {verdict} | {score:.2f} | {confidence:.2f} | {functions} | {missing} | {suggestion} |".format(
|
||
|
|
uid=item.get("requirement_uid", ""),
|
||
|
|
verdict=item.get("verdict", ""),
|
||
|
|
score=float(item.get("coverage_score") or 0),
|
||
|
|
confidence=float(item.get("confidence") or 0),
|
||
|
|
functions=len(item.get("matched_functions") or []),
|
||
|
|
missing=len(item.get("missing_points") or []),
|
||
|
|
suggestion=str(item.get("suggestion") or "").replace("|", "/"),
|
||
|
|
)
|
||
|
|
)
|
||
|
|
|
||
|
|
for item in rows:
|
||
|
|
lines.extend(
|
||
|
|
[
|
||
|
|
"",
|
||
|
|
f"## {item.get('requirement_uid', '')} {item.get('requirement_title', '')}",
|
||
|
|
"",
|
||
|
|
f"- 判定: `{item.get('verdict', '')}`",
|
||
|
|
f"- 覆盖分: {float(item.get('coverage_score') or 0):.2f}",
|
||
|
|
f"- 置信度: {float(item.get('confidence') or 0):.2f}",
|
||
|
|
f"- 建议: {item.get('suggestion') or '-'}",
|
||
|
|
"",
|
||
|
|
"### 匹配函数",
|
||
|
|
]
|
||
|
|
)
|
||
|
|
for function in item.get("matched_functions") or []:
|
||
|
|
lines.append(
|
||
|
|
f"- `{function.get('name')}` {function.get('file')}:{function.get('start_line')} "
|
||
|
|
f"(similarity={float(function.get('similarity') or 0):.2f})"
|
||
|
|
)
|
||
|
|
lines.extend(["", "### 缺失点"])
|
||
|
|
for point in item.get("missing_points") or ["-"]:
|
||
|
|
lines.append(f"- {point}")
|
||
|
|
if item.get("conflict_points"):
|
||
|
|
lines.extend(["", "### 冲突点"])
|
||
|
|
for point in item.get("conflict_points") or []:
|
||
|
|
lines.append(f"- {point}")
|
||
|
|
return "\n".join(lines)
|
||
|
|
|
||
|
|
|
||
|
|
def export_excel(results: Iterable[Any]) -> bytes:
|
||
|
|
try:
|
||
|
|
from openpyxl import Workbook
|
||
|
|
except ImportError as exc:
|
||
|
|
raise RuntimeError("openpyxl is required to export Excel reports.") from exc
|
||
|
|
|
||
|
|
rows = normalize_result_dicts(results)
|
||
|
|
workbook = Workbook()
|
||
|
|
sheet = workbook.active
|
||
|
|
sheet.title = "Consistency"
|
||
|
|
headers = [
|
||
|
|
"需求ID",
|
||
|
|
"需求标题",
|
||
|
|
"需求类型",
|
||
|
|
"判定",
|
||
|
|
"覆盖分",
|
||
|
|
"置信度",
|
||
|
|
"匹配函数数量",
|
||
|
|
"主要文件",
|
||
|
|
"缺失点数量",
|
||
|
|
"建议",
|
||
|
|
]
|
||
|
|
sheet.append(headers)
|
||
|
|
for item in rows:
|
||
|
|
functions = item.get("matched_functions") or []
|
||
|
|
sheet.append(
|
||
|
|
[
|
||
|
|
item.get("requirement_uid", ""),
|
||
|
|
item.get("requirement_title", ""),
|
||
|
|
item.get("requirement_type", ""),
|
||
|
|
item.get("verdict", ""),
|
||
|
|
item.get("coverage_score", 0),
|
||
|
|
item.get("confidence", 0),
|
||
|
|
len(functions),
|
||
|
|
functions[0].get("file", "") if functions else "",
|
||
|
|
len(item.get("missing_points") or []),
|
||
|
|
item.get("suggestion", ""),
|
||
|
|
]
|
||
|
|
)
|
||
|
|
output = io.BytesIO()
|
||
|
|
workbook.save(output)
|
||
|
|
return output.getvalue()
|
||
|
|
|