装闭 RenoPit 源码解析(12):从AI分析结果到React避坑报告

1785882947310

设计分析、合同审查、增项预测和跨文档核查分别产生不同结构的数据,报告页却需要一次性展示它们。装闭 RenoPit 在开源仓库 fthux/RenoPit 中通过 /result 接口先统一后端数据,再由 React 按结果内容组合页面。

项目报告-总体评价

一、报告页只请求一个聚合接口

AnalysisPage.tsx 从路由参数取得项目 ID,调用:

const res = await fetch(`${API}/projects/${projectId}/result`)
if (res.ok) setResult(await res.json())

页面不直接查询 AnalysisDocumentAnalysis 或交叉核查接口。数据拼装集中在后端,前端只消费 AnalysisResult

get_analysis_result() 先确认项目存在,再按 Analysis.created_at 倒序获取最近一条分析。失败分析也会返回固定结构:评分和各级问题数量为零,summary_texterror_message 保存失败原因,使前端仍能进入统一的状态判断。

二、原始 AI JSON 如何变成 pitfalls

成功记录交给 _build_result_data()。它从 raw_result_json.problems 读取模型问题,再逐条转换成前端的 PitfallItem

pitfalls.append({
    "id": str(i + 1),
    "category": _infer_category(problem),
    "description": problem.get("title", ""),
    "severity": _infer_severity(problem),
    "location": problem.get("location"),
    "suggestion": problem.get("alternative", ""),
    "critique": problem.get("critique"),
    "trap_explanation": problem.get("trap_explanation"),
    "bbox": problem.get("bbox"),
})

严重程度通过标题和批判文本中的关键词推断。例如安全、坠落、火灾、漏电优先归为 critical;高额、陷阱、浪费归为 high;未命中时默认 medium

类别同样采用关键词映射,依次识别卫生死角、空间压迫、安全健康、隐性成本和实用性伪需求,无法识别时返回“其他”。

三、评分和统计如何生成

如果模型返回的 summary 中带有 score,后端优先使用该值;否则根据问题数计算:

score = 95 if problem_count == 0 else max(
    0, 100 - problem_count * 8
)

_count_severities() 再统计严重、高、中、低四类数量,组装 summary。因此前端无需遍历问题列表计算顶部统计卡。

页面将评分分为三个显示区间:80 分以上“优秀”,60~79 分“待改进”,低于 60 分“需重视”。这些标签只负责展示,原始分数仍来自后端结果。

四、文档结果如何合并

接口查询当前项目全部已完成的 DocumentAnalysis,按完成时间倒序交给 _serialize_document_analyses()

序列化结果以 project_file_id 为键。同一文件如果被分析多次,只保留排序后的第一条,也就是最新结果。每条数据包含风险列表、分类置信度、总结、预估风险金额和可选的 extra_item_prediction

最后,接口检查综合分析 JSON 中是否存在 cross_document_checks,存在就直接注入返回值。至此,一次响应已经包含报告页的全部章节。

五、React 如何决定显示哪些章节

AnalysisPage 根据数据动态创建导航项:

  • 总体评价、陷阱数、综合评分始终显示;
  • pitfalls 非空时显示问题详情;
  • 存在文档分析时显示合同与报价单;
  • 任一文档带增项预测时显示增项章节;
  • 存在差异项时显示跨文档核查。

页面使用 IntersectionObserver 观察这些章节,选择可见比例最高的部分更新 activeSection。桌面端显示可折叠的固定侧栏,移动端使用单独导航,点击后按照顶部偏移量平滑滚动。

六、问题详情如何渲染

RenoPit 装修问题详情

每个 PitfallCard 根据 severityConfig 选择图标、颜色、背景和中文标签。卡片展示分类、位置、问题分析、套路说明与替代建议;后端没有提供的可选字段不会渲染空区域。

合同结果由文档风险区块展示,增项预测交给 ExtraPredictionPanel,跨文档结果交给 CrossCheckPanel。这些组件不再请求后端,只处理已经聚合到 result 中的数据。

加载、接口失败和分析失败也分别有独立页面状态。这样报告页不会在数据未准备好时尝试解构 summarypitfalls

七、报告数据链小结

RenoPit 的报告展示分成两层:后端把模型原始 JSON 转换为稳定的 AnalysisResult,React 再根据字段是否存在组合页面。评分、严重程度、最新文档结果和交叉核查都在 /result 这一条边界上汇合。

结果聚合函数、TypeScript 类型和报告组件可以在 fthux/RenoPit 中查看。下一篇将继续复用同一份结果数据,分析 RenoPit 如何使用 ReportLab 生成可下载的中文 PDF 报告。

posted on 2026-08-18 13:41  fthux  阅读(39)  评论(0)    收藏  举报