Files

149 lines
4.5 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Document 文档模型。"""
from sqlalchemy import ForeignKey, Integer, String, Text
from sqlalchemy.orm import Mapped, mapped_column, relationship
from app.models.base import Base, TimestampMixin, UUIDPrimaryKeyMixin
class Document(UUIDPrimaryKeyMixin, TimestampMixin, Base):
"""文档模型。
技术审查 §2.2documents 表。
"""
__tablename__ = "documents"
knowledge_base_id: Mapped[str] = mapped_column(
String(32),
ForeignKey("knowledge_bases.id"),
nullable=False,
index=True,
comment="所属知识库 ID",
)
user_id: Mapped[str] = mapped_column(
String(32),
ForeignKey("users.id"),
nullable=False,
index=True,
comment="所有者用户 ID (冗余,便于隔离校验)",
)
category_id: Mapped[str | None] = mapped_column(
String(32),
ForeignKey("document_categories.id"),
nullable=True,
comment="分类 ID",
)
original_filename: Mapped[str] = mapped_column(
String(512),
nullable=False,
comment="原始文件名或文本标题 (仅展示)",
)
storage_path: Mapped[str | None] = mapped_column(
String(1024),
nullable=True,
comment="相对于 data/ 的物理存储路径(文本内容文档为 NULL)",
)
content: Mapped[str | None] = mapped_column(
Text,
nullable=True,
comment="直接输入的文本内容(非文件上传时使用)",
)
content_format: Mapped[str] = mapped_column(
String(16),
default="markdown",
nullable=False,
comment="内容格式:markdown / text",
)
markdown_path: Mapped[str | None] = mapped_column(
String(1024),
nullable=True,
comment="相对于 data/ 的 Markdown 文件路径",
)
file_size: Mapped[int] = mapped_column(
Integer,
default=0,
nullable=False,
comment="文件大小 (字节),文本内容文档为内容长度",
)
mime_type: Mapped[str] = mapped_column(
String(127),
default="text/markdown",
nullable=False,
comment="MIME 类型",
)
file_ext: Mapped[str] = mapped_column(
String(16),
default=".md",
nullable=False,
comment="文件扩展名 (.docx/.pdf/.md)",
)
sha256: Mapped[str | None] = mapped_column(
String(64),
nullable=True,
comment="文件 SHA-256 哈希(文本内容文档为 NULL",
)
doc_token_hash: Mapped[str] = mapped_column(
String(64),
unique=True,
nullable=True,
index=True,
comment="SHA-256(document_token) 十六进制",
)
doc_token_encrypted: Mapped[str | None] = mapped_column(
Text,
nullable=True,
comment="Fernet 加密的 document_token 原文",
)
doc_token_hint: Mapped[str | None] = mapped_column(
String(16),
nullable=True,
comment="document_token 末 8 位明文",
)
title: Mapped[str | None] = mapped_column(
String(512),
nullable=True,
comment="文档标题 (用户可改)",
)
description: Mapped[str | None] = mapped_column(
Text,
nullable=True,
comment="文档描述 (用户可改)",
)
keywords: Mapped[str | None] = mapped_column(
Text,
nullable=True,
comment="关键词 (逗号分隔)",
)
content_summary: Mapped[str | None] = mapped_column(
Text,
nullable=True,
comment="抽取式摘要 (~200字)",
)
status: Mapped[str] = mapped_column(
String(16),
default="PENDING",
nullable=False,
comment="状态 (PENDING/PROCESSING/READY/FAILED/DELETED)",
)
deleted_at: Mapped[str | None] = mapped_column(
String(32),
nullable=True,
index=True,
comment="进入回收站时间(NULL=未删除),3 天后自动清理",
)
error_code: Mapped[str | None] = mapped_column(
String(64),
nullable=True,
comment="错误码 (如 SCANNED_PDF_NO_TEXT_LAYER)",
)
# 关系
knowledge_base = relationship("KnowledgeBase", back_populates="documents", lazy="selectin")
user = relationship("User", back_populates="documents", lazy="selectin")
category = relationship("DocumentCategory", back_populates="documents", lazy="selectin")
access_logs = relationship("AccessLog", back_populates="document", lazy="selectin")
def __repr__(self) -> str:
return f"<Document {self.original_filename!r} (status={self.status!r})>"