From b532ffc3b95d19f38149199efebab85da30be43d Mon Sep 17 00:00:00 2001 From: wren <“porlong@qq.com”> Date: Wed, 13 May 2026 15:25:13 +0800 Subject: [PATCH] =?UTF-8?q?feat(govdoc):=20=E8=A1=A5=20structure/outline?= =?UTF-8?q?=20API=20=E7=AB=AF=E7=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controllers/govdocController.py | 18 +++++++++++ .../govdoc_bridge/result_adapter.py | 31 +++++++++++++++++++ .../fastapi_leaudit/govdoc_bridge/runner.py | 4 +++ .../fastapi_leaudit/services/govdocService.py | 10 ++++++ .../services/impl/govdocServiceImpl.py | 8 +++++ 5 files changed, 71 insertions(+) diff --git a/fastapi_modules/fastapi_leaudit/controllers/govdocController.py b/fastapi_modules/fastapi_leaudit/controllers/govdocController.py index ccd9ddb..31e1efe 100644 --- a/fastapi_modules/fastapi_leaudit/controllers/govdocController.py +++ b/fastapi_modules/fastapi_leaudit/controllers/govdocController.py @@ -181,6 +181,24 @@ class GovdocController(BaseController): result = await self.GovdocService.GetRunEntities(runId=runId) return Result.success(data=result) + @self.router.get("/runs/{runId}/structure") + async def GetRunStructure( + runId: int, + payload: dict[str, Any] = Depends(verify_access_token), + ): + """获取文档结构统计(结构面板数据)。""" + result = await self.GovdocService.GetRunStructure(runId=runId) + return Result.success(data=result) + + @self.router.get("/runs/{runId}/outline") + async def GetRunOutline( + runId: int, + payload: dict[str, Any] = Depends(verify_access_token), + ): + """获取文档大纲树(大纲面板数据)。""" + result = await self.GovdocService.GetRunOutline(runId=runId) + return Result.success(data=result) + @self.router.get("/runs/{runId}/paragraphs") async def GetRunParagraphs( runId: int, diff --git a/fastapi_modules/fastapi_leaudit/govdoc_bridge/result_adapter.py b/fastapi_modules/fastapi_leaudit/govdoc_bridge/result_adapter.py index 2ae6d13..3c89d36 100644 --- a/fastapi_modules/fastapi_leaudit/govdoc_bridge/result_adapter.py +++ b/fastapi_modules/fastapi_leaudit/govdoc_bridge/result_adapter.py @@ -86,6 +86,37 @@ class ResultAdapter: }) return entities + def AdaptStructure(self, EngineResult: AuditResult) -> list[dict[str, Any]]: + """从 AuditResult.structure 提取文档结构统计。""" + results: list[dict[str, Any]] = [] + for s in EngineResult.structure: + results.append({ + "role": s.role, + "label": s.label, + "count": s.count, + "expected": s.expected, + "paragraphIndices": s.paragraph_indices, + "samples": s.samples, + "charTotal": s.char_total, + "dominantFont": s.dominant_font, + "dominantSizePt": s.dominant_size_pt, + "styleUniform": s.style_uniform, + }) + return results + + def AdaptOutline(self, EngineResult: AuditResult) -> list[dict[str, Any]]: + """从 AuditResult.outline 提取大纲树(递归)。""" + + def _node(n) -> dict[str, Any]: + return { + "paragraphIndex": n.paragraph_index, + "level": n.level, + "text": n.text, + "children": [_node(c) for c in (n.children or [])], + } + + return [_node(n) for n in EngineResult.outline] + def AdaptArtifacts(self, _EngineResult: AuditResult, _RunId: int) -> list[dict[str, Any]]: """从引擎结果提取报告产物清单。 diff --git a/fastapi_modules/fastapi_leaudit/govdoc_bridge/runner.py b/fastapi_modules/fastapi_leaudit/govdoc_bridge/runner.py index c47d60b..55c8e77 100644 --- a/fastapi_modules/fastapi_leaudit/govdoc_bridge/runner.py +++ b/fastapi_modules/fastapi_leaudit/govdoc_bridge/runner.py @@ -77,6 +77,8 @@ class GovdocRunner: runSummary = self.ResultAdapter.AdaptRunSummary(engineResult) ruleResults = self.ResultAdapter.AdaptRuleResults(engineResult) entities = self.ResultAdapter.AdaptEntities(engineResult) + structure = self.ResultAdapter.AdaptStructure(engineResult) + outline = self.ResultAdapter.AdaptOutline(engineResult) artifacts = self.ResultAdapter.AdaptArtifacts(engineResult, RunId) # 5. 持久化结果 @@ -95,5 +97,7 @@ class GovdocRunner: "documentId": DocumentId, "status": "completed", "ruleResultsCount": len(ruleResults), + "structureCount": len(structure), + "outlineCount": len(outline), "artifactCount": len(artifacts), } diff --git a/fastapi_modules/fastapi_leaudit/services/govdocService.py b/fastapi_modules/fastapi_leaudit/services/govdocService.py index 61419dd..20ba9aa 100644 --- a/fastapi_modules/fastapi_leaudit/services/govdocService.py +++ b/fastapi_modules/fastapi_leaudit/services/govdocService.py @@ -98,6 +98,16 @@ class IGovdocService(ABC): """获取前端文档联动视图所需的段落 HTML。""" ... + @abstractmethod + async def GetRunStructure(self, runId: int) -> dict[str, Any]: + """获取文档结构统计(结构面板数据)。""" + ... + + @abstractmethod + async def GetRunOutline(self, runId: int) -> dict[str, Any]: + """获取文档大纲树(大纲面板数据)。""" + ... + @abstractmethod async def GetReportHtml(self, runId: int) -> dict[str, Any]: """获取 HTML 报告内容或下载地址。""" diff --git a/fastapi_modules/fastapi_leaudit/services/impl/govdocServiceImpl.py b/fastapi_modules/fastapi_leaudit/services/impl/govdocServiceImpl.py index 04aa60c..e7997c4 100644 --- a/fastapi_modules/fastapi_leaudit/services/impl/govdocServiceImpl.py +++ b/fastapi_modules/fastapi_leaudit/services/impl/govdocServiceImpl.py @@ -111,6 +111,14 @@ class GovdocServiceImpl(IGovdocService): logger.info("[Govdoc] GetRunParagraphs placeholder — runId=%s", runId) return {"runId": runId, "paragraphs": []} + async def GetRunStructure(self, runId: int) -> dict[str, Any]: + logger.info("[Govdoc] GetRunStructure placeholder — runId=%s", runId) + return {"runId": runId, "structure": []} + + async def GetRunOutline(self, runId: int) -> dict[str, Any]: + logger.info("[Govdoc] GetRunOutline placeholder — runId=%s", runId) + return {"runId": runId, "outline": []} + async def GetReportHtml(self, runId: int) -> dict[str, Any]: logger.info("[Govdoc] GetReportHtml placeholder — runId=%s", runId) return {"runId": runId, "htmlUrl": ""}