feat: 优化权益管理并完成一期验收

This commit is contained in:
2026-07-31 18:49:48 +08:00
parent b6aff78aac
commit a3946013f5
14 changed files with 740 additions and 284 deletions

View File

@@ -1,6 +1,6 @@
from __future__ import annotations
from alembic import op
from alembic import context, op
import sqlalchemy as sa
revision = "0008_unique_kb_node"
@@ -10,7 +10,9 @@ depends_on = None
def upgrade() -> None:
constraints = {item["name"] for item in sa.inspect(op.get_bind()).get_unique_constraints("sys_knowledge")}
constraints = set() if context.is_offline_mode() else {
item["name"] for item in sa.inspect(op.get_bind()).get_unique_constraints("sys_knowledge")
}
if "uq_knowledge_feishu_node" not in constraints:
op.create_unique_constraint(
"uq_knowledge_feishu_node",
@@ -20,6 +22,8 @@ def upgrade() -> None:
def downgrade() -> None:
constraints = {item["name"] for item in sa.inspect(op.get_bind()).get_unique_constraints("sys_knowledge")}
constraints = {"uq_knowledge_feishu_node"} if context.is_offline_mode() else {
item["name"] for item in sa.inspect(op.get_bind()).get_unique_constraints("sys_knowledge")
}
if "uq_knowledge_feishu_node" in constraints:
op.drop_constraint("uq_knowledge_feishu_node", "sys_knowledge", type_="unique")

View File

@@ -3,7 +3,7 @@
Revision ID: 0009_logs_storage
Revises: 0008_unique_kb_node
"""
from alembic import op
from alembic import context, op
import sqlalchemy as sa
revision = "0009_logs_storage"
@@ -13,8 +13,8 @@ depends_on = None
def upgrade() -> None:
inspector = sa.inspect(op.get_bind())
tables = set(inspector.get_table_names())
inspector = None if context.is_offline_mode() else sa.inspect(op.get_bind())
tables = set() if inspector is None else set(inspector.get_table_names())
if "sys_log_retention_policy" not in tables:
op.create_table(
"sys_log_retention_policy",
@@ -45,7 +45,10 @@ def upgrade() -> None:
def _create_index_if_missing(table: str, name: str, columns: list[str]) -> None:
if name not in {item["name"] for item in sa.inspect(op.get_bind()).get_indexes(table)}:
indexes = set() if context.is_offline_mode() else {
item["name"] for item in sa.inspect(op.get_bind()).get_indexes(table)
}
if name not in indexes:
op.create_index(name, table, columns)

View File

@@ -4,7 +4,7 @@ Revision ID: 0013_question_insight_indexes
Revises: 0012_knowledge_latest_only
"""
from alembic import op
from alembic import context, op
import sqlalchemy as sa
@@ -19,11 +19,16 @@ def upgrade() -> None:
def downgrade() -> None:
indexes = {item["name"] for item in sa.inspect(op.get_bind()).get_indexes("sys_chat_message")}
indexes = {"ix_chat_message_role_created"} if context.is_offline_mode() else {
item["name"] for item in sa.inspect(op.get_bind()).get_indexes("sys_chat_message")
}
if "ix_chat_message_role_created" in indexes:
op.drop_index("ix_chat_message_role_created", table_name="sys_chat_message")
def _create_index_if_missing(table: str, name: str, columns: list[str]) -> None:
if name not in {item["name"] for item in sa.inspect(op.get_bind()).get_indexes(table)}:
indexes = set() if context.is_offline_mode() else {
item["name"] for item in sa.inspect(op.get_bind()).get_indexes(table)
}
if name not in indexes:
op.create_index(name, table, columns)

View File

@@ -4,7 +4,7 @@ Revision ID: 0014_entitlements_topics
Revises: 0013_question_insight_indexes
"""
from alembic import op
from alembic import context, op
import sqlalchemy as sa
@@ -17,8 +17,8 @@ PRIMARY_KEY_TYPE = sa.BigInteger().with_variant(sa.Integer(), "sqlite")
def upgrade() -> None:
inspector = sa.inspect(op.get_bind())
tables = set(inspector.get_table_names())
inspector = None if context.is_offline_mode() else sa.inspect(op.get_bind())
tables = set() if inspector is None else set(inspector.get_table_names())
if "sys_entitlement_plan" not in tables:
op.create_table(
"sys_entitlement_plan",
@@ -100,19 +100,26 @@ def upgrade() -> None:
op.create_index("ix_sys_topic_session_chat_session_id", "sys_topic_session", ["chat_session_id"])
op.create_index("ix_sys_topic_session_status", "sys_topic_session", ["status"])
columns = {column["name"] for column in inspector.get_columns("sys_chat_message")}
columns = set() if inspector is None else {column["name"] for column in inspector.get_columns("sys_chat_message")}
if "topic_session_id" not in columns:
op.add_column("sys_chat_message", sa.Column("topic_session_id", sa.BigInteger(), nullable=True))
op.create_index("ix_sys_chat_message_topic_session_id", "sys_chat_message", ["topic_session_id"])
def downgrade() -> None:
inspector = sa.inspect(op.get_bind())
columns = {column["name"] for column in inspector.get_columns("sys_chat_message")}
inspector = None if context.is_offline_mode() else sa.inspect(op.get_bind())
columns = {"topic_session_id"} if inspector is None else {
column["name"] for column in inspector.get_columns("sys_chat_message")
}
if "topic_session_id" in columns:
op.drop_index("ix_sys_chat_message_topic_session_id", table_name="sys_chat_message")
op.drop_column("sys_chat_message", "topic_session_id")
tables = set(inspector.get_table_names())
tables = {
"sys_topic_session",
"sys_user_entitlement_log",
"sys_user_entitlement",
"sys_entitlement_plan",
} if inspector is None else set(inspector.get_table_names())
if "sys_topic_session" in tables:
op.drop_index("ix_sys_topic_session_status", table_name="sys_topic_session")
op.drop_index("ix_sys_topic_session_chat_session_id", table_name="sys_topic_session")
@@ -136,18 +143,18 @@ def _seed_default_plans() -> None:
op.bulk_insert(
sa.table(
"sys_entitlement_plan",
sa.column("name"),
sa.column("plan_type"),
sa.column("description"),
sa.column("validity_days"),
sa.column("monthly_topic_limit"),
sa.column("enable_growth_profile"),
sa.column("enable_periodic_reports"),
sa.column("allow_help_card"),
sa.column("allow_share_draft"),
sa.column("deduct_quota"),
sa.column("status"),
sa.column("sort_order"),
sa.column("name", sa.String(80)),
sa.column("plan_type", sa.String(30)),
sa.column("description", sa.String(255)),
sa.column("validity_days", sa.Integer()),
sa.column("monthly_topic_limit", sa.Integer()),
sa.column("enable_growth_profile", sa.Integer()),
sa.column("enable_periodic_reports", sa.Integer()),
sa.column("allow_help_card", sa.Integer()),
sa.column("allow_share_draft", sa.Integer()),
sa.column("deduct_quota", sa.Integer()),
sa.column("status", sa.Integer()),
sa.column("sort_order", sa.Integer()),
),
[
{

View File

@@ -4,7 +4,7 @@ Revision ID: 0015_growth_profiles
Revises: 0014_entitlements_topics
"""
from alembic import op
from alembic import context, op
import sqlalchemy as sa
@@ -17,8 +17,8 @@ PRIMARY_KEY_TYPE = sa.BigInteger().with_variant(sa.Integer(), "sqlite")
def upgrade() -> None:
inspector = sa.inspect(op.get_bind())
tables = set(inspector.get_table_names())
inspector = None if context.is_offline_mode() else sa.inspect(op.get_bind())
tables = set() if inspector is None else set(inspector.get_table_names())
if "sys_topic_summary" not in tables:
op.create_table(
@@ -85,8 +85,12 @@ def upgrade() -> None:
def downgrade() -> None:
inspector = sa.inspect(op.get_bind())
tables = set(inspector.get_table_names())
inspector = None if context.is_offline_mode() else sa.inspect(op.get_bind())
tables = {
"sys_growth_profile_revision",
"sys_user_growth_profile",
"sys_topic_summary",
} if inspector is None else set(inspector.get_table_names())
if "sys_growth_profile_revision" in tables:
op.drop_index("ix_sys_growth_profile_revision_topic_summary_id", table_name="sys_growth_profile_revision")
op.drop_index("ix_sys_growth_profile_revision_profile_id", table_name="sys_growth_profile_revision")

View File

@@ -4,7 +4,7 @@ Revision ID: 0016_teacher_help_cards
Revises: 0015_growth_profiles
"""
from alembic import op
from alembic import context, op
import sqlalchemy as sa
@@ -17,8 +17,8 @@ PRIMARY_KEY_TYPE = sa.BigInteger().with_variant(sa.Integer(), "sqlite")
def upgrade() -> None:
inspector = sa.inspect(op.get_bind())
tables = set(inspector.get_table_names())
inspector = None if context.is_offline_mode() else sa.inspect(op.get_bind())
tables = set() if inspector is None else set(inspector.get_table_names())
if "sys_teacher_help_card" in tables:
return
op.create_table(
@@ -40,8 +40,8 @@ def upgrade() -> None:
def downgrade() -> None:
inspector = sa.inspect(op.get_bind())
tables = set(inspector.get_table_names())
inspector = None if context.is_offline_mode() else sa.inspect(op.get_bind())
tables = {"sys_teacher_help_card"} if inspector is None else set(inspector.get_table_names())
if "sys_teacher_help_card" not in tables:
return
op.drop_index("ix_sys_teacher_help_card_topic_created", table_name="sys_teacher_help_card")

View File

@@ -4,7 +4,7 @@ Revision ID: 0017_share_drafts
Revises: 0016_teacher_help_cards
"""
from alembic import op
from alembic import context, op
import sqlalchemy as sa
@@ -17,8 +17,8 @@ PRIMARY_KEY_TYPE = sa.BigInteger().with_variant(sa.Integer(), "sqlite")
def upgrade() -> None:
inspector = sa.inspect(op.get_bind())
tables = set(inspector.get_table_names())
inspector = None if context.is_offline_mode() else sa.inspect(op.get_bind())
tables = set() if inspector is None else set(inspector.get_table_names())
if "sys_share_draft" in tables:
return
op.create_table(
@@ -40,8 +40,8 @@ def upgrade() -> None:
def downgrade() -> None:
inspector = sa.inspect(op.get_bind())
tables = set(inspector.get_table_names())
inspector = None if context.is_offline_mode() else sa.inspect(op.get_bind())
tables = {"sys_share_draft"} if inspector is None else set(inspector.get_table_names())
if "sys_share_draft" not in tables:
return
op.drop_index("ix_sys_share_draft_topic_created", table_name="sys_share_draft")

View File

@@ -4,7 +4,7 @@ Revision ID: 0018_ai_cost_tracking
Revises: 0017_share_drafts
"""
from alembic import op
from alembic import context, op
import sqlalchemy as sa
@@ -15,8 +15,8 @@ depends_on = None
def upgrade() -> None:
inspector = sa.inspect(op.get_bind())
model_columns = {column["name"] for column in inspector.get_columns("sys_model")}
inspector = None if context.is_offline_mode() else sa.inspect(op.get_bind())
model_columns = set() if inspector is None else {column["name"] for column in inspector.get_columns("sys_model")}
_add_column_if_missing(model_columns, "sys_model", sa.Column("input_price_per_1k", sa.Numeric(12, 6), nullable=True))
_add_column_if_missing(model_columns, "sys_model", sa.Column("output_price_per_1k", sa.Numeric(12, 6), nullable=True))
_add_column_if_missing(model_columns, "sys_model", sa.Column("currency", sa.String(10), nullable=False, server_default="CNY"))
@@ -26,7 +26,7 @@ def upgrade() -> None:
_add_column_if_missing(model_columns, "sys_model", sa.Column("allow_fixed_info", sa.Integer(), nullable=False, server_default="1"))
_add_column_if_missing(model_columns, "sys_model", sa.Column("allow_deep_chat", sa.Integer(), nullable=False, server_default="1"))
log_columns = {column["name"] for column in inspector.get_columns("sys_ai_request_log")}
log_columns = set() if inspector is None else {column["name"] for column in inspector.get_columns("sys_ai_request_log")}
_add_column_if_missing(log_columns, "sys_ai_request_log", sa.Column("model_id", sa.BigInteger(), nullable=True))
_add_column_if_missing(log_columns, "sys_ai_request_log", sa.Column("estimated_cost", sa.Numeric(18, 6), nullable=True))
_add_column_if_missing(log_columns, "sys_ai_request_log", sa.Column("currency", sa.String(10), nullable=True))
@@ -38,15 +38,20 @@ def upgrade() -> None:
def downgrade() -> None:
inspector = sa.inspect(op.get_bind())
log_columns = {column["name"] for column in inspector.get_columns("sys_ai_request_log")}
inspector = None if context.is_offline_mode() else sa.inspect(op.get_bind())
log_columns = {
"model_id", "estimated_cost", "currency", "route_reason", "question_type", "knowledge_hit"
} if inspector is None else {column["name"] for column in inspector.get_columns("sys_ai_request_log")}
if "model_id" in log_columns:
op.drop_index("ix_sys_ai_request_log_model_id", table_name="sys_ai_request_log")
for column in ["knowledge_hit", "question_type", "route_reason", "currency", "estimated_cost", "model_id"]:
if column in log_columns:
op.drop_column("sys_ai_request_log", column)
model_columns = {column["name"] for column in inspector.get_columns("sys_model")}
model_columns = {
"input_price_per_1k", "output_price_per_1k", "currency", "usage_scenarios",
"allow_summary", "allow_report", "allow_fixed_info", "allow_deep_chat",
} if inspector is None else {column["name"] for column in inspector.get_columns("sys_model")}
for column in [
"allow_deep_chat",
"allow_fixed_info",