装闭 RenoPit 源码解析(02):AI装修闭坑系统数据库与模型设计

装闭 RenoPit 的项目、装修素材、AI 分析结果和 PDF 报告都需要跨请求保存。本篇结合开源仓库 fthux/RenoPit 中的 SQLAlchemy 模型,分析六张核心数据表如何组织一份完整的装修闭坑项目。

一、六张表围绕 Project 展开

后端模型位于 backend/app/models,全部继承 core/database.py 中的 Base。六张表的关系如下:
erDiagram PROJECT ||--o{ PROJECT_IMAGE : contains PROJECT ||--o{ PROJECT_FILE : contains PROJECT ||--o{ ANALYSIS : produces PROJECT ||--o{ DOCUMENT_ANALYSIS : produces PROJECT ||--o{ REPORT : owns ANALYSIS ||--o| REPORT : generates PROJECT { uuid id PK string name string status text input_text } ANALYSIS { uuid id PK uuid project_id FK json raw_result_json string status } DOCUMENT_ANALYSIS { uuid id PK uuid project_id FK uuid project_file_id FK json risks_json }

Project 是整个数据模型的入口。图片、普通文件、设计分析和报告都通过 project_id 回到项目,因此 API 只要拿到项目 UUID,就能继续查询全部业务数据。

二、Project 保存业务状态

Project 的核心字段如下:

python 复制代码
class Project(Base):
    id = Column(Uuid(as_uuid=False), primary_key=True)
    name = Column(String(255), nullable=False)
    access_token = Column(String(64), nullable=False)
    status = Column(String(20), default="pending")
    input_text = Column(Text, nullable=True)

name 和 description 描述项目,input_text 保存用户补充的装修需求。status 是前后端共同使用的状态字段,主要在 pending、analyzing、completed 和 failed 之间变化。

模型还为 access_token、status 和 created_at 建立索引。列表接口按创建时间倒序查询,状态则会被项目页和 SSE 接口反复读取。

images、files、analysis、report 都设置了 cascade="all, delete-orphan"。删除项目 ORM 对象时,关联的数据行会一起进入删除流程。数据库外键同时使用 ondelete="CASCADE",在数据库层继续维护父子关系。

三、图片和文档为什么分表

ProjectImage 保存原始文件名、磁盘路径、文件大小、宽度和高度。图片会进入多模态 LLM,因此后端需要尺寸信息,并在分析前转换成 Base64。

ProjectFile 面向 TXT、Markdown、DOCX 和 PDF 等文档,除路径和文件类型外,还包含 extracted_text:

python 复制代码
class ProjectFile(Base):
    original_filename = Column(String(500), nullable=False)
    storage_path = Column(String(500), nullable=False)
    file_type = Column(String(20), nullable=False)
    extracted_text = Column(Text, nullable=True)

上传阶段提取出的文本会直接写入该字段。后续设计分析、合同审查和跨文档核查可以复用它,不必每次重新读取 PDF 或 DOCX。

两个表都在 project_id 上建立索引,并通过 back_populates 回到 Project.images 和 Project.files。

四、两类 AI 分析使用不同模型

Analysis 保存设计图和综合装修闭坑分析。大模型返回的完整结构放在 raw_result_json,失败原因放在 error_message。project_id 没有唯一约束,一次重新分析会创建新的 Analysis 记录,结果接口再按创建时间取最近一条。虽然 Project.analysis 在 ORM 中配置为标量关系,业务接口读取分析历史时使用的是显式查询和排序。

DocumentAnalysis 则保存单份合同或报价单的分析。它包含:

  • doc_type:合同、报价单或未知类型;
  • confidence:文档分类置信度;
  • classifications_json:分类依据和关键片段;
  • risks_json:风险项及增项预测;
  • summary、risks_count:供列表和报告快速读取。

project_file_id 使用 ondelete="SET NULL"。当原始文件记录被删除时,文档分析记录仍可保留,只是失去文件关联;project_id 则继续使用级联删除。

五、Report 连接分析结果和 PDF

Report 同时引用 Project 和 Analysis,analysis_id 上还有唯一约束:

python 复制代码
UniqueConstraint("analysis_id", name="uq_reports_analysis_id")

这表示一条分析记录最多对应一条报告记录;project_id 本身没有唯一约束。当前下载接口会优先复用项目已有的第一条 Report 记录。file_path 用来记录生成文件的位置,而实际下载接口也可以现场调用 ReportLab 生成 PDF 字节。

六、模型如何变成 API 数据

数据库模型不会直接返回给浏览器。项目接口使用 Pydantic 的 ProjectCreateRequest、ProjectUpdateRequest 和 ProjectResponse 约束输入输出。例如创建项目时限制名称 255 字、描述 500 字、补充说明 2000 字。

_project_to_response() 还会根据 ORM 关系计算 image_count 和 file_count。前端 types/index.ts 中的 Project、ProjectFile、ProjectImage、AnalysisResult 等接口再接住这些 JSON 字段,使页面状态与后端响应保持同一套结构。

七、数据模型调用链小结

RenoPit 的数据层可以分为三组:Project、ProjectImage、ProjectFile 保存用户输入;Analysis 和 DocumentAnalysis 保存 AI 结构化结果;Report 保存最终输出。所有后续调用链都围绕 project_id 展开。

完整模型和 Schema 可以在 fthux/RenoPit 中继续对照查看。下一篇将沿着这些模型进入项目 API,分析一个装修项目从创建、编辑到复制和删除的完整生命周期。

相关推荐
笨蛋©几秒前
2026制造业质量数字化:Infra CONVERT 中国代理技术支持下的检验计划自动化实战
ai·数字化·cad·质量管理·制造业
玩AI的奶茶5 分钟前
从零到跑通:在算家云上部署大模型的完整操作手册(实例创建 / 镜像选择 / 远程连接 / 成本控制)
人工智能·ai·gpu算力·token·算力租赁
超级架构师5 分钟前
迈向数字文明的秩序基石:全面解析 AICTRI 开源 AI 智能体身份与访问管理规范(AgentIAM)
人工智能·开源·ai编程·安全架构
智能制造爱好者7 分钟前
7 类新能源汽车驱动电机梳理:从技术特性到量产落地
人工智能·汽车
DcMedia元宇宙7 分钟前
智能体丛林法则1:人类的存活与演进
人工智能
田里的水稻10 分钟前
EI_策略训练--机器人策略训练的神经网络种类一
人工智能·神经网络·机器人
QYR-分析13 分钟前
锂电制造核心装备:全球电芯焊接机市场格局与增长趋势研判
大数据·人工智能·制造
ofoxcoding13 分钟前
Opus 5.5 实战:从 CSV 数据校验到动态图表视频 MP4 导出全流程
ai
生活商业界18 分钟前
联想至像:拒绝高耗材高门槛,聚焦细分场景下的打印机使用体验
人工智能·生活
合米AI SOP系统21 分钟前
车间光线忽明忽暗?合米科技 AI SOP 视觉防错凭借强光照鲁棒性稳定核验工序.
人工智能·科技