feat: 建立知识版本与检索追踪数据模型
This commit is contained in:
@@ -0,0 +1,319 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
from sqlalchemy.dialects import mysql
|
||||||
|
|
||||||
|
revision = "0007_knowledge_agent_rebuild"
|
||||||
|
down_revision = "0006_expand_ai_request_log_text"
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade() -> None:
|
||||||
|
for column in [
|
||||||
|
sa.Column("source_title", sa.String(255), nullable=True),
|
||||||
|
sa.Column("knowledge_type", sa.String(30), nullable=False, server_default="general"),
|
||||||
|
sa.Column("review_mode", sa.String(30), nullable=False, server_default="manual"),
|
||||||
|
sa.Column("lifecycle_status", sa.String(30), nullable=False, server_default="active"),
|
||||||
|
sa.Column("source_status", sa.String(30), nullable=False, server_default="normal"),
|
||||||
|
sa.Column("source_error", mysql.MEDIUMTEXT(), nullable=True),
|
||||||
|
sa.Column("manifest_confirmed", sa.Integer(), nullable=False, server_default="0"),
|
||||||
|
sa.Column("current_version_id", sa.BigInteger(), nullable=True),
|
||||||
|
sa.Column("pending_version_id", sa.BigInteger(), nullable=True),
|
||||||
|
sa.Column("last_synced_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("last_published_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("migration_status", sa.String(30), nullable=False, server_default="pending"),
|
||||||
|
]:
|
||||||
|
op.add_column("sys_knowledge", column)
|
||||||
|
|
||||||
|
op.create_table(
|
||||||
|
"sys_knowledge_source_snapshot",
|
||||||
|
sa.Column("id", sa.BigInteger(), autoincrement=True, nullable=False),
|
||||||
|
sa.Column("knowledge_id", sa.BigInteger(), nullable=False),
|
||||||
|
sa.Column("sync_job_id", sa.BigInteger(), nullable=True),
|
||||||
|
sa.Column("source_title", sa.String(255), nullable=False),
|
||||||
|
sa.Column("source_content", mysql.LONGTEXT(), nullable=False),
|
||||||
|
sa.Column("content_hash", sa.String(64), nullable=False),
|
||||||
|
sa.Column("source_identifier", sa.String(255), nullable=False),
|
||||||
|
sa.Column("fetched_at", sa.DateTime(), server_default=sa.text("now()"), nullable=False),
|
||||||
|
sa.Column("created_by", sa.BigInteger(), nullable=True),
|
||||||
|
sa.ForeignKeyConstraint(["knowledge_id"], ["sys_knowledge.id"]),
|
||||||
|
sa.PrimaryKeyConstraint("id"),
|
||||||
|
)
|
||||||
|
_indexes("sys_knowledge_source_snapshot", "knowledge_id", "sync_job_id", "content_hash")
|
||||||
|
|
||||||
|
op.create_table(
|
||||||
|
"sys_knowledge_version",
|
||||||
|
sa.Column("id", sa.BigInteger(), autoincrement=True, nullable=False),
|
||||||
|
sa.Column("knowledge_id", sa.BigInteger(), nullable=False),
|
||||||
|
sa.Column("snapshot_id", sa.BigInteger(), nullable=False),
|
||||||
|
sa.Column("version_no", sa.Integer(), nullable=False),
|
||||||
|
sa.Column("status", sa.String(30), nullable=False),
|
||||||
|
sa.Column("quality_status", sa.String(30), nullable=False, server_default="pending"),
|
||||||
|
sa.Column("change_summary", mysql.MEDIUMTEXT(), nullable=True),
|
||||||
|
sa.Column("quality_report", mysql.MEDIUMTEXT(), nullable=True),
|
||||||
|
sa.Column("processing_rule_version", sa.String(50), nullable=False),
|
||||||
|
sa.Column("generation_model", sa.String(100), nullable=True),
|
||||||
|
sa.Column("created_by", sa.BigInteger(), nullable=True),
|
||||||
|
sa.Column("created_at", sa.DateTime(), server_default=sa.text("now()"), nullable=False),
|
||||||
|
sa.Column("published_by", sa.BigInteger(), nullable=True),
|
||||||
|
sa.Column("published_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.ForeignKeyConstraint(["knowledge_id"], ["sys_knowledge.id"]),
|
||||||
|
sa.ForeignKeyConstraint(["snapshot_id"], ["sys_knowledge_source_snapshot.id"]),
|
||||||
|
sa.PrimaryKeyConstraint("id"),
|
||||||
|
sa.UniqueConstraint("knowledge_id", "version_no", name="uq_kb_version_no"),
|
||||||
|
)
|
||||||
|
_indexes("sys_knowledge_version", "knowledge_id", "status")
|
||||||
|
|
||||||
|
op.create_table(
|
||||||
|
"sys_knowledge_manifest",
|
||||||
|
sa.Column("id", sa.BigInteger(), autoincrement=True, nullable=False),
|
||||||
|
sa.Column("knowledge_id", sa.BigInteger(), nullable=False),
|
||||||
|
sa.Column("version_id", sa.BigInteger(), nullable=False),
|
||||||
|
sa.Column("purpose", mysql.MEDIUMTEXT(), nullable=False),
|
||||||
|
sa.Column("applicable_questions", mysql.MEDIUMTEXT(), nullable=False),
|
||||||
|
sa.Column("inapplicable_questions", mysql.MEDIUMTEXT(), nullable=False),
|
||||||
|
sa.Column("core_topics", mysql.MEDIUMTEXT(), nullable=False),
|
||||||
|
sa.Column("entities", mysql.MEDIUMTEXT(), nullable=True),
|
||||||
|
sa.Column("boundaries", mysql.MEDIUMTEXT(), nullable=True),
|
||||||
|
sa.Column("content_hash", sa.String(64), nullable=False),
|
||||||
|
sa.Column("change_level", sa.String(20), nullable=False, server_default="major"),
|
||||||
|
sa.Column("confirmed", sa.Integer(), nullable=False, server_default="0"),
|
||||||
|
sa.Column("confirmed_by", sa.BigInteger(), nullable=True),
|
||||||
|
sa.Column("confirmed_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.ForeignKeyConstraint(["knowledge_id"], ["sys_knowledge.id"]),
|
||||||
|
sa.ForeignKeyConstraint(["version_id"], ["sys_knowledge_version.id"]),
|
||||||
|
sa.PrimaryKeyConstraint("id"),
|
||||||
|
)
|
||||||
|
_indexes("sys_knowledge_manifest", "knowledge_id", "version_id")
|
||||||
|
|
||||||
|
op.create_table(
|
||||||
|
"sys_knowledge_section",
|
||||||
|
sa.Column("id", sa.BigInteger(), autoincrement=True, nullable=False),
|
||||||
|
sa.Column("knowledge_id", sa.BigInteger(), nullable=False),
|
||||||
|
sa.Column("version_id", sa.BigInteger(), nullable=False),
|
||||||
|
sa.Column("section_key", sa.String(64), nullable=False),
|
||||||
|
sa.Column("title", sa.String(255), nullable=False),
|
||||||
|
sa.Column("content", mysql.LONGTEXT(), nullable=False),
|
||||||
|
sa.Column("source_start", sa.Integer(), nullable=False),
|
||||||
|
sa.Column("source_end", sa.Integer(), nullable=False),
|
||||||
|
sa.Column("sort_order", sa.Integer(), nullable=False),
|
||||||
|
sa.Column("content_hash", sa.String(64), nullable=False),
|
||||||
|
sa.ForeignKeyConstraint(["knowledge_id"], ["sys_knowledge.id"]),
|
||||||
|
sa.ForeignKeyConstraint(["version_id"], ["sys_knowledge_version.id"]),
|
||||||
|
sa.PrimaryKeyConstraint("id"),
|
||||||
|
)
|
||||||
|
_indexes("sys_knowledge_section", "knowledge_id", "version_id")
|
||||||
|
|
||||||
|
op.create_table(
|
||||||
|
"sys_knowledge_chunk",
|
||||||
|
sa.Column("id", sa.BigInteger(), autoincrement=True, nullable=False),
|
||||||
|
sa.Column("knowledge_id", sa.BigInteger(), nullable=False),
|
||||||
|
sa.Column("version_id", sa.BigInteger(), nullable=False),
|
||||||
|
sa.Column("section_id", sa.BigInteger(), nullable=False),
|
||||||
|
sa.Column("title", sa.String(255), nullable=False),
|
||||||
|
sa.Column("content", mysql.MEDIUMTEXT(), nullable=False),
|
||||||
|
sa.Column("normalized_text", mysql.MEDIUMTEXT(), nullable=False),
|
||||||
|
sa.Column("keywords", mysql.MEDIUMTEXT(), nullable=True),
|
||||||
|
sa.Column("synonyms", mysql.MEDIUMTEXT(), nullable=True),
|
||||||
|
sa.Column("source_start", sa.Integer(), nullable=False),
|
||||||
|
sa.Column("source_end", sa.Integer(), nullable=False),
|
||||||
|
sa.Column("sort_order", sa.Integer(), nullable=False),
|
||||||
|
sa.Column("content_hash", sa.String(64), nullable=False),
|
||||||
|
sa.ForeignKeyConstraint(["knowledge_id"], ["sys_knowledge.id"]),
|
||||||
|
sa.ForeignKeyConstraint(["version_id"], ["sys_knowledge_version.id"]),
|
||||||
|
sa.ForeignKeyConstraint(["section_id"], ["sys_knowledge_section.id"]),
|
||||||
|
sa.PrimaryKeyConstraint("id"),
|
||||||
|
)
|
||||||
|
_indexes("sys_knowledge_chunk", "knowledge_id", "version_id", "section_id")
|
||||||
|
|
||||||
|
op.create_table(
|
||||||
|
"sys_knowledge_card",
|
||||||
|
sa.Column("id", sa.BigInteger(), autoincrement=True, nullable=False),
|
||||||
|
sa.Column("knowledge_id", sa.BigInteger(), nullable=False),
|
||||||
|
sa.Column("version_id", sa.BigInteger(), nullable=False),
|
||||||
|
sa.Column("section_id", sa.BigInteger(), nullable=False),
|
||||||
|
sa.Column("title", sa.String(255), nullable=False),
|
||||||
|
sa.Column("summary", mysql.MEDIUMTEXT(), nullable=False),
|
||||||
|
sa.Column("core_conclusion", mysql.MEDIUMTEXT(), nullable=False),
|
||||||
|
sa.Column("applicable_questions", mysql.MEDIUMTEXT(), nullable=False),
|
||||||
|
sa.Column("inapplicable_questions", mysql.MEDIUMTEXT(), nullable=False),
|
||||||
|
sa.Column("keywords", mysql.MEDIUMTEXT(), nullable=False),
|
||||||
|
sa.Column("synonyms", mysql.MEDIUMTEXT(), nullable=True),
|
||||||
|
sa.Column("entities", mysql.MEDIUMTEXT(), nullable=True),
|
||||||
|
sa.Column("risk_level", sa.String(20), nullable=False, server_default="normal"),
|
||||||
|
sa.Column("source_range", sa.String(100), nullable=False),
|
||||||
|
sa.Column("content_hash", sa.String(64), nullable=False),
|
||||||
|
sa.Column("generation_model", sa.String(100), nullable=True),
|
||||||
|
sa.Column("generation_rule_version", sa.String(50), nullable=False),
|
||||||
|
sa.Column("review_status", sa.String(20), nullable=False, server_default="pending"),
|
||||||
|
sa.ForeignKeyConstraint(["knowledge_id"], ["sys_knowledge.id"]),
|
||||||
|
sa.ForeignKeyConstraint(["version_id"], ["sys_knowledge_version.id"]),
|
||||||
|
sa.ForeignKeyConstraint(["section_id"], ["sys_knowledge_section.id"]),
|
||||||
|
sa.PrimaryKeyConstraint("id"),
|
||||||
|
)
|
||||||
|
_indexes("sys_knowledge_card", "knowledge_id", "version_id", "section_id")
|
||||||
|
|
||||||
|
_create_job_and_log_tables()
|
||||||
|
|
||||||
|
|
||||||
|
def _create_job_and_log_tables() -> None:
|
||||||
|
op.create_table(
|
||||||
|
"sys_knowledge_sync_job",
|
||||||
|
sa.Column("id", sa.BigInteger(), autoincrement=True, nullable=False),
|
||||||
|
sa.Column("knowledge_id", sa.BigInteger(), nullable=False),
|
||||||
|
sa.Column("mode", sa.String(30), nullable=False),
|
||||||
|
sa.Column("status", sa.String(30), nullable=False),
|
||||||
|
sa.Column("stage", sa.String(50), nullable=False),
|
||||||
|
sa.Column("progress", sa.Integer(), nullable=False, server_default="0"),
|
||||||
|
sa.Column("source_error", mysql.MEDIUMTEXT(), nullable=True),
|
||||||
|
sa.Column("result_summary", mysql.MEDIUMTEXT(), nullable=True),
|
||||||
|
sa.Column("requested_by", sa.BigInteger(), nullable=False),
|
||||||
|
sa.Column("created_at", sa.DateTime(), server_default=sa.text("now()"), nullable=False),
|
||||||
|
sa.Column("started_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("finished_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.ForeignKeyConstraint(["knowledge_id"], ["sys_knowledge.id"]),
|
||||||
|
sa.PrimaryKeyConstraint("id"),
|
||||||
|
)
|
||||||
|
_indexes("sys_knowledge_sync_job", "knowledge_id", "status")
|
||||||
|
|
||||||
|
op.create_table(
|
||||||
|
"sys_knowledge_review_record",
|
||||||
|
sa.Column("id", sa.BigInteger(), autoincrement=True, nullable=False),
|
||||||
|
sa.Column("knowledge_id", sa.BigInteger(), nullable=False),
|
||||||
|
sa.Column("version_id", sa.BigInteger(), nullable=False),
|
||||||
|
sa.Column("card_id", sa.BigInteger(), nullable=True),
|
||||||
|
sa.Column("action", sa.String(30), nullable=False),
|
||||||
|
sa.Column("reason", mysql.MEDIUMTEXT(), nullable=True),
|
||||||
|
sa.Column("reviewed_by", sa.BigInteger(), nullable=False),
|
||||||
|
sa.Column("created_at", sa.DateTime(), server_default=sa.text("now()"), nullable=False),
|
||||||
|
sa.ForeignKeyConstraint(["knowledge_id"], ["sys_knowledge.id"]),
|
||||||
|
sa.ForeignKeyConstraint(["version_id"], ["sys_knowledge_version.id"]),
|
||||||
|
sa.ForeignKeyConstraint(["card_id"], ["sys_knowledge_card.id"]),
|
||||||
|
sa.PrimaryKeyConstraint("id"),
|
||||||
|
)
|
||||||
|
_indexes("sys_knowledge_review_record", "knowledge_id", "version_id")
|
||||||
|
|
||||||
|
op.create_table(
|
||||||
|
"sys_knowledge_publish_log",
|
||||||
|
sa.Column("id", sa.BigInteger(), autoincrement=True, nullable=False),
|
||||||
|
sa.Column("knowledge_id", sa.BigInteger(), nullable=False),
|
||||||
|
sa.Column("from_version_id", sa.BigInteger(), nullable=True),
|
||||||
|
sa.Column("to_version_id", sa.BigInteger(), nullable=True),
|
||||||
|
sa.Column("action", sa.String(30), nullable=False),
|
||||||
|
sa.Column("keep_open", sa.Integer(), nullable=False, server_default="0"),
|
||||||
|
sa.Column("detail_json", mysql.MEDIUMTEXT(), nullable=True),
|
||||||
|
sa.Column("operated_by", sa.BigInteger(), nullable=False),
|
||||||
|
sa.Column("created_at", sa.DateTime(), server_default=sa.text("now()"), nullable=False),
|
||||||
|
sa.ForeignKeyConstraint(["knowledge_id"], ["sys_knowledge.id"]),
|
||||||
|
sa.PrimaryKeyConstraint("id"),
|
||||||
|
)
|
||||||
|
_indexes("sys_knowledge_publish_log", "knowledge_id")
|
||||||
|
|
||||||
|
op.create_table(
|
||||||
|
"sys_knowledge_retrieval_log",
|
||||||
|
sa.Column("id", sa.BigInteger(), autoincrement=True, nullable=False),
|
||||||
|
sa.Column("session_id", sa.BigInteger(), nullable=True),
|
||||||
|
sa.Column("message_id", sa.BigInteger(), nullable=True),
|
||||||
|
sa.Column("user_id", sa.BigInteger(), nullable=True),
|
||||||
|
sa.Column("question", mysql.MEDIUMTEXT(), nullable=False),
|
||||||
|
sa.Column("catalog_snapshot", mysql.LONGTEXT(), nullable=False),
|
||||||
|
sa.Column("catalog_hash", sa.String(64), nullable=False),
|
||||||
|
sa.Column("safety_rule_version", sa.String(50), nullable=False),
|
||||||
|
sa.Column("knowledge_called", sa.Integer(), nullable=False, server_default="0"),
|
||||||
|
sa.Column("selected_knowledge_ids", sa.String(500), nullable=True),
|
||||||
|
sa.Column("query_terms", mysql.MEDIUMTEXT(), nullable=True),
|
||||||
|
sa.Column("tool_trace", mysql.LONGTEXT(), nullable=True),
|
||||||
|
sa.Column("final_section_ids", sa.String(500), nullable=True),
|
||||||
|
sa.Column("discarded_conflicts", mysql.MEDIUMTEXT(), nullable=True),
|
||||||
|
sa.Column("final_answer", mysql.LONGTEXT(), nullable=True),
|
||||||
|
sa.Column("status", sa.String(20), nullable=False),
|
||||||
|
sa.Column("tool_cost_ms", sa.Integer(), nullable=True),
|
||||||
|
sa.Column("total_cost_ms", sa.Integer(), nullable=True),
|
||||||
|
sa.Column("error_message", mysql.MEDIUMTEXT(), nullable=True),
|
||||||
|
sa.Column("attention_created", sa.Integer(), nullable=False, server_default="0"),
|
||||||
|
sa.Column("created_at", sa.DateTime(), server_default=sa.text("now()"), nullable=False),
|
||||||
|
sa.PrimaryKeyConstraint("id"),
|
||||||
|
)
|
||||||
|
_indexes("sys_knowledge_retrieval_log", "session_id", "message_id", "user_id")
|
||||||
|
|
||||||
|
op.create_table(
|
||||||
|
"sys_knowledge_retrieval_candidate",
|
||||||
|
sa.Column("id", sa.BigInteger(), autoincrement=True, nullable=False),
|
||||||
|
sa.Column("retrieval_log_id", sa.BigInteger(), nullable=False),
|
||||||
|
sa.Column("knowledge_id", sa.BigInteger(), nullable=False),
|
||||||
|
sa.Column("version_id", sa.BigInteger(), nullable=False),
|
||||||
|
sa.Column("chunk_id", sa.BigInteger(), nullable=False),
|
||||||
|
sa.Column("section_id", sa.BigInteger(), nullable=False),
|
||||||
|
sa.Column("lexical_score", sa.String(30), nullable=False),
|
||||||
|
sa.Column("rerank_score", sa.String(30), nullable=True),
|
||||||
|
sa.Column("selected", sa.Integer(), nullable=False, server_default="0"),
|
||||||
|
sa.Column("discard_reason", sa.String(255), nullable=True),
|
||||||
|
sa.ForeignKeyConstraint(["retrieval_log_id"], ["sys_knowledge_retrieval_log.id"]),
|
||||||
|
sa.PrimaryKeyConstraint("id"),
|
||||||
|
)
|
||||||
|
_indexes("sys_knowledge_retrieval_candidate", "retrieval_log_id", "knowledge_id", "version_id")
|
||||||
|
|
||||||
|
op.create_table(
|
||||||
|
"sys_human_attention_record",
|
||||||
|
sa.Column("id", sa.BigInteger(), autoincrement=True, nullable=False),
|
||||||
|
sa.Column("session_id", sa.BigInteger(), nullable=False),
|
||||||
|
sa.Column("message_id", sa.BigInteger(), nullable=False),
|
||||||
|
sa.Column("user_id", sa.BigInteger(), nullable=False),
|
||||||
|
sa.Column("trigger_message", mysql.MEDIUMTEXT(), nullable=False),
|
||||||
|
sa.Column("problem_summary", mysql.MEDIUMTEXT(), nullable=False),
|
||||||
|
sa.Column("trigger_reason", mysql.MEDIUMTEXT(), nullable=False),
|
||||||
|
sa.Column("priority", sa.String(20), nullable=False),
|
||||||
|
sa.Column("status", sa.String(20), nullable=False, server_default="pending"),
|
||||||
|
sa.Column("handler_id", sa.BigInteger(), nullable=True),
|
||||||
|
sa.Column("handler_note", mysql.MEDIUMTEXT(), nullable=True),
|
||||||
|
sa.Column("created_at", sa.DateTime(), server_default=sa.text("now()"), nullable=False),
|
||||||
|
sa.Column("updated_at", sa.DateTime(), server_default=sa.text("now()"), nullable=False),
|
||||||
|
sa.PrimaryKeyConstraint("id"),
|
||||||
|
)
|
||||||
|
_indexes("sys_human_attention_record", "session_id", "message_id", "user_id", "priority", "status")
|
||||||
|
|
||||||
|
op.create_table(
|
||||||
|
"sys_human_attention_history",
|
||||||
|
sa.Column("id", sa.BigInteger(), autoincrement=True, nullable=False),
|
||||||
|
sa.Column("attention_id", sa.BigInteger(), nullable=False),
|
||||||
|
sa.Column("from_status", sa.String(20), nullable=True),
|
||||||
|
sa.Column("to_status", sa.String(20), nullable=False),
|
||||||
|
sa.Column("note", mysql.MEDIUMTEXT(), nullable=True),
|
||||||
|
sa.Column("operated_by", sa.BigInteger(), nullable=False),
|
||||||
|
sa.Column("created_at", sa.DateTime(), server_default=sa.text("now()"), nullable=False),
|
||||||
|
sa.ForeignKeyConstraint(["attention_id"], ["sys_human_attention_record.id"]),
|
||||||
|
sa.PrimaryKeyConstraint("id"),
|
||||||
|
)
|
||||||
|
_indexes("sys_human_attention_history", "attention_id")
|
||||||
|
|
||||||
|
|
||||||
|
def _indexes(table: str, *columns: str) -> None:
|
||||||
|
for column in columns:
|
||||||
|
op.create_index(f"ix_{table}_{column}", table, [column])
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade() -> None:
|
||||||
|
for table in [
|
||||||
|
"sys_human_attention_history",
|
||||||
|
"sys_human_attention_record",
|
||||||
|
"sys_knowledge_retrieval_candidate",
|
||||||
|
"sys_knowledge_retrieval_log",
|
||||||
|
"sys_knowledge_publish_log",
|
||||||
|
"sys_knowledge_review_record",
|
||||||
|
"sys_knowledge_sync_job",
|
||||||
|
"sys_knowledge_card",
|
||||||
|
"sys_knowledge_chunk",
|
||||||
|
"sys_knowledge_section",
|
||||||
|
"sys_knowledge_manifest",
|
||||||
|
"sys_knowledge_version",
|
||||||
|
"sys_knowledge_source_snapshot",
|
||||||
|
]:
|
||||||
|
op.drop_table(table)
|
||||||
|
for column in [
|
||||||
|
"migration_status", "last_published_at", "last_synced_at", "pending_version_id",
|
||||||
|
"current_version_id", "manifest_confirmed", "source_error", "source_status",
|
||||||
|
"lifecycle_status", "review_mode", "knowledge_type", "source_title",
|
||||||
|
]:
|
||||||
|
op.drop_column("sys_knowledge", column)
|
||||||
@@ -2,7 +2,23 @@ from app.models.admin import Admin, Role
|
|||||||
from app.models.ai_config import ModelConfig, Prompt, SystemConfig
|
from app.models.ai_config import ModelConfig, Prompt, SystemConfig
|
||||||
from app.models.base import Base
|
from app.models.base import Base
|
||||||
from app.models.chat import ChatMessage, ChatSession
|
from app.models.chat import ChatMessage, ChatSession
|
||||||
from app.models.knowledge import Knowledge, UserKnowledgePermission
|
from app.models.knowledge import (
|
||||||
|
HumanAttentionHistory,
|
||||||
|
HumanAttentionRecord,
|
||||||
|
Knowledge,
|
||||||
|
KnowledgeCard,
|
||||||
|
KnowledgeChunk,
|
||||||
|
KnowledgeManifest,
|
||||||
|
KnowledgePublishLog,
|
||||||
|
KnowledgeRetrievalCandidate,
|
||||||
|
KnowledgeRetrievalLog,
|
||||||
|
KnowledgeReviewRecord,
|
||||||
|
KnowledgeSection,
|
||||||
|
KnowledgeSourceSnapshot,
|
||||||
|
KnowledgeSyncJob,
|
||||||
|
KnowledgeVersion,
|
||||||
|
UserKnowledgePermission,
|
||||||
|
)
|
||||||
from app.models.logs import AiRequestLog, OperationLog
|
from app.models.logs import AiRequestLog, OperationLog
|
||||||
from app.models.user import User
|
from app.models.user import User
|
||||||
|
|
||||||
@@ -13,6 +29,19 @@ __all__ = [
|
|||||||
"ChatMessage",
|
"ChatMessage",
|
||||||
"ChatSession",
|
"ChatSession",
|
||||||
"Knowledge",
|
"Knowledge",
|
||||||
|
"KnowledgeCard",
|
||||||
|
"KnowledgeChunk",
|
||||||
|
"KnowledgeManifest",
|
||||||
|
"KnowledgePublishLog",
|
||||||
|
"KnowledgeRetrievalCandidate",
|
||||||
|
"KnowledgeRetrievalLog",
|
||||||
|
"KnowledgeReviewRecord",
|
||||||
|
"KnowledgeSection",
|
||||||
|
"KnowledgeSourceSnapshot",
|
||||||
|
"KnowledgeSyncJob",
|
||||||
|
"KnowledgeVersion",
|
||||||
|
"HumanAttentionHistory",
|
||||||
|
"HumanAttentionRecord",
|
||||||
"ModelConfig",
|
"ModelConfig",
|
||||||
"OperationLog",
|
"OperationLog",
|
||||||
"Prompt",
|
"Prompt",
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from sqlalchemy import BigInteger, DateTime, ForeignKey, String
|
from sqlalchemy import BigInteger, DateTime, ForeignKey, Integer, String, Text, UniqueConstraint, func
|
||||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||||
|
|
||||||
from app.models.base import Base, TimestampMixin
|
from app.models.base import Base, TimestampMixin
|
||||||
@@ -17,6 +17,18 @@ class Knowledge(Base, TimestampMixin):
|
|||||||
feishu_node_id: Mapped[str] = mapped_column(String(100), nullable=False)
|
feishu_node_id: Mapped[str] = mapped_column(String(100), nullable=False)
|
||||||
status: Mapped[int] = mapped_column(default=1, nullable=False)
|
status: Mapped[int] = mapped_column(default=1, nullable=False)
|
||||||
remark: Mapped[str | None] = mapped_column(String(255), nullable=True)
|
remark: Mapped[str | None] = mapped_column(String(255), nullable=True)
|
||||||
|
source_title: Mapped[str | None] = mapped_column(String(255), nullable=True)
|
||||||
|
knowledge_type: Mapped[str] = mapped_column(String(30), default="general", nullable=False)
|
||||||
|
review_mode: Mapped[str] = mapped_column(String(30), default="manual", nullable=False)
|
||||||
|
lifecycle_status: Mapped[str] = mapped_column(String(30), default="active", nullable=False)
|
||||||
|
source_status: Mapped[str] = mapped_column(String(30), default="normal", nullable=False)
|
||||||
|
source_error: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||||
|
manifest_confirmed: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
|
||||||
|
current_version_id: Mapped[int | None] = mapped_column(BigInteger, nullable=True)
|
||||||
|
pending_version_id: Mapped[int | None] = mapped_column(BigInteger, nullable=True)
|
||||||
|
last_synced_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
||||||
|
last_published_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
||||||
|
migration_status: Mapped[str] = mapped_column(String(30), default="pending", nullable=False)
|
||||||
|
|
||||||
user_permissions: Mapped[list["UserKnowledgePermission"]] = relationship(
|
user_permissions: Mapped[list["UserKnowledgePermission"]] = relationship(
|
||||||
"UserKnowledgePermission", back_populates="knowledge"
|
"UserKnowledgePermission", back_populates="knowledge"
|
||||||
@@ -35,3 +47,227 @@ class UserKnowledgePermission(Base, TimestampMixin):
|
|||||||
|
|
||||||
user: Mapped["User"] = relationship("User", back_populates="knowledge_permissions")
|
user: Mapped["User"] = relationship("User", back_populates="knowledge_permissions")
|
||||||
knowledge: Mapped[Knowledge] = relationship("Knowledge", back_populates="user_permissions")
|
knowledge: Mapped[Knowledge] = relationship("Knowledge", back_populates="user_permissions")
|
||||||
|
|
||||||
|
|
||||||
|
class KnowledgeSourceSnapshot(Base):
|
||||||
|
__tablename__ = "sys_knowledge_source_snapshot"
|
||||||
|
|
||||||
|
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
|
||||||
|
knowledge_id: Mapped[int] = mapped_column(ForeignKey("sys_knowledge.id"), index=True, nullable=False)
|
||||||
|
sync_job_id: Mapped[int | None] = mapped_column(BigInteger, index=True, nullable=True)
|
||||||
|
source_title: Mapped[str] = mapped_column(String(255), nullable=False)
|
||||||
|
source_content: Mapped[str] = mapped_column(Text, nullable=False)
|
||||||
|
content_hash: Mapped[str] = mapped_column(String(64), index=True, nullable=False)
|
||||||
|
source_identifier: Mapped[str] = mapped_column(String(255), nullable=False)
|
||||||
|
fetched_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now(), nullable=False)
|
||||||
|
created_by: Mapped[int | None] = mapped_column(BigInteger, nullable=True)
|
||||||
|
|
||||||
|
|
||||||
|
class KnowledgeVersion(Base):
|
||||||
|
__tablename__ = "sys_knowledge_version"
|
||||||
|
__table_args__ = (UniqueConstraint("knowledge_id", "version_no", name="uq_kb_version_no"),)
|
||||||
|
|
||||||
|
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
|
||||||
|
knowledge_id: Mapped[int] = mapped_column(ForeignKey("sys_knowledge.id"), index=True, nullable=False)
|
||||||
|
snapshot_id: Mapped[int] = mapped_column(ForeignKey("sys_knowledge_source_snapshot.id"), nullable=False)
|
||||||
|
version_no: Mapped[int] = mapped_column(Integer, nullable=False)
|
||||||
|
status: Mapped[str] = mapped_column(String(30), index=True, nullable=False)
|
||||||
|
quality_status: Mapped[str] = mapped_column(String(30), default="pending", nullable=False)
|
||||||
|
change_summary: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||||
|
quality_report: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||||
|
processing_rule_version: Mapped[str] = mapped_column(String(50), nullable=False)
|
||||||
|
generation_model: Mapped[str | None] = mapped_column(String(100), nullable=True)
|
||||||
|
created_by: Mapped[int | None] = mapped_column(BigInteger, nullable=True)
|
||||||
|
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now(), nullable=False)
|
||||||
|
published_by: Mapped[int | None] = mapped_column(BigInteger, nullable=True)
|
||||||
|
published_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
||||||
|
|
||||||
|
|
||||||
|
class KnowledgeManifest(Base):
|
||||||
|
__tablename__ = "sys_knowledge_manifest"
|
||||||
|
|
||||||
|
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
|
||||||
|
knowledge_id: Mapped[int] = mapped_column(ForeignKey("sys_knowledge.id"), index=True, nullable=False)
|
||||||
|
version_id: Mapped[int] = mapped_column(ForeignKey("sys_knowledge_version.id"), index=True, nullable=False)
|
||||||
|
purpose: Mapped[str] = mapped_column(Text, nullable=False)
|
||||||
|
applicable_questions: Mapped[str] = mapped_column(Text, nullable=False)
|
||||||
|
inapplicable_questions: Mapped[str] = mapped_column(Text, nullable=False)
|
||||||
|
core_topics: Mapped[str] = mapped_column(Text, nullable=False)
|
||||||
|
entities: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||||
|
boundaries: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||||
|
content_hash: Mapped[str] = mapped_column(String(64), nullable=False)
|
||||||
|
change_level: Mapped[str] = mapped_column(String(20), default="major", nullable=False)
|
||||||
|
confirmed: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
|
||||||
|
confirmed_by: Mapped[int | None] = mapped_column(BigInteger, nullable=True)
|
||||||
|
confirmed_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
||||||
|
|
||||||
|
|
||||||
|
class KnowledgeSection(Base):
|
||||||
|
__tablename__ = "sys_knowledge_section"
|
||||||
|
|
||||||
|
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
|
||||||
|
knowledge_id: Mapped[int] = mapped_column(ForeignKey("sys_knowledge.id"), index=True, nullable=False)
|
||||||
|
version_id: Mapped[int] = mapped_column(ForeignKey("sys_knowledge_version.id"), index=True, nullable=False)
|
||||||
|
section_key: Mapped[str] = mapped_column(String(64), nullable=False)
|
||||||
|
title: Mapped[str] = mapped_column(String(255), nullable=False)
|
||||||
|
content: Mapped[str] = mapped_column(Text, nullable=False)
|
||||||
|
source_start: Mapped[int] = mapped_column(Integer, nullable=False)
|
||||||
|
source_end: Mapped[int] = mapped_column(Integer, nullable=False)
|
||||||
|
sort_order: Mapped[int] = mapped_column(Integer, nullable=False)
|
||||||
|
content_hash: Mapped[str] = mapped_column(String(64), nullable=False)
|
||||||
|
|
||||||
|
|
||||||
|
class KnowledgeChunk(Base):
|
||||||
|
__tablename__ = "sys_knowledge_chunk"
|
||||||
|
|
||||||
|
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
|
||||||
|
knowledge_id: Mapped[int] = mapped_column(ForeignKey("sys_knowledge.id"), index=True, nullable=False)
|
||||||
|
version_id: Mapped[int] = mapped_column(ForeignKey("sys_knowledge_version.id"), index=True, nullable=False)
|
||||||
|
section_id: Mapped[int] = mapped_column(ForeignKey("sys_knowledge_section.id"), index=True, nullable=False)
|
||||||
|
title: Mapped[str] = mapped_column(String(255), nullable=False)
|
||||||
|
content: Mapped[str] = mapped_column(Text, nullable=False)
|
||||||
|
normalized_text: Mapped[str] = mapped_column(Text, nullable=False)
|
||||||
|
keywords: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||||
|
synonyms: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||||
|
source_start: Mapped[int] = mapped_column(Integer, nullable=False)
|
||||||
|
source_end: Mapped[int] = mapped_column(Integer, nullable=False)
|
||||||
|
sort_order: Mapped[int] = mapped_column(Integer, nullable=False)
|
||||||
|
content_hash: Mapped[str] = mapped_column(String(64), nullable=False)
|
||||||
|
|
||||||
|
|
||||||
|
class KnowledgeCard(Base):
|
||||||
|
__tablename__ = "sys_knowledge_card"
|
||||||
|
|
||||||
|
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
|
||||||
|
knowledge_id: Mapped[int] = mapped_column(ForeignKey("sys_knowledge.id"), index=True, nullable=False)
|
||||||
|
version_id: Mapped[int] = mapped_column(ForeignKey("sys_knowledge_version.id"), index=True, nullable=False)
|
||||||
|
section_id: Mapped[int] = mapped_column(ForeignKey("sys_knowledge_section.id"), index=True, nullable=False)
|
||||||
|
title: Mapped[str] = mapped_column(String(255), nullable=False)
|
||||||
|
summary: Mapped[str] = mapped_column(Text, nullable=False)
|
||||||
|
core_conclusion: Mapped[str] = mapped_column(Text, nullable=False)
|
||||||
|
applicable_questions: Mapped[str] = mapped_column(Text, nullable=False)
|
||||||
|
inapplicable_questions: Mapped[str] = mapped_column(Text, nullable=False)
|
||||||
|
keywords: Mapped[str] = mapped_column(Text, nullable=False)
|
||||||
|
synonyms: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||||
|
entities: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||||
|
risk_level: Mapped[str] = mapped_column(String(20), default="normal", nullable=False)
|
||||||
|
source_range: Mapped[str] = mapped_column(String(100), nullable=False)
|
||||||
|
content_hash: Mapped[str] = mapped_column(String(64), nullable=False)
|
||||||
|
generation_model: Mapped[str | None] = mapped_column(String(100), nullable=True)
|
||||||
|
generation_rule_version: Mapped[str] = mapped_column(String(50), nullable=False)
|
||||||
|
review_status: Mapped[str] = mapped_column(String(20), default="pending", nullable=False)
|
||||||
|
|
||||||
|
|
||||||
|
class KnowledgeSyncJob(Base):
|
||||||
|
__tablename__ = "sys_knowledge_sync_job"
|
||||||
|
|
||||||
|
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
|
||||||
|
knowledge_id: Mapped[int] = mapped_column(ForeignKey("sys_knowledge.id"), index=True, nullable=False)
|
||||||
|
mode: Mapped[str] = mapped_column(String(30), nullable=False)
|
||||||
|
status: Mapped[str] = mapped_column(String(30), index=True, nullable=False)
|
||||||
|
stage: Mapped[str] = mapped_column(String(50), nullable=False)
|
||||||
|
progress: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
|
||||||
|
source_error: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||||
|
result_summary: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||||
|
requested_by: Mapped[int] = mapped_column(BigInteger, nullable=False)
|
||||||
|
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now(), nullable=False)
|
||||||
|
started_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
||||||
|
finished_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
||||||
|
|
||||||
|
|
||||||
|
class KnowledgeReviewRecord(Base):
|
||||||
|
__tablename__ = "sys_knowledge_review_record"
|
||||||
|
|
||||||
|
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
|
||||||
|
knowledge_id: Mapped[int] = mapped_column(ForeignKey("sys_knowledge.id"), index=True, nullable=False)
|
||||||
|
version_id: Mapped[int] = mapped_column(ForeignKey("sys_knowledge_version.id"), index=True, nullable=False)
|
||||||
|
card_id: Mapped[int | None] = mapped_column(ForeignKey("sys_knowledge_card.id"), nullable=True)
|
||||||
|
action: Mapped[str] = mapped_column(String(30), nullable=False)
|
||||||
|
reason: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||||
|
reviewed_by: Mapped[int] = mapped_column(BigInteger, nullable=False)
|
||||||
|
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now(), nullable=False)
|
||||||
|
|
||||||
|
|
||||||
|
class KnowledgePublishLog(Base):
|
||||||
|
__tablename__ = "sys_knowledge_publish_log"
|
||||||
|
|
||||||
|
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
|
||||||
|
knowledge_id: Mapped[int] = mapped_column(ForeignKey("sys_knowledge.id"), index=True, nullable=False)
|
||||||
|
from_version_id: Mapped[int | None] = mapped_column(BigInteger, nullable=True)
|
||||||
|
to_version_id: Mapped[int | None] = mapped_column(BigInteger, nullable=True)
|
||||||
|
action: Mapped[str] = mapped_column(String(30), nullable=False)
|
||||||
|
keep_open: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
|
||||||
|
detail_json: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||||
|
operated_by: Mapped[int] = mapped_column(BigInteger, nullable=False)
|
||||||
|
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now(), nullable=False)
|
||||||
|
|
||||||
|
|
||||||
|
class KnowledgeRetrievalLog(Base):
|
||||||
|
__tablename__ = "sys_knowledge_retrieval_log"
|
||||||
|
|
||||||
|
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
|
||||||
|
session_id: Mapped[int | None] = mapped_column(BigInteger, index=True, nullable=True)
|
||||||
|
message_id: Mapped[int | None] = mapped_column(BigInteger, index=True, nullable=True)
|
||||||
|
user_id: Mapped[int | None] = mapped_column(BigInteger, index=True, nullable=True)
|
||||||
|
question: Mapped[str] = mapped_column(Text, nullable=False)
|
||||||
|
catalog_snapshot: Mapped[str] = mapped_column(Text, nullable=False)
|
||||||
|
catalog_hash: Mapped[str] = mapped_column(String(64), nullable=False)
|
||||||
|
safety_rule_version: Mapped[str] = mapped_column(String(50), nullable=False)
|
||||||
|
knowledge_called: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
|
||||||
|
selected_knowledge_ids: Mapped[str | None] = mapped_column(String(500), nullable=True)
|
||||||
|
query_terms: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||||
|
tool_trace: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||||
|
final_section_ids: Mapped[str | None] = mapped_column(String(500), nullable=True)
|
||||||
|
discarded_conflicts: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||||
|
final_answer: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||||
|
status: Mapped[str] = mapped_column(String(20), nullable=False)
|
||||||
|
tool_cost_ms: Mapped[int | None] = mapped_column(Integer, nullable=True)
|
||||||
|
total_cost_ms: Mapped[int | None] = mapped_column(Integer, nullable=True)
|
||||||
|
error_message: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||||
|
attention_created: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
|
||||||
|
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now(), nullable=False)
|
||||||
|
|
||||||
|
|
||||||
|
class KnowledgeRetrievalCandidate(Base):
|
||||||
|
__tablename__ = "sys_knowledge_retrieval_candidate"
|
||||||
|
|
||||||
|
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
|
||||||
|
retrieval_log_id: Mapped[int] = mapped_column(ForeignKey("sys_knowledge_retrieval_log.id"), index=True, nullable=False)
|
||||||
|
knowledge_id: Mapped[int] = mapped_column(BigInteger, index=True, nullable=False)
|
||||||
|
version_id: Mapped[int] = mapped_column(BigInteger, index=True, nullable=False)
|
||||||
|
chunk_id: Mapped[int] = mapped_column(BigInteger, nullable=False)
|
||||||
|
section_id: Mapped[int] = mapped_column(BigInteger, nullable=False)
|
||||||
|
lexical_score: Mapped[str] = mapped_column(String(30), nullable=False)
|
||||||
|
rerank_score: Mapped[str | None] = mapped_column(String(30), nullable=True)
|
||||||
|
selected: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
|
||||||
|
discard_reason: Mapped[str | None] = mapped_column(String(255), nullable=True)
|
||||||
|
|
||||||
|
|
||||||
|
class HumanAttentionRecord(Base):
|
||||||
|
__tablename__ = "sys_human_attention_record"
|
||||||
|
|
||||||
|
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
|
||||||
|
session_id: Mapped[int] = mapped_column(BigInteger, index=True, nullable=False)
|
||||||
|
message_id: Mapped[int] = mapped_column(BigInteger, index=True, nullable=False)
|
||||||
|
user_id: Mapped[int] = mapped_column(BigInteger, index=True, nullable=False)
|
||||||
|
trigger_message: Mapped[str] = mapped_column(Text, nullable=False)
|
||||||
|
problem_summary: Mapped[str] = mapped_column(Text, nullable=False)
|
||||||
|
trigger_reason: Mapped[str] = mapped_column(Text, nullable=False)
|
||||||
|
priority: Mapped[str] = mapped_column(String(20), index=True, nullable=False)
|
||||||
|
status: Mapped[str] = mapped_column(String(20), index=True, default="pending", nullable=False)
|
||||||
|
handler_id: Mapped[int | None] = mapped_column(BigInteger, nullable=True)
|
||||||
|
handler_note: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||||
|
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now(), nullable=False)
|
||||||
|
updated_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now(), onupdate=func.now(), nullable=False)
|
||||||
|
|
||||||
|
|
||||||
|
class HumanAttentionHistory(Base):
|
||||||
|
__tablename__ = "sys_human_attention_history"
|
||||||
|
|
||||||
|
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
|
||||||
|
attention_id: Mapped[int] = mapped_column(ForeignKey("sys_human_attention_record.id"), index=True, nullable=False)
|
||||||
|
from_status: Mapped[str | None] = mapped_column(String(20), nullable=True)
|
||||||
|
to_status: Mapped[str] = mapped_column(String(20), nullable=False)
|
||||||
|
note: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||||
|
operated_by: Mapped[int] = mapped_column(BigInteger, nullable=False)
|
||||||
|
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now(), nullable=False)
|
||||||
|
|||||||
Reference in New Issue
Block a user