chore(prep): shared groundwork for the Sprint-2 parallel batch
第二批(T6~T11)协调提交: - 迁移 0005:kb 七表(entity/relation/rule/chunk vector1024+tsv 生成列/ asset/color/gap),HNSW+GIN 索引,FK 级联 - ORM:七个 Kb* 模型(pgvector Vector/TSVECTOR/Computed) - 配置:检索与 embedding、华为 JWKS、短信全参数组 - 错误码:40110/40111/42910/42911/61000 - 骨架路由:kb.py + auth_sms.py(已注册);依赖:tencentcloud-sdk-python-sms + spike extra(onnxruntime/opencv);gitignore:models/ 与 spike 输出
This commit is contained in:
+176
-1
@@ -18,9 +18,11 @@ from datetime import datetime
|
||||
from decimal import Decimal
|
||||
from typing import Any
|
||||
|
||||
from pgvector.sqlalchemy import Vector
|
||||
from sqlalchemy import (
|
||||
BigInteger,
|
||||
Boolean,
|
||||
Computed,
|
||||
DateTime,
|
||||
Index,
|
||||
Integer,
|
||||
@@ -31,8 +33,9 @@ from sqlalchemy import (
|
||||
Text,
|
||||
UniqueConstraint,
|
||||
func,
|
||||
text,
|
||||
)
|
||||
from sqlalchemy.dialects.postgresql import JSONB
|
||||
from sqlalchemy.dialects.postgresql import JSONB, TSVECTOR
|
||||
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
|
||||
|
||||
|
||||
@@ -304,3 +307,175 @@ class ObEvent(Base):
|
||||
Index("ix_ob_event_name_ts", "event_name", "server_ts"),
|
||||
Index("ix_ob_event_user_ts", "user_id", "server_ts"),
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# kb 域(知识库,架构文档 §6.2)
|
||||
# ---------------------------------------------------------------------------
|
||||
class KbEntity(Base):
|
||||
"""12 类实体统一表:attrs JSONB 承载类目差异化字段(架构 §6.2).
|
||||
|
||||
状态机 draft→reviewing→published→archived 由 service 层校验;
|
||||
published 实体不可直接改(version 递增需回 draft 重走评审)。
|
||||
"""
|
||||
|
||||
__tablename__ = "kb_entity"
|
||||
|
||||
entity_id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=False)
|
||||
entity_type: Mapped[str] = mapped_column(String(32), nullable=False)
|
||||
name: Mapped[str] = mapped_column(String(128), nullable=False)
|
||||
attrs: Mapped[dict[str, Any]] = mapped_column(JSONB, nullable=False, default=dict)
|
||||
status: Mapped[str] = mapped_column(String(16), nullable=False, default="draft")
|
||||
version: Mapped[int] = mapped_column(Integer, nullable=False, default=1)
|
||||
source: Mapped[str | None] = mapped_column(String(255))
|
||||
license: Mapped[str | None] = mapped_column(String(64))
|
||||
updated_by: Mapped[str | None] = mapped_column(String(64))
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), nullable=False, server_default=func.now()
|
||||
)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), nullable=False, server_default=func.now()
|
||||
)
|
||||
|
||||
__table_args__ = (
|
||||
UniqueConstraint("entity_type", "name", name="uq_kb_entity_type_name"),
|
||||
Index("ix_kb_entity_type_status", "entity_type", "status"),
|
||||
)
|
||||
|
||||
|
||||
class KbRelation(Base):
|
||||
"""邻接表 + 递归 CTE 做 1~3 跳(TD-09:不上 Neo4j)."""
|
||||
|
||||
__tablename__ = "kb_relation"
|
||||
|
||||
relation_id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=False)
|
||||
from_id: Mapped[int] = mapped_column(BigInteger, nullable=False)
|
||||
rel_type: Mapped[str] = mapped_column(String(64), nullable=False)
|
||||
to_id: Mapped[int] = mapped_column(BigInteger, nullable=False)
|
||||
weight: Mapped[Decimal] = mapped_column(Numeric(4, 3), nullable=False, default=Decimal("1"))
|
||||
confidence: Mapped[Decimal] = mapped_column(Numeric(4, 3), nullable=False, default=Decimal("1"))
|
||||
evidence: Mapped[str | None] = mapped_column(String(255))
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), nullable=False, server_default=func.now()
|
||||
)
|
||||
|
||||
__table_args__ = (
|
||||
UniqueConstraint("from_id", "rel_type", "to_id", name="uq_kb_relation_triple"),
|
||||
Index("ix_kb_relation_to", "to_id"),
|
||||
)
|
||||
|
||||
|
||||
class KbRule(Base):
|
||||
"""决策表(TD-10 自研规则引擎)。conditions/effects 为 JSONB DSL."""
|
||||
|
||||
__tablename__ = "kb_rule"
|
||||
|
||||
rule_id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=False)
|
||||
rule_key: Mapped[str] = mapped_column(String(64), nullable=False)
|
||||
category: Mapped[str] = mapped_column(String(32), nullable=False)
|
||||
version: Mapped[int] = mapped_column(Integer, nullable=False, default=1)
|
||||
status: Mapped[str] = mapped_column(String(16), nullable=False, default="draft")
|
||||
priority: Mapped[int] = mapped_column(Integer, nullable=False, default=60)
|
||||
conditions: Mapped[dict[str, Any]] = mapped_column(JSONB, nullable=False)
|
||||
effects: Mapped[dict[str, Any]] = mapped_column(JSONB, nullable=False)
|
||||
is_hard: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
|
||||
confidence: Mapped[Decimal] = mapped_column(
|
||||
Numeric(4, 3), nullable=False, default=Decimal("0.9")
|
||||
)
|
||||
evidence: Mapped[str | None] = mapped_column(String(255))
|
||||
author: Mapped[str | None] = mapped_column(String(64))
|
||||
reviewer: Mapped[str | None] = mapped_column(String(64))
|
||||
published_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), nullable=False, server_default=func.now()
|
||||
)
|
||||
|
||||
__table_args__ = (
|
||||
UniqueConstraint("rule_key", name="uq_kb_rule_key"),
|
||||
Index("ix_kb_rule_status_priority", "status", "priority"),
|
||||
)
|
||||
|
||||
|
||||
class KbChunk(Base):
|
||||
"""向量 + 全文双索引,支撑混合检索(架构 §8.3).
|
||||
|
||||
embedding_model/version 必填:没有版本号的向量不可重跑(T-P2-03)。
|
||||
tsv 是生成列——写入时不要手工填。
|
||||
"""
|
||||
|
||||
__tablename__ = "kb_chunk"
|
||||
|
||||
chunk_id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=False)
|
||||
entity_id: Mapped[int] = mapped_column(BigInteger, nullable=False)
|
||||
chunk_type: Mapped[str] = mapped_column(String(32), nullable=False, default="text")
|
||||
text: Mapped[str] = mapped_column(Text, nullable=False)
|
||||
embedding = mapped_column(Vector(1024), nullable=False)
|
||||
embedding_model: Mapped[str] = mapped_column(String(64), nullable=False)
|
||||
embedding_version: Mapped[str] = mapped_column(String(16), nullable=False)
|
||||
tsv = mapped_column(
|
||||
TSVECTOR, Computed("to_tsvector('simple', text)", persisted=True), nullable=False
|
||||
)
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), nullable=False, server_default=func.now()
|
||||
)
|
||||
|
||||
__table_args__ = (Index("ix_kb_chunk_entity", "entity_id"),)
|
||||
|
||||
|
||||
class KbAsset(Base):
|
||||
"""图像资产。tryon_ready 是换装闭环的关键标志位(架构 §6.2)."""
|
||||
|
||||
__tablename__ = "kb_asset"
|
||||
|
||||
asset_id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=False)
|
||||
entity_id: Mapped[int] = mapped_column(BigInteger, nullable=False)
|
||||
asset_type: Mapped[str] = mapped_column(String(32), nullable=False)
|
||||
cos_key: Mapped[str] = mapped_column(String(255), nullable=False)
|
||||
spec_check: Mapped[dict[str, Any]] = mapped_column(JSONB, nullable=False, default=dict)
|
||||
tryon_ready: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
|
||||
review_status: Mapped[str] = mapped_column(String(16), nullable=False, default="pending")
|
||||
license: Mapped[str | None] = mapped_column(String(64))
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), nullable=False, server_default=func.now()
|
||||
)
|
||||
|
||||
__table_args__ = (
|
||||
Index("ix_kb_asset_entity", "entity_id"),
|
||||
Index("ix_kb_asset_tryon_ready", "tryon_ready", postgresql_where=text("tryon_ready")),
|
||||
)
|
||||
|
||||
|
||||
class KbColor(Base):
|
||||
"""自建色板(TD-18:规避「四季色彩/CMB」商标)。Lab 用于 ΔE 数值匹配."""
|
||||
|
||||
__tablename__ = "kb_color"
|
||||
|
||||
color_id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=False)
|
||||
season_code: Mapped[str] = mapped_column(String(16), nullable=False)
|
||||
role: Mapped[str] = mapped_column(String(8), nullable=False)
|
||||
lab_l: Mapped[Decimal] = mapped_column(Numeric(6, 2), nullable=False)
|
||||
lab_a: Mapped[Decimal] = mapped_column(Numeric(6, 2), nullable=False)
|
||||
lab_b: Mapped[Decimal] = mapped_column(Numeric(6, 2), nullable=False)
|
||||
hex: Mapped[str] = mapped_column(String(7), nullable=False)
|
||||
name_cn: Mapped[str] = mapped_column(String(64), nullable=False)
|
||||
|
||||
__table_args__ = (Index("ix_kb_color_season", "season_code"),)
|
||||
|
||||
|
||||
class KbGap(Base):
|
||||
"""知识缺口埋点:无检索结果的查询,驱动内容生产(T-P2-06)."""
|
||||
|
||||
__tablename__ = "kb_gap"
|
||||
|
||||
gap_id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=False)
|
||||
query_text: Mapped[str] = mapped_column(Text, nullable=False)
|
||||
filter_ctx: Mapped[dict[str, Any]] = mapped_column(JSONB, nullable=False, default=dict)
|
||||
hit_count: Mapped[int] = mapped_column(Integer, nullable=False, default=1)
|
||||
first_seen_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), nullable=False, server_default=func.now()
|
||||
)
|
||||
last_seen_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), nullable=False, server_default=func.now()
|
||||
)
|
||||
|
||||
__table_args__ = (Index("ix_kb_gap_query", "query_text"),)
|
||||
|
||||
Reference in New Issue
Block a user