""" 新增 ORM 模型 — ai_chat_sessions / sales_logs / ai_report_drafts """ from __future__ import annotations import uuid from datetime import date, datetime from sqlalchemy import Boolean, Date, DateTime, ForeignKey, SmallInteger, String, Text, func from sqlalchemy.dialects.postgresql import UUID, JSONB, ARRAY from sqlalchemy.orm import Mapped, mapped_column from app.models.base import Base class AiChatSession(Base): __tablename__ = "ai_chat_sessions" id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) user_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("sys_users.id"), nullable=False) role: Mapped[str] = mapped_column(String(10), nullable=False) content: Mapped[str] = mapped_column(Text, nullable=False) msg_type: Mapped[str] = mapped_column(String(20), default="text") metadata_: Mapped[dict | None] = mapped_column("metadata", JSONB, default=dict) created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now()) class SalesLog(Base): __tablename__ = "sales_logs" id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) salesperson_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("sys_users.id"), nullable=False) involved_company_ids: Mapped[list] = mapped_column( ARRAY(UUID(as_uuid=True)), nullable=False, default=list, comment="该篇日志涉及的公司ID列表" ) customer_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), ForeignKey("crm_customers.id"), nullable=True) content: Mapped[str] = mapped_column(Text, nullable=False) log_date: Mapped[date] = mapped_column(Date, default=date.today) contact_ids: Mapped[list | None] = mapped_column(JSONB, default=list, nullable=True) ai_processed: Mapped[bool] = mapped_column(Boolean, default=False) ai_coaching_feedback: Mapped[dict | None] = mapped_column( JSONB, default=dict, nullable=True, comment="AI 教练引擎回写的指导反馈" ) created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now()) updated_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now(), onupdate=func.now()) is_deleted: Mapped[bool] = mapped_column(Boolean, default=False) class AiReportDraft(Base): __tablename__ = "ai_report_drafts" id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) author_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("sys_users.id"), nullable=False) report_type: Mapped[str] = mapped_column(String(20), nullable=False) period_start: Mapped[date] = mapped_column(Date, nullable=False) period_end: Mapped[date] = mapped_column(Date, nullable=False) content_md: Mapped[str] = mapped_column(Text, nullable=False) status: Mapped[str] = mapped_column(String(20), default="draft") created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now()) updated_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now(), onupdate=func.now()) is_deleted: Mapped[bool] = mapped_column(Boolean, default=False) class KbObsidianVector(Base): """知识库向量表 —— pgvector 存储 Obsidian 文档分块向量""" __tablename__ = "kb_obsidian_vectors" id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) company_id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), ForeignKey("sys_companies.id"), nullable=False, index=True ) source_path: Mapped[str] = mapped_column(String(500), nullable=False, comment="源文件路径") chunk_index: Mapped[int] = mapped_column(SmallInteger, default=0) content: Mapped[str] = mapped_column(Text, nullable=False) metadata_: Mapped[dict | None] = mapped_column("metadata", JSONB, default=dict) # 向量字段使用 raw SQL 创建(vector(1536))因 SQLAlchemy 无原生 pgvector 类型 created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now()) is_deleted: Mapped[bool] = mapped_column(Boolean, default=False)