109 lines
3.7 KiB
Python
109 lines
3.7 KiB
Python
from __future__ import annotations
|
||
|
||
from dataclasses import dataclass
|
||
from datetime import datetime
|
||
from pathlib import Path
|
||
from uuid import uuid4
|
||
|
||
from docx import Document
|
||
|
||
|
||
@dataclass(frozen=True)
|
||
class AnalysisReport:
|
||
source_filename: str
|
||
provider_name: str
|
||
model_name: str
|
||
matched_skills: list[str]
|
||
summary: str
|
||
findings: list[dict[str, str]]
|
||
recommendations: list[str]
|
||
raw_model_output: str
|
||
|
||
|
||
def _safe_stem(filename: str) -> str:
|
||
stem = Path(filename).stem or "analysis"
|
||
safe = "".join(ch if ch.isalnum() or ch in ("-", "_") else "_" for ch in stem)
|
||
return safe[:60] or "analysis"
|
||
|
||
|
||
def _report_base_path(report: AnalysisReport, output_dir: Path, suffix: str) -> Path:
|
||
output_dir.mkdir(parents=True, exist_ok=True)
|
||
return output_dir / f"{_safe_stem(report.source_filename)}_{uuid4().hex[:8]}_analysis.{suffix}"
|
||
|
||
|
||
def generate_markdown_report(report: AnalysisReport, output_dir: Path | str) -> Path:
|
||
path = _report_base_path(report, Path(output_dir), "md")
|
||
lines = [
|
||
"# DOCX 规范分析报告",
|
||
"",
|
||
"## 基本信息",
|
||
"",
|
||
f"- 源文件:{report.source_filename}",
|
||
f"- 分析时间:{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}",
|
||
f"- 模型供应商:{report.provider_name}",
|
||
f"- 模型名称:{report.model_name}",
|
||
f"- 命中技能:{', '.join(report.matched_skills) or '无'}",
|
||
"",
|
||
"## 总体结论",
|
||
"",
|
||
report.summary,
|
||
"",
|
||
"## 技能符合性矩阵",
|
||
"",
|
||
"| 状态 | 检查项 | 证据或说明 |",
|
||
"| --- | --- | --- |",
|
||
]
|
||
for finding in report.findings:
|
||
lines.append(
|
||
f"| {finding.get('status', '')} | {finding.get('item', '')} | {finding.get('evidence', '').replace('|', '/')} |"
|
||
)
|
||
lines.extend(["", "## 修改建议", ""])
|
||
for item in report.recommendations:
|
||
lines.append(f"- {item}")
|
||
lines.extend(["", "## 模型分析原文", "", report.raw_model_output])
|
||
path.write_text("\n".join(lines), encoding="utf-8")
|
||
return path
|
||
|
||
|
||
def generate_docx_report(report: AnalysisReport, output_dir: Path | str) -> Path:
|
||
path = _report_base_path(report, Path(output_dir), "docx")
|
||
document = Document()
|
||
document.add_heading("DOCX 规范分析报告", level=0)
|
||
document.add_heading("基本信息", level=1)
|
||
for label, value in [
|
||
("源文件", report.source_filename),
|
||
("分析时间", datetime.now().strftime("%Y-%m-%d %H:%M:%S")),
|
||
("模型供应商", report.provider_name),
|
||
("模型名称", report.model_name),
|
||
("命中技能", ", ".join(report.matched_skills) or "无"),
|
||
]:
|
||
document.add_paragraph(f"{label}:{value}")
|
||
|
||
document.add_heading("总体结论", level=1)
|
||
document.add_paragraph(report.summary)
|
||
|
||
document.add_heading("技能符合性矩阵", level=1)
|
||
table = document.add_table(rows=1, cols=3)
|
||
table.style = "Table Grid"
|
||
headers = table.rows[0].cells
|
||
headers[0].text = "状态"
|
||
headers[1].text = "检查项"
|
||
headers[2].text = "证据或说明"
|
||
for finding in report.findings:
|
||
row = table.add_row().cells
|
||
row[0].text = finding.get("status", "")
|
||
row[1].text = finding.get("item", "")
|
||
row[2].text = finding.get("evidence", "")
|
||
|
||
document.add_heading("修改建议", level=1)
|
||
for item in report.recommendations:
|
||
document.add_paragraph(item, style="List Bullet")
|
||
|
||
document.add_heading("模型分析原文", level=1)
|
||
for line in report.raw_model_output.splitlines() or ["无"]:
|
||
document.add_paragraph(line)
|
||
|
||
document.add_paragraph("说明:模型分析结果需人工复核,不应直接作为正式审查结论。")
|
||
document.save(path)
|
||
return path
|