"""数据表定义(SQLAlchemy 2.0)。 模型注册表由接口定义驱动: - InterfaceDefinition:具体接入协议及其动态表单字段 - ModelResource:模型配置与鉴权值 - AssistantModelBinding:助手按能力选择模型资源 """ from datetime import datetime from sqlalchemy import JSON, Boolean, DateTime, ForeignKey, String, func from sqlalchemy.dialects.postgresql import JSONB from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column class Base(DeclarativeBase): pass class InterfaceDefinition(Base): """具体接入协议,例如 xfyun-tts 与 xfyun-super-tts。""" __tablename__ = "interface_definitions" interface_type: Mapped[str] = mapped_column(String(64), primary_key=True) name: Mapped[str] = mapped_column(String(128)) capability: Mapped[str] = mapped_column(String(16), index=True) field_schema: Mapped[dict] = mapped_column(JSONB, default=dict) enabled: Mapped[bool] = mapped_column(Boolean, default=True) version: Mapped[int] = mapped_column(default=1) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) updated_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), server_default=func.now(), onupdate=func.now() ) class ModelResource(Base): """统一模型资源:接口类型决定能力、鉴权字段和调用参数。""" __tablename__ = "model_resources" id: Mapped[str] = mapped_column(String(40), primary_key=True) name: Mapped[str] = mapped_column(String(128), default="") capability: Mapped[str] = mapped_column(String(16), index=True) interface_type: Mapped[str] = mapped_column( String(64), ForeignKey("interface_definitions.interface_type", ondelete="RESTRICT"), index=True, ) values: Mapped[dict] = mapped_column(JSONB, default=dict) secrets: Mapped[dict] = mapped_column(JSONB, default=dict) support_image_input: Mapped[bool] = mapped_column(Boolean, default=False) enabled: Mapped[bool] = mapped_column(Boolean, default=True) is_default: Mapped[bool] = mapped_column(Boolean, default=False) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) updated_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), server_default=func.now(), onupdate=func.now() ) class KnowledgeBase(Base): """知识库注册表。本身引用一个 Embedding 模型资源。 文档/分块(pgvector)是 KB 内部实现,这里先不展开;助手侧只认 knowledge_base_id。 """ __tablename__ = "knowledge_bases" id: Mapped[str] = mapped_column(String(40), primary_key=True) # kb_xxx name: Mapped[str] = mapped_column(String(128)) description: Mapped[str] = mapped_column(String(2048), default="") embedding_model_resource_id: Mapped[str | None] = mapped_column( String(40), ForeignKey("model_resources.id", ondelete="SET NULL"), nullable=True, ) status: Mapped[str] = mapped_column(String(16), default="active") # active|archived created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) updated_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), server_default=func.now(), onupdate=func.now() ) class Assistant(Base): """助手(单表,无版本化)。type 为可变普通列,5 种类型共用此表。 模型/KB 以 FK 引用注册表;类型专属字段塞进 config(JSON)。 """ __tablename__ = "assistants" id: Mapped[str] = mapped_column(String(40), primary_key=True) # asst_xxx name: Mapped[str] = mapped_column(String(128)) # prompt|workflow|dify|fastgpt|opencode;创建后可改 type: Mapped[str] = mapped_column(String(16), index=True, default="prompt") runtime_mode: Mapped[str] = mapped_column(String(16), default="pipeline") greeting: Mapped[str] = mapped_column(String(2048), default="") enable_interrupt: Mapped[bool] = mapped_column(Boolean, default=True) vision_enabled: Mapped[bool] = mapped_column(Boolean, default=False) vision_model_resource_id: Mapped[str | None] = mapped_column( String(40), ForeignKey("model_resources.id", ondelete="SET NULL"), nullable=True, ) # KB 引用:被引用时禁止删 KB(RESTRICT),无默认兜底 knowledge_base_id: Mapped[str | None] = mapped_column( String(40), ForeignKey("knowledge_bases.id", ondelete="RESTRICT"), nullable=True ) # ---- 瘦类型专属字段(真列,稀疏:按 type 用其中几列) ---- prompt: Mapped[str] = mapped_column(String(8192), default="") # prompt / opencode api_url: Mapped[str] = mapped_column(String(512), default="") # dify / fastgpt / opencode api_key: Mapped[str] = mapped_column(String(512), default="") # dify / fastgpt / opencode(打码/哨兵) app_id: Mapped[str] = mapped_column(String(128), default="") # fastgpt # workflow 专属:图(nodes/edges)。要版本化时再迁出到 assistant_workflow 表 graph: Mapped[dict] = mapped_column(JSON, default=dict) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) updated_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), server_default=func.now(), onupdate=func.now() ) class AssistantModelBinding(Base): """助手按能力绑定统一模型资源;config 可覆盖资源默认 options。""" __tablename__ = "assistant_model_bindings" assistant_id: Mapped[str] = mapped_column( String(40), ForeignKey("assistants.id", ondelete="CASCADE"), primary_key=True, ) capability: Mapped[str] = mapped_column(String(16), primary_key=True) model_resource_id: Mapped[str] = mapped_column( String(40), ForeignKey("model_resources.id", ondelete="RESTRICT"), index=True, ) config: Mapped[dict] = mapped_column(JSONB, default=dict) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) updated_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), server_default=func.now(), onupdate=func.now() )