From 92a9077f3c3cb73f4966efea95250dc311d1e68c Mon Sep 17 00:00:00 2001 From: kuangji <819823900@qq.com> Date: Tue, 26 May 2026 17:16:30 +0800 Subject: [PATCH] integrate question table generate function --- app/main.py | 11 ++++++++- app/static/app.js | 2 ++ app/templates/index.html | 2 +- handoff-2026-05-26-17-14-49-integrate-0005.md | 23 +++++++++++++++++++ tests/test_web.py | 10 +++++++- 5 files changed, 45 insertions(+), 3 deletions(-) create mode 100644 handoff-2026-05-26-17-14-49-integrate-0005.md diff --git a/app/main.py b/app/main.py index dfaadaa..73876d4 100644 --- a/app/main.py +++ b/app/main.py @@ -24,6 +24,7 @@ from app.analyzer import ( from app.config import load_api_config from app.docx_parser import parse_docx from app.report_generator import generate_docx_report, generate_markdown_report +from app.review_filler import fill_review_docx_from_analysis from app.skill_loader import load_skill_catalog @@ -33,6 +34,7 @@ OUTPUT_DIR = ROOT_DIR / "outputs" SKILL_ROOT = ROOT_DIR / "skills" DEFAULT_SKILL_COLLECTION = "GJB438C-2021_prd_skills" CONFIG_PATH = ROOT_DIR / "configs" / "api_config.yaml" +REVIEW_DOCX_TEMPLATE = ROOT_DIR / "test" / "附录A文档审查.docx" MAX_UPLOAD_BYTES = 30 * 1024 * 1024 MAX_SKILL_ARCHIVE_BYTES = 50 * 1024 * 1024 ProgressCallback = Callable[[int, str], None] @@ -263,14 +265,21 @@ def analyze_saved_docx( progress(85, "正在生成 Markdown 分析文档") markdown_path = generate_markdown_report(report, OUTPUT_DIR) + progress(92, "正在生成 DOCX 文档审查单") + review_docx_path = markdown_path.with_name(f"{markdown_path.stem}_review.docx") + fill_review_docx_from_analysis(markdown_path, REVIEW_DOCX_TEMPLATE, review_docx_path) progress(100, "分析完成") return { "source_filename": parsed.filename, "summary": report.summary, "matched_skills": report.matched_skills, - "downloads": {"markdown": f"/download/{markdown_path.name}"}, + "downloads": { + "markdown": f"/download/{markdown_path.name}", + "review_docx": f"/download/{review_docx_path.name}", + }, "markdown_filename": markdown_path.name, + "review_docx_filename": review_docx_path.name, } diff --git a/app/static/app.js b/app/static/app.js index 9df48d4..3a0ca07 100644 --- a/app/static/app.js +++ b/app/static/app.js @@ -5,6 +5,7 @@ const skillUploadStatus = document.querySelector("#skill-upload-status"); const result = document.querySelector("#result"); const summary = document.querySelector("#summary"); const skills = document.querySelector("#skills"); +const reviewDocxLink = document.querySelector("#download-review-docx"); const mdLink = document.querySelector("#download-md"); const progressBar = document.querySelector("#analysis-progress"); const statusText = document.querySelector("#analysis-status"); @@ -120,6 +121,7 @@ form.addEventListener("submit", async (event) => { item.textContent = name; skills.appendChild(item); }); + reviewDocxLink.href = task.downloads.review_docx; mdLink.href = task.downloads.markdown; } catch (error) { summary.textContent = error.message; diff --git a/app/templates/index.html b/app/templates/index.html index f4ff721..79d1e72 100644 --- a/app/templates/index.html +++ b/app/templates/index.html @@ -97,7 +97,7 @@
diff --git a/handoff-2026-05-26-17-14-49-integrate-0005.md b/handoff-2026-05-26-17-14-49-integrate-0005.md new file mode 100644 index 0000000..7a7fa4d --- /dev/null +++ b/handoff-2026-05-26-17-14-49-integrate-0005.md @@ -0,0 +1,23 @@ +# Handoff - 2026-05-26 + +## Completed Tasks +- 昨天完成了独立模块 `app/review_filler.py` 向 FastAPI 主流程的集成:在 Markdown 分析报告生成后,自动调用审查单填充逻辑,生成已勾选的 DOCX 文档审查单。 +- 新增审查单模板路径 `REVIEW_DOCX_TEMPLATE`,当前沿用 `test/附录A文档审查.docx`,生成结果写入现有 `outputs/` 目录,并通过 `/download/{filename}` 下载。 +- 扩展分析任务返回值,在原有 `markdown` 下载项之外新增 `review_docx` 下载项,同时保留 `markdown_filename` 并新增 `review_docx_filename`。 +- 更新系统 UI,在分析结果区域新增“下载 DOCX 审查单”按钮,并在前端轮询任务完成后绑定 `task.downloads.review_docx`。 +- 补充 Web 集成测试,验证页面包含新下载入口、分析流程生成 DOCX 审查单,并校验 A.2、A.3、A.4 审查表每个序号行均满足三选一互斥勾选。 +- 完成验证:`pytest tests/test_web.py tests/test_review_filler.py` 通过,`pytest` 全量测试通过,结果为 `24 passed`,`git diff --check` 通过。 +- 启动本地服务并用真实 `/analyze` 上传流程做了运行验证,确认任务完成后返回 Markdown 和 DOCX 审查单两个下载项。 + +## Blockers +- 当前审查单模板仍位于 `test/附录A文档审查.docx`,可运行但不够产品化;后续建议迁移到专门的模板或资源目录。 +- `app/review_filler.py` 的判定仍依赖 Markdown 自然语言报告和关键词规则,准确性受模型输出格式影响,自动勾选结果仍需要人工复核。 +- 本地启发式分析模式下没有结构化“符合项/不符合项”证据段,审查单可生成并通过互斥校验,但判定质量偏保守。 +- 默认会填写 A.2、A.3、A.4 全部审查单;如果上传文档只对应单一文档类型,后续可能需要在 Web 流程中提供目标审查表选择。 + +## Next Steps +- 明天计划将审查单模板从 `test/` 迁移到正式资源目录,例如 `resources/templates/` 或 `app/templates/docx/`,并更新常量和测试。 +- 优化模型分析输出格式,增加结构化审查证据或审查项结果,降低 `review_filler` 对自然语言关键词匹配的依赖。 +- 在 UI 中评估是否增加“目标审查表”选择项,支持只生成 A.2、A.3 或 A.4 的审查单填写结果。 +- 增加端到端测试,覆盖 `/analyze` 提交、任务轮询、Markdown 下载和 DOCX 审查单下载的完整 HTTP 流程。 +- 继续抽查真实样本文档生成的审查单,重点确认“未通过”和“不适用”判定是否符合人工审查预期。 diff --git a/tests/test_web.py b/tests/test_web.py index 58fe74d..1e56cd8 100644 --- a/tests/test_web.py +++ b/tests/test_web.py @@ -6,6 +6,7 @@ from docx import Document import app.main as main from app.main import OUTPUT_DIR, ROOT_DIR, analyze_saved_docx, app +from app.review_filler import validate_review_results class FakeUploadFile: @@ -44,7 +45,9 @@ def test_index_template_contains_upload_ui() -> None: assert "analysis-progress" in html assert "analysis-status" in html assert "下载 Markdown 报告" in html + assert "下载 DOCX 审查单" in html assert "download-md" in js + assert "download-review-docx" in js assert "pollTask" in js assert "skill_collection" in html assert "skill-upload-form" in html @@ -150,9 +153,14 @@ def test_analyze_saved_docx_creates_downloadable_report(tmp_path: Path) -> None: payload = analyze_saved_docx(docx_path, provider="deepseek", use_model=False) assert payload["source_filename"] == "upload.docx" - assert "docx" not in payload["downloads"] assert payload["downloads"]["markdown"].endswith(".md") + assert payload["downloads"]["review_docx"].endswith(".docx") assert (OUTPUT_DIR / Path(payload["downloads"]["markdown"]).name).exists() + review_docx_path = OUTPUT_DIR / Path(payload["downloads"]["review_docx"]).name + assert review_docx_path.exists() + assert validate_review_results(review_docx_path, "A.2") == [] + assert validate_review_results(review_docx_path, "A.3") == [] + assert validate_review_results(review_docx_path, "A.4") == [] def test_analyze_saved_docx_uses_selected_collection(tmp_path: Path) -> None: